Format String¶
约 766 个字 21 张图片 预计阅读时间 4 分钟
任务 1:使程序崩溃¶
首先我们从 server 中获取地址信息:
我们输入 10 个 %s
,使程序将栈上 10 个 4 字节的数据当作字符串地址去读取,Payload 如下:
程序会崩溃:
任务 2:打印服务器程序的内存¶
任务 2.A:栈数据¶
我们输入一个数据 num
,通过 100 个 %x
来读取栈上 100 个 4 字节的数据,Payload 如下:
得到 server 输出如下:
可以看到 num
出现在了第 64 个 %x
的位置上
任务 2.B:堆数据¶
我们通过之前的信息知道秘密字符串的位置在 0x080b4008
,因此我们可以将这个当作一个地址,用 %s
来读取,Payload 如下:
得到 server 输出如下:
所以秘密字符串为 A secret message
任务 3:修改服务器程序的内存¶
任务 3.A:将值更改为不同的值¶
修改地址为 target 的地址,将之前的 %s
改为 %n
,Payload 如下:
得到 server 输出如下:
可以看到我们成功修改了 target 的值,且说明了之前输出了 0xec=236
个字节
任务 3.B:将值更改为 0x5000¶
我们利用宽度控制符,限定地址以 %.8x
输出,再在最后一个 %x
补齐,控制输出的字节数为 0x5000 即可,Payload 如下:
得到 server 输出如下:
可以看到我们成功将 target 的值修改为 0x5000
任务 3.C:将值更改为 0xAABBCCDD¶
我们利用长度修饰符来减少填充的字符数,Payload 如下:
得到 server 输出如下:
可以看到我们成功将 target 的值修改为 0xAABBCCDD
任务 4:向服务器程序注入恶意代码¶
理解栈布局¶
根据我们获得的地址信息,标记为 ② 的位置的内存地址即为 myprintf()
函数的返回地址位置,即 ebp+4=0xffffd5dc
,标记为 ③ 的位置的内存地址即为 buffer
的位置,即 0xffffd6b0
,我们需要 64 个 %x
才能使参数指针移动到 ③
任务¶
根据上面得到的数据,设置跳转地址为 0xffffd8b0
(NOP 区域),覆盖返回地址 0xffffd5dc
,构造 Payload 如下:
运行即可获得 Reverse Shell:
任务 5:攻击 64 位服务器程序¶
首先获得服务器的地址信息:
同理,我们可以通过任务 2.A 的方法得知需要 34 个 %lx
就可以到达 buffer 的地址,由于地址存在 0x00
字节会导致 printf 函数将其后面的内容都不再当作格式字符串使用,所以我们将构造的格式字符串放在前面,将要覆盖的地址放在后面(offset 为 256),并通过 k$
进行访问和覆写(其中第一个 2 字节的位置即为 \(\frac{256}{8}+34=66\)),构造 Payload 如下:
运行即可获得 Reverse Shell:
任务 6:解决问题¶
我们只要修改 format.c 的 printf 函数即可修复漏洞:
重新编译,可以看到,警告消失了:
进行任务 2.A 的攻击:
可以看到,我们没能读取出栈上的值,攻击失败