你可选择以下两种方式之一来运行工作坊练习:
使用本地 CodeQL 安装来完成工作坊练习。
git。curl -L -O "https://github.com/sylwia-budzynska/codeql-workshop/releases/download/v1/test-app-db.zip" curl -L -O "https://github.com/sylwia-budzynska/codeql-workshop/releases/download/v1/kohya_ss-db.zip"
3. 在 VS Code 中:文件 -> **从文件打开工作区...** `vscode-codeql-starter.code-workspace`
4. 继续[选择 CodeQL 数据库](#select-codeql-database)
5. 然后[测试你的安装](#test-your-installation)
### 选项 B:GitHub Codespace
使用远程 GitHub Codespace 完成本工作坊的练习。
#### 先决条件
* GitHub 账户([免费注册](https://github.com/))
* 浏览器(你可以在浏览器中完成整个工作坊——这是最快的配置方式),或安装了 [GitHub Codespaces](https://marketplace.visualstudio.com/items?itemName=GitHub.codespaces) 扩展的本地 [Visual Studio Code](https://code.visualstudio.com/download)(VS Code)。
注意:Codespace 使用量每月每核前 120 小时免费。本工作坊使用一个 4 核的 Codespace,因为 4 核是当前免费账户的最大配置。(如果你有 Pro 账户,我们建议改用 8 核机器。)
#### 操作步骤
1. 登录你的 [GitHub](https://github.com/login) 账户
2. 前往仓库 https://github.com/sylwia-budzynska/codeql-workshop
3. 点击 代码 -> Codespaces
4. 点击加号(+)以创建新的 Codespace。
<img src="https://assets.kitploit.com/production/public/readmes/33098/c86e537f9e7891fb6bdb5da727cae5b6ad0b2c9ac94f67854d48296f2dad89cb.png" width="439" alt="截图:创建 Codespace,点击加号">
VS Code 将在你的浏览器中启动,并构建一个远程 Codespace。这可能需要几分钟。
如果系统提示你打开工作区 `vscode-codeql-starter.code-workspace`,请点击“打开工作区”。
5. 如果你想在本地使用 VS Code,请点击左上角的三条横线按钮,然后选择“在 VS Code Desktop 中打开”。该选项可能需要几分钟才会出现。
<img src="https://assets.kitploit.com/production/public/readmes/33098/f2c8c2fe6da80142344b17c208da31a23c3fa68a3917a124f0e2f7871b6a20f7.png" width="300" alt="截图:点击三条横线按钮并在 VS Code Desktop 中打开">
6. 继续[选择 CodeQL 数据库](#select-codeql-database)
7. 然后[测试你的安装](#test-your-installation)
你可以在 [github.com/codespaces](https://github.com/codespaces) 查看你的 Codespace。Codespace 闲置数小时后会自动关闭,但为确保你不会消耗更多 120 小时免费额度中的时长,请在工作坊结束后前往 [github.com/codespaces](https://github.com/codespaces) > 三个点 > “停止 Codespace”。
#### 安装故障排除
如果你看到如下错误:
* `Failed to run query: Could not resolve library path for [..]`
* `Could not resolve module [..]`
* `Could not resolve type [..]`
那么很可能你漏掉了克隆 git 子模块(即 ql 仓库)的步骤。要修复此问题,请运行 `git submodule init && git submodule update --recursive`。
### 选择 CodeQL 数据库
1. 确保已在 VS Code 中打开工作区 `vscode-codeql-starter.code-workspace`。
2. 点击左侧标签栏中的“QL”图标进入 CodeQL 视图。
3. 点击“Choose Database from Archive”(从归档文件中选择数据库),然后选择仓库根目录下的 `test-app-db.zip` 文件。
注意:此时你可能会在 VSCode 中遇到一个错误,弹出消息要求安装 CodeQL CLI。接受此安装即可解决该问题。CLI 安装完成后,你应该就能完成上述数据库选择了。
<img src="https://assets.kitploit.com/production/public/readmes/33098/65cc5790b8b49113623bc9a9b34a1be61575b05bea2428c46f83115e2271148b.png" alt="截图:VSCode 中与 CodeQL 相关的错误消息">
<img src="https://assets.kitploit.com/production/public/readmes/33098/c3bf9c304d9c1f6199f591c9bcbf6e446ee4f5388ab209e30887326698129f84.png" alt="截图:VSCode 正在安装 CodeQL CLI">
### 测试你的安装
#### 先决条件
确保之前在 CodeQL 视图中选择的 CodeQL 数据库仍处于选中状态。(如果没有,请点击“选择”)
当数据库被选中时,界面应如下所示(注意勾选标记):
<img src="https://assets.kitploit.com/production/public/readmes/33098/fee6e47c0d9b0754c7ac9e29e2f0b3a721093aa5ce882615b3839a99f4862506.png" alt="截图:已选择 CodeQL 数据库">
#### 操作步骤
1. 在 VS Code 中:进入工作区文件夹:`codeql-custom-queries-python`
2. 创建一个新文件 `test.ql`
3. 添加以下内容:`select "Hello World!"`
4. 保存文件,在文件区域中右键点击并选择“CodeQL: Run Query on Selected Database”
5. 你应该会看到一个新选项卡打开,并显示结果“Hello World!”
## :books: 资源
- [QL 教程](https://codeql.github.com/docs/writing-codeql-queries/ql-tutorials/)
- [CodeQL for Python 语言指南](https://codeql.github.com/docs/codeql-language-guides/codeql-for-python/)
- [CodeQL 文档](https://codeql.github.com/docs/)
- [QL 语言参考](https://codeql.github.com/docs/ql-language-reference/)
- [用于 Python 的 CodeQL 库](https://codeql.github.com/codeql-standard-libraries/python/)
- [Python 代码的基本查询](https://codeql.github.com/docs/codeql-language-guides/basic-query-for-python-code/)
- [QL 类](https://codeql.github.com/docs/ql-language-reference/types/#classes)
- [CodeQL 从零到精通(一):漏洞研究的静态分析基础](https://github.blog/2023-03-31-codeql-zero-to-hero-part-1-the-fundamentals-of-static-analysis-for-vulnerability-research/)
- [CodeQL 从零到精通(二):CodeQL 入门](https://github.blog/2023-06-15-codeql-zero-to-hero-part-2-getting-started-with-codeql/)
- [CodeQL 从零到精通(三):安全研究](https://github.blog/2024-04-29-codeql-zero-to-hero-part-3-security-research-with-codeql/)
- [CodeQL 从零到精通(四):Gradio 案例分析](https://github.blog/security/vulnerability-research/codeql-zero-to-hero-part-4-gradio-framework-case-study/)
- [CodeQL 从零到精通(五):调试查询](https://github.blog/security/vulnerability-research/codeql-zero-to-hero-part-5-debugging-queries/)
## 工作坊
欢迎参加“使用 CodeQL 发现漏洞”工作坊!
本次环节将介绍在软件中寻找漏洞时所使用的安全研究和静态分析基础知识。我们将以一个简单的漏洞为例,逐步演示 CodeQL 如何检测该漏洞,并提供示例,帮助与会者了解如何使用 CodeQL 自行发现漏洞。
在开始之前,请确保满足所有先决条件,以便你能够参与本工作坊。
本工作坊分为多个部分,每个部分包含一系列练习,这些练习循序渐进,最终形成一个完整的查询。
对于每个部分,我们都提供了*指南*,通过给出你可以使用的 QL 类和成员谓词(member predicates)的参考,帮助你完成练习。
### 概述
在本工作坊中,我们将寻找 [kohya_ss](https://securitylab.github.com/advisories/GHSL-2024-019_GHSL-2024-024_kohya_ss/) 中的已知*命令注入漏洞*。此类漏洞的出现,是因为用户可控的信息进入了应用程序代码,而该代码不安全地构造并执行命令。由用户输入不安全构造的命令可能被改写,从而执行未预期的操作,例如任意命令执行、敏感信息泄露。
本工作坊讨论的命令注入漏洞包括 [CVE-2024-32022, CVE-2024-32026, CVE-2024-32025, CVE-2024-32027](https://securitylab.github.com/advisories/GHSL-2024-019_GHSL-2024-024_kohya_ss/)。
## 理论
### 源(Sources)和汇(Sinks)
试想一种最著名的漏洞——命令注入。当用户输入被用于那些允许直接在服务器上的 shell 中运行命令的函数时,就会发生这种漏洞。它允许攻击者在运行应用程序的服务器上执行操作系统(OS)命令,通常还会完全攻陷应用程序及其数据。
注入漏洞的主要原因是不可信的、用户可控的输入被用于程序中敏感或危险的函数。为了在静态分析中表示这些概念,我们使用数据流(data flow)、源(sources)和汇(sinks)等术语。
用户输入通常来自应用程序的入口点——即数据的来源。这些入口点包括 HTTP 方法中的参数(如 GET 和 POST),或程序的命令行参数。它们被称为“**源(sources)**”。
继续以命令注入为例,一个不应使用未经净化的不可信数据调用的危险函数示例是 `os.system`。这些危险函数被称为“**汇(sinks)**”。请注意,某个函数具有潜在危险性并不意味着它马上就是一个可被利用的漏洞并必须被移除。许多汇都有安全使用的方式。其他不应与用户输入一起使用的汇的示例还有:来自 Python MySQLdb 库的 MySQLCursor.execute()(导致 SQL 注入),或 Python 的内置函数 eval()(它会计算任意表达式,导致代码注入)。
要存在漏洞,不安全的、用户可控的输入必须在未经正确净化或输入验证的情况下被用于危险函数。换句话说,源和汇之间必须存在一条代码路径,这种情况下我们说数据从源流向汇——即从源到汇存在“**数据流(data flow)**”。
<img src="https://assets.kitploit.com/production/public/readmes/33098/ff60a1649737805a71bd27710209dba66203a77159cc72ae435c165353e56491.png">
### CodeQL 速查表
基本查询结构```codeql
import python
from <type> <name> //variables used in the query
where <conditions for variables>
select <output> //results, referring to the variables
查找 os.system() 调用的引用```codeql
import python
import semmle.python.ApiGraphs
from API::CallNode call where call = API::moduleImport("os") .getMember("system") .getACall() select call, "Call to os.system"
查找对 `os.system()` 调用的引用,这次带有一个谓词```codeql
predicate isOsSystemSink(API::CallNode call) {
call = API::moduleImport("os")
.getMember("system").getACall()
}
from API::CallNode call
where isOsSystemSink(call)
select call, "Call to os.system"
查找对 os.system() 调用的引用,这次使用一个类```codeql
class OsSystemSink extends API::CallNode {
OsSystemSink() {
this = API::moduleImport("os")
.getMember("system").getACall()
}
}