Android Island work profile apps and AFWall

Island is an app that allows you to isolate, clone, freeze, hide, archive apps.

Unfortunately when you use it with iptables firewall app like AFWall the apps placed in the work profile have no access to the network. (because there aren’t rules allowing them in the firewall)

AFWall doesn’t support multiple profiles – there’s an experimental option called “multi-user support" but only works in mode where selected items are blocked:

 

AFWall doesn’t show work profile apps. So I need a way to allow work profile app traffic.

With a bit of digging, I found the rule for work profile (UNIX) uid : user_id*100000+app_uid , the primary user has user id of 0, the work profile Island created has user id 10.

So you can go look for app uid, add user_id*100000 , and it becomes the (UNIX) uid of the app in that work profile.

A quick way to know app_uid is go to AFWall preferences > User interface > “Show UID for apps".

Then you need to write your own rules that allows traffic to pass through, the number after --uid-owner is the UID you want to change, in this example I allowed 3 apps:

Place it in /data/local/, chmod +x it, add its path to AFWall custom script, then apply rules in AFWall. You should now get internet in work profile apps.

Linux kernel function / system call hijacking

想要 hijack 某個 Linux kernel 的 function ,所以開始了這次的搜尋。

Linux kernel 各部分之間的 function 呼叫有2種,一種是直接把要呼叫的 function header file include 進來,如果是在同一個檔案當然也不需要 include。另一種是呼叫 exported function ,允許外部呼叫的 function 在定義之後會加上 EXPORT_SYMBOL(function_name) ,這個 function 的記憶體位址就可以從 kernel symbol table 找到(symbol table 裏面不只有 function ,也有變數)。外部呼叫是指 kernel 的其他部分還有 kernel module ,外部呼叫時會去 symbol table 找位址再進行呼叫(應該吧)。

所以只要修改 symbol table 的內容,就可以 hijack 特定的 function,讓他去找我們自己定義的位址的 function 去呼叫了。不對

但是一般 kernel symbol table 是唯讀的,看一下 /proc/kallsyms 的內容,第一欄是記憶體位址,第二欄是屬性(是否可讀寫等等,標籤代表的意義請 man nm),第三欄是變數或函式名稱。

system call table 裏面存了所有 system call 的記憶體位址,它的 symbol 叫做 sys_call_table ,在大部分的 Linux 上面應該是 R (唯讀)需要先解除 page write protection 才能修改。(其他參考)HTC Android kernel 的 sys_call_table 標籤居然是 T ,意思好像是可讀寫?

syscall table 裏面存了所有 syscall 的進入點(記憶體位址),用 sys_call_table[CONSTANT] 的方式可以找到特定 syscall 的進入點,像是如果要找 fork() 的進入點,就這樣寫:sys_call_table[__NR_fork]__NR_fork 這些 constant 定義於 unistd.h ,依處理器架構會有不同。上面連結的那兩篇有如何 hijack syscall 的教學。

後來發現我要的不是 syscall hijacking ,而是 kernel function hijacking ,我搞混了這兩個。syscall 是 userspace 程式和 kernel 溝通的界面,一般來說都是由應用程式呼叫;kernel function 是 kernel 內部的函式,提供給其他 kernelspace (可能在 kernel 或是 kernel module )的函式調用,又有是否 export 之分,有 export 的 function 在宣告後會加上 EXPORT_SYMBOL(function_name) ,它的位址就在 symbol table 找得到。

要 hijack kernel function 似乎要牽涉到一些 shellcode… 而且是 platform-specific ,還有待研究。(順帶一看

搜尋的過程當中找到這幾個問答:

發現若不是要 hijack 的話,基本的 debug 可以透過 kprobe

 

編譯 HTC Android kernel 和自製 kernel module

Kernel

這部分參考 HTC kernel source code 隨附的 Readme

首先把 compiler 抓下來

git clone https://android.googlesource.com/platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6

指定環境變數

export TOP= [where you installed the toolchain or top of android AOSP code base]
export PATH=$TOP/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin:$PATH (use corresponding arm-eabi bin path)
export ARCH=arm
export SUBARCH=arm
export CROSS_COMPILE=arm-eabi-

套用 defconfig 設定檔

make k2_u_defconfig

真正編譯,可以調整平行編譯數

make -j8

Kernel Module

kernel module 需要已經編譯好的 kernel 才能編譯。Makefile 參考這邊

obj-m 指定編譯出的 object 檔名,應該要與 .c 原始檔同名(如果要編 feng.c ,object 檔就要寫 feng.o)
KERNELDIR 是已經編譯好的 kernel 的目錄

CROSS_COMPILE 指定 toolchain 的目錄

然後 make 就可以了。

初探 Android kernel 漏洞

爲了想要取得 HTC One SV 的 root 權限,進行了這次研究。

通常要 root HTC 的手機必須先到 HTCDev 網站解鎖 bootloader ,安裝第三方 bootloader ,然後注入 su 執行檔。如此一來 HTC 就知道那一臺裝置解鎖了,未來維修的時候或許會拒絕。(雖然網路上爬文的結果大部分人都說只要有將 bootloader 重新鎖定,維修的工程師就不會去特別檢查解鎖記錄。非軟體問題在保固期間內就算有解鎖記錄,只要有重新鎖定,維修的價格還是有保固的優惠。這是臺灣的情形)這種官方解鎖也會將手機上的資料完全清除,因爲一旦解鎖就有可能取得 root 權限,可以取得 /data 分割區內的各種個人資料、帳號密碼。

我就在想,有沒有辦法不跟 HTC 註冊就取得 root 權限?

如果不找官方解鎖,取得 root 權限的方法還有一種,就是利用 kernel 本身的提權 (privilege escalation) 漏洞。開啓 USB 偵錯模式,使用 adb shell ,我們就有了本地一般使用者的權限,再上傳利用這種漏洞的執行檔,執行之後如果利用成功,就可以取得 root 權限。

這種漏洞很多,android_run_root_shell 工具整合了多種漏洞來取得 root 權限。

這種漏洞可以藉由分析 kernel 原始碼來取得,很多都是 overflow 和 pointer 的問題(但我不會分析啦)。就算不親自去分析,也有很多已經公開,甚至已經有 exploit 程式的漏洞,大部分手機的 kernel 都沒有修補。Android kernel 很多漏洞都是從 Linux kernel 移植過來的。出自 Linux kernel 的漏洞影響的裝置幾乎是全部(所有的裝置都可以利用這個漏洞);出自 driver 的漏洞就只影響有使用此 driver 的裝置。

研究 Android kernel 漏洞的人好像蠻多的,而且很多已經有 Proof of Concept 或是實際的攻擊程式,大概是因爲 Android 裝置很多,而且這類核心漏洞修補困難吧。(製造商客製化的 Android kernel 要套用 patch 比較麻煩吧,而且每一款裝置的 kernel 都略有不同)

CVE-2013-2094

又稱 perf_swevent_init exploit 。

這個漏洞的破解程式 android_run_root_shell 裏面有,有漏洞的裝置清單在這

這個漏洞有點麻煩,要能夠利用它得取得幾個 kernel symbol 的位址,可以藉由反組譯 kernel 來取得,爲了要反組譯 kernel 得先取得 kernel image (zImage) ,使用工具可以把 zImage 從 boot.img 分離出來。

boot.img 是從 /dev/block/mmcblk0p16 之類的裝置(每一款手機裝置節點不同)當中 dd 出來的映像檔,裏面包含 zImage 和 init ramdisk ,boot.img 格式的細節

再利用 arm-linux-androideabi-objdump (ndk 裏面有)反組譯 kernel ,取得 kernel symbol 位址

$ arm-linux-androideabi-objdump --disassemble-all -b binary -m arm --adjust-vma=0xc0008000 kernel.zImage > kernel.dasm

這步驟我不是很懂。後來找到一個 script 把分離 boot.img 和反組譯、找 symbol 全包了。總之就是要找到這幾個位址(別照抄這幾個位址,這不是臺灣版 One SV 的):

prepare_kernel_cred=0xc00b3cc4
commit_creds=0xc00b3814
remap_pfn_range=0xc0132584
ptmx_fops=0xc0ede13c
perf_swevent_enabled=0xc0ec7784

利用找到的 kernel symbol 位址去 android_run_root_shell 加上 One SV 的支援,改改 C 的 code ,加上裝置和位址的定義這樣,這還是在資工系學 C 以來第一次有實際用途…… 不過這個工具裏面的另一個 fb_mem exploit 會造成 segmentation fault ,執行不到這個漏洞就結束,所以要註解掉 fb_mem 的 code 。如何編譯 README 有寫了。

但……我最大的麻煩是,連 boot.img 都沒有辦法取得。不同版本不同地區的 kernel 略有不同,kernel symbol 的位址也不一樣,我在網路上找不到臺灣版 One SV 原廠 Android 4.1.2 的 boot.img

另一個取得 symbol 位址的方法是讀取 /proc/kallsyms ,但是從 2011 年初 Android 就引進了 patch ,預設在 /proc/kallsyms 的地址只顯示全零,必須要將 /proc/sys/kernel/kptr_restrict 設爲1,才會顯示真的地址。但 /proc/sys/kernel/kptr_restrict 限定只有 root 才能更改……

這就要靠下一個漏洞來解決了……

CVE-2013-2596

又稱 fb_mem exploit ,我在 One SV 實測確實可以取得 root 權限的漏洞。kernelchopper 是比較低階利用此漏洞的程式,可以任讀寫記憶體,我實測是可以讀,但我不敢亂寫記憶體所以沒試,所以這個漏洞在 One SV 是存在的,它寫的手動改記憶體取得 root 權限的方式我看不太懂,不會用。motochopper 是高階工具 ,原本是專爲 Galaxy S4 做的,我稍微修改一下執行用 script 讓它破解完不要重開機就可以給 One SV 用了。HTC 的手機都有額外的防寫機制,執行檔放進 /system 之後重開機會消失,這應該就是所謂的 S-ON / S-OFF (我還沒深入研究),所以破解程式送進去執行之後不能重開機。

取得了 root 之後,就可以改 /proc/sys/kernel/kptr_restrict 然後讀 /proc/kallsyms 了。不過都已經有 root 了,要那些 kernel symbol 地址只是要驗證 perf_swevent_init 漏洞而已。

android_run_root_shell 工具包裏面還有其他漏洞,不過我要先去研究 s-off 了。