YAK-SSA,古希腊掌管PHP代码审计的神
字数 952 2025-08-20 18:17:07
ThinkPHP代码审计与YAK-SSA工具使用指南
1. ThinkPHP代码审计基础
1.1 ThinkPHP请求处理机制
ThinkPHP框架封装了请求对象$request,提供了多种参数获取方法:
-
I()方法:框架提供的输入过滤方法- 过滤行为依赖于config文件配置
- 若未显式指定过滤参数且config未配置,则等同于传统参数获取方式
- 审计要点:检查是否配置了默认过滤规则
-
常见可控变量来源:
request() input() I() *request.get() *request.post() *input() *param() *post()
1.2 数据库操作相关API
审计时需要重点关注的数据库操作方法:
Db::table()
xx->insert()
xx->update()
xx->delete()
$model::where()
Db::transaction()
1.3 文件上传相关API
ThinkPHP中常见的文件上传辅助函数:
$file->move()
$file->check()
$file->save()
Filesystem()
$file->error()
$file->getError()
2. YAK-SSA工具使用
2.1 SyntaxFlow基础语法
YAK-SSA的核心功能是SyntaxFlow语法:
-
基本定义:
$source #-> as $sink // 顶级定义 $source --> as $sink // 底级使用 -
重要配置指令:
include: 路径上有(包含) exclude: 路径上无(排除)
2.2 规则编写示例
示例1:基本控制流分析
$a = 1;
if($a){
$a = filter($a);
}else{
$a = unsafe($a);
}
eval($a);
对应规则:
// 寻找顶级定义的过程中,排除路径上filter的
*a #{exclude: `*?{have: filter}`}-> as $sink
示例2:改进版规则(加入可控变量检查)
// 寻找顶级定义的过程中,路径上包含与_POST相交的点,并且排除filter
_POST as $source
*a #{exclude: <<<CODE
*?{have: filter}
CODE,include: <<<CODE
* & $source
CODE}-> as $sink
2.3 实战审计流程
-
项目编译:
- 大型PHP项目编译可能较慢
- 可跳过非核心依赖(如imageutil、wechat等)以加快速度
-
存储型XSS审计规则:
request() as $source1
input() as $source3
i() as $source4
*request.get() as $source5
*request.post() as $source6
.input() as $source7
.param() as $source8
.post() as $source9
$source1+$source3+$source4+$source5+$source6+$source7+$source8+$source9 as $source
.add() as $func5
.save() as $func6
$func5 +$func6 as $func
$func #{include: `* & $source`}-> as $sink
- 漏洞验证:
- 定位到system.php等关键文件
- 检查是否存在请求判断和未过滤的数据存储
- 构造PoC请求验证:
POST /index.php/admin/sys.Auth/groupAdd HTTP/1.1
Host: target.com
Content-Type: application/x-www-form-urlencoded
title=<script>alert(1)</script>
2.4 文件上传审计
- 定位文件上传点:
.request().file() as $source1
request().file() as $source2
$source1+$source2 as $source
$source
- 检查验证逻辑:
- 常见的ThinkPHP validate校验
- 检查过滤器实现是否正确
2.5 API签名校验绕过
常见问题模式:
- 时间戳校验
- appid校验
- 签名校验(基于输入计算MD5)
- 数据库中存在默认的appid和appsecret
热加载Hook示例:
// 使用标签 {{yak(handle|param)}} 可触发热加载调用
handle = func(param) {
// 在这里可以直接返回一个字符串
}
// beforeRequest 允许发送数据包前再做一次处理
beforeRequest = func(req) {
params = poc.GetAllHTTPPacketPostParams(req)
params.Delete("sign")
params["key"] = "123456"
var buildSign = ""
for k,v in params{
buildSign = buildSign+sprintf("%s=%s", k,v)
buildSign = buildSign+ "&"
}
buildSign = buildSign[:-1]
params.Set("sign", codec.Md5(buildSign))
return poc.ReplaceAllHTTPPacketPostParams(req, params)
}
3. YAK官方资源
-
Yak语言官方教程:
-
GitHub仓库:
-
Yakit官网:
4. 审计要点总结
- 重点检查ThinkPHP的I()方法是否配置了默认过滤
- 关注路由参数绑定处的数据流向
- 数据库操作和文件上传是高风险点
- 使用YAK-SSA的SyntaxFlow可以高效定位漏洞链
- 热加载功能可用于动态修改请求以绕过校验
通过结合ThinkPHP框架特性和YAK-SSA工具的强大分析能力,可以高效地进行PHP代码审计工作。