shiro codeql分析理解(附带完整ql代码)
字数 919 2025-08-22 12:23:06
Shiro反序列化漏洞的CodeQL分析教学文档
1. 反序列化漏洞分析基础
在分析Shiro反序列化漏洞时,CodeQL审计的核心是寻找source(入口点)和sink(危险操作点)。
1.1 反序列化入口点(source)
反序列化漏洞的入口点通常是实现了Serializable接口的类:
import java
from Class cls
where
cls.getASupertype() instanceof TypeSerializable
and cls.fromSource()
select cls
这条查询会找出所有实现了Serializable接口且来自源代码的类。
2. 定位关键类和方法
2.1 查找特定类的实例化
要查找User类的实例化:
import java
/* 找到实例化User的类 */
class FindUser extends RefType {
FindUser() {
this.hasQualifiedName("com.summersec.shiroctf.bean", "User")
}
}
from ClassInstanceExpr clie
where
clie.getType() instanceof FindUser
select clie
FindUser类构造函数验证当前类是否是User类的引用from ClassInstanceExpr clie获取所有实例化对象where条件判断实例化对象是否为User类的实例
2.2 查找关键方法
查找Tools包下的三个关键方法:
import java
from Method m
where
(m.getName() = "deserialize"
or m.getName() = "serialize"
or m.getName() = "base64Encode")
and m.getDeclaringType().getPackage().getName() = "com.summersec.shiroctf.Tools"
select m
3. 查找危险方法调用
查找所有调用exeCmd方法的位置:
import java
from MethodAccess call
where call.getMethod().hasName("exeCmd")
select call, "调用 exeCmd 方法"
4. 完整的数据流分析
4.1 定义sink点
predicate deser(Expr arg) {
exists(MethodAccess des |
des.getMethod().hasName("deserialize")
and arg = des.getArgument(0)
)
}
4.2 使用RemoteFlowSource
CodeQL提供了RemoteFlowSource来覆盖所有不受信任的远端输入:
override predicate isSource(DataFlow::Node source) {
source instanceof RemoteFlowSource
}
4.3 完整QL规则
/**
* @name Unsafe shiro deserialization
* @kind path-problem
* @id java/unsafe-shiro-deserialization
*/
import java
import semmle.code.java.dataflow.FlowSources
import DataFlow::PathGraph
// 定义反序列化sink点
predicate deser(Expr arg) {
exists(MethodAccess des |
des.getMethod().hasName("deserialize")
and arg = des.getArgument(0)
)
}
// 配置类
class ShiroUnsafeDeserializationConfig extends TaintTracking::Configuration {
ShiroUnsafeDeserializationConfig() {
this = "StrutsUnsafeDeserializationConfig"
}
// 定义source
override predicate isSource(DataFlow::Node source) {
source instanceof RemoteFlowSource
}
// 定义sink
override predicate isSink(DataFlow::Node sink) {
exists(Expr arg |
deser(arg)
and sink.asExpr() = arg
)
}
}
// 查询数据流路径
from ShiroUnsafeDeserializationConfig config,
DataFlow::PathNode source,
DataFlow::PathNode sink
where config.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "Unsafe shiro deserialization",
source.getNode(), "this user input"
5. 漏洞利用链分析
- 入口点:
IndexController类中可以设置request参数,通过cookie传入 - 处理流程:cookie经过一系列处理后到达
deserialize方法 - 危险操作:如果能将
exeCmd方法放入反序列化中,就能完成利用
关键点:
deserialize方法的bytes参数是sink点- 远端输入(如cookie)是source点
- 数据流从source流向sink即构成漏洞
6. 总结
通过CodeQL分析Shiro反序列化漏洞的关键步骤:
- 识别反序列化入口点(实现
Serializable的类) - 定位关键方法(
serialize/deserialize) - 查找危险方法调用(如
exeCmd) - 定义source和sink
- 分析数据流路径
- 确认漏洞存在条件(数据从source流向sink)
这种分析方法不仅适用于Shiro,也可应用于其他Java反序列化漏洞的分析。