<pre id="vvttv"><mark id="vvttv"><progress id="vvttv"></progress></mark></pre>
    <pre id="vvttv"></pre>

      <p id="vvttv"></p>

          <p id="vvttv"></p>

                <p id="vvttv"></p>

                <pre id="vvttv"><cite id="vvttv"><progress id="vvttv"></progress></cite></pre>

                  <output id="vvttv"><dfn id="vvttv"><th id="vvttv"></th></dfn></output>

                    <p id="vvttv"></p>

                    原文地址:http://drops.wooyun.org/tips/7764

                    作者: 陵軒,美成,宋楊

                    Linux安全機制簡介


                    近些年來,由于Android系統的興起,作為Android 底層實現的 Linux內核其安全問題也是越來越被人們所關注。為了減小漏洞給用戶帶來的危害和損失,Linux 內核增加了一系列的漏洞緩解技術。其中包括DEPALSR,更強的 Selinux,內核代碼段只讀,PXN等等。 Linux 中這些安全特性的增加,使得黑客們對漏洞的利用越來越困難。其中,DEPALSRSelinux 等技術在 PC 時代就已經比較成熟了。內核代碼段只讀也是可以通過修改ptmx_fops 指針表等方案來繞過。那么,PXN是什么?它又該如何繞過呢?

                    PXN簡介


                    PXN其實就是 Privileged Execute-Never 的縮寫,按字面翻譯就是“特權執行從不”。它的開啟與否主要由頁表屬性的PXN位來控制,如圖所示。

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

                    1. 修改ptmx_fops表的fsync指針地址,使其指向我們用戶態的提權代碼。
                    2. 應用層調用fsync函數,使得系統觸發我們的提權代碼。
                    3. 獲取root權限。
                    4. ptmx_fops表的fsync指針置為NULL,主要防止其他進程調用 fsync而使系統崩潰。

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

                    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


                    基本思路

                    在帶有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);
                    

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

                    1. 泄露sp的值;
                    2. 計算addr_limit的地址;
                    3. 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上運用的最新的漏洞緩解機制讓系統漏洞的利用越發困難,但繞過這些緩解機制的技術也在推陳出新。攻與防的博弈永遠不會結束。

                    參考文章:

                    http://git.kernel.org/cgit/linux/kernel/git/davem/net.git/commit/?id=1d4d37159d013a4c54d785407dd8902f901d7bc5

                    http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.subset.architecture.reference/index.html

                    https://bugzilla.redhat.com/show_bug.cgi?id=1218074

                      <pre id="vvttv"><mark id="vvttv"><progress id="vvttv"></progress></mark></pre>
                      <pre id="vvttv"></pre>

                        <p id="vvttv"></p>

                            <p id="vvttv"></p>

                                  <p id="vvttv"></p>

                                  <pre id="vvttv"><cite id="vvttv"><progress id="vvttv"></progress></cite></pre>

                                    <output id="vvttv"><dfn id="vvttv"><th id="vvttv"></th></dfn></output>

                                      <p id="vvttv"></p>

                                      这里只有精品视频