IoT设备调试实战-基于UART串口命令构造调试功能
如果无法正常显示,请先停止浏览器的去广告插件。
1. CLICK TO EDIT MASTER TITLE STYLE
2. IoT设备调试实战
基于UART串口命令构造调试功能
朱文哲
平安科技银河实验室高级安全研究员
3. 传统Linux IoT设备调试的方法
通常来说传统Linux IoT设备的调试方
法主要有两种:
1. 一种是拿到设备的Shell权限后通过
上传静态编译的gdbserver程序进
行远程调试。
2. 另一种是利用QEMU或Qiling框架
通过模拟执行技术模拟运行设备固
件从而进行调试。
4. 非Linux IoT设备调试的困境
但上面讲到的这些方法对于非Linux系统则不再适用,例如基于VxWorks或eCos等实时操作系统的IoT
设备进行调试通常需要在固件编译时就启用调试功能。
然而目前市面上的非Linux IoT设备大多默认取消了这些调试功能,这对于我们安全研究人员进行设备
安全分析产生很大的阻力。
本次分享主要针对这一现象提出了一种解决思路,下面将通过两个实际案例讲解如何利用设备UART串
口的内存操作等内置命令,间接实现对设备的调试及分析能力。
5. 第一部分
利用UART串口命令
辅助分析eCos设备漏洞
6. eCos系统简介
eCos(embedded configurable operating system)是一个免费开源的嵌入式可配置实时操作系统,
主要应用于消费电子、电信、车载设备及其他一些低成本的便携式设备中。和传统Linux系统不同,
eCos系统采用静态链接的方式进行编译,因此通常情况下编译好的eCos固件都是独立的一个二进制
文件。
7. 获取UART串口命令行
案例中的设备是某厂商的行车记录仪,通过拆卸设备后可以在主板右下角找到标识好的UART串口焊点。
8. 获取UART串口命令行
完成焊接后即可使用串口工具连接计算机获取串口命令行,在命令行中我们可以清晰的看到eCos系统相关
的命令。
9. 固件分析
通过分析手机APP进行固件更新时的流量获取到固件文件,在拿到固件后,可以使用binwalk进行分析
同样可以发现一些eCos系统固件的特征字符串。
10. 固件分析
结合UART串口获取到的引导日志可以得知,这款设备是基于NOVATEK SDK所开发的固件。
11. 固件分析
通过使用nfc4ntk工具可以对NOVATEK SDK打包的固件进行解包。
12. 固件分析
如左图所示在解包后的固件头部找到了0x80000400地址的值, 再结合右图NT96660处理器的内存分布
图,可以初步得知0x80000400很可能就是固件的entrypoint内存地址。
13. 固件分析
这里我们就可以选用Ghidra将该固件加载到0x80000000地址并在0x80000400处进行分析。
14. 固件分析
成功完成初始化分析后,我们可以发现string的引用都是正确的,这也证明解包后的固件加载地址的确
是0x80000000, 不过很遗憾在固件中并没有找到符号表,只能通过其他手段分析。
15. 固件分析
函数名缺失的问题可以采用静态分析函数报错信息的方法进行修复:
1. 找到所有具备函数报错特征的字符串,获取这些字符串的引用地址。
2. 根据引用地址,定位所有调用了这些特征字符串的函数(主要是减少需要反编译的函数数量)。
3. 利用Ghidra的API反编译所有这些函数,利用P-code的功能去解析所有调用FUN_80015f48函
数的参数,当参数1满足错误输出的字符串特征时,参数2的值就是当前函数的函数名了。
16. 固件分析
具体的脚本这里不做讲解了,主要是基于我们已开源的trace_function_call_parm_value 这个Ghidra
脚本进行修改,修复脚本执行的效果如下:
利用脚本我们一共修复了2462个函数,此时我们就可以通过关键字来分析固件中的一些功能了。
17. 利用UART功能辅助分析漏洞
在对设备通讯协议进行Fuzzing测试时,我们发现了一个可以影响PC寄存器的漏洞。
设备崩溃时的报错信息还会将寄存器的状态等信息进行输出,而这个功能也就可以被我们进行利用从
而帮助我们进行漏洞定位及分析。
18. 利用UART功能辅助分析漏洞
除了利用报错信息外,我们还可以通过在关键的位置写入调用内存dump函数的shellcode来查看我们
所关心的内存地址的内存信息。
19. 利用UART功能辅助分析漏洞
通过内存写入功能我们可以利用报错信息查看寄存器或调用内存dump的功能进行内存查看。
有了这两个基础的功能,我们就可以一步一步的对漏洞进行分析,最终成功的定位分析到了一个远程
RCE漏洞。
20. 第二部分
利用UART串口命令
辅助调试VxWorks系统
21. VxWorks系统简介
VxWorks系统是WindRiver公司最早于1987年发布的嵌入式实时操作系统,该系统被广泛应用于航天、
航空、工业控制、电信、军工等各个领域。
22. 获取UART串口命令行
案例中的设备是某厂商的家用路由器使用的是VxWorks 5系统,通过拆卸设备后可以在主板上找到UART
串口焊点。
23. 固件分析
VxWorks固件分析的部分这里就不多做介绍了,案例中的设备固件包含了独立的符号表文件,可以利用
我们开源的VxHunter工具结合IDA、Ghidra或Radare2直接加载分析。
24. 常规VxWorks调试方法
通常情况下若需要对VxWorks系统进行调试则必须要在VxWorks固件编译时编入WDB调试服务并使
用Tornado或Wind River Workbench这类专用软件进行调试,而通过分析我们的固件中并未编入
WDB调试服务。
25. 编写调试功能的前置条件
编写调试功能的前置条件:
1. 能够直接对VxWorks的内核态内存进行直接读写(我们的目标基于VxWorks 5操作系统,而
VxWorks 5系列只有内核态)。
2. 能够获取到task的寄存器值, 这个步骤主要用于判断哪个task触发了断点 (VxWorks的task有点像
其他系统中的线程,在VxWorks 5中他们之间共享内存)。
26. 编写调试功能的前置条件
第一个必要条件很容易满足,完整功能的cmd命令行自带内存修改功能且简单好用。
27. 编写调试功能的前置条件
第二个必要条件略微复杂一些,当前设备的task命令无法直接显示所有task的PC寄存器。
28. 编写调试功能的前置条件
需要通过task –c命令来循环获取单个task的寄存器等信息后进行处理。
29. 串口调试功能设计
串口调试功能设计,主要就是以下几部分:
1. 利用命令行的内存读写功能,将调试用的shellcode写入到设备内存中。
2. 利用类似Inline Hook的 技 术 在需 要 调 试 的 代 码处 进行 插桩, 跳 转执行Ho o k 代码 ( 调试
shellcode),调试shellcode会无限循环,等待下一步的调试指令执行。
3. 此时就可以通过命令行的指令查看调试task的寄存器及内存等信息。
4. 完成调试指令后,还原插桩处的代码,更新CPU缓存,跳转恢复执行。
30. 串口调试功能设计
31. 串口调试功能设计
32. 设计调试shellcode
用于调试的shellcode主要分为以初始化debug栈、debug loop、Recover三个部分。
其中初始化debug栈主要用于申请及初始化debug调试shellcode会使用到的栈内存。
33. 设计调试shellcode
插装处的代码如图所示:
34. 设计调试shellcode
初始化代码全部由汇编编写,具体代码如下:
35. 设计调试shellcode
Debug loop 第一部分代码如下:
36. 设计调试shellcode
Debug loop 剩余代码如下:
37. 设计调试shellcode
Recover代码如下:
38. 设计调试shellcode
实际调试时的效果如下图所示,我们可以利用编写的调试功能更便捷的对设备进行分析。
39.