这道题目比赛的时候思路卡住了,有两个其实很简单的点都没想到,不然初赛战队就能第三名拿钱了。
题目分析
GLIBC2.27,符号表都没去,就是add,edit,show,delete,exit。malloc返回的指针存在数组里。漏洞明显的不能再明显了,add申请一个size,edit没检查,任意溢出。然后show就是printf %s的泄露,exit调用了libc中的exit函数。
但是这个free比较幽默,是这样的:
1 | void __cdecl freechunk() |
稍微看一下就能发现,这个free乱搞了半天完全是自己忙活自己的,所有内容都是函数的局部变量,input都是自己初始化的,问了copilot说这是个rc4的加密算法,不过没什么用就是了。再观察一下就能发现程序根本就没链接到free,没有free的符号。调的库就puts,这里面的strlen还有malloc。
除了没有free以外,edit有个很有意思的地方。在edit之前,会检查这个chunk指针的地址。定位一下可以知道,这两个地址分别检查了mallochook以及前面的0x3000和linkmap中的两个"exithook",即在exit的时候会触发的两个函数指针。(发现mallochook不能用就第一时间上网找利用方式就看到了这个,结果也ban了…)。
1 | bool __cdecl checksanbox(char *ptr) |
这里有个伏笔↑,后面会说
没有free我们怎么做?
首先没有free一定是houseoforange的前半步了,glibc2.27 ban了House of Orange的后半段,但不影响拿free块。同时在unsortedbin之后再切割就能拿libc。
1 | evil_size=0xd91 |
这道题虽然不用,但是还有一个重要的点是,这里**一块就能泄露libc和堆地址了。**比赛的时候试着打堆地址有0截断出不来,但是其实有个关键细节想错了,就是这个用orange拿到的堆块并不更新lastremainder,它没有被切过,此时lastremainder是0,也就是说分配0x1000这个largechunk之前会跑一次循环,把这个堆块放进largebin!也就是说这个块里面会同时有我们的堆和libc地址,申请出来的可控chunk也是都有的,只需要泄露libc后将fd和bk填充上再泄露就不会0截断了,把fdnextsize打出来就有heap地址了。
第二步呢?
orange只能给我们一个free堆块,常规手段应该就到这了,比赛就卡在这里。按学长和WM的wp走的话这里有两种思路:
-
复读!
-
House of Force
先来说第一种,这道题是任意溢出,完全不检查,因此我们申请出的第二个0xe10的chunk应该是新的top切下来的,那我们从这溢出新的top再free不就有新的堆块了?而且这个堆块的size我们可以任意控制,由于没有free我们不好构造fakechunk进行操作,最好的办法肯定是劫持到tcache,因此把size改到最小的对齐然后拿到tcache,2.27的tcache基本是四处漏风:
1 | edit(1,0xe10,b'a'*0xe08+p64(0x1f1)) |
然后第二种,目前不清楚有没有什么限制,没有的话看wp的步骤也是一种很好用的方法,是利用整数溢出的houseofforce把top抬高到我们想要的位置。当然这道题要想任意地址分配的话还是得走tcache,这里拿到tcache perthread struct的控制权然后随便找个合适的size写入也能达到任意地址分配的目的。
1 | add(0xB60)# 3 取走bin里的chunk |
下一步…
最幽默的一集来了,回收伏笔:
1 | bool __cdecl checksanbox(char *ptr) |
注意这个malloc,他妈的他这边在mallochook这没有等号!也就是说只要返回的指针恰好是mallochook就没问题了。。。tcache里面直接写mallochook然后返回写入onegadget直接getshell
这里比赛当天还尝试在mainarena附近用house of lore打chunklist,看来想多了,确实是ezheap。这下知道house of orange的妙用了。