PXN防護技術的研究與繞過

2021-09-11 11:21:28 字數 4087 閱讀 9861

阿里移動安全 · 2015/08/07 14:59

近些年來,由於android系統的興起,作為android底層實現的linux核心其安全問題也是越來越被人們所關注。為了減小漏洞給使用者帶來的危害和損失,linux核心增加了一系列的漏洞緩解技術。其中包括depalsr,更強的selinux,核心**段唯讀,pxn等等。linux中這些安全特性的增加,使得黑客們對漏洞的利用越來越困難。其中,depalsrselinux等技術在pc時代就已經比較成熟了。核心**段唯讀也是可以通過修改ptmx_fops指標表等方案來繞過。那麼,pxn是什麼?它又該如何繞過呢?

pxn其實就是privileged execute-never的縮寫,按字面翻譯就是「特權執行從不」。它的開啟與否主要由頁表屬性的pxn位來控制,如圖所示。

在沒有pxn安全機制的android機器上,我們一般的提權思路大致可分為如下幾步:

修改ptmx_fops表的fsync指標位址,使其指向我們使用者態的提權**。

應用層呼叫fsync函式,使得系統觸發我們的提權**。

獲取root許可權。

ptmx_fops表的fsync指標置為null,主要防止其他程序呼叫fsync而使系統崩潰。

上述說到的提權步驟是在沒有pxn影響下的一般思路。那麼在帶有pxn的機器上表現又是如何呢?經過我們的多番測試,在不同的機型上表現各不相同。在有的機器上會卡住,shellcode不會繼續執行;有的機器上會產生kernel panic,機器直接重啟。 所以說,pxn的大致工作原理就是在核心狀態下,系統是無法直接執行使用者態**的。因此,我們常用的提權思路也就行不通了。更加坑爹的是在絕大部分的arm64系統機型(如三星s6,華為p8),和一些arm32位機型(如三星note3,三星s5等主流機型)的最新rom都預設開啟了pxn

在cve-2015-3636漏洞的一種利用方式中,我們最終可以控制inet_release函式中 sk->sk_prot->close 指標的值。對應彙編**如圖所示。

圖2中x2暫存器的值即為sk->sk_prot->close指標的位址,這裡的x2對應著32位系統中的r2。blr x2指令就是跳轉到x2所指向的位址處執行。 在開啟了pxn的機型上,如果我們將sk_prot->close指標的位址指向使用者態的提權**,那麼系統就直接panic重啟了,錯誤資訊如下圖所示。在這個panic資訊中可以看到pc暫存器的值為0x558d15a2a8,是乙個使用者態位址。

既然在核心狀態下pxn機制能阻止系統執行使用者態的**,那麼它會不會阻止核心層的**執行呢?我們將sk_prot->close指標的位址指向了inet_release函式的返回處。**如圖所示。

此時再觸發漏洞,函式能正確返回到使用者態,並且系統也沒有panic,從而驗證了pxn是不會阻止核心態**執行的。這和pxn自身的原理也是一致的。

基本思路

在帶有pxn的機器上雖然不能執行使用者態的shellcode,但是依然可以執行核心態的**。因此,我們的策略就是使用核心rop:構建核心gadget,使得棧指標sp洩露,然後通過sp計算得到thread_info結構的位址,之後patch thread_info結構的addr_limit欄位,從而達到使用者態任意讀寫核心態的目的。

構建gadget

接下來,我們的主要目的就是驗證上述方案的可行性。首要任務就是尋找合適的核心gadget。 假設我們現在已經可以利用漏洞控制x1暫存器的值,如圖所示。

因此,在尋找rop需要的gadget時,我們以x1所指向的記憶體區域為基礎來控制其他暫存器的值。在觸發漏洞前,通過mmap函式來建立一塊使用者態可以控制的記憶體空間。如下所示

void *map_addr_tmp = mmap((void*) 0x30303000, 0x10000, 

prot_write|prot_read|prot_exec,

map_shared|map_anonymous|map_fixed, -1, 0);

複製**

做完了上面的準備工作,接下來,我將上述方案分解成下面三步來完成:

洩露sp的值;

計算addr_limit的位址;

patch addr_limit。

首先,用rop來完成sp的洩露。因為暫存器x1所指向的位址是我們在使用者態自己分配出來,並且可以隨意控制的記憶體塊,所以我們在第一段gadget中藉由x1來布局各個跳轉的位址,然後跳轉到下一段gadget開始執行。 第二段gadget主要是將sp棧指標的值賦給x0,然後跳轉到下一段gadget。在這個例子裡面,使用者態是無法直接通過x0來獲得sp的。所以我們在gadget3裡面通過一條str指令將x0的值儲存到使用者態。rop的大致思路如下圖所示。 找gadget在某種程度上是乙個體力活,當然也可以通過一些工具來make life easier,大家可以自行google。注意這裡描述的gadget只是乙個大致的思路,和實際中可能會有一些區別。

我們得到sp的值後,就可以計算出addr_limit欄位的位址了。在arm64系統上,棧的最大深度為16k。其次,addr_limit欄位位於thread_info結構+8的位置。因此,計算方式如下所示:

unsigned long thread_info_addr = sp & 0xffffffffffffc000;

unsigned long addr_limit_addr = thread_info_addr + 8;

printf("addr_limit_addr: %p\n", addr_limit_addr); 

複製**

最後,我們通過rop來設定addr_limit的值為0xffffffffffffffff。同樣,x1暫存器我們可以隨意控制其內容。第一段gadget用來設定各個跳轉位址。第二段gadget完成主要任務,即通過乙個str指令來完成patch addr_limit的目的。最後跳轉到inet_release的函式返回處。rop的大致思路如圖所示。

完成了addr_limit欄位的patch之後,那麼使用者態就可以任意讀寫核心態了。接下來的選擇就很多了,一種方法是先確定task_struct的位址,它是在thread_info+0x10的位置。得到了task_struct的位址之後,就可以定位到cred欄位,之後patch uid、gid、capability、selinux等即可。 實踐中,通過結合已知的漏洞,上述方案在近期發布的一些64位旗艦機型上均能測試成功,如圖所示。當然,這個思路在32位機型上也同樣適用。

假設我們所使用的是乙個任意寫的漏洞,那麼繞過pxn的方式其實是類似的。首先通過任意寫的洞控制kernel的乙個函式指標,指向我們的gadget,洩露出sp的值。接下來,可以直接通過任意寫的能力去patch addr_limit(不需要再通過rop去patch了)。

近些年來隨著對android、linux的研究越來越深入,通用的linux平台漏洞,例如:cve-2013-6282、cve-2014-3153 (towelroot)以及最新的cve-2015-3636(pingpong)紛紛被公之於眾。 同時,linux上運用的最新的漏洞緩解機制讓系統漏洞的利用越發困難,但繞過這些緩解機制的技術也在推陳出新。攻與防的博弈永遠不會結束。

關於重複發包的防護與繞過

路人甲 2014 11 15 12 28 目前由重 包造成的問題主要有撞庫,爆破等。而隨著洩漏密碼的越來越多,這一類問題造成的影響也越來越嚴重,隨之大部分 都做了對重 包的防護。但是也有部分防護不完善,可以進行繞過。許多 為了防止重 包這一問題,限制了每個ip的嘗試次數,如果失敗n次之後這個ip就暫...

關於重複發包的防護與繞過

0x00.前言 目前由重 包造成的問題主要有撞庫,爆破等。而隨著洩漏密碼的越來越多,這一類問題造成的影響也越來越嚴重,隨之大部分 都做了對重 包的防護。但是也有部分防護不完善,可以進行繞過。0x01.基於ip的防護 許多 為了防止重 包這一問題,限制了每個ip的嘗試次數,如果失敗n次之後這個ip就暫...

滲透防護牆的滲透技術

說到通道技術,我想再提一下 埠復用 很多朋友以為通道技術就是埠復用技術。那麼,錯了,埠復用是指乙個埠上建立了多個連線,而不是在乙個端 口上面開放了多個服務而互不干擾。假如你想在已經開放了www服務的主機上,在80埠再新增一項服務,只有2種可能 1.新增服務失敗 2.www服務出錯。那麼什麼是通道呢?...