今天来康康这道题gyctf_2020_document
静态分析确定漏洞类型
经典的堆菜单题,保护全开,2.23的libc。保护全开意味着got表劫持不了。增删改查四样动作都有,并且没有那种虚晃一枪(例如show函数直接给你puts一个too young too simple之类的)的函数。
先看add函数,malloc了两个堆块,都是固定大小,一个堆块是0x20大小,另一个是0x90大小。然后第二个堆块的指针存在了第一个堆块上面。第一个堆块后八个字节用来存了性别,性别要么1要么16,是通过判断你输入的是否为W来决定的。之后就是那个0x90的大堆块上面存一个名字,中间间隔一个flag,然后堆块偏移0x10的位置上面放上你要输入的内容。
看看delete函数,存在明显 的UAF漏洞,可以操作free的堆块。并且只free 0x90的堆块而0x20的堆块不会free。那么通过这些分析我们就可以先add两个堆块,free掉第一个之后show第一个就能泄露出libc的地址。
其它的中规中矩,唯独edit函数正常情况下它每个堆块只允许edit一次,但也只是因为那个0x20堆块的后面的那个flag原因。
泄露libc地址
这里建议,name强制8位就不要想这么多直接给/bin/sh;
就完了。
1 | add(b'/bin/sh;',b'W',b'a'*0x70) |
得到libc地址
确定攻击思路
构造堆重叠以此能修改0x20堆块上面的指针到free_hook
去覆盖free_hook
为system函数,再free一个带有/bin/sh的堆块就可以getshell,此时bin中已经有一个0x90的unsorted bin
,再次add一个因为先分配了这个0x20的堆块,unsorted bin
就会进行切割,但是edit 0发现它在0x10偏移上edit的,因此不行。不行咱就再换一个嘛,再add一次,此时的unsorted bin
会进入smallbin,但是不影响,还是从上面切割下来作为第四组的小块。然后edit第0个块把这个块的指针改成free_hook
。此时第四个堆块的指针被改成了free_hook
,那么此时再edit 3为system即可。实际测试需要考虑它在读数据之后会写在那个指针偏移0x10的地方写数据,所以前面我们edit的时候也把它改成free_hook
-0x10。最后edit 3 为system函数。由于这个输入是for() read(0,buf,1)读取的,因此0x70个字节必须写满,那边由于都是hook,我们都清空较为保险,因为万一不小心调用到了那边的hook很容易crash,那么exp根据以上思路很容易得到了。
exp
1 | from pwn import * |