-
-
[原创]2026软件系统安全赛决赛StudentManagement WP
-
发表于: 1天前 1146
-
Glibc版本2.39,保护全开
(部分偏移因IDA对寄存器赋值识别错误,以文字为准~)
malloc一个0x88的堆块
向+0x0处写入ID(0xF大小)
如果check发现已存在,就free掉0x88的堆块
如果不存在,就向chunk+0x10处写入name(0x3F大小),向读取结尾处写0
同时,向chunk+0x50写入pass(0x1F大小),向读取结尾处写0
向notes数组写入堆块用户指针
向当前0x88堆块末尾八字节(下一个chunk的prev_size处)写入当前chunk的堆地址
鉴权逻辑:确认存不存在ID
若存在,比较0x50处字符串是否相同,若相同进入menu
1.show,打印,但用的是printf,遇到\x00会截断
2.新增bio,输入小于0x400的size,若不存在已有的bio,则malloc一个并向chunk+0x70处写入新malloc的指针,向chunk+0x78处写入新malloc的size,并写入,末尾补0
若存在已有的bio且输入size大于已有bio,free掉原bio,新malloc一个chunk,逻辑同上
输入ID,与chunk的开头校验,若校验通过,则进入free逻辑,首先检查0x70处是否存在指针,若存在,则先free0x70处的bio指针,再free当前user_chunk,同时清空了notes数组,不存在UAF漏洞
若检验不通过,则将指针后移0x80,进行遍历
这题的难点在于,所有的写入操作都在末尾处补零了,且size计算合理不存在off by null漏洞,free也伴随了正确的指针清零操作,所以常见的堆利用三板斧:UAF、堆溢出、off by null均无法正常实现,且无法通过程序读功能泄露基地址(强制写入,且写入必补零)
因此,此题并非为简单的堆利用,而是一套组合漏洞,漏洞的根源来自于当malloc时并未清空内存中的数据
这意味着,如果通过malloc->edit->free->malloc
就能控制user中0x70偏移的bio指针,再通过user_menu实现对于任意地址的读/写操作

回顾register最后的逻辑
其向堆中写入了堆地址,这在后续的内存中会有大用,我们通过调试来看这道题的利用思路
根据刚才的思路,我们必须在先申请满7个堆块填满tcache的情况下继续申请、释放,并构造出一个足够我们进行堆利用大小的Unsortedbin,我们先合并四个堆块看看Unsortedbin的内存是什么样的

如果我们可以使得下图中的A作为register申请时会从Unsortedbin切割下来的堆块,我们就成功伪造了一个0x70地址处的bio指针,且这个指针指向的地址是libc中main_arena的一个地址,我们就可以拿到libc的基地址,不难计算出,如果我们先切割0x120的堆块,再进行register,就可以拿到这个我们想要的堆块
而user_menu中的edit_bio可以申请一个任意大小的堆块,我们在重新填满tcache后申请一个0x130的堆块,再进行register就可以使得bio指针被伪造,效果如下