### SaTC自动化漏洞分析和实例测试
自动化漏洞挖掘
自动化漏洞挖掘分为动态测试和静态测试
动态测试
iot设备Fuzz,简单来说就是针对物联网设备进行模糊测试。它利用自动化工具,向设备发送大量随机或变异的数据,以发现潜在的安全漏洞。
AFL++
American Fuzzy Lop plus plus (afl++)
是一个由社区驱动的开源工具,它结合了最新的模糊研究,使研究具有可比性,可重复性,可组合性。它提供了多种新功能,例如,Custom Mutator API
(传统的突变API)能够增加模糊测试处理策略,特定目标的变异也可以由经验丰富的安全测试人员编写。具体细节可以参阅AFL++ : Combining Incremental Steps of Fuzzing Research。
https://github.com/AFLplusplus/AFLplusplus
Boofuzz
Boofuzz是一个基于生成(generation-based)的协议Fuzz工具,它通过python语言来描述协议的格式,是经典模糊测试框架Sulley的继承者,除了众多的bug修复之外,boofuzz还致力于扩展性。Boofuzz对协议的模糊测试有着良好的支持,且其代码开源,目前被广泛使用。物联网设备中设计到了大量的协议,常见的如tcp,udp,mqtt,upnp等等,还有一些各个厂商自己设计的协议等等,而boofuzz则是一款对于协议模糊测试效果非常出众的模糊测试框架。
https://github.com/jtpereyda/boofuzz
现有fuzz工具的不足
路由器通常为终端用户提供基于web的界面来配置系统。底层固件包含web服务器、各种前端文件和后端二进制程序。web服务器接受来自前端的HTTP请求,并调用后端二进制文件来处理它们。在这种情况下,攻击者可能会在前端构建恶意输入,以破坏相应的后端二进制文件。
现有的方法无法有效分析嵌入式系统中的服务以检测漏洞。动态方法如模糊测试和仿真,只能到达程序所有可能状态的一小部分,导致很高的误报率。静态方法如KARONTE依赖前后端之间的通用进程间通信(IPC)来定位处理输入数据的代码,并执行集中测试,但这些方法可能会导致许多误报。从嵌入式系统发现bug的关键点是使用web前端用户提供的数据来定位后端处理该数据的代码。
尽管传统fuzz在通用平台上能对程序进行有效的测试,但因为fuzz对硬件配置有较高的要求,所以AFL对iot设备fuzz的适配性有限,比如:提取一个固件并找到一个应用程序,然后使用AFL对此程序进行fuzz,AFL难以模拟物联网设备的复杂交互场景,例如设备发现、连接、数据传输等,正常情况下fuzz会失败。他主要针对二进制文件进行模糊测试,对网络协议的支持也有限。
污点分析
静态测试中的污点分析由三部分组成:污点源(source)、污点汇集点(sink)和数据流处理(processor)
- source 即污点源,代表直接引入不受信任的数据或者机密数据到系统中
- sink 即污点汇聚点,代表直接产生安全敏感操作(违反数据完整性)或者泄露隐私数据到外界(违反数据保密性)
- processor 即数据流处理,代表整个数据传输和处理的过程(例如加密、编码处理),外部输入的数据经过processor处理后会得到一个适合软件核心模块处理的数据形式.
SaTC简介
SaTC代码:https://github.com/NSSL-SJTU/SaTC/tree/py2_env
数据集 https://drive.google.com/file/d/1rOhjBlmv3jYmkKhTBJcqJ-G56HoHBpVX/view?usp=sharing
论文 https://www.usenix.org/system/files/sec21fall-chen-libo.pdf
SaTC(Sharing More and Checking Less)是一个创新的开源工具,专为检测嵌入式系统的漏洞设计。其核心理念是利用共同的输入关键词,以更高效的方式识别潜在的漏洞,如命令注入和缓冲区溢出问题。SaTC提供了强大的自动化分析功能,大大简化了固件的安全审计工作。
他基于Ghidra逆向工程框架,通过定制的Ghidra脚本,如ref2sink_cmdi和ref2sink_bof,自动追踪可能的风险路径。这些脚本能够挖掘命令注入和缓冲区溢出类漏洞的源码路径。此外,ref2share和share2sink脚本组合使用,可以探测到共享输入数据导致的问题。工具还集成了污点分析,增强了对潜在风险的识别能力。
工作流程图
通过跟踪前端和后端之间用户输入的数据流,以精确检测安全漏洞。处理用户输入的后端函数通常与相应的前端文件共享一个关键字:在前端,用户输入被标记为关键字并编码在数据包中;在后端,使用相同或相似的关键字从数据包中提取用户输入。因此,可以使用共享关键字来标识前端和后端之间的连接,并在后端找到用户输入的入口。
SaTC实例测试
安装
SaTC安装参见**Github**
也可以直接docker镜像拉取
# 拉取docker镜像
docker pull smile0304/satc
# 进入docker环境
docker run -it smile0304/satc:V1.0
# 安装pip requirement
pip install -r requirement.txt
这里以tenda ac15为例,测试/bin/httpd是否存在命令注入漏洞
固件版本:US_AC15V1.0BR_V15.03.05.19_multi_TD01
将解包后的squashfs-root目录docker cp复制到docker中的SaTC目录(也可以用-v作目录映射)
iot@research:~/gujian/tenda/_US_AC15V1.0BR_V15.03.05.19_multi_TD01.bin.extracted/squashfs-root$ docker cp ./squashfs-root/ 9d85e744e75e:/home/satc/SaTC/tendaac15
测试httpd中是否存在命令注入漏洞
python satc.py -d /home/satc/SaTC/tendaac15/squashfs-root/ -o /home/satc/SaTC/res_ac15 --ghidra_script=ref2sink_cmdi -b httpd --taint_check
这里指定了只寻找httpd的命令执行漏洞
optional arguments:
-h, --help 查看帮助
-d /root/path/_ac18.extracted, --directory /root/path/_ac18.extracted
指定从固件中提取出的文件系统
-o /root/output, --output /root/output
指定结果输出位置
--ghidra_script {ref2sink_cmdi,ref2sink_bof,share2sink,ref2share,all}
(可选) 指定要使用的 Ghidra 脚本。 如果使用`all`命令,`ref2sink_cmdi`、`ref2sink_bof`和`ref2share`三个脚本将同时运行
--ref2share_result /root/path/ref2share_result (可选) 运行`share2sink` Ghidra脚本时,需要使用该参数指定`ref2share`脚本的输出结果
--save_ghidra_project (可选) 是否保存程序运行时产生的ghidra工程路径
--taint_check (可选) 指定是否启用污点分析
-b /var/ac18/bin/httpd, --bin /var/ac18/bin/httpd
(可选) 用于指定需要分析的程序,如果不指定,SaTC将使用内置算法确认需要分析的程序
-l 3, --len 3 (可选) 根据分析结果分析可能为边界的前N个程序,默认为3
Ghidra Script介绍
ref2sink_cmdi : 该脚本从给定的字符串的引用中找到命令注入类型sink函数的路径。
ref2sink_bof : 改脚本从给定的字符串的引用中找到缓冲区溢出类型sink函数的路径。
ref2share: 此脚本用来查找输入等字符串中被写入共享函数等参数,例如:nvram_set, setenv等函数。需要与share2sink来配合使用
share2sink: 此脚本与ref2share功能类似。需要与ref2share来配合使用;使用此脚本的输入为ref2share脚本的输出
开始了从Ghidra decompiler到keyword finding的过程,找到共享的关键字,基于这个关键字开展污点分析,然后再进行一步步的筛选。这里需要一定时间才能跑完。
result目录结构如下
|-- ghidra_extract_result # ghidra寻找函数调用路径的分析结果, 启用`--ghidra_script`选项会输出该目录
| |-- httpd # 每个被分析的bin都会生成一个同名文件夹
| |-- httpd # 被分析的bin
| |-- httpd_ref2sink_bof.result # 定位bof类型的sink函数路径
| |-- httpd_ref2sink_cmdi.result # 定位cmdi类型的sink函数路径
|-- keyword_extract_result # 关键字提取结果
| |-- detail # 前端关键字提取结果(详细分析结果)
| | |-- API_detail.result # 提取的API详细结果
| | |-- API_remove_detail.result # 被过滤掉的API信息
| | |-- api_split.result # 模糊匹配的API结果
| | |-- Clustering_result_v2.result # 详细分析结果(不关心其他过程关心此文件即可)
| | |-- File_detail.result # 记录了从单独文件中提取的关键字
| | |-- from_bin_add_para.result # 在二进制匹配过程中新增的关键字
| | |-- from_bin_add_para.result_v2 # 同上,V2版本
| | |-- Not_Analysise_JS_File.result # 未被分析的JS文件
| | |-- Prar_detail.result # 提取的Prar详细结果
| | |-- Prar_remove_detail.result # 被过滤掉的Prar结果
| |-- info.txt # 记录前端关键字提取时间等信息
| |-- simple # 前端关键字提取结果, 比较简单
| |-- API_simple.result # 在全部二进制中出现的全部API名称
| |-- Prar_simple.result # 在全部二进制中出现等的全部Prar
|-- result-httpd-ref2sink_cmdi-ctW8.txt # 污点分析结果,启用`--taint-check` 和 `--ghidra_script`选项才会生成该文件
最终污点分析结果存储在了result-httpd-ref2sink_cmdi-6MIi.txt
中
binary: /home/satc/SaTC/tendaac15/squashfs-root/bin/httpd
configfile: /home/satc/SaTC/res_ac15/ghidra_extract_result/httpd/httpd_ref2sink_cmdi.result-alter2
0xef168 0xa1808 not found
0xf1f24 0xa5560 not found
0xefa70 0xa1d20 not found
```
0xf2208 0xa6890 found : 0xa68f8
```
0xefb24 0xa2994 not found
total cases: 85
find cases: 1
从结果中看到,httpd的0xa68f8位置疑似存在命令执行,并且该位置的命令执行在sink函数路径文件中也有体现污点传播过程。
ghidra_extract_result/httpd/httpd_ref2sink_cmdi.result:[Param "deviceName"(0x000f2208), Referenced at formsetUsbUnload : 0x000a68c4] >> 0x000a68f4 -> doSystemCmd
IDA打开httpd,jump到0xa68f8
v3获取了deviceName的值,并传递给doSystemCmd,显然这里的doSystemCmd是能够命令注入的。
formsetUsbUnload这个函数很眼熟,deviceName为用户可控的注入点,查了一下cve编号为cve-2020-10987
根据上海交通大学的论文给出的原理,deviceName(results中0xf2208位置对应其data段)映射为前端用户可控的关键字,先获取了前端可控key-value,后端以相同或相似的关键字从二进制或cgi中进行了提取。
share的关键字连接了前端后端,在污点传播的过程中选择数据流,跟踪不受信任的输入并识别危险函数,最终发现了该漏洞。
查找前端对应点:由于在污点传播过程中deviceName是前后端的 shared key-Value
在文件结构web目录中查找deviceName即可找到对应的前端页面然后进行手工验证
$ grep -ir "devicename"|awk -F ":" '{print($1)}'|grep -E 'html|js'|sort|uniq
......
status_usb.html
status_usb.js
至此 SaTC就为我们找到了命令注入点,大大提高了iot漏洞的挖掘效率
手工确认实例-cve-2020-10987
固件下载 https://www.tenda.com.cn/download/detail-2680.html
固件模拟
这里使用了qemu-system模拟,模拟的详情可见IOTsec-Zone文章 qemu固件模拟、网卡分析---我与br0的爱恨情仇 - IOTsec-Zone
进入qemu虚拟机后启动httpd
进入status_usb.html页面,这里由于js文件的设置,无法显示Unmount button
在浏览器的Network中禁用了http://192.168.0.3/goform/GetUsbCfg*后可以显示出来。
查看该页面的js文件,正常这里就是一个usb插拔的操作,SaTC应该就是在这里帮助我们枚举到了deviceName
点击Unmount按钮抓包
看到了前后端共享的key-Value值deviceName=xxx,那么这里就是我们的命令注入点
POC