栈溢出逆向分析
栈溢出漏洞逆向分析
摘要:针对StackOverflow.cpp程序,首先将其编译为二进制文件,进而通过动态逆向分析工具,以汇编指令为粒度,详细分析指令的功能及漏洞触发和利用方法。
关键词:栈溢出 逆向分析
工具:Windows10 Dev-C++ Ollydbg[吾爱]
栈溢出漏洞原理
栈溢出属于缓冲区溢出,指的是程序向栈中某个变量中写入的字节数超过了这个变量本身所申请的字节数,因而导致其写入与其相邻的栈,导致相邻栈中数据改变。
- 转载请注明出处:https://www.cnblogs.com/merk11/
利用方式有:
通过覆盖某些局部变量值达到绕过验证效果
通过移植恶意代码并修改返回地址达到某种目的
代码逆向分析
- 首先将stackoverflow.cpp编译生成exe文件,并用OD打开动态调试。找到程序运行的入口和main函数入口并下断点,完成准备工作。
-
对stackoverflow.cpp次要部分进行简要理解
-
我们跟进到scanf函数那里,测试栈溢出的情形,首先我们尝试正常的错误密码1234561
我们可以看到它的存入方式是从右到左从上到下的。
再尝试溢出的错误密码555555555
我们可以看到它抢占了当前位置+0x4的栈帧空间,可能会导致未知的错误。
- 接着我们进入重点分析的verify_password函数中,主要观察函数的返回位置和栈帧的变化。
00401500 55 push ebp
00401501 89E5 mov ebp,esp
00401503 83EC 28 sub esp,0x28 #更新栈基址指针,提升栈顶指针,分配一段0x28空间
00401506 C74424 04 00404>mov dword ptr ss:[esp+0x4],StackOve.0040400> #将“1234567”字符串变量地址存入esp+0x4
0040150E 8B45 08 mov eax,dword ptr ss:[ebp+0x8] #将ebp+0x8变量地址存入eax
00401511 890424 mov dword ptr ss:[esp],eax #将eax中的地址存入esp的字符串变量
由c语言程序分析,这里的返回值是strcmp产生的,而strcpy则是起到存储此密码的作用,这两个函数在栈溢出的情形很可能造成未知的错误,所以F7步入函数内部查看。
这里我的输入密码为:88888888
764496A0 8B5424 04 mov edx,dword ptr ss:[esp+0x4]
764496A4 8B4C24 08 mov ecx,dword ptr ss:[esp+0x8] #使用edx,ecx存储esp+0x4和esp+0x8
764496A8 F7C2 03000000 test edx,0x3 #也就是“1234567”和输入值,test会将ZF置1
764496AE 75 3C jnz short msvcrt.764496EC #于是这里跳转
764496B0 8B02 mov eax,dword ptr ds:[edx] #将edx变量地址放入eax
764496B2 3A01 cmp al,byte ptr ds:[ecx] #比较eax和ecx中变量的低位,ZF置1
764496B4 75 2E jnz short msvcrt.764496E4 #于是这里不跳转
764496E4 1BC0 sbb eax,eax #eax归零
764496E6 D1E0 shl eax,1 #移位
764496E8 83C0 01 add eax,0x1 #加1,此时eax值为00000001
764496EB C3 retn #返回
strcmp函数似乎没有引发错误,返回值正确
返回main函数
00401519 8945 F4 mov dword ptr ss:[ebp-0xC],eax #eax中的变量放入ebp-0xC位置
0040151C 8B45 08 mov eax,dword ptr ss:[ebp+0x8] #将ebp+0x8变量地址放入eax
0040151F 894424 04 mov dword ptr ss:[esp+0x4],eax #将eax中地址放入esp+0x4位置
00401523 8D45 EC lea eax,dword ptr ss:[ebp-0x14] #将ebp-0x14变量地址装入eax
00401526 890424 mov dword ptr ss:[esp],eax #将eax变量地址值放入esp位置
现在我们知道重点关注的是存储返回值的位置ebp-0xC也就是0062FA6C ,接下来F7进入strcpy函数看看是否有事发生。由于栈溢出,存储位置向下的高地址最可能被覆盖。
我们快进到strcpy中的关键语句
76446819 8917 mov dword ptr ds:[edi],edx
7644681B 83C7 04 add edi,0x4
7644681E BA FFFEFE7E mov edx,0x7EFEFEFF
76446823 8B01 mov eax,dword ptr ds:[ecx]
76446825 03D0 add edx,eax
76446827 83F0 FF xor eax,-0x1
7644682A 33C2 xor eax,edx
7644682C 8B11 mov edx,dword ptr ds:[ecx]
7644682E 83C1 04 add ecx,0x4
76446831 A9 00010181 test eax,0x81010100
76446836 74 E1 je short msvcrt.76446819
这里4字节为单位依次存入我们所输入变量的数据。
76446870 8817 mov byte ptr ds:[edi],dl #将edx低位存入edi
76446872 8B4424 08 mov eax,dword ptr ss:[esp+0x8] #将esp+0x8地址放入eax
76446876 5F pop edi #edi出栈
注意到这里edi的地址为0062FA6C,也就是我们重点关切的地方,如果这里被覆盖为0则会使错误的密码通过验证
为什么会引起覆盖,虽然我输入的是“88888888”似乎刚好占用了两个栈帧,但是一般字符串后面会带有一个空字符,空字符的ascii码为0,并且入栈方式是从右向左,从高地址到低地址的所以这里刚好覆盖了我们的返回值。
利用方式
漏洞触发的地方是在verify_password函数中的strcmp函数的返回值,在strcpy函数中进行赋值的过程中,栈溢出导致高地址的栈帧数据被覆盖,从而改变了返回值,使程序验证判定出现错误。
- 利用字符串覆盖返回值
首先我们知道strcmp的返回值有三种情况
大于返回00000001 可以通过构造字符串进行覆盖,利用字符串结尾的空字符
等于返回00000000
小于返回FFFFFFFF 不太容易进行构造覆盖,因为\0无法输入
- 利用字符串覆盖返回地址
这种方式在源代码的方式难以进行,具体思路是:
将字符串覆盖到EIP地址,通过修改返回地址为“congratulation~”对应地址,直接跳转到验证成功语句。
- 利用恶意代码修改程序
由于栈溢出导致覆盖的漏洞,导致恶意代码可以肆意寻找着陆点,如修改程序走向,这里不详细介绍。
- 转载请注明出处:https://www.cnblogs.com/merk11/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通