edit功能里的offset和size都为有符号数,因此,可以令offset为负数,size为整数,这样,可以对当前这个堆的上方任意地址进行写数据。

由于程序中全程使用的是write进行输出,加上程序没有show功能,因此,攻击IO_2_1_stdout的方法在这里就泄露不了数据。
edit功能里的offset和size都为有符号数,因此,可以令offset为负数,size为整数,这样,可以对当前这个堆的上方任意地址进行写数据。
由于程序中全程使用的是write进行输出,加上程序没有show功能,因此,攻击IO_2_1_stdout的方法在这里就泄露不了数据。
栈溢出,可以利用3次
由于没有截断字符串,因此puts可以泄露出栈里的数据,在最后一次我们做rop重新回到main函数再一次进行利用,泄露出其他数据。由于windows上调用writefile的参数太多了,我们就直接使用kernel32.dll里的LoadLibraryA获得ucrtbase.dll加载地址,然后得到system地址,调用system(“cmd.exe”)来getshell。
根据这里的越界异或,将返回地址改为one_gadget。其中注意到能够异或的值是有限定的,可以异或(7 << (i - 1))的值,如下
1 | 00000011 |
用IDA分析一下,在edit功能里,没有检查length,可以直接溢出
由于是在windows server 2016上,所以堆header有加密,通过伪造header里的flag状态为0,然后设置好fd、bk,unlink即可。经过测试,在这个版本的windows上,可以直接unlink,只需要注意,在windows里fd和bk指向的是堆的content出,而不是header处。
首先,检查一下程序的保护机制
然后,我们用IDA分析一下,在Query的构造函数中,如果我们查询的name存在,则将对应的对象从容易里取出,获得其shared_ptr对象,关键在于调用了shared ptr的get函数,取得了对象的指针值,用这个指针值创建了一个新的shared_ptr对象。漏洞点在于,从一个shared_ptr对象里取得了被托管的对象的地址值创建了一个新的shared_ptr对象,因此,前面shard_ptr指针里的计数不会被传递给新创建的这个shared_ptr对象,因此这个局部的shared_ptr对象析构时,把受托管的对象也给free掉了。
在glibc中,当一个程序调用glibc中的exit函数时,exit函数内部会调用_dl_fini,而_dl_fini函数会调用程序中的fini_array段的函数指针去执行。查看glibc源码如下
1 | void |
我们注意到,有一个函数指针数组的遍历调用执行。我们来看看ld.so中相应的汇编。