一周前,黄浦江边烟花肆虐,市内交通一度中断;正开场时,德尔塔破防了也才持续没多久的平静祥和,真是刚松弛下来的神经跟口罩一样不自觉又绷紧起来;新制度几周后上线,不免让人担忧技术交流难再续写此般纯粹、酣畅和淋漓。

MOSEC 2021如约而至!

好像什么都在变,还好我们没变。

六个移动端最前沿的漏洞议题,茅台味浓厚的BaiJiuCon搭配出道即巅峰的小微议题,满满当当一整天,上个厕所都恨不得跑步往返。那就让我们赶紧趁热回顾一下MOSEC上的精彩议题:

1. 无接触攻破智能手机中的5G基带

这个议题的演讲者是腾讯科恩实验室的Marco Grassi和陈星宇。近年5G的发展与逐渐普及和特有的0click攻击面使5G安全问题备受关注。他们研究的对象是三星Exynos 980芯片,搭载这款芯片的手机采用了SA(Standalone)模式组网(即基带要支持5G中的New Radio)。逆向分析后他们发现三星自研的基带系统Shannon缺乏Stack Cookie的保护,而且运行ARM指令集,为研究人员提供了友好的漏洞分析和利用环境。

和之前基带漏洞相关的议题不同的是,他们关注的是比较上层的通信,即IMS交互采用的SIP协议。这是一个类HTTP的纯文本协议,进一步分析发现其body可以搭载XML形式的负载。尽管已经有很多历久经年的XML解析库供参考,三星基带的XML parser依然是自研的 :)复杂的XML的解析逻辑就成了一个巨大的攻击面。他们从发现的众多漏洞里选择了一个展开分析。

这个漏洞是tag的长度未校验导致的问题,可以发送超长的tag向栈上的buffer无限制地拷贝可控数据,导致了一个教科书级别的栈溢出。尽管软件部分直观简洁,但基带漏洞研究一个掉头发的难点在于构造出5G基站和手机相连。他们一开始选择docker_Open5GS在搭建的IMS server时发现,尽管高通芯片的手机可以正常连接,但三星的UE就各种问题。通过三星系统自带的Sysdump和IMS logger(adb logcat -b radio/all可以看到基带的崩溃信息),结合本地的抓包定位了Open5GS的Bug。在NOP了开源server代码里IPSec的检查才得以发送SIP的payload到手机。

最后他们演示了如何远程触发基带执行shellcode,并修改手机存放在NVRAM中的IMEI,成功利用后可以在AP侧(也就是Android端)显示指定的IMEI。

2. XNU port类型混淆利用探讨

盘古的联合创始人王铁磊为大家带来的议题是围绕苹果系统核心IPC机制port展开的。王铁磊首先介绍了苹果操作系统的微内核架构,并类比文件系统普及了一下port的基本通信机制和对象结构。由于微内核的系统高度依赖IPC,port的功能十分丰富,除了传输数据,还兼备句柄、权限、进程控制、信号量等几十种特性于一身。

一开始他是从Google Project Zero公布的在野漏洞CVE-2020-27932受到启发,在diff和尝试复现时突发奇想填写了相同的发送和接受port触发了新漏洞。由于这个新漏洞的原理涉及深层次的系统逻辑,一万字讨论不清楚,大家可以参考他之前zer0con的slides理解一下(https://github.com/wangtielei/Slides)。结论就是利用这个漏洞,可以对任意port结构中的io_bits实现减1的操作。io_bits被用来描述一个port的类型,因而利用这个漏洞可以改变port的种类,实现可控的类型混淆。

接下来王铁磊展示了七种花式利用该漏洞的提权的思路:iouserclient和UNDReply/clock这类包含指针的port混淆,进而直接控PC;通过控制SEMAPHORE -> count,伪造成PROCESSOR后,可以利用processor_info从伪造port中泄露任意内核地址的数据;遍历IORegistry树拿到任意IOService接口,再通过port类型转换拿到对应服务的IOUserClient,从而绕过权限检查和任意服务通信;伪造host_entry的port可以任意修改当前进程的security token,进而让NMS复活,任意free如voucher,semaphore等port的内核对象;由于semaphore对象的refcount在+72位置,通过NMS减少它的refcount时可以利用堆风水,让混淆后的IOUserIterator对象其后OSArray里的指针指向任意地址;对于MAC,伪造kuncd的port可以直接以root命令启动terminal;利用host security的port可以伪造自身为launchd进程,打开几乎绝大部分系统接口,绕过内核检查。

议题结束前,按照惯例,王铁磊演示了iPhone 11 Pro 最新系统iOS 15 beta 4的越狱,旨在鼓励研究者们面对再严苛的环境也要心存希望。

3. Binder:安卓的阿喀琉斯之踵

上午最后一个议题是由360 Alpha实验室的韩洪立、简容、王晓东和周鹏带来的。该议题中,他们分享了一套Android系统上通用的fullchain。首先简容讲解了chrome浏览器的远程代码执行漏洞。他先分析了V8引擎Runtime实现Promise API的代码,之后他构造了特殊的JS类,使其返回带有then回调的对象,从而利用这个对象同时获取到V8内部的resolve和reject的函数,让尚未完成初始化的JSArray返回,进而篡改JSArray类型,使其和NumberDictonary发生混淆。借此他在仅需破坏1bit内存数据结构的情况下修改NumberDictionary的MaxNumberKey实现越界读,泄露ArrayBuffer地址,伪造double JSArray对象,修改ArrayBuffer内部指针完成任意读写,最后利用WASM的RWX内存实现代码执行。

接下来,是该议题最精彩的沙盒逃逸至Root的部分。王晓东先介绍了Binder的通杀和其沙盒内可访问的特性,之后又解释了Binder驱动通信的代码流程,以及他们CVE-2020-0043的原理,即当client发起BINDER_THREAD_EXIT时server也同时发起BC_BUFFER_FREE消息后,两者竞争会导致UAF。

随后,韩洪立介绍了这个漏洞的两种不同难度的漏洞利用方案。第一种是从Untrusted App域提权到Root的方案,该方案充分利用了这个UAF漏洞可以转换成“Double Free”的特性,结合freelist hijack技术向swapper中写入伪造的页表来完成镜像攻击。从Chrome沙盒直接提权到Root则比第一个方案困难得多,因为沙盒中存在诸多限制。他首先介绍了如何利用padding thread、调整线程优先级和/proc/self/stat泄露CPU信息等方法提高race的成功率。接着他展示了如何利用了Double Free存在+8偏移量的特点,基于他们研究的任意地址读写漏洞利用模型,构建struct epitem -> data字段和struct seq_file -> buf字段在内存上重叠的场景,从而实现了仅触发一次漏洞就拿到了稳定的任意地址读写元语。议题最后,韩洪立在Pixel 4上演示了该套远程Root利用链。

4. Android GPU内存管理拾遗补阙

盘古实验室的安全研究员slipper带来了下午的第一个议题。他分析了最近被Google Project Zero爆料的四个GPU在野漏洞,分别是Qualcomm Adreno驱动的CVE-2021-1905、CVE-2021-1906和ARM Mali驱动的CVE-2021-28663、CVE-2021-28664。Qualcomm Adreno和ARM Mali几乎占据了手机上100%的市场份额,所以漏洞的影响范围非常广泛。而且在野漏洞的最大特点就是品相非常好,因而才会被攻击者写出稳定的利用代码。由于GPU自身的内存也是CPU来管理,两者看内存的视角不同,可能引发很多问题。这四个漏洞都是是内存管理代码里的逻辑问题导致的。

ARM Mali的代码并没有git commit,但是通过两个版本r28和r29的代码diff还是可以定位CVE-2021-28664漏洞的位置。漏洞主要成因是CPU RO的内存被映射到GPU视角时,保留了GPU RO + CPU RW的属性,再次从GPU将内存映射到CPU时可以拿到CPU RW。这使得本来只读访问的内存会变成可写,类似Dirty-Cow的效果。由于selinux和RKP/HKIP这类保护的存在,通用的利用思路其实可以不局限于root,通过劫持共享库的只读内存也能可以拿到zygote的权限,访问任意应用数据。

接下来讨论的是CVE-2021-28663,64位系统下,创建和映射GPU区域是可以分两部操作的。这样先创建但不映射,进而通过创建ALIAS标记其引用的NATIVE区域为DONT_NEED,之后再映射,可以绕过DONT_NEED标记的检查。如果再构造内存紧张的条件,就可以CPU视角释放掉该内存,同时GPU仍然保持了对该内存的读写访问,形成完全可控的UAF。

CVE-2021-1905则是一个相对有趣得多的漏洞,多进程同时调用kgsl_gpumem_vm_close会导致的kgsl_mem_entry中gpuaddr被上一次分配地址覆盖,这使得释放entry时无法正确清理页表,导致和CVE-2021-28663一样的结果,即GPU可以对CPU已经释放的内存进行读写访问。但这两个漏洞利用时都需要构造内存紧张的条件,显然这对spray的对象有进一步的要求,即调用次数和申请的内存要基本不受限制。slipper发现一个非常好的spray方法:直接选择用mmap在内核空间里spray页表,一方面这种spray可以通过控制申请的内存大小,短时间制造大量内存占用,另一方面通过UAF修改页表,也可以直接获取物理地址的读写权限,进而构造通用的root提权。Adreno的驱动中可以找到具体使用GPU读写内存的方法,所以利用这个思路可以写出来稳定的利用。Mali这方面就缺乏可参考的资料,还不清楚如何让GPU来读写内存。

5. 利用JIT编译器绕过iOS PAC保护机制

接下来的议题是北京赛博昆仑科技有限公司资深安全研究员招啟汛(@S0rryMybad)带来的。他详细介绍了去年天府杯上,是如何在具有PAC的iPhone 11上实现Safari的RCE的。他用到了一个JSC的漏洞,但和以往不同,这个漏洞并不是JIT引擎的问题,而是一个经典的回调导致的TOCTOU。

当通过for-in遍历对象内属性时,会创建一个propertyNameEnumerator对象。在快速路径中,getGenericPropertyNames会触发回调,通过在回调中修改被遍历的对象,可以实现TypeConfusion(被遍历对象变成不适合走快速路径),以及越界读(被遍历对象的当前属性数量比propertyNameEnumerator事先保存的属性数量少)。以上两种形式可以分别构造出addrof和fakeobj原语,从而实现任意地址读写。

但难点在于接下来如何从任意读写实现代码执行。iOS的PAC机制通过对返回地址、虚表、函数指针、JIT代码的保护,使得常规代码执行的路走不通。另外针对JIT,苹果的另一套APRR保护机制使得只有通过执行特殊的unlock指令才能修改JIT内存的读写执行权限。APRR和PAC互相保护,只有同时绕过两者才可能实现代码执行。

APRR修改权限是线程独立的,这里他发现JIT Compile的过程是有机会race的,也就是编译线程将代码复制进JIT,还没有进行hash校验(这部分也是使用PAC计算的)前的窗口内,主线程可以执行shellcode并且马上thread_suspend住即将hash校验失败并崩溃的编译线程。主线程执行shellcode需要一个合法的pac指针(JSEntryPtrTag),而将JIT地址的pac指针从LinkBufferPtrTag retag成JSEntryPtrTag正好是在主线程中做的。

思路清晰,但真走起来就是一步一个坑,比如循环不能太大,否则会错过时间窗口,但太小又不能触发JIT。没有调试环境,各种莫名崩溃只能靠大脑模拟猜测。JIT::link过程中一些字段导致的崩溃,只能是哪里崩溃改哪里,将一些闲杂指针赋NULL向下继续摸索。还有触发gc时可能造成的崩溃,需要禁用Scavenger等等。代码执行的机会是靠race创造,所以第一阶段的shellcode要尽可能短小精悍,仅调用unlock APRR寄存器到rw后拷贝第二阶段的shellcode,再修改APRR到rx。

最后,他演示了一下当时的iPhone 11 RCE,浏览器点开连接后,PC直接拿到相册里的照片。

6. checkm30

最后是盘古实验室的闻观行和slipper带来的议题,这个议题主要讨论的是华为海思芯片手机bootrom的漏洞。首先,闻观行介绍了手机的安全启动链,和以往谈及启动链最大的不同在于,这次分了cortex-m和cortex-a两个阶段。上电之初,烧写在m核的bootrom首先启动,加载磁盘上的xloader继续执行,xloader接下来会再启动a核的bootloader,最后加载Android系统。bootrom会在启动时判断bootmode这个gpio管脚是否接地,低电平时手机就会进入usb下载模式,接受PC发送过来的usb_xloader,xloader随后也会继续从PC以相同协议接受bl2和fastboot,进而在内存中引导整套bootloader实现手机的救砖。

接下来slipper分析了这个下载模式的通信协议和其中的漏洞。下载模式主要使用了0xFE, 0xDA, 0xED三个指令,分别完成地址设定、数据发送和通知完成。这里发现的两个漏洞,一个是传输的文件可以足够大,越界到了栈空间,直接覆盖PC实现代码执行。另一个问题是,0xFE可以指定任意地址,实现内存任意写。通过改写usb_device结构体还可以把任意写转化为任意读。无论哪个漏洞都可以在bootrom阶段取得完整的控制权。

闻观行之后选择了三个漏洞利用案例来说明checkm30的威力:bootloader解锁、EL3 Root和JTAG调试。bootloader解锁和EL3 Root的思路类似,都是逐级patch,在xloader,fastboot,bl2,kernel,trustfirmware阶段放置自己的wrapper代码。解锁需要patch fastboot的解锁标记位,而EL3 Root就要一路patch到底,这样Android主系统下可以通过su -> insmod -> smc调用预留的wrapper代码直接获取EL3层的读写执行。其实前两个案例都并不一定要bootrom漏洞才能实现,17年他讲的bootloader解锁漏洞或者19年讲的EL3代码执行漏洞也能做到相同的效果。但第三个案例就真的只有bootrom的漏洞才能做到。

在研究开启手机JTAG时,尽管最后写在纸上的答案并不复杂,但由于硬件寄存器是厂商自定义的,所以往往只能看着ARM文档盲调。结论就是,bootrom阶段要patch掉xloader里关闭secdbg的代码,其次要设置JTAG MUX寄存器,让JTAG和主芯片相连,另外还要设置的是JTAG和SD卡接口复用的寄存器。硬件上就需要自己制作一条长得和SD卡一样的FPC转接线连接手机,另一端和仿真器相连。他最后演示的是如何在手机上电后单步调试Mate 30的bootrom代码。

bootrom的漏洞(如苹果的checkm8)一般是修不了的,所以A11之前的机型仍受其影响。不过针对checkm30,华为通过OTA阻断了下载模式,修复了该漏洞。售后成本虽然高了,却保障了用户的安全。

稍作休息就是BaiJiuCon环节的六个议题。今年slipper同样通过斗鱼平台直播了全程,https://www.douyu.com/exploit

首先是盘古实验室的黄涛带来的《IM攻击面》,除了以往搞的Facetime, iMessage, WhatsApp, Wechat外,这次他又演示了一个桌面版QQ的RCE,可以直接通过视频通信的信道触发远端QQ漏洞弹出calc.exe。最后他还表示IM不仅限于聊天软件,类似暴雪,STEAM这些平台中的游戏很多都带有音频聊天功能,也有机会RCE,利用不成功至少也能把推塔时的对手都打掉线 :)

接下来是Flanker的《Hidden Droid RCE Treasures》,他首先介绍了Android Wifi Pac接口的Javascript攻击面,并演示了利用这个接口RCE反弹shell的platform_app权限。之后他又介绍了Google此后几年时间对这个接口逐步完善的过程,最后彻底废弃libpac,转而使用和系统同版本的webview。他随后演示了自己最新的研究成果,通过组合4个漏洞,实现远程劫持任意APP,点开微信和telegram都能反弹应用的shell。

之后是wangyong的《logo for fun》,他介绍了一个有趣的persistent,取得root后可以修改splash分区。由于该分区没有校验,可以持久化篡改开机启动画面。最后他在演示时提到,把女朋友照片放桌面谁都会,但能放在开机启动logo上就厉害多了。

zhouzhi带来了一个很特别的攻击方案《XSS 2 Calculation on iOS》。特殊的URL可以触发Safari支持的itmss schema,直接跳转到itune store打开指定页面。之后再通过触发apple所属域名下的xss执行可以利用itune store的特殊bridge直接启动任意app,弹出iOS下的计算器。利用效果和Safari的代码执行 + 沙盒绕过非常像,并且全程都是逻辑漏洞,很稳。

MJ0011是MOSEC的老朋友了。他一直想来MOSEC讲点什么,无奈自己研究的是Windows,但BaiJiuCon给了他这个可以自由发挥的机会。这次讲的驱动漏洞是苹果笔记本使用BootCamp启动的Windows才特有的问题。这当中的他分析了两个漏洞,CVE-2014-1523和CVE-2021-30675,并调侃自己可能是世界上仅存的BootCamp漏洞的研究人员。议题尾声他也欢迎更多人加入他按Google Project Zero标准打造的昆仑实验室。

最后一个议题是ricter zheng带来的《Taking Over vCenter in ? Secs》,他在vCenter当中一共发现了9个漏洞,写了两套完整的工具,由于漏洞很多还没有报,不方面透露细节。他演示了远程通过vCenter打到虚拟机,以及利用vmtools漏洞从虚拟机打host。

精彩议题没看够的话,记得下次来现场。

新朋友,老面孔,明年见!

声明:本文来自MOSEC,版权归作者所有。文章内容仅代表作者独立观点,不代表安全内参立场,转载目的在于传递更多信息。如有侵权,请联系 anquanneican@163.com。