同样的,也仅仅是记录自己学习的记录、思考。
优秀的学习文章
使用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师傅的分析。



















