主要参考了土爷的博客文章以及一些搜到的其他文章进行的学习
https://lorexxar.cn/2020/09/21/whiteboxaudit

https://cloud.tencent.com/developer/article/2235686

https://tttang.com/archive/1375/

https://www.freebuf.com/sectool/290671.html

为什么要研究AST工具

从挖洞角度来说,人工审计一来在熟练之后逐渐趋向于重复劳动的形式,难以再提升平均效率,二来对于一些复杂的调用情形,人工有时候难以发现,因此就会有需求来进行自动化的代码审计工具,来对项目做安全性的检查,由此就衍生出了AST的这些安全技术和产品。

如何定义工具的效率

在讨论工具的各种实现方案之前,我们就需要对工具的效率做出定义,从挖洞角度来看主要是误报率漏报率运行效率这些方面去进行评价,当然背后的还有开发维护成本、使用成本等等因素。

AST是什么

先说ASTASTApplication Security Testing,应用程序安全检测,是一个比较笼统的概念,指用来对应用做安全检测的这么一项技术。

AST现在又分为SAST(Static Application Security Testing)DAST(Dynamic Application Security Testing)、IAST(Interactive Application Security Testing),分别指静态、动态、交互式应用程序安全测试。

SAST

基于正则

SAST是静态应用程序交互测试,顾名思义,静态指不会实际执行代码发送请求,而是通过“推理”的方式来判断是不是有危险函数以及调用到的可能。这种形式误报率比较高。

SAST是白盒形式的,根据写好的规则进行正则/AST的匹配,来发现漏洞。

假如从最简单的情形进行思考,如果我们要用代码去检测一段代码是不是存在漏洞,比如说有eval($_GET['a'])这样的情形,那么我们可以利用正则去进行匹配,匹配eval函数的参数中是否有$_GET或者$_POST

那么如果是如下的代码片段呢

1
2
$a = $_GET['a'];
eval($a);

这里的话刚刚的检测手段就检测不到了,如果还是依照先前的方案,误报率低但是漏报率就变高了。

那也许我们可以通过只匹配eval这样的危险函数的方式,但是这样就会存在误报率高的问题,并没有办法检测到eval的参数是否可控,只能用人工进行后续的跟进。正则匹配的方案最多算是半自动化,具体正则规则的编写决定了误报率和漏报率的问题,但是很难以这样的方式做到准确、高效、覆盖率全。

基于AST

正则匹配关键字的策略即便是人工写的再好再复杂,面对本质相同但是形式不同的代码,还是难以匹配,所以基于AST的检测可以从编译后的结果来看,就可以做到不受代码编写形式的限制。

在词法分析和语法分析之后,代码就变成了抽象语法树(AST),接下来就是考虑如何分析AST

这里我们需要明确三个概念,sinksourceinformation flow

information flow表示数据从source流动到sink的过程,以上面的代码为例子,$_GET['a']就是source,也就是用户可控的输入,eval这样的危险函数就是sink,而从用户输入参数到参数被传递至危险函数内,就是information flow

那么如何进行information flow的分析呢?

核心问题是对于作用域的变动,从主AST语法树到函数的作用域,这里要递归的去分析作用域,那么如何在这个递归的调用中制定规则是比较困难的。

土爷的文章中提到了两点比较困难的情形,第一是函数封装。

对于代码

1
2
3
4
5
6
$a = $_GET['a']

function ee($p){
eval($p);
}
ee($a)

这里危险函数eval被封装成了新函数ee进行调用,需要进行作用域上的处理。

这里就需要逆向的进行分析,从eval为危险函数,进而分析函数参数会直接传递进危险函数,从而判断ee函数为危险函数。

第二是多重调用链。

假如c函数是危险函数,a函数中调用了b,b中调用了c,在存在复杂数据流向时的处理问题,以及如果在多重调用中,存在过滤函数的情形如何去处理,都是比较复杂的点。

基于IR/CFG

IR/CFG在编译过程中比AST更底层,相比于基于AST,有利于获得执行顺序,可以专注于sourcesink的过程。

codeql

codeqlgithub推出的SAST工具,可以基于规则来定义问题,从而扫描漏洞。

可以参考https://github.com/ASTTeam/CodeQL,有一些codeql的资料

DAST

DAST是动态应用程序安全测试,简单来说就是黑盒漏洞扫描器。黑盒的形式主要就是运行项目,通过爬虫找到接口并发送请求,根据payload和回显来判断是否存在漏洞。很显然误报率会比较低,但是漏报率会比较高,只能发现一小部分的漏洞。

黑盒本身也存在一定的限制,毕竟相比于白盒可以看到程序运行的内部逻辑,黑盒在找接口,确定参数,接口返回行为不明确,缺少数据等等方面受到限制。

接下来说一说我认为的DAST的实现会存在哪些难点。

首先是需要爬虫能够精确的覆盖Web站点的url,并且能够灵活的对于各种特殊参数进行payload的替换,以及针对不同的漏洞类型,做对于漏洞是否存在的检测。

比如说想要对越权进行检测,那么就有水平越权和垂直越权,对于绕过登陆的垂直越权场景,我们可以想到将http请求的cookie做替换,来发送不同的请求,并且根据http响应码和内容,就比较容易判断出来是否存在垂直越权。但是如果对于水平越权,回显的内容非常相似,这时候就比较难以判断,需要能够有比较精准的检测规则,对于口类型的判断,响应的长度以及相似度这些方面做检测,不然就容易误报或者漏报。

IAST

IAST指交互式应用程序安全测试,IAST的主要原理是在代码的运行过程中发现漏洞,这里可以直接体验一下火线安全开源的IAST产品洞态https://github.com/HXSecurity/DongTai,就能对IAST产品有个概念。

IAST的核心就是Hook危险函数/底层api,并且通过前端爬虫判断程序是否运行到了危险函数来判断是否存在漏洞。IAST的误报率比较低,因为可以通过污点跟踪来判断危险函数是否被运行了。缺陷来说的话,从实现机制上决定了,IAST是不能做Go这种静态编译的,没有虚拟机的语言的安全检查的,因为插桩的实现主要依靠runtime agent在虚拟机上做hook

IAST产品的分类我目前也并不是很能理解,可能是缺少在公司中做iast产品实践的机会,主要靠看文章和看开源产品源码学习,希望之后实习会有机会接触到,下面这段分类主要还是根据前辈的文章做整理学习所得,并不一定准确。

IAST产品根据场景有比较多的模式,比如说代理扫描,镜像旁路,插桩扫描等等,洞态是被动式插桩实现的IAST产品。

代理扫描模式是在代理处通过数据包打标进行隔离,打入污点数据后总流量会放大,一定程度导致数据污染和运维的压力。那么就会考虑容器化单独启动测试环境,不过也就需要去单独迭代测试环境造成更多的成本,以及在各种https加密之类的场景下代理模式也会遇到一些困难。

镜像旁路模式是离线分析的方案,在服务器加解密流量后,导向流量清洗集群。这样也会导致在清洗时加重安全侧压力,将污点数据带入QA测试结果等等问题。

插桩扫描模式的实现主要是靠agent等去hook关键函数,来确认流量链路。插桩扫描又分主动和被动,区别在于是否有流量输出。

对各种AST工具的粗浅理解就到这里,之后会想深入研究一下洞态这个被动式插桩的实现,并且再写篇文章讲讲。