js-fuzz-learning

js相关原理

javascript引擎重要用于浏览器中,常见的js引擎有v8、chakraCore、javascriptcore、spiderMonkey、jerryscript等,js引擎解析js代码分为语法检查和运行阶段,语法检查包括词法分析和语法分析,运行阶段包
括预解析和实际执行。js引擎使用JIL即时编译技术,即存在监视模块监控代码运行的情况,会对多次运行的某段代码进行优化,并将编译后的代码(机器码)保存在缓存中,下次调用直接执行机器码。
js引擎运行流程,如图
avatar
在js解析过程中,一但遇到错误,后面的代码就无法执行,相关错误有:语法错误(syntaxError)、范围错误(RangeError)、引用错误(ReferenceError)、类型错误(TypeError)和URI错误(URIError)。
js中常见的漏洞类型有缓冲区溢出漏洞(overflow)、释放后重用漏洞(uaf)、类型混淆漏洞和JIT漏洞

缓冲区溢出漏洞

程序一般空间布局如图
avatar
调用函数的栈空间布局如图
avatar
一般缓冲区溢出漏洞可以控制栈上的内容,从而劫持程序流到system等函数。

释放后重用漏洞

uaf漏洞,一般为内存操作操作不当导致,即内存被释放后,可以继续修改内存内容,此时巧妙构造内存的内容,即可通过该内存进行对
应的攻击,例子

1
2
3
4
5
6
7
8
9
10
#include <stdlib.h>
#include <stdio.h>

int main() {
int *ptr_a = malloc(0x80);
read(0,ptr_a,0x80);
free(ptr_a);
read(0,ptr_a,0x80);
//这个例子中 ptr_a 应该置0
}

类型混淆漏洞

类型混淆指数据类型A当作数据类型B解析使用,导致程序可以非法访问数据,在浏览器中有一个非常典型的例子,如下

1
2
var a = [1.1,2.2,3.3];
var b = [a];

如果类型b解释为a类型,此时就能泄露a的相关内容,进而可以任意地址读写

JIT类型漏洞

JIT类型漏洞的产生原因,一般是由于对代码进行错误的优化,例子
avatar

jsfuzz中涉及到的相关技术

污点分析

污点分析是一种跟踪污点信息在程序传递的技术,本质上是一个跟踪输入数据流向的过程,通过把不可信任的数据标记为污点数据,并跟踪污点数据,对程序漏洞进行监测。
一个简单的例子,如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void ()
{
string X = source();
string Y = new String();
for(int i = 0;i < X.length();i++)
{
int x = (int)X.charAt(i)p;
int y = 0;
for(int j = 0; j<x; j++)
y = y + 1;
Y = Y + (char)y;
}
sink(Y);
}

字符串X和字符串Y之间没有显示流关系,但字符串X的污点标记通过控制以来可以隐式的传播到字符串Y。

符号执行

符号执行是一种使用符号值来代替具体值执行程序的技术,将一些变量值用符号表示,分析程序可能的执行过程,将变量取值表示为符号和常量的计算表达式
例子如下
avatar
最后给出3个输入就能遍历这三条路径,符号执行的目标就是生成输入集合,探索程序的路径

模糊测试

模糊测试的思路:通过向目标提供特殊构造的非预期的输入,监视程序运行中的异常,并且保存异常的测试用力,通过人工分析导致异常的测试用力进一步定位程序中漏洞的位置和形成原因。
一般流程如图
avatar

变异

AFL变异原理

AFL的变异策略: bitflip位翻转、arithmetic简单算术、interest特殊整数、dictionary字典、havoc大破坏和splice拼接6种
如图
avatar
上面的变异策略对与非结构化输入(png、avi等)有比较好的效果,但是对于结构化输入(javascript和xml)这类程序,难以产生有效的测试案例(无法通过语法检查等)

AFL基本块

AFL中使用基本块计算覆盖率信息。基本块是一段线性代码语句,只有一个入口和一个出口,且基本块中的语句只会顺序执行一次。因此AFL根据基本块,获取基本块中所有的入口和出口语句,获取程序中所有的基本块。判断基本块的入口和出口语句方法
基本块入口语句:

  1. 程序的第一条语句
  2. 跳转语句的目标语句
  3. 条件条状的下一条语句
    基本块出口语句:
  4. 停机语句
  5. 跳转语句
  6. 跳转目标语句的前一个语句
    获取程序基本图后,在基本块集合中加入控制信息形成程序的有向图,该有向图就是程序的控制流图,如图
    avatar

覆盖率反馈方法

AFL中通过gcc或者clang插桩实现覆盖率反馈。在插桩阶段,对目标程序变异时,在每个基本块插入一段代码,用以记录当前基本块和上一个基本块的信息,主要代码如下

1
2
3
cur_location = <COMPILE_TIME_RANDOM>;
shared_mem[cur_location^prev_location]++;
prev_location = cur_location >> 1;

cur_location的值随机产生,用于标记当前基本块;shared_mem数组记录上一个基本块和当前基本块这条边的命中次数,如果命中次数的分类发生改变,则认为产生新路径;pre_location表示上一个基本块的标记值,右移一位是为了区分基本块的执行顺序,假设存在基本块A和B,若pre_location不右移,则A^B和结果和B^A的结果一致,但实际上A->B和B->A由于执行顺序不同,是两条不同的边。
插桩完成之后AFL的工作流程:

  1. 从输入队列(包括初始种子和产生新路径的测试用例)中挑选一个种子;
  2. 对种子进行变异生成新的测试用例;
  3. 执行新的测试用例,并监控目标程序执行状态;
  4. 根据目标程序执行结果根性输入队列,然后跳转步骤1
    流程图,如图
    avatar