摘要:同時,阿里聚漏洞掃描器有一個檢測項叫未使用地址空間隨機化技術(shù)該檢測項會分析中包含的文件判斷它們是否使用了該項技術(shù)。在版本上線前使用阿里聚安全漏洞掃描系統(tǒng)進(jìn)行安全掃描,將安全隱患阻擋在發(fā)布之前。
前言
我們在前文《APP漏洞掃描器之本地拒絕服務(wù)檢測詳解》了解到阿里聚安全漏洞掃描器有一項靜態(tài)分析加動態(tài)模糊測試的方法來檢測的功能,并詳細(xì)的介紹了它在針對本地拒絕服務(wù)的檢測方法。
同時,阿里聚漏洞掃描器有一個檢測項叫未使用地址空間隨機化技術(shù), 該檢測項會分析APP中包含的ELF文件判斷它們是否使用了該項技術(shù)。如果APP中存在該項漏洞則會降低緩沖區(qū)溢出攻擊的門檻。
本文主要介紹該項技術(shù)的原理和掃描器的檢測方法。由于PIE的實現(xiàn)細(xì)節(jié)較復(fù)雜,本文只是介紹了大致的原理。想深入了解細(xì)節(jié)的同學(xué)可以參看潘愛民老師的書籍《程序員的自我修養(yǎng)》。
PIE是什么PIE(position-independent executable)是一種生成地址無關(guān)可執(zhí)行程序的技術(shù)。如果編譯器在生成可執(zhí)行程序的過程中使用了PIE,那么當(dāng)可執(zhí)行程序被加載到內(nèi)存中時其加載地址存在不可預(yù)知性。
PIE還有個孿生兄弟PIC(position-independent code)。其作用和PIE相同,都是使被編譯后的程序能夠隨機的加載到某個內(nèi)存地址。區(qū)別在于PIC是在生成動態(tài)鏈接庫時使用(Linux中的so),PIE是在生成可執(zhí)行文件時使用。
PIE的作用PIE可以提高緩沖區(qū)溢出攻擊的門檻。它屬于ASLR(Address space layout randomization)的一部分。ASLR要求執(zhí)行程序被加載到內(nèi)存時,它其中的任意部分都是隨機的。包括
Stack, Heap ,Libs and mmap, Executable, Linker, VDSO。通過PIE我們能夠?qū)崿F(xiàn)Executable 內(nèi)存隨機化
除了安全性,地址無關(guān)代碼還有一個重要的作用是提高內(nèi)存使用效率。
一個共享庫可以同時被多個進(jìn)程裝載,如果不是地址無關(guān)代碼(代碼段中存在絕對地址引用),每個進(jìn)程必須結(jié)合其自生的內(nèi)存地址調(diào)用動態(tài)鏈接庫。導(dǎo)致不得不將共享庫整體拷貝到進(jìn)程中。如果系統(tǒng)中有100個進(jìn)程調(diào)用這個庫,就會有100份該庫的拷貝在內(nèi)存中,這會照成極大的空間浪費。
相反如果被加載的共享庫是地址無關(guān)代碼,100個進(jìn)程調(diào)用該庫,則該庫只需要在內(nèi)存中加載一次。這是因為PIE將共享庫中代碼段須要變換的內(nèi)容分離到數(shù)據(jù)段。使得代碼段加載到內(nèi)存時能做到地址無關(guān)。多個進(jìn)程調(diào)用共享庫時只需要在自己的進(jìn)程中加載共享庫的數(shù)據(jù)段,而代碼段則可以共享。
PIE工作原理簡介我們先從實際的例子出發(fā),觀察PIE和NO-PIE在可執(zhí)行程序表現(xiàn)形式上的區(qū)別。管中窺豹探索地址無關(guān)代碼的實現(xiàn)原理。
例子一
定義如下C代碼:
#includeint global; void main() { printf("global address = %x ", &global); }
程序中定義了一個全局變量global并打印其地址。我們先用普通的方式編譯程序。
gcc -o sample1 sample1.c
運行程序可以觀察到global加載到內(nèi)存的地址每次都一樣。
$./sample1 global address = 6008a8 $./sample1 global address = 6008a8 $./sample1 global address = 6008a8
接著用PIE方式編譯 sample1.c
gcc -o sample1_pie sample1.c -fpie -pie
運行程序觀察global的輸出結(jié)果:
./sample1_pie global address = 1ce72b38 ./sample1_pie global address = 4c0b38 ./sample1_pie global address = 766dcb38
每次運行地址都會發(fā)生變換,說明PIE使執(zhí)行程序每次加載到內(nèi)存的地址都是隨機的。
例子二
在代碼中聲明一個外部變量global。但這個變量的定義并未包含進(jìn)編譯文件中。
#includeextern int global; void main() { printf("extern global address = %x ", &global); }
首先使用普通方式編譯 extern_var.c。在編譯選項中故意不包含有g(shù)lobal定義的源文件。
gcc -o extern_var extern_var.c
發(fā)現(xiàn)不能編譯通過, gcc提示:
/tmp/ccJYN5Ql.o: In function `main": extern_var.c:(.text+0xa): undefined reference to `global" collect2: ld returned 1 exit status
編譯器在鏈接階段有一步重要的動作叫符號解析與重定位。鏈接器會將所有中間文件的數(shù)據(jù),代碼,符號分別合并到一起,并計算出鏈接后的虛擬基地址。比如 “.text”段從 0x1000開始,”.data”段從0x2000開始。接著鏈接器會根據(jù)基址計算各個符號(global)的相對虛擬地址。
當(dāng)編譯器發(fā)現(xiàn)在符號表中找不到global的地址時就會報出 undefined reference to `global`. 說明在靜態(tài)鏈接的過程中編譯器必須在編譯鏈接階段完成對所有符號的鏈接。
如果使用PIE方式將extern_var.c編譯成一個share library會出現(xiàn)什么情況呢?
gcc -o extern_var.so extern_var.c -shared -fPIC
程序能夠順利編譯通過生成extern_var.so。但運行時會報錯,因為裝載時找不到global符號目標(biāo)地址。這說明-fPIC選項生成了地址無關(guān)代碼。將靜態(tài)鏈接時沒有找到的global符號的鏈接工作推遲到裝載階段。
那么在編譯鏈接階段,鏈接器是如何將這個缺失的目標(biāo)地址在代碼段中進(jìn)行地址引用的呢?
鏈接器巧妙的用一張中間表GOT(Global Offset Table)來解決被引用符號缺失目標(biāo)地址的問題。如果在鏈接階段(jing tai)發(fā)現(xiàn)一個不能確定目標(biāo)地址的符號。鏈接器會將該符號加到GOT表中,并將所有引用該符號的地方用該符號在GOT表中的地址替換。到裝載階段動態(tài)鏈接器會將GOT表中每個符號對應(yīng)的實際目標(biāo)地址填上。
當(dāng)程序執(zhí)行到符號對應(yīng)的代碼時,程序會先查GOT表中對應(yīng)符號的位置,然后根據(jù)位置找到符號的實際的目標(biāo)地址。
所謂地址無關(guān)代碼要求程序被加載到內(nèi)存中的任意地址都能夠正常執(zhí)行。所以程序中對變量或函數(shù)的引用必須是相對的,不能包含絕對地址。
比如如下偽匯編代碼:
PIE方式:代碼可以運行在地址100或1000的地方
100: COMPARE REG1, REG2 101: JUMP_IF_EQUAL CURRENT+10 ... 111: NOP
Non-PIE: 代碼只能運行在地址100的地方
100: COMPARE REG1, REG2 101: JUMP_IF_EQUAL 111 ... 111: NOP
因為可執(zhí)行程序的代碼段只有讀和執(zhí)行屬性沒有寫屬性,而數(shù)據(jù)段具有讀寫屬性。要實現(xiàn)地址無關(guān)代碼,就要將代碼段中須要改變的絕對值分離到數(shù)據(jù)段中。在程序加載時可以保持代碼段不變,通過改變數(shù)據(jù)段中的內(nèi)容,實現(xiàn)地址無關(guān)代碼。
在Non-PIE時程序每次加載到內(nèi)存中的位置都是一樣的。
執(zhí)行程序會在固定的地址開始加載。系統(tǒng)的動態(tài)鏈接器庫ld.so會首先加載,接著ld.so會通過.dynamic段中類型為DT_NEED的字段查找其他需要加載的共享庫。并依次將它們加載到內(nèi)存中。注意:因為是Non-PIE模式,這些動態(tài)鏈接庫每次加載的順序和位置都一樣。
而對于通過PIE方式生成的執(zhí)行程序,因為沒有絕對地址引用所以每次加載的地址也不盡相同。
不僅動態(tài)鏈接庫的加載地址不固定,就連執(zhí)行程序每次加載的地址也不一樣。這就要求ld.so首先被加載后它不僅要負(fù)責(zé)重定位其他的共享庫,同時還要對可執(zhí)行文件重定位。
PIE與編譯器選項GCC編譯器用于生成地址無關(guān)代碼的參數(shù)主要有-fPIC, -fPIE, -pie。
其中-fPIC, -fPIE屬于編譯時選項,分別用于生成共享庫和可執(zhí)行文件。它們能夠使編譯階段生成的中間代碼具有地址無關(guān)代碼的特性。但這并不代表最后生成的可執(zhí)行文件是PIE的。還需要在鏈接時通過-pie選項告訴鏈接器生成地址無關(guān)代碼的可執(zhí)行程序。
一個標(biāo)準(zhǔn)的PIE程序編譯設(shè)置如下:
gcc -o sample_pie sample.c -fPIE -pie
在gcc中使用編譯選項與是否生成PIE可執(zhí)行文件對應(yīng)關(guān)系如下:
Type為DYN的程序支持PIE,EXEC類型不支持。DYN, EXEC與PIE對應(yīng)關(guān)系詳見后文。
ASLR在Android中的應(yīng)用PIE屬于ASLR的一部分,如上節(jié)提到ASLR包括對Stack, Heap, Libs and mmap, Executable, Linker, VDSO的隨機化。
而支持PIE只表示對Executable實現(xiàn)了ASLR。隨著Android的發(fā)展對ASLR的支持也逐漸增強。
ASLR in Android 2.x
Android對ASLR的支持是從Android 2.x開始的。2.x只支持對Stack的隨機化。
ASLR in Android 4.0
而在4.0,即其所謂的支持ASLR的版本上,其實ASLR也僅僅增加了對libc等一些shared libraries進(jìn)行了隨機化,而對于heap, executable和linker還是static的。
對于heap的隨機化來說,可以通過
echo 2 > /proc/sys/kernel/randomize_va_space
來開啟。
而對于executable的隨機化,由于大部分的binary沒有加GCC的-pie -fPIE選項,所以編譯出來的是EXEC,而不是DYN這種shared object file,因此不是PIE(Position Independent Executable),所以沒有辦法隨機化;
同樣的linker也沒有做到ASLR。
ASLR in Android 4.1
終于,在4.1 Jelly Bean中,Android支持了所有內(nèi)存的ASLR。在Android 4.1中,基本上所有binary都被編譯和連接成了PIE模式(可以通過readelf查看其Type)。所以,相比于4.0,4.1對Heap,executable和linker都提供了ASLR的支持。
ASLR in Android 5.0
5.0中Android拋棄了對non-PIE的支持,所有的進(jìn)程均是ASLR的。如果程序沒有開啟PIE,在運行時會報錯并強制退出。
PIE程序運行在Android各版本
支持PIE的可執(zhí)行程序只能運行在4.1+的版本上。 在4.1版本之前運行會出現(xiàn)crash。而Non-PIE的程序,在5.0之前的版本能正常運行,但在5.0上會crash。
如何檢測是否開啟PIE未開啟PIE的執(zhí)行程序用readelf查看其文件類型應(yīng)顯示EXEC(可執(zhí)行文件),開啟PIE的可執(zhí)行程序的文件類型為DYN(共享目標(biāo)文件)。另外代碼段的虛擬地址總是從0開始。
為什么檢測DYN就可以判斷是否支持PIE?
DYN指的是這個文件的類型,即共享目標(biāo)文件。那么所有的共享目標(biāo)文件一定是開啟了PIE的嗎?我們可以從源碼中尋找答案。查看glibc/glibc-2.16.0/elf/dl-load.c中的代碼。
從源碼可知,如果加載類型不為ET_DYN時調(diào)用mmap加載文件時會傳入MAP_FIXED標(biāo)志。將程序映射到固定地址。
阿里聚安全開發(fā)中建議針對Android 2.x-4.1之前的系統(tǒng)在編譯時不要使用生成PIE的選項。
在Android 4.1以后的版本必須使用PIE生成Native程序,提高攻擊者中的攻擊成本。
在版本上線前使用阿里聚安全漏洞掃描系統(tǒng)進(jìn)行安全掃描,將安全隱患阻擋在發(fā)布之前。
Referencehttps://en.wikipedia.org/wiki...
http://www.openbsd.org/papers...
https://source.android.com/se...
http://ytliu.info/blog/2012/1...
https://codywu2010.wordpress....
http://www.cnblogs.com/huxiao...
http://stackoverflow.com/ques...
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/11205.html
摘要:然而,處理器的某些特殊硬件特性能夠打破這種保護(hù),使得普通程序在用戶態(tài)能夠直接訪問內(nèi)核空間,直接打破內(nèi)核空間與用戶空間的隔離,修改內(nèi)核代碼,開啟上帝模式。假設(shè)某臺安卓終端擁有內(nèi)存。至此,上帝模式已經(jīng)開啟。 文/圖 阿里安全潘多拉實驗室 團(tuán)控 編者按:團(tuán)控,阿里安全潘多拉實驗室研究人員,該實驗室主要聚焦于移動安全領(lǐng)域,包括對iOS和Android系統(tǒng)安全的攻擊和防御技術(shù)研究。團(tuán)控的主攻方向...
摘要:中的名稱,一定要是服務(wù)中注冊的名稱。添加這個的注解,主要是因為定義的時候報錯,也就是說明沒有被實例化。采用隨機分配的策略。添加訪問層添加電影微服務(wù)啟動類電影微服務(wù),使用定制化在客戶端進(jìn)行負(fù)載均衡,使用不同服務(wù)不同配置策略。 SpringCloud(第 007 篇)電影微服務(wù),使用定制化 Ribbon 在客戶端進(jìn)行負(fù)載均衡,使用 RibbonClient 不同服務(wù)不同配置策略 - 一、大...
摘要:序隨著蘋果對系統(tǒng)多年的研發(fā),上的安全防護(hù)機制也是越來越多,越來越復(fù)雜。代碼簽名為了保護(hù)開發(fā)者的版權(quán)以及防止盜版應(yīng)用,蘋果系統(tǒng)擁有非常嚴(yán)格的簽名保護(hù)機制。除了傳統(tǒng)的簽名機制以外,蘋果還額外增加了的安全防護(hù)措施,用來增強系統(tǒng)的安全性。 0x00 序 隨著蘋果對iOS系統(tǒng)多年的研發(fā),iOS上的安全防護(hù)機制也是越來越多,越來越復(fù)雜。這對于剛接觸iOS安全的研究人員來說非常不友好,往往不知從何入...
閱讀 3789·2021-11-24 09:39
閱讀 3596·2019-08-30 15:56
閱讀 1412·2019-08-30 15:55
閱讀 1089·2019-08-30 15:53
閱讀 1980·2019-08-29 18:37
閱讀 3659·2019-08-29 18:32
閱讀 3181·2019-08-29 16:30
閱讀 3049·2019-08-29 15:14