-
-
[原创]看雪.TSRC 2017CTF秋季赛第七题 pwn_Ox9A82
-
发表于:
2017-11-6 12:50
3998
-
[原创]看雪.TSRC 2017CTF秋季赛第七题 pwn_Ox9A82
第六题真可怕,还好放弃的早。。。佩服做出来的大佬
第七题由于是作者自己实现的内存分配机制,所以描述起来比较麻烦,贴了很多图。其实没有那么复杂。
拿到程序后,还是按照流程先用pwntools
检查一下,结果如下。
可以看到程序是64位的,可以改got表,有栈保护,有NX,没有PIE。虽然开了NX保护,但是并没有什么用,还是可以用shellcode,后面会说到。
然后先跑一下程序,了解一下基本流程。进过几次测试之后,很幸运的发现一个使程序崩溃的漏洞,虽然不知道漏洞详情,但能崩溃就有可能导致代码执行。
pwn题的逆向一般会简单很多,因为里面会有很多字符串,而且考点也不是逆向。只挑和漏洞有关的几个函数说一下。
首先main很简单。
在函数init_game
里面,用函数mmap_mem
分配了一块内存,将这块内存的首尾地址保存在了两个全局变量mem_start, mem_end
中,然后又保存了一个top_chunk
指针,用于作者自己实现的mymalloc
函数分配内存。
在往下看,到mmap_mem
函数里面,就发先一些问题了,函数mmap
分配的内存是可读、可写、可执行的。这也就是NX保护没有用,可以使用shellcode的原因。
在注册、登陆之后,主要循环如下。
其中的cheat
函数存在问题,如果是首次cheat,会分配一块大小为48字节的内存,前16字节作为name,后32字节作为content。然而再次cheat的时候,读入content的最大长度为300,这显然是个漏洞。
现在来看一下为什么登陆两次会发生崩溃。
在signup的时候,程序会分配一块48字节大小的内存,并调用set_buf
函数来使全局变量userinfo
指向这块内存。当再次signup的时候,程序又分配一块新内存,然后将全局变量userinfo
指向新的内存,并对原来的那块内存进行一次应该是类似于free
但是很奇怪的操作。
下面来看一下maybe_free
和与之相关的几个函数。
首先是set_buf
函数,它调用了maybe_free
函数。
然后是maybe_free
函数本身。
再然后是find_valid_addr_in_chunk
函数。
再然后是valid_address
函数。
最后是add_to_array
函数。
用图解释一下add_to_array
做了什么
弄清楚这几个函数之后,就可以搞清楚崩溃的问题了。
maybe_free
函数调用find_valid_addr_in_chunk
函数在要释放的内存中找出它认为是指针(也就是找它认为合法的地址)的字段,然后将这个指针指向的chunk地址保存到一个全局变量free_array
指向的数组里,这个数组也是通过myalloc
函数分配的,然后将数组的当前地址保存进上述指针指向的位置。一开始输入的用户名weizi
变成64为整数为0x697A696577
,正好是程序认为的合法地址,但是这个地址又不可写,所以造成了崩溃。可以利用这个漏洞来写got表。
在写exploit之前,还需要了解一下数据结构
利用的思路是首先用printf
的got表项地址作为用户名signup,然后login并cheat一次。退出后再signup一次,将printf
的got表项改为free_array
指向的数组的地址。最后用cheat把shellcode写入数组的位置,并触发对printf
的调用。
第一次signup,login,cheat之后,内存布局如下:
再signup,login之后,内存布局如下
接下来,只要再一次用cheat来把shellcode写入array的位置,并触发printf就可以了。我选取的是函数show_my_status
来调用printf
,还有一点需要注意的是在show_location
函数里面用到了userinfo->characterinfo->location
,如果location不合法会退出,所以在覆盖new_usrnf
的时候要稍微注意一下。
只需要signup,login,cheat,show_my_status四个操作就可以拿到shell。
最后得到的flag为flag{Cr4k4ndH4ckF0rFunG00dLuck2o17}
。
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!