议题学习:MOSEC2022 MediAttack - break the boot chain of MediaTek SoC
背景
前段时间MOSEC上盘古关于MTK BootROM Exploit的议题非常精彩,所以我画了一些时间对议题内容进行分析,并结合手边能找到的一些材料做了逆向分析,也感谢同事@C0ss4ck在会场拍下了完整的Slide :)
配合MOSEC官方的微博食用更佳 :)
议题学习
MTK Based Boot flow
在进行研究之前需要搞明白MTK方案的设备的冷启动流程,议题中提供的图简洁明了:
按照ARM的标准流程preloader应该是bl2
因为后面使用了preloader的洞把BROM dump出来了,所以我判断MTK的preloader应该是和BROM跑在同一个Exception Level的,即EL3,后来也找了一些资料确认了这个说法,但是不确定现在最新的SoC还是不是这样的。
Preloader部分
出漏洞的模块在preloader的USB Download模式,MTK自定义了一些命令,在这个模式下USB handshake之后可以发送DA,然后加载DA,随后就可以和DA通信读写分区什么的,类似高通的9008(进edl模式后加载FH),当然如果开启了SecurityBoot,公版的DA无法使用,需要对应签名的DA才可以。
根据大佬的议题内容可知,漏洞是一个整数溢出,是在判断读/写命令地址范围的时候出现的:
因为MTK的方案有很多开发板,所以基线代码基本上都很容易找到,比如使用了MT6737的香橙派-4G-IOT这个开发板(好像停产了,现存的巨贵),有个大哥把代码放github了
根据这份代码,分析这个漏洞其实很简单了
/home/muhe/Code/MT6737/linux/bootloader/preloader/platform/mt6735/src/core/download.c
1 | int usbdl_handler(struct bldr_comport *comport, u32 hshk_tmo_ms) |
支持的命令也很多:
直接定位到 static u32 usbdl_read16(bool legacy)
1 | static u32 usbdl_read16(bool legacy) |
核心逻辑还是 sec_region_check(base_addr,len8);
1 | void sec_region_check (U32 addr, U32 len) |
这里执行了两个检查:
- 判断你要操作的是不是物理外设所在的内存
- 判断你要操作的外设是不是在黑名单里,有部分外设不能操作
- 这里可能是因为方案不同,大佬PPT里的那个方案是白名单的操作,只允许操作xxx,不过不影响理解。
1 | REGION g_blacklist[] = { |
这里就要祭出datasheet里的memory map
根据memory map,利用这漏洞就可以把BROM dump出来了
BROM部分
基本分析
MTK的话BROM Exp满天飞,多搜一搜可以找到,或者按照dissecting-a-mediatek-bootrom-exploit中的办法,应该也可以,或者对于没开SecurityBoot的设备搞个mini DA进去也可以(参考这里 https://github.com/MTK-bypass/bypass_utility/blob/master/main.py#L111
)。
这里以某个SoC的BROM为例作分析,推荐使用Ghirda来做,选ARMv7就行。
1 | DECIMAL HEXADECIMAL DESCRIPTION |
前面还是喜闻乐见的中断向量表,根据reset handler,能定位到类似main的位置,但是我们的目的是分析usb dl的逻辑,这里我看了下已知的文章,可以通过handshake来确定,直接暴搜一波 A0 0A 50 05
,但是这里需要注意,有两个handshake,uart和usb的,需要做好区分,然后就可以定位到 process_cmd() 里了。
然后可以还原出来 相关标志位,如 security boot & SLA & DAA。
不过这显然不是这次的目的,这次是想找到盘古议题中提到的两个BROM的漏洞 :)
议题中的漏洞
vuln1
根据MTK的公告可知和议题内容,这个应该是那个Issue1,即 Endpoint processing vulnerability
的这枚漏洞 :)
我这里根据几个地方来确认函数位置的
- 少的可怜的两个字符串
[USBDL]
开头的,和timeout相关 - 根据
https://github.com/chaosmaster/bypass_payloads
中,我目前这个方案的一些寄存器、函数地址来确定的,比如可以确定
1 | void (*send_usb_response)(int, int, int) = (void*)******; |
- 议题中漏洞特征
最终让我找到了这个漏洞,和我最开始预想的差不多,处理USB协议相关的逻辑,不过是在标准的流程后面
[TBD]vuln2
说来也比较巧合,rrr拍的图里似乎没有标题为MTK BootROM Vul #2
的slide,所以我目前还没有分析出来,只找到了一些相关的资料辅助分析:
- https://www.usbzh.com/article/detail-842.html
-
https://yhsnlkm.github.io/2019/08/14/USB相关/应用层遍历所有接入的USB设备-1/
-
https://github.com/mtek-hack-hack/mtktest/blob/master/%20mtktest%20--username%20qq413187589/N65/N65_V1/usb/src/usbacm_drv.c
- https://shequ.stmicroelectronics.cn/thread-612750-1-1.html
比较有意思的是链接3里面的这份代码,看着很像古早时期的BROM源码 -.-
在usb相关的目录也找到了一些议题中提到的信息,比如CDC、data_ep_in_info
,以及议题截图中一些变量命名,基本上都对的上,我猜测这应该是因为这是一种标准实现,所以延用这些命名方便分析,那么找洞的方向就有了:
- 继续了解USB CDC
- 找一些标准实现看看,找一些特征+已知的USB相关的一些符号判断出来相关的处理逻辑大概在哪里
- 结合MTK的公告描述来尝试找这个漏洞(
Character-formatting command vulnerability
)
看了几个地方还不是很确定- -. 失败
攻击思路
基本概念
- SLA (Serial Link Authorization): 未授权是没办法加载DA的
- DAA (Download agent authentication): 对加载的DA做验证
当然,如果能绕过SLA,加载自定义的DA,那DAA也是可以绕过的
通过SP Flash Tool可以对设备进行读写
- Download-Agent: 一小段程序,加载到SRAM中和Host交互,类比高通的FH
- Scatter: 可以理解成flash的内存布局,描述每个分区的情况,如起始地址、大小、属性等
- Authentication File & Cert File: 开启了SecurityBoot的设备需要提供,用于验证DownloadAgent是否合法
所以,对于开了SecurityBoot的设备,就不能用公版DA了,大佬的议题中也是以开了SecurityBoot的设备为例讲的,通过前面的漏洞disable sla & daa,从而实现加载自定义的DA,然后通过这个DA来读写任意分区,从而实现加载任意代码的目的 :)
Attacking DA
大佬在议题中对MTK的DA做了详细的介绍,这里主要涉及了
- DA如何被加载
- DA的执行阶段
- stage1
- stage2
- 如何攻击DA实现任意分区读写
MTK的SP Flash Tool里带的这个公版DA其实是个DA的合集,SP FlashTool根据读到的chip id选对应的DA用来交互
DA stage1
这里提到了一个EMI file,stage1会根据这个EMI file来初始化DRAM,既然可以从preloader里后去,那么前面的基线代码里妥妥也会有了
当然也可以借助工具来解析出来,比如这个 https://github.com/mr-m96/MTKPreloaderParser
, 相关内容就不展开了,为了理解议题内容的话,只需要了解这个东西的作用以及在哪里就行了:)
DA stage2
stage2是比较关键的内容了,它被stage1加载到了dram里执行(前面初始化dram这里要用)
这里列举了secure enable的情况,DA的能力将受到限制,即一部分功能无法使用,作者通过之前的BROM exploit disable了daa,然后加载自己patch过的da,从而使用这个patch过的da来实现全分区的读写,以及使用da中全部的功能。
policy_part_map?
这部分感觉PPT顺序有点问题,不过也不是特别影响理解吧,主要是启动过程中对加载的镜像完整性校验相关的介绍,这块和后面大佬讲攻击流程能对上。
github随便搜了下,就能看明白这个东西了 :)
主要是有这么个结构体来描述对应的镜像的安全配置,是否受到保护、能不能刷这个分区等等啥的。
相关的部分代码,这是在加载镜像之前,加载这个policy,然后根据结果去对镜像做对应的操作,比如 是否应该做校验
1 | static char get_sec_policy(unsigned int policy_entry_idx) |
BROM EXPLOIT
这里的话,参考dissecting-a-mediatek-bootrom-exploit 的介绍会了解的更清楚,简化一下描述就是:
需要找到需要的函数、全局变量的地址
-
send_usb_response
-
usbdl_put_dword
-
usbdl_put_data
-
usbdl_get_data
-
uart_reg0
-
uart_reg1
-
sla_passed
-
skip_auth_1
-
skip_auth_2
-
exp工作流程参考 common exp,类似议题中的Vuln1
当然,所需要覆盖的变量也比较好找,把cmd是 0xd8
的 CMD_GET_TARGET_CONFIG
为入口就可以找到需要的东西了
common exp
直接参考 common exp,就行,利用漏洞获得的任意地址读写能力去覆盖
-
sla_passed
-
skip_auth_1
-
skip_auth_2
这三个变量,然后就可以加载任意da,并且禁用了daa
start.S
直接跳main函数,里面逻辑也很简单,覆盖变量,然后接收下个阶段的交互(usb handshake),方便后续加载DA啥的,交互完毕,就正常进入usbdl模式去了
1 | int main() { |
MTE mode
这个模式看描述是MTK的一个特殊的测试模式,也算是一个之前没见过的攻击面
在这个模式下,可以做很多事情:
- Obtain/Modify EFUSE/RPMB Info
- Load Customized OS
- USERDATA Decrypt
- Obtain/Modify Hardware Key
- Unlock Bootloader
- …
巧了,咱手里正好有个某个MTK方案的设备的完整镜像 :-) 根据PPT中的信息,可以check下相关的逻辑
我这个设备没有找到相关的逻辑,应该是删除了这个模式,不过幸运的是 meta_tst
没有删除:),而且根据PPT里的内容,这个服务应该是比较核心的,MTK设计了私有协议做一些交互
分析的难度也不大,而且有趣的是如果你在github上搜一些特定的字符串,会发现很多有意思的repo :) 这对理解一些逻辑很有帮助
more exploit
这没什么可说的,既然从源头破坏掉了信任链,那么自然可以做任何事 😎
基本上一些很成熟的“取证”工具都能干- 。- 比如这一篇
support-for-mediatek-devices-in-oxygen-forensic-detective
感兴趣的话可以阅读一下
后记
这次虽然过程艰辛又带着一些遗憾,不过个人起码了解了MTK方案BROM Exploit的思路,vuln#2还没找到,后面等不忙了时间多了再尝试看看好了 :)
参考
https://github.com/SoCXin/MT6737/tree/master/linux
https://github.com/chaosmaster/bypass_payloads
https://tinyhack.com/2021/01/31/dissecting-a-mediatek-bootrom-exploit/
https://www.cnblogs.com/wen123456/p/14034493.html
https://blog.csdn.net/u011784994/article/details/104898430
https://github.com/rn2/ven/blob/db95d7f096/hardware/meta/common/README
https://blog.oxygen-forensic.com/support-for-mediatek-devices-in-oxygen-forensic-detective/