Windows系統(tǒng)下典型堆漏洞產(chǎn)生原理及利用方法研究

  • 寫在前面
    本文為本科期間想不開報名的科技創(chuàng)新論文,由于重視程度不夠以及時間分配不合理悄蕾,最終趕在deadline前完成。希望這篇能夠給在這方面存在疑惑的人提供一些參考和幫助,但同時由于本人研究深度不夠等因素永高,導(dǎo)致本文中存在或多或少與實際情況不符的結(jié)論隧土,希望大家提高甄別能力。

摘要

隨著時代的進(jìn)步和科技的發(fā)展命爬,在計算機(jī)的操作性能都急速發(fā)展的今天曹傀,人們對個人計算機(jī)的需求逐漸從可操作性向安全性進(jìn)行轉(zhuǎn)變。尤其是近年來個人計算機(jī)內(nèi)存漏洞的頻頻披露饲宛,嚴(yán)重危害到用戶的個人信息安全的事件頻發(fā)更是加速了思想轉(zhuǎn)變的進(jìn)程皆愉。Windows操作系統(tǒng)作為個人電腦的主流操作系統(tǒng),肩負(fù)著對用戶個人信息負(fù)責(zé)的重任艇抠,Windows操作系統(tǒng)的安全性直接關(guān)乎著絕大多數(shù)人的個人信息安全幕庐。

Windows操作系統(tǒng)內(nèi)存管理中的棧由于操作單一,已經(jīng)被研究得很透徹家淤,也被防御地很透徹异剥,很難再掀起波瀾。而堆則擁有著相對更為復(fù)雜的管理機(jī)制以及操作方式絮重,擁有著無數(shù)耐人尋味的排列組合冤寿。

本文將通過對Windows操作系統(tǒng)堆的歷史沿革、底層算法青伤、實現(xiàn)原理進(jìn)行探尋督怜,總結(jié)歸納出各階段Windows操作系統(tǒng)的堆管理機(jī)制具體實現(xiàn)及典型堆漏洞的產(chǎn)生原理及利用方法。旨在通過歸納和總結(jié)加深對Windows操作系統(tǒng)底層的了解狠角,以及為對Windows操作系統(tǒng)堆有強(qiáng)烈興趣的安全愛好者們提供一定的幫助号杠。

關(guān)鍵詞:Windows、操作系統(tǒng)擎厢;安全性究流;堆管理機(jī)制;堆漏洞

ABSTRACT

With the advancement of the times and the development of science and technology, as the operational performance of computers has rapidly developed, the demand for personal computers has gradually changed from operability to security. In particular, in recent years, the frequent disclosure of personal computer memory vulnerabilities has seriously jeopardized the user's personal information security incidents, which has accelerated the process of ideological transformation. As the mainstream operating system of personal computers, the Windows operating system shoulders the responsibility of being responsible for the personal information of users. The security of the Windows operating system is directly related to the personal information security of most people.

The stack in the memory management of the Windows operating system has been thoroughly researched due to its single operation, and it has been thoroughly defended. It is difficult to make waves again. The heap has a relatively more complex management mechanism and operation mode, and has a myriad and intriguing arrangement.

This paper will explore the history of the Windows operating system heap, the underlying algorithm, and the implementation principle, and summarize the implementation of the heap management mechanism and the generation and utilization of the typical heap vulnerability in each stage of the Windows operating system. It aims to deepen the understanding of the underlying Windows operating system by summarizing and summarizing, and to provide some help to security enthusiasts who have a strong interest in the Windows operating system heap.

Keywords:Windows operating system;Safety;Heap management mechani-sm;Heap vulnerability

一动遭、研究背景

近年來芬探,作為操作系統(tǒng)主流的Windows系統(tǒng)漏洞層出不窮,嚴(yán)重威脅到了計算機(jī)使用者的信息安全厘惦。其中偷仿,緩沖區(qū)溢出漏洞作為老牌漏洞發(fā)揮著不可忽視的作用。本著對漏洞成因的好奇宵蕉,筆者開始了對Windows堆緩沖區(qū)的探索酝静。Windows內(nèi)存中,堆是最為神秘羡玛、迷人甚至有些耐人尋味的地方别智,同時堆也是Windows內(nèi)存中較為混亂的區(qū)域。由于微軟對Windows操作系統(tǒng)中的堆管理細(xì)節(jié)并未完全公開稼稿,所以一切探索都只能靠OllyDbg薄榛、WinDbg等調(diào)試工具讳窟,及各個前輩們探索的資料的指引才能緩緩前行。

Windows操作系統(tǒng)經(jīng)過了很多年的發(fā)展敞恋,其中堆管理機(jī)制也發(fā)生了巨大的變化丽啡,目前的堆管理機(jī)制考慮到了Windows操作系統(tǒng)內(nèi)存有效利用、分配決策效率硬猫、安全性补箍、健壯性等各種因素,在帶來各種性能上優(yōu)化的同時啸蜜,這也使得Windows操作系統(tǒng)的堆管理機(jī)制變得異常復(fù)雜坑雅。本文選取了比較有代表性的Win32平臺的堆管理機(jī)制,研究Windows操作系統(tǒng)堆管理機(jī)制的發(fā)展盔性。經(jīng)過研究霞丧,我們可以將Windows下堆管理機(jī)制的發(fā)展分為三個階段呢岗,

  1. Windows 2000 – Windows XP SP1:這時的堆管理系統(tǒng)比較原始冕香,其完全不考慮堆內(nèi)存的安全性等問題,將全部精力放在任務(wù)分配和提高性能的方面后豫。此時的堆的安全問題比較嚴(yán)重悉尾,比較容易被攻擊。

  2. Windows XP SP2 – Windows 2003:在吸取了上一階段的經(jīng)驗后挫酿,在這一階段构眯,Windows將堆管理分為了前端堆管理器和后端堆管理器。同時也加入了許多安全保護(hù)措施早龟,比如惫霸,堆塊的首部格式被改變并且加入了安全驗證機(jī)制,即Cookie機(jī)制葱弟,當(dāng)雙向鏈表節(jié)點在觸發(fā)刪除操作時壹店,系統(tǒng)會對堆塊的指針進(jìn)行驗證。這些安全保護(hù)措施使得針對堆的攻擊變得非常困難芝加,但是攻擊者仍能通過一些高級的攻擊手段在軟件開發(fā)人員編碼不規(guī)范的情況下對堆溢出實施成功利用硅卢。

  3. Windows Vista – Windows 7:在經(jīng)歷了長時間的發(fā)展后,改革了前端堆管理機(jī)制藏杖,引入了新的堆管理機(jī)制以及堆塊結(jié)構(gòu)将塑。使得在該階段中,不論在分配效率還是在安全防護(hù)上蝌麸,都有了里程碑式的飛躍点寥。

下面本文將就這三個階段堆的環(huán)境準(zhǔn)備、重要結(jié)構(gòu)来吩、分配機(jī)制敢辩、保護(hù)機(jī)制以及常見漏洞的成因和利用方法做出詳細(xì)講解說明汉柒。

二、Windows 2000 – Windows XP SP1

2.1 環(huán)境準(zhǔn)備

32位Windows 2000 SP4虛擬機(jī)责鳍、OllyDbg碾褂、WinDbg。

2.2 重要結(jié)構(gòu)

在該階段历葛,整個堆空間主要由4個結(jié)構(gòu)來維護(hù)正塌,分別是段表(segment list)、虛表(Virtual Allocation list)恤溶、空表(freelist)和快表(lookaside)乓诽。其中,與空表伴生的還有兩個數(shù)據(jù)結(jié)構(gòu)咒程,分別是空表位圖(Freelist Bitmap)和堆緩存(Heap Cache)鸠天,這兩個數(shù)據(jù)結(jié)構(gòu)的引入減少了在分配時對空表的遍歷次數(shù),加快了分配速度帐姻。

2.2.1 堆塊基本結(jié)構(gòu)

該階段中占用狀態(tài)的堆塊結(jié)構(gòu)如圖1所示稠集。

圖1 占用狀態(tài)的堆塊結(jié)構(gòu)

該階段中空閑狀態(tài)的堆塊結(jié)構(gòu)如圖2所示。

圖2 空閑狀態(tài)的堆塊結(jié)構(gòu)

2.2.2 空表

在堆的分配過程中饥瓷,我們主要關(guān)心管理空閑堆塊的空表與快表的分配規(guī)則剥纷。空表共有128個雙向鏈表呢铆,每一條雙向鏈表為一條空表晦鞋,除第0號、1號空表外棺克,從第2號空表到127號空表分別維護(hù)著從16字節(jié)(含堆頭)開始到1016字節(jié)(含堆頭)每8字節(jié)遞增的空表悠垛,即(空表號*8字節(jié))大小。由于空閑狀態(tài)的堆頭信息占8字節(jié)娜谊,因此1號空表始終不會有堆塊鏈入确买。進(jìn)入空表的堆塊遵從先進(jìn)后出(FILO)的規(guī)律。而0號空表則維護(hù)著按大小升序排列的因俐,所有大于1016字節(jié)的小塊和大塊(<512KB)拇惋。空表結(jié)構(gòu)如圖3所示抹剩。

圖3 空表索引區(qū)

2.2.3 空表位圖

空表位圖大小為128bit撑帖,每一bit都對應(yīng)著相應(yīng)一條空表。若該對應(yīng)的空表中沒有鏈入任何空閑堆塊澳眷,則對應(yīng)的空表位圖中的bit就為0胡嘿,反之為1。在從對應(yīng)大小空表分配內(nèi)存失敗后钳踊,系統(tǒng)將嘗試從空表位圖中查找滿足分配大小且存在空閑堆塊的最近的空表衷敌,從而加速了對空表的遍歷勿侯。

2.2.4 堆緩存

堆緩存是一個包含有896個指針的數(shù)組,數(shù)組中的指針為NULL指向0號空表中1024-8192字節(jié)的空閑堆塊缴罗。數(shù)組中的每個元素都對應(yīng)著0號空表中大小為(1K+8字節(jié)*其索引號)的空閑堆塊助琐,若0號空表中存在與其大小匹配的空閑堆塊,則堆緩存數(shù)組中對應(yīng)的元素為指向該空閑堆塊的指針面氓,若無兵钮,則對應(yīng)元素為NULL。堆緩存數(shù)組中的最后一個元素較為特殊舌界,該元素并不會僅指向大小為8192字節(jié)的空閑堆塊掘譬,而是指向0號空表中第一個大于等于8192字節(jié)的空閑堆塊。為加快對堆緩存的遍歷呻拌,又引入了堆緩存位圖對堆緩存中的非空指針進(jìn)行了標(biāo)記葱轩,其作用機(jī)理與上文中的空表位圖相同,在此不做過多贅述藐握。在利用空表位圖從非0號空表中分配內(nèi)存失敗后靴拱,系統(tǒng)將嘗試通過堆緩存位圖索引到堆緩存數(shù)組查找滿足分配大小的0號空表中的空閑堆塊。

2.2.5 快表

快表是與Linux系統(tǒng)中Fastbin相似的存在趾娃,是為加速系統(tǒng)對小塊的分配而存在的一個數(shù)據(jù)結(jié)構(gòu)缭嫡〉抻快表共有128條單向鏈表抬闷,每一條單鏈表為一條快表,除第0號耕突、1號快表外笤成,從第2號快表到127號快表分別維護(hù)著從16字節(jié)(含堆頭)開始到1016字節(jié)(含堆頭)每8字節(jié)遞增的快表,即(快表號*8字節(jié))大小眷茁。由于空閑狀態(tài)的堆頭信息占8字節(jié)炕泳,因此0號和1號快表始終不會有堆塊鏈入。每條快表最多有4個結(jié)點上祈,進(jìn)入快表的堆塊遵從先進(jìn)后出(FILO)的規(guī)律培遵。為提升小堆塊的分配速度,在快表中的空閑堆塊不會進(jìn)行合并操作登刺∽淹螅快表索引區(qū)結(jié)構(gòu)如圖4所示。

圖4 空表索引區(qū)

2.3 堆塊操作

在內(nèi)存中纸俭,堆塊按大小分為3種皇耗,分別為小塊(<1KB)、大塊(<512KB)和巨塊(≥512KB)揍很,堆塊間主要存在3中操作方式郎楼,分別是堆塊的分配箍镜、堆塊的釋放闷营、堆塊的合并。

2.3.1 堆塊分配

堆塊在進(jìn)行分配時,主要會從上文提到的快表和空表中進(jìn)行分配祸轮。

從快表進(jìn)行堆塊分配時,首先會通過用戶申請堆塊大小索引到維護(hù)對應(yīng)大小的快表廊敌,將最后鏈入表中的空閑堆塊從表中卸下湾盒,分配給用戶使用,并將快表頭指向后項空閑堆塊荐操。

從空表進(jìn)行堆塊分配時芜抒,首先會找到維護(hù)對應(yīng)大小的空表,將最后鏈入表中的空閑堆塊從表中卸下托启,分配給用戶使用宅倒,并將空表頭的后項指針指向被卸下的堆塊的后項堆塊。若對應(yīng)大小的空表內(nèi)分配失敗屯耸,則會尋找次優(yōu)項拐迁,在下一個空表中進(jìn)行分配,直到尋找到能夠滿足內(nèi)存分配的最小內(nèi)存的空閑堆塊疗绣。當(dāng)在空表中尋找次優(yōu)項成功時线召,會進(jìn)行切割分配,即從找到的較大堆塊中切割下申請大小的堆塊分配給程序使用多矮,并將切割剩余的部分按大小加上堆頭鏈入對應(yīng)的空表缓淹。若將所有除0號空表外的所有空表都遍歷完仍然沒有分配成功,則判斷0號空表中的最后一個堆塊大小是否大于所需分配內(nèi)存大小塔逃,若大于則從0號空表中正向查找滿足分配大小的最小堆塊進(jìn)行分配讯壶。

在用戶申請分配某一大小的內(nèi)存空間時,系統(tǒng)會首先判斷申請的堆塊是否屬于巨塊范疇湾盗,若是巨塊伏蚊,則采用虛分配,在漏洞利用中遇到較少格粪,本文不予討論躏吊。若申請大塊,則首先考慮堆緩存進(jìn)行分配帐萎,若分配不成功比伏,則從0號空表中尋找最合適的空閑塊進(jìn)行分配。若申請小塊吓肋,則首先查看對應(yīng)大小的快表中有沒有空閑的堆塊凳怨,若無則查看對應(yīng)大小的空表中有沒有空閑的堆塊,若無則通過空表位圖查找更大的空表中有沒有空閑的堆塊進(jìn)行切割分配,若無則采用堆緩存進(jìn)行分配肤舞,若分配失敗紫新,則從0號空表中尋找最適合的空閑快進(jìn)行分配,若依然失敗李剖,則會先進(jìn)行內(nèi)存緊縮后再嘗試分配芒率。堆塊分配流程如圖5所示。

圖5 堆塊分配流程

2.3.2 堆塊釋放

堆塊釋放篙顺,即將堆塊從占用狀態(tài)更改為空閑狀態(tài)偶芍。在準(zhǔn)備釋放某一大小的內(nèi)存空間時,首先會判斷釋放釋放的堆塊是否屬于巨塊范疇德玫,若是巨塊匪蟀,則直接將該空間釋放,不會進(jìn)入任何堆表宰僧。若是大塊材彪,則嘗試將其釋放入堆緩存,若堆緩存已滿琴儿,則鏈入0號空表段化。若是小塊,則首先嘗試鏈入對應(yīng)大小的快表造成,若鏈入快表显熏,為了加快堆塊的分配,系統(tǒng)不會更改其占用狀態(tài)晒屎。若對應(yīng)大小的快表中已經(jīng)鏈滿了4個空閑堆塊喘蟆,則將該堆塊鏈入對應(yīng)大小的空表中。

2.3.3 堆塊合并

在進(jìn)行堆塊釋放時夷磕,若釋放堆塊直接進(jìn)入空表(鏈接在快表中的空閑堆塊不會進(jìn)行合并操作)履肃,并且與該堆塊物理地址相鄰的堆塊同為空閑態(tài),則會進(jìn)行堆塊的合并坐桩。在進(jìn)行堆塊合并時,會將堆塊從空表中卸下封锉,將兩個相鄰的內(nèi)存空間整合后更新新空閑堆塊的堆頭信息绵跷,并根據(jù)新空閑堆塊的大小鏈入相應(yīng)大小的空表中。除了堆塊的釋放會觸發(fā)堆塊合并外成福,在申請堆塊時碾局,若未成功從快表、堆緩存及空表中分配空間奴艾,則會觸發(fā)內(nèi)存緊縮净当。內(nèi)存緊縮會將堆空間中的所有空閑堆塊,無論地址是否連續(xù),都整合成一個大的空閑堆塊再進(jìn)行堆塊分配像啼。

2.4 保護(hù)機(jī)制

微軟對于Windows系統(tǒng)的內(nèi)存保護(hù)機(jī)制是從Windows XP SP2版本才開始有明顯建樹的俘闯,在Windows 2000 – Windows XP SP1版本這一階段,微軟僅考慮了操作系統(tǒng)的性能和功能完整性忽冻,并沒有過多考慮安全性因素真朗,也正是由于這點,導(dǎo)致在該階段系統(tǒng)中存在的漏洞極易被利用僧诚。

2.5 漏洞利用

如上文所說遮婶,該階段為Windows系統(tǒng)原生階段,只考慮了系統(tǒng)的性能和功能完整性湖笨,并沒有過多的考慮安全性因素旗扑。因此在該階段的堆漏洞的利用方法是最多樣、最自由也是最穩(wěn)定的慈省,如DWORD SHOOT肩豁、Heap Spray等。接下來將詳細(xì)介紹在該階段操作系統(tǒng)中比較經(jīng)典和常見的漏洞的產(chǎn)生原因以及利用方式辫呻。

2.5.1 DWORD SHOOT

2.5.1.1 漏洞成因

該漏洞產(chǎn)生的主要原因是空表在將堆塊進(jìn)行Unlink操作時清钥,未對堆塊前項指針和后項指針的合法性進(jìn)行安全檢測,在對其賦值時產(chǎn)生的漏洞放闺,Unlink算法偽代碼如圖6所示祟昭。

圖6 Unlink算法

由于可以達(dá)到對任意地址寫4字節(jié)數(shù)據(jù)的效果,因此被命名為DWORD SHOOT怖侦。也是為了防止攻擊者對該漏洞的利用篡悟,Windows在下一階段的版本中更新了Safe Unlink機(jī)制,對將要Unlink堆塊的前項指針及后項指針的合法性進(jìn)行安全檢測匾寝。

2.5.1.2 利用方式

在堆溢出的基礎(chǔ)上搬葬,修改相鄰堆塊堆頭中的前項指針和后項指針,之后在對被修改后的堆塊進(jìn)行Unlink操作時艳悔,由于不會檢測前項指針及后項指針的合法性急凰,按照Unlink算法的邏輯會將Flink的數(shù)據(jù)寫到Blink指向地址字節(jié)的位置,即可實現(xiàn)任意地址寫4字節(jié)可控數(shù)據(jù)的操作猜年。在得到任意地址寫4字節(jié)的機(jī)會后抡锈,可以有各式各樣的利用方式,比如將敏感函數(shù)的地址寫到另一個函數(shù)的跳轉(zhuǎn)地址或虛表上乔外,再引導(dǎo)程序流去觸發(fā)該跳轉(zhuǎn)達(dá)到利用目的床三,當(dāng)然該敏感函數(shù)的地址也可以為提前布置好的shellcode起始地址。接下來舉一個較為常見的利用DWORD SHOOT漏洞的方法杨幼。

該方法通過篡改P.E.B中的函數(shù)指針為shellcode起始地址實現(xiàn)惡意代碼的執(zhí)行撇簿。P.E.B結(jié)構(gòu)中存放的RtlEnterCriticalSection()和RtlLeaveCriticalSection()函數(shù)指針是一個比較理想的攻擊地址聂渊。在程序正常退出時會調(diào)用ExitProcess(),為了同步線程該函數(shù)又會調(diào)用RtlEnterCriticalSection()及RtlLeaceCriticalSection()進(jìn)行處理四瘫。除此之外汉嗽,在此階段的Windows系統(tǒng)中P.E.B結(jié)構(gòu)擁有著固定的地址為0x7FFDF000,向下偏移0x20位RtlEnterCriticalSection()的函數(shù)指針莲组,即地址為0x7FFDF020诊胞,緊接著0x7FFDF024的地址存放著RtlLeaveCriticalSection()的函數(shù)指針。由于以上原因锹杈,導(dǎo)致在該階段的操作系統(tǒng)中撵孤,P.E.B結(jié)構(gòu)成了DWORD SHOOT等任意地址寫漏洞利用方法的絕佳狙擊點。為防止攻擊者有機(jī)可乘竭望,Windows在下一階段的版本中更新了P.E.B Random機(jī)制邪码,將P.E.B結(jié)構(gòu)的地址進(jìn)行了隨機(jī)化。

了解該漏洞利用方式的原理后咬清,我們將堆塊的后項指針篡改為0x7FFDF020闭专,將前項指針篡改為提前布置好的shellcode的起始地址,在將該堆塊從空表中申請回來時觸發(fā)Unlink操作就完成了漏洞的利用旧烧,導(dǎo)致shellcode中代碼的執(zhí)行影钉。

除了狙擊P.E.B結(jié)構(gòu)外,該漏洞還常常攻擊Windows異常處理機(jī)制中的S.E.H結(jié)構(gòu)掘剪、V.E.H結(jié)構(gòu)平委、U.E.F結(jié)構(gòu)等,由于上述結(jié)構(gòu)在內(nèi)存中都有固定地址夺谁,利用方法與剛剛提到的P.E.B結(jié)構(gòu)相同廉赔,因此不再一一贅述。

2.5.2 Heap Spray

2.5.2.1 漏洞成因

Heap Spray匾鸥,又稱堆噴蜡塌,與典型能夠?qū)嵤┚珳?zhǔn)攻擊的堆漏洞不同,堆噴是一種比較暴力且相對不穩(wěn)定的攻擊手法勿负,并且該手法常常被用來針對瀏覽器馏艾。其產(chǎn)生的原因主要是應(yīng)用程序在堆分配空間時沒有過多的約束,使得攻擊者能夠多次申請堆塊占據(jù)大部分內(nèi)存笆环,再通過地毯式的覆蓋攒至,最終劫持程序控制流導(dǎo)致惡意代碼被執(zhí)行。

在棧溢出的利用方式中躁劣,劫持程序控制流后往往會將EIP修改為shellcode布置的地址,而為了提高shellcode成功執(zhí)行的幾率库菲,往往會在前方加一小段不影響shellcode執(zhí)行的滑梯指令(slide code)账忘,常用的滑梯指令有nop指令(0x90)及or al指令(0x0c0c)。而隨著操作系統(tǒng)安全性的提升,尤其是地址隨機(jī)化的誕生鳖擒,使得普通的溢出漏洞難以再掀起波瀾溉浙。于是研究者們發(fā)明了堆噴這一種攻擊手法作為輔助攻擊的方式。

2.5.2.2 利用方式

該攻擊手法的前提條件為已經(jīng)可以修改EIP寄存器的值為0x0c0c0c0c蒋荚。每次申請1M的內(nèi)存空間戳稽,利用多個0x0c指令與shellcode相結(jié)合用來填充該空間,一般來說shellcode只占幾十字節(jié)期升,相對的滑梯指令占了接近1M惊奇,導(dǎo)致滑梯指令的大小遠(yuǎn)遠(yuǎn)大于shellcode大小。通過多次申請1M的空間來將進(jìn)程空間中的0x0c0c0c0c地址覆蓋播赁。因為有遠(yuǎn)大于shellcode的滑梯指令的存在颂郎,該地址上的值有99%以上的幾率被覆蓋為0x0c0c0c0c,從而執(zhí)行到shellcode容为。由于堆分配是從低地址向高地址分配乓序,因此一般申請200M(0x0c800000)的堆塊就能夠覆蓋到0x0c0c0c0c的地址。

該利用方式中之所以不采用0x90作為滑梯指令坎背,主要是因為內(nèi)存空間中存放了許多對象的虛函數(shù)指針替劈,當(dāng)將這些虛函數(shù)指針覆蓋到0x90909090后,在調(diào)用該函數(shù)就會導(dǎo)致程序崩潰得滤,該階段操作系統(tǒng)分配給用戶使用的內(nèi)存為前2G陨献,即0x00000000 - 0x7FFFFFFF,其中進(jìn)程僅能訪問0x00010000 – 0x7FFEFFFF耿戚,從0x80000000 – 0xffffffff的后2G內(nèi)存被設(shè)計來只有內(nèi)核能夠訪問湿故。而覆蓋為0x0c0c0c0c時,0x0c0c0c0c地址有很大幾率已經(jīng)被我們用滑梯指令所覆蓋膜蛔,從而直接執(zhí)行shellcode坛猪。因此,若虛函數(shù)指針被覆蓋為0x90909090為內(nèi)核空間皂股,不能被進(jìn)程所訪問墅茉,采用0x0c作為滑梯指令一舉兩得。

該利用方式由于會很暴力地申請多次內(nèi)存呜呐,并將構(gòu)造好的大量滑梯指令及小部分的shellcode像井噴一樣“噴”滿內(nèi)存各處就斤,因此又被很形象地命名為“堆噴”。

三蘑辑、 Windows XP SP2 – Windows 2003

3.1 環(huán)境準(zhǔn)備

32位Windows XP SP3虛擬機(jī)洋机、OllyDbg、WinDbg洋魂。

3.2 重要結(jié)構(gòu)

在該階段绷旗,堆塊的數(shù)據(jù)結(jié)構(gòu)基本繼承于Windows 2000 – Windows XP SP1階段的數(shù)據(jù)結(jié)構(gòu)喜鼓。但由于增加了一些保護(hù)機(jī)制,導(dǎo)致了堆塊的堆頭的基本結(jié)構(gòu)與原始結(jié)構(gòu)有所差別衔肢。

該階段中占用狀態(tài)的堆塊結(jié)構(gòu)如圖7所示庄岖。

圖7 占用狀態(tài)的堆塊結(jié)構(gòu)

該階段下空閑狀態(tài)的堆塊結(jié)構(gòu)如圖8所示。

圖8 空閑狀態(tài)的堆塊結(jié)構(gòu)

3.3 堆塊操作

在該階段角骤,堆的分配被劃分為前端堆管理器(Front-End Manager)和后端堆管理器(Back-End Manager)隅忿,其中前端堆管理器主要由上文中提到的快表有關(guān)的分配機(jī)制構(gòu)成,后端堆管理器則是由空表有關(guān)的分配機(jī)制構(gòu)成邦尊。除前背桐、后端堆管理器以外的堆塊分配、釋放胳赌、合并等操作基本繼承于Windows 2000 – Windows XP SP1階段的堆塊操作牢撼。

3.4 保護(hù)機(jī)制

從該階段開始,微軟漸漸開始重視Windows操作系統(tǒng)的安全性疑苫,逐步在內(nèi)存中加入了許多安全保護(hù)機(jī)制熏版,如GS、Safe S.E.H捍掺、DEP撼短、ASLR及部分堆保護(hù)機(jī)制等。本部分將就該階段中Windows系統(tǒng)中新增加的堆保護(hù)機(jī)制做出部分說明挺勿。

3.4.1 Heap Cookie

Heap Cookie從Windows XP SP2版本開始使用曲横,為上文提到的改變了Windows堆塊結(jié)構(gòu)的保護(hù)機(jī)制,該機(jī)制將堆頭信息中原1字節(jié)的段索引(Segment Index)的位置新替換成了security cookie用來校驗是否發(fā)生了堆溢出不瓶,相應(yīng)的原1字節(jié)的標(biāo)簽索引(Tag Index)的位置替換為段索引位置禾嫉,取消掉了標(biāo)簽索引。

該機(jī)制是在堆塊分配時在堆頭中隨機(jī)生成1字節(jié)的cookie用于保護(hù)其之后的標(biāo)志位(Flags)蚊丐、未使用大小(Unused bytes)熙参、段索引及前項堆塊指針(Flink)、后項堆塊指針(Blink)等敏感數(shù)據(jù)不被堆溢出所篡改麦备。并在堆塊被釋放時檢查堆頭中的cookie是否被篡改孽椰,若被篡改則調(diào)用RtlpHeapReportCorruption()結(jié)束進(jìn)程。值得一提的是凛篙,此函數(shù)在HeapEnableTerminateOnCorrupton字段被設(shè)置后才會起到結(jié)束進(jìn)程的效果黍匾,而在該階段的版本中該字段默認(rèn)不啟用,因此該函數(shù)并沒有起到結(jié)束進(jìn)程的作用呛梆。

3.4.2 Safe Unlink

Safe Unlink保護(hù)機(jī)制在前一階段版本中的Unlink算法前加上了安全檢查機(jī)制锐涯。該機(jī)制在堆塊從堆表中進(jìn)行拆卸的操作時,對堆頭前項指針和后項指針的合法性進(jìn)行了檢查填物,解決了之前版本中可通過篡改堆頭的前項指針和后項指針輕易執(zhí)行惡意代碼的安全隱患全庸。Safe Unlink算法偽代碼如圖9所示秀仲。

圖9 Safe Unlink算法

3.4.3 PEB Random

P.E.B結(jié)構(gòu)(Process Envirorment Block Structure)中包含了進(jìn)程的信息融痛。該機(jī)制將在老版本W(wǎng)indows中固定為0x7FFDF000的P.E.B結(jié)構(gòu)地址進(jìn)行了隨機(jī)化壶笼,解決了之前版本中能輕易對固定地址的P.E.B結(jié)構(gòu)中函數(shù)指針進(jìn)行非法操作,從而執(zhí)行惡意代碼的安全隱患雁刷。

3.5 漏洞利用

如上文所說覆劈,該階段的版本只是在前一階段的基礎(chǔ)上加入了一些保護(hù)機(jī)制,盡管這些保護(hù)機(jī)制的引入杜絕了前一版本中的一些常見漏洞沛励,如空表堆塊拆卸時的DWORD SHOOT责语,和一些通用的攻擊手法,如狙擊P.E.B結(jié)構(gòu)中的函數(shù)指針目派。在常規(guī)空表利用條件日漸苛刻的環(huán)境下坤候,安全研究人員將目光轉(zhuǎn)向了快表、0號空表企蹭、堆緩存及空表位圖的利用白筹。

3.5.1 Bypass Safe Unlink

3.5.1.1 漏洞成因

雖然在加入了Safe Unlink條件后,極大的限制了DWORD SHOOT攻擊的使用場景谅摄,但隨著研究人員對Safe Unlink檢測機(jī)制的研究徒河,仍然構(gòu)造出了一種十分苛刻的場景達(dá)到去繞過Safe Unlink檢測機(jī)制,觸發(fā)漏洞最終導(dǎo)致任意地址寫送漠。

3.5.1.2 利用方式

按照上文Safe Unlink保護(hù)機(jī)制所述顽照,在unlink一個堆塊時,會檢查該堆塊后項堆塊的Flink字段和該堆塊前項堆塊的Blink字段是否都指向該堆塊闽寡,根據(jù)堆塊指針和前項后項指針的偏移為0和4字節(jié)代兵,可以將判斷條件簡化為如圖10所示偽代碼。

圖10 Safe Unlink算法

當(dāng)需要unlink的堆塊為該空表上的唯一一個堆塊爷狈,此時會存在一個特殊情況:堆塊的Flink字段等于Blink字段等于空表頭結(jié)點植影,空表頭結(jié)點的Flink字段也等于Blink字段等于堆塊地址,如圖11所示淆院。

圖11 Bypass Safe Unlink(1)

若能夠通過堆溢出漏洞將該堆塊的Flink字段修改為Freelist[x-1].Blink何乎,將Blink字段修改為Freelist[x].Blink,此時仍然可以通過Unlink之前的安全檢測土辩,如圖12所示支救。

圖12 Bypass Safe Unlink(2)

并且此時繞過安全檢測后執(zhí)行Unlink操作的結(jié)果如圖13所示。

圖13 Bypass Safe Unlink(3)

在下次申請該大小的堆塊時拷淘,按照算法會將Freelist[x].Blink指向的堆塊分配給用戶使用各墨,而在之前構(gòu)造好的條件下會將Freelist[x-1].Blink及下方的空間當(dāng)成堆塊分配給用戶,并且該堆塊的用戶區(qū)指針為Freelist[x].Blink启涯。此時我們第一次對指針進(jìn)行寫時贬堵,會從Freelist[x-1].Blink往下寫恃轩,很容易將Freelist[x].Blink覆蓋為任意地址,第二次寫時即可往任意地址寫任意數(shù)據(jù)黎做。

3.5.2 LookAside Attack

3.5.2.1 漏洞成因

該漏洞的產(chǎn)生是由于快表在分配堆塊時叉跛,未檢測其Flink字段指向地址的合法性,會造成在按照快表分配算法執(zhí)行時蒸殿,會將非法地址作為堆頭分配給用戶筷厘,最終導(dǎo)致任意地址寫任意長度數(shù)據(jù)的漏洞。

3.5.2.2 利用方式

在堆溢出的基礎(chǔ)上宏所,使與可溢出堆塊相鄰的下一個堆塊鏈入空表酥艳,再利用堆溢出將鏈入空表堆塊的前項指針修改為函數(shù)跳轉(zhuǎn)地址或虛表地址。構(gòu)造好堆塊后爬骤,在接下來快表第一次分配相應(yīng)大小的堆塊時會將被篡改堆頭的堆塊分配給用戶使用充石,并將非法Flink地址作為堆頭鏈入空表頭結(jié)點,在快表第二次分配相應(yīng)大小的堆塊時霞玄,即可將指定地址及其后方空間作為堆塊申請給用戶使用骤铃,再對堆塊進(jìn)行賦值即可造成任意地址寫任意數(shù)據(jù)的操作。該偽造的地址一般可以為敏感函數(shù)溃列、虛表地址等以及上文所提到的該版本中的堆攻擊重災(zāi)區(qū):P.E.B結(jié)構(gòu)及異常處理機(jī)制中的各種結(jié)構(gòu)劲厌。整個過程如圖14所示。

圖14 LookAside Attack利用過程

3.5.3 Bitmap XOR Attack

3.5.3.1 漏洞成因

該漏洞產(chǎn)生的原因為在更新空表位圖狀態(tài)時听隐,以當(dāng)前堆塊的Size字段作為索引补鼻,且在之前未有適當(dāng)?shù)陌踩珯z測機(jī)制,可能會導(dǎo)致空表位圖狀態(tài)與實際空表狀態(tài)不同步的效果雅任,最終通過利用漏洞會達(dá)到任意地址寫任意數(shù)據(jù)的效果证膨」矗空表位圖更新算法的偽代碼如圖15所示丐重。

圖15 空表位圖更新算法

3.5.3.2 利用方式

如上文空表位圖更新算法所示怒见,在每次空表中的堆塊進(jìn)行Unlink操作后會判斷相應(yīng)的空表位圖是否需要更新,若Unlink的堆塊為該空表中的最后一個堆塊禽车,則會對堆塊當(dāng)前Size字段對應(yīng)的空表位圖做異或操作寇漫。在基于堆溢出的場景中,該算法中存在多處漏洞殉摔。

首先構(gòu)造只存在一個堆塊的空表且與該堆塊相鄰前一堆塊存在堆溢出的場景州胳。如圖16所示。

圖16 Bitmap XOR Attack(1)

若此時上方堆塊只存在單字節(jié)溢出漏洞逸月,即僅能覆蓋到空表中堆塊的Size字段栓撞。在對空表中堆塊進(jìn)行Unlink操作前,先將其Size字段篡改為8*n,如圖17所示瓤湘。

圖17 Bitmap XOR Attack(2)

按照空表位圖更新算法瓢颅,該堆塊會正常進(jìn)行Unlink操作,并且會執(zhí)行更新空表位圖的代碼弛说。但是由于Size字段已被覆蓋挽懦,導(dǎo)致在索引空表位圖時不再是Bitmap[x]而是Bitmap[n],然后對索引到的空表位圖做異或操作剃浇,即Bitmap[x]不改變巾兆,Bitmap[n]進(jìn)行反轉(zhuǎn)。如圖18所示虎囚。

圖18 Bitmap XOR Attack(3)

此時x號空表中沒有堆塊,表頭的前項指針和后項指針都指向自身蔫磨,并且對應(yīng)的空表位圖置位為1淘讥,即堆管理器認(rèn)為x號空表中仍有空閑堆塊。在下一次申請8x大小的堆塊時堤如,則會將Freelist[x].Blink指向的地址作為堆塊分配給用戶使用蒲列,即將8x大小的空表表頭當(dāng)做堆塊,在用戶進(jìn)行編輯后的第二次申請編輯時即可造成任意地址寫任意數(shù)據(jù)搀罢。

以上討論了堆溢出僅能覆蓋堆塊Size字段時的場景蝗岖,在當(dāng)堆溢出能夠覆蓋到堆塊的前項和后項指針字段時,該攻擊手法的應(yīng)用場景更加廣泛榔至。

首先抵赢,將前項指針和后項指針覆蓋為相同值,此時按照空表位圖更新算法唧取,在Safe Unlink的安全檢測機(jī)制處會被檢查出來铅鲤,且不會對該堆塊執(zhí)行Unlink操作,而是調(diào)用了RtlpHeapReportCorruption()枫弟。如上文所提到的邢享,在現(xiàn)階段的版本中該函數(shù)不會導(dǎo)致進(jìn)程結(jié)束。因此淡诗,prev和next并未被新賦值骇塘,仍然為覆蓋后相等的狀態(tài),因此會被判斷為需要更新空表位圖韩容,并且此時的Size字段也是在堆溢出的覆蓋范圍內(nèi)款违,之后的操作與第一種場景中相同,此處不再贅述宙攻。

在構(gòu)造的第二種場景中奠货,由于跳過了Unlink的賦值,prev和next始終相等座掘,一定會更新空表位圖递惋。因此不需要滿足被溢出堆塊為其空表中的唯一一個堆塊的條件柔滔,所以應(yīng)用場景更加廣泛

3.5.4 Freelist[0] Linking Attack

3.5.4.1 漏洞成因

在引入Safe Unlink機(jī)制使得Unlink操作變得困難后,研究人員們將目光投向了Unlink的逆過程Link萍虽。很快他們就發(fā)現(xiàn)了Link操作尚未添加保護(hù)機(jī)制檢測堆塊前項指針和后向指針的合法性睛廊,并在對指針進(jìn)行賦值操作時能產(chǎn)生和DWORD SHOOT效果相似的漏洞。但是相較于DWORD SHOOT存在一定的局限性杉编,該漏洞最終只能達(dá)到任意地址寫4字節(jié)堆塊地址的效果超全。Link算法偽代碼如圖19所示,其中ChunkA為將要鏈入0號空表的堆塊邓馒,ChunkB為本就在0號空表中的堆塊嘶朱。

圖19 Link算法

3.5.4.2 利用方式

首先構(gòu)造一個在Freelist[0]中并且與該堆塊相鄰的前一堆塊存在至少0x10字節(jié)溢出的場景,并且該堆塊的大小應(yīng)該大于其后項堆塊大小的兩倍光酣,本場景中為0x550>0x220*2疏遏。如圖20所示。

圖20 Freelist[0] Linking Attack(1)

在從0號空表中申請堆塊前將空表中堆塊的堆頭溢出救军,覆蓋其前項后項指針财异,在該攻擊方式中Size字段甚至可以不變。如圖21所示唱遭。

圖21 Freelist[0] Linking Attack(2)

此時戳寸,申請一個大于其后項堆塊小于自身,且與自身的差大于申請堆塊大小的堆塊拷泽,本場景中為0x250(0x550>0x250>0x220且0x550-0x250>0x250)疫鹊。按照0號空表的分配算法,首先會對0x550堆塊進(jìn)行Unlink操作跌穗,由于前項后項指針被篡改后不通過Safe Unlink的檢查機(jī)制订晌,因此不會執(zhí)行Unlink而直接將該堆塊切分為0x250堆塊和0x300堆塊。其中的0x250堆塊分配給用戶使用蚌吸,0x300堆塊被插入到0號空表中的合適位置锈拨。根據(jù)算法,該合適位置將會是0x250堆塊之后羹唠。如圖22所示奕枢。

圖22 Freelist[0] Linking Attack(3)

該堆塊在合適位置進(jìn)行Link操作前,需滿足相對Fake_Flink和Fake_Blink的Size字段大于插入堆大小的條件佩微,本場景中為[Fake_Flink-8]>0x300和[Fake_Blink-0xc]>0x300缝彬。除此之外,還需滿足并且Fake_Flink及Fake_Blink+4的地址可寫的條件哺眯。

在滿足上述各項條件后谷浅,0x300堆塊插入0號空表合適位置時,按照Link算法將會觸發(fā)漏洞的效果如圖23所示。

圖23 觸發(fā)效果

由于Fake_Flink及Fake_Blink都是通過堆溢出可控的字段一疯,因此觸發(fā)該漏洞達(dá)到了任意地址寫堆塊地址的效果撼玄。雖然該攻擊手段利用條件十分苛刻且單靠其很難劫持控制流,但可同時配合其他漏洞達(dá)成更具有攻擊性的目的墩邀。

3.5.5 Freelist[0] Searching Attack

3.5.5.1 漏洞成因

該漏洞的產(chǎn)生是由于0號空表在進(jìn)行遍歷搜索合適堆塊時掌猛,未對鏈表中堆塊前項指針的合法性進(jìn)行校驗,導(dǎo)致在遍歷時跳出0號空表眉睹,最終通過利用漏洞達(dá)到任意地址寫任意數(shù)據(jù)的效果荔茬。

3.5.5.2 利用方式

首先構(gòu)造一個在Freelist[0]中并且與該堆塊相鄰的前一堆塊存在至少0xc字節(jié)溢出的場景,并且該堆塊不能為0號空表中的最大塊竹海。如圖24所示慕蔚。

圖24 Freelist[0] Searching Attack(1)

在遍歷0號空表中前將空表中堆塊的堆頭溢出,覆蓋其前項指針站削,在該攻擊方式中Size字段甚至可以不變坊萝。如圖25所示。

圖25 Freelist[0] Searching Attack(2)

此時许起,申請一個大于該堆塊且小于0號空表中最大堆塊大小的堆塊。按照0號空表的搜索算法菩鲜,在遍歷過被溢出堆塊后园细,會將偽造的Fake_Flink作為下一個堆塊的入口地址,比較其Size字段是否滿足申請空間的大小接校。如圖26所示猛频。

圖26 Freelist[0] Searching Attack(3)

為了使堆管理器將該Fake_Flink地址作為堆塊入口分配給用戶使用,需要滿足[Fake_Flink-8]的Size字段大于申請大小蛛勉,并且為了不產(chǎn)生堆切割及其后續(xù)繁瑣操作鹿寻,應(yīng)該控制該Size字段在申請堆塊大小+8字節(jié)之內(nèi),即RequstSize≤Size≤RequestSize+8诽凌。在Size字段條件滿足后毡熏,該偽造堆塊會進(jìn)行Unlink操作,雖然會毫無懸念地被Safe Unlink機(jī)制檢測出來侣诵,但仍然會被分配給用戶使用痢法。由于會進(jìn)行Safe Unlink檢測,因此該堆塊的Flink及Bilnk杜顺,即Fake_Flink和Fake_Flink+4應(yīng)該是可讀的财搁。

由于Fake_Flink為堆溢出所偽造,因此只需要攻擊者構(gòu)造滿足上述條件的Fake_Flink躬络,即可達(dá)到任意地址寫任意數(shù)據(jù)的效果尖奔。

四、 Windows Vista – Windows 7

4.1 環(huán)境準(zhǔn)備

32位Windows 7 SP1虛擬機(jī)、OllyDbg提茁、WinDbg淹禾。

4.2 重要結(jié)構(gòu)

從Windows Vista版本開始,Windows系統(tǒng)舍棄了前版本中的以快表為核心的前端堆管理器甘凭,而引入了一套稱為低碎片堆(Low Fragmentation Heap)的全新的數(shù)據(jù)結(jié)構(gòu)和算法作為前端堆管理器稀拐,后端堆管理器為了適配新的前端堆管理器的在管理機(jī)制也與前版本的后端管理器有部分差異。

從該版本開始丹弱,由前端堆管理器分配給用戶的堆塊的結(jié)構(gòu)改變成了UserBlocks德撬,與之前版本中的Lookaside相類似。有后端堆管理器分配給用戶的堆塊結(jié)構(gòu)改變成了ListHints,與之前版本中的Freelist相類似躲胳。除此之外蜓洪,管理堆的HeapBase中有個FreeLists成員容易與之前版本中的Freelist相混淆,該成員鏈接了該HeapBase所管理的所有空閑堆的指針坯苹。值得一提的是隆檀,在下文中將用到新的單位block,1block=8byte粹湃。

4.2.1 UserBlocks

該結(jié)構(gòu)體位于HeapBase(_HEAP)->FrontEndHeap(_LFH_HEAP)->LocalData(_HEAP_LOCAL_DATA)->SegmentInfo(_HEAP_LOCAL_SEGMENT_INFO)->ActiveSubsegment/Hint(_HEAP_SUBSEGMENT)結(jié)構(gòu)體中恐仑。

由于前端堆的管理結(jié)構(gòu)較為復(fù)雜,本文挑選其中重要結(jié)構(gòu)體中的重要成員進(jìn)行闡述为鳄。

4.2.1.1 _LFH_HEAP

FrontEndHeap的數(shù)據(jù)結(jié)構(gòu)_LFH_HEAP如圖27所示裳仆。

圖27 _LFH_HEAP數(shù)據(jù)結(jié)構(gòu)

_LFH_HEAP結(jié)構(gòu)體中我們主要關(guān)心LocalData字段,該字段是一個指針孤钦,保存了每個維護(hù)UserBlocks的SubSegment的信息歧斟。

4.2.1.2 _HEAP_LOCAL_DATA

LocalData的數(shù)據(jù)結(jié)構(gòu)_HEAP_LOCAL_DATA如圖28所示。

圖28 _HEAP_LOCAL_DATA數(shù)據(jù)結(jié)構(gòu)

_HEAP_LOCAL_DATA結(jié)構(gòu)體中共包含了大小為128的SegmentInfo數(shù)組偏形,該數(shù)組中的每個元素都按照_RtlpBucketBlockSizes數(shù)組中所對應(yīng)的大小(不包括堆頭大小)維護(hù)著所有小于16KB的UserBlocks静袖。該數(shù)組如圖29所示。

圖29 _RtlpBucketBlockSizes數(shù)組

例如SegmentInfo[0]維護(hù)著所有用戶區(qū)為0字節(jié)的堆塊俊扭,由于不存在队橙,所以SegmentInfo[0]不維護(hù)堆塊,SegmentInfo[8]則維護(hù)著所有用戶區(qū)為0x40字節(jié)的堆塊统扳。

4.2.1.3 _HEAP_LOCAL_SEGMENT_INFO

SegmentInfo的數(shù)據(jù)結(jié)構(gòu)_HEAP_LOCAL_SEGMENT_INFO如圖30所示喘帚。

圖30 _HEAP_LOCAL_SEGMENT_INFO數(shù)據(jù)結(jié)構(gòu)

Hint和ActiveSubsegment都是直接管理UserBlocks的字段,初始化為NULL咒钟,其中Hint字段僅在free了前端管理器所分配的堆塊后才會被賦值吹由,ActiveSubsegment字段在第一次請求分配時就會被賦值,兩個字段相輔相成朱嘴,為方便表述倾鲫,以下以Hint字段為例進(jìn)行進(jìn)一步的說明粗合。

LocalData字段指向管理該SegmentInfo的LocalData地址。

BucketIndex字段表示該SegmentInfo所維護(hù)的堆塊用戶區(qū)的blcok尺寸乌昔。

4.2.1.4 _HEAP_SUBSEGMENT

Hint的數(shù)據(jù)結(jié)構(gòu)_HEAP_SUBSEGMENT如圖31所示隙疚。

圖31 _HEAP_SUBSEGMENT數(shù)據(jù)結(jié)構(gòu)

LocalInfo字段指向管理該Hint/ActiveSubsegment的SegmentInfo地址。

UserBlocks字段為用戶堆塊開始的頭部磕道,緊接著UserBlocks之后就是相連的大小固定的用戶區(qū)供屉。下面以SegmentInfo[5]->Hint.UserBlcks所維護(hù)的大小為0x30(用戶區(qū)為0x28)的堆塊為例,其在內(nèi)存空間上如圖32所示溺蕉。

圖32 SegmentInfo[5]->Hint.UserBlocks

值得一提的是伶丐,空閑狀態(tài)堆塊用戶區(qū)的前2字節(jié)會存放下一個空閑堆的偏移,以方便在申請堆塊時及時更新下文中提到的AggregateExchg中的FreeEntryOffset字段疯特,如圖33所示哗魂。

圖33 用戶區(qū)偏移

BlockSize字段表示該結(jié)構(gòu)體所維護(hù)堆塊(包括堆頭)的block尺寸。

BlockCount字段表示該結(jié)構(gòu)體所維護(hù)的所有堆塊的數(shù)量漓雅。

SizeIndex字段表示該結(jié)構(gòu)體所維護(hù)堆塊用戶區(qū)的block尺寸录别,與之前提到的BucketIndex相同,即存在以下等式:BucketIndex=SizeIndex=BlockSize-1邻吞。

AggregateExchg字段指向_INTERLOCK_SEQ結(jié)構(gòu)體组题,該用于在分配和釋放堆塊時索引相應(yīng)堆塊。

4.2.1.5 _INTERLOCK_SEQ

AggregateExchg的數(shù)據(jù)結(jié)構(gòu)_INTERLOCK_SEQ如圖34所示抱冷。

圖34 _INTERLOCK_SEQ數(shù)據(jù)結(jié)構(gòu)

Depth字段記錄了在UserBlocks中的空閑堆塊個數(shù)往踢。

FreeEntryOffset字段表示從UserBlocks頭部索引到下一個將要分配的堆塊的block尺寸,即下一個分配堆塊的地址為UserBlocks+8*FreeEntryOffset徘层。

4.2.2 FreeLists

該結(jié)構(gòu)體位于HeapBase(_HEAP)結(jié)構(gòu)體中。

4.2.2.1 _LIST_ENTRY

FreeLists的_LIST_ENTRY結(jié)構(gòu)如圖35所示利职。

圖35 _HEAP_ENTRY結(jié)構(gòu)體

該結(jié)構(gòu)相對簡單趣效,F(xiàn)link和Blink即后項指針和前項指針。FreeLists為雙向鏈表猪贪,將該HeapBase所管理的所有后端分配的空閑堆塊按照大小由小到大的順序鏈在一起跷敬。

4.2.3 ListHints

該結(jié)構(gòu)體位于HeapBase(_HEAP)->BlocksIndex(_HEAP_LIST_LOOKUP)結(jié)構(gòu)體中。

4.2.3.1 _HEAP_LIST_LOOKUP

管理ListHints的_HEAP_LIST_LOOKUP結(jié)構(gòu)體數(shù)據(jù)結(jié)構(gòu)如圖36所示热押。

圖36 _HEAP_LIST_LOOKUP數(shù)據(jù)結(jié)構(gòu)

下面針對該版本下此結(jié)構(gòu)體中的重要成員進(jìn)行講解西傀。

若該結(jié)構(gòu)體需要擴(kuò)展,則ExtendedLookup為指向下一個_HEAP_LIST_LOOKUP的指針桶癣,若不需要擴(kuò)展拥褂,則為NULL。

ArraySize為在該結(jié)構(gòu)中ListHints可以尋址到的最大的block尺寸牙寞,在該階段的版本中ArraySize的值為0x80或0x800饺鹃。例如莫秆,HeapBase->BlocksIndex中的ArraySize為0x80,若有擴(kuò)展悔详,則擴(kuò)展后結(jié)構(gòu)中的ArraySize為0x800,即HeapBase->BlocksIndex->ExtendedLookup.ArraySize=0x800镊屎。

ItemCount的值表示該_HEAP_LIST_LOOKUP結(jié)構(gòu)中free狀態(tài)堆塊的個數(shù)。

OutOfRangeItems的值表示該_HEAP_LIST_LOOKUP結(jié)構(gòu)中超過ArraySize大小的堆塊茄螃,即接下來即將提到的ListHints[ArraySize-BaseIndex-1]鏈表中的堆塊個數(shù)缝驳。例如,該_HEAP_LIST_LOOKUP結(jié)構(gòu)有擴(kuò)展归苍,則OutOfRangeItems為0用狱。

BaseIndex的值表示該_HEAP_LIST_LOOKUP結(jié)構(gòu)的起始block尺寸。例如霜医,從_HEAP結(jié)構(gòu)中的BlocksIndex索引到的_HEAP_LIST_LOOKUP結(jié)構(gòu)中的該字段為0齿拂,而從_HEAP_LIST_LOOKUP結(jié)構(gòu)中的ExtendedLookup索引到的_HEAP_LIST_LOOKUP結(jié)構(gòu)中的改字段為0x80。

ListHead與HeapBase->FreeLists指向同一個地方肴敛,鏈接了該HeapBase所管理的所有空閑堆的指針署海。

ListsInUseUlong為一個數(shù)組,相當(dāng)于一個ListHints 的BitMap医男。

ListHints也是一個_LIST_ENTRY結(jié)構(gòu)體數(shù)組砸狞,_LIST_ENTRY結(jié)構(gòu)體僅占8個字節(jié),其中有2個大小為4字節(jié)的Flink和Blink字段镀梭。ListHints數(shù)組的索引號代表著所管理堆塊的block尺寸刀森,每個Flink指向_HEAP->FreeLists鏈上的第一個對應(yīng)大小堆塊。此處的Blink較為特殊报账,不會指向堆塊的地址研底,而是在該大小堆塊開啟了LFH分配機(jī)制后會指向索引號對應(yīng)的Buckets(_HEAP_BUCKET)+1地址;在未開啟LFH分配機(jī)制時透罢,Blink的前2字節(jié)表示所有占用狀態(tài)該大小堆塊總數(shù)的2倍榜晦,后2字節(jié)表示申請該大小堆塊的總次數(shù)。另外羽圃,如前文中所提到的乾胶,ListHints[ArraySize-BaseIndex-1]的Flink指針會指向FreeLists鏈上第一個block尺寸大于ArraySize-1的空閑堆塊,類似于前版本中的Freelist[0]朽寞。

總的來說识窿,ListHints的Flink起著FreeLists鏈表堆緩存的作用,ListHints的Blink則起著連接后端堆管理器和前端堆管理器的作用脑融,因為它標(biāo)志著對應(yīng)大小的堆塊是否已啟用LFH進(jìn)行分配喻频。

4.3 堆塊操作

4.3.1 堆塊分配

堆塊在被申請時,主要會從上文提到的前端堆管理器和后端堆管理器中進(jìn)行分配吨掌。

從前端堆管理器進(jìn)行堆塊分配時半抱,會通過用戶申請堆塊大小索引到維護(hù)對應(yīng)大小堆塊的SegmentInfo數(shù)組脓恕,并獲得SegmentInfo->Hint->AggregateExchg->OffsetAndDepth字段,在Depth非0的情況下窿侈,將UserBlocks+8*FreeEntryOffset地址的堆塊分配給用戶使用炼幔,然后將FreeEntryOffset字段更新為位于該堆塊用戶區(qū)前2字節(jié)的Offset,便于在下一次分配時進(jìn)行尋址史简,并將Depth字段-1乃秀。

從后端堆管理器進(jìn)行堆塊分配時,會通過用戶申請堆塊大小索引到維護(hù)對應(yīng)大小堆塊的ListHints數(shù)組圆兵,并通過Flink指針找到在FreeLists鏈表中大小相對應(yīng)的堆塊跺讯,并進(jìn)行Unlink操作將其從鏈表上卸下返回給用戶使用。若未找到對應(yīng)大小堆塊則會向后遍歷FreeLists鏈表殉农,直到找到第一個最小滿足申請大小的堆塊進(jìn)行切割分配刀脏。若遍歷完整個鏈表仍然沒有成功分配,則會擴(kuò)展堆超凳。該版本的后端堆管理器分配機(jī)制與前版本中有許多相似之處愈污。

在用戶申請分配某一大小的內(nèi)存空間時,首先會判斷申請大小轮傍,若大于0xFE00blocks暂雹,即504KB,則調(diào)用VirtualAlloc()進(jìn)行分配创夜,若大于0x800blocks杭跪,即16KB,則直接以后端堆管理器進(jìn)行分配驰吓。若小于16KB涧尿,則先以后端堆管理器對這次分配操作進(jìn)行響應(yīng),在BlocksIndex及ExtendedLookup結(jié)構(gòu)中尋找相應(yīng)大小的ListHints檬贰,在找到相對應(yīng)大小的ListHints數(shù)組時會判斷其Blink是否為奇數(shù)现斋,即Buckets+1,若是則會將該分配操作交給前端堆管理器進(jìn)行響應(yīng)偎蘸。若不為奇數(shù),則判斷Blink的低2字節(jié)是否大于0x20或高2字節(jié)是否大于0x1000瞬内,即判斷在占用狀態(tài)的該大小堆塊的總數(shù)是否大于0x10或是否進(jìn)行了0x1000次該大小堆塊的申請迷雪。若判斷為真,則會設(shè)置HeapBase->CompatibilityFlags虫蝶,在下次再分配同樣大小堆塊時將Blink賦值為Buckets+1章咧,并啟用前端堆管理器響應(yīng)堆塊分配;若判斷為假能真,則仍然采用后端堆管理器響應(yīng)堆塊分配赁严,并將Blink的值加0x10002扰柠。

4.3.2 堆塊釋放

在進(jìn)行堆塊釋放操作時,系統(tǒng)遵循“從哪來疼约,回哪去”的規(guī)則卤档。在接收到堆塊釋放的請求時,系統(tǒng)會先判斷堆的大小程剥,所有大于504KB的堆塊都直接調(diào)用VirtualFree()進(jìn)行釋放劝枣,小于504KB大于16KB的堆塊都將鏈入FreeLists鏈表中。小于16KB的堆塊织鲸,系統(tǒng)會通過堆頭信息判斷該堆塊是從前端堆管理區(qū)進(jìn)行分配還是后端堆管理區(qū)進(jìn)行分配舔腾,若從前端分配,則將其釋放回前端堆中搂擦,并將AggregateExchg結(jié)構(gòu)中的FreeEntryOffset寫入堆塊用戶區(qū)的前2字節(jié)稳诚,并用該堆塊對于UserBlocks的偏移更新FreeEntryOffset字段,再將Depth字段+1瀑踢。若從后端分配扳还,則將其鏈入FreeLists鏈表中,并更新對應(yīng)大小的ListHints中的Flink指針丘损,再判斷該對應(yīng)大小是否已開啟LFH分配策略普办,若未開啟,則將Blink-0x0002徘钥。

4.3.3 堆塊合并

該階段的堆塊合并操作與前版本中幾乎相同衔蹲。在釋放前端堆塊時不會觸發(fā)合并操作,在釋放后端堆塊時呈础,若與該堆塊毗鄰的堆塊為空閑堆塊舆驶,則會進(jìn)行堆塊合并操作,合并后的堆塊會重新鏈入FreeLists的合適位置而钞,并更新相應(yīng)大小的ListHints的對應(yīng)數(shù)值沙廉。

4.4 保護(hù)機(jī)制

該階段Windows系統(tǒng)在保護(hù)堆方面除繼承前版本的保護(hù)機(jī)制外上又引入了一些額外的保護(hù)機(jī)制,如堆基址隨機(jī)化臼节、堆頭編碼撬陵、Safe Link等。這些保護(hù)機(jī)制的引入使得Windows操作系統(tǒng)的堆漏洞更難以被攻擊者所利用网缝。

4.4.1 堆基址隨機(jī)化

該機(jī)制會在創(chuàng)建堆時巨税,將HeapBase的地址隨機(jī)對齊到64KB地址,即將HeapBase隨機(jī)對齊到低4字節(jié)為0的地址粉臊。該堆基址隨機(jī)化與棽萏恚基址隨機(jī)化有異曲同工之處,目的是讓每次產(chǎn)生堆的地址都不相同扼仲,使得在漏洞利用時需要首先泄露隨機(jī)化的堆基址远寸,增大了漏洞利用的難度抄淑。

4.4.2 堆頭編碼

如上文所述,在前一階段的Windows版本中驰后,引入了Heap Cookie這一重要保護(hù)機(jī)制肆资。但經(jīng)過實踐的檢驗,這1字節(jié)的Heap Cookie并不能十分有效地阻止攻擊者對堆頭敏感數(shù)據(jù)的篡改:攻擊者可通過多次爆破來碰撞僅僅1字節(jié)的Heap Cookie倡怎。

為了更好的保護(hù)堆頭敏感信息不被攻擊者惡意篡改迅耘,Windows在該階段引入了堆頭編碼的保護(hù)機(jī)制。在介紹該機(jī)制前首先簡要介紹一下堆頭的_HEAP_ENTRY結(jié)構(gòu)體监署,如圖37所示颤专。

圖37 _HEAP_ENTRY數(shù)據(jù)結(jié)構(gòu)

堆頭編碼機(jī)制會首先確定該堆區(qū)是否已開啟堆頭編碼機(jī)制,若已開啟則將堆頭中代表Size以及Flags的前三個字節(jié)逐字節(jié)異或后賦值給SmallTagIndex钠乏,之后再與隨機(jī)生成的每個HeapBase都不同的HeapBase->Encoding進(jìn)行異或運(yùn)算得到編碼過后的堆頭栖秕。堆頭編碼算法偽代碼如圖38所示。

圖38 EncodeHeader算法

在解碼時晓避,會首先判斷該堆頭是否已經(jīng)編碼簇捍,若已編碼則將堆頭與HeapBase->Encoding進(jìn)行異或運(yùn)算解碼得到真實的堆頭,從而獲得Size以及Flags字段中的數(shù)據(jù)俏拱。堆頭解碼算法偽代碼如圖39所示暑塑。

圖39 DecodeHeader算法

在開啟了該機(jī)制后,攻擊者將很難在不泄露任何信息的條件下修改堆頭中的Size及Flags等敏感信息锅必。該機(jī)制較前版本中的Heap Cookie機(jī)制更有效地保護(hù)了堆頭信息事格。

4.4.3 Safe Link

如上文所述,前一階段的Windows版本中搞隐,引入了Safe Unlink保護(hù)機(jī)制后驹愚,攻擊者又在Link操作時發(fā)現(xiàn)了可利用的漏洞。為了完善操作鏈表時的保護(hù)機(jī)制劣纲,Windows在該階段引入了Safe Link的保護(hù)機(jī)制逢捺。該保護(hù)機(jī)制會判斷在鏈入堆塊前判斷鏈表上將要斷鏈的地方的Blink和Flink是否合法,若合法則進(jìn)行Link操作癞季,若不合法則調(diào)用RtlpLogHeapFailure()結(jié)束進(jìn)程劫瞳。Safe Link的算法偽代碼如圖40所示。

圖40 Safe Link算法

4.4.4 HeapEnableTerminateOnCorrupton

如上文所述绷柒,在前一階段版本加入的安全機(jī)制中柠新,檢測不通過時會調(diào)用RtlpHeapReportCorruption()。但是由于HeapEnableTerminateOnCorrupton字段默認(rèn)不啟用,導(dǎo)致在檢測不通過后繼續(xù)進(jìn)程,因此導(dǎo)致了上文所述的多種利用手法的存在吟榴。在本階段的版本中,默認(rèn)啟用了HeapEnableTerminateOnCorruption字段憔恳,使得在安全機(jī)制檢測不通過時直接結(jié)束進(jìn)程,杜絕了上一階段版本中的多種攻擊手法净蚤。

4.5 漏洞利用

該階段的版本中钥组,Windows的堆管理機(jī)制有了較大的修改,新加入了多種數(shù)據(jù)結(jié)構(gòu)以及一些關(guān)鍵性的保護(hù)機(jī)制今瀑,是Windows操作系統(tǒng)安全性發(fā)展的一個里程碑程梦,同時也使得堆漏洞的利用難度提升到了一個新高度。

4.5.1 突破堆頭編碼

在該階段加入的眾多安全機(jī)制中橘荠,堆頭編碼機(jī)制有著關(guān)鍵性的地位屿附。在之前介紹的多種漏洞利用方式中,幾乎都是以相鄰前一堆塊溢出作為前提哥童。在前一階段版本中挺份,可通過多次碰撞僅1字節(jié)的Heap Cookie,從而繞過安全機(jī)制覆蓋到堆頭的敏感信息贮懈。而在本階段版本中該機(jī)制的引入匀泊,導(dǎo)致堆頭信息皆被編碼,阻斷了對堆頭敏感信息的篡改朵你,以及對后方前項各聘、后項指針的覆蓋,幾乎阻絕了上文中介紹的所有攻擊方式抡医。

但通過分析堆頭編碼的算法躲因,如圖38所示,可以發(fā)現(xiàn)堆頭的敏感信息是通過異或進(jìn)行編碼魂拦,并且異或運(yùn)算可逆毛仪。如果我們擁有一次泄露的機(jī)會,可將已知狀態(tài)堆塊編碼后的堆頭泄露出來芯勘,并且由于我們已知堆塊狀態(tài)箱靴,即前3字節(jié),通過逐字節(jié)異或可計算出第4字節(jié)的SmallTagIndex字段荷愕,再用前4字節(jié)與泄露出的編碼后堆頭相異或即可得到HeapBase->Coding的值衡怀。

雖說對堆頭編碼的突破嚴(yán)格上來說并不算是漏洞的利用,但是通過突破堆頭編碼所得到的HeapBase->Encoding字段可在利用其他漏洞時對構(gòu)造堆頭進(jìn)行編碼安疗,從而繞過堆頭編碼的檢測抛杨。可以說突破堆頭編碼使得上文中提到的多種攻擊方式有了一線生機(jī)荐类。

4.5.2 LFH FreeEntryOffset OverFlow

4.5.2.1 漏洞成因

如上文介紹的怖现,在該階段版本中新引入的前端堆管理器LFH中,由其管理的每個空閑堆塊用戶區(qū)前2字節(jié)都存儲著可以用于更新FreeEntryOffset字段的Offset值。而FreeEntryOffset字段在前端堆管理器分配堆時起著極為重要的尋址作用屈嗤。

在突破堆頭編碼后潘拨,由前端堆管理器管理的空閑堆塊用戶區(qū)上前2字節(jié)的Offset顯得脆弱不堪,十分容易被覆蓋饶号,導(dǎo)致前端堆管理器分配時被劫持铁追,極易形成漏洞。

4.5.2.2 利用方式

在介紹該漏洞利用方式之前茫船,首先將_INTERLOCK_SEQ結(jié)構(gòu)體中關(guān)鍵字段在堆塊分配和釋放時的具體操作進(jìn)行詳細(xì)介紹琅束。接下來以BlockSize為6,即0x30字節(jié)的UserBlock為例進(jìn)行講解算谈。

首先在該大小UserBlock剛被初始化時涩禀,會將FreeEntryOffset字段初始化為0x2,原因是在第一個堆塊前會有0x10字節(jié)大小的_HEAP_USERDATA_HEADER結(jié)構(gòu)濒生;Depth字段會通過當(dāng)前可用內(nèi)存量(UserDataAllocSize)運(yùn)算出該大小堆塊的總個數(shù)埋泵,即Depth=(UserDataAllocSize-sizeof(_HEAP_USERDATA_HEADER)/BlockSize,在本例中假設(shè)為0x2A罪治。初始化的堆塊如圖41所示丽声。

圖41 LFH FreeEntryOffset OverFlow(1)

此時申請第一個0x28字節(jié)大小堆塊時(含堆頭共0x30字節(jié)),會通過前端堆管理器將FreeEntryOffset字段所指的堆塊分配發(fā)給用戶使用觉义,同時將FreeEntryOffset更新為用戶區(qū)前2字節(jié)存放的用于尋址下一堆塊的Offset雁社,并將Depth的值-1。分配后堆塊結(jié)構(gòu)如圖42所示晒骇。

圖42 LFH FreeEntryOffset OverFlow(2)

同理霉撵。在第三次申請完0x28字節(jié)大小的堆塊后堆塊結(jié)構(gòu)如圖43所示。

圖43 LFH FreeEntryOffset OverFlow(3)

/v:imagedata></v:shape>

此時若將第二次申請的堆塊釋放掉洪囤,則會將FreeEntryOffset當(dāng)前的值存放到該釋放堆塊的前兩字節(jié)作為Offset徒坡,并通過該堆塊與_HEAP_USERDATA_HEADER的相對block偏移更新FreeEntryOffset字段,再將Depth的值+1瘤缩。釋放第二個堆塊后的堆塊結(jié)構(gòu)如圖44所示喇完。

圖44 LFH FreeEntryOffset OverFlow(4)

通過示例不難發(fā)現(xiàn),空閑堆塊前2字節(jié)Offset值在前端堆管理器分配和釋放堆塊算法中的重要性剥啤,若能夠通過堆溢出將其覆蓋為含有虛表函數(shù)指針對象的堆塊偏移锦溪,就能夠通過申請堆塊拿到該對象的使用權(quán),并修改虛表指針劫持程序控制流府怯。

承接上例所述刻诊,構(gòu)造漏洞利用場景如下:第一個堆塊作為可由用戶控制的存在堆溢出的用戶堆塊,第三個堆塊作為含有虛表函數(shù)指針對象的占用堆塊牺丙。如圖45所示则涯。

圖45 LFH FreeEntryOffset OverFlow(5)

此時,對用戶堆塊進(jìn)行編輯,導(dǎo)致第二個空閑堆塊前2字節(jié)存放的Offset的值被用戶對快溢出所覆蓋粟判,并修改值為0xE肖揣,即第三個對象堆塊的偏移。如圖46所示浮入。

圖46 LFH FreeEntryOffset OverFlow(6)

緊接著,申請大小為0x28的堆塊羊异,前端堆管理器會按照算法將FreeEntryOffset更新為偽造的Offset即0xE事秀。如圖47所示。

圖47 LFH FreeEntryOffset OverFlow(7)

再次申請大小為0x28字節(jié)的堆塊時野舶,前端堆管理器會按照算法將對象堆塊分配給用戶使用易迹,并將FreeEntryOffset更新為Vtable_ptr的前2字節(jié)。如圖48所示平道。

圖48 LFH FreeEntryOffset OverFlow(8)

最終睹欲,會有2指針指向第3個堆塊,一個用戶指針一屋,一個對象指針窘疮,通過編輯用戶指針可覆蓋虛表函數(shù)指針為任意地址,最后調(diào)用對象指針執(zhí)行篡改后的虛表指針達(dá)到漏洞利用冀墨。

五闸衫、 總結(jié)與展望

本文從堆管理視圖出發(fā),將Windows7操作系統(tǒng)及之前的系統(tǒng)版本分為三個階段诽嘉,分階段按照重要結(jié)構(gòu)蔚出、堆塊操作、保護(hù)機(jī)制及漏洞利用五個部分進(jìn)行了詳細(xì)的講解虫腋,并在一些較難理解的關(guān)鍵部分佐以圖片進(jìn)行輔助講解骄酗。

在第一部分的環(huán)境準(zhǔn)備中,主要對在研究當(dāng)前階段版本中堆管理所采用的環(huán)境進(jìn)行了說明悦冀;在第二部分的重要結(jié)構(gòu)中趋翻,主要對當(dāng)前階段版本中堆管理所涉及到的重要數(shù)據(jù)結(jié)構(gòu)進(jìn)行了詳細(xì)講解;在第三部分的堆塊操作中雏门,主要對當(dāng)前階段版本中堆管理所涉及到的分配嘿歌、釋放及合并等操作的算法進(jìn)行了詳細(xì)講解;在第四部分的保護(hù)機(jī)制中茁影,主要對當(dāng)前階段版本中堆管理所涉及到的系統(tǒng)新增加的安全保護(hù)機(jī)制進(jìn)行了詳細(xì)講解宙帝;在第五部分漏洞利用中,主要對當(dāng)前階段版本中堆管理所涉及到的典型堆漏洞的產(chǎn)生原理以及利用方式進(jìn)行了詳細(xì)講解募闲。

總的來看步脓,本文對Windows下典型堆漏洞產(chǎn)生原理及利用方法的研究不夠深入徹底,仍存在部分盲區(qū)。如本文在操作系統(tǒng)的階段劃分中不夠全面靴患,未覆蓋到Windows最新的Windows 8 – Windows 10這一階段仍侥;以及在漏洞利用部分的講解中,僅僅挑選了較為常見鸳君、應(yīng)用較廣泛的漏洞农渊,對漏洞種類研究的不夠全面;而且對典型堆漏洞的闡述僅僅停留在了理論層次或颊,缺少本地Demo復(fù)現(xiàn)以及實際漏洞分析進(jìn)行實踐佐證砸紊,導(dǎo)致對漏洞的存在和利用缺乏說服力。

由于本人的學(xué)識有限囱挑,在文中難免存在錯誤醉顽,望海涵并及時指正。雖說論文已經(jīng)結(jié)束平挑,但學(xué)習(xí)卻永無止境游添,今后應(yīng)該針對上方的總結(jié)對癥下藥,完成好對Windows下典型堆漏洞產(chǎn)生原理及利用方法的進(jìn)一步研究通熄。

參考文獻(xiàn)

[1] John Mcdonald,Chris Valasek. Practical Windows XP/2003 Heap Exploitation[EB/OL].https://www.blackhat.com/presentations/bh-usa-09/MCDONALD/BHUSA09-McDonald-WindowsHeap-PAPER.pdf,2009.

[2] Moore,Brett. Exploiting Freelist[0] on XP Service Pack 2[EB/OL].http://www.insomniasec.com/publications/Exploiting_Freelist%5B0%5D_On_XPSP2.zip,2005-12.

[3] Chris Valasek. Understanding the Low Fragmentation Heap[EB/OL].http://illmatics.com/Understanding_the_LFH_Slides.pdf,2010-07.

[4] Ben Hawkes. Attacking the Vista Heap[EB/OL].https://www.lateralsecurity.com/downloads/hawkes_ruxcon-nov-2008.pdf,2008-11.

[5] coneco. 讀后感之“Understanding the LFH”[EB/OL].https://bbs.pediy.com/thread-248443.htm,2018-12-16.

[6] Magictong. Heap Spray原理淺析[EB/OL].https://blog.csdn.net/magictong/article/details/7391397,2012-03.

[7] 王清,張東輝.0day安全:軟件漏洞分析技術(shù)(第2版)[M].電子工業(yè)出版社:北京,2011-06:144.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末唆涝,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子棠隐,更是在濱河造成了極大的恐慌石抡,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件助泽,死亡現(xiàn)場離奇詭異啰扛,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)嗡贺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門隐解,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人诫睬,你說我怎么就攤上這事煞茫。” “怎么了摄凡?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵续徽,是天一觀的道長。 經(jīng)常有香客問我亲澡,道長钦扭,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任床绪,我火速辦了婚禮客情,結(jié)果婚禮上其弊,老公的妹妹穿的比我還像新娘。我一直安慰自己膀斋,他們只是感情好梭伐,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著仰担,像睡著了一般糊识。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上摔蓝,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天技掏,我揣著相機(jī)與錄音,去河邊找鬼项鬼。 笑死,一個胖子當(dāng)著我的面吹牛劲阎,可吹牛的內(nèi)容都是我干的绘盟。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼悯仙,長吁一口氣:“原來是場噩夢啊……” “哼龄毡!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起锡垄,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤沦零,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后货岭,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體路操,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年千贯,在試婚紗的時候發(fā)現(xiàn)自己被綠了屯仗。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡搔谴,死狀恐怖魁袜,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情敦第,我是刑警寧澤峰弹,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站芜果,受9級特大地震影響鞠呈,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜师幕,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一粟按、第九天 我趴在偏房一處隱蔽的房頂上張望诬滩。 院中可真熱鬧,春花似錦灭将、人聲如沸疼鸟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽空镜。三九已至,卻和暖如春捌朴,著一層夾襖步出監(jiān)牢的瞬間吴攒,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工砂蔽, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留洼怔,地道東北人。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓左驾,卻偏偏與公主長得像镣隶,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子诡右,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容

  • 01 小學(xué)時候的我對男女沒有很清晰的概念安岂,每天跟著一幫男生爬山、翻墻帆吻、去果園偷果子吃域那。起初,那些男生在我眼里都是一...
    木子Lee54閱讀 614評論 0 0