CodeQL 的学习以及尝试漏洞挖掘
CodeQL 是一个白盒源代码审计工具。其开发公司 Semmle 也成功和 Github 联姻,成立了 Github Security Lab,负责 Github 上开源软件的代码安全审计。
网上关于该工具的安装教程见官方文档,顺便一说网上的教程也不少,这里就不赘述了。
CodeQL 使用
官方提供了 QL 语法的文档: https://help.semmle.com/QL/ql-handbook/ 以及 CodeQL 的一些 api 接口 https://help.semmle.com/qldoc/cpp/
关于CodeQL 使用,在这篇文章咱们以一个 Github Security Lab 公开的教程作为示例
CodeQL CTF 2: U-Boot
- CTF 2: U-Boot Challenge - Follow in the footsteps of our security research team and discover 13 vulnerabilities un U-Boot. Language: C - Difficulty level:
0x01 查找特定函数的定义
CodeQL 使用的时候需要通过 import
关键词导入特定语言的解析库,例如这里使用的是 import cpp
,如果我要查询 strlen
的函数定义,我只需要编写如下代码
1 | import cpp |
右键点击运行,效果如下
其中第三个是关于 strlen
的定义,
0x2 查找特定宏定义
但是在 c 代码里, 有些情况我们需要查找宏的定义,这个时候就需要使用 Macro
这个 Predicates, 例如样例里提到的 ntohs
族,函数
另外, QL 语言支持正则匹配,我们可以通过 regexpMatch
匹配一类函数例如如下代码
1 | import cpp |
0x3 函数的调用
在代码审计的场景里,我们在查找函数定义的同时,也需要根据函数调用查找完整的数据流,在 CodeQL 里,函数的调用通过 FunctionCall
这个 Predicates 可以直接完成,例如如下代码
1 | from FunctionCall c |
0x04 宏定义的调用
查找宏定义的的调用,使用 MacroInvocation
完成,代码如下
1 | from MacroInvocation mi |
0x05 获取 ntohs 族宏定义的表达式
在 0x04 中,我们提到了宏定义的调用,另外我们知道, ntoh
族函数,通常用来进行网络字节序到主机字节序的转换,通常而言,如果是一个网络协议,我们可能会从某个字段中取出某个特定的值,并且赋值给某个变量,这个时候我们就需要获取他们的表达式。
这里以表达式出现的话,我们可以使用 getExpr()
函数完成,仅仅只需要将 select mi
修改为 select mi.getExpr()
,效果如下:
1 | import cpp |
例如这里的赋值语句就是第 78 个表达式
0x06 编写一个 QL 类
QL 类包括三个部分
更多关于类的编写可以参考 https://help.semmle.com/QL/ql-handbook/types.html#classes
这里我们需要编写尝试编写一个 NetworkByteSwap
的类
1 | import cpp |
0x07 数据流分析
现在我们来开始做数据流分析,通过定义源和接收器来创建配置类。 来源应该是调用ntohl
,ntohll
或ntohs
。该接收器应为不安全调用memcpy的size参数。通过查找此类的数据流判断是否存在安全问题
这里需要使用
1 | import semmle.code.cpp.dataflow.TaintTracking |
两个新库,然后我们要设置 来源和 Sink 的对象。
首先设置来源:
1 | override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof NetworkByteSwap } |
设置来源对象为 表达式,是 NetworkByteSwap
这个类的值,NetworkByteSwap
这个类在 0x06 定义
然后设置接收器,接收器为 memcpy
的size 参数
1 | override predicate isSink(DataFlow::Node sink) { |
完整代码如下:
1 | import cpp |
效果如下
其中有多个明显的缓冲区溢出漏洞
使用CodeQL 进行 0day 挖掘
我们通过 CodeQL 编写了一个 ntoh -> memcpy 的数据流追踪,当我们通过检查相应的代码我们即可分析是否有缓冲区溢出风险。我们学习了差不多了,我们可以通过这个成型的查询来查询一些类似这样的安全问题。
例如我通过这个查询,挖掘了两个缓冲区溢出漏洞: CVE-2020-28194 和 CVE-2020-15173
大家也可以去尝试尝试。