2019 中关村第三届新兴领域专题赛网络与信息安全专项赛 pwn writeup
0x01 one_string
程序分析
如图,32位程序,静态链接的,啥保护都没开,还有RWX(可读可写可执行)段,现在真是不常见了。
程序是静态链接的,功能上属于典型的堆题的记事本形式。简单调试识别后可以识别出主要的函数名。程序提供了add、delete、edit的功能。主要函数如下:
main函数
add功能函数
delete功能函数
edit功能函数(存在漏洞)
红框的位置,如果add时申请content的大小是4字节对齐而非8字节对齐的大小,如0x1c这样的size,会存在内存复用,即下一个chunk的pre_size字段会给0x1c大小的这个chunk借用。那么如果edit时输入0x1c长度的字符串,字符串就会和下一个chunk的size字段连起来,这样sizeof()时,得到的new_size就会比原来的size要大1个字节或2个字节,取决于下一个chunk的size。这样就能够造成堆溢出。
漏洞利用
我们可以通过上面edit函数中的漏洞做一个unlink,然后就可以控制到结构体列表,控制列表后就实现了任意地址写。接着往下图中具有可读可写可执行权限的.bss段中写入shellcode。
我们注意到,main函数中输入4会调用exit()函数退出,而exit()函数会调用到程序中的**.fini_array中存放的指针指向的代码。因此将shellcode所在的缓冲区地址写入到.fini_array列表**中,main函数中输入4就可以触发shellcode读取flag了。
由于本题赛场环境时远程是不可以保持连接的,所以shellcode要用open、read、write三个系统调用来读取flag并一次输出。详细的操作请看以下EXP,结合调试很容易就能明白。
完整EXP
题目原题是加了一个base64限制的,就是说要把payload用base64编码后一次性发过去,稍微修改一下下面的EXP,将payload存储到一个字符串里,编码远程发过去就行了。写本文时是本地利用的,因此这里的EXP删去了远程的部分,方便阅读复盘。
1 | #-*-coding:utf8-*- |