跳转到内容
Go back

CodeQL 使用札记

更新于:

CodeQL 使用札记

CodeQL 是一个语义代码分析引擎,它可以扫描发现代码库中的漏洞;通过对项目源码(C/C++、C#、golang、java、JavaScript、typescript、python)进行完整编译,并在此过程中把项目源码文件的所有相关信息(调用关系、语法语义、语法树)存在数据库中,然后编写 QL 代码或使用自带的 QL 规则查询该数据库来发现安全漏洞。

官方文档:

快速使用命令

整个工作流程主要分为两步:

  1. 提取创建数据库
  2. 编写 QL 语句进行查询

编译代码,生成数据库

codeql database create <database-folder> --language=cpp --command=<prefix command>

# 方式1
codeql database create webgoat-ql -l java

# 方式2
codeql database create xxx-database   --language="java"   --command="mvn clean install --file pom.xml" --source-root=文件目录

# 方式3
codeql database create test --language=java --command="mvn clean compile --file pom.xml -Dmaven.test.skip=true" --source-root=../micro_service_seclab/

codeql database create 支持 --overwrite 标志

    --no-overwrite
    [Advanced]  If  the  database  already  exists,  delete  it  and  
    proceed  with  this  command  instead  of  failing.  
    If  the  directory  exists,  but  it  does  not  look  like  a  database,  
    an  error  will  be  thrown.

对于 Java 语言的 Maven 项目使用如下命令即可:

codeql database create --language java --source-root . --command 'mvn clean install -f "pom.xml"   -U -B -V -e -Dfindbugs.skip -Dcheckstyle.skip -Dpmd.skip=true -Dspotbugs.skip -Denforcer.skip -Dmaven.javadoc.skip -DskipTests -Dmaven.test.skip.exec -Dlicense.skip=true -Drat.skip=true -Dspotless.check.skip=true' xxx-db

参数说明:

如果省略 --command 参数,则 codeQL 会自动检测并使用自己的工具来构建。但还是强烈推荐使用自己自定义的参数,尤其是大项目时。

生成 Java 项目的数据库时,之所以使用手动输入编译命令的方式,是因为当项目使用 Maven Wrapper 时,自动编译脚本会使用 mvnw 命令进行编译,此时会拉取相应版本的 maven 安装包,这个过程需要很长的时间,而且意义不大,因此使用上述命令是最高效的方式。

在较新的 codeql 版本中,codeql 支持在不构建代码的情况下生成数据库,实测对于源码项目,这种无构建模式形成数据库非常缓慢,效果聊胜于无。 可能对于 jar、war 等格式的二进制包的构建效果会比较好,待进一步测试和确认

无构建模式的示例命令:

codeql database create db-name --language=java --source-root=./sources --build-mode=none

分析数据库,生成结果

使用如下命令查询第三步生成的数据库:

codeql database analyze xxx-db $CODEQL_HOME/qlpacks/codeql/$LANGUAGE-queries/0.8.13/codeql-suites/$LANGUAGE-code-scanning.qls --format sarifv2.1.0 --output xxx.sarif

参数说明:

codeql database analyze 命令 不支持 --overwrite 标志

  • 原因analyze 命令不创建数据库,只是分析现有数据库,因此不需要 --overwrite 标志
  • 相关选项--no-rerun - 重新评估已有 BQRS 结果的查询

关于官方规则

codeql 官方规则中,存在两组安全规则

这两组规则的主要区别在于:experimental 目录下的规则是实验性质的,而 Security 目录下的规则是正式且稳定的。

批量查询

codeql database run-queries --ram=16384 --threads=12 XNU-database  --min-disk-free=1024 -v D:\codeql-starter\ql\java\ql\src\codeql-suites\java-security-extended.qls
codeql database run-queries --ram=16384 --threads=12 .\Log4jDB\ --min-disk-free=1024 -v .\codeql-main\java\ql\src\codeql-suites\java-security-extended.qls

Cli 性能控制参数

--ram=16384 --threads=12 --min-disk-free=1024

用于控制 RAM 使用情况的选项

查询规则集

java 规则集

codeql-suites

- java-code-scanning.qls
- java-lgtm-full.qls
- java-lgtm.qls
- java-security-and-quality.qls
- java-security-experimental.qls
- java-security-extended.qls

环境准备

CodeQL 本身包含两部分:解析引擎 +SDK。

  1. 解析引擎用来解析我们编写的规则,虽然不开源,但是我们可以直接在官网下载二进制文件直接使用;
  2. SDK 完全开源,里面包含大部分现成的漏洞规则,我们也可以利用其编写自定义规则。

安装:

ql 库(SDK)路径说明

  1. 两个目录必须放置到同级,因为 codeql-cli 把同层目录作为查找路径,调用更方便

快速部署

# 下载codeql.zip
wget https://github.com/github/codeql-cli-binaries/releases/latest/download/codeql.zip

# 解压
unzip codeql.zip

# 将codeql添加至path中
echo "export PATH=\$PATH:/path/to/codeql" >> ~/.zshrc
source ~/.zshrc

此外,还可以使用包管理器进行安装

# windows
scoop install codeql
choco install codeql

# macos
brew install codeql

SARIF Viewer 使用避坑

安装 SARIF Viewer 插件之后,使用 vscode 打开 sarif 文件进行预览分析时,会提示文件找不到,有两种解决办法:

  1. 先用 vscode 打开 sarif 文件对应的源码目录,然后打开 sarif 文件即可正常预览分析
  2. 修改 sarif 文件,在 runs 字段中添加如下属性
"originalUriBaseIds" : {
"%SRCROOT%" : {
"uri" : "file:///tmp/java-sec-code/"
}
},

工作区配置

Codeql 除了直接使用 codeql cli +codeql 库 之外,GitHub 官方还提供了 vs code 工作区来方便使用

该工作区内含了 QL 库,因此一定要使用递归方式来下拉工作区代码

vscode 的工作区缓存数据库格式为 .vscdb,位置默认在 vscode 的安装目录下,其为 SQLite 数据库,默认未加密;


git clone --recursive git@github.com:github/vscode-codeql-starter.git

内网使用环境配置

目录规范

  1. 创建工作目录

    mkdir F:\Codes\
    mkdir F:\Codes\00-CodeQL-source\ # 源代码存放目录
    mkdir F:\Codes\00-CodeQL-result\  # 扫描结果存放目录
    mkdir F:\Codes\00-CodeQL-database\  # CodeQL 数据库存放目录
  2. 使用 GitHub Actions 构建一个完整的 scoop 环境,然后打包归档至内网进行重建,GitHub Actions 可以顺带拷贝一份 codeql 的规则

  3. 下载一份免安装的Oracle jdk 8到主机目录

  4. 修改和配置 mavenidea-ultimatemaven 配置文件 (setting.xml)

    1. 本地 .m2 目录:Local repository 目录
    2. 内网的 maven 源
  5. 安装和激活 idea-ultimate

  6. 配置 vs-code,下载 VSIX 格式插件安装文件,拷贝到内网,然后在 VSCode 的 more actions 中选择【从 VSIX 文件安装】

    • CodeQL for VSCode
    • sarif viewer

基础环境快速配置

Windows 环境下,可以使用 scoop 来完成 codeql 使用环境的构建:

scoop install liberica-full-jdk liberica11-full-jdk liberica17-full-jdk liberica8-full-jdk
scoop install maven gradle chsrc
scoop install codeql

统一 IDEA 自动的 maven 配置

IDEA 自带 Maven,在 IDEA 安装目录下 plugins\maven\lib\maven3,如果需要换 IDEA 中自带的 Maven 和配置,可以按 Ctrl + Alt + S 打开当前 IDEA 项目的设置,找到 Build, Execution, Deployment -> Build Tools -> Maven,修改:

  1. Maven home path 替换成刚解压的位置 D:\Maven\apache-maven-3.9.8\conf\settings.xml
  2. Local repository 设置成 D:\Maven\repository,这个目录不存在会自动创建。
  3. 或者在 Maven 配置文件 settings.xml 中的 <localRepository>/path/to/local/repo</localRepository> 部分指定仓库路径,后续 maven 会读取这个仓库路径自动配置 Local repository

GitHub Action 打包 Scoop 归档更新 Codeql 环境事项

通过 GitHub action 打包的 codeql 离线归档进行更新时,先删除原始的 codeql 规则和 codeql vs 工作区文件夹

rm D:\00PackageManager\vscode-codeql-starter
rm D:\00PackageManager\CodeqlRules

批量值守思路

基本思路:

  1. 先判断 source 文件夹是否存在
    1. 不存在:执行 git clone
    2. 存在:进入文件夹,执行 git fetch --all
  2. 判断代码仓库是否存在更新
    1. 存在更新:进入文件夹,执行 git fetch --all 和 codeql 的数据库的创建和扫描
    2. 不存在更新:跳过这个数据库
  3. codeql 数据库的创建,使用两个 jdk 版本进行编译
    1. 使用 jdk 8 和 jdk 21 分别编译
    2. 首先使用 jdk 8 进行 maven 的编译,编译失败切换到 jdk 21
    3. 编译 jdk 版本则使用临时环境变量进行制定

批量获取仓库地址

懒人办法:

在 chrome 系浏览器中,安装 id 为 cljbfnedccphacfneigoegkiieckjndh,名称为 Easy Scraper的插件

内网环境下插件流程:

  1. 下载插件的离线安装包
  2. 下载 edge 或者 chrome 的管理模板并添加到组策略中,然后在组策略中设置如下两项配置项
    • 启用【配置扩展程序安装许可名单】,并添加扩展插件的 id
    • 禁用【禁止安装外部扩展程序】
  3. 解压离线安装包,然后将 crx 安装文件拖动到浏览器的插件管理页面
  4. 打开 git 仓库页面并登录,然后使用【Easy Scraper】进行爬取
  5. 处理扫描结果
    • 反选仓库描述为废弃的仓库
    • 然后使用 Excel 拼接语句完成后续批量命令的整理

Chrome 管理模板及组策略配置过程

相关示例截图为 edge 浏览器配置截图,可对照修改

  1. 找到 Chrome 管理模板的下载地址,下载管理模板到本地
  2. 将下载的管理模板进行解压,确保能访问 \windows\adm\zh-CN 子目录
  3. 按【Win+R】键打开运行,输入【gpedit.msc】确定,进入本地组策略编辑器。

  1. 点击【计算机配置 →管理模板】 ,右键菜单【添加/删除模板 →添加】

  1. 选择解压文件夹中的【windows/adm/zh-CN/msedge.adm】文件,将我们刚才找到的文件添加进去

  1. 添加完成后,在管理模版列表中会出现【经典管理模块 ADM】

  1. 修改如下两个配置项
    • 启用【配置扩展程序安装许可名单】,并添加扩展插件的 id
    • 禁用【禁止安装外部扩展程序】

LLM 分析 Codeql 输出格式笔记

在结合 LLM 进行漏洞分析和确认时,推荐使用 SARIF(Static Analysis Results Interchange Format)格式。以下是具体分析和理由:

1. 为什么选择 SARIF?

2. 其他格式的局限性

3. 推荐工作流程

  1. 生成 SARIF 报告

    codeql database analyze --format=sarif-latest --output=results.sarif my-db
  2. 解析并输入 LLM 提取 SARIF 中的关键信息(如代码片段、漏洞描述),构建 LLM 提示词:

    请分析以下漏洞:
    - 文件: src/main.cpp:42
    - 描述: 用户输入未经过滤,可能导致 SQL 注入。
    - 代码: `query = "SELECT * FROM users WHERE id = " + user_input;`
    这是否为误报?如何修复?
  3. LLM 输出优化建议

    模型可返回:

    • 漏洞确认/误报判断
    • 修复建议(如参数化查询)
    • 风险等级评估

4. 附加技巧

总结:SARIF 格式凭借其结构化、高信息密度标准化支持,是连接 CodeQL 与 LLM 的最佳桥梁,能有效提升漏洞分析的准确性和自动化程度。

编写 QL 规则查询

~/codeql/ql/java/ql/examples/test.ql 中编写测试代码,因为 examples 目录下有 qlpack.yml 就不需要再新建了。

codeQL 规则有包结构/目录结构要求(qlpack.yml 定义一个 package),才能正常编译、执行。

参考:https://codeql.github.com/docs/codeql-cli/using-custom-queries-with-the-codeql-cli/

编译 Ql 文件

在批量构建和查询时,建议增加此步骤

一般情况下,我们在执行一遍 codeql database analyze 命令后,便会将 ql 的编译结果写入缓存,因此个人使用时无需使用提前编译的功能,但是在 CI/CD 流程中使用 CodeQL 进行自动化扫描时,则需要提前编译好,因为这种场景每次运行 codeql 都是在一个新的环境,因此我们就需要提前将 ql 编译好,再将 codeql 安装包打包,这样会极大提升扫描速度。

提前编译 ql 文件的命令如下:

codeql  query  compile  --  $CODEQL_HOME/qlpacks/codeql/$LANGUAGE-queries/0.8.13/codeql-suites/$LANGUAGE-code-scanning.qls

例如,需要编译 java 的 java-code-scanning.qls 查询套件,就可以使用如下命令:

codeql query compile -- $CODEQL_HOME/qlpacks/codeql/java-queries/0.8.13/codeql-suites/java-code-scanning.qls

创建自定义查询套件

codeql 安装目录下的 qlpacks 目录,存放了 codeql 所有的规则

以 Java 为例,最常用的查询套件就是 java-code-scanning.qls,其内容如下:

- description: Standard Code Scanning queries for Java
- queries: .
- apply: code-scanning-selectors.yml
   from: codeql/suite-helpers

发现其引用了 $CODEQL_HOME/qlpacks/codeql/suite-helpers/0.7.13 目录下的 code-scanning-selectors.yml 文件,其内容如下

- description: Selectors for selecting the Code-Scanning-relevant queries for a language
- include: # include表示该查询套件包含如下查询
      kind: # kind属性表示如何展示查询分析的结果
      - problem # 仅展示漏洞sink点
      - path-problem # 展示漏洞source -> sink完整的数据流
      - alert # 该属性不常用
      - path-alert # 该属性不常用
      precision: # precision属性表示该查询规则的精准度,包括低、中、高、超高四种级别
      - high
      - very-high
      problem.severity: # problem.severity属性表示该查询结果的危害程度
      - error
      - warning
      tags contain: # tags属性表示该查询规则的标签,主要目的方便被搜索和引用
      - security
- include:
      kind:
      - diagnostic # 分析数据库时的故障报告
- include:
      kind:
      - metric # 输出源码的一些摘要指标,如代码行数,引用的依赖库等
      tags contain:
      - summary
- exclude:
      deprecated: //
- exclude: # exclude表示该查询套件会排除如下查询
      query path:
         - /^experimental\/.*/ # 排除实验性的查询规则
         - Metrics/Summaries/FrameworkCoverage.ql
         - /Diagnostics/Internal/.*/
- exclude: # 排除tags属性中包含modeleditor和modelgenerator的查询规则
      tags contain:
         - modeleditor
         - modelgenerator

前面提到的 $LANGUAGE-code-scanning.qls 查询套件,默认会扫描所有的安全规则,如果我们只想扫描我们关心的高危漏洞,那就可以新建一个查询套件。当使用如下扫描套件时,仅会扫描如下 id 对应的规则:

-  description:  rce漏洞扫描规则
- include:
      id:
      - java/path-injection
      - java/zipslip
      - java/jndi-injection
      - java/command-line-injection
      - java/sql-injection
      - java/mybatis-xml-sql-injection
      - java/mybatis-annotation-sql-injection
      - java/spel-expression-injection
      - java/unsafe-deserialization
      - java/ognl-injection
      - java/unsafe-eval
      - java/jshell-injection
      - java/jython-injection
      - java/server-side-template-injection
      - java/mvel-expression-injection
      - java/groovy-injection
      - java/jexl-expression-injection

这些 id 值可以从如下目录中获取:

$CODEQL_HOME/qlpacks/codeql/$LANGUAGE-queries/0.8.13/Security/CWE

该目录中以 CWE 漏洞类型,将规则进行了分类,如 CWE-022 目录下全部为路径操作相关的漏洞规则,其中 TaintedPathLocal.ql 规则用于查询路径穿越漏洞,其 id 值为 java/path-injection

个人测试效果比较好的规则

大批量查询下的性能优化思路

  1. 预编译查询规则
  2. 创建 CodeQL CLI 数据库捆绑包

此示例 database bundle 命令需要 CodeQL CLI 版本 2.17.6 或更高版本。

codeql database bundle --output=codeql-debug-artifacts.zip --include-diagnostics --include-logs --include-results -- <dir>

为已编译语言创建数据库

指定生成命令

以下示例旨在让你了解可为编译语言指定的一些生成命令。

--command 选项接受单个参数,如果需要使用多个命令,请多次指定 --command。 如果需要传递子命令和选项,则需要引用整个参数才能正确解释。

# Use `--no-daemon` because a build delegated to an existing daemon cannot be detected by CodeQL.

# To ensure isolated builds without caching, add `--no-build-cache` on persistent machines.

codeql database create java-database --language=java-kotlin --command='gradle --no-daemon clean test'
codeql database create java-database --language=java-kotlin --command='mvn clean install'
codeql database create java-database --language=java-kotlin --command='ant -f build.xml'

关于使用 CodeQL CLI 分析数据库

正在运行 codeql database analyze

可以通过运行以下命令来分析数据库:

codeql database analyze <database> --format=<format> --output=<output> <query-specifiers>...

必须指定 <database>--format--output。 可以指定其他选项,具体取决于要执行的分析。

选项必选使用情况
--sarif-add-baseline-file-info×推荐。 用于将文件覆盖率信息提交到 工具状态页。 有关详细信息,请参阅“关于代码扫描的工具状态页”。
—threads×如果想使用多个线程来运行查询,请使用此选项。 默认值是 1。 可以指定更多线程来加快查询执行速度。 要将线程数设置为逻辑处理器数,请指定 0
—verbose×用于从数据库创建过程中获取有关分析过程和诊断数据的更多详细信息。

将文件覆盖率信息添加到结果以供监视

可以选择将文件覆盖率信息提交到 GitHub,以供显示在 code scanning 的 工具状态页 上。 有关文件覆盖率信息的详细信息,请参阅“关于代码扫描的工具状态页”。

若要在 code scanning 结果中包含文件覆盖率信息,请将 --sarif-add-baseline-file-info 标志添加到 CI 系统中的 codeql database analyze 调用,例如:

$ codeql database analyze /codeql-dbs/example-repo \
      javascript-code-scanning.qls --sarif-category=javascript-typescript \
      --sarif-add-baseline-file-info \ --format=sarif-latest \
      --output=/temp/example-repo-js.sarif

报错解决

Error Running Query: Internal Error

报错:

Error running query: Internal error. (codeQLQueries.runLocalQueryFromQueriesPanel) Error: Error running query: Internal error.

报错原因:

电脑内存不足

Git 报错 schannel: next InitializeSecurityContext failed

最近在使用 git 拉取代码和提交代码时报错:

schannel: next InitializeSecurityContext failed: Unknown error 

查阅资料,导致的原因可能是使用代理导致了 git 的连接模式改变。

解决方式:

打开 cmd 窗口,执行下面命令把 URL 模式从 HTTPS 改为 SSH 即可:

git config --system http.sslbackend openssl

参考资料


分享文章至:

Previous Post
BusyBox 删除空文件夹
Next Post
解决 Git 识别 Scoop 导出列表为二进制文件