软件安全实验六——sprintf()函数
一、 *实验目标*
%x查看栈内容
%s查看指定地址内容
è 复习缓冲区溢出覆写返回地址跳转shellcode的操作流程
è 了解sprintf()函数缺陷所在
è 分析shellcode的构造原理
è 实际操作对格式化输出函数漏洞进行利用
二、 *测试步骤与结果*
(一)通过%x来查看栈内容,重建栈内存,获得该frame的返回地址;
- 代码如下
如上所示,执行printf时第四个%x没有提供对应的参数,因此会显示本应该是参数所在位置的栈内容
- 运行至CALL test._printf处,可以看到显示了本应该是参数所在位置的栈内容。
- 通过更多的%x可以重建更多的栈内存:
(二)通过%s查看指定地址内容;
- 分析源代码
- 在OllyDbg中打开程序,并执行printf函数:
1,2,3是提供3个参数。利用%x步进,将%s的参数对应到77E61010,因此可以输出77E61010开始的字符串直到遇到截断符。0x0012FF58为format字符串起始地址,前四个字节即我们想要查看的内存地址77E61010:
(三)对sprintf函数及shellcode做解释分析;
作为向字符数组中写入数据的格式化输出函数,sprintf会假定存在任意长度的缓冲区。此处将字符数组user作为由用户构造的输入,其中出现了非常规字符%497d,是此次实验成功的关键。\x39\x4a\x42\x00是shellcode的起始地址,用来覆盖返回地址。\x90…\x33…\xD0…\x90为此次的弹框的shellcode:
(四)通过格式化字符串造成的缓冲区溢出覆盖返回地址,执行shellcode;
- 运行ollidbg,打下两处断点
- 运行至第一个 sprintf 处步过,观察缓冲区,可见存储位置从0012FB2C开始。由于后续被\x00截断,不在复制user后续内容
继续运行到第二个断点后,运行结果指向0012FD2C
可以看到第二个存储栈的内容
为满足%497d,中间使用\x20填充。最后写入\x39\x4a\x42\x00的十进制格式
- 由于“ERR Wrong command:”+若干个补充字符’\x20’+1245056D+0x00424A39=516字节,大于存储结构定义时的512,多余的四个字节会将返回地址覆盖淹没。返回地址转跳到shellcode代码地址。
三、 *测试结论*
格式化字符串漏洞是由于程序员在使用诸如printf这类的格式化输出函数时未能正确验证输入,导致攻击者可以通过构造特定的输入来控制格式化字符串的行为。如果格式化函数如sprintf或printf使用了用户控制的输入作为格式化参数,攻击者可能会插入恶意格式化指令,这些指令可以读取或写入内存,导致缓冲区溢出或其他安全问题,例如执行任意代码。这种类型的漏洞在软件安全中是严重且常见的,因为它允许攻击者绕过正常的权限检查来危害系统。
本次实验中了解到了格式化字符串造成缓冲区溢出的具体原理,并对其危害和效果进行了尝试。
四、 *思考题*
*破解foo.exe程序,在不改变源代码的情况下,要求通过命令行输入,利用格式化字符串漏洞n%的方式,调用隐藏的foo函数,并尝试调用一个shellcode。*
- 使用ollydbg启动程序,并在输出函数打断点。
- 尝试输入%x做参数,查看输出效果
- 查看输出结果
- 查看栈空间
可见存储从0012FD18开始,由于设定 char buf[512]因此会一直存储到0012FF18。但是_snprintf(buf, sizeof(buf)-1, “Can’tFind%s”, file);所以无法实现对0012FF18的直接写入。
- 查看%x的指针调用位置。
- 因此进行分析:如果想调用foo函数,需要在返回地址,即0012FF18写入foo函数地址00401014,而现有转跳是00401005。
因此可以使用%hn替换其低四位内容,即%hn输出前字符串输出1014。并且使指针通过%x遍历,最后停止在0012FF18的地址上。
参数格式应为%x%x%x%x……%x%x%x%x%hn \x00 \x12 \xFF \x18
- 计算%x个数。1014转换为10进制为4116,由此构造输出位数,结果如下。
- 尝试运行,运行成功
- 同理构造shellcode。由于shellcode构造在参数部分,即0012FD20。因此在转跳时需要转跳此处,需要把0012FF18处内容00401005全部替换。构造如下:
- 运行结果