为东航MU5735航班的机组成员和乘客祈祷!!!今天怀着沉重的心情,给大家推荐一篇AsiaCCS 2022的论文——“The Convergence of Source Code and Binary Vulnerability Discovery – A Case Study”,这篇论文探讨的问题是在漏洞检测中,源代码分析和二进制代码分析应该如何结合。在很多情况下,针对源代码的漏洞检测和针对二进制代码的漏洞检测几乎是平行的研究内容,两者需要处理的困难和使用的技术手段都缺乏交集。本文作者试图利用反编译器作为辅助手段,观察源代码漏洞检测工具是否可以帮助二进制代码漏洞检测。实验表明,这种想法可能是很有前景的:在测试的二进制代码案例中,有超过71%的情况,源代码漏洞检测工具(SAST tool)是可以通过分析反编译器的输出结果而找到问题的(注意:直接使用反编译工具的输出结果去投喂源代码漏洞检测工具是不可行的,相关“代码”还需要一定程度的人工干预调整!)。
由于这篇论文讨论的是传统的源代码漏洞检测和二进制代码漏洞检测的结合,所以作者并没有提出什么新的技术,而是聚焦于评估 state-of-the-art 分析工具。具体地,作者选择了6款开源的源代码漏洞检测工具和2款商业源代码漏洞检测工具进行评估。在反编译器的选择上,作者使用了IDA HexRays 7.1(作者的版本有点旧),Ghidra 9.2 以及 Retdec 4.0 三款反编译器。
作者按照上图的工作流程进行了实验测试。在实验中,作者运用下面的一些代码漏洞进行测试
首先,我们关注一下反编译器的工作效果。从下表中可见,除了RetDec的部分情况以外,大部分情况下反编译器均能生成出相关的代码,且和原始的代码相比规模差别不大(更为细节的实验评估再次表明,IDA还是那个质量最好的反编译器)。
除了关注二进制代码到源代码的生成,作者也关心这些生成的源代码能否通过编译,因此很多源代码漏洞检测工具需要先对代码进行编译(至少进行到编译的某个阶段,例如生成AST)之后,才能开展分析。很不幸的是,所有的反编译器输出的代码显然都不能很好地通过编译器测试,作者只能花24小时去人工修复编译错误,然后再利用源代码漏洞检测工具进行后续测试。
经过手工修复后的代码可以通过编译,在诸多代码分析工具的测试横评中,我们看到Joern、Clang(CSA)和CodeQL表现相当不错。相比之下商业工具反而没那么好的效果。
接下来我们要关注的是分析工具的误报率,这个是工程师最为关注的一点。如果分析工具以极高的误报率换来对漏洞更全面的捕获,那基本上可以认定这个工具是没有多少实用价值的。在这一项测试中,我们注意到Joern和CodeQL较少产生高误报,特别是Joern,基本上对所有的分析对象都没有输出高误报结果。
当然,高误报结果可能并非因为针对二进制代码,被测试的源代码分析工具本来也容易产生误报。作者进一步分析了这些工具在面对二进制代码时,误报是上升还是下降。下表显示,像CPPCheck这种比较粗糙的分析,会在二进制代码分析上产生极高的误报增长,Facebook的Infer在这个测试中表现也不理想。而Joern和Clang就相对来说好很多——误报率在二进制代码分析时下降了。
作者还发现了一些有趣的现象,例如有些代码在编译前可能因为各种复杂的定义,让分析工具难以识别相关的bug。但是在编译后的二进制代码反编译得到的伪代码中,分析工具反而更容易发现这种bug了。
当然,反编译这个过程必然存在一些信息丢失,在很多时候拥有源代码就能防止的误报,在反编译得到的代码上就很难保证结果的准确性。例如下面的代码,由于反编译过后丢失了数组listbuf
的长度,因此代码分析工具往往会认为这里存在一个潜在的越界内存访问风险(认为memset
和fread
都可能越界读)。类似这样的例子在论文的第五章还有好多,大家可以去细细品味。
这篇论文对反编译器研发的启示之一,是反编译器并不一定要“为人服务”。传统的反编译器输出结果通常考虑的用户是人类分析师,因此在代码可读性上下了很多功夫,但是这并不一定是机器最喜欢的。如果反编译器研发换一下思路,为那些代码分析工具服务,输出结果可能并不一定直观,但是可能会带来更好的分析准确性!
实验数据:
https://github.com/elManto/SAST_on_Decompilers
论文PDf:
https://www.s3.eurecom.fr/docs/asiaccs22_mantovani.pdf