泄露地址的方式还是一样的,但不能像栈上一样直接利用格式化字符串改数据。
思路就是因为目标地址不在栈上,也无法直接在栈上写入该地址,那么就找一个与目标地址相似的栈上的地址,改写该栈上地址即可。
技巧:
但是改ret地址中的libc_start_main为onegadget有局限性,有时候要要考虑是否满足条件,才能打通;第二个将printf的got表改为onegadget也是有局限性,但是改为system,然后传参binsh就是可以通杀的。
例题一:Playfmt
main函数:
只初始化了一个输出,没有初始化输入。
程序的逻辑,一个read将数据读入到bss段上0xc8个字节。然后比较是否为quit,若为quit则break然后返回result;如果不写quit的话,则可以触发一个格式化字符串的漏洞。 虽然该格式化字符串漏洞不在栈上,但泄露地址还是一样的。
方法一:
将printf的got表改为system,然后传参binsh,触发漏洞然后getshell。
将printf 的got表里的真实地址改为system的真实地址,然后输入binsh,就会触发漏洞。
gdb调试:
在printf出下断点:
查看栈中情况找偏移:
然后libc start main 减去libc基址即得偏移为0x18647,然后exp中泄露地址的减去偏移则为基址。
system,onegadget地址同理也可得到:部分exp如下
得到system地址后接下来把printf got表地址给改为system地址:
我们知道printf got表地址为:0x8054a010
system地址为:
然后在栈中找相似printf地址的地址:
第一个替身
但是这个只有一个依托的指针,后续写不进去,要找依托指针为3个的,比如ebp处的,那么先改0xff9a6c88指向0xff9a6c7c,
修改成功
依托指针变为3个。然后再改0xff9a6c7c指向的指针0x8048584为printfgot表0x804a010
修改成功。
然后再将0x804a010指向的printf真实地址改为system地址
最终一步一步成功改写printf地址为system地址,最后发送/bin/sh即可。
但是exp中要找两个替身,第一个改print低位2字节,第二个替身改高位1字节 。
方法二:
将返回地址中的__libc_start_main改为onegadget
先泄露地址,方法一样
先通过ebp把链给链起来,将0xffd27e88指向的0xffd27e98改为0xffd27eac
Comments | NOTHING