Linux pwn入门教程(6)——格式化字符串漏洞

本文是Linux pwn系列教程的第六部分,专注于格式化字符串漏洞。通过实例,介绍了如何利用该漏洞实现任意地址读写,以及如何在64位环境下进行利用。此外,还探讨了如何避免程序无限循环以及相关的漏洞缓解机制,如RELRO和FORTIFY。
摘要由CSDN通过智能技术生成

作者:Tangerine@SAINTSEC

0x00 printf函数中的漏洞

printf函数族是一个在C编程中比较常用的函数族。通常来说,我们会使用printf([格式化字符串],参数)的形式来进行调用,例如

char s[20] = “Hello world!\n”;
printf(“%s”, s);

然而,有时候为了省事也会写成

char s[20] = “Hello world!\n”;
printf(s);

事实上,这是一种非常危险的写法。由于printf函数族的设计缺陷,当其第一个参数可被控制时,攻击者将有机会对任意内存地址进行读写操作。

0x01 利用格式化字符串漏洞实现任意地址读

首先我们来看一个自己写的简单例子~/format_x86/format_x86


这是一个代码很简单的程序,为了留后门,我调用system函数写了一个showVersion().剩下的就是一个无线循环的读写,并使用有问题的方式调用了printf().正常来说,我们输入什么都会被原样输出


但是当我们输入一些特定的字符时输出出现了变化。


可以看到,当我们输入printf可识别的格式化字符串时,printf会将其作为格式化字符串进行解析并输出。原理很简单,形如printf(“%s”, “Hello world”)的使用形式会把第一个参数%s作为格式化字符串参数进行解析,在这里由于我们直接用printf输出一个变量,当变量也正好是格式化字符串时,自然就会被printf解析。那么后面输出的内容又是什么呢?我们继续做实验。
我们直接在call _printf一行下断点然后以调试方式启动程序,然后输入一大串%x.,输出结果如图


此时的栈情况如图


我们很容易发现输出的内容正好是esp-4开始往下的一连串数据。所以理论上我们可以通过叠加%x来获取有限范围内的栈数据。那么我们有可能泄露其他数据吗?我们知道格式化字符串里有%s,用于输出字符。其本质上是读取对应的参数,并作为指针解析,获取到对应地址的字符串输出。我们先输入一个%s观察结果。


我们看到输出了%s后还接了一个换行,对应的栈和数据如下:


栈顶是第一个参数,也就是我们输入的%s, 第二个参数的地址和第一个参数一样,作为地址解析指向的还是%s和回车0x0A。由于此时我们可以通过输入来操控栈,我们可以输入一个地址,再让%s正好对应到这个地址,从而输出地址指向的字符串,实现任意地址读。
通过刚刚的调试我们可以发现,我们的输入从第六个参数开始(上图从栈顶往下数第六个‘000A7325’ = %s\n\x00)。所以我们可以构造字符串”\x01\x80\x04\x08%x.%x.%x.%x.%s“。这里前面的地址是ELF文件加载的地址08048000+1,为什么不是08048000后面再说,有兴趣的可以自己试验一下。
由于字符串里包括了不可写字符,我们没办法直接输入,这回我们用pwntools+IDA附加的方式进行调试。


我们成功地泄露出了地址0x08048001内的内容。
经过刚刚的试验,我们用来泄露指定地址的payload对读者来说应该还是能够理解的。由于我们的输入本体恰好在printf读取参数的第六个参数的位

  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值