ARM Exploitation
原文:Learning Pentesting for Android Devices
0x00
本文主要帶大家了解ARM處理器的基礎知識和ARM世界中不同種類的漏洞.我們會進一步分析這些漏洞來搞清楚它的具體利用場景.此外,我們還會研究不同的安卓rooting利用腳本用于挖掘潛在的漏洞.考慮大世面上大多數android智能手機都是基于ARM架構處理器,因此了解ARM以及ARM中存在的安全隱患是非常有價值的.
0x01 Introduction to ARM architecture
ARM架構基于精簡指令集(Reduced Instruction Set Computing RISC),這意味著它具有比基于復雜指令集(Complex Instruction Set ComputingCISC)少得多的指令架構.使用ARM處理器的設備幾乎無處不在,比如智能手機,電視,電子書,嵌入式設備等等.
ARM共有16個通用寄存器從R0到R15.(R0-R7,8個通用寄存器)其中5個有特?殊意義:
- R11: Frame Pointer (FP)
- R12: 內部過程調用暫時寄存器 Intra-procedure Register (IP)
- R13: 棧指針 Stack Pointer (SP)
- R14: 鏈接寄存器 Link Register (LR)
- R15: 程序計數器 Program Counter (PC)
下圖顯示了ARM架構:
這五個寄存器中我們應重點關注如下三個:
-
棧指針 Stack Pointer (SP-R13):存儲棧頂指針
-
鏈接寄存器 Link Register (LR-R14):存儲被調用函數返回地址
-
程序計數器 Program Counter (PC-R15):存儲著下一條執行指令的地址.每條執行被執行后,該計數器會進行自增.
0x02 Execution modes
ARM有兩種執行模式:
- ARM 模式: In the ARM mode, 32位指令集
- Thumb 模式: In the Thumb mode, 16位指令集
執行模式取決于程序狀態寄存器(CPSR)的狀態.其實存在第三種模式: Thumb-2模式,就是將arm模式和Thumb模式混合.我們不會去分析這兩種模式的區別,因為這樣就超出本文的范圍了.即使是Android SDK中的模擬器也是arm平臺的,其他大多數的智能手機也是基于arm.但是我們還是選擇從開源硬件模擬器QEMU開始進行ARM exploitation的訓練.
0x03 Setting up the environment
在我們開始基于ARM平臺設備的exploiting前建議先安裝好對應的環境.盡管Android SDK的模擬器也能基于arm運行,而且大多數的智能手機也是基于arm.我們還是選擇用QEMU(開源硬件虛擬機和模擬器)開始ARM exploitation.
為了在android設備上執行接下來的操作,我們需要下載和配置Android NDK環境.如果你正使用Mac,那么安裝QEMU是非常簡單的,只需要輸入:brew install qemu
如果系統是Ubuntu需要執行如下操作:
1.第一步下載安裝QEMU依賴包
sudo apt-get build-dep qemu wget http://wiki.qemu-project.org/download/qemu-1.7.0.tar.bz22.下一步配置QEMU,指定目標為ARM最后make.只需要進入解壓后的目錄輸入如下命令.
./configure --target-list=arm-softmmu make && make install3.一但QEMU安裝成功,我們就可以下載ARM平臺的Debian鏡像運行exploitation習題.下載列表:
http://people.debian.org/~aurel32/qemu/armel/
4.這里我們下載格式為qcow2的鏡像,debian_squeeze_armel_ standard是基于QUME的系統鏡像.qcow2 for our OS.內核文件是 vmlinuz-2.6.32- 5-versatile ,RAM磁盤文件是initrd.img-2.6.32-5- versatile.下載完必須文件后就可以通過以下指令啟動QEMU實例.
qemu-system-arm -M versatilepb -kernel vmlinuz-2.6.32-5-versatile -initrd initrd.img-2.6.32-5-versatile -hda debian_squeeze_armel_standard.qcow2 -append "root=/dev/sda1" --redir tcp:2222::225.上述所有操作成功就可以通過以下命令ssh登錄QEMU:
ssh root@[ip address of Qemu] -p 22226.默認帳號密碼是root:root.
到此我們已經成功配置好環境,是時候開始exploiting存在漏洞的應用
0x04 Simple stack-based buffer overflow
簡單來講,緩存(buffer)是用于存儲任意數據的地方.當緩存的數據超過了緩存區的大小就會發生溢出(overflow).攻擊者可以利用溢出攻擊來控制程序執行惡意代碼.
下面就用一個簡單的程序來演示如何利用溢出攻擊.下圖中顯示程序有三個函數:vulnerable, ShouldNotBeCalled以及 main.
執行程序的時候函數 ShouldNotBeCalled 一直沒有被調用.
函數vulnerable只有一個操作就是將成員變量拷貝到只有10bytes大小的緩存buff中.
寫完此程序后通過gcc編譯(arm虛擬機中編譯).此外我們還將禁用空間格局隨機化Address Space Layout Randomization (ASLR)讓利用場景變得更簡單些.ASLR是一種針對緩沖區溢出的安全保護技術,通過對堆、棧、共享庫映射等線性區布局的隨機化,通過增加攻擊者預測目的地址的難度,防止攻擊者直接定位攻擊代碼位置,達到阻止溢出攻擊的目的.據研究表明ASLR可以有效的降低緩沖區溢出攻擊的成功率,如今Linux、FreeBSD、Windows等主流操作系統都已采用了該技術.Android 4.0之后也實現了該方案.http://www.duosecurity.com/blog/exploit-mitigations-in-android-jelly-bean-4-1
echo 0 > /proc/sys/kernel/randomize_va_space //禁用ASLR gcc -g buffer_overflow.c -o buffer_overflow //編譯example下一步,用gdb調試二進制文件.
gdb -q buffer_overflow使用disass命令反編譯一部分函數,下圖為反編譯ShouldNotBeCalled
正如截圖中說看到的,函數ShouldNotBeCalled從內存地址0x00008408開始.如果我們查看反編譯的main函數,將會發現vulnerable函數是從0x000084a4開始調用,在0x000084a8返回.當程序進入存在漏洞的函數,使用有漏洞的指令strcpy,函數并不會檢查拷貝字符串的大小.如果程序進入存在漏洞的子程序,我們就能夠通過控制LR控制整個程序流程.
這里目標是估算LR何時被重寫之后插入ShouldNotBeCalled地址來調用函數ShouldNotBeCalled.用一個較長的參數運行程序,比如下面的命令,觀察發生了啥.在此之前先在調用strcpy地址處設置斷點.
b vulnerable b *<address of the strcpy call>通過設置斷點,我們可以將參數改成AAAABBBBCCCC運行程序觀察他如何被覆蓋.觀察發現在vulnerable和strcpy函數被調用時觸發斷點.一但斷點觸發,我們就可以通過x命令指定sp操作堆棧.如下圖
如圖所示,堆棧已經被我們輸入(ASCII: 41 for A, 42 for B, and so on)的buffer重寫.分析截圖,發現0x000084a8這種情況我們需要多于4個字節去覆蓋返回地址.
最終輸入的字符串為16字節的垃圾數據和函數ShouldNotBeCalled的地址
r `printf "AAAABBBBCCCCDDDD\x38\x84"`如圖所示,我們將IShouldNeverBeCalled起始地址插入參數中
請注意,因為框架原因這里字節順序是相反的.這樣就能看到程序調用函數ShouldNotBeCalled了.如下圖
0x05 Return-oriented programming
大多數情況下,我們并不需要調用程序自身的其他函數.相反,我們需要在攻擊向量中插入shellcode,這樣就可以通過shellcode達到任意目的.但是,再大多數基于arm平臺的設備中內存區域是不可執行的,這樣就阻止了我們插入和執行shellcode.
所以,攻擊者必須依賴一項技術返回導向編程 return-oriented programming ROP.所謂ROP,簡單的說就是把原來內存已經存在的代碼塊拼接起來,拼接的方式是通過一個預先準備好的特殊的返回棧,里面包含了各條指令結束后下一條指令的地址.最終執行我的shellcode.在一般程序里面,都包含著大量的返回指令(ret),他們基本位于函數的尾部,或是函數中部需要返回的地方.而從函數開始的地方到ret指令之間的這一段序列稱為二進制指令代碼塊(gadgets).我們需要在整個內存空間中搜索我們需要的gadgets
舉個例子,如果我們在調試程序的時候反編譯seed48(),得到如下輸出:
分析反編譯代碼,代碼包含一個ADD指令接著是POP和BX指令,這就是完美的 ROP gadget.這里攻擊者可以想到為了利用 ROP gadget 首先跳到POP指令控制R4(which will be six less than the address of /bin/sh)之后在LR中輸入ADD指令的值.最后我們得到 /bin/sh 的地址,當我們跳會ADD (R0 = R4 + 6 ),之后我們可以在R4中指定任意垃圾數據以及LR中指定 system() 的地址.
這意味著我們最終講跳到 system() 并且參數為 /bin/sh , 這樣就可以執行shell命令了.用同樣的方式,我們可以創建任意ROP gadget 來達到執行任意命令的效果.因為ROP是個非常復雜的話題,強烈建議自己動手嘗試分析反編譯代碼,然后構造exploit.
0x06 Android root exploits
在早期android版本中,各種android版本的各種設備都遇到Android root exploits .Android rooting就是獲取設備的最高權限而不是手機制造廠商給用戶的默認權限.這些root exploits利用了各種Android系統漏洞.下面是一些漏洞列表和漏洞原理簡介:
-
Exploid: CVE-2009-1185 影響android2.1及之前版本,此exploit基于udev漏洞CVE-2009-1185,udev是一個android組件負責USB連接,進程應該只處理kernel發送的device的NETLINK的socket消息,但實際上并未檢測NETLINK的socket消息的來源,這樣可以廣播add device的socket信息,觸發硬件處理事件,將惡意代碼傳入kernel,由其寫入設備文件.這樣,攻擊者只需發送一條構造好的udev消息就可以提權了.
-
Gingerbreak:CVE-2011-1823,此exploit利用vold的漏洞,原理類似上一個.(android并沒有實現linux的udev,其功能由vold進程實現,其包含VolumeManager,NetlinkManager,CommandListener等modules).Android 2.3.4之前版本的 volume 守護進程(vold)由于信任從 PF_NETLINK socket 接收到的消息,因此允許以 root 權限執行任意代碼,利用方法是通過一個負數索引繞過指針對最大值的有符號整數檢查.
-
RageAgainstTheCage:此exploit基于RLIMIT_NPROC,RLIMIT_NPROC用于指定用戶調用setuid()函數的時候能創建的最大進程數.adb 后臺是root權限,之后會調用 setuid() 自行降權.android 2.2 以及之前版本如果進程數達到RLIMIT_NPROC的閾值,程序就不會調用setuid()降權,這樣adb就會以root權限運行了.
-
Zimperlich:與RageAgainstTheCage原理類似,不一樣的是此處依賴的zygote進程的降權.所有的android應用是由Zygote進程fork分支后啟動的.Zygote是由root權限運行的.在fork之后新的進程將使用setuid調用降權至目標應用的uid.Android2.2以及之前版本的Zygote沒有對降權時setuid調用的返回值進行檢查.同樣,在耗盡目標程序uid的最大進程數之后,Zygote就無法降低它的權限,然后就以root權限啟動應用了.
-
KillingInTheNameOf: CVE-2011-1149 此expolit利用了ashmem (the shared memory manager) 接口漏洞,用于修改ro.secure的值,ro.secure決定了設備的root狀態.Android 的共享內存(Ashmem)子系統是一個共享內存分配器.共享內存可以通過 mmap 或者文件 I/O 進行訪問.在android 2.3之前,ashmem 允許任何用戶重新映射屬于 init 進程的共享內存,將包括系統屬性地地址空間的內存進行共享,KillingInTheNameOf 利用程序將系統屬性空間重新映射為可寫,并將 ro.secure 屬性設置為0.在重啟 adbd 后,ro.secure 屬性的修改會允許 adb shell 取得 root 權限訪問.
這些都是比較出名的用戶root安卓設備的exploits.
0x07 附錄
數據處理指令-指令編碼
操作碼功能表
分支指令B/BL-指令編碼
分支指令BX-指令編碼
分支指令功能表
- 跳轉指令:
- B 跳轉指令。
- BL 帶返回的跳轉指令。
- BLX 帶返回和狀態切換的跳轉指令。
- BX 帶狀態切換的跳轉指令。
- 數據處理指令
- MOV 數據傳送指令
- MVN 數據取反傳送指令
- CMP 比較指令
- CMN 反值比較指令
- TST 位測試指令
- TEQ 相等測試指令
- ADD 加法指令28
- ADC 帶進位加法指令
- SUB 減法指令
- SBC 帶借位減法指令
- SUB 減法指令
- SBC 帶借位減法指令
- RSB 逆向減法指令
- RSC 帶借位的逆向減法指令
- AND 邏輯與指令
- ORR 邏輯或指令
- EOR 邏輯異或指令
- BIC 位清除指令
- 乘法指令與乘加指令
- MUL 32 位乘法指令
- MLA 32 位乘加指令
- SMULL 64 位有符號數乘法指令
- SMLAL 64 位有符號數乘加指令
- UMULL 64 位無符號數乘法指令
- UMLAL 64 位無符號數乘加指令
- 程序狀態寄存器存取指令
- MRS 程序狀態寄存器到通用寄存器的數據傳送指令。
- MSR 通用寄存器到程序狀態寄存器的數據傳送指令。
- 寄存器加載/存儲指令
- LDR 字數據加載指令
- LDRB 字節數據加載指令
- LDRH 半字數據加載指令
- STR 字數據存儲指令
- STRB 字節數據存儲指令
- STRH 半字數據存儲指令
- LDM 連續數據加載指令
- STM 連續數據存儲指令
- 數據交換指令 :
- SWP 字數據交換指令
- SWPB 字節數據交換指令
- 移位元指令:
- LSL 邏輯左移
- ASL 算術左移
- LSR 邏輯右移
- ASR 算術右移
- ROR 循環右移
- RRX 帶擴充的循環右移
- 協處理器指令
- CDP 協處理器數據操作指令
- LDC 協處理器數據加載指令
- STC 協處理器數據存儲指令
- MCR ARM處理器寄存器到協處理器寄存器的數據傳送指令
- MRC 協處理器寄存器到ARM處理器寄存器的數據傳送指令
arm架構完整版
0x08 參考
http://infocenter.arm.com/help/topic/com.arm.doc.qrc0001mc/QRC0001_UAL.pdf
http://bbs.pediy.com/showthread.php?t=176283
http://hack0nair.me/2013-04-05-return-oriented-programming/
http://blog.csdn.net/jackaduma/article/details/7286348
原文地址: http://drops.wooyun.org/mobile/5915
總結
以上是生活随笔為你收集整理的ARM Exploitation的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Pocket Hacking: NetH
- 下一篇: 一个例子让你了解Java反射机制