源码审计工具调研

开始

​ C/C++语言的语法拥有其它语言所没有的灵活性,这种灵活性带来了代码效 率的提升,但相应也使得代码编写具有很大的随意性,另外 C/C++编译器不进 行强制类型检查,也不做任何边界检查,这就增加了代码中存在隐患的可能性。 如果能够在代码提交测试之前发现这些潜在的错误,就能够极大地减轻测试人员 的压力,减少软件项目的除错成本,可是传统的 C/C++编译器对此已经无能为力,这个任务只能由专用的代码检查工具完成。

llvm & clang

  • LLVM 是个很大很大的项目群,几乎把从编译到调试的各个构建环节都重新实现了一遍,目的:一是尽可能地模块化现有代码以方便在此基础上进行二次开发、一是提供比传统构建工具链更好的用户体验。clang是LLVM的子项目,是一款非常优秀的C++ 编译器,前端 clang + 后端 LLVM(后简称 LLVM/clang)就是一款可替代 GCC 的优秀编译
  • GCC 配套的标准库涉及 libstdc++ 和 libsupc++ 两个子库,前者是接口层(即,上层的封装),后者是实现层(即,底层的具体实现),对应到clang,则libc++(接口层)和 libc++abi(实现层)

->IR->x86,arm,ppc,mips,amd64

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
1:
2: char *test( int m, int n, char *p )
3:{
4int result;
5char *temp;
6long nm;
7int i, k, kk;
8char name[11] = "Joe Jakeson";
9
10: nm = n * m;
11: temp = p == "" ? "null" : p;
12for( i = 0; i < m; I++ ) {
14: k++;
15: kk = i;
16: }
17
18if( k== 1 )
result = nm;
19else if( kk > 0 )
result = 1;
20else if( kk < 0 )
result = -1;
21
22if (m == result)
return temp;
23else
return name;
24:}
  • 第 8 行向 name 数组赋值时丢掉了结尾的 nul 字符
  • 第 10 行的乘法精度会失准,即使考虑到 long 比 int 的字长更长,由 于符号位的原因仍然会造成精度失准
  • 第 11 行的比较有问题
  • 第 14 行的变量 k 没有初始化
  • 第 15 行的 kk 可能没有被初始化
  • 第 22 行的 result 也有可能 没有被初始化
  • 第 23 行返回的是一个局部对象的地址。

TscanCode

Description:

  • TscanCode是鹅厂静态分析团队开发的一款开源免费的C/C++静态分析工具。
  • 扫描C/C++代码不需要进行编译, 操作简单。
  • 速度快,平均扫描速度10W行/分钟。误报较多
  • 项目不再维护
  • 结果以图形化或者xml显示

Download :

github

测试集

samples/cpp

Usage:

1
./tscancode --xml func.cpp 2>result.xml

scan-build *****

description

  • scan-build 是一个命令行工具,它是一款静态分析器,是clang-tools的一款工具。
  • 需要编译项目,通过重写cc和cxx环境变量来改变你的编译环境,scan-build将编译器gcc设置为analyze-ccanalyze-cc作为一个伪编译器,转发命令行参数给gccclang来执行静态分析。不会分析没有参与编译的源码
  • 精准度非常之高。特别是逻辑上的漏洞很多都可以探查出来。
  • 项目构建完毕后,以html web页面显示代码缺陷报告

当一个项目在构建中,源文件在编译时同时也被静态分析器有序的检查着。当构建完成时,结构将会作为一个web网页的形式呈现给使用者。

insall

1
2
3
4
$ sudo apt-get install clang-8 clang-tools-8
$ la /usr/bin/ | grep scan-build
lrwxrwxrwx 1 root root 42 Dec 10 2019 scan-build-8 -> ../share/clang/scan-build-8/bin/scan-build
lrwxrwxrwx 1 root root 45 Dec 10 2019 scan-build-py-8 -> ../share/clang/scan-build-py-8/bin/scan-build

Usage

-h 显示scan-build的所有参数
-o html 报告文件的存放目录。默认将报告文件保存在/tmp目录里。
-k 增加一个继续运行的参数到具体的命令中
-v 冗余输出结果。可以选择2个或3个”-v”增加冗余度。
-V 当命令完成后,在浏览器中查看运行结果。

automake项目

1
scan-build ./configure

Cmake

1
2
mkdir build && cd build 
scan-build ./cmake ..

Make

1
scan-build --use-analyzer `which clang` make -j8

结果请到/tmp/scan-build-xxxxxxxxxxxxxxx/failures 查看。它是 html 的。

比如capstone项目的编译展示

1
2
3
4
5
6
git clone https://github.com/aquynh/capstone.git && cd capstone && git checkout next 
mkdir build && cd build
scan-build-8 --use-analyzer `which clang-8` ../cmake.sh
# 顺带安装下,后面课程需要用到
cd bindings/python
sudo make install

image-20200914233000688

Cppcheck***

官方网站

Description

CppCheck是一个C/C++代码缺陷静态检查工具。不同于C/C++编译器及其它分析工具,CppCheck只检查编译器检查不出来的bug,不检查语法错误。所谓静态代码检查就是使用一个工具检查我们写的代码是否安全和健壮,是否有隐藏的问题。

  • 检出多,有效检出少
  • 无须编译配置项目

Build

Debian:

  • sudo apt-get install cppcheck

Usage

Visual stdio

image-20200915131408641

1
$ cppcheck . -j 3 --enable=all --xml 2>result.xml

multi threads

1
cppcheck -j 4 <path>

Visual studio

在整个解决方案上运行 cppcheck:

1
$ cppcheck --project=<proj>.sln

在单个项目文件上运行 cppcheck:

1
$ cppcheck --project=<proj>.vcxproj

其他参数

1
2
3
4
5
$ cppcheck --enable=warning,performance <path>
# warning,performance 启用警告和性能消息:
# all 启用所有消息
# style 可以启用警告、性能、可移植性和样式信息
# information 启用信息消息

不确定消息: 默认情况下,如果确定,Cppcheck 只显示错误消息。如果使用 --inconclusive,当分析不确定时,也会写错误消息。

1
cppcheck --inconclusive <path>

输出格式:template

1
2
3
cppcheck --template=gcc gui/test.cpp
# vs, gcc 编译器输出风格
# "{file},{line},{severity},{id},{message}" 自定义

PC-lint

官网

Description

  • PC-lint for C/C++是由Gimpel软件公司于1985年开发的代码静态分析工具
  • 它能有效地发现程序语法错误、潜在的错误隐患、不合理的编程习惯等。
  • PC-lint是资格最老,最强力的代码检查工具
  • 收费软件, 有30天体验
  • 需要完整的项目环境,如头文件等,并且配置起来有一点点麻烦。
  • PC-Lint 则偏重于代码的逻辑分析,它能够发现代码中潜在的错误,比如数组访 问越界、内存泄漏、使用未初始化变量等

Usage

PC-Lint能够检查出很多语法错误和语法上正确的逻辑错误,PC-Lint为大部分错误消息都分配了一个错误号,编号小于1000的错误号是分配给C语言的,编号大于1000的错误号则用来说明C++的错误消息。

  1. 在doc/manual.pdf中给出了错误号

image-20200915150904327

以C语言为例,其中的
编号 001-199 指的是一般编译器也会产生的语法错误;
编号 200-299 是PC-Lint程序内部的错误,这类错误不会出现在代码中的;
编号 300-399 指的是由于内存限制等导致的系统致命错误。
编号 400-999 中出现的提示信息,是根据隐藏代码问题的可能性进行分类的:
编号 400-699 指的是被检查代码中很可能存在问题而产生的告警信息;
编号 700-899 中出现的信息,产生错误的可能性相比告警信息来说级别要低,但仍然可能是因为代码问题导致的问题。
编号 900-999 是可选信息,他们不会被默认检查,除非你在选项中指定检查他们。

  1. PC-Lint/FelexLint 提供了和许多编译器类似的告警级别设置选项
  • -wLevel,它的告警级别分为以下几个级别,缺省告警级别为 3 级:
  • -w0 不产生信息(除了遇到致命的错误)
  • -w1 只生成错误信息 – 没有告警信息和其它提示信息
  • -w2 只有错误和告警信息
  • -w3 生成错误、告警和其它提示信息(这是默认设置)
  • -w4 生成所有信息
  1. PC-Lint/FelexLint 还提供了用于处理函数库的头文件的告警级别设置选项

    -wlib(Level),这个选项不会影响处理 C/C++源代码模块的告警级别。
    它有和 -wLevel 相同的告警级别,缺省告警级别为 3 级:

    • -wlib(0) 不生成任何库信息
    • -wlib(1) 只生成错误信息(当处理库的源代码时)
    • -wlib(2) 生成错误和告警信息
    • -wlib(3) 生成错误、告警和其它信息(这是默认设置)
    • -wlib(4) 产生所有信息
  2. PC-Lint 的检查分很多种类,有:

    • 强类型检查
    • 变量值跟踪
    • 语义信息
    • 赋值顺序检查
    • 弱定义检查
    • 格式检查
    • 缩进检查
    • const 变量检查
    • volatile 变量检查等等。

    对每一种检查类型,PC-Lint 都有很多详细的选项,用以控制 PC-Lint 的检查效果。

    PC-Lint 的选项有 300 多种,这些选项可以放在注释中(以注释 的形式插入代码中)

    例如:

    /*lint option1 option2 ... optional commentary */选项可以有多行

    //lint option1 option2 ... optional commentary 选项仅为一行(适 用于 C++)

    选项间要以空格分开,lint 命令一定要小写,并且紧跟在/或//后面,不能有空格。

    如果选项由类似于操作符和操作数的部分组成,例如-esym(534, printf, scanf, operator new),其中最后一个选项是 operator new,那么在 operator 和 new 中间只能有一个空格。

    PC-Lint 的选项还可以放在宏定义中,当宏被展 开时选项才生效。

    例如:

    #define DIVZERO(x) /*lint -save -e54 */ ((x) /0) /*lint -restore */ 允许除数为 0 而不告警

需要把发到邮箱的许可证eval-license.lic文件放到主程序pclp64路径

运行config/pclp_config来自动生成内容。

1
2
3
4
5
6
7
$ pip install regex pyyaml
$ python3 pclp_config.py --compiler=gcc --compiler-bin=`which gcc` --config-output-lnt-file=co-gcc.lnt --config-output-header-file=co-gcc.h --generate-compiler-config
$ python3 pclp_config.py --compiler=clang --compiler-bin=`which clang-8` --config-output-lnt-file=co-clang.lnt --config-output-header-file=co-clang.h --generate-compiler-config

#生成
-rw-rw-r-- 1 u16s u16s 17K Sep 15 17:58 co-gcc.h
-rw-rw-r-- 1 u16s u16s 2.0K Sep 15 17:58 co-gcc.lnt

适当添加 --compiler-options="--std=c++11"

1
2
$ pclp co.lnt source-files
$ pclp co.lnt -w1 +e900 source-files

windows visual studio

管理员启动 config\pclpvscfg.exe

1
.\gencfg.bat

大型项目:

On Linux or macOS this can be done with:

export IMPOSTER_LOG=.commands

and on Windows:

set IMPOSTER_LOG=.commands

编译 imposter

clang-8 config/imposter.c -o imposter

1
2
3
4
5
6
7
8
9
10
11
12
$ make -e CC=/path/to/imposter 
# 生成了 <proj>.commands
$ python3 pclp_config.py\
--compiler=gcc\
--imposter-file=<proj>.commands\
--config-output-lnt-file=project.lnt\
--generate-project-config\
#生成了hello.lnt

$ pclp64_linux co-gcc.lnt project.lnt 1>output.txt


#capstone项目太大, 内存不足炸了

![image-20200915190426990](/Users/notify/Library/Application Support/typora-user-images/image-20200915190426990.png)结果如下,不是很直观

image-20200915190052759

Coverity

Coverity概述

COVERITY是被Gartner、Forrester、 IDC和 VDC权威机构评定为最领先的应用安全测试解决方案(超大规模分布式静态代码检查工具)。世界上几乎所有超大型软件企业都在使用(包括谷歌,亚马逊,洛克希德马丁,空中客车,华为等)。

Coverity公司是由一流的斯坦福大学的科学家于2002年成立的,产品核心技术是1998年至2002年在斯坦福大学计算机系统实验室开发的,用于解决一个计算机科学领域最困难的问题,在2003年发布了第一个能够帮助Linux、FreeBSD等开源项目检测大量关键缺陷的系统。Coverity公司推出的综合开发测试平台,基于新一代的不做代码规则检查、只专注检测代码中的Bug静态分析技术,可以更好地帮助开发人员在写代码的时候就能发现并修复安全缺陷,缩短产品上市时间和降低风险。Coverity是唯一位列IDC前10名软件质量工具供应商的静态分析工具厂商,被VDC评为静态源代码分析领域的领导者。

Coverity支持的语言和

C/C++ C# Java JavaScript PHP Python ASP.NET Objective-C JSP Node.js Ruby

支持检测的主要缺陷类型列表:

  • API usage errors
  • Best practice coding errors
  • Build system issues
  • Buffer overflows
  • Class hierarchy inconsistencies
  • Code maintainability issues
  • Concurrent data access violations
  • Control flow issues
  • Cross-site scripting (XSS)
  • Cross-site request forgery (CSRF)
  • Deadlocks
  • Error handling issues
  • Hard-coded credentials
  • Incorrect expression
  • Insecure data handling
  • Integer handling issues
  • Integer overflows
  • Memory – corruptions
  • Memory – illegal accesses
  • Null pointer dereferences
  • Path manipulation
  • Performance inefficiencies
  • Program hangs
  • Race conditions
  • Resource leaks
  • Rule violations
  • Security best practices violations
  • Security misconfigurations
  • SQL Injection
  • Uninitialized members

使用https://scan.coverity.com对仓库代码进行coverity静态检查,如果检测到coverity issues会通过邮件通知相关patcher作者或者maintainer进行修改,但是邮件中无法看到issues的详细细节。需要登陆https://scan.coverity.com网站去查看详细细节,另外我们需要有方法在向社区提交修复patch之前检查修改后的代码是否能通过coverity检测。本文简述查看issue及对修复代码进行检测的方法。

有小伙伴说,用公司内部的coverity检查不就行了?不好意思,coverity是商业软件,公司内部使用的版本的和社区使用的版本大概率不同,另外2边检查范围和告警屏蔽配置的不同,导致最终检查出来的结果很可能有差异。

download

Usage

注册

image-20200910171309584

关联Github账户

在My Account -> Github中 关联自己的Github账户,

image-20200910171600312

去github检查相关项目访问权限image-20200910172815718

image-20200910171901007

添加项目

来到DashBoard->Add Projects

image-20200910171942696

开始创建目标分析项目(误将闭源源码泄漏与我无关)

image-20200910172341892

填好项目摘要信息

image-20200910174644153

注意选择缺陷报告访问权限,分别为

1: 公开项目摘要信息和缺陷(只读)

2: 只公开项目摘要信息

3: 需要维护人员授权才可访问项目摘要和缺陷

构建项目

image-20200910173408953

先使用coverity二进制工具构建好项目并打包再上传即可开始分析

最下侧下载对应系统平台的二进制工具包

image-20200910195410865

  1. 下载
1
$ wget https://scan.coverity.com/download/linux64 --post-data "token=<token>&project=<ProjName>" -O coverity_tool.tgz
  1. 解压
1
$ tar -zxvf cov-analysis-linux64-2019.03.tar.gz
  1. 初始化编译器

查看所有编译器配置

1
cov-configure --list-configured-compilers json

gcc

1
cov-configure --comptype gcc --compiler `which gcc`

clang

1
2
3
$ rm -rf CMakeCache.txt CMakeFiles
$ cov-configure --comptype clangcxx --compiler `which clang++`
$ export CC=`which clang` && export CXX=`which clang++`
  1. 开始编译项目

cd到项目

采用cmake的项目构建框架

1
2
3
4
5
$ export CC=`which clang++` 可选
$ export CXX=`which clang++` 可选
$ cmake ..
# 对代码进行coverity清除和重编:
$ cov-build --dir cov-int bash -c 'make clean && make -j 8'

采用automake的项目构建框架

1
2
3
4
$ export CXXFLAGS="-O2 -fno-omit-frame-pointer -g"
$ CXX="clang++ $CXXFLAGS" CC="clang $CXXFLAGS" CCLD="clang++ $CXXFLAGS" ./configure
# 对代码进行coverity清除和重编:
$ cov-build --dir cov-int bash -c 'make clean && make -j 8'

或者

1
2
3
./configure
# 对代码进行coverity清除和重编:
$ CXX=/opt/local/bin/clang++ COVERITY_UNSUPPORTED=1 CXXFLAGS="-DNDEBUG -g3 -O2 -std=c++11" cov-build --dir cov-int bash -c 'make clean && make -j 8'

企业完整版才能有的如下功能

获取权限:

1
cov-analyze --dir coverity --all --wait-for-license
1
cov-analyze --dir coverity @@rule.txt

生成检测报告:

1
cov-format-errors --dir coverity --html-output coverity_html

检测报告web前端展示

1
cov-commit-defects --dir cov --host 127.0.0.1 --user x x x x x x x x --password xxxxx projname --stream STRAM-NAME

打包

1
tar czvf coverity.tgz cov-int

开始上传

1
2
3
4
5
6
curl --form token=<token> \
--form email=<email> \
--form file=@`pwd`/coverity.tgz \
--form version="<Version>" \
--form description="<Description>" \
https://scan.coverity.com/builds\?project\=<ProjName>

排除/添加扫描组件

image-20200911150915054

创建模型文件

https://scan.coverity.com/tune

image-20200911113248265

查看缺陷

image-20200911165935460

image-20200911171202562

1、空指针引用(Null pointer dereferences)
描述:程序调用值为null的指针的任何方法,会引发空指针异
可能的后果:程序Crash,exit, restart,执行未授权代码或命令
Checker:FORWARD_NULL

img

Checker: NULL_RETURNS

img

2、资源泄漏(Resource leaks)
描述:程序未释放资源,或程序错误地释放了资源
可能的后果:Dos攻击,敏感数据泄漏,资源消耗
Checker: RESOURCE_LEAK

img

3、内存破坏(Memory - corruptions)
描述:

  • 读写预期边界以外的内存缓冲区
  • 使用未初始化的变量
  • 函数/功能调用过程中使用了错误的参数取值
  • 重复使用释放后的内存

可能的后果:程序Crash,exit, restart,执行未授权代码或命令

Checker: OVERRUN

img

4、内存非法访问(Memory - illegal accesses)
描述:

  • 使用未初始化的变量

  • 使用释放后的资源(CPU、内存、Socket、文件等)

  • 函数返回堆栈变量的地址

可能的后果:程序Crash,exit, restart,资源消耗等

Checker: OVERRUN

img

Checker: USE_AFTER_FREE

img

Checker: RETURN_LOCAL

img

5、错误的表达式(Incorrect expression)
描述:使用错误的变量,不正确的类型转换
可能的后果:不符合预期的输出值,程序逻辑错误,运行时错误

Checker: COPY_PASTE_ERROR

img

6、未初始化变量(Uninitialized variables)
描述:变量使用前未初始化
可能的后果:程序逻辑不正确,产生错误的数据,程序Crash

Checker: UNINIT

img

Fortify

HP Fortify Source Code Analysis-Premium

Fortify更聚焦于产品代码的安全方面,被hp收购;

http://www8.hp.com/us/en/software-solutions/static-code-analysis-sast/

审计工具对比

检出数量: pclint >> cppcheck > TSC > coverity > scan-build

准确率: scan-build > coverity ≈ TSC >> cppcheck > pclint

综合评分:coverity > scan-build > TSC > cppcheck > pclint