栈上的格式化字符串漏洞利用

发布于 2023-04-03  319 次阅读


例题一(32位):

一:gdb调试找所需的地址:

1:libc地址

2: 找libc基地址

然后用libc地址减去libc基地址得出偏移。

不论程序中的函数地址如何变化,之间的偏移是不会变的。exp中泄露的libc地址减去这个偏移就是libcbase的地址。

二:复写got表

查看printf函数地址和system地址有几位不一样。

printf_got 与printf_got+2:

也就是说先%6$n改写后俩字节,然后%7$n再改写printf_got+2的后俩字节,最后拼在一起就是改写成system的地址了。

先改写printf_got的后俩字节:

修改成功。

再来修改高位两字节:

之后就能拿到shell。

例题二(64位):

main函数:

方法一:劫持malloc_hook/free hook

修改malloc_hook为onegadget 。

gdb调试:

再找到栈基地址,libc-栈基地址得到偏移,在利用libcbase+libc.symbols['__malloc_hook']即可得到malloc_hookf真实地址 。

方法二:劫持返回地址

在printf处下断点,c之后输入程序所需的 "Hey,siri!",再c运行,再输入”Remind me to“,再查看栈:

栈顶存储的是printf函数的返回地址,printf执行完后会返回到该地址,那么我们可以将该地址覆盖位onegadget,

exp

把发送大量信息触发malloc_hook的给注释掉,劫持返回地址不用触发malloc_hook,rip的地址由gdb调试得到,

随便泄露一个栈地址,然后gdb中对应的栈减去rsp得到偏移,再利用泄露的栈地址减去偏移即为栈顶地址。

例题三:

main函数

printf("%*d",5,10)就是*取5当作宽度输出10,printf("%.*s",3,'abcdef')是.*取3当作要输出对象的前几个字符。

gdb调试程序:

调试payload:

第一个payload:

在fprintf处下断点,c运行到此处。

改写栈链指向第一个随机数的地址

计算相对于输入的格式化字符串的偏移位置,由于是aaaa 第二个参数,fmtarg算出的要减去1。

改写成功

第二个payload:

看下第一个随机数地址的偏移:

栈拉长一点

getshell。

例题四:

main函数:

只有一个printf,需要多次运行。如何多次运行?

可以看出main函数不是第一个执行的函数,main函数执行完退出程序时会执行fini_array内的函数。 ctrl+s查看

如果把这个do_global...............函数改为main函数,那么又可以运行一次main函数。不是无限循环main,gdb源码级调试看原因:

先看下源码级调试的准备工作

先下载源码,编辑gdbinit文件。

加入源码目录后gdb调试执行到这个函数的时候就能看见对应的源码。

开始调试:

可以看到_dl_fini函数会调用fini_array。

####################################################

第一个题快速生成payload

int一次性写入四字节,short 一次性写入2字节,bit一次性写入一字节。工具有局限性,有的题对payload构造有要求,比如对齐程序的字符串。


穿过云层我试着努力向你奔跑