Angora: Efficient Fuzzing by Principled Search
0x00 解决路径问题的五种技术
上下文敏感路径覆盖 (像AFL这种都是基于bitmap的edge计数,并不细分edge的上下文)
关于taint analysis 确定 input 和 path constraints之间的映射。
梯度下降算法 作用在 input mutate(ion)
input的结构推导 (shape => 结构, type => 结构里面字段)
input长度的探索方法
0x01 Something interesting
上下文分支敏感的分支统计
通常情况下我们的分支记录在有向图CFG上来完成,通过执行过程中对经过有向边edge进行计数,这里会丢失一些东西,理想情况下,在CFG上记录一条完整的分支,应该是edges的一个拓扑排序
文章在这里用一个例子说明问题,但是这个例子我觉得并不好,作者认为原有的edge计数并不能区别输入为10和01的区别,实际上是可以区别的:
10: L3:true;L4:false;L3:false;L10:true; 01: L3:false:L10:true;L3:true:L4:true;L5:(true|false);
两次执行走的分支情况,在01下是其实触发了新的路径,会多出一个L5分支记录,原文说两次都触发执行了L4,L10会被认为没有触发新路径。但是01的时候是触发了L5。
注意label %5这个基本块,01是会触发label %5到label %8这条边的。所以这个例子实际上在这里不合适。那在这里什么样的例子应该合适呢?应该是确保走过相同的edge的,不同上下文带来的影响。我能想到的唯一改变是下列这种情况:
1 | void f(int x){ |
加入context以后,因为L7和L8,处于不同callside,但是两者调用f,假设经过的edge一样,会导致在f,会多出一倍的edge元素,就像我前面说的,可能以前某个edge计数为2,可能现在被拆分成了两个不同的edge。在某种程度上改变了AFL中的edge计数的feature,可能变得更“敏感”一些了。但是我很难去推演它的这种”敏感“,到底能带来什么?我想要知道这种形式的”敏感“,是否可以孤身存在,而不对其他东西产生影响?这些东西于我而言,现在还是难以解释。
字节粒度的污点分析 (没有涉及taint rules)
文中没有细讲taint的过程,而是主要讲了一下taint过程中的污点表示,taint存在的意义是为了将输入和路径条件建立映射关系,在mutating阶段能更好的去解决路径条件。
定义:标签
Binary tree:(
代表一个位向量, 代表位向量的长度,长度概念应用树里面,就是指结点的高度)每一个位向量 ,都可以用这个树上的高度为 的节点 唯一表示,从根节点root到 路径上的节点依次展开为 。其中的每个结点都一个指向它父结点的指针,这样可以从 开始顺着树回溯遍历得到完整 。 Look-up table: 表里存储着
, 即保存着指向 Binary tree里面结点的指针。 画了一个图,方便理解和记忆:
注意到这个算法只在生产新结点的时候,插入
基于梯度下降的搜索算法
目标是解决路径,让路径条件满足某种要求,我们从最简单的条件出发,某个二元运算,和两个基本变量:我用
将二元运算转化成了具体函数,函数值间接表示约束的成立。通过合适的函数表示,将所有的约束成立都变成了
1 | if(a&b){} |
这样,向最优化问题的转换变成了可能。注意
使用梯度下降过程中需要计算梯度,但是前面说了这里的
现给出
其中
是一个单调函数或者凸函数。 - 局部最小值满足约束。
- 如果局部最小值不满足于约束,Angora将会随机的使用其他的
,直到局部最小值满足约束。
结构和类型推断
前面提到过
结构推断:哪些bytes总是一起被使用?
类型推断:一起被使用bytes是什么类型?
Angora里面的primitive type分为1,2,4,8bytes。它们之前可能会出现矛盾情况(e.g. 相同连续位置,被fetch一次8bytes,同时也被fetch一次4bytes),这种情况下,取最短的type。类型推断的依据使用其上下文的语义所决定的,比如某个指令操作对象是signed int,那么对应的type也是signed int。注意其整个过程都是在动态的污点分析中完成的。
输入长度探索
Angora这里特别地采取了关于输入长度的判断策略,通过关联read-like函数和read 系统调用,对read-like函数传参判定对应的输入offset(taint相关), 还会特殊标记它们的返回值,如果它们的返回值流到了路径条件上,且没有满足路径条件,Angora会尝试增加输入长度。这里我觉得这个策略并不会普遍适用于一般的程序输入,只能说一种有趣的尝试。
0x02 Self Conclusion
很有趣且朴素的一篇文章,使用的5种解决路径方法很实用,且开源(能看代码的感觉真好),但是仔细研究细节可能还是与自己想的不太一样。其中很多东西,可以尝试应用到实际情况下,我觉得就值得。“纸上得来终觉浅,绝知此事要躬行”。