软安实验2—栈溢出
实验2:栈溢出
1. 实验目标
通过对程序输入的密码的长度、内容等修改用Ollydbg来验证缓冲区溢出的发生。
完成淹没相邻变量改变程序流程实验。
完成淹没返回地址改变程序流程实验
信安思考题:
在不修改源代码的情况下,修改StackOverrun程序的流程,通过淹没返回地址,用jmp esp的方式,让其调用bar函数并输出结果。
双培思考题:
在不修改源代码的情况下,修改OverFlow_EXE程序的流程,通过弧注入的方式,不植入可执行代码,让其调用MessageBoxA函数(函数地址:0x77E23D68)弹出对话框(对话框显示bupt),之后调用ExitProcess函数(函数地址:0x77E7B0BB)退出进程。
2. 实验要求
- 详述修改过程
- 实验结果需要截图证明
- 绘制修改原理的图示
3. 测试步骤与结果
源代码
1 |
|
3.1 Ollydbg验证缓冲区溢出
将可执行文件拖入Ollydbg中进行调试,找到strcpy()
函数设置断点,运行输入错误的密码123456。
步过到strcpy()
函数下一行时,程序已将字符串复制到buf数组地址,可以看到返回值为FFFFFFFF即为-1的补码,说明密码对比不正确。
同样的操作输入正确的密码1234567进行查看。
可以看到其返回值为0,说明密码对比正确。但是输入过长字符串时程序并没有设置限制,而是继续在栈中写入,从而导致缓冲区溢出,如输入1111111111。
可以看到其存储早已超出buf申请的8字符长度,可说明其存在缓冲区溢出,栈结构如下。
3.2 淹没相邻变量改变程序流
当输入长于存储空间的字符串12345678时,因为没有保护机制所以会将其输入内容溢出到高地址上,此处即为溢出更改anthenticated的值。
可以看到anthenticated的值被字符串溢出更改为0,即不输入正确的密码也可判定为密码正确。
相邻变量溢出覆盖的栈结构如下。
3.3 淹没返回地址改变程序流
如果输入超长字母,就可以将栈中的返回地址也覆盖更改,从而就能实现控制程序流的效果,输入123456789123456789123456789。
可以看到返回地址已经被覆盖,因此如果将返回地址覆盖成有意义的地址,即可截获程序流。
此时需要填充8位buf[8] + 4位anthenticated存储空间 + 4位EBP回调存储空间 + 想要其返回的地址位置,此处想要直接跳转到congratulations处,即0x00401116
。
因此输入123412341234123416114000即可达成目的,不过其地址都是以16进制存入,所以需要通过010Editor
编译其对应的16进制,写入字符并按ctrl+h
即可。
右侧内容作为密码输入即可成功淹没返回地址改变程序流。
返回地址溢出被覆盖的栈结构如下。
4. 测试结论
可以看出栈溢出对程序运行的安全性有很大的威胁,如果不对栈进行保护,只要系统中存在栈溢出漏洞,即可令攻击者通过非正当方法获取操作权限。因此,需要对栈中保存数据的可执行权限做严格的管理,并且系统要能判断栈溢出从而采取相应的保护措施。
5. 思考题
信安
在不修改源代码的情况下,修改StackOverrun程序的流程,通过淹没返回地址,用jmp esp的方式,让其调用bar函数并输出结果。
源代码(仅作参考,主要根据老师给的StackOverrun.exe)
1 | /* |
运行StackOverrun.exe。发现程序打印了foo函数和bar函数的地址位置,并且调用了foo函数,输出了栈顶向下的40字节的数据。
将StackOverrun.exe拖入Ollydbg中分析。在菜单栏选择
调试->参数
,并输入参数11223344
,并重新开始。通过查找输出字符串定位到主函数位置并设置断点,调试观察调用foo函数前的栈空间情况。
可以看到EBP指向了
0x0012FFC0
,ESP指向了0x0012FF70
,由此栈顶向下依次为004060C4,00401060(bar函数地址),004060DC,00401000(foo函数地址)。继续调试进入foo函数。
观察此时栈空间,可以看到EBP未改变,ESP因
SUB ESP,0C
改变为0x0012FF60
,此时的0x0012FF6C
存储的是main函数地址。如下图,继续运行至strcpy函数处,可以看到输入的参数
11223344
也在栈空间中,所以可以通过输入12个填充字符和jmp esp指令地址使栈溢出覆盖之前返回main函数的地址为jmp esp,并让程序将栈空间的数据当做代码运行,从而调用bar函数。右键->Overflow Return Address->ASCII overflow returns->Search JMP/CALL ESP
来查找jmp esp指令。待下方搜索进度条满后,对其弹出提示进行确认后,点击菜单栏的
L
按键查看日志。本次选用
77F8948B
处的JMP ESP指令。构造shellcode。
需要将
77F8948B
利用UltraRdit转换成字符为嫈鴚
。输入参数
12345678912嫈鴚
运行调试,可以看到foo函数结束后跳转到了JMP ESP指令处,可以看到此时ESP为0012FF70,由此需要把该地址指令改为调用bar函数。继续运行调试,可以看到跳到了0012FF70处。双击0012FF70处指令,更改为
CALL 00401060
就可以获取到其机器码为E8EB102D00
,不过查看后一定要改回原来的语句。将机器码转为字符
桦-
。由此可以构造参数为123456789012嫈鴚桦-
输入shellcode进行测试。
双培
在不修改源代码的情况下,修改OverFlow_EXE程序的流程,通过弧注入的方式,不植入可执行代码,让其调用MessageBoxA函数(函数地址:0x77E23D68)弹出对话框(对话框显示bupt),之后调用ExitProcess函数(函数地址:0x77E7B0BB)退出进程。
源代码
1 |
|
程序中打开password.txt
进行读取,所以需要在程序目录下创建文件并在其中写入1234567作为密码。将程序拖入Ollydbg中,在memcpy()
函数处设置断点,将程序运行到断点。
可以看到其保存返回地址的地址为0012FB24
,向下步过可以看到字符存储地址为0012FAF0
。
两个地址之间的距离为13*4,其为需要填充的长度,通过题目可知messagebox地址为0x77E23D68
,Exit地址为0x77E7B0BB
,输出参数为bupt
,由此可以通过010Editor编写password.txt
文件,在其中输入payload。
弧注入的栈结构如下。
根据栈结构编写的payload。
更改password中的文本后,运行程序即可看到窗口弹出,从而证明程序流被劫持。