同样的,也仅仅是记录自己学习的记录、思考。
优秀的学习文章
使用realloc函数来调整栈帧让one_gadget生效 | ZIKH26
调试分析
one_gadget失效
这种都需要自己动手调试来看
以经典的libc-2.23的fastbin attack为例
one_gadget libc-2.23.so
edit(2,8,p64(malloc_hook-0x23)) # fake_chunk
add(0x68)
add(0x68)
info_addr("one_gadget",og)
pl = b'a'*19 + p64(og)
#pl = b'a'*11 + p64(og) + p64(realloc+16)
edit(4,len(pl),pl)
debug()
add(0xFF)
这是申请到malloc_hook-0x13处的用户段,然后将__malloc_hook
改为one_gadget
可以看到此时已经成功修改了
然后在 calloc处下断点,单步进去。
跟到这里,发现 call rax
就是要执行我们的__malloc_hook,这里是已经被替换为one_gadget了
然后继续单步进去。
看此时是否满足one_gadget的触发条件。
对于第一个,条件是 rax == NULL
此时的rax,不满足
对于第二个,条件是 [rsp+0x30] == NULL
此时的栈
后面两个同理。
所以,四个one_gadget全部失效。因为,我们需要用realloc函数来调整栈帧。
为什么用realloc来调整栈帧?
原因一
realloc跟malloc类似,也有一个__realloc_hook
,而且__realloc_hook和__malloc_hook是相邻的。
这意味着我们改写__malloc_hook的时候可以顺带改写__realloc_hook,
比如:把__realloc_hook写入one_gadget,然后把__malloc_hook改为__realloc_hook,这样最后还是会执行one_gadget。
原因二
查看 libc-2.23.so
可以发现realloc里面有大量的push指令。
这就可以用来调整栈帧。我们既有push也有sub rsp,38h
可以抬高rsp。
所以可以尝试来调整栈帧后,使得[rsp+0x30]
的值为NULL
具体调整方法
前面提到,我们有的指令都是使得栈抬高的,所以要在原本的[rsp+0x30]
下面(低地址)来找NULL。
然后这里算一下能抬高的最少最高范围。
6个push,一个sub
最大:6 * 0x8 + 0x38 = 0x68
但其实我们还多执行了一个call指令,原本是call one_gadget,但我们改为了call realloc;call one_gadget,
所以多了一次压栈。
所以最大: 0x70
最少就是仅仅多一个call加上sub的0x38: 0x40
例如,对于 [rsp+0x30]
,我们就应该在[rsp+0x30-0x40]
和[rsp+0x30-0x70]
也就是 [rsp-0x40]
~[rsp-0x10]
找NULL
很容易在第二个QWORD就找到0了
所以我们想要少执行一次push,就能够对应上NULL了。
所以从realloc+2
开始即可(跳过一次push)。
本地exp调整后就能够打通了
再用远程测试。
一些思考
正如ZIKH师傅文章提到的,不需要完全的 +2,其实+1,+3这种不完全的偏移都能够成功。
one_gadget的条件是获取shell的充分条件
具体的这里就不探究了,可以看ZIKH师傅的分析。