Sophos X-Ops Profile picture
A task force composed of our SophosLabs, SecOps, and SophosAI teams working together towards one goal: protecting our customers.

Dec 17, 2021, 21 tweets

NEW on #Log4Shell...

Inside the code: How the Log4Shell exploit works

1/21

The critical vulnerability in Apache’s #Log4j Java-based logging utility (CVE-2021-44248) has been called the “most critical vulnerability of the last decade.”

The flaw has forced developers of many software products to push out updates or mitigations to customers. 2/21

And Log4j’s maintainers have published two new versions since the bug was discovered—the second completely eliminating the feature that made the exploit possible in the first place. 3/21

👉 How Log4j logging works

Log4j outputs logging events using TTCCLayout: time, thread, category and context information. By default, it uses the below pictured pattern.

Here, %r outputs the time elapsed in milliseconds since the program was started; 4/21

%t is the thread, %p is priority of the event, %c is the category, %x is the nested diagnostic context associated with the thread generating the event, and %m is for application-supplied messages associated with the event. 5/21

It’s this final field where our vulnerability comes into play.

The vulnerability can be exploited when the “logger.error()” function is called with a message parameter that includes a JNDI URL (“jndi:dns://”, “jndi:ldap://”, or... 6/21

...any of the other JNDI defined interfaces discussed in our previous post).

When that URL is passed, a JNDI “lookup” will be called which can lead to remote code execution. 7/21

To replicate the vulnerability, we looked at one of the many proofs of concept, which replicates how many applications interact with Log4j.

In the code for logger/src/main/java/logger/App.java in this PoC, we can see that it calls logger.error() with a message parameter. 8/21

For debugging purposes, we changed the message to a test URL that uses DNS with JNDI (built with the Interactsh tool) to pass it as a parameter to the “logger.error()” function and stepped through the program. 9/21

We can see that after calling “logger.error()” method from “AbstractLogger” class with crafted URL, another method is called which is “logMessage”

The log.message method creates a message object with the provided URL. 10/21

Next, it calls “processLogEvent” from “LoggerConfig” class, to log the event.

Then it calls the “append” method from “AbstractOutputStreamAppender” class, which appends the message to the log. 11/21

👉 Where the badness happens

This in turns, calls “directEncodeEvent” method.

The directEncodeEvent method in turn calls the “getLayout().Encode” method, which formats the log message and adds the provided parameter— which is in this case the test exploit URL. 12/21

It then creates a new “StringBuilder” Object.

StringBuilder calls the “format” method from “MessagePatternConvert” class and parses the supplied URL, it looks for ‘$’ and ‘{’ to identify the URL. 13/21

After that it tries to identify various Name and values which are separated by ‘:’ or ‘-’:

Then it calls for “resolveVariable” method from “StrSubstitutor” class which will identify the Variables, it can be any of the following: 14/21

The code then calls the “lookup” method from the “Interpolator” class which will check the service associated with the variable (in this case, “jndi”)

Finding “jndi”, it calls the “lookup” method from the “jndiManager” class, which evaluates the value of the JNDI resource. 15/21

After that, it calls for “getURLOrDefaultInitCtx” from “IntialContext” class. This is where it creates the request that will be sent to the JNDI interface to retrieve context, depending on the URL provided. This is where the exploit begins to kick in. 16/21

In the case of a DNS URL, as this fires, we can see a DNS query to the provided URL with Wireshark.

(This is a test URL, and not actually malicious)

If URL is ‘jndi:ldap://’ it calls another method from “ldapURLConext” class to check if URL has “queryComponents”. 17/21

After that it calls “lookup” method in “ldapURLContext” class, “name” variable here contains the ldap URL.

This in turn connects with the ldap “ provided. 18/21

Then “flushBuffer” method will be called from “OutputStreamManager” class, here ‘buf’ contains the data returned from LDAP server, in this case the “mmm….” string we see below.

Looking at the packet capture in Wireshark, we see the request has the following bytes. 19/21

This is the serialized data and this will be displayed by the client as we can see below which shows that the vulnerability was exploited, notice the “[main] ERROR logger .App” string in the message followed by data. 20/21

See more details and Sophos coverage in the article from @thepacketrat and @hardik05...

news.sophos.com/en-us/2021/12/…

21/21

Share this Scrolly Tale with your friends.

A Scrolly Tale is a new way to read Twitter threads with a more visually immersive experience.
Discover more beautiful Scrolly Tales like this.

Keep scrolling