HouseofHusk
本质是利用一个存在于printf
中的hook
。
但是这个hook和下图中libc中puts等函数的hook又不同。这里的puts是由于libc没有开启FULLRELRO导致的,也就是利用libc里面的got表hook。
而houseofhusk
里面所说的printf
的hook
,是利用glibc
开放的一个自定义格式化格式化的接口。原理是检查__printf_function_table
,如果这个值不为空,说明有开发者自定义的格式化字符。比如我要自定义一个%a
,然后让printf
在遇到%a
的时候去执行我指定的函数。那么glibc
会在__printf_arginfo_table[61]
(这个61是%a
中a
的ascii
码)的位置上放一个我指定的函数指针,然后去call
这个函数指针.
HouseofHusk使用结论
为了更轻松的记住HouseofHusk
的机制及使用情景,下面是HouseofHusk
使用结论的简单总结.
1.__printf_function_table
的值不为空。
2.__printf_arginfo_table
被覆写为一个可写地址。
3.在__printf_arginfo_table[x]
上写上我们的gadget
或是别的要调用地址。(x
为程序中printf
所调用的格式化字符的ascii码
)
4.缺陷是无法做到调整参数,基本只能搭配one_gadget
使用.
5.优点是触发条件简单,比起io
的各路神仙满天飞,这个触发条件还是可以接受的。
例题
libc
版本2.31.程序几个关键点如下
1.只能申请0x500-0x540
大小的堆块,但无次数限制,同时最多存在5个未被释放堆块。
2.第一次释放堆块有uaf
,以后的释放堆块都没有uaf。
3.只有一次编辑堆块的机会(看着似乎难度很大,但是实际上要编辑哪个堆块大不了就释放了在申请一次就行。这个编辑堆块本质上是给uaf
的那个堆块用的)
4.show
函数只有一次机会,并且只展示堆块的前十个字节(相当于是必须把uaf
的那个堆块调成fd和bk
一个为main_arena
,一个为堆地址
,然后一次拿下libc_base
和堆基地址
了,不过调一下风水还是可以做到的)
5.还有一次任意地址写一字节机会。
思路
任意地址写一字节机会给__printf_function_table
,largebinattack
打__printf_arginfo_table
,在上面写上一个堆地址。然后调整堆风水,在__printf_arginfo_table['s']也就是__printf_arginfo_table[0x73]
的位置写上one_gadget
。最后引导程序流走到上图所示的LABEL_15
执行printf("%s","GoodBye!")
触发我们的自定义格式化字符成功getshell。
largebinattack
之前对于largebinattack
一直半懂不懂的,这次也是刚好花时间整理了一下。
下面是glibc
的源码部分,问题出在
victim->bk_nextsize = fwd->fd->bk_nextsize;
fwd->fd->bk_nextsize = victim->bk_nextsize->fd_nextsize = victim;
这两行,其中没有对fwd->fd->bk_nextsize
进行检查,所以这个新进来的堆块victim
的bk_nextsize
会被赋值成fwd->fd->bk_nextsize
,也就是我们覆盖的bk_nextsize
.
然后在下一步,在victim->bk_nextsize
所找到的错误的地址再去->fd_nextsize
也就是+0x20
上面写上victim
的地址。
largebin使用结论
为了更轻松地记住largebinattack
机制及使用方法,下面是使用结论的简单总结。
一个大小为x的largebin
,其bk_nextsize
被改为地址y
。
当一个大小为z
的堆块进入largebin
,并且大小z和x
属于同一组largebin
,bk_nextsize+0x20
的地址会被写上新进入的这个堆块的堆地址。
测试demo
写了个demo
练练手。可以配合本地环境编译之后逐步调试试试。