系統安全與漏洞利用

位址空間佈局隨機化(ASLR)

/ A-S-L-R /

大多數利用都需要「知道」某個位址——libc 的 system() 在哪、一個 ROP gadget 在哪、堆疊在哪。ASLR 是「搬動家具」這道防禦:程式每次執行時,作業系統把它的各部分載入到隨機化的基底位址,使攻擊者無法再把所需的位址寫死。它就像一棟每次造訪房號都被重新洗牌的大樓——你上次的地圖派不上用場。

具體而言,當一個行程啟動時,載入器把主要區段——可執行檔(若建構成與位置無關)、共享函式庫、堆積、堆疊、以及 mmap 區段——放到加了隨機位元而選定的基底位址。所以 libc 這次可能載入在 0x7f3a...,下次在 0x7f8c...。利用程式以絕對位址引用的任何東西(一個 gadget、一個函式、一個緩衝區)如今都在未知的位置,使得為固定位址寫成的 ROP 鏈與返回 libc 攻擊破功。ASLR 的強度以「熵」衡量——有多少隨機位元進入基底位址;位元越多代表可能位置越多,猜中的機率越小。

它之所以重要,是作為一道便宜、廣泛的緩解措施,替幾乎所有記憶體利用提高了門檻,但誠實地說它是一道機率性的障礙,不是一堵牆。有兩件事能擊敗它。第一,一次資訊洩漏(一次任意讀、一個格式字串 %x、一次未初始化記憶體的揭露)只要揭露「一個」真實的執行期位址,攻擊者就能算出其他所有的,因為各區段是依單一隨機基底一起移動的。第二,「低熵」:32 位元系統的隨機位元太少,所以暴力嘗試或堆積噴灑可能得手;64 位元的 ASLR 強得多。這就是為何 ASLR 總是與 DEP、金絲雀、CFI 搭配——它拖慢攻擊者,但單一一次洩漏就能讓它失效。

$ cat /proc/self/maps | grep libc # 第 1 次執行 7f3a1c200000-7f3a1c3c0000 r-xp ... libc.so.6 $ cat /proc/self/maps | grep libc # 第 2 次執行 7f8c4e800000-7f8c4e9c0000 r-xp ... libc.so.6 # 每次基底都不同

libc 每次執行都載入在不同的基底,所以利用程式寫死的位址會落空。

只有當二進位檔建構成與位置無關(PIE/PIC)時,ASLR 才會隨機化它自己的程式碼;而一次資訊洩漏揭露一個基底,就掀開了整個區段——ASLR 拖慢攻擊者,卻擋不住一個帶著洩漏的攻擊者。

又稱
address space layout randomizationaddress randomization位址隨機化