介绍
- 简介: 微软开发的 SAST 工具,将代码转化成一种关系型数据库,可用 QL 查询语句来查找符合特定模式的代码片段,通过这种方式查找漏洞。
- QL 语言: 一种面向对象的逻辑编程语言,语法类似于 SQL,但引入了类 (Class) 和谓词 (Predicate) 等概念。
- 下载: 使用 CodeQL CLI 或 VSCode 插件。
使用
- 下载 CodeQL CLI:
apt install codeql
- 使用 VSCode 导入数据库文件: 下载 CodeQL 插件,然后在左侧的 CodeQL 插件图标处,导入数据库。
- ql 查询: 编写 ql 查询脚本,右键 Run Query,查看执行结果。
-- 基础语法 --
文件
- .ql 文件: 查询文件,是 CodeQL 分析的执行入口。
- .qll 文件: 库文件,不包含查询语句,其中定义/封装类、谓词、模块等可复用的逻辑,供其他 ql/qll 文件引入 (import)。
- .qls 文件: 查询套件文件,本质上是 yaml 文件,用于批量管理/执行 ql 文件。
- .model.yml 文件: 通过 yaml 格式来定义污点。
- qlpack.yml: 用于定义一个 CodeQL 包,并定义该包的元数据和依赖关系。
- codeql-analysis.yml: 放在
.github/workflows/ 下,用于在代码仓库发生变动时,自动触发 CodeQL 对源代码进行静态分析。
指令
- 创建数据库:
codeql database create <数据库存放路径> --language=<语言> --source-root=<源码路径>
- 编译: 若源码是需编译/构建的语言 (如 C/C++/Java/Go),需要加上
--command="<编译/构建语句>" 来编译/构建,否则需要 --build-mode=none 显式指定不编译 (可能会导致漏测率上升);若是解释型语言 (如 JS/Py) 则无需。
- 编译语句: Java 常见语句为
mvn clean package -DskipTests。
- 覆盖: 加上
--overwrite 让目标数据库目录已存在时进行覆盖。
- 运行查询脚本
- 单个 ql 文件:
codeql database analyze <数据库存放路径> --format=<格式,常为sarif-latest> --output=<输出文件名> --query=<ql文件路径>
- qls 文件:
codeql database analyze <数据库存放路径> --format=<格式,常为sarif-latest> --output=<输出文件名> <qls文件路径>
- 注: qls 文件路径可为 系统绝对/相对路径,也可为
<包名>:<相对于包的路径>。
ql/qll 基础
- from-where-select
- 简介: 是 CodeQL 的基本查询结构,执行时实际将数据库中所有类型匹配的元素筛选出来。
- 定义:
from <数据类型> <变量名> (每个变量都代表代码中的实体,如方法、类),执行时会自动给变量赋值,值为数据类型匹配的所有元素组成的集合。
- 筛选:
where <条件语句> 执行后会去除变量 (也即集合) 中不匹配的元素,若条件语句中包含多个变量,则只会留下匹配的元素的组合。
- 输出:
select <值>,... 执行后输出对应的值。
- 条件判断:
- 逻辑连接词:
and (与)、or (或)、not (非)、implies (蕴含,A implies B <==> (not A) or B)。
- 比较运算符:
=、!=、<、>、<=、>=。
- 条件表达式:
if ... then ... else (相当于三目运算符)。
- 集合判断符:
<Var> in <集合> 约束变量中的元素属于集合。
- 类型判断符:
<Var> instanceof <数据类型/类> 约束一个变量是否属于某种类型 (本质是约束集合中元素是否属于数据类型/类的范围内)。
- 量词 (Quantifiers)
- 简介: 常用于 where 的条件语句中,允许引入临时变量来进行筛选。
- 存在量词 (exists):
exists(<变量声明> | <条件>) 筛选满足条件的情况,若满足条件则返回 true。
- 全称量词 (forall):
forall(<变量声明> | <限定范围> | <检查条件>) 筛选 <限定范围> 集合中的所有元素都满足条件的情况,若所有都满足才返回 true。
- 注:
<限定范围> 是将声明的临时变量中的集合进行缩小/限制,<检查条件> 检查的是缩小后的集合中的所有元素。
- 谓词 (Predicates)
- 简介: 类似其他语言中的函数,用于封装逻辑。
- 无结果谓词:
predicate <谓词>(<形参数据类型> <形参名>,...){...} 常用于 where 条件语句中,来限制变量集合。
- 有结果谓词:
<数据类型> <谓词>(<形参数据类型> <形参名>,...){...} 内部全为条件语句,用于限制 result 集合 (可看作全集集合) 并返回。
- 调用:
<谓词>(实参,...)。
- 传递闭包: (此处待补充)。
- 聚合词: 对变量中的集合元素进行计算,本质类似函数。
- count: 返回元素的数量。
- min/max: 返回最小/最大的元素。
- sum: 返回元素的总和。
- avg: 返回元素的平均值。
- concat: 拼接字符串。
- 数据类型
- 简介: CodeQL 中的所有数据类型本质都为对应数据的集合,因此 CodeQL 中传递/操作的值都为集合 (字面量值也只是只有一个对应元素的集合)。
- 基础类型:
boolean (true/false)、int (整数)、float (浮点数)、string (字符串)、date (日期)。
- 实体类型: CodeQL 数据库将代码解析为抽象语法树 (AST),标准库为 AST 节点提供了对应的类。
- Java 实体类型: 函数 (Function)、方法 (Method)、函数调用 (Call)、类 (Class)、表达式 (Expr)、语句 (Stmt)。
- Python 实体类型: Function、Class、Call、Attribute。
- 类型转换:
<变量>.(<目标类型>) 转换后会自动调用子类的特征谓词来限制变量,通常用于父类转换为子类来调用子类的谓词。
- 注: 类型转换本质相当于取变量与目标类型两个集合的交集。
- 类 (Classes)
- 简介: CodeQL 中类是为了定义一个新的数据类型,也即为了能够自定义变量被系统自动赋予的值 (集合)。
- 定义:
class <类名> extends <父类名>{...}。
- 继承: 类必须使用
extends <父类名> 继承某个类/数据类型,会继承父类的所有谓词,也可以重写父类的谓词 (需要添加 override 关键词)。
- 特征谓词: 与类名同名的谓词,无参数且无结果 (返回值),会将父类所代表的集合的范围通过特征谓词限制,用于定义该类所代表的集合的范围 (所以特征谓词是唯一一种无法获取调用其的对象集合范围之外的集合的谓词)。
- 成员谓词: 定义在类中的谓词。
- this 对象: 在特征谓词/成员谓词中可调用,代表当前对象 (集合)。
- 调用成员谓词:
对应数据类型的变量.成员谓词名(实参,...)。
- 抽象类: 加上
abstract 关键词来定义,不能包含特征谓词,成员谓词可包含/可不包含谓词体,其子类必须覆盖 (Override) 不包含谓词体的谓词,抽象类的范围会被判定为其所有非抽象子类范围的并集。
- 模块
- 简介: 用于组织 QL 代码,封装和复用逻辑,并防止命名冲突,分为文件级模块/显式模块/参数化模块。
- 文件级模块: 每个 .ql 或 .qll 文件本身都换算作一个模块 (模块名即文件名)。
- 显式模块: 在文件中使用
module <模块名> {...} 来显式定义模块。
- 导入:
import <模块名> (每个 ql 文件都需要导入对应编程语言的标准库,即 import java/python/cpp/javascript)。
- 调用模块中的成员:
<模块名>::<成员名>。
- 接口
- 简介: 用来描述一个作为参数的模块必须满足的“形状” (而非类)。
- 定义:
signature module <接口名> {...}。
- 实现:
module <模块名> implements <接口名> { ... }。
- 特征: 可包含普通谓词/类/类中的成员谓词,不能包含类中的特征谓词,其内谓词都不能包含谓词体 (除非使用 default,用 default 可定义默认实现,实现模块可以选择性地覆盖它,或者直接继承使用)。
- 定义参数化模块:
module 模块名<需实现的接口名 模块参数名,...> {} 参数化模块必须传入实现了特定接口的模块作为参数。
- 实例化参数化模块:
module 变量名 = 模块名<参数,...>。
.qls 基础
- 注: 可用
codeql resolve queries <qls文件> 来查看具体选中了哪些查询文件。
- description: "<qls文件描述>"
# 导入(可指定包/qls文件/目录路径,指定包会导入其内所有ql查询文件,若指定目录则会导入指定目录下的所有ql查询文件)
- import: codeql/java-queries
# 导入指定包中的指定ql/qls查询文件
- import: codeql-suites/java-security-and-quality.qls
from: codeql/java-queries
- query: ./my-custom-queries/DetectBackdoor.ql # 引入单个ql查询(通过文件路径)
- queries: ./my-custom-queries/DetectBackdoor.qls # 引入单个qls查询(通过文件路径)
# 在当前已引入查询文件中,只保留符合条件的查询(这些条件都来源于ql文件头部定义的元数据)
- include:
id: # 查询的唯一标识符(支持通配符),一般为<语言>/<漏洞类别>
java/*-injection
...
severity: # 严重程度(一般为error,warning,recommendation)
error
...
precision: # 准确度(一般为very-high,high,medium,low)
high
...
kind: # 查询类型(一般为problem,path-problem,diagnostic,metric)
problem
...
tags: # 查询的标签
cwe-79
...
# 在当前已引入查询文件中,排除符合条件的查询
- exclude:
... # 跟include相同
.model.yml 基础
- 作用: 用于直接扩展包的 sink/source 等,来优化查询。其原理是在运行
codeql database analyze 时,CodeQL 会扫描当前环境下的所有 CodeQL Packs,扫描到的 .model.yml,其数据会被填充到 extensible_summaryModel 这个表中。在执行 isSource/isSink/isAdditionalTaintStep 时,都会自动查表来影响执行效果。
- 特点: 只能用于扩展包的 sink/source/summary/neutral,无法做到删除/覆盖对应查询套件中的 sink/source/additionalTaintStep。
- pack: 指定 CodeQL 中需要扩展的包的名称 (只能填包名,不能指定 qls/ql/qll 文件),一般填写对应语言包。
- extensible: 指定扩展的模型类型。
sourceModel: 用于定义哪些方法的哪些参数/返回值为污染源,影响污点配置类中的 isSource 方法。
sinkModel: 用于定义哪些方法的哪些参数为汇聚点,影响污点配置类中的 isSink 方法。
summaryModel: 用于定义哪些方法的哪些参数为污点时,对应方法的哪些参数/返回值也会成为污点,来连接断裂的数据流,影响污点配置类中的 isAdditionalTaintStep 方法。
neutralModel: 用于定义哪些方法是安全的,其内部污点不会传播/不会存在 source 点/不会存在 sink 点,影响污点配置类中的 isAdditionalTaintStep 方法。看似和 isBarrier 相同 (isBarrier 代表污点被清洗/阻断),但 neutral 无法根据具体的 sink/source 来进行阻断,而是一刀切的方式,滥用会导致漏测率上升。
- 数据定义: 用于定义具体扩展的模型数据。
- 格式:
["包名", "类名", 是否涵盖对应类的子类, "方法名", "参数签名", "扩展字段", "输入位置", "输出位置", "类型", "来源标识"]
- 注:
sourceModel 没有输入位置,sinkModel 没有输出位置,summaryModel 有输入/输出位置,neutralModel 没有输入/输出位置。
- 包名/类名/是否涵盖子类/方法名/参数签名: 用于定位具体的方法 (若参数签名为
"",则不限制参数签名)。
- 扩展字段: 一般留空。
- 输入/输出位置:
Argument[n] 代表第 n+1 个参数,Argument[this]/Argument[-1] 代表对象本身,ReturnValue 代表返回值 (只有输出位置可用)。
- 输入/输出位置 (特殊):
.Element 表示集合或数组中的元素,.Field[name] 表示对象的特定字段,.MapKey/.MapValue 表示 Map 的键或值。
- 类型:
sourceModel (remote 为远程输入,database 为数据库读取);sinkModel (具体的漏洞类型名);summaryModel (taint 为污点传播,value 为值保留);neutralModel (summary 为污点不会传播,sink 为不会存在 sink 点,source 为不会存在 source 点)。
- 来源标识: 用于标记这条规则是谁写的,便于调试和合并,manual 为人工手写,df-generated 为工具生成,model-generator 为模型自带。
- 格式 (例子)
extensions:
- addsTo:
pack: codeql/java-all # 指定要扩展的基础包
extensible: sinkModel # 指定扩展的模型类型(sourceModel/sinkModel/summaryModel/neutralModel)
- ["org.json", "JSONObject", True, "getString", "(String)", "", "Argument[this]", "ReturnValue", "taint", "manual"]
- ... # 包含具体的模型数据,通常是一个多列的元组列表
extensible: ...
- ...
- addsTo:
...
qlpack.yml 文件
- 简介: 用于定义一个包,声明了包的名称、版本以及它所依赖的其他包。
- 修改 qlpack.yml:
- 可手动修改
qlpack.yml 中的内容,此时需要运行 codeql pack install 来下载依赖。
- 可运行
codeql pack add <包名> (默认最新版本) 或 codeql pack add <包名>@<版本> (指定版本),会自动将依赖写入 qlpack.yml 并下载包。
- 包: 分为查询包/库包/扩展包。
- 查询包:
- 定义: 包含一组可执行查询的包,包含各种 ql/qls 文件,用于生成查询结果。
- 使用: 通过
codeql database analyze <数据库> <包名> ... 来使用,或者将 包名 改为 包名:包内qls路径 来使用包内指定 qls 文件。
- 注: 使用时会使用包内
default-suite 中指定的 qls 文件,若不存在该字段则使用 default.qls,若 default.qls 还不存在,则使用包内所有 ql 文件。
# 查询包pack.yml文件格式
name: my-company/my-custom-queries # 包名
version: 1.0.0 # 版本
dependencies: # 依赖,可在包内ql/qll/qls文件中引用
codeql/java-all: "*"
<包名>: "<版本>" # *代表最新版本
...
default-suite: <qls文件路径> # 可选,指定使用包时使用的
- 库包:
- 定义: 包含 qll 文件,定义类/谓词等,供 ql 文件引用 (qll 文件一般放在 libraries 文件夹中)。
- 使用: 在其他包中的
qlpack.yml 中的 dependencies 中引用来使用。
# 库包pack.yml文件格式
name: my-company/my-custom-queries # 包名
version: 1.0.0 # 版本
library: true # 设为true表示这是一个库,不包含可执行查询(防止CodeQL把这个包当作扫描包来运行,对于库包,必须设为true)
dependencies: # 依赖,可在包内ql/qll/qls文件中引用
codeql/java-all: "*"
<包名>: "<版本>" # *代表最新版本
...
- 扩展包:
- 定义: 包含
.model.yml 的文件,用于扩展其他包 (.model.yml 文件一般放在 models 文件夹中)。
- 使用: 使用
codeql database analyze 时通过 --search-path 来指定使用。
# 扩展包pack.yml文件格式
name: my-company/java-extensions # 包名
version: 1.0.0 # 版本
library: true # 设为true表示这是一个库,不包含可执行查询(防止CodeQL把这个包当作扫描包来运行,对于扩展包,必须设为true)
extensionTargets: # 声明扩展目标(当执行的ql文件加载了以下库其中之一时,就加载该包内容,不管他有没有显式引用这个扩展包)
codeql/java-all: "*"
...
dependencies: # 依赖项
codeql/java-all: "*"
...
-- 污点 --
简介
- 概念: 追踪不可信数据 (污点) 在程序中的传播路径,判断其是否在未经过滤的情况下流向了危险执行点。
污点
- Source (污点源): 外部不可信数据的入口。
- Sink (汇聚点): 污染导致危害的地方,即漏洞触发点。
- Barrier (阻断点): 切断污点传播的地方,一旦污点经过,污点就会被认为是安全的。
- Sanitizer (清洗器): Barrier 的一种,通过改变数据本身,使其变为安全 (如 XSS 进行 HTML 编码)。
- Guard (卫语句): Barrier 的一种,数据本身不变,但在特定控制流分支下被视为安全 (如用 if 语句配合黑名单检测)。
- SanitizerFlows/Flow Labels (带标签的清洗): 辅助 Barrier,给污点打上标签 (Label),定义 Barrier 可以只阻断带有特定 Label 的污点,而放行其他污点 (用于针对类似 HTML 编码防止 XSS,但防不了 SQL 注入的情况)。
- AdditionalTaintStep (额外传播步): 类似反向 Barrier,当 CodeQL 无法自动推断数据流 (例如通过了一个复杂的字符串处理函数,或者存入数据库再取出来) 时,可定义 AdditionalTaintStep 手动连接断开的两个点。
流类型
- Flow (数据流): 数据从 Source 传播到 Sink 的具体路径。
- AST (抽象语法树): 源代码的树状表现形式,节点代表语法单元,边代表包含关系,描述了代码的语法结构和父子层级关系。
- CFG (控制流图): 节点为基本块 (一段“要么全执行,要么全不执行”的直线代码),边代表执行流的跳转 (常见于 if/while/for 等),描述了程序执行的顺序和逻辑跳转。
- DFG (数据流图): 节点为变量的定义/使用,边代表数据流向,描述了变量的值如何在 CFG 的不同节点之间传递。
.ql 污点追踪
Expr asExpr()
// 作用:获取节点对应的表达式
Parameter asParameter()
// 作用:获取节点对应的函数参数
- DataFlow::ConfigSig 接口
- 简介: 规定了进行全局数据流分析或污点追踪时,必须提供的谓词集合。
- DataFlow 常用谓词
DataFlow::Node exprNode(Expr e)
// 作用:将Expr包装成DataFlow::Node节点
DataFlow::Node parameterNode(Parameter p)
// 作用:将Parameter包装成DataFlow::Node节点
- TaintTracking::Configuration 类
- 简介: 抽象类,用于定义污点追踪 (source/sink/清洗/传播) 规则的“配置容器”。
- TaintTracking::Global 模块
- 简介: 参数模块,接收实现了
DataFlow::ConfigSig 接口的模块作为参数,实例化生成一个专属的污点分析模块。
- 定义污点配置 (旧版
TaintTracking::Configuration)
- 简介: 配置类继承
TaintTracking::Configuration 抽象类。
// 元数据,供qls文件来批量操作
/**
* @name SQL injection
* @description ...
* @kind path-problem
* @problem.severity error
* @precision high
* @id java/sql-injection
* @tags security
* external/cwe/cwe-89
*/
import semmle.code.java.dataflow.TaintTracking // 引入污点追踪组件
// 定义污点配置类(需要继承TaintTracking::Configuration)
class <配置类名> extends TaintTracking::Configuration {
// 通过特征谓词来给配置实例起一个唯一的字符串标识,CodeQL内部通过这个字符串区分不同的污点分析配置
<配置类名>() { this = "<字符串标识>" }
// 通过重写isSource谓词定义污点源
override predicate isSource(DataFlow::Node source){
...
}
// 通过重写isSink谓词定义汇聚点
override predicate isSink(DataFlow::Node sink){
...
}
// 通过重写isSanitizer谓词定义清洗点(可选)
override predicate isSanitizer(DataFlow::Node sanitizer){
...
}
}
// 定义配置类/污点源/汇聚点的变量
from <配置类名> cfg, DataFlow::Node source, DataFlow::Node sink
// 查询(调用配置类的hasFlow)
where cfg.hasFlow(source, sink)
// 输出
select sink, source, sink, "Found taint flow from $@", source, "here"
- 定义污点配置 (新版
TaintTracking::Global)
// 元数据,供qls文件来批量操作
/**
* @name SQL injection
* @description ...
* @kind path-problem
* @problem.severity error
* @precision high
* @id java/sql-injection
* @tags security
* external/cwe/cwe-89
*/
import java
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.dataflow.DataFlow
// 定义配置模块(实现DataFlow::ConfigSig签名接口)
module <配置模块名> implements DataFlow::ConfigSig {
// 注意:新版不需要构造函数来定义"this = string"唯一标识
// 通过实现isSource谓词定义污点源
predicate isSource(DataFlow::Node source) {
...
}
// 通过实现isSink谓词定义汇聚点
predicate isSink(DataFlow::Node sink) {
...
}
// 通过实现isBarrier谓词定义清洗点/阻断点(可选)
predicate isBarrier(DataFlow::Node node) {
...
}
}
// 实例化分析模块,将配置模块传入Global模板,生成一个专属的污点分析模块
module <分析流模块名> = TaintTracking::Global<<配置模块名>>;
// 引入专属路径图(必须引入由上面实例化的模块生成的PathGraph,而不是通用的DataFlow::PathGraph)
import <分析流模块名>::PathGraph
// 定义污点源/汇聚点的变量
from <分析流模块名>::PathNode source, <分析流模块名>::PathNode sink
// 查询(调用模块内的flowPath)
where <分析流模块名>::flowPath(source, sink)
// 输出
select sink.getNode(), source, sink, "Found taint flow from $@", source, "here"
污点追踪方法
- 官方查询组件:
codeql/java-queries:codeql-suites/java-security-extended.qls (包含基础的各种通用漏洞查询规则 122 条,误报率低)。
codeql/java-queries:codeql-suites/java-security-experimental.qls (包含基础的 122 条+实验性规则 55 条,误报率中,但测试范围广)。
- 挖 CVE 的方法:
- 写一个 qls 文件,引用
codeql/java-queries:codeql-suites/java-security-experimental.qls,并尝试用该 qls 文件查询。
- 根据查询情况,通过在 qls 中用
exclude 来去除没有必要的查询。
- 根据漏报情况,通过写
.model.yml 文件,并在查询时引用来改善。
- 根据误报情况,找到对应的 ql 文件,在 qls 文件中
exclude 该 ql 查询,然后自己创建一个 ql 文件 (内容复制对应 ql 文件),并手动更改内容后在 qls 中引用。
-- AST 实体数据类型 --
继承关系
classDiagram
Element <|-- File
Element <|-- Type
Element <|-- Variable
Element <|-- Callable
Element <|-- Stmt
Element <|-- Expr
Type <|-- PrimitiveType
PrimitiveType <|-- int
PrimitiveType <|-- boolean
PrimitiveType <|-- 等等
Type <|-- RefType
RefType <|-- Class
RefType <|-- Interface
Variable <|-- Field
Variable <|-- Parameter
Variable <|-- LocalVariableDecl
Callable <|-- Method
Callable <|-- Constructor
Expr <|-- Call
Call <|-- MethodAccess
Call <|-- ConstructorCall
Expr <|-- VarAccess
Expr <|-- Literal
Expr <|-- BinaryExpr
Stmt <|-- IfStmt
Stmt <|-- Block
Stmt <|-- ReturnStmt
Element
Location getLocation()
// 作用:获取代码行号、列号等位置信息
File getFile()
// 作用:获取元素所属的File对象
string toString()
// 作用:获取该元素的字符串表示
Element getParent()
// 作用:获取在AST树中的直接父节点
File
string getAbsolutePath()
// 作用:获取文件的绝对路径
string getRelativePath()
// 作用:获取相对于项目根目录(数据库根目录)的相对路径
string getExtension()
// 作用:获取文件的后缀名 (如 "java", "xml", "py")
string getStem()
// 作用:获取文件名中不包含后缀的部分
int getNumberOfLines()
// 作用:获取文件总行数
RefType (Class/Interface)
- 简介: 表示引用类型,通常指类 (Class)、接口 (Interface) 或枚举。
string getPackageName()
// 作用:获取该类所属的包名
string getQualifiedName()
// 作用:获取类的全限定名
RefType getASupertype()
// 作用:获取该类的直接父类或实现的接口(可能返回多个结果)
Method getAMethod()
// 作用:获取该类中声明的任意一个方法
Field getAField()
// 作用:获取该类中声明的任意一个字段
isInterface() / isClass()
// 作用:判断具体是不是接口/类
Callable
- 简介: 表示可调用的代码单元,是
Method (方法) 和 Constructor (构造函数) 的父类。
string getName()
// 作用:获取方法或函数的名称
RefType getDeclaringType()
// 作用:获取定义该方法的类或接口类型
Type getReturnType()
// 作用:获取返回值的类型
Parameter getParameter(int i)
// 作用:获取该方法的第i个参数对象(索引从0开始)
int getNumberOfParameters()
// 作用:获取该方法的参数总数量
Block getBody()
// 作用:获取该方法的方法体代码块
isStatic()
// 作用:判断是否为静态方法
Call
- 简介: 代表一次函数/方法 (包裹构造函数) 的调用表达式。
Callable getCallee()
// 作用:获取被调用的目标(包含方法和构造函数)
int getNumberOfArguments()
// 作用:获取参数数量
MethodAccess
- 简介: 表示一次函数/方法 (不包括构造函数) 的调用表达式,Call 的子类。
Method getMethod()
// 作用:获取被调用的目标方法实体(静态绑定结果)
Expr getArgument(int i)
// 作用:获取调用时传入的第i个参数的表达式
Expr getQualifier()
// 作用:获取方法调用的限定符(即调用该方法的对象实例,如 a.b() 中的 a)
int getNumArgument()
// 作用:获取调用时传入的参数数量
Field
Type getType()
// 作用:获取该字段声明的数据类型
RefType getDeclaringType()
// 作用:获取该字段属于哪个类
boolean isStatic()
// 作用:判断该字段是否为静态(static)
Expr getAnAccess()
// 作用:获取对该字段的任意一次读写访问表达式
Expr getInitializer()
// 作用:获取字段的初始化表达式(如 int a = 10; 中的10)
Expr
Type getType()
// 作用:获取该表达式计算结果的类型
Element getParent()
// 作用:获取包含该表达式的父节点
Container getEnclosingCallable()
// 作用:获取该表达式所处的函数/方法
Stmt
- 简介: 语句,标识程序执行的控制流单元 (如 if/for/return 等)。
Container getEnclosingCallable()
// 作用:获取包含该语句的方法或构造函数
Stmt getEnclosingStmt()
// 作用:获取包裹该语句的外层语句
Variable
- 简介: 变量的抽象基类,
Field (字段)、Parameter (参数) 和 LocalVariable (局部变量) 通常都继承自它。
Type getType()
// 作用:获取变量类型
string getName()
// 作用:获取变量名称
Expr getAnAccess()
// 作用:获取对该变量的任意访问
Expr getInitializer()
// 作用:获取变量初始化表达式
Location
int getStartLine()
// 作用:获取代码起始的行号
int getEndLine()
// 作用:获取代码结束的行号
int getStartColumn()
// 作用:获取代码起始的列号
int getEndColumn()
// 作用:获取代码结束的列号
-- 常见污点辅助模块 --
- 污点源 (java) -
- RemoteFlowSource:
- 作用: 涵盖了多种远程输入的情况。
- 范围: 包含 Spring Boot (Controller 参数)、Servlet (request.getParameter)、Struts2 等几十种常见 Web 框架的远程输入源 (可覆盖 90% 以上 Web 攻击面)。
- LocalUserInput:
- 作用: 包含了多种来自本地用户的输入的情况,常用于分析本地提权或命令行注入。
- 范围: 命令行参数 (
public static void main(String[] args))、环境变量 (System.getenv())、标准输入流 (System.in, Scanner 等)、本地文件读取 (在某些上下文中,不可信的文件内容也被视为本地输入)。
- DatabaseInput:
- 作用: 包含了多种来自数据库输入的情况,常用于检测存储型 XSS 或 SQL 二次注入。
- 其他 (semmle.code.java.security) -
Web 安全与通用漏洞
| 漏洞类型 |
Query 模块 |
基础模块 |
Sink |
Barrier (Sanitizer) |
AdditionalFlowStep |
| SQL 注入 |
SqlInjectionQuery.qll |
QueryInjection.qll |
QueryInjectionSink<br>SqlInjectionSink<br>PersistenceQueryInjectionSink |
SimpleTypeSanitizer<br>QueryInjectionSanitizer |
AdditionalQueryInjectionTaintStep |
| XSS |
XssQuery.qll |
XSS.qll |
XssSink<br>DefaultXssSink |
XssSanitizer<br>XssSinkBarrier |
XssAdditionalTaintStep |
| 命令注入 |
CommandLineQuery.qll |
- |
CommandInjectionSink<br>DefaultCommandInjectionSink |
CommandInjectionSanitizer<br>SimpleTypeSanitizer |
CommandInjectionAdditionalTaintStep |
| SSRF |
RequestForgery.qll |
- |
RequestForgerySink<br>sinkNode("request-forgery") |
RequestForgerySanitizer<br>SimpleTypeSanitizer |
RequestForgeryAdditionalTaintStep |
| LDAP 注入 |
LdapInjectionQuery.qll |
LdapInjection.qll |
LdapInjectionSink |
LdapDnInjectionSanitizer<br>LdapSearchInjectionSanitizer |
- |
| XPath 注入 |
XPathInjectionQuery.qll |
XPath.qll |
XPathInjectionSink |
XPathInjectionSanitizer |
- |
| XSLT 注入 |
XsltInjectionQuery.qll |
XsltInjection.qll |
XsltInjectionSink |
- |
- |
| JNDI 注入 |
JndiInjectionQuery.qll |
JndiInjection.qll |
JndiInjectionSink |
JndiInjectionSanitizer |
- |
| HTTP 响应分割 |
ResponseSplittingQuery.qll |
ResponseSplitting.qll |
HeaderSplittingSink |
ResponseSplittingSanitizer |
- |
| URL 重定向 |
UrlRedirectQuery.qll |
UrlRedirect.qll |
UrlRedirectSink |
UrlRedirectSanitizer |
- |
| URL 转发 |
UrlForwardQuery.qll |
- |
UrlForwardSink |
- |
- |
| 格式化字符串 |
ExternallyControlledFormatStringQuery.qll |
- |
ExternallyControlledFormatStringSink |
- |
- |
| CSRF 防护缺失 |
CsrfUnprotectedRequestTypeQuery.qll |
SpringCsrfProtection.qll |
(检测配置项,非数据流 Sink) |
- |
- |
Java 安全
| 漏洞类型 |
Query 模块 |
基础模块 |
Sink |
Barrier (Sanitizer) |
AdditionalFlowStep |
| SpEL 注入 |
SpelInjectionQuery.qll |
SpelInjection.qll |
SpelExpressionEvaluationSink |
SpelInjectionSanitizer |
SpelExpressionInjectionAdditionalTaintStep |
| MVEL 注入 |
MvelInjectionQuery.qll |
MvelInjection.qll |
MvelEvaluationSink |
MvelInjectionSanitizer |
- |
| Groovy 注入 |
GroovyInjectionQuery.qll |
GroovyInjection.qll |
GroovyInjectionSink |
GroovyInjectionSanitizer |
GroovyInjectionAdditionalTaintStep |
| 模板注入 |
TemplateInjectionQuery.qll |
TemplateInjection.qll |
TemplateInjectionSink |
TemplateInjectionSanitizer |
TemplateInjectionAdditionalTaintStep |
| JEXL 注入 |
JexlInjectionQuery.qll |
- |
JexlEvaluationSink |
- |
JexlInjectionAdditionalTaintStep |
| OGNL 注入 |
OgnlInjectionQuery.qll |
OgnlInjection.qll |
OgnlInjectionSink |
- |
- |
文件与 IO 安全
| 漏洞类型 |
Query 模块 |
基础模块 |
Sink |
Barrier (Sanitizer) |
AdditionalFlowStep |
| 路径遍历 |
TaintedPathQuery.qll |
- |
sinkNode("path-injection") |
PathSanitizer<br>PathInjectionSanitizer |
TaintedPathAdditionalTaintStep |
| Zip Slip |
ZipSlipQuery.qll |
- |
ZipSlipSink |
- |
- |
| 不安全反序列化 |
UnsafeDeserializationQuery.qll |
- |
UnsafeDeserializationSink |
SimpleTypeSanitizer |
- |
| XXE |
XxeQuery.qll |
Xxe.qll |
XxeSink |
XxeSanitizer |
- |
| 日志注入 |
LogInjectionQuery.qll |
LogInjection.qll |
LogInjectionSink |
LogInjectionSanitizer |
LogInjectionAdditionalTaintStep |
| 部分路径遍历 |
PartialPathTraversalQuery.qll |
PartialPathTraversal.qll |
(验证逻辑缺陷 Sink) |
- |
- |
安卓安全
| 漏洞类型 |
Query 模块 |
基础模块 |
Sink |
Barrier (Sanitizer) |
AdditionalFlowStep |
| Intent 重定向 |
AndroidIntentRedirectionQuery.qll |
AndroidIntentRedirection.qll |
AndroidIntentRedirectionSink |
AndroidIntentRedirectionSanitizer |
AndroidIntentRedirectionAdditionalFlowStep |
| Fragment 注入 |
FragmentInjectionQuery.qll |
FragmentInjection.qll |
FragmentInjectionSink |
- |
FragmentInjectionAdditionalFlowStep |
| 任意 APK 安装 |
ArbitraryApkInstallationQuery.qll |
ArbitraryApkInstallation.qll |
ArbitraryApkInstallationSink |
- |
- |
| 隐式 PendingIntent |
ImplicitPendingIntentsQuery.qll |
ImplicitPendingIntents.qll |
ImplicitPendingIntentSink |
- |
- |
| URI 权限操纵 |
IntentUriPermissionManipulationQuery.qll |
IntentUriPermissionManipulation.qll |
IntentUriPermissionManipulationSink |
- |
- |
| Content URI 解析 |
UnsafeContentUriResolutionQuery.qll |
UnsafeContentUriResolution.qll |
UnsafeContentUriResolutionSink |
- |
- |
| 明文存储 (DB) |
CleartextStorageAndroidDatabaseQuery.qll |
- |
CleartextStorageAndroidDatabaseSink |
- |
- |
| 敏感通信 |
AndroidSensitiveCommunicationQuery.qll |
- |
SensitiveCommunicationSink |
- |
- |
| WebView 调试 |
WebviewDebuggingEnabledQuery.qll |
- |
WebviewDebuggingEnabledSink |
- |
- |
| 证书绑定失效 |
AndroidCertificatePinningQuery.qll |
- |
(配置检查 Sink) |
- |
- |
密码学安全
| 漏洞类型 |
Query 模块 |
基础模块 |
Sink |
Barrier (Sanitizer) |
AdditionalFlowStep |
| 弱加密算法 |
BrokenCryptoAlgorithmQuery.qll |
- |
(算法名称常量 Sink) |
- |
- |
| 密钥长度不足 |
InsufficientKeySizeQuery.qll |
InsufficientKeySize.qll |
InsufficientKeySizeSink |
- |
- |
| 不安全随机数 |
InsecureRandomnessQuery.qll |
RandomDataSource.qll |
InsecureRandomnessSink |
- |
InsecureRandomnessAdditionalFlowStep |
| 静态 IV |
StaticInitializationVectorQuery.qll |
- |
StaticInitializationVectorSink |
- |
- |
| 证书信任问题 |
UnsafeCertTrustQuery.qll |
UnsafeCertTrust.qll |
UnsafeCertTrustSink |
UnsafeCertTrustSanitizer |
- |
| 主机名验证 |
UnsafeHostnameVerificationQuery.qll |
- |
UnsafeHostnameVerificationSink |
- |
- |
| JWT 签名缺失 |
MissingJWTSignatureCheckQuery.qll |
JWT.qll |
JwtSignatureCheckSink |
- |
- |
| Basic Auth |
InsecureBasicAuthQuery.qll |
InsecureBasicAuth.qll |
InsecureBasicAuthSink |
- |
- |
| LDAP 明文认证 |
InsecureLdapAuthQuery.qll |
InsecureLdapAuth.qll |
InsecureLdapAuthSink |
- |
- |
敏感数据
| 漏洞类型 |
Query 模块 |
基础模块 |
Sink |
Barrier (Sanitizer) |
AdditionalFlowStep |
| 硬编码凭证 |
HardcodedCredentialsSourceCallQuery.qll |
HardcodedCredentials.qll |
HardcodedCredentialSink |
- |
- |
| 明文存储 (通用) |
CleartextStorageQuery.qll |
CleartextStorageClass.qll |
CleartextStorageSink |
CleartextStorageSanitizer |
CleartextStorageAdditionalFlowStep |
| 敏感日志 |
SensitiveLoggingQuery.qll |
- |
SensitiveLoggerSink |
- |
- |
| 敏感 UI 显示 |
SensitiveUiQuery.qll |
SensitiveUiQuery.qll |
SensitiveUiSink |
- |
- |
| 报错信息泄露 |
SensitiveDataExposureThroughErrorMessageQuery.qll |
- |
(异常消息返回 Sink) |
- |
- |
| 键盘缓存 |
SensitiveKeyboardCacheQuery.qll |
- |
SensitiveKeyboardCacheSink |
- |
- |
| 信任边界破坏 |
TrustBoundaryViolationQuery.qll |
- |
TrustBoundaryViolationSink |
TrustBoundaryViolationSanitizer |
- |
| 环境变量污染 |
TaintedEnvironmentVariableQuery.qll |
- |
TaintedEnvironmentVariableSink |
TaintedEnvironmentVariableSanitizer |
- |
| 临时目录泄露 |
TempDirLocalInformationDisclosureQuery.qll |
TempDirUtils.qll |
TempDirLocalInformationDisclosureSink |
TempDirLocalInformationDisclosureSanitizer |
- |
| Actuator 泄露 |
SpringBootActuatorsQuery.qll |
- |
(端点配置 Sink) |
- |
- |
| Bean 验证绕过 |
InsecureBeanValidationQuery.qll |
- |
InsecureBeanValidationSink |
- |
- |