关于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,可以继续搞搞。
瞎扯到这里,不说了,大家再一起继续郁闷吧。
技术性很强大