做题的时候有考虑过CVE,但当时没去查……
CVE–2018-1000001
该题思路来源于glibc的CVE–2018-1000001,是一个glibc的缓冲区溢出漏洞,分析后发现能在堆上进行溢出。
以下分析stdlib/canonicalize.c中的__realpath()函数(__canonicalize_file_name仅仅调用__realpath(),没有其它操作)。
| 1 | /* Return the canonical absolute name of a given file. | 
从源代码中可以发现,如果getcwd返回的地址不以/开头的话,就会产生堆的上溢的问题,同时能够向这个上溢的地址写入数据。
easyexp
本题的原理即__canonicalize_file_name。在本题中,由于程序变更工作目录后,并没有更新当前目录的根目录,因此getcwd() 会在返回的路径前加上(unreachable),即getcwd()在本题中返回(unreachable)/tmp。随后为了保证程序正常运行,需要通过__lxstat64()的检查,所以需要保证(unreachable)/tmp存在,故将用户名设置为(unreachable)并在该文件夹下创建名为tmp的文件。
由于存在堆上的前溢且程序构造了堆的使用,因此可以修改chunk的pre_inuse,利用unlink获得shell。
程序创建文件的过程
在程序中定义了如下数据结构:
| 1 | struct FILE_CACHE { | 
在bss上存在一个FILE_CACHE[3]数组用于保存相关信息。
| 1 | if ( filename ) | 
以上程序位于创建文件的函数中,当用户创建文件时,会现在“缓存”中查找,如果文件名相同或“缓存”未满,则会在“缓存”上保存一份数据,如已满则重置一个“缓存”。这里的结构可以在unlink中进行利用。
程序创建文件夹的过程
| 1 | for ( i = 0; ; i = *(_DWORD *)v3 + 1 ) | 
当程序调用mkdir()函数后,会将用户输入的路径传入canonicalize_file_name()进行验证是否创建成功,此处即为触发漏洞的位置。
利用思路
当“缓存”满后,将会重用最后使用的“缓存”的下一个“缓存”。首先将三个“缓存”都填满,第二个缓存内容均为’/‘,利用CVE漏洞改写第三个“缓存”指向的内容的chunk的size域,将size改小(防止和top chunk合并)并布置合适的fake chunk。
随后进行unlink攻击,通过改写“缓存”结构体中的内容指针来泄漏地址和修改__free_hook。
Exp
| 1 | # coding=utf-8 |