日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
PHP7.0.0格式化字符串漏洞與EIP劫持分析

PHP7.0.0的這個格式化字符串漏洞是15年12月在exploit-db上發(fā)現(xiàn)的。當初發(fā)現(xiàn)時,筆者還在北京東北方向的某信息安全公司上班,那時比較忙,并未能深入探究。最近幾天無意間又看到了這個漏洞,發(fā)現(xiàn)該漏洞多了一個CVE編號:CVE-2015-8617,于是深入地看了看這個漏洞,在這里對該格式化字符串漏洞進行一些簡要分析,并討論一下利用該漏洞劫持EIP的潛在方法,供各位讀者參考。

成都創(chuàng)新互聯(lián)公司客戶idc服務中心,提供成都服務器托管、成都服務器、成都主機托管、成都雙線服務器等業(yè)務的一站式服務。通過各地的服務中心,我們向成都用戶提供優(yōu)質(zhì)廉價的產(chǎn)品以及開放、透明、穩(wěn)定、高性價比的服務,資深網(wǎng)絡工程師在機房提供7*24小時標準級技術(shù)保障。

1.引言

在PHP中有兩個常見的格式化字符串函數(shù),分別是sppintf()和vsppintf(),它們分別對應sprintf()函數(shù)和vsprintf()函數(shù),這兩個函數(shù)的聲明為:

 
 
 
 
  1. PHPAPI int spprintf( char **pbuf, size_t max_len, const char *format, ...);  
  2. PHPAPI int vspprintf(char **pbuf, size_t max_len, const char *format, va_list ap); 

通過其函數(shù)聲明可以看到,spprintf()接收可變數(shù)量的參數(shù),而vspprintf()僅接收4個參數(shù)。

雖然這兩個函數(shù)的內(nèi)部實現(xiàn)原理是類似的,但筆者不打算就此點進行深入討論,如有感興趣讀者,可以看一看《程序員的自我修養(yǎng)》一書。關(guān)于格式化字符串漏洞的分析文章普遍集中于sprintf()函數(shù),而在本文中則需要重點討論一下vsprintf()函數(shù),即著重討論下PHP中的vspprintf()函數(shù)。

2.漏洞分析

本文所研究的vspprintf()函數(shù)在zend_throw_error()函數(shù)中,當觸發(fā)漏洞時,zend_throw_error()函數(shù)由zend_throw_or_error()函數(shù)調(diào)用。zend_throw_or_error()函數(shù)不是很長,所以復制其代碼如下:

 
 
 
 
  1. static void zend_throw_or_error(int fetch_type, zend_class_entry *exception_ce, const char *format, ...) 
  2.  { va_list va; char *message = NULL; va_start(va, format); zend_vspprintf(&message, 0, format, va); if (fetch_type & ZEND_FETCH_CLASS_EXCEPTION) { zend_throw_error(exception_ce, message); //vul_func //zend_throw_error(exception_ce, "%s", message); patched in the subsequent version } else { zend_error(E_ERROR, "%s", message); } efree(message); va_end(va); } 

在上述代碼段中,觸發(fā)漏洞的函數(shù)調(diào)用已用紅色筆標明出,由于調(diào)用時少了一個參數(shù)導致觸發(fā)了格式化字符串漏洞。該漏洞的補丁也用紅色筆在代碼中標明了。

關(guān)于該格式化字符串漏洞,并沒有很多需要分析說明的地方,下面開始分別從windows和linux兩個環(huán)境中討論利用該漏洞劫持EIP的方法。

3.windows環(huán)境下分析

為了減少在win7環(huán)境下的分析難度,筆者暫且把ASLR關(guān)掉。若計劃實現(xiàn)穩(wěn)定的EIP劫持,可能還需要通過其他手段獲取一些模塊基址,當然這PHP7.0.0格式化字符串漏洞本身也可以泄露一部分有用的內(nèi)存數(shù)據(jù)。

在windows版本的PHP中,其漏洞函數(shù)位于php7ts.dll動態(tài)鏈接庫中,構(gòu)造php頁面如下:

 
 
 
 
  1. $name="%n%n"; $name::doSomething(); ?> 

通過調(diào)試器啟動PHP解析該php頁面,執(zhí)行到程序崩潰時,通過?;厮?,可以找到vspprintf()函數(shù)調(diào)用(該函數(shù)是導出函數(shù),也可以直接在導出表中找到此函數(shù)),在該函數(shù)的函數(shù)頭下斷點,重新執(zhí)行,找到即將觸發(fā)漏洞的某次調(diào)用。此時,觀察棧中的數(shù)據(jù):

上圖中,棧頂是函數(shù)返回地址,即返回到zend_throw_error()函數(shù)中,接下來的是vspprintf()函數(shù)的四個參數(shù)。其中,0441E890即為va_list類型的參數(shù)。

這里需要指出的是,如果是傳統(tǒng)的spprintf()函數(shù)的格式化字符串溢出,則只需要不斷地利用%x遞增棧上參數(shù)數(shù)量,最后利用%n實現(xiàn)覆蓋函數(shù)返回地址即可有效地實現(xiàn)劫持EIP。但是此處是vspprintf()函數(shù)的,只接受4個參數(shù),所以如果打算繼續(xù)劫持EIP,則需要研究一下va_list,va_list在不同環(huán)境下的定義略有不同,這里我們可以粗略地定義va_list類型如下:

 
 
 
 
  1. #define va_list void* 

即認為va_list是一個指向可變數(shù)量參數(shù)的指針。在vspprintf()函數(shù)中,對于%x的處理是直接取va_list指向的內(nèi)容,如下圖:

其中,0441E890即為va_list的起始地址,通過圖1的第四個參數(shù)可以觀察到。對于第一個%x,則輸出0565D3C0;對于第二個%x,則輸出96E436E2;對于第三個%x,則輸出0441E8C4,以此類推下去。

在vspprintf()函數(shù)中,對于%n的處理則較為麻煩,它不會像%x那樣直接依次地讀寫下去,而是取va_list指向的參數(shù)表的每個參數(shù)作為指針,進而覆蓋該指針所指向的內(nèi)容。結(jié)合圖2,具體敘述如下:對于第一個%n,則覆蓋0565D3C0所指向的內(nèi)容,對于第二個%n,則覆蓋96E436E2所指向的內(nèi)容,此時PHP就崩潰了,因為該地址是無效的。

此時,是無法直接覆蓋函數(shù)的返回地址。為實現(xiàn)劫持EIP的目的,需要在棧上找一個二級指針。該二級指針取值第一次為保存函數(shù)返回地址變量的地址,取值兩次為函數(shù)返回地址變量的值。但筆者在棧上并沒有找到所需的二級指針,所以,筆者只能選擇構(gòu)造一個這樣子的指針,其構(gòu)造方法如下:

1,首先在棧上選擇一個合適位置,該位置存儲內(nèi)容指向棧的另一個位置,指向位置大于且接近該位置的地址。

復制部分棧內(nèi)容如下:

0441E890 0565D3C0

0441E894 96E436E2

0441E898 0441E8C4

正如上表所示,0441E8C4就是4字節(jié)對齊的,大于且接近0441E898,是一個非常合適的棧位置。

2,通過上一步找到的合適位置,覆蓋0441E8C4的內(nèi)容,使其指向棧上保存函數(shù)返回地址的地址。

在筆者調(diào)試時,將其覆蓋為0441E82C,即當前函數(shù)返回到vspprintf()函數(shù)的返回地址:

3,第一次覆蓋之后,用%x繼續(xù)在棧上滑行,直到0441E8C4的位置,此時將會第二次覆蓋0441E82C的內(nèi)容,使其指向我們需要跳轉(zhuǎn)的位置,比方說跳轉(zhuǎn)到04422222的位置。

按照上述思路,其??臻g的內(nèi)容大致如下:

0441E824 96E40112

0441E828 96E43659

0441E82C 04422222

基于此,筆者嘗試構(gòu)造php頁面如下:

 
 
 
 
  1. $name="%71428125x%x%n%x%x%x%x%x%x%x%x%x%14788x%n"; $name::doSomething(); ?> 

當PHP解析該頁面的時候,首先輸出2個%x后,遇到第一個%n,則會覆蓋0441E8C4覆蓋為0441E82C;繼續(xù)跳過10個%x后,遇到第二個%n,則會覆蓋0441E82C覆蓋為04422222。

其運行結(jié)果如下圖所示:

單步執(zhí)行后,就會來到04422222的位置:

Windows環(huán)境下的分析就到此位置,至于出現(xiàn)的幾個常數(shù):71428125和14788以及10個%x從何而來,相信讀者自己也能想到。至于是否可以在棧上構(gòu)造一些合適的數(shù)據(jù),最后通過ROP實現(xiàn)EXP,這點也留給讀者自己考慮分析一下吧。

4.Linux環(huán)境下分析

Linux環(huán)境下,同樣先把ASLR關(guān)掉,用以減少我們的分析難度。與Windows環(huán)境下的分析略有不同,由于Linux環(huán)境下的?;繁容^高,如下圖所示:

聲明一個如此之長的字符串,容易出現(xiàn)各種各樣的問題,所以筆者只好放棄直接覆蓋函數(shù)返回地址實現(xiàn)劫持EIP的方法。

這里考慮另一種劫持EIP的方法,覆蓋對象虛表的方法(一般情況下有三種常見的方法,在筆者之前的分析《kill.exe溢出漏洞分析與EXP討論》中有提到,感興趣的讀者可以看一下)。構(gòu)造合適的php頁面,令PHP不崩潰,而是讓其繼續(xù)下去的話,就會發(fā)現(xiàn)PHP接下來將要調(diào)用_object_init_ex()函數(shù),初始化異常對象。該初始化函數(shù)會進一步調(diào)用object_and_properties_init()函數(shù),而在此函數(shù)中,會調(diào)用對象虛表中的函數(shù),關(guān)鍵代碼段如下:

 
 
 
 
  1. object_and_properties_init() { … mov ebx, [esp+0Ch+class_type] … mov eax, [ebx+0FCh] … call eax ; call [[esp+0Ch+class_type]+0FCh] … } 

考慮到此時存儲在[esp+0Ch+class_type]+0FCh的值比較小,可以嘗試利用此處的call eax實現(xiàn)劫持EIP。

選擇在第3章節(jié)描述的二次覆蓋方法,可以構(gòu)造??臻g如下:

08948F5C 08945D4C

08948F60 08945D50

08948F64 08955555

基于以上討論,筆者構(gòu)造php頁面如下:

 
 
 
 
  1. ini_set("memory_limit", "2G"); $name="%143953757x%n%x%x%x%x%x%x%x%x%x%x%50621x%n"; $name::doSomething(); ?> 

當PHP在解析該頁時,第一次遇到%n將會覆蓋8FFFBFCC位置的數(shù)據(jù)為08948F64;而第二次遇到%n時,將08948F4位置的數(shù)據(jù)覆蓋為08955555。此后,程序會正常執(zhí)行,直到call eax指令的位置:

此時,PHP將跳轉(zhuǎn)到我們指定的地址繼續(xù)執(zhí)行,在上圖中為8955555地址。

值得慶幸的是,在Linux環(huán)境中,并沒有Windows環(huán)境的CFG保護。如果存在CFG保護,即有/GUARD:CF標記,將可能導致此種利用方式失敗。

Linux環(huán)境下的分析也就到此位置,至于出現(xiàn)的幾個常數(shù):143953757和50621以及11個%x從何而來,相信讀者自己也能想到。至于是否可以實現(xiàn)有效的EXP,這點也留給讀者自己考慮分析一下吧。

5.小結(jié)

本文簡要地分析了PHP7.0.0格式化字符串漏洞,并在windows和linux兩種不同的環(huán)境下,給出了運用該漏洞劫持EIP的方法。但需要指出的是,本文所有的分析都在禁用了ASLR的場景之下進行的,若打算實際利用該漏洞,還需要獲取一些模塊基址等其他有用信息。


當前文章:PHP7.0.0格式化字符串漏洞與EIP劫持分析
路徑分享:http://www.dlmjj.cn/article/ccdjosj.html