缓冲区溢出漏洞攻击分析

-回复 -浏览
楼主 2018-07-15 10:04:16
举报 只看此人 收藏本贴 楼主

漏洞原理

漏洞原理是通过往程序的缓冲区写超出其长度的内容,造成缓冲区的溢出,从而破坏程序的堆栈,造成程序崩溃或使程序转而执行其它指令,以达到攻击的目的。造成缓冲区溢出的原因是程序中没有仔细检查用户输入的参数,对参数的类型、长度等未做限制。


举个通俗易懂的例子,程序的缓冲区就像一个个格子,每个格子中存放不同的东西,有的是命令,有的是数据,当程序需要接收用户数据,程序预先为之分配了4个格子。按照程序设计,就是要求用户输入的数据不超过4个。而用户在输入数据时,假设输入了16个数据,而且程序也没有对用户输入数据的多少进行检查,就往预先分配的格子中存放,这样不仅4个分配的格子被使用了,其后相邻的12个格子中的内容都被新数据覆盖了。这样原来12个格子中的内容就丢失了,这时就出现了缓冲区(0~3号格子)溢出了。

案例分析

Freefloat FTPServer v1.0版本曾经爆出过一个cve-2012-5106的漏洞,我们就以这个版本完成一次缓冲区溢出漏洞的复现及分析。


首先通过metasploit中的fuzzer模块对其进行模糊测试,估算ftp server进程中可被覆盖的缓冲区大小。

观察发现当客户端向服务器发送大于250字节的缓冲区后,ftp server崩溃。崩溃的原因很显然是eip被改写成了一个不可读的内存地址。

Infigo FTPStress Fuzzer工具也可以对ftp server测试。发现发送520到700个字节之间大小的数据,服务器就会溢出崩溃。

虽然metasploit和Infigo FTPStress Fuzzer得到的缓冲区溢出大小不同,不过通常的思路是先使用范围大的,然后逐步缩小。


将ftp server进程附加到ImmunityDebugger中,使用插件mona发现该系统没有开启ASLR保护机制。另外,确保dep保护也是关闭的。

开始调试:找到输出ftp服务器返回欢迎信息的函数,在该函数处设置断点00402ffa,然后发送ftp请求及payload,ftp进程直接跳转到00402ffa。

f8单步调试,发现00403065处调用函数后就溢出。

重新调试,跟进00403065处的函数,发现一个循环,为跳出循环,在0040210a0040212a下断点,跳出后到0040213a调用函数后又溢出了。

重新调试,在0040213a处下断点,跟进该函数,发现程序已经运行到了服务器用内置命令和发送的命令在做比较。

继续单步跟,发现还是不断比较,那么这个调用比较字符串的函数其实是call ftpserve.00403d70,打开IDA发现,这个地址的确是调用一个strncmp函数,并且将三个参数压入栈中,和ida中的函数形式参数一样。

继续单步,发现在004028ed处调用函数后又一次溢出。

查看esp,发现payload已经压入栈中。

重新调试,在004028ed处设置断点并跟进该函数,跟到00402e5f处,此处实现了REP MOVS循环拷贝。最后在retn 8处溢出,retn指令就相当于pop eipretn 8指令执行后,esp会加8

 ida中查看REP MOVS循环,其实是使用函数strcpy完成循环复制。

问题就出现在strcpy函数,v8变量的最大长度是bp-fc,由于没有使用ebp索引,因此变量最后分配到栈中的最大长度是0xfc即252个字节,而之前的payload长度是500。

       

使用mona插件缩小payload到300个字节。重新发送payload2。

溢出成功,eip定位为346943133。而346943133超出ftp程序的地址范围,内存不可读。

计算34694133相对于ebp的偏移量,得知是251个字节。也就是说变量v8保存在栈中是从ebp到ebp-fc之间。因此eip被修改的位置是ebp-251。

继续缩小payload,这次偏移251+4个字节,发送payload3,执行到最后一条指令retn 8。当执行该指令后,esp指向的栈顶是00bdfc20,其值是BBBB,该值直接pop eip中。

f8单步果然如此。内存地址BBBB很显然是不可读的,那么如果将esp改为一个能执行的函数的地址,然后pop到eip中,那么该程序就会造成任意代码执行。

输入命令!mona find -s "\xff\xe4" -m,查找jmp esp,选择其中一个kernel32模块,该地址是7c86467b。

构造payload4,然后retn执行后指令跳转到7c86467b,然后esp则增加了8个字节。发现cpu下一条指令就要执行7c86467b中的值,而该值正是ffe4即jmp esp,而jmp esp的意思正是将eip修改为esp的值,因此下一步就要构造shellcode,而shellcode会由于缓冲区溢出而压入到栈中,而此时的esp则会指向shellcode。

再次构造pyload5,而shellcode就是我们要注入的恶意代码,这里暂时用字符串test代替。由于retn 8,因此esp会加8,因此要用至少8个空字符\x90代替这段8个字节。

f8单步执行,eip执行+1,最终会执行到esp00BDFC34,而00dbfc34的内存值则是7465即我们的shellcode字符串test,那么现在构造真正可执行的shellcode即可。

使用MessageBox弹窗api生成exp.exe。

加载exp到调试器中,提取汇编代码对应的机器码。

shellcode=“\x66\x81\xEC\x40\x04\x33\xDB\x53\x68\x2c\x63\x63\x72\x68\x20\x66\x6f\x72\x68\x20\x79\x6f\x75\x68\x67\x6f\x6f\x64\x8B\xC4\x53\x50\x50\x53\xB8\xEA\x07\xD5\x77\xFF\xD0\x53\xB8\xFA\xCA\x81\x7C\xFF\xD0”

发送payload6,成功溢出并执行任意代码。

通过调试器,也可以看到执行shellcode的第一条指令正是\x66\x8c\xec\x40\x04。即subsp,440。


总结

通过上述分析过程发现缓冲区溢出其本质就是在程序中对用户输入的数据长度没有做限制,最终通过构造畸形字符串控制程序的执行流向,导致任意代码的执行。

热点推荐

我要推荐
转发到