跳转至

Latest

latest

如果要做堆,建议把对应版本的源码&带调试符号的libc都下载下来,然后在gdb里面使用dir xxx/src/malloc,就可以带源码调试,在crash的时候就可以判断出是什么检查没有通过(详情请看葵佬的视频)

修:

打开发现main十分丑,首先是有一个神秘的call,其实出现这个的原因是ida分析出错,实际函数起始地址在0x1289,解决方法是跳到sub_1288把它先Undefine,然后在sub_1289的地方重新定义为code,再create function,就能够恢复正常

image-20210919212112358

switch也坏了,可以参照https://www.cjovi.icu/mess/1345.html修复跳表,修好再改改名之后大概长这样:

image-20210919212814325

然后随便进一个函数,发现里面乱七八糟:

image-20210919212933244

其实是因为我自己定义了一个头部,仔细观察可以还原出大概的结构:

image-20210919213231115

如果希望在ida里面能正确显示出struct结构,可以参考https://thinkycx.me/2019-07-15-how-to-create-structs-in-IDA.html

改好之后好看了很多,可以正常阅读了:

image-20210919214205532

整个程序的逻辑十分简单,就是标准菜单题,提供add,edit,show,rm四个功能,其中有问题的就是rm里面free的时候没有把ptrs里存的指针清空,导致UAF

本题glibc版本是2.34(可以直接运行libc.so他会输出版本信息,或者用strings),有tcache(自2.26),有safe-linking(自2.32),没有malloc_hook/free_hook/realloc_hook..(自2.34)

关于tcache的内容可以参考https://ctf-wiki.org/pwn/linux/user-mode/heap/ptmalloc2/tcache-attack/,利用过程十分简单,可以视为简化版的fastbin attack,在2.26时几乎没有检查,在后续版本中增加了double free检测、cnt检测(记录对应bin里有多少个chunk)、safe-linking、内存对齐检测

由于我们这里有UAF,考虑直接修改tcache的next来实现任意地址分配,所以我们需要绕过safe-linking

safe-linking:

 339 #define PROTECT_PTR(pos, ptr) \
 340   ((__typeof (ptr)) ((((size_t) pos) >> 12) ^ ((size_t) ptr)))
 341 #define REVEAL_PTR(ptr)  PROTECT_PTR (&ptr, ptr)

逻辑就是把next/fd与当前chunk所在地址左移3个字节的结果异或,在查找bin上下一个chunk的时候再异或一次获得真实地址

所以如果要想实现任意地址malloc,需要leak出堆地址,或者更简单地,当某个tcache bin里面只有一个chunk的时候,这个chunk的next正好就是它的key

ps:pwndbg至今仍未修复存在safe-linking时bins命令显示错误的问题,gef则已经实现,且gef在无libc调试符号的情况下也能分析堆内存,可以考虑尝试一下(不过有点丑

pss:如果遇到pwndbg调试glibc2.34 heap命令直接失败的问题,可以试着更新到最新版本,因为某些符号发生了变化,参见https://github.com/pwndbg/pwndbg/issues/952

在这题里面我们只需要利用UAF,然后show一下就能得到异或用的key

在libc地址的leak上,由于程序对于申请的堆块大小基本没有限制,可知直接申请出unsorted bin大小的chunk,然后show即可得到libc地址,具体参考https://ctf-wiki.org/pwn/linux/user-mode/heap/ptmalloc2/unsorted-bin-attack/#leak_1

地址我们都有了,现在就可以直接tcache attack打了,但你如果试着按照套路申请到__malloc_hook的位置,写入onegadget地址,你会发现并不能getshell(或者 __free_hook改为system),原因是新版本的glibc 2.34直接把__malloc_hook/__free_hook/xx_hook从libc主体里面删除了,移动到了libc_malloc_debug.so,正常程序并不会链接,libc主体里虽然保留了符号,但已经对实际代码执行不会产生任何影响了(参考https://sourceware.org/git/?p=glibc.git;a=blob;f=NEWS;h=3c610744c97c5cd0d4955a2f105338833d926474;hb=ae37d06c7d127817ba43850f0f898b793d42aea7#l174)

所以我们需要换个思路,重新回到栈上修改程序执行流,经过一番搜索(或者看了一眼hint(((),可以发现glibc里面有一个environ,里面存的是一个栈上的指针,实际上是指向当前程序的环境变量,我们可以申请到这个位置然后show就能leak栈地址

接下来gdb调试一下,找到和返回地址的偏移,然后tcache attack申请到栈上,造ROP链即可

这题环境我搭的可能有点问题(,如果用system打远程会打不出来(还没搞清楚为什么),我的exp是用gadget调整寄存器内容,调整成符合one_gadget条件的值,就可以打通了

源码&exp:https://git.hit.edu.cn/lilac-2021-tryout/pwn-problems/-/blob/master/pwn-latest/src