【表哥有话说 第101期】Java安全-JNDI注⼊

admin 2023年10月17日21:33:57评论25 views字数 3041阅读10分8秒阅读模式

百期后的第一期内容来喽

又是崭新的知识

本期内容较为简洁

需要大家仔细研究

快快拿好小本本认真记起来吧~

【表哥有话说 第101期】Java安全-JNDI注⼊

Java安全-JNDI注⼊

JNDI(Java Naming and Directory Interface)是Java提供的Java 命名和⽬录接⼝。通过调⽤JNDI的API应⽤程序可以定位资源和其他程序对象。JNDI是Java EE的重要部分,JNDI可访问的现有的⽬录及服务有:JDBC、LDAP、RMI、DNS、NIS、CORBA

⾸先来介绍⼀下JNDI的具体内容

Naming Service 命名服务

这就是JNDI中的N

命名服务将名称和对象进⾏关联,提供通过名称找到对象的操作,例如:DNS系统将计算机名和IP地址进⾏关联、

⽂件系统将⽂件名和⽂件句柄进⾏关联等等,简单的说,就是把⼀个名称绑定到⼀个对象上,以⽅便后续的查找

在名称系统中,有⼏个重要的概念。

Bindings : 表示⼀个名称和对应对象的绑定关系,⽐如在⽂件系统中⽂件名绑定到对应的⽂件,在 DNS 中域名绑

定到对应的 IP 。

Context : 上下⽂,⼀个上下⽂中对应着⼀组名称到对象的绑定关系,我们可以在指定上下⽂中查找名称对应的对

象。这个概念⽐较抽象,我个⼈的理解就是⼀个前后⽂环境的意思,⽐如在⽂件系统中,⼀个⽬录就是⼀个上下

⽂,你需要查找该⽬录中的⽂件,就需要去到这个⽬录中,所以这个⽬录就可以理解为这个⽂件的环境,其中⼦⽬

录也可以称为⼦上下⽂ ( subcontext )。

References : 在⼀个实际的名称服务中,有些对象可能⽆法直接存储在系统内,这时它们便以引⽤的形式进⾏存

储,可以理解为C语⾔中的指针。引⽤中包含了获取实际对象所需的信息,甚⾄对象的实际状态,


Directory Service ⽬录服务

这就是JNDI中的D

是命名服务的扩展,除了提供名称和对象的关联,还允许对象具有属性,⽐如⼀个⽂件,它的属性就是⽂件⼤⼩、⽂件类型等,⽬录服务就可以通过这些特定的属性,去寻找相关对象。⽬录服务中的对象称之为⽬录对象,⽬录服务提供创建、添加、删除⽬录对象以及修改⽬录对象属性等操作,我们不仅可以根据名称去查找( lookup )对象(并获取其对应属性),还可以根据属性值去搜索( search )对象。总而言之,目录服务也是⼀种特殊的名称服务,关键区别是在⽬录服务中通常使⽤搜索( search )操作去定位对象,而不是简单的根据名称查找( lookup )去定位。下文中命名和目录服务简称为目录服务。

JNDI架构

根据上⾯的介绍,我们知道⽬录服务是中⼼化⽹络应⽤的⼀个重要组件,什么意思呢,⽐如DNS就是⼀种⽬录服务,域名就相当于⼀个名称,这个名称所对应的IP地址就相当于⼀个对象,通过域名去查找IP地址的服务,就是⼀个⽬录服务,Java除了这种常规的⽤法,就是⽤⽬录服务作为对象存储的系统,⽤⽬录服务来存储和获取对象,⽐如对于打印机服务,我们可以通过在⽬录服务中查找打印机,并获得⼀个打印机对象,基于这个 Java 对象进⾏后续的操作,⽐如打印,复印等。

SPI

SPI 全称为 Service Provider Interface ,即服务供应接⼝,⽐如java的JDBC SPI,我们在连接不同的数据库时,⽐如Mysql,Oracle之类的数据库,就是通过JDBC SPI进⾏连接的,这个JNDI SPI也是⼀样的概念,使⽤者可以使⽤官⽅已经有的SPI,或者去下载第三⽅提供的SPI进⾏使⽤,⽆需⾃⼰重复修改代码,简单的说,我们能直接调⽤到的就是API的接⼝,⽽java内部调⽤的,我们看不到的部分,就是SPI接⼝

有三个JDK⾃带的SPI

RMI : Java Remote Method Invocation , Java 远程⽅法调⽤;

LDAP : 轻量级⽬录访问协议;

CORBA : Common Object Request Broker Architecture ,通⽤对象请求代理架构,⽤于 COS 名称服务( Common Object Services );

RMI

RMI是⼀种跨JVM进⾏⽅法调⽤的技术,RMI核⼼特点之⼀就是动态类加载,如果当前JVM中没有某个类的定义,它可以从远程URL到另⼀个JVM去下载这个类的class,动态加载的对象class⽂件可以使⽤Web服务的⽅式进⾏托管。在JVM之间通信时,RMI对远程对象和⾮远程对象的处理⽅式是不⼀样的,它并没有直接把远程对象的本体复制⼀份传递给客户端,⽽是传递了⼀个远程对象的Stub,Stub基本上相当于是远程对象的引⽤或者代理,可以理解为⼀个包含某些信息的指针。Stub对开发者是透明的,客户端可以像调⽤本地⽅法⼀样直接通过它来调⽤远程⽅法。Stub中包含了远程对象的定位信息,如Socket端⼝、服务端主机地址等等,也就是相当于利⽤RMI这个服务去远程加载类,先在RMI服务上绑定了⼀个对象,通过JNDI去获取调⽤RMI,然后获取到RMI绑定的那个对象,然后远程将其下载到本地,RMI远程有⼀个叫注册中⼼的东⻄,它⾥⾯有⼀个RMI注册表(RMIRegistry),服务端现在注册表⾥登记这个⽅法,然后当客户端进⾏查询的时候,注册中⼼给客户端返回⼀个叫Stub的代理,然后通过代理跟服务端进⾏交流。

我们⽤JNDI注⼊,是如何实现攻击的呢?

在JNDI服务中,RMI服务端除了直接绑定远程对象之外,还可以通过References类来绑定⼀个外部的远程对象(当前名称⽬录系统之外的对象)。绑定了Reference之后,服务端会先通过Referenceable.getReference()获取绑定对象的引⽤,并且在⽬录中保存。当客户端在lookup()查找这个远程对象时,客户端会获取相应的object factory,最终通过factory类将reference转换为具体的对象实例。

我们举⼀个例⼦,当我本地的客户端调⽤JNDI的lookup⽅法去获取⼀个叫testObj的远程对象的时候,会从RMI注册中⼼上获取到⼀个Reference 类的存根,也就是说相当于我这个RMI的注册中⼼绑定的不是具体的⽅法,⽽是返回⼀个Reference类,这个类才指向具体⽅法,然后客户端在获取到了这个Reference 类的之后,会在本地先进⾏查找其绑定的⽅法,如果在本地未找到,则会到远程服器 http://example.com:8888/testClassName.class

动态加载class,然后调⽤具体需要调⽤的⽅法

整个利⽤流程如下:

1. ⽬标代码中调⽤了Context.lookup(URL),且URL为⽤户可控;

2. 攻击者控制URI参数为恶意的RMI服务地址,如:rmi://hacker_rmi_server//name,然后去调⽤JNDI的lookup;

3. 攻击者RMI服务器向⽬标返回⼀个Reference对象,Reference对象中指定某个精⼼构造的Factory类;

4. ⽬标在进⾏lookup()操作时,会动态加载并实例化Factory类,接着调⽤factory.getObjectInstance()获取外部远程对象实例;

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

好啦本期内容到此结束

大家有收获吗

萌新如有疑惑可以随时在群里询问表哥们呢

记得继续关注我们哦~
【表哥有话说 第101期】Java安全-JNDI注⼊

原文始发于微信公众号(SKSEC):【表哥有话说 第101期】Java安全-JNDI注⼊

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年10月17日21:33:57
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   【表哥有话说 第101期】Java安全-JNDI注⼊https://cn-sec.com/archives/2121065.html

发表评论

匿名网友 填写信息