繞過Windows Control Flow Guard思路是怎樣的,針對這個問題,這篇文章詳細(xì)介紹了相對應(yīng)的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
為梁子湖等地區(qū)用戶提供了全套網(wǎng)頁設(shè)計制作服務(wù),及梁子湖網(wǎng)站建設(shè)行業(yè)解決方案。主營業(yè)務(wù)為成都網(wǎng)站設(shè)計、做網(wǎng)站、梁子湖網(wǎng)站設(shè)計,以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務(wù)。我們深信只要達到每一位用戶的要求,就會得到認(rèn)可,從而選擇與我們長期合作。這樣,我們也可以走得更遠(yuǎn)!
通常,攻擊者可以通過利用內(nèi)存漏洞來截獲控制流。但是研究人員也提出了各種各樣的防御手段避免發(fā)生這樣的問題,例如地址空間隨機化(ALSR),異或執(zhí)行(XOR Execute),控制流完整性(CFI)等各種各樣的防御措施。CFI通過強制控制流完整性保證程序的執(zhí)行不會出現(xiàn)問題,目前部署最為廣泛的CFI是windows提供的control flow guard(CFG)。CFG目前部署在最新的Windows 8.1,Windows 10上,已經(jīng)超過了5億使用量。因此一旦在CFG上出現(xiàn)問題,可能導(dǎo)致非常嚴(yán)重的后果。
Windows的CFI實現(xiàn)稱為Control Flow Guard(CFG),因為實際的性能要求,不可能做到非常精確的CFI,因此,實際在windows上部署的CFI是粗粒度的、前向CFI。首先,粗粒度的CFI是:所有的有效跳轉(zhuǎn)地址為一個全局的集合,即不精確的為每一個間接跳轉(zhuǎn)指定一個有效跳轉(zhuǎn)地址;其次,什么叫做前向CFI:只考略call,jump的直接跳轉(zhuǎn)和間接跳轉(zhuǎn),沒有計算ret的情況。此外,Windows CFG實現(xiàn)還依賴于bitmap表,該表存儲的信息是關(guān)于目標(biāo)地址是否有效的一張表。bitmap表中的兩位與實際地址的16byte一一對應(yīng),因此有四種情況:
00:該地址范圍沒有有效的跳轉(zhuǎn)地址
01:地址范圍包含導(dǎo)出抑制表目標(biāo)
10:只有16位對其的地址有效(該范圍的第一個地址)
11:地址范圍的所有地址均有效
因此,可以看出一個非常明顯的漏洞:
在編碼為11的情況在,整個16位地址均為有效跳轉(zhuǎn)地址,此時,如果存在間接跳轉(zhuǎn)漏洞,例如:jump [eax] (eax = 0x1007),當(dāng)eax的值可以修改的時候,跳轉(zhuǎn)地址可以跳轉(zhuǎn)到0x1007地址的上面的指令,(add rsp, 0x40)這是Windows CFG的設(shè)計漏洞之一。其次,由于Windows CFG是前向的CFI防御,因此不能阻止重寫return address的情況,則利用該特點,如果可以改寫ret addr,也可以達到繞過CFG的目的。
在論文中提到了一種繞過CFG的方法,該方法和以往的繞過相比較:
需要更少的??刂?,只需要控制棧頂?shù)膮^(qū)域即可
靈活性更大,在實際攻擊場景中可以復(fù)現(xiàn)
所需gadget在Windows系統(tǒng)中廣為存在
文章定義了兩種gadget,通過兩種gadget的配合可以實現(xiàn)繞過CFG。定義P(p)R(r) gadget:
該gadget是一個有效的CFG目標(biāo)
該gadget是一條 add {e, r}sp, m 指令,可以不存在
該gadget是n條 pop 指令,可以不存在
該gadget是一條 ret r 指令,r可以為0
p = m + wn(w是一個字的長度,32-bit是4,64-bit是8)
這樣一系列定義其實描述了程序函數(shù)調(diào)用結(jié)束的操作。例如上圖中有效代碼段
add rsp, 0x40 pop rdi pop rbx ret
根據(jù)定義,該gadget可以定義為P(80)R(0),p = 64 + 8 * 2, r = 0。該gadget鏈主要目的是更改棧幀的位置,以便修改ret addr。在32位系統(tǒng)中,參數(shù)傳遞是通過棧來傳遞,通過改變參數(shù)即可以影響棧中的內(nèi)容,通過這種方式可以達到修改ret addr的目的。然而,在64位系統(tǒng)中參數(shù)傳遞是通過寄存器完成的,因此,棧中的內(nèi)容一般不會被影響,所以重新定義了 S gadget 以便可以修改棧中內(nèi)容。通常一個尾調(diào)用優(yōu)化可能產(chǎn)生S gadget。
該gadget是一個有效的CFG目標(biāo)
該gadget溢出n個寄存器到寄存器參數(shù)區(qū)域(RPA)
該gadget以一個受控制的間接跳轉(zhuǎn)結(jié)束
mov [rsp + 0x8], rcx mov [rsp + 0x10], rdx sub rsp, 0x40 ... mov rax, [rcx] mov rax, [rax + 0x20] add rsp, 0x40 jmp [dispatch_fptr]
rcx, rdx一般在Windows 64-bit函數(shù)調(diào)用中是作為第一個參數(shù)和第二個參數(shù),假設(shè)參數(shù)可以被攻擊者控制,則在這段gadget中,一個被攻擊者控制的參數(shù)被傳入棧中,即有機會修改ret addr。
下圖展示了一個PR-P鏈的連接過程:
如何利用PR,P gadget進行攻擊,論文中以Edge作為攻擊目標(biāo),實施遠(yuǎn)程攻擊。首先需要知道object在內(nèi)存中的地址,因此需要有地址泄露的過程,其次,我們需要偽造一些數(shù)據(jù),要有一定的寫內(nèi)存操作。在攻擊的Demo中,利用CVE-2016-7200和CVE-2016-7201兩個Edge漏洞,達到地址泄露和任意內(nèi)存讀寫的權(quán)限。
1 ; @ chakra+0x31f0000 2 chakra!ScriptEngine::EnumHeap: 3 mov r11, rsp 4 ; Spill arguments to RPA 5 mov [r11+0x10], rdx 6 mov [r11+0x8], rcx 7 ; Allocate stack frame 8 sub rsp, 0x28 9 ; Prepare call to rcx->__vfptr[10] 10 mov rax, [rcx] 11 mov r8, rdx 12 xor edx, edx 13 mov rax, [rax+0x50] 14 ; Deallocate stack frame 15 add rsp, 0x28 16 ; Perform indirect call via CFG 17 jmp cs:__guard_dispatch_icall_fptr
pop rdi pop rsi ret
目標(biāo)函數(shù)是JavascriptFunction::HasInstance虛函數(shù),首先定位JavascroptFunction object在內(nèi)存中的位置,通過修改VTable pointer指向一個偽造的VTable,其中instanceof函數(shù)在VTable中的位置為0x200,將該函數(shù)修改為S(2) gadget 地址。當(dāng)instanceof函數(shù)調(diào)用時即執(zhí)行S(2) gadget。
S gadget 得到一個指向JavascroptFunction object的指針作為第一個參數(shù),指向Var的指針做為第二個參數(shù),S gadget 在第5行和第6行將參數(shù)放入棧中。第13行將JavascroptFunction偏移0x50的放入rax中,之后jmp rax執(zhí)行P(16)R(0) gadget。
我們只需要設(shè)置一個自己構(gòu)造的Var指針,即可截獲控制流。
截獲控制流之后,便可以通過傳統(tǒng)的ROP進行攻擊。
論文中提出了一種新的繞過Windows CFG的方法,具有一定的靈活性,并且文章中提到在Windows系統(tǒng)中存在較多的可用gadget,因此,如果進行系統(tǒng)性的掃描Windows所有常用動態(tài)庫,可以在很多場景下進行利用。
關(guān)于繞過Windows Control Flow Guard思路是怎樣的問題的解答就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道了解更多相關(guān)知識。