2025京麒CTF初赛-web
2025京麒CTF初赛-web
计算器
前端删除expression
的disable
,然后就可以正常输入了。
代码注入,成功
flag在环境变量中
赛后看到其他师傅的解法,打的websocket
FastJ 复现
参考:2025第三届京麒CTF挑战赛 writeup by Mini-Venom | CTF导航
前置知识
fastjson的“AutoTypeCheck”机制
Fastjson 从1.2.68
开始引入白名单,在 1.2.80
中更加严格。只有在 白名单 中的类才能通过 @type
被反序列化。
一些常见 Java 基础类,例如:
-
java.util.HashMap
-
java.util.ArrayList
-
java.lang.Integer
-
java.lang.String
-
特定配置下用户添加的类(通过
ParserConfig.addAccept("com.example.")
)特定第三方库被明示允许的类(比如某些 JSON 处理类)
不再支持自动根据
@type
加载任意类。
fastjson的类缓存机制
Fastjson
的类缓存机制:ParserConfig.classMapping
当使用 @type
加载了一个类,Fastjson 会把它缓存起来:
1 | classMapping.put(typeName, clazz); |
这是为了提升解析性能、减少重复反射。
所以,只要你通过 @type
加载了某个类,Fastjson 后续就可以:
- 复用这个
Class
实例 - 不再检查
autoType
(因为已经被认为是“合法的”了)
缓存机制由来:
- 该机制很早就有(至少在 1.2.6+ 就存在),本是出于性能目的
- 后来被用于各种 Gadget 利用链中作为“class 引导缓存”技巧
rmb
RMI-Based MarshalOutputStream
是 JDK 自带的一个类:sun.rmi.server.MarshalOutputStream
-
ObjectOutputStream
的子类; - 在对象序列化过程中,会调用其内部 OutputStream 的 write 方法;
- 是 JDK RMI 模块中用于序列化对象时的工具类。
可以利用反序列化触发 write()
,实现数据流写入
InflaterOutputStream
标准 JDK 类,负责接收压缩数据 → 解压 → 向底层流写入
解题过程
fastjson
版本为1.2.80
核心代码:
1 | // IndexController.java |
调用getflag()
会触发new FilterFileOutputStream("/flag", "/");
将触发调用FilterFileOutputStream
类,构造函数调用 super(name)
➜ 调用了 FileOutputStream(String name)
➜ 会尝试打开或新建这个文件
试探一下autotype
是否开启
1 | { |
开启。那就可以借助 Fastjson
的反序列化能力,构造这样一个对象:
1 | { |
但存在“AutoTypeCheck”
机制,由于 FilterFileOutputStream
不在白名单中,无法被正常反序列化
关于FastJson 1.2.80的利用,找到CVE-2022-25845
CVE-2022-25845 - Fastjson RCE 漏洞分析
该漏洞的核心在于只要目标类继承了Throwable
类,Fastjson就能反序列化这个目标类。
将 OutputStream
加入autoType
缓存
luelueking/CVE-2022-25845-In-Spring: CVE-2022-25845(fastjson1.2.80) exploit in Spring Env!
该项目是一个把java.io.InputStream
加入 fastjson autotype
缓存的demo,简单看看这个项目
1 | { |
其核心链条:
1 | Throwable bypass: InputCoercionException |
Fastjson 在构造这些类时会顺便初始化其字段类型(如 in: InputStream
),从而将 InputStream
加入 autoType 缓存。
根据上述思路找 OutputStream Gadget
的思路
- 继承 Throwable
- 有字段指向某个含
OutputStream
成员的类 - 类路径没有被 Fastjson 拦截
在BOOT-INF/lib/
中查看项目依赖
发现jackson
生态全套,其中jackson-core-2.13.2.jar
中包含 UTF8JsonGenerator
,可构造 OutputStream
缓存链
使用Mini-Venom师傅构造的gadget
1 | UTF8JsonGenerator |
payload
1 | { |
得到回显,说明绕过了“AutoTypeCheck”
机制
1 | HTTP/1.1 200 |
任意文件写入
题目实现了FilterFileOutputStream
类,可以通过@type
加载
利用 JDK 的标准类 InflaterOutputStream
和 MarshalOutputStream
可以在反序列化期间触发写入流数据
1 | Fastjson parse() |
-
MarshalOutputStream
- 属于 JDK 中 RMI 模块:
sun.rmi.server.MarshalOutputStream
- 在
readObject()
过程中会触发它包装的底层OutputStream.write()
方法
1 | public class MarshalOutputStream extends ObjectOutputStream { |
-
InflaterOutputStream
是一个解压类,持有字段:
1
2
3OutputStream out;
Inflater infl;
byte[] buf;其中
infl.input.array
被赋值后,当InflaterOutputStream.write()
触发时会尝试将解压数据写入 out
-
FilterFileOutputStream
(题目实现)
1 | public class FilterFileOutputStream extends FileOutputStream { |
- 只要满足
name.startsWith(prefix)
条件,就会成功创建文件; - 而
super(name)
会在构造函数中就打开文件; - 之后通过反序列化链流入的内容会写进去。
进而可以构造出payload
1 | { |
array
: 压缩后的字符串内容
数据压缩部分的 Java 实现代码解析
1 | package exp; |
然后写定时任务反弹shell