CVE-2017-7269 IIS6.0遠端程式碼執行漏洞分析及Exploit
原帖地址:http://whereisk0shl.top/cve-2017-7269-iis6-interesting-exploit.html
感謝仙果和Wingdbg,我將我部落格的這篇分析轉到看雪和大家一起分享。我的部落格會長期更新二進位制分析的文章,希望能與大家多多交流,水平不高,大家多多包涵,多多指點。
0x00 前言
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地址:
這個漏洞其實原理非常簡單,但是其利用方法卻非常有趣,我在入門的時候除錯過很多stack overflow及其exp,但多數都是通過覆蓋ret,覆蓋seh等方法完成的攻擊,直到我見到了這個exploit,感覺非常藝術。但這個漏洞也存在其侷限性,比如對於aslr來說似乎沒有利用面,因此在高版本windows server中利用似乎非常困難,windows server 2003 r2沒有aslr保護。
在這篇文章中,我將首先簡單介紹一下這個漏洞的利用情況;接著,我將和大家一起分析一下這個漏洞的形成原因;然後我將給大家詳細介紹這個漏洞的利用,最後我將簡要分析一下這個漏洞的rop及shellcode。
我是一隻菜鳥,如有不當之處,還望大家多多指正,感謝閱讀!
0x01 彈彈彈--一言不合就“彈”計算器
1、 漏洞環境搭建
漏洞環境的搭建非常簡單,我的環境是windows server 2003 r2 32位英文企業版,安裝之後需要進入系統配置一下iis6.0,首先在登陸windows之後,選擇配置伺服器,安裝iis6.0服務,之後進入iis6.0管理器,在管理器中,有一個windows擴充套件,在擴充套件中有一個webdav選項,預設是禁用狀態,在左側選擇allow,開啟webdav,之後再iis管理器中預設網頁中建立一個虛擬目錄(其實這一步無所謂),隨後選擇run->services.msc->WebClient服務,將其開啟,這樣完成了我的配置。
2、 觸發漏洞
漏洞觸發非常簡單,直接在本地執行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請求來完成一次精妙的利用,最後在<lock token>指令下完成最後一擊。
我嘗試去掉第二次<>以及<lock token>請求,同樣能引發iis服務的crash。
0x02 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 |
|
在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 |
|
在利用的關鍵一次,我們獲取的是poc中http://localhost/bbbbb的字串,這個字串長度很長,可以看到eax暫存器存放的是url長度,長度是0x2fd,隨後會進入一系列的判斷,主要是檢查url中一些特殊字元,比如0x2f。
1 2 3 4 5 6 7 8 9 10 |
|
經過一系列的檢查之後,會進入一系列的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 |
|
這次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 |
|
可以看到,這次拷貝的長度是0x17f,長度非常大,而在整個分析的過程中,並沒有對拷貝的長度進行控制,因此,可以拷貝任意超長的字串,進入這個堆空間。
這個堆空間非常有意思,存放的是一個vftable,這個vftable會在ScStorageFromUrl函式中的某個內層函式呼叫呼叫到,還記得之前分析的ScStripAndCheckHttpPrefi函式嗎
1 2 3 4 5 6 |
|
獲取完虛表之後,會獲取到對應的虛擬函式,在ScStripAndCheckHttpPrefix函式中call呼叫到。但是由於之前的memcpy覆蓋,導致這個vftable被覆蓋
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
這個漏洞的原理非常簡單,在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 |
|
0x03 CVE-2017-7269 Exploit!精妙的漏洞利用
其實通過上面的分析,我們發現這個漏洞的 原理非常簡單,但是究竟如何利用呢,我們來看一下關於ScStorageFromUrl函式中,包含了GS check,也就是說,我們在進行常規的覆蓋ret方式利用的情況下,將會把cookie也會覆蓋,導致利用失敗。
1 2 3 4 5 6 7 8 9 10 |
|
漏洞利用非常精妙,也就是用這種方法,巧妙的繞過了gs的檢查,最後達到漏洞利用,穩定的程式碼執行,首先,WebDav對資料包的處理邏輯是在DAVxxx函式中完成的。比如當前資料包是PROPFIND,那麼當前的函式處理邏輯就是DAVpropfind函式。
1 2 3 4 5 6 7 8 |
|
在內層的函式處理邏輯中,有一處關鍵的函式處理邏輯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 |
|
如果看的比較迷糊,可以看我下面的描述,首先這個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 |
|
這個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 |
|
可以看到,第一次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 |
|
經過這次stack buffer overflow,這個值已經被覆蓋,覆蓋成了一個堆地址0x680312c0。接下來進入第二次呼叫。
1 2 3 4 5 6 7 8 9 10 11 12 |
|
第二次獲得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 |
|
可以看到,第二次利用的時候,會把ebp-328這個地方的值推入棧中,這個地方應該是stack buffer的地址,應該是個棧地址,但是現在變成了堆地址,就是由於第一次棧溢位,覆蓋了這個變數。
而這個值,會作為引數傳入ScStorageFromUrl函式,作為memcpy拷貝的值。
這也就解釋了為什麼我們在上面分析漏洞的時候,會是向堆地址拷貝,而這一次拷貝,就不需要控制長度了,因為這個地方的值已經是堆地址,再怎麼覆蓋,也不會覆蓋到cookie。這裡未來要覆蓋IEcb虛表結構。從而達到漏洞利用。這樣,第二次向堆地址拷貝之後,這個堆地址會覆蓋到IEcb的虛表,這個虛表結構會在最後利用時引用到。
在PoC中,有一處<locktoken>,這個會觸發漏洞利用,是在CheckIfHeader之後到達位置,在CheckIfHeader的PszToken函式判斷沒有<>的http url之後,break掉,之後進入lock token處理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
這時候對應的IEcb已經被覆蓋,這樣,在進入ScStoragePathFromUrl函式之後,會進入我們在漏洞分析部分提到的CheckPrefixUrl函式,這個函式中有大量的IEcb虛表虛擬函式引用。
1 2 3 4 5 6 7 8 9 |
|
和大家分享了這個精妙利用,一般可能都會覺得是第二次url bbbbb的這個memcpy覆蓋了關鍵函式導致的溢位、利用,實際上,在第一次url aaaaaa中,就已經引發了棧溢位,覆蓋到了stackbuffer申請的指向棧buffer的指標,這個指標存放在棧裡,用於後續呼叫存放虛擬路徑,由於第一次棧溢位,覆蓋到了這個變數導致第二次url bbbbb拷貝的時候,是向一個堆地址拷貝,這個堆地址後面的偏移中,存放著IEcb的vftable,通過覆蓋虛表虛擬函式,在最後locktoken觸發的ScStoragePathFromUrl中利用虛擬函式達到程式碼執行。
而這個過程,也是巧妙的繞過了GS的檢查
0x04 簡析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 |
|
經過一系列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 |
|