CodeQL学习笔记
郑重声明:文中所涉及的技术、思路和工具仅供以安全为目的的学习交流使用,如果您不同意请关闭该页面!任何人不得将其用于非法用途以及盈利等目的,否则后果自行承担!

安装CodeQL
CodeQL CLI
首先需要配置一下引擎,在这个项目中有编译好的项目https://github.com/github/codeql-cli-binaries
。
CLI 二进制文件支持主流的操作系统,包括 Windows、MacOS、Linux
解压下载的文件
- 将下载的CodeQL CLI安装包解压到你选择的安装目录,例如
C:\Software\codeql
(Windows)或/usr/local/codeql
(Linux/MacOS)。
设置环境变量
- 将CodeQL CLI的安装目录添加到你的系统环境变量中,以便在命令行中直接调用
codeql
命令。 - 在Windows上,可以通过“系统属性”->“高级”->“环境变量”来设置。
- 在Linux/MacOS上,可以通过修改
~/.bashrc
、~/.zshrc
或类似的shell配置文件,并添加类似export PATH=$PATH:/usr/local/codeql
的行来实现。
举例
在 MacOS 上安装为例
# 下载codeql.zip |
最后在终端输入codeql --version
,如果显示CodeQL CLI的版本信息,则表示安装成功
CodeQL SDK
在这边下载规则库文件https://github.com/github/codeql
,用来在后续库中进行查询
可以在解压后的文件中输入codeql pack ls
来查看当前SDK中支持的规则集。
VScode
在商店里面搜索安装CodeQL插件,然后再设置中把CLI地址配置进去
使用CodeQL进行代码分析
使用CodeQL生成数据库
准备源代码
- 确保你有需要分析的源代码,并知道源代码的语言类型(如Java、Python等)。
使用CodeQL CLI创建数据库
-
打开命令行,切换到源代码所在的目录。
-
执行创建数据库的命令,例如
codeql database create <数据库名> --language=<语言标识符> --source-root=<源码路径>
-
如果源代码是一个Maven项目,可能需要使用Maven命令来构建项目,并在创建数据库时指定该命令
--command="mvn clean install"
。
Language对应关系如下:
Language | Identity |
---|---|
C/C++ | cpp |
C# | csharp |
Go | go |
Java | java |
javascript/Typescript | javascript |
Python | python |
举例
Java
我们利用Java的靶场来做测试
# 创建一个CodeQL数据库,指定存储路径 |
然后在这里把C:\code\codeql_databases\java
的文件添加进去
接着在添加CodeQL SDK:“文件”-“将文件添加到工作区”

接着在文件夹中找到这个路径\codeql\java\ql\src\Security\CWE
,选一个右键执行Run Queries in Selected Files
,既可以看到结果
Cpp
如何需要自己重建数据库的话可以下载这个项目,跳转到有风险的hash位置
git clone https://github.com/u-boot/u-boot.git |
如果嫌麻烦可以先下载SDK
git clone https://github.com/cq674350529/codeql-uboot |
接着下载已经创建好的数据库,这个数据库是在https://github.com/github/codeql/discussions/14939
这个地方找到的
https://github.com/github/securitylab/releases/download/u-boot-codeql-database/u-boot_u-boot_cpp-srcVersion_d0d07ba86afc8074d79e436b1ba4478fa0f0c1b5-dist_odasa-2019-07-25-linux64.zip |
基本查询结构
为了使用CodeQL进行定制分析,我们可以通过自己编写查询来实现查找漏洞或错误。CodeQL的查询类型有:
- 告警查询:突出显示代码中特定位置的问题的查询。
- 路径查询:代码中source和sink之间信息流的查询。
用CodeQL编写的查询文件扩展名为.ql
,并包含一个select
子句。
import <language> /* 导入对应的语言包 */ |
CodeQL主要使用逻辑连接词(如and
、 or
、 not
), 限定词(如forall
、exists
), 还有谓词(predicates
)等重要逻辑概念。同时CodeQL也提供了递归的支持和聚合(如count
、 sum
、 average
)
import语句
每个查询通常包含一个或多个import
语句,这些语句定义了要导入到查询中的库或模块。
From子句
每个声明必须采用 <type> <variable name>
的形式。
Where子句
该子句使用聚合,谓词和逻辑公式将目标变量限制为较小的集合,这些集合满足已定义的条件。
Select 子句
select element, string |
- Element:查询所标识的代码元素。这定义了告警的位置。
- String:为该代码元素显示的消息,描述了生成告警的原因。
关于上述的内容,使用个简单的例子,筛选system函数调用
import cpp |
高级语法
一定要看一遍官方文档!一定要看一遍官方文档!一定要看一遍官方文档!
谓词
在CodeQL中,函数并不叫"函数",叫做Predicates
(谓词)
无返回值的谓词
无返回值的谓词以predicate
关键词开头,无返回值的谓词其实有点像宏的意思,他会直接替换过来,举个例子
//这里的i是一个无穷大的int类型数组,可以把它当成没有初始化的 |
有返回值的谓词
当我们需要将某些结果从谓词中返回时,使用的是result
,和其他语言不一样,该值是一个特殊的变量
int isTest(int i) { |
并且可以多个结果输出
string getANeighbor(string country) { |
如果要限制集合数据大小,可以添加一个bindingset
标注,不然的话这两个值是不合法的运算
bindingset[x] bindingset[y] |
递归
/*官方的解释 |
第二个运算的例子
int getANumber() { |
传递闭包
使用+
来表示通常,p.getAParent+()
等价于以下递归谓词:
COPYPerson getAnAncestor() { |
使用*
来表示, p.getAParent*()
将会输出p的祖先,或者p。该谓词调用等价于以下谓词:
COPYPerson getAnAncestor2() { |
类
CodeQL中的类,并不意味着建立一个新的对象,而只是表示特定一类的数据集合。
class OneTwoThree extends int { |
特征谓词类似于C++中的类构造函数,它将会进一步限制当前类所表示数据的集合。例如上面的特征谓词
OneTwoThree() { // characteristic predicate |
this
变量表示的是当前类中所包含的数据集合。与result
变量类似,this
同样是用于表示数据集合直接的关系。
string getAString() { // member predicate |
Source和Sink
在安全审计的理论当中有一个三元组概念,分别是source、sink和sanitizer
-
Source:是指漏洞污染链条的输入点。可以是请求的参数(GET、POST等)、上传的文件、Cookie、数据库数据等用户可控或者间接可控的地方
-
Sink:是指漏洞污染链条的执行点。比如在c++中system、scanf、sprintf等函数。
-
Sanitizer:处理函数是对数据进行过滤或者编解码的函数这些函数会对输入造成影响,为漏洞利用带来不确定性。
大概的流程图
graph LR |
参考文章
https://codeql.github.com/codeql-standard-libraries/cpp/ |