~~摆了,~~可以参考:
- https://bbs.kanxue.com/thread-272098.htm#msg_header_h3_31
- 高版本的思路,包括libcgot表,_rtld_global的攻击等:https://www.cnblogs.com/LynneHuan/p/17822172.html#:~:text=可以在 Bi
上文的总结对于细节更丰富也更好用,我自己也会参考。我自己写的导演剪辑版实在献丑。堆就没有完全透彻过,原理和做题是两码事,本质很简单但是利用链路很复杂。
Basic:
UAF
free后指针不置空可以再次使用。
Overflow
溢出,这个一般用于篡改size或prevsize域比较多,能溢出fd和bk也行。
Off By One
只能溢出1字节。可以篡改下一个chunk的PREV_INUSE位造成合并等。
Double Free
多次释放同一堆块。接着通过分配可以获得指向同一堆块的多个不同指针。可以类型混淆,也可以获取UAF。
-
对于fastbin chunk,PREV_INUSE永远为1,因此double free会有奇效。同时只检查第一块是否double free。
Overlap
重叠。本质上也是借助上面几个漏洞修改size(向前重叠)或者prevsize(向后重叠)域然后释放。这样就有一个chunk内部的一个额外指针了。(未必)更加细节的介绍
house of Rabbit也是差不多
Leak
Unsorted Bin Leak
unsortedbin中的头部chunk的fd会指向main_arena+88的位置。只有一个chunk的话fd和bk都会指向其中。
tcache leak
用tcache可以泄露堆的起始地址。
其他
类似的放入bin中然后打出内容的思想都可以。
hook
在2.34之前hook没有移除的情况下我们一直可以通过修改mallochook,freehook,reallochook等函数来劫持控制流。一般来说是将chunk分配到这里然后改成one_gadget。比如House_of_Roman中针对2.23的malloc_hook-0x23
地方的fastbinchunk等等
然而实际利用中很多时候我们会发现所有的one_gadget都不满足的情况,这种时候该怎么办?下面是一些思路
-
利用realloc_hook。观察
__libc_realloc
的代码可以发现,前面push了很多参数:
1 | .text:00000000000846C0 ; __unwind { |
realloc调整栈帧og触发,或者利用其他环境触发malloc包括doublefree异常–strdup等
realloc的意思是,我们在malloc_hook处填上realloc的地址,而在realloc_hook处填上one_gadget的地址,利用realloc调用前的这段push参数对栈帧进行微调。
一些常识:
1 |
tcache最多64个,每个最大连接7个chunk。下标就是按malloc_align分,以64位为例,0-24大小的对应idx0,25-40对应idx1,41-56对应idx2依次类推每个+16。然后32位就是0-12,13-20这样。
1 | DEFAULT_MXFAST 64 (for 32bit), 128 (for 64bit) |
Glibc 2.23
无tcache,检查较少,很经典
arena attack(House of Mind & House of Gods)
实战利用价值小,看个乐
House of mind
伪造arena,blog没写,是一种通过伪造arena从而将释放的chunk连入假arena的过程,利用比较抽象而且最后似乎还没有任意写。
House of Gods
利用arena结构体中的数据和错位实现在main_arena中构建一个chunk进行写入,然后篡改arena的next指针将堆变成我们自己的arena来劫持整个堆。具体参见How2Heap3,虽然非常复杂没什么用但是可以看看这个堆风水的过程,非常的神必,有助于理解main_arena的结构:
-
泄露unsorted bin 头的地址,malloc一个smallchunk然后直接读。通过free+malloc(intm)启动遍历过程,将位图置位。这个时候我们让bin[0]作为伪造的size域存在。此时它是0x200.
-
首先将smallchunk放回unsortedbin中。用上面的leak在main_arena内寻址。利用UAF修改smallchunk的bk,在unsortedbin里面链接上这个伪造chunk。
-
利用malloc_state的特性,修改fastbin chunk的bk字段然后将其释放,控制其在malloc_state的开头,接着作为一个伪造的bk字段存在,链接到INTM。巧妙至极。
这时候的unsorted bin:head->smallchunk->binmap[last](伪造的)->main_arena的开头(由于next指针开始就是指向本身的)->fast40->INTM
-
将binmap chunk作为一个“chunk”取出。得到了写入main_arena(即便是部分)的权限!开始为触发
reused_arena()
的条件铺路。 -
接着UAF改INTM的bk,让INTM后面再连接上narenas字段。然后取出INTM触发unsortedbin attack,将narenas写为一个大数。同时用binmap chunk,改掉system_mem字段。
-
用binmap chunk将arena的next指针随便写成你想分配的地址
-
连续调用两次
malloc(0xffffffffffffffbf + 1)
,arena直接全部hijack掉。 -
随便操。
Top chunk related attack(House of Force & House of Orange)
利用topchunk的一些特性达成我们的目的。House of Force可以实现任意地址分配,House of Orange可以实现不调用free情况下的一次释放。
House of Force
见How2Heap3
将top chunk的size域改到极大,然后通过分配evil_size的chunk将topchunk推进到我们想分配的地址,随后下次分配就会从top中切出我们指定地址的chunk。
-
其中top的size一般写成-1,evil_size的计算如下
new_top = old_top + nb
nb = new_top - old_top
req + 2sizeof(long) = new_top - old_top
req = new_top - old_top - 2sizeof(long)
req = dest - 2sizeof(long) - old_top - 2sizeof(long)
req = dest - old_top - 4*sizeof(long)
House of Orange
见How2Heap4
神中神,适用于没有free的情况。通过先改小top chunk的size域然后申请一个较大的chunk来触发sysmalloc中的brk扩展,就会将旧的top放进unsortedbin中。
-
top的size需要页对齐,动调确定,一般改为0xfe1然后申请0x1000刚好。
-
新申请的会放在新的内存页。
-
【glibc 2.23】借助unsorted bin attack改写IO_LIST_ALL为unsorted(av)后将old top放入smallbins[4](改写size为0x61)从而实现用伪造chunk链接至IO_list_all触发fsop。
Fastbin(normal, house of spirit, House of Rabbit)
Normal fast bin attack:
将一个fastbin分配在我们想要的位置。通过劫持已在fastbin中的一个chunk的fd指针来做到这一点。
-
会检查size域,需要提前伪装。
-
分配在malloc_hook或free_hook的话经常配合0x7f的字节错位来伪造size域
-
UAF和Double free,fastbin在2.23中只检查头部是否double free从而我们可以用dup来实现Write after free
House of Spirit
伪造fastbin的chunk。通过free放入bin。需要注意:
-
边界0x10对齐
-
size域大小合适,满足fastbin要求
-
next的地址不能是top,而且size要正常(不用必须是fastbin)
House of Rabbit
参考
针对consolidate不严格检查size的fastbin attack. 要能修改size域并且有触发consolidate的条件
-
修改size,然后触发consolidate变成overlap。
-
修改fd然后触发consolidate将fake_chunk放入bin中变成合法chunk(注意伪造size)
Unsorted Bin Attack
参考
利用Unsorted Bin取出chunk时候的这个特性(双向链表,bk遍历):
1 | bck = victim->bk; |
控制住unsorted bin中的下一个会取出的chunk的bk域,我们就能将一个大数(unsorted_chunks(av)
)写入我们想要的地址,由于是fd偏移,所以将chunk中的bk写成targetaddr-16即可。可以用于篡改循环次数或GLOBAL_MAX_FAST
等。
House of Lore(Small bin attack)
参考
smallbin attack。一个UAF改一下smallchunk的fd就是任意地址fakechunk分配。只要能绕过smallbin分配唯一的检查就行
1 | if (__glibc_unlikely (bck->fd != victim)) |
Large Bin Attack
参考
利用large bin的指针将指定地址的内容写成一个合法的large chunk的地址。将已经在largebin中的chunk的bk或bk_nextsize篡改为target-16、-32即可实现在下一次victim放入largebin时触发将victim写入target的效果。
-
从 unsorted bin 中来的 large chunk 要紧跟在攻击过的large chunk后面,也就是要连在一个bin里,大小也要相邻。
-
可以篡改io_list_all进行fsop
-
可以帮助tcache smash unlink?
COMBO FISTS (House of Roman, House of Storm)
House of Roman(组合拳,getshell思路很常用而且允许爆破, Fastbin atk + Unsorted bin atk)
参考
通过分配一个malloc_hook附近的chunk(确切的说是在malloc_hook-0x23
处获取一个fastbinchunk)写入one_gadget。
这个思路是非常好的,只要是2.23并且任意地址分配chunk就可以用来getshell。有libc地址最好,没有也没关系借助unsorted bin attack+爆破来实现。
原poc的流程如下:
-
拿一个0x60的fastbin chunk 1(实际大小0x70)
-
分配一个不用的chunk,大小0x80,实际大小0x90,此时相对堆基址的偏移来到了0x100,这灵性的一步是为了待会我们改一个字节就能修改指针指向的chunk
-
分配一个0x80的chunk 2,等会放入unsorted bin,chunk2的地址此时是0x100对齐的
-
分配一个0x60的fastbin chunk 3,该chunk的偏移地址来到了0x190
-
释放chunk2,放入unsorted bin,此时其fd和bk存有main_arena+0x68
-
取0x60大小的chunk4(fake_libc_chunk),会从chunk2中进行分割,带有main_arena地址
-
读取取出的chunk4,泄露main_arena地址然后计算偏移获取malloc_hook
-
释放chunk3,放入fastbin
-
释放chunk1,接入fastbin链表头,其fd指向chunk3(0x190)
-
模拟一个UAF,写chunk1的fd一字节0x00将其fd指向0x100的chunk2(chunk 4)
-
写chunk4,修改低位地址令其fd指向目标地址
-
最后将fastbin中的chunk1和3取出,再次取就取到了malloc_hook-0x23处的chunk
House of Storm (unsorted bin atk + largebin atk)
BLOG没有写懒得补了写在这里,该技术实现任意地址chunk分配
2.26-2.28 需要tcache填满,再往后该漏洞不可用这个技术最关键的一步是largebin attack将fake_chunk地址写上一个堆地址,而且非常巧妙的利用了一个字节错位将其作为了size。下面是POC的流程
-
准备一个unsortedbin堆块一个largebin堆块,其中unsortedbin中的堆块要比largebin中的大 (还要防止top合并)
-
将unsortedbin的地址进行一下处理,算出一个移位偏移量。
-
将unsorted bin的chunk bk写为fake_chunk,将large chunk的bk写成fake_chunk+8
-
将large chunk的bk_nextsize写成fake chunk-0x18-shift_amount,shift是我们先前的偏移
-
利用一个large_bin attack将unsorted chunk的地址写入一个恰当的位置正好伪造出fakechunk的size
-
申请相应大小(堆地址高8位?)即可获得fake_chunk
House of Einhejar——off by null
参考
仅需off by one就能工作。控制住当前chunk的末8字节(prev_size写成evil_size,差值)然后溢出修改掉下一个chunk的PREV_INUSE位。然后通过free下一个chunk触发合并后,下次分配就能从指定地址取chunk了(prev_size错误合并,overlap)。
-
由于off by one,最好溢出的下个chunk的size是0x100对齐的,便于改写
-
fakechunk的size要和我们修改的prev_size一致
Unsafe Unlink
利用Unlink实现overlap或指定地址写(确切地说是将target写成&target-0x18)。但是这个POC中利用所需要的前置条件较多…需要同时修改被unlink的chunk的fd和bk以及下一chunk的prevsize和PREV_INUSE位,要求太高了。
glibc 2.27
这个版本首次引入了tcache
下面会着重涉及tcache相关的攻击,同时大部分上面的攻击技巧都要和tcache打交道,比如先填满7个。
Fastbin
同上,只是每次要先填满对应大小的7个tcache
tcache
Same as fastbin
和fastbin一样只不过更简单(没有了fastbin szie检查)。包括double free,house of spirit,tcache poison(对应fastbin attack)等。
tcache stashing unlink attack
在有tcache的情况下替代unsorted bin attack实现任意地址写一个libc地址。同时还能构造fake chunk(任意地址chunk分配)。
-
tcache空两个,拿到两个small bin和一个small bin的UAF,fake_chunk的bk写入target
-
修改后释放的smallbin块的bk为fake_chunk地址,calloc触发写入攻击,target被改同时tcache头部会链入fake_chunk
-
下次malloc会返回fake_chunk
House of botcake
double free实现任意堆块分配。
-
用0x110的堆块填满tcache,然后再释放两个相邻的0x110堆块(先a后b)放入unsorted bin并导致合并
-
取出一个0x110的chunk(从tcache),然后再次释放上一步中的a块,a块此时被放入tcache,这里形成了一个重叠
-
分配一个0x130的堆块,这会从unsorted bin中合并好的块切割,而这时候我们取得的这个chunk可以拿来修改tcache头部的a块
-
修改fd后malloc两次即可
glibc 2.34+
Glibc 2.31 House of Pig
House of Kiwi
House of Apple
一种思想。在glibc 2.34+的版本中已经没有了malloc_hook这种函数让我们一次就能getshell。堆利用的思想更多的集中到了FSOP上。
v1
v2
参考How2Heap实战——强网杯2024babyheap的板子用一次largebin attack将io_list_all劫持,然后将vtable换成wide版本来让内核从wvtable找函数调用从而规避检查,*(wdata+0xe0)+0x68就是能劫持控制流的地方。
值得注意的是,在我们劫持的时候,rdi中存放的是fp的地址(也就是我们劫持到的堆地址,借助一些gadget以及setcontext这种我们能够控制几乎所有的寄存器,只要堆上布局合理。
在setcontext最后会将[rdx+0xa8]的内容push到栈上然后ret,这也是我们ROP链路的开始。
v3
House of Banana
攻击_rtld_global的一种方法。劫持rtld_global到可写堆块后通过伪造程序基地址或者finiarray的办法,让程序在调用exit()退出的时候执行我们想要执行的函数。
rtld_global的第一字段是linkmap结构体的地址,无论是伪造linkmap还是篡改本来的,再或者改掉程序基地址,我们最终是要让