A third Log4j2 vulnerability was disclosed the night between Dec 17 and 18 by the Apache security team, and was given the ID of CVE-2021-45105.
According to the security advisory, 2.16.0, which fixed the two previous vulnerabilities, is susceptible to a DoS attack caused by a Stack-Overflow in Context Lookups in the configuration file’s layout patterns.
What is this CVE about? What can you do to fix it? How does it differ from the previous CVEs?
After disabling the JNDI functionality altogether, and removing the message lookup feature, 2.16.0 was thought to be unaffected by any further exploits using the Lookups in general.
However, although it prevented Remote Code Execution (RCE) and even Local Code Execution (LCE) exploits from taking place, it did not address crafted input that could manipulate the Context Lookup functionality into rendering an infinite recursion, the last leading to a stack-overflow and crash.
The StrSubstitutor and StrLookup classes in log4j-core are responsible for parsing Lookups that are made within layout patterns, such as ${ctx:username}. When the substitutor attempts to resolve the username lookup, it’ll evaluate the corresponding username variable of the ThreadContext map, and substitute it with its value (hence the name “substitutor”).
This all works, until someone messes with the values of variables in the ThreadContext Map.
At first, setting ThreadContext’s username variable to the string: ${ctx:username}, would produce the following steps for the substitutor, resulting in an infinite loop:
This did not crash the entire application as previously stated about CVE-2021-45046, before escalating its severity to Critical. It merely throws a java.lang.IllegalStateException, thanks to StrSubstitutor’s checkCyclicSubstitution method.
However, it was later discovered that one could use another feature of the lookup format and trigger an infinite loop that is not detected by Log4j. This will result in a java.lang.StackOverflowError, and cause an application Denial-of-Service. The vulnerable feature is the Lookup default value.
The Lookup pattern accepts the following format:
${lookupName:key:-defaultValue}
There may be readers who already figured this out:
If a variable in a ThreadContext map is attacker-controlled, one can use the default value to hold the same string as a Context Lookup.
Here’s an example of what it looks like:
Given a vulnerable application whose Log4j configuration sets a custom layout pattern as follows:
%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} – %msg%n ${ctx:user}
And assuming an application user can control the user variable, which is stored in the ThreadContext map.
An attacker can set the value of user to the following, and trigger a stack-overflow.:
${ctx:user1:-${ctx:user}}
How does it work?
Illustration of the crash traceback:
Other payloads were also found to trigger DoS in the same manner, one of them was mentioned by Ross Cohen, which created the ticket tracking this vulnerability:
${${::-${::-$${::-j}}}}
Apache have since released a fix to mitigate this vulnerability — 2.17.0, which fixed the StrSubstitutor logic, and prevented cases in which there is a recursion in lookup within the string itself:
2.17.0 also restricted recursive lookups that originate from the lookup value itself:
It is highly recommended for users of Log4j to upgrade to the latest 2.17.0 version.
If it is not possible at the moment, make sure your Log4j version is at least upgraded to 2.16.0, and ensure you are not using any Context lookups of the form:
${ctx:username}
You can switch such lookups into Thread Context Map patterns, such as:
%X, %mdc, or %MDC
If Context Lookups are mandatory, ensure that there are no such lookups that reference data that is user-controlled in any way.
Learn More: Get free tools to detect and fix Log4j vulnerabilities at our Log4j Vulnerability Resource Center.
In order to make sure that your dependencies are updated and secure, we recommend you to:
– Keep your open source components up to date with tools like Mend Remediate to make sure direct dependencies are automatically patched to the latest version.
– Add an integration to your repository, so that when a vulnerability is detected, you get a GitHub issue and a PR is opened automatically.
Integrating automated security into your repo, so that issues are addressed as soon as possible, is the best way to mitigate open source risks early, before they hit the headlines.
Want to find and fix vulnerable versions of Log4j in your code? Learn about our free CLI tool, or download it now.