7.3.2 IDA帮助分析 warFTP漏洞

“好,我们在IDA的帮助下来分析warFTP的漏洞吧!”

“IDA是强大的反汇编工具(光盘有收录),不仅可以给出反汇编代码,还可以在我们的指引下主动进行一些分析;而且可以写些脚本IDC来进行自动分析。IDA是白盒法测试时必用的工具!”

“打开IDA后,选择‘open’,打开warFTP.exe程序就开始分析反汇编了。”

“等一会儿分析完毕后,在‘Function’一栏可以直接看到调用的函数,包括MFC的函数名都可清楚的分析出来。”

大家看了看图7-31,果然如此!

“我们想一下,warFTP是因为我们的过长字符串才引发的溢出;而且是远程溢出;所以……”老师慢慢的说,“一定是通过网络,warFTP接收了我们的过长字符串才引起的溢出。”

“嗯!”大家点点头。

“一般的网络编程,百分之九九都是用Socket来完成的。warFTP接收我们的字符串,应该就是通过……”

“哦!一定是使用Socket,用recv或类似函数来完成的吧!”宇强抢着说道。

“对!我们看看IDA的‘function’那一栏,查看Socket相关的函数。发现了MFC的CAsyncSocket ::Receive函数,那是MFC封装的用于接收网络数据的函数,其位置在0x004345B8。”

text:004345B8 ; public: virtual int __thiscall CAsyncSocket::Receive(void *,int,int)

小知识:MFC

微软基础类库,是微软对Windows API的再次封装,期望简化编程的复杂度,提高软件开发效率并减少软件成本。

“经过白盒法的辅助分析后,我们得到了关键的启发。再运行Ollydbg,加载程序,然后对0x004345B8地址设断点,如图7-32。”

“运行全A的超长字符串攻击程序,果然被Ollydbg成功中断下来。Receive其实还是调用了WSOCK32的recv函数。我们跟进去就可以看见如下代码:”

73D4A22E > FF7424 0C PUSH DWORD PTR SS:[ESP+C]
73D4A232 FF7424 0C PUSH DWORD PTR SS:[ESP+C]
73D4A236 FF7424 0C PUSH DWORD PTR SS:[ESP+C]
73D4A23A FF71 04 PUSH DWORD PTR DS:[ECX+4]
73D4A23D E8 03000000 CALL MFC42.73D4A245 ; JMP to WSOCK32.recv
73D4A242 C2 0C00 RETN 0C

“看,最后一个参数是[ECX+4],值为00D7E93C,是接收后数据存放的地方。我们在左下角的内存窗口中按 Ctrl+G,弹出地址对话框,输入00D7E93C就会显示该地址的内容。recv执行完后,可以看到,收到的就是我们发的东东:User AAAAA……如图7-33。”

“哦!”

“这就完成了我们漏洞分析最关键的一步,在字符串处理的前端中断了下来!我们继续跟踪,注意随时查看各个参数里的内容,发现我们发送的字符串就多多观察。”

“到了下面这里,是在判断开头的命令字符,这里是USER命令,如图7-34。”

“然后程序处理后面的字符串,经过耐心的跟踪,在 0042E2FA:call 004044c0 时,有对00BBFD54进行了写操作!即该函数把地址保存在00BBFD54这个位置。如图7-35。”

“哦!但00BBFD54和00BBFD5C不是同一个地址啊!”古风一脸疑问的表情。

“莫非是ret n?”宇强说道。

“呵呵!我们按F8跟进去看看!”

“好,一下子就看见有一个sprinft函数!如图7-36。”

“我们边单步运行,边查看它的参数。”

“首先PUSH EAX,这个EAX为如下:”

"[C 2004 11 26 22:42] 00001 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

“就是日期时间加上我们输入的超长字符串。”

“然后,PUSH war-ftpd.004406C0,这里是%s,一个标准的字符串拷贝。”

“最后PUSH ECX,再CALL <&MSVCRT.sprintf>。”

“我们来计算一下,ecx=0x00BBFB54;而保存返回地址在ESP=0x00BBFD54中。”

“相减,0x00BBFD54-0x00BBFB54=0x200=512。”

“而前面[C 2004 11 26 22:42] 00001 AAA…有28个字符, 所以填充A为是512-27=485。果然是这样!”

“继续跟踪,到函数返回的时候,果然和宇强同学说的一样,是RETN 4,如图7-37。”

“我们说过RET 4=POP EIP,ADD ESP,4。现在ESP=00BBFD54,对应的值为41414141,所以返回后,系统会执行0x41414141的地方,如图7-38。

“最后看看为什么RET 4返回后,ESP会成为00BBFD5C。”

“RET 4=POP EIP,ADD ESP,4。首先POP EIP,那么EIP变成0x41414141,而ESP+4=00BBFD54+4=00BBFD58;再ADD ESP,4=ESP+4=00BBFD58+4=00BBFD5C。”

“所以返回后,EIP=41414141,ESP=00BBFD5C,果然验证了我们的分析,如图7-39。”

“小结一下,溢出是因为执行了 sprintf(eax,”%s”,”[] AAAAAAAAAA”) 。这里,eax是一个局部变量,而sprintf没有验证字符串的长度,所以就发生溢出了!”