CVE-2016-10277在MOTO X手机上的漏洞利用实践

时间:2022-04-29
本文章向大家介绍CVE-2016-10277在MOTO X手机上的漏洞利用实践,主要内容包括0x00 系统环境、0x01 漏洞原理、0x02 漏洞验证、0x03 漏洞利用、2) 通过参数注入劫持initramfs加载、3) 构造initramfs获取root权限、0x04 总结、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。

CVE-2016-10277是存在于摩托罗拉系列手机的bootloader高危漏洞,可以通过内核命令注入劫持手机的启动流程,加载攻击者控制的initramfs,从而达到root提权的目的。我们手上正好有一个摩托罗拉的MOTO X手机,于是参照[1]的漏洞利用过程,将CVE-2016-10277的漏洞利用过程实践了一把,复现过程还是十分曲折。

0x00 系统环境

1.手机: MOTO X(XT1581) 2.系统固件版本: 3.Android版本:5.1.1

在漏洞利用过程中需要用到手机boot.img中的aboot、initramfs,手机没有root的话是无法提取系统固件的,幸好我们在网上找到了对应的系统固件,可以直接提取使用。

0x01 漏洞原理

CVE-2016-10277的基本原理并不复杂,主要就是可以通过fastboot向bootloader注入内核命令参数。首先我们可以通过fastoot oem config 查看配置参数:

这些参数都未受保护,即使bootloader已锁,仍然可以通过fastboot oem config命令配置:

漏洞就在于bootloader未对配置的这些参数进行过滤,而这些参数会直接传递给内核的命令行。内核命令行参数的注入会影响bootloader的加载过程,攻击者如果精心构造某些参数,将达到控制手机启动,甚至root提权的目的。

0x02 漏洞验证

首先我们要先确定MOTO X是否受CVE-2016-10277漏洞的影响。

1) 注入参数设置property

执行命令:

fastboot oem config fsg-id "a androidboot.bar=1"

该命令注入了androidboot.bar=1参数,该参数如果注入成功,将会设置系统的ro.boot.bar属性为1。当然,这里我们只是虚构了一个bar属性。

2) 启动系统查看property

执行命令:

  fastoot continue
  adb shell getprop ro.boot.bar

可以看到成功设置系统属性,说明内核命令行参数注入成功,确定MOTO X受CVE-2016-10277漏洞的影响。

0x03 漏洞利用

通过该漏洞的命令行注入,我们可以向内核命令行注入众多参数,而这些参数又会在OS启动阶段多个地方被引用,因此该漏洞的攻击面是很广的,这里我们主要尝试能否通过该漏洞进行root提权。我们首先简单介绍下手机的启动过程,找到其中的利用点。

1) Android手机的Secure Boot过程

MOTO系列的手机大部分使用高通芯片,而高通芯片的手机大致启动过程如下:

[Primary Bootloader (PBL)] 
`-.
   [Secondary Bootloader (SBL)]
  `-.
    [Applications Bootloader (ABOOT)]
    `-.      
      [{boot,recovery}.img]
      |-- Linux Kernel
      `-- initramfs
          `-.
            [system.img]

手机开机后,首先启动的是bootloader,而bootloader又大致分为3个阶段,最先启动的是PBL,然后是SBL、ABOOT,最后通过ABOOT从boot.img或recovery.img中加载linux kernel和initramfs,进入系统加载阶段。initramfs是一个内存文件系统,bootloader一般会从固定的内存地址中加载,系统启动后会挂载到rootfs,即根目录/。initramfs包含很多重要文件,包括系统启动后第一个用户态进程init、服务启动脚本init.rc、selinux策略文件sepolicy、adbd程序等。如果我们能够让系统启动时加载我们构造的initramfs,那么我们就可以在这里面做很多劫持动作。而CVE-2016-10277的一个攻击面就是通过注入内核命令参数控制手机启动时的initramfs加载地址,加载我们指定的initramfs。

2) 通过参数注入劫持initramfs加载

通过CVE-2016-10277漏洞我们可以向内核注入initrd参数,该参数控制了initramfs的内存加载地址,参数形式如下:

initrd=<initramfs_address>,<initramfs_size>

首先我们测试是否可以劫持initramfs的加载地址,命令如下:

fastboot oem config fsg-id "a initrd=0x12341234,1024"
fastboot continue

执行命令后我们发现手机进入无限循环启动,无法进入系统,手机已崩溃,说明initrd参数起到了作用。为了验证能否顺利劫持initramfs加载,我们还需要找到可用的initramfs,并且找到向内存注入可控initramfs的方法。

由于不同的手机系统固件不一样,initramfs也不通用,我们只有通过网上下载的对应系统固件来提取initramfs。下载固件后解压缩找到boot.img,使用imgtool工具提取内核文件:

这里的ramdisk即是我们要找得initramfs。接下来我们想办法向内存中注入我们的ramdisk,可通过如下命令:

  fastboot flash thor ramdisk

我们向bootloader flash一个不存在image,虽然不能刷入,但是ramdisk肯定已经存在于手机内存中某个位置,接下来我们需要的就是找到这个位置。ABOOT二进制文件中有一个target_get_scratch_address函数,该函数返回的地址就是downloaded image存在的地址,所以我们通过IDA查看ABOOT文件就能够找到该地址。

ABOOT文件存在于bootloader中,提取固件中的bootloader.img,使用imgtool提取却出错了:

用010editor查看,看到了aboot的存在,但是bootloader.img应该是做了定制,不是普通的image文件。

使用谷歌大法,找到了一个专门用于提取moto image文件的python脚本https://github.com/laginimaineb/unpack_motoboot:

成功提取aboot文件后,放入IDA查看,由于没有删掉符号信息,可以快速定位到target_get_scratch_address函数:

我们从而得到flash image时image在内存中的地址为:0x11000000。综上,我们终于可以尝试劫持initramfs的加载:

不幸的是,手机依然无限循环重启。问题出在什么地方的?由于我们看不到任何启动时打印的信息,也不知从何入手。漏洞的发现者做出了一个猜测,有可能是flash image后,手机的启动过程中污染了我们发送的initramfs,导致initramfs被破坏。因此,我们需要将控制的initramfs填充,将真正的initramfs放到高地址的内存中:

.--------------------------------.----------------------.
| Physical Address               | Data                 |
|--------------------------------|----------------------|
| SCRATCH_ADDR                   | Corrupted PADDING    | 
| SCRATCH_ADDR + sizeof(PADDING) | Controlled initramfs |
`--------------------------------'----------------------'

我们选择padding的数据长度为32MB,

这次终于成功启动了系统,说明我们成功劫持了initramfs:

3) 构造initramfs获取root权限

成功劫持了initramfs后,我们需要想办法替换或修改initramfs中的文件来进行root提权。我们首先解压缩initramfs,它是一个cpio打包、gzip压缩的文件:

我们在sbin目录下看到了adbd二进制文件,它是我们我们执行adb shell时的服务程序。

我们想要root提权,一种方法就是patch adbd程序,让adb shell直接以root权限执行,而不是降权执行。在AOSP的adbd源码中我们看到,只要我们patch掉should_drop_privileges的执行,那么就能让adb shell以root权限执行。

但是,我们将adbd放入IDA一看,发现strip掉了函数符号,IDA在ARM64下没法F5,而且厂商在AOSP基础上做了很多定制,导致使用strings找特征都不好使。

如果要直接patch adbd程序估计得花很多时间逆向分析,这里我们走一下捷径,直接分析https://github.com/alephsecurity/initrootpatch后的adbd,然后对比原来的adbd程序,分析patch点,最后根据32位程序来推测64位arm程序可能的patch点。事实证明这是一条快速通道,我们很快就对比找到了patch点:

一共两处patch点,根据patch点的结构,我们在64位adbd中找到相似的patch点:

于是我们patch掉这两个地方,用patch后的adbd替换原来initramfs中的程序,重新打包运行,adb shell直接就是root权限:

通过类似的方法,我们还可以patch init程序,关掉selinux。

0x04 总结

CVE-2016-10277是一个比较有意思的漏洞,原理不复杂,只是一个简单的命令行参数注入,但是它的攻击面却很广,危害也很大。我们在复现该漏洞的利用过程中,经历了非常曲折的一个过程。本来漏洞发现者已经给出了MOTO G4、G5手机可用的exploit,但是我们的手机是MOTO X,原来的exp都没法用,只有自己摸索漏洞利用过程。在研究过程学习了secure boot、aboot、selinux等知识,该漏洞的利用覆盖了很广的知识面,值得研究。