自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

PHP7.0.0格式化字符串漏洞與EIP劫持分析

安全 漏洞
PHP7.0.0的這個(gè)格式化字符串漏洞是15年12月在exploit-db上發(fā)現(xiàn)的。發(fā)現(xiàn)該漏洞多了一個(gè)CVE編號(hào):CVE-2015-8617,于是深入地看了看這個(gè)漏洞,在這里對(duì)該格式化字符串漏洞進(jìn)行一些簡(jiǎn)要分析,并討論一下利用該漏洞劫持EIP的潛在方法,供各位讀者參考。

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

1.引言

在PHP中有兩個(gè)常見的格式化字符串函數(shù),分別是sppintf()和vsppintf(),它們分別對(duì)應(yīng)sprintf()函數(shù)和vsprintf()函數(shù),這兩個(gè)函數(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); 

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

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

2.漏洞分析

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

  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)用已用紅色筆標(biāo)明出,由于調(diào)用時(shí)少了一個(gè)參數(shù)導(dǎo)致觸發(fā)了格式化字符串漏洞。該漏洞的補(bǔ)丁也用紅色筆在代碼中標(biāo)明了。

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

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

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

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

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

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

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

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

  1. #define va_list void* 

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

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

在vspprintf()函數(shù)中,對(duì)于%n的處理則較為麻煩,它不會(huì)像%x那樣直接依次地讀寫下去,而是取va_list指向的參數(shù)表的每個(gè)參數(shù)作為指針,進(jìn)而覆蓋該指針?biāo)赶虻膬?nèi)容。結(jié)合圖2,具體敘述如下:對(duì)于第一個(gè)%n,則覆蓋0565D3C0所指向的內(nèi)容,對(duì)于第二個(gè)%n,則覆蓋96E436E2所指向的內(nèi)容,此時(shí)PHP就崩潰了,因?yàn)樵摰刂肥菬o(wú)效的。

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

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

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

0441E890 0565D3C0

0441E894 96E436E2

0441E898 0441E8C4

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

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

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

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

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

0441E824 96E40112

0441E828 96E43659

0441E82C 04422222

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

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

當(dāng)PHP解析該頁(yè)面的時(shí)候,首先輸出2個(gè)%x后,遇到第一個(gè)%n,則會(huì)覆蓋0441E8C4覆蓋為0441E82C;繼續(xù)跳過(guò)10個(gè)%x后,遇到第二個(gè)%n,則會(huì)覆蓋0441E82C覆蓋為04422222。

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

單步執(zhí)行后,就會(huì)來(lái)到04422222的位置:

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

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

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

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

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

考慮到此時(shí)存儲(chǔ)在[esp+0Ch+class_type]+0FCh的值比較小,可以嘗試?yán)么颂幍腸all eax實(shí)現(xiàn)劫持EIP。

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

08948F5C 08945D4C

08948F60 08945D50

08948F64 08955555

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

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

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

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

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

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

5.小結(jié)

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

責(zé)任編輯:武曉燕 來(lái)源: 紅黑聯(lián)盟
相關(guān)推薦

2017-01-16 16:33:06

Python 字符串漏洞

2009-11-26 18:36:52

PHP函數(shù)sprint

2024-12-09 08:10:00

Python字符串格式化

2017-01-17 15:47:18

2021-06-09 07:55:18

Python格式化字符串

2024-02-22 09:46:04

C++字符串格式化開發(fā)

2009-09-02 15:56:49

C#格式化字符串

2020-06-28 08:26:41

Python開發(fā)工具

2022-05-09 14:04:27

Python字符串格式化輸出

2009-09-03 18:45:06

GridView格式化

2010-02-01 16:46:07

C++格式化字符串

2009-09-03 18:05:04

ASP.NET字符串格

2024-03-06 08:41:14

Python字符串格式化工具

2022-03-28 10:56:11

Python字符串格式化

2024-05-27 00:10:00

2024-03-28 10:17:03

JDK 17字符串十六進(jìn)制

2009-11-25 09:13:41

PHP數(shù)組轉(zhuǎn)字符串PHP字符串轉(zhuǎn)數(shù)組

2024-02-26 08:00:00

Pythonformat()字符串

2010-11-26 13:10:17

2024-01-02 08:43:48

qs工具庫(kù)格式化
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)