群里大佬们打哈哈的内容,菜鸡拿出来整理学习一下,炒点冷饭。

主要包含以下三个部分:

  1. jndi注入原理
  2. jndi注入与反序列化
  3. jndi注入与jdk版本

jndi注入原理:

JNDI(Java Name and Dictionary Interface Java名称与目录接口),一套JavaEE的标准,类似Windows注册表。

结构如下:

key:路径+名称
value:存的数据(在jndi中存的是对象Object)

jndi是java用于访问目录和命名服务的 API。使用jndi进行查询本来是一个正常的功能,但由于实现时没有考虑安全问题,如果查询了恶意对象就会导致被攻击。但是不是所有攻击都能够导致RCE(比如dnslog2333)

JNDI查询分为以下两个步骤:

1、客户端请求一个命名服务并获取对象

2、客户端解析这个对象

这两个步骤都有可能导致漏洞的发生,jndi支持LDAP、RMI、DNS、CORBA四种可能导致危险的协议,每种都对应了不同的实现方式,支持绑定的对象也包含了引用对象、反序列化对象、属性对象等等,所以攻击手段和漏洞都很多。

最常用也是最危险的攻击有jndi+rmi和jndi+ldap,corba也可以用来命令执行(但是修复得比较早,而且用corba的基本都可以用rmi)

JNDI+RMI

关键代码位于RegistryContext#lookup

public Object lookup(Name name) throws NamingException {
if (name.isEmpty()) {
return (new RegistryContext(this));
}
Remote obj;
try {
obj = registry.lookup(name.get(0));
//这里可以看到远程对象是通过rmi原生的lookup获取到的
} catch (NotBoundException e) {
throw (new NameNotFoundException(name.get(0)));
} catch (RemoteException e) {
throw (NamingException)wrapRemoteException(e).fillInStackTrace();
}
return (decodeObject(obj, name.getPrefix(1)));

可以看到远程对象是通过rmi原生的lookup获取到的,而rmi是通过反序列化获取到的远程对象,这时如果客户端系统里有gadget组件,这一步的反序列化就能导致代码执行了。

第二步,在decodeObject里面对获取到的obj进行了解析,逻辑位于RegistryContext#decodeObject

private Object decodeObject(Remote r, Name name) throws NamingException {
try {
Object obj = (r instanceof RemoteReference)
? ((RemoteReference)r).getReference(): (Object)r;
/*
* Classes may only be loaded from an arbitrary URL codebase when
* the system property com.sun.jndi.rmi.object.trustURLCodebase
* has been set to "true".
*/
//这里注释写得很清楚
// Use reference if possible
Reference ref = null;
if (obj instanceof Reference) {
ref = (Reference) obj;
} else if (obj instanceof Referenceable) {
ref = ((Referenceable)(obj)).getReference();
}
if (ref != null && ref.getFactoryClassLocation() != null &&
!trustURLCodebase) {
throw new ConfigurationException(
"The object factory is untrusted. Set the system property" +
" 'com.sun.jndi.rmi.object.trustURLCodebase' to 'true'.");
}
return NamingManager.getObjectInstance(obj, name, this,
environment);

注释注明了,如果com.sun.jndi.rmi.object.trustURLCodebase为true就可以通过codebase加载

任意远程类,导致代码执行。这个校验是在jdk8u121开启的,并且是加在RegistryContext里面的,也就是只对了jndi的rmi实现作了限制,所以安全人员后续才会发掘出ldap的利用。

Object obj = (r instanceof RemoteReference) ? ((RemoteReference)r).getReference(): (Object)r;

这段代码判断传入的对象,是否满足RemoteReference接口,如果有则getReference()获取reference对象,然后进入getObjectInstance函数。

具体利用流程如下:

1、目标代码中调用了InitialContext.lookup(URI),URI为用户可控的;

2、攻击者设置uri为恶意rmi服务地址;

3、攻击者设置rmi server向目标返回一个reference引用对象,reference对象中指定了一个精心构造的Factory类;

4、目标进行lookup操作远程对象时,获取到动态加载并实例化了这个Factory类,接着调用factory.getObjectInstance()加载外部远程对象实例;

5、攻击者可以在Factory类文件的构造方法、静态代码块、getObjectInstance()方法等处写入恶意代码,达到RCE的效果;

getObjectInstance 主函数当中使用此类的getInstance()函数,即可得到系统当前已经实例化的该类对象,若当前系统还没有实例化过这个类的对象,则调用此类的构造函数。

可以引出后续的两种命令执行利用方式:

if (ref != null) {
            String f = ref.getFactoryClassName();
            if (f != null) {
                // if reference identifies a factory, use exclusively
 
 
 
 
                factory = getObjectFactoryFromReference(ref, f); //触发点1
                if (factory != null) {
                    return factory.getObjectInstance(ref, name, nameCtx,
                                                     environment); //触发点2
                }
                // No factory found, so return original refInfo.
                // Will reach this point if factory class is not in
                // class path and reference does not contain a URL for it
                return refInfo;

第一种是getObjectFactoryFromReference(),在这个函数中会通过获取到对应的恶意class对象,在开启trustURLCodebase时可以通过URLClassloader加载远程类并进行实例化,通过class.newInstance()触发恶意构造函数:

return (clas != null) ? (ObjectFactory) clas.newInstance() : null;

第二种是通过实例化的类,调用起getObjectInstance函数,来执行恶意代码:

只要攻击者实现ObjectFactory接口,重写getObjectInstance,即可执行恶意代码。

public class Exec implements ObjectFactory {
    public Exec(){}
    public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
        System.out.println("factory.getObjectInstance hook!");
        return null;
    }
}

综上所述,RMI的RCE利用从某种意义上说并不是利用反序列化导致的代码执行,只是利用反序列化来加载恶意远程对象。

JNDI+LDAP

核心逻辑在ldapCtx#c_lookup

protected Object c_lookup(Name name, Continuation cont)
throws NamingException {
cont.setError(this, name);
Object obj = null;
Attributes attrs;
try {
......
if (attrs.get(Obj.JAVA_ATTRIBUTES[Obj.CLASSNAME]) != null) {
// 序列化对象或序列化引用
obj = Obj.decodeObject(attrs);
}
if (obj == null) {
obj = new LdapCtx(this, fullyQualifiedName(name));
}
} catch (LdapReferralException e) {
......
try {
return DirectoryManager.getObjectInstance(obj, name,
this, envprops, attrs);
......
}

只看关键代码,这里主要分为两个步骤:

首先通过Obj.deocodeObject从ldap获取字符串,解码出一个ldap对象,然后通过DirectoryManager.getObjectInstance解析,这里和RMI是一样的逻辑,只是没有rmi关于trusrURLCodebase的校验。

所以jndi+ldap获取对象的方式和rmi差不多,都是通过反序列化获取的。然后解析对象调用的是DirectoryManager.getObjectInstance,其实和NamingManager.getObjectInstance基本是一样的。decodeRefernce,原生反序列化,但是如果com.sun.jndi.ldap.object.trustURLCodebase开启,会调一个重写的resolveClass进行远程类加载。

1、解析对象时调用getObjectFactoryFromReference,在开启com.sun.jndi.ldap.object.trustURLCodebase时进行远程类加载

2、和rmi一样用本地工厂类,但ldap服务端不能像rmi一样直接绑远程对象,需要绑序列化后的数据。

JNDI注入与jdk版本

jdk针对jndi注入的利用有两次修复,8u121对RMI和corba的jndi注入进行限制,com.sun.jndi.ldap.object.trustURLCodebase 限制了这两种服务加载远程工厂类。

8u191禁用了ldap的远程类加载。

至此,高版本可用的jndi注入还有:加载本地工厂类,打本地反序列化链,

前者是tomcat8/9才引入的,后者需要本地反序列化链。

总结:

1、jndi注入的原理

一般说的jndi注入原理是远程类加载。其他攻击方法还有本地工厂类代码执行、反序列化。

2、jndi注入与反序列化

jndi注入依赖反序列化来传递对象,但常说的jndi注入代码执行并不是由反序列化链导致的。同样jndi注入也可以转化成通常说的反序列化攻击。

3、jndi注入与jdk升级

jdk升级只能修复jndi远程类加载的攻击方式,高版本依然有加载本地工厂类和反序列化本地利用链的攻击方式。

Java反序列化中jndi注入的高版本jdk绕过的更多相关文章

  1. Java安全之JNDI注入

    Java安全之JNDI注入 文章首发:Java安全之JNDI注入 0x00 前言 续上篇文内容,接着来学习JNDI注入相关知识.JNDI注入是Fastjson反序列化漏洞中的攻击手法之一. 0x01 ...

  2. 从高版本JDK换成低版本JDK报错Unsupported major.minor version 52.0的解决方案

    从高版本JDK换成低版本JDK报错Unsupported major.minor version 52.0 java.lang.UnsupportedClassVersionError: PR/Sor ...

  3. 解决:高版本jdk编译低版本代码时eclipse提示Access restriction:The type 'Unsafe' is not accessible due to restriction on required library

    在Eclipse中采用高版本jdk编译一些低版本的源码时,由于源码中使用了一些高版本中过时的API,可能就会报错,类似于: Access restriction:The type 'Unsafe' i ...

  4. 解决eclipse高版本JDK编译的项目到低版本JDK服务器上不能运行的问题

    错误提示信息:Unsupported major.minor version 52.0,意思是说,当前jdk的版本不支持更高版本jdk编译出来的class文件. 我的编译环境,eclipse使用的是j ...

  5. 从高版本JDK换成低版本JDK报错Unsupported major.minor version 52.0

    ava.lang.UnsupportedClassVersionError: PR/Sort : Unsupported major.minor version 52.0这个错误是由于高版本的java ...

  6. 【转】ubuntu 配置 java jdk1.8 环境,增加多版本 jdk 和切换方法

    一.安装java jdk1.8 1.添加软件源 sudo add-apt-repository ppa:webupd8team/java 2.更新软件源 sudo apt-get update 3.安 ...

  7. 一篇博客带你轻松应对java面试中的多线程与高并发

    1. Java线程的创建方式 (1)继承thread类 thread类本质是实现了runnable接口的一个实例,代表线程的一个实例.启动线程的方式start方法.start是一个本地方法,执行后,执 ...

  8. Java Spring 中你不知道的注入方式

    前言 在Spring配置文件中使用XML文件进行配置,实际上是让Spring执行了相应的代码,例如: 使用<bean>元素,实际上是让Spring执行无参或有参构造器 使用<prop ...

  9. Java Spring-Bean中属性注入

    2017-11-06 20:29:13 类属性的注入的三种方法 1.接口方法注入 public interface injection{ public void setName(String name ...

随机推荐

  1. 它把RabbitMQ的复杂全屏蔽了,我朋友用它后被老板一夜提拔为.NET架构师

    本文技术源自外企,并已在多个世界500强大型项目开发中运用. 本文适合有初/中级.NET知识的同学阅读.(支持.NET/.NET Framework/.NET Core) RabbitMQ作为一款主流 ...

  2. EMAS Serverless系列~4步教你快速搭建小程序

    体验简介 本实验基于 EMAS Serverless 的云函数.云数据库.云存储等云服务能力一站式快速开发小程序<私人云相册>.Demo 主要包括如下功能: 1 相册管理 2 上传相片 3 ...

  3. Jmeter工具使用总结

    Jmeter工具使用总结 目录 Jmeter函数总结 第一章 前言 第二章 常用函数的介绍 2.1. timeShift函数 2.2. time函数 2.3. groovy函数 第三章 常用用法 3. ...

  4. 关于 Excel 函数对字符、布尔、数字的运算的细节

    使用函数时,通过引用单元格作为参数进行运算,不会计算字符和布尔. 假如 A1.B1.C1 这三个单元格,其中 A1 为布尔TRUE:B1 为字符"2":C1 为数字1. 求和函数= ...

  5. cad开发动态块对应的界面

    为了使设计人员更加容易的操作动态块, 应经可能对动态块的制作制定相关的规范, 如动态块的属性 => 类的属性 动态块操作名称(作为变量名,后台数据库的字段) 动态块操作描述  (作为注释,后台数 ...

  6. NC202475 树上子链

    题目链接 题目 题目描述 给定一棵树 T ,树 T 上每个点都有一个权值. 定义一颗树的子链的大小为:这个子链上所有结点的权值和 . 请在树 T 中找出一条最大的子链并输出. 输入描述 第一行输入一个 ...

  7. Linux虚拟机破解密码步骤

    Linux破解密码 重启系统 到达logo界面快速 按 e 编辑当前条目 将光标移至以 linux 开头的行,此为内核命令行 在UTF-8(RHEL7):ro(RHEL8)后添加 rd.break ( ...

  8. 对比es6class类和构造函数

    构造函数 在原来class 类这个语法糖没有出来之前 我们一般会把方法挂在prototype 上 为了防止过多的开辟内存 1 // 构造函数------------------------------ ...

  9. 我的Vue之旅、01 深入Flexbox布局完全指南

    花了几个小时整合的"A Complete Guide to Flexbox"最新版本,介绍了flexbox的所有属性,外带几个实用的例子. 传统布局.Flexbox 布局的传统解决 ...

  10. Python 代码智能感知 —— 类型标注与特殊的注释(献给所有的Python人)

    [原文地址:https://xiaokang2022.blog.csdn.net/article/details/126936985] ​ 一个不会写好的类型标注和注释的Python程序员,是让使用T ...