论文简介
Snipuzz: Black-box Fuzzing of IoT Firmware via Message Snippet Inference. In Proceedings of CCS 2021.
其实这篇文章最核心也是最创新的工作就在于,对协议的响应信息进行了相似度计算,然后根据这个计算的结果来完成两个目标:
- 协议格式解析
- 反馈指导
ok,直接开读,一些正文里没有的或者我的主观想法会写到“引用格式”(>
)里
Introduction
- 物联网(IoT)设备现在越来越多,但同时又有各种安全问题,所以我们要早在攻击者之前就发现里面的漏洞
- 很多方法都依赖固件的获取,但现在很多厂商都不公开固件了,所以可以用模糊测试来发送数据包并检测是否异常
- 现有黑盒模糊测试方法有很多问题,以此引出了三大挑战
- 缺少反馈机制
- 消息格式有很多,需要能自动推断
- 响应中往往包含很多“随机”信息
- 作者简述了他们的解决方案
- 使用响应作为反馈
- 根据响应初步推断消息中每个字节的角色
- 利用编辑距离和凝聚分层聚类来忽略随机信息
Background
这章介绍了Fuzz和IoT的通信架构(没有细看,大概是说,第一层是过滤,然后一个switch,之后执行,最后响应)
Motivation
也没有细看,大概是说这几个方法的灵感来源是什么,两个小节的末尾各自讲了下设计的大致思路
第一个是使用响应来指导模糊测试,第二个是每次删掉一个字节,每次收集响应并比较,将相同反馈且连续的字节视作一个语法部分
这章主要是通过一些背景或者现象来引出来这几个技术,看网上说安全的会议还是挺吃这套东西的,看重讲故事和创新,而不是用的技术有多么高级,这篇文章的思路确实很巧妙,没有用一些特别大的新的方法却很好地解决了一个实际问题,而且用响应来指导模糊测试确实给未来的工作带来了很大启发
Method
这就是正式开始讲细节了,主要是两个技术 (1) Message Sequence Acquisition (2) Snippet Determination
整体框架上的话,初始种子中包含了很多个请求,每个请求都会收到响应,所以为每个请求划分一个响应池。接下来就是每个请求分开处理了,会对每个请求都进行语法片段的划分
Message Sequence Acquisition
- 初始种子获取:一串消息,能够触发目标IoT设备的某个行为
- 恢复消息:每次测试后,发送恢复消息让设备回到初始状态
Snippet Determination
4.2.1 语法片段划分
第一个阶段就是语法划分,Snipuzz的思路很简单,删除其中某个字节,看看响应是什么,再删除后面一个字节,看看响应是否一样,一样的话就认为这两个字节属于同一个语法片段。文章里的例子很直观,直接看例子吧。
Messages | Content | Responses | Content | Category |
---|---|---|---|---|
Message $m$ | {"on":true} |
$r_0$ | {"success":"..."} |
0 |
$p_1$ | "on":true} |
$r_1$ | {"error":"type":2,"description":"invalid json"} |
1 |
$p_2$ | {on":true} |
$r_2$ | {"error":"type":2,"description":"invalid json"} |
1 |
$p_3$ | {"n":true} |
$r_3$ | {"error":"type":6,"description":"n, not avaliable"} |
2 |
$p_4$ | {"o":true} |
$r_4$ | {"error":"type":6,"description":"o, not avaliable"} |
3 |
$p_5$ | {"on:true} |
$r_5$ | {"error":"type":2,"description":"invalid json"} |
1 |
$p_{11}$ | {"on":true |
$r_{11}$ | {"error":"type":2,"description":"invalid json"} |
1 |
$p_i$ 是 Probe message 的缩写
那么这个例子最后划分的结果就是:
{"on":true}
: {"
| o
| n
| ":true}
但看到这里不能忘了Introduction里还有一个挑战,那就是响应中是可能包含一些“随机”信息的,比方说时间戳,token这些
所以作者给出的方法是,使用编辑距离来计算两个响应时间的相似度,具体计算公式如下:
$$s_{kt}=1-\dfrac{edit_distance(r_k,r_t)}{max_len(r_k,r_t)}$$
编辑距离是什么就不细讲了,是个比较经典的字符串比较算法
那么这样就还有一个问题,相似度达到了多少才算是一样的响应呢?人为设定一个阈值吗?
作者又给出了一个解决方案,我们不妨把$p_i$发送两次,这样就能接收到两个$r_i$,那么就可以算一个自相似度$s_{ii}$了。这样就可以用这个自相似度$s_{ii}$作为这个阈值,对于另外一个$p_j$的响应$r_j$,就可以计算$s_{ij}$和$s_{jj}$,如果$s_{ij}<=min(s_{ii}, s{jj})$那么就可以认为两个响应是不一样的
4.2.2 分层聚类
考虑到划分结果还是会有问题,例如上面的例子里把o
和n
识别为了两个不同的语法片段,作者又想到了进一步的解决方案,也就是分层聚类
具体方法是对每个响应构建一个向量:(自相似度,响应长度,字母段数,数字段数量,符号段数)
接下来根据向量的距离,不断对两个最相似的片段进行聚类
这个结果将会用到后面的过程,也就是用于变异了
其实一直不太明白这一步为什么要这么做,比如这个五元组是怎么构造出来的,为什么就要选择这5个参数,为什么算向量距离
Mutation Schemes
每个变异方法都是对某个语法片段做变异
- Empty: 把某个片段删掉
- Byte Flip: 反转片段中的所有字节
- Data Boundary: 把数值数据修改为边界值(65536)
- Dictionary: 将某个片段替换为true或false等预定义字符串
- Repeat: 多次重复某个片段
雪崩:选择多个片段来进行变异,直到出现新的响应类别或者崩溃之前,都不会停止雪崩变异
Experimental Evaluation
选择了20个IoT设备,和7个方法对比
- IoTFuzzer
- Nemesys
- Boofuzz
- Boofuzz-Default
- Boofuzz-Byte:每个字节单独变异
- Boofuzz-Reversal:专注于非数据部分的变异
- Doona
- Snipuzz-NoSnippet:和没有分段的自己做消融实验
文章里说Peach是灰盒的,但我印象中应该是黑盒,不过对比的方法很多了,不缺这一个
直接看发现的漏洞吧
成功在5个设备中找到了13个漏洞,遗憾的是只在json格式的协议中发现了漏洞
另外作者还计算了语法片段推理的效果,Snipuzz准确率达到了87.1%,而Nemesys只有64.5%
不过可惜作者没有按照JSON,SOAP,K-V pair等不同格式来计算准确率,挺好奇会不会有区别
Discussion
讨论也不是很重要,大概看看吧
可扩展性:已知有效的网络数据包,Snipuzz就可以测试IoT设备。作者给了三种方法:
- 运行API程序和抓包,或者直接静态分析API程序
- 反编译和污点分析3
- 在APP和IoT设备之间抓包
手动操作:需要收集初始种子
可能的限制:
- 缺少 API 程序,在这种情况下,可以使用类似于IoTFuzzer的方法(利用IoT设备的配套APP),但可能需要更多的手动工作
- 加密,方法是把解密模块集成到Snipuzz中
- 测试的范围会受到API功能的限制,比如API只有开灯,那调亮度部分的代码就测不到了,作者说未来可以通过重新组合来自不同种子的消息片段来生成新的有效输入
第三点限制里,作者说的是Coverage会受到限制,这么写一开始让我有点迷惑,毕竟这个工作和Coverage按理说没啥关系,可能换成别的词会更好懂一些吧,不过也可能是我英语太菜了
个人思考
我感觉这个文章的思路是很新的,21年之前应该几乎没什么文章使用响应来做为反馈信息指导模糊测试,上一个有印象的应该是AFLNet?那篇文章用代码覆盖和状态两个指标共同反馈。不过这篇文章的另一个优势就是又通过反馈来对协议做了一个简单的语法分析。事实上,从这个思路往后展开也能进一步扩展到协议逆向这个方向上,不过可惜刚有这想法没多久就有人这么做了(DynPRE)。
当然,这个方法的有效性还是有待商榷的,至少用开源的python版本代码体验比较一般。之前试了一个比较长的协议,会耗费很长时间在初始的语法片段分析上,不知道是不是打开的方式不对(不过作者自己也只在JSON里找到了漏洞)。而且对于具有关联信息的协议也不好用,比如对方做了个时间戳的校验,或者分配了一个uuid之类的,也就是场景还有一个隐藏的约束,那就是协议得能够重放,不过好在IoT设备应该都还是可以这么做的。