CodeQL 初探

简介

CodeQL 是 GitHub 开发的一种静态分析工具,广泛用于代码安全性和质量的检测。CodeQL 允许开发人员使用一种类似于 SQL 的查询语言来分析源代码,并查找潜在的漏洞或代码缺陷。它通过创建一个"代码数据库",使得用户可以查询程序中的各种数据流、控制流、API 调用等信息,从而发现安全漏洞、代码重复或不良编码实践。

CodeQL 支持多种编程语言,包括但不限于:C/C++、Java、JS、Python、Golang、Ruby、Rust、C#等。

环境搭建

下面我们搭建 CodeQL 所需要的环境。

CodeQL CLI

CodeQL CLI 是进行代码分析的核心工具,它允许您创建数据库、运行查询等操作

  • Linux
bash 复制代码
wget https://github.com/github/codeql-cli-binaries/releases/download/v2.20.7/codeql-linux64.zip

配置.bashrc文件,这里我是通过定义别名来使用的:

shell 复制代码
alias codeql=/tools/binary/codeql/codeql

VSCode插件

扩展插件搜索 codeql 插件,然后安装即可。

点击插件自动更新右边的齿轮按钮设置插件一些参数,Code QL>Cli:Execuble Path表示我们的 CodeQL CLI 路径,这里我们设置为我们的 codeql 目录下的 codeql 路径。

工作区

下载工作区

shell 复制代码
git clone --recursive https://github.com/github/vscode-codeql-starter

从文件打开工作区。

创建数据库

接下来我们需要为要审计的项目创建一个 CodeQL 数据库,以便进行查询。

假如我们要审计以下test.c文件:

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {

    char buffer[16];
    strcpy(buffer, input);  // 无边界检查
    printf("Copied: %s\n", buffer);

    return 0;
}

使用以下命令来创建:

shell 复制代码
codeql database create ./test-db --language=cpp --command="gcc test.c -o test"
  • codeql database create:创建数据库;
  • test-db:指定数据库创建成功后存放在test-db目录下;
  • language:指定语言,这里选择cpp即 C++;
  • command:编译指令,如果使用 make 编译那么就将 make 语句写在这里。

选择数据库

在 VSCode 中选择数据库。

之后我们就可以编写ql语句文件,然后运行在数据库中查询就可以了。而且我们不仅可以自己编译数据库,还可以使用别人编译好的数据库。

QL查询语句

CodeQL 所使用的查询语言是一种类 SQL 的语法。用于查找每种受支持语言最相关和最有趣的问题。您还可以编写自定义查询来查找与您自己的项目相关的问题。

重要的查询类型包括:

  • 警报查询:突出显示代码中特定位置的问题的查询。
  • 路径查询:描述代码中源和接收器之间的信息流的查询。

基本结构

q 复制代码
import <语言库>  // 如 java, cpp, python

from <变量声明>
where <条件表达式>
select <输出结果>
  • import - 导入库

codeql 为每种语言提供了大量库,包含类、谓词和辅助工具。

复制代码
import cpp

cpp 模块会自动导入所有核心 C/C++ 库,使你能访问整个抽象语法树(AST)、数据流、控制流等类和谓词。

  • from - 变量声明

用于声明要操作的元素(如函数、表达式、语句等)。

示例:

sql 复制代码
from Function f, Parameter p
  • where - 过滤条件

用于描述逻辑约束,筛选出满足条件的变量。

常见构造:逻辑运算(and, or, not),聚合与比较(=, !=, <, >=),调用谓词(isPublic(), hasName()),库提供的数据流、控制流谓词。

sql 复制代码
where f.getName() = "main"
  • select - 输出结果

定义最终展示的内容。

查询输出格式:

q 复制代码
select element,string

element 是由查询标识的代码元素,用于定义警报的显示位置;string 表示一条消息,其中还可以包含连接和占位符,说明生成警报的原因。

示例:

sql 复制代码
select c, "Found dangerous call here: " + c.getTarget().getName()

基础抽象类

类名 描述 子类示例
Element 所有 CodeQL 元素基类 ---
AstNode 抽象语法树节点 Stmt, Expr, Decl
Stmt 所有语句 IfStmt, SwitchStmt, ReturnStmt
Expr 所有表达式 CallExpr, BinaryExpr
Decl 所有声明 Function, VariableDecl
Type 所有类型 PrimitiveType, PointerType

声明类

  • 变量声明
CodeQL 类 示例
GlobalVariable int g;
NamespaceVariable namespace ns { int x; }
MemberVariable class C{int x;};

示例:查找所有类型为std::string的类成员变量。

sql 复制代码
from MemberVariable v
where v.getType().getName() = "string"
select v
  • 函数声明
CodeQL 类 示例
Function void foo()
VirtualFunction virtual void f()
FormattingFunction printf()
Parameter void foo(int param)

查找静态函数:

sql 复制代码
from Function f
where f.isStatic()
select f, "static function"

查找从未调用的函数:

sql 复制代码
from Function f
where not exists(FunctionCall fc | fc.getTarget() = f)
select f, "unused function"
  • 模板与类
CodeQL 类 示例
ClassDecl class C {...}
StructDecl struct S{...}
ClassTemplateInstantiation vector<int>
TemplateParameter typename T
Constructor ClassName()
Destructor ~ClassName()
TemplateDecl template<typename T>
TemplateInstantiation vector<int>
TemplateParameter typename T

查找所有vector<int>实例化点:

sql 复制代码
from ClassTemplateInstantiation c
where c.getTemplate().getName() = "vector"
select c

语句类

  • 控制流语句
CodeQL 类 示例
IfStmt if(x)
IfElseStmt if(x) else y
SwitchStmt switch(x)
WhileStmt while (x)
DoStmt do {...} while(x)
ForStmt for(int i=0;i<n;i++)
RangeBasedForStmt for(auto& x : v)

查找空if语句:

sql 复制代码
from IfStmt ifs, BlockStmt blk
where ifs.getThen() = blk and blk.getNumStmt() = 0 and not ifs.hasElse()
select ifs, "redundant if"
  • 跳转语句
CodeQL 类 示例
BreakStmt break;
ContinueStmt continue;
ReturnStmt return x;
GotoStmt goto label;
  • 复合语句
CodeQL 类 示例
CompoundStmt { ... }
BlockStmt 一组语句

表达式类

  • 运算符
CodeQL 类 示例
BinaryExpr a + b
UnaryExpr !x
AssignExpr a = b
CallExpr foo()
MemberAccess obj.a
ArrayAccess arr[i]

查找调用sprintf的位置且 format 字符串不是字面量(格式化字符串漏洞):

sql 复制代码
from FunctionCall fc
where fc.getTarget().getName() = "sprintf"
  and not fc.getArgument(1) instanceof StringLiteral
select fc, "sprintf with non-literal format string"
  • 字面量
示例
IntegerLiteral 42
StringLiteral "abc"
FloatingLiteral 3.14

查找右边为 0 的赋值:

sql 复制代码
from AssignExpr e
where e.getRValue().getValue().toInt() = 0
select e
  • 特殊表达式
示例
NewExpr new int[x]
DeleteExpr delete p
LambdaExpr [&](int x){...}

其它元素

  • 类型类
CodeQL 类 示例
PrimitiveType int
PointerType int*
ReferenceType int&
ArrayType int[10]
ClassType std::string
  • 预处理器类
CodeQL 类 示例
Macro #define X 1
MacroInvocation X
IncludeDirective #include <stdio.h>

自动化分析

使用 CodeQL 官方的 C/C++ 安全查询包分析目标数据库。

shell 复制代码
codeql database analyze test-db codeql/cpp-queries --format=sarifv2.1.0 --output=result.sarif

在 VSCode 中安装 SARIF Viewer 插件分析 result.sarif 文件。

Reference

CodeQL 入门和基本使用
适用于 C 和 C++ 的 CodeQL 库 --- CodeQL

[原创CodeQL入门 - U-Boot Challenge-二进制漏洞-看雪论坛-安全社区|非营利性质技术交流社区](https://bbs.kanxue.com/thread-277560.htm#msg_header_h1_3)

相关推荐
zyplayer-doc2 小时前
VuePress类静态文档站和动态知识库怎么选:两种技术路线的适用场景
javascript·人工智能·后端·安全·智能手机
KKKlucifer3 小时前
拨开接口黑盒迷雾:运营商第三方合作接口安全审计与准入管控落地实践
网络·人工智能·安全
小绫网络安全4 小时前
【每日一讲】学习网络安全的一些注意事项
网络·安全·web安全
SamChan907 小时前
PDF翻译API的JWT签名鉴权与速率限制设计:安全实战指南
网络·安全·pdf
Atomic121387 小时前
CVE 漏洞复现通论:从漏洞情报到 Root Cause 分析的标准化实战指南
web安全·网络安全·渗透测试
Python私教9 小时前
签名 URL 刷新导致审批失效?别急着删掉所有 query
python·安全
weixin_618232309 小时前
OpenAI 因安全暂停 Astra:前沿 Agent 第一次撞上“关键级”红线
安全
Python私教9 小时前
一次性批准令牌:挡住旧授权误发新版本的工程设计
python·安全
漫路在线10 小时前
无境红日靶场五 wp
网络·安全·web安全
AmyLin_200111 小时前
PDF 脱敏技术【1】:PDF 脱敏不是盖黑框:为什么敏感信息仍能被复制,正确的保护方式是什么?
安全·pdf·sdk·脱敏·文档安全·pdf 脱敏·智能脱敏