回顧:針對(duì)代碼注入的防護(hù)機(jī)制
1. 經(jīng)典代碼注入的核心思想
利用邏輯異常姻政,在程序數(shù)據(jù)中混入代碼
劫持控制流,使得指令指針從數(shù)據(jù)段讀取指令
所需弱點(diǎn):讀取指令時(shí),CPU無(wú)法區(qū)分目標(biāo)內(nèi)存區(qū)域的性質(zhì)
2. 數(shù)據(jù)執(zhí)行保護(hù)(Data Execution Prevention)
別名:W⊕X,NX-bit
機(jī)制:對(duì)內(nèi)存頁(yè)面增加一個(gè)標(biāo)識(shí)bit,使之要么可改寫孕豹,要么可執(zhí)行
防御思路:引入新的硬件安全屬性,支持CPU在執(zhí)行時(shí)區(qū)分代碼和數(shù)據(jù)區(qū)域(但是:若不試圖執(zhí)行數(shù)據(jù)區(qū)內(nèi)容十气,則不能發(fā)現(xiàn)/阻止溢出励背,也無(wú)法防范溢出的其他后果)
目標(biāo):繞過(guò)DEP(代碼重用(code reuse)攻擊)
- 異常數(shù)據(jù)的注入仍然可以實(shí)施
- 代碼無(wú)法直接注入,那么就利用進(jìn)程空間中已經(jīng)存在的代碼
- 不管所利用代碼原本的用途為何砸西,通過(guò)注入的異常數(shù)據(jù)控制其為攻擊者服務(wù)
return-to-libc攻擊
返回導(dǎo)向編程(return-oriented programming)(圖靈完備)
一種非常規(guī)方式將短小指令片段串聯(lián)成完整的代碼流
為ROP搜索可用的指令資源 --- Galileo算法
特點(diǎn):
- 始于對(duì)程序控制流的篡改(控制流異常)
- 各gadget由ret指令(或者pop-jump組合)代替eip加以鏈接(大量控制流異常)
- 原始棧結(jié)構(gòu)遭到破壞叶眉,ROP過(guò)程中棧指針單向移動(dòng)(棧的行為異常)
- 有時(shí),棧指針可能被篡改并指向不屬于棧區(qū)的內(nèi)存(棧的行為異常)
注:
ret指令(與棧溢出方向吻合籍胯,具有指令尋址能力)
- 根據(jù)當(dāng)前棧頂內(nèi)容竟闪,修改指令寄存器所指向的地址
- 將棧指針位置向棧底方向移動(dòng)4字節(jié)
圖靈完備的指令集應(yīng)當(dāng)包括
- 加載/存儲(chǔ)
- 算術(shù),邏輯運(yùn)算杖狼,位移
- 控制流:條件跳轉(zhuǎn)炼蛤,系統(tǒng)調(diào)用
利用點(diǎn)1:復(fù)雜指令集(complex instruction set computing,CISC)
步驟:
- 將劫持后的控制流引導(dǎo)至正常指令的內(nèi)部(middle of an instruction)
- 利用CISC的特點(diǎn)蝶涩,形成意外的指令片段(unintended instruction sequence)
- Gadget資源的重要來(lái)源:因誤解析而形成的“指令”(特別是0xC3字節(jié))
需要注意的是:
- 指令變長(zhǎng)(目的:以最短的代碼長(zhǎng)度壓縮最多的指令內(nèi)容)
- CPU串行地讀取指令理朋,依據(jù)上下文區(qū)分操作碼/操作數(shù)等成分
- 典型:x86指令構(gòu)架
- 存在問(wèn)題:代碼中一個(gè)字節(jié)的含義取決于上下文
a. 各種指令的使用率相差懸殊,且微碼串行執(zhí)行讓頻繁使用的簡(jiǎn)單指令也效率低下
b. 復(fù)雜指令 → 復(fù)雜的硬件結(jié)構(gòu)绿聘,CISC越來(lái)越難以集成在單一芯片上
c. 許多復(fù)雜指令需要極復(fù)雜的操作嗽上,多數(shù)已可視為某種高級(jí)語(yǔ)言的翻版,通用性差
利用點(diǎn)2:精簡(jiǎn)指令集(RISC)
背景:
CISC存在許多缺點(diǎn)(上面說(shuō)過(guò)了)
RISC的特點(diǎn):
統(tǒng)一指令編碼熄攘,如所有指令長(zhǎng)度相等兽愤、op-code位置相同等,可快速解譯
泛用的緩存器挪圾,單純的尋址模式(用計(jì)算指令序列取代復(fù)雜尋址模式)
硬件中支持少數(shù)數(shù)據(jù)型別(如區(qū)分整數(shù)/浮點(diǎn)數(shù)等)
栗子
“可擴(kuò)充處理器架構(gòu)”(Scalable Processor ARChitecture浅萧,SPARC)
SPARC的寄存器“窗口”機(jī)制
- 32個(gè)通用寄存器,其中8個(gè)全局寄存器和一個(gè)“窗口”(包含24個(gè)寄存器)
- 支持2~32個(gè)“窗口”(取決于硬件實(shí)現(xiàn))哲思,通常為7~8個(gè)——由此得名“可擴(kuò)展的”
- 在任何時(shí)候洼畅,只有一個(gè)寄存器窗口是可見(jiàn)的
針對(duì)RISC的返回導(dǎo)向編程(圖靈完備)
對(duì)SPARC構(gòu)造返回導(dǎo)向編程所面臨的問(wèn)題:
無(wú)法利用意外的指令序列(該種情況不可能發(fā)生)
x86下返回導(dǎo)向編程gadget的所有構(gòu)造特點(diǎn)在RISC中均不存在新的返回導(dǎo)向編程設(shè)計(jì)思路:
將函數(shù)的后綴作為gadget使用(利用其結(jié)尾處的ret-restore指令序列)
利用結(jié)構(gòu)化數(shù)據(jù)流使得gadget與SPARC的函數(shù)調(diào)用慣例相吻合
構(gòu)造內(nèi)存-內(nèi)存gadget(寄存器僅在gadget內(nèi)部使用)
如何防御
核心思路:破壞返回導(dǎo)向編程的原子指令組件(gadget),阻止x86代碼中出現(xiàn)意外的gadget
難點(diǎn):x86編譯器所生成的代碼高度優(yōu)化棚赔,難以隨意改變指令長(zhǎng)度
- 因此帝簇,Smashing the gadgets必須是(in-place)的
- 像上面這樣抹掉0xC3字節(jié)僅僅是可用的手段之一
手段2:指令重新排序
手段3:寄存器壓棧順序隨機(jī)化
手段4:寄存器重分配
ROP without return
參考論文:Return-Oriented Programming without Returns
有了這盤論文之后徘郭,之前的防御措施都沒(méi)啥卵用了
核心思想:防范普遍針對(duì)ret指令(0xC3),那就想出不用ret也可以的辦法
- 利用update-load-branch指令序列“pop x; jmp *x”
-
但是丧肴,update-load-branch序列并不像ret那樣常見(jiàn)残揉,因此要采用“蹦床”(trampoline)機(jī)制
ROP without return之圖靈完整性:可用資源及trampoline
ROP without return之圖靈完整性:條件分支
ROP without return之圖靈完整性:函數(shù)調(diào)用
- 在esi中載入call-jmp序列的地址
- 在ebp中載入leave-jmp序列的地址
- 在eax中載入n+偏移量
- 將call-jmp序列的地址存儲(chǔ)至地址n
- 改寫esi,使其存儲(chǔ)“返回地址”
- esi值寫入result位置后闪湾,再讀出至edi
- 交換使返回值存入ebp冲甘,leave指令換入edi
- 在esi中載入pop-jmp序列的地址
- 在ecx中載入函數(shù)入口地址
- 在eax中載入地址n
- 交換esp和eax,棧指針指向n(函數(shù)地址)
- edi處的leave指令將使函數(shù)“返回” 至0x7d
防御思路
由ROP的一些特點(diǎn):
- 始于對(duì)程序控制流的篡改(控制流異常)
- 各gadget由ret指令(或者pop-jump組合)代替eip加以鏈接(大量控制流異常)
- 原始棧結(jié)構(gòu)遭到破壞途样,ROP過(guò)程中棧指針單向移動(dòng)(棧的行為異常)
- 有時(shí),棧指針可能被篡改并指向不屬于棧區(qū)的內(nèi)存(棧的行為異常)
可以有如下辦法:
- 要求程序按照程序猿所規(guī)定的邏輯去執(zhí)行
- 當(dāng)出現(xiàn)不應(yīng)出現(xiàn)的控制轉(zhuǎn)移行為時(shí)濒憋,阻止程序執(zhí)行
- 當(dāng)程序的棧結(jié)構(gòu)發(fā)生異常變化時(shí)何暇,阻止程序執(zhí)行
并由此產(chǎn)生的返回導(dǎo)向編程防御思路:控制流完整性保護(hù)(CFI)技術(shù)
控制流完整性保護(hù)(CFI)技術(shù)
基本思想:
- 通過(guò)預(yù)設(shè)的運(yùn)行時(shí)校驗(yàn),確保程序執(zhí)行與預(yù)先定義的控制流圖嚴(yán)格吻合
- 通過(guò)對(duì)二進(jìn)制碼的靜態(tài)分析來(lái)獲取CFI所需保證的控制流圖
- 藉由靜態(tài)的二進(jìn)制代碼改寫為程序添加運(yùn)行時(shí)的自我校驗(yàn)
CFI的基本安全性假設(shè):
- 控制轉(zhuǎn)移目標(biāo)的標(biāo)示符(ID)具有唯一性
- 程序代碼不可寫
- 程序數(shù)據(jù)不可執(zhí)行
實(shí)用(粗粒度)的控制流完整性保護(hù)
改進(jìn)思路:借鑒SFI的思想凛驮,優(yōu)化CFI的校驗(yàn)機(jī)制
設(shè)計(jì)效果:間接控制轉(zhuǎn)移只能以Springboard段內(nèi)的適當(dāng)存根作為目標(biāo)
基于動(dòng)態(tài)優(yōu)化的CFI
前述CFI方案仍然存在不盡人意之處:需要改寫程序的二進(jìn)制代碼:
- 即使是最強(qiáng)大的二進(jìn)制分析工具裆站,也很難識(shí)別出程序中所有的合法控制轉(zhuǎn)移目標(biāo)
- 對(duì)二進(jìn)制代碼的修改同樣困難且容易出錯(cuò),且兼容性問(wèn)題在一定程度上仍然存在
改進(jìn)思路:在程序執(zhí)行過(guò)程中加以監(jiān)視和約束
設(shè)計(jì)基礎(chǔ):動(dòng)態(tài)執(zhí)行優(yōu)化工具
不足:效率太低
利用硬件特性和虛擬化技術(shù)的CFI
改進(jìn)思路:利用虛擬化技術(shù)
實(shí)現(xiàn)基礎(chǔ):Last Branch Record
- 一組存在于CPU內(nèi)部黔夭、記錄其最后n次控制轉(zhuǎn)移目標(biāo)的寄存器(如Intel i5中設(shè)有16個(gè))
- 需要內(nèi)核權(quán)限開(kāi)啟(恰好與虛擬化技術(shù)相適應(yīng))
CFI弱點(diǎn)
- 即使是在靜態(tài)分析中宏胯,間接控制轉(zhuǎn)移的合法跳轉(zhuǎn)目標(biāo)也既不是唯一的、也不是排他的
- 受到性能的制約本姥,粗粒度化的CFI對(duì)控制流的約束更加松散
針對(duì)CFI的改進(jìn)型返回導(dǎo)向編程
CFI的弱點(diǎn)為返回導(dǎo)向編程提供了新類型的gadget來(lái)源
- gadget的位置滿足粗粒度CFI的約束規(guī)則
- 新約束條件下的gadgets仍然有可能形成具備圖靈完整性的攻擊載荷
- 副作用: gadget為了滿足CFI約束而不可避免地增大了(無(wú)論是字節(jié)數(shù)還是指令數(shù))
返回導(dǎo)向編程改進(jìn)型1:利用以函數(shù)入口和函數(shù)調(diào)用點(diǎn)為起始的gadget
繞過(guò)CFI是否將導(dǎo)致返回導(dǎo)向編程的功能性有所缺損肩袍?不會(huì)
返回導(dǎo)向編程的變種:數(shù)據(jù)導(dǎo)向編程
注:Return-to-Libc攻擊特點(diǎn)
- 篡改返回地址指向指定函數(shù)入口
- 通過(guò)溢出偽造輸入?yún)?shù)等棧數(shù)據(jù)結(jié)構(gòu)
- 誘使函數(shù)在執(zhí)行中使用偽造的參數(shù)數(shù)據(jù),實(shí)現(xiàn)惡意目的
從Return-to-Libc攻擊可以看出:數(shù)據(jù)污染可以成為代碼重用類攻擊的重要成分
數(shù)據(jù)導(dǎo)向編程特點(diǎn):
- 通過(guò)污染數(shù)據(jù)(特別是指針)改變被重用代碼的實(shí)際語(yǔ)義
- 借助循環(huán)不斷注入新的攻擊載荷梧却,使得被重用代碼的實(shí)際執(zhí)行效果隨之改變
因此烤黍,數(shù)據(jù)導(dǎo)向編程所重用的代碼資源主要來(lái)自串操作(或同類執(zhí)行行為)
數(shù)據(jù)導(dǎo)向編程的循環(huán)調(diào)度
- 交互式攻擊 – 允許攻擊者在每輪循環(huán)中輸入不同的載荷以激活不同的gadget
- 非交互式攻擊 – 攻擊者必須一次性輸入整個(gè)攻擊載荷
地址空間隨機(jī)化(Address Space Layout Randomization)
基本思想:地址空間隨機(jī)化
發(fā)展
粗粒度ASLR的改進(jìn):偏移量+內(nèi)存區(qū)段的位置置換
細(xì)粒度的ASLR:
- 區(qū)段間 → 區(qū)段內(nèi)
- 改變代碼文本的具體內(nèi)容
細(xì)粒度ASLR的實(shí)施
- 程序在加載時(shí)自我隨機(jī)化
- 通過(guò)虛擬機(jī)進(jìn)行動(dòng)態(tài)隨機(jī)化
- 操作系統(tǒng)的隨機(jī)化
對(duì)ASLR的攻擊
ASLR假設(shè)的攻擊模型
- Case 1:攻擊者無(wú)法披露目標(biāo)程序的內(nèi)存空間
- Case 2:攻擊者可以實(shí)施內(nèi)存空間披露籍琳,但只能獲得一個(gè)代碼指針(如果攻擊者真的尋獲了一個(gè)可以遠(yuǎn)程利用的內(nèi)存披露漏洞,為何不反復(fù)利用之艰管,以最大化漏洞價(jià)值?)
ASLR的無(wú)效化:Just-In-Time代碼重用
Limitation:對(duì)于任何ASLR蒋川,程序在執(zhí)行時(shí)不再改變其內(nèi)存空間結(jié)構(gòu)