关于MS08-067的一点细节

作者:

这个漏洞就不介绍了,已经沸沸扬扬了。

首先milw0rm上那个exp的编译问题,作者在里面放的些小trick很容易fix,主要麻烦的是midl编译idl文件后,在VC6环境下编译可能出现rcpt库的错误。可能是SDK的版本导致的,云舒用最新的SDK(好像是2008?)编译成功了。

其次是触发问题,什么权限都不需要,空连接后就能触发。

ncacn_np:\\\\192.168.152.101[\\pipe\\srvsvc] 直接请求就可以了。

问题还是出在 NetpwPathCanonicalize() 的第二个参数,这个漏洞非常奇特。

首先这个参数的长度不能超过 0x207(unicode)

71BB58F6    81FF 07020000   CMP EDI,207
71BB58FC ^ 0F87 F447FFFF   JA NETAPI32.71BAA0F6   // 如果大于了就直接函数返回了
71BB5902 ^ E9 1247FFFF     JMP NETAPI32.71BAA019

然后会走到一个wcscat的地方,这里没有问题,因为空间是足够的
71BAA019    8D85 E8FBFFFF   LEA EAX,DWORD PTR SS:[EBP-418]
71BAA01F    53              PUSH EBX
71BAA020    50              PUSH EAX
71BAA021    FF15 9810BA71   CALL DWORD PTR DS:[<&msvcrt.wcscat>]     ; msvcrt.wcscat

继续往下会把所有的 “/” 替换为 “\” 这里也无关紧要

然后就走到出问题的函数

71BAA05A    8D85 E8FBFFFF   LEA EAX,DWORD PTR SS:[EBP-418]
71BAA060    50              PUSH EAX
71BAA061    E8 AB020000     CALL NETAPI32.71BAA311

跟进去后很复杂,可以参考下这里的伪代码
http://www.phreedom.org/blog/2008/decompiling-ms08-067/

估计很多人在这里绕晕了,我跟了一晚上,总算搞明白了一点。

首先是为什么老是会上溢的问题,这个就是这个漏洞的原因所在了。cocoruder在blog上引用了这么一段话:
There are two copies, the first copy is OK, but when there is another “..\”, it will lead to start the another copy (repeat the first copy codes), the second copy firstly does not calculate the base pointer correctly (firstly it is basePointer-2, so the ‘JZ’ checking in the loop of searching character ‘\’ will never come ture), that lead to get an unexpected stack pointer which is below the base pointer, after the wrong calculation, it starts the second copy and uses the unexpected pointer as the first parameter of function “wcscpy()”, therefore, the wrong-calculation memory will be rewritten. The EIP will be controlled in the main function, probably.

实际上就是在找目录的时候,

\x\..\yyyyyyyyyyyyy

会拷贝为 \yyyyyyyyyyyy   中间的 \x\.. 就没有了。

然后程序会往栈的上面去找 “\” 的存在,但是往往栈低址里没有 “\”的存在,所以就找完了整个栈,上溢了。

很多同学估计都卡在这个地方了。

bp 0x71baa398 first copy 第一次拷贝,这里没问题

71BCDC12    8D46 04         LEA EAX,DWORD PTR DS:[ESI+4]
71BCDC15    8BCE            MOV ECX,ESI
71BCDC17    50              PUSH EAX
71BCDC18    51              PUSH ECX
71BCDC19    FF15 2C10BA71   CALL DWORD PTR DS:[<&msvcrt.wcscpy>]     ; msvcrt.wcscpy

此时 si = 0x2e 然后前后判断是否是 \..\

71BAA363    8D46 FE         LEA EAX,DWORD PTR DS:[ESI-2]
71BAA366    3BD8            CMP EBX,EAX
71BAA368    0F85 50380200   JNZ NETAPI32.71BCDBBE
71BAA36E    8D46 02         LEA EAX,DWORD PTR DS:[ESI+2]
71BAA371    66:8B10         MOV DX,WORD PTR DS:[EAX]
71BAA374    66:83FA 2E      CMP DX,2E
71BAA378    0F85 8A380200   JNZ NETAPI32.71BCDC08
71BAA37E    8D46 04         LEA EAX,DWORD PTR DS:[ESI+4]
71BAA381    66:8B18         MOV BX,WORD PTR DS:[EAX]
71BAA384    66:83FB 5C      CMP BX,5C

second copy 第二个拷贝,把中间的 \x\.. 弄没了
71BAA388   /0F85 3D380200   JNZ NETAPI32.71BCDBCB
71BAA38E   |85FF            TEST EDI,EDI
71BAA390   |0F84 0B630000   JE NETAPI32.71BB06A1
71BAA396   |50              PUSH EAX
71BAA397   |57              PUSH EDI
71BAA398   |FF15 2C10BA71   CALL DWORD PTR DS:[<&msvcrt.wcscpy>]     ; msvcrt.wcscpy

漏洞代码就是下面这个:
71BCDBDE    8D47 FE         LEA EAX,DWORD PTR DS:[EDI-2]
71BCDBE1    66:8338 5C      CMP WORD PTR DS:[EAX],5C
71BCDBE5   /75 18           JNZ SHORT NETAPI32.71BCDBFF
71BCDBE7   |66:8B38         MOV DI,WORD PTR DS:[EAX]
71BCDBEA   |8B4D 08         MOV ECX,DWORD PTR SS:[EBP+8]
71BCDBED   |66:83EF 5C      SUB DI,5C
71BCDBF1   |66:F7DF         NEG DI
71BCDBF4   |1BFF            SBB EDI,EDI
71BCDBF6   |F7D7            NOT EDI
71BCDBF8   |23F8            AND EDI,EAX
71BCDBFA ^|E9 55C7FDFF     JMP NETAPI32.71BAA354
71BCDBFF   \3B45 08         CMP EAX,DWORD PTR SS:[EBP+8]
71BCDC02 ^ 74 E3           JE SHORT NETAPI32.71BCDBE7
71BCDC04    48              DEC EAX
71BCDC05    48              DEC EAX
71BCDC06 ^ EB D9           JMP SHORT NETAPI32.71BCDBE1

试图往栈低址去寻找”\”,结果错误计算了开始的地址,导致根本找不到。

按照cocoruder的说法,在计算错误后,有机会第二次执行第二个 wcscpy ,从而覆盖那个错误计算出的地址。

不过我没找到能再次执行拷贝的方法,我的整个栈低址几乎就是一片0,每次都上溢了.

有的机器里也许能够找到那个“\”吧,或者存在一种能够稳定利用的方法。

使用 \\pipe\browser 好像也有机会控制EIP,可以继续搞搞。

瞎扯到这里,不说了,大家再一起继续郁闷吧。

相关日志

抢楼还有机会... 抢座Rss 2.0或者 Trackback

发表评论