diff --git a/.travis.yml b/.travis.yml
index 963c37fc6..b14482939 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,12 +3,6 @@ language: python
cache: pip
python:
- 2.7
- - 3.6
-matrix:
- include:
- - python: 3.7
- dist: xenial # required for Python 3.7 (travis-ci/travis-ci#9069)
- sudo: required # required for Python 3.7 (travis-ci/travis-ci#9069)
install:
#- pip install -r requirements.txt
- pip install flake8 # pytest # add another testing frameworks later
diff --git a/deployment_scripts/README.md b/deployment_scripts/README.md
index 92a2fd76e..10027edce 100644
--- a/deployment_scripts/README.md
+++ b/deployment_scripts/README.md
@@ -13,9 +13,10 @@ Don't forget to add python to PATH or do so while installing it via this script.
## Linux
-You must have root permissions, but there is no need to run the script as root.
+You must have root permissions, but don't run the script as root.
Launch deploy_linux.sh from scripts directory.
-First argument is an empty directory (script can create one) and second is branch you want to clone.
+First argument should be an empty directory (script can create one, default is ./infection_monkey) and second is the branch you want to clone (develop by default).
+Choose a directory where you have all the relevant permissions, for e.g. /home/your_username
Example usages:
./deploy_linux.sh (deploys under ./infection_monkey)
./deploy_linux.sh "/home/test/monkey" (deploys under /home/test/monkey)
diff --git a/monkey/common/utils/attack_utils.py b/monkey/common/utils/attack_utils.py
index cb3c8f029..708bc8f3c 100644
--- a/monkey/common/utils/attack_utils.py
+++ b/monkey/common/utils/attack_utils.py
@@ -10,6 +10,20 @@ class ScanStatus(Enum):
USED = 2
+class UsageEnum(Enum):
+ SMB = {ScanStatus.USED.value: "SMB exploiter ran the monkey by creating a service via MS-SCMR.",
+ ScanStatus.SCANNED.value: "SMB exploiter failed to run the monkey by creating a service via MS-SCMR."}
+ MIMIKATZ = {ScanStatus.USED.value: "Windows module loader was used to load Mimikatz DLL.",
+ ScanStatus.SCANNED.value: "Monkey tried to load Mimikatz DLL, but failed."}
+ MIMIKATZ_WINAPI = {ScanStatus.USED.value: "WinAPI was called to load mimikatz.",
+ ScanStatus.SCANNED.value: "Monkey tried to call WinAPI to load mimikatz."}
+ DROPPER = {ScanStatus.USED.value: "WinAPI was used to mark monkey files for deletion on next boot."}
+ SINGLETON_WINAPI = {ScanStatus.USED.value: "WinAPI was called to acquire system singleton for monkey's process.",
+ ScanStatus.SCANNED.value: "WinAPI call to acquire system singleton"
+ " for monkey process wasn't successful."}
+ DROPPER_WINAPI = {ScanStatus.USED.value: "WinAPI was used to mark monkey files for deletion on next boot."}
+
+
# Dict that describes what BITS job was used for
BITS_UPLOAD_STRING = "BITS job was used to upload monkey to a remote system."
diff --git a/monkey/infection_monkey/config.py b/monkey/infection_monkey/config.py
index f7e4cfae4..cb5bf881b 100644
--- a/monkey/infection_monkey/config.py
+++ b/monkey/infection_monkey/config.py
@@ -1,3 +1,4 @@
+import hashlib
import os
import json
import sys
@@ -13,9 +14,11 @@ GUID = str(uuid.getnode())
EXTERNAL_CONFIG_FILE = os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), 'monkey.bin')
+SENSITIVE_FIELDS = ["exploit_password_list", "exploit_user_list"]
+HIDDEN_FIELD_REPLACEMENT_CONTENT = "hidden"
+
class Configuration(object):
-
def from_kv(self, formatted_data):
# now we won't work at <2.7 for sure
network_import = importlib.import_module('infection_monkey.network')
@@ -53,6 +56,12 @@ class Configuration(object):
result = self.from_kv(formatted_data)
return result
+ @staticmethod
+ def hide_sensitive_info(config_dict):
+ for field in SENSITIVE_FIELDS:
+ config_dict[field] = HIDDEN_FIELD_REPLACEMENT_CONTENT
+ return config_dict
+
def as_dict(self):
result = {}
for key in dir(Configuration):
@@ -174,7 +183,7 @@ class Configuration(object):
# TCP Scanner
HTTP_PORTS = [80, 8080, 443,
- 8008, # HTTP alternate
+ 8008, # HTTP alternate
7001 # Oracle Weblogic default server port
]
tcp_target_ports = [22,
@@ -272,5 +281,17 @@ class Configuration(object):
PBA_linux_filename = None
PBA_windows_filename = None
+ @staticmethod
+ def hash_sensitive_data(sensitive_data):
+ """
+ Hash sensitive data (e.g. passwords). Used so the log won't contain sensitive data plain-text, as the log is
+ saved on client machines plain-text.
+
+ :param sensitive_data: the data to hash.
+ :return: the hashed data.
+ """
+ password_hashed = hashlib.sha512(sensitive_data).hexdigest()
+ return password_hashed
+
WormConfiguration = Configuration()
diff --git a/monkey/infection_monkey/control.py b/monkey/infection_monkey/control.py
index f34784041..4e917e5a6 100644
--- a/monkey/infection_monkey/control.py
+++ b/monkey/infection_monkey/control.py
@@ -125,6 +125,7 @@ class ControlClient(object):
@staticmethod
def send_telemetry(telem_category, data):
if not WormConfiguration.current_server:
+ LOG.error("Trying to send %s telemetry before current server is established, aborting." % telem_category)
return
try:
telemetry = {'monkey_guid': GUID, 'telem_category': telem_category, 'data': data}
@@ -168,7 +169,8 @@ class ControlClient(object):
try:
unknown_variables = WormConfiguration.from_kv(reply.json().get('config'))
- LOG.info("New configuration was loaded from server: %r" % (WormConfiguration.as_dict(),))
+ LOG.info("New configuration was loaded from server: %r" %
+ (WormConfiguration.hide_sensitive_info(WormConfiguration.as_dict()),))
except Exception as exc:
# we don't continue with default conf here because it might be dangerous
LOG.error("Error parsing JSON reply from control server %s (%s): %s",
diff --git a/monkey/infection_monkey/dropper.py b/monkey/infection_monkey/dropper.py
index 6bd9dab84..7c576fc30 100644
--- a/monkey/infection_monkey/dropper.py
+++ b/monkey/infection_monkey/dropper.py
@@ -15,7 +15,7 @@ from infection_monkey.exploit.tools.helpers import build_monkey_commandline_expl
from infection_monkey.model import MONKEY_CMDLINE_WINDOWS, MONKEY_CMDLINE_LINUX, GENERAL_CMDLINE_LINUX
from infection_monkey.system_info import SystemInfoCollector, OperatingSystem
from infection_monkey.telemetry.attack.t1106_telem import T1106Telem
-from common.utils.attack_utils import ScanStatus
+from common.utils.attack_utils import ScanStatus, UsageEnum
if "win32" == sys.platform:
from win32process import DETACHED_PROCESS
@@ -158,7 +158,6 @@ class MonkeyDrops(object):
else:
LOG.debug("Dropper source file '%s' is marked for deletion on next boot",
self._config['source_path'])
- T1106Telem(ScanStatus.USED, "WinAPI was used to mark monkey files"
- " for deletion on next boot.").send()
+ T1106Telem(ScanStatus.USED, UsageEnum.DROPPER_WINAPI).send()
except AttributeError:
LOG.error("Invalid configuration options. Failing")
diff --git a/monkey/infection_monkey/exploit/mssqlexec.py b/monkey/infection_monkey/exploit/mssqlexec.py
index bac923063..e4eaf3151 100644
--- a/monkey/infection_monkey/exploit/mssqlexec.py
+++ b/monkey/infection_monkey/exploit/mssqlexec.py
@@ -124,8 +124,9 @@ class MSSQLExploiter(HostExploiter):
# Core steps
# Trying to connect
conn = pymssql.connect(host, user, password, port=port, login_timeout=self.LOGIN_TIMEOUT)
- LOG.info('Successfully connected to host: {0}, '
- 'using user: {1}, password: {2}'.format(host, user, password))
+ LOG.info(
+ 'Successfully connected to host: {0}, using user: {1}, password (SHA-512): {2}'.format(
+ host, user, self._config.hash_sensitive_data(password)))
self.add_vuln_port(MSSQLExploiter.SQL_DEFAULT_TCP_PORT)
self.report_login_attempt(True, user, password)
cursor = conn.cursor()
diff --git a/monkey/infection_monkey/exploit/rdpgrinder.py b/monkey/infection_monkey/exploit/rdpgrinder.py
index 70b5da262..0cf225637 100644
--- a/monkey/infection_monkey/exploit/rdpgrinder.py
+++ b/monkey/infection_monkey/exploit/rdpgrinder.py
@@ -9,6 +9,8 @@ from rdpy.core.error import RDPSecurityNegoFail
from rdpy.protocol.rdp import rdp
from twisted.internet import reactor
+from common.utils.attack_utils import ScanStatus, BITS_UPLOAD_STRING
+from common.utils.exploit_enum import ExploitType
from infection_monkey.exploit import HostExploiter
from infection_monkey.exploit.tools.helpers import get_monkey_depth, get_target_monkey, build_monkey_commandline
from infection_monkey.exploit.tools.http_tools import HTTPTools
@@ -16,8 +18,6 @@ from infection_monkey.model import RDP_CMDLINE_HTTP_BITS, RDP_CMDLINE_HTTP_VBS
from infection_monkey.network.tools import check_tcp_port
from infection_monkey.telemetry.attack.t1197_telem import T1197Telem
from infection_monkey.utils import utf_to_ascii
-from common.utils.exploit_enum import ExploitType
-from common.utils.attack_utils import ScanStatus, BITS_UPLOAD_STRING
__author__ = 'hoffer'
@@ -298,8 +298,8 @@ class RdpExploiter(HostExploiter):
for user, password in user_password_pairs:
try:
# run command using rdp.
- LOG.info("Trying RDP logging into victim %r with user %s and password '%s'",
- self.host, user, password)
+ LOG.info("Trying RDP logging into victim %r with user %s and password (SHA-512) '%s'",
+ self.host, user, self._config.hash_sensitive_data(password))
LOG.info("RDP connected to %r", self.host)
@@ -326,8 +326,8 @@ class RdpExploiter(HostExploiter):
except Exception as exc:
LOG.debug("Error logging into victim %r with user"
- " %s and password '%s': (%s)", self.host,
- user, password, exc)
+ " %s and password (SHA-512) '%s': (%s)", self.host,
+ user, self._config.hash_sensitive_data(password), exc)
continue
http_thread.join(DOWNLOAD_TIMEOUT)
diff --git a/monkey/infection_monkey/exploit/smbexec.py b/monkey/infection_monkey/exploit/smbexec.py
index dc7b38e89..0a17d7622 100644
--- a/monkey/infection_monkey/exploit/smbexec.py
+++ b/monkey/infection_monkey/exploit/smbexec.py
@@ -11,7 +11,7 @@ from infection_monkey.network import SMBFinger
from infection_monkey.network.tools import check_tcp_port
from common.utils.exploit_enum import ExploitType
from infection_monkey.telemetry.attack.t1035_telem import T1035Telem
-from common.utils.attack_utils import ScanStatus
+from common.utils.attack_utils import ScanStatus, UsageEnum
LOG = getLogger(__name__)
@@ -68,8 +68,8 @@ class SmbExploiter(HostExploiter):
self._config.smb_download_timeout)
if remote_full_path is not None:
- LOG.debug("Successfully logged in %r using SMB (%s : %s : %s : %s)",
- self.host, user, password, lm_hash, ntlm_hash)
+ LOG.debug("Successfully logged in %r using SMB (%s : (SHA-512) %s : %s : %s)",
+ self.host, user, self._config.hash_sensitive_data(password), lm_hash, ntlm_hash)
self.report_login_attempt(True, user, password, lm_hash, ntlm_hash)
self.add_vuln_port("%s or %s" % (SmbExploiter.KNOWN_PROTOCOLS['139/SMB'][1],
SmbExploiter.KNOWN_PROTOCOLS['445/SMB'][1]))
@@ -81,8 +81,8 @@ class SmbExploiter(HostExploiter):
except Exception as exc:
LOG.debug("Exception when trying to copy file using SMB to %r with user:"
- " %s, password: '%s', LM hash: %s, NTLM hash: %s: (%s)", self.host,
- user, password, lm_hash, ntlm_hash, exc)
+ " %s, password (SHA-512): '%s', LM hash: %s, NTLM hash: %s: (%s)", self.host,
+ user, self._config.hash_sensitive_data(password), lm_hash, ntlm_hash, exc)
continue
if not exploited:
@@ -133,11 +133,11 @@ class SmbExploiter(HostExploiter):
service = resp['lpServiceHandle']
try:
scmr.hRStartServiceW(scmr_rpc, service)
- T1035Telem(ScanStatus.USED, "SMB exploiter ran the monkey by creating a service via MS-SCMR.").send()
+ status = ScanStatus.USED
except:
- T1035Telem(ScanStatus.SCANNED,
- "SMB exploiter failed to run the monkey by creating a service via MS-SCMR.").send()
+ status = ScanStatus.SCANNED
pass
+ T1035Telem(status, UsageEnum.SMB).send()
scmr.hRDeleteService(scmr_rpc, service)
scmr.hRCloseServiceHandle(scmr_rpc, service)
diff --git a/monkey/infection_monkey/exploit/sshexec.py b/monkey/infection_monkey/exploit/sshexec.py
index dfa922b24..f26630ed4 100644
--- a/monkey/infection_monkey/exploit/sshexec.py
+++ b/monkey/infection_monkey/exploit/sshexec.py
@@ -1,10 +1,11 @@
+import StringIO
import logging
import time
import paramiko
-import StringIO
import infection_monkey.monkeyfs as monkeyfs
+from common.utils.exploit_enum import ExploitType
from infection_monkey.exploit import HostExploiter
from infection_monkey.exploit.tools.helpers import get_target_monkey, get_monkey_depth, build_monkey_commandline
from infection_monkey.exploit.tools.helpers import get_interface_to_target
@@ -73,26 +74,26 @@ class SSHExploiter(HostExploiter):
exploited = False
- for user, curpass in user_password_pairs:
+ for user, current_password in user_password_pairs:
try:
ssh.connect(self.host.ip_addr,
username=user,
- password=curpass,
+ password=current_password,
port=port,
timeout=None)
- LOG.debug("Successfully logged in %r using SSH (%s : %s)",
- self.host, user, curpass)
+ LOG.debug("Successfully logged in %r using SSH. User: %s, pass (SHA-512): %s)",
+ self.host, user, self._config.hash_sensitive_data(current_password))
exploited = True
self.add_vuln_port(port)
- self.report_login_attempt(True, user, curpass)
+ self.report_login_attempt(True, user, current_password)
break
except Exception as exc:
LOG.debug("Error logging into victim %r with user"
- " %s and password '%s': (%s)", self.host,
- user, curpass, exc)
- self.report_login_attempt(False, user, curpass)
+ " %s and password (SHA-512) '%s': (%s)", self.host,
+ user, self._config.hash_sensitive_data(current_password), exc)
+ self.report_login_attempt(False, user, current_password)
continue
return exploited
@@ -111,7 +112,7 @@ class SSHExploiter(HostExploiter):
LOG.info("SSH port is closed on %r, skipping", self.host)
return False
- #Check for possible ssh exploits
+ # Check for possible ssh exploits
exploited = self.exploit_with_ssh_keys(port, ssh)
if not exploited:
exploited = self.exploit_with_login_creds(port, ssh)
@@ -164,17 +165,17 @@ class SSHExploiter(HostExploiter):
ftp.putfo(file_obj, self._config.dropper_target_path_linux, file_size=monkeyfs.getsize(src_path),
callback=self.log_transfer)
ftp.chmod(self._config.dropper_target_path_linux, 0o777)
- T1105Telem(ScanStatus.USED,
- get_interface_to_target(self.host.ip_addr),
- self.host.ip_addr,
- src_path).send()
+ status = ScanStatus.USED
ftp.close()
except Exception as exc:
LOG.debug("Error uploading file into victim %r: (%s)", self.host, exc)
- T1105Telem(ScanStatus.SCANNED,
- get_interface_to_target(self.host.ip_addr),
- self.host.ip_addr,
- src_path).send()
+ status = ScanStatus.SCANNED
+
+ T1105Telem(status,
+ get_interface_to_target(self.host.ip_addr),
+ self.host.ip_addr,
+ src_path).send()
+ if status == ScanStatus.SCANNED:
return False
try:
diff --git a/monkey/infection_monkey/exploit/tools/helpers.py b/monkey/infection_monkey/exploit/tools/helpers.py
index 83a8bfd92..bc74128e2 100644
--- a/monkey/infection_monkey/exploit/tools/helpers.py
+++ b/monkey/infection_monkey/exploit/tools/helpers.py
@@ -19,6 +19,7 @@ def get_interface_to_target(dst):
s.connect((dst, 1))
ip_to_dst = s.getsockname()[0]
except KeyError:
+ LOG.debug("Couldn't get an interface to the target, presuming that target is localhost.")
ip_to_dst = '127.0.0.1'
finally:
s.close()
diff --git a/monkey/infection_monkey/exploit/wmiexec.py b/monkey/infection_monkey/exploit/wmiexec.py
index c9287a25e..1f3e1cecc 100644
--- a/monkey/infection_monkey/exploit/wmiexec.py
+++ b/monkey/infection_monkey/exploit/wmiexec.py
@@ -36,8 +36,10 @@ class WmiExploiter(HostExploiter):
creds = self._config.get_exploit_user_password_or_hash_product()
for user, password, lm_hash, ntlm_hash in creds:
- LOG.debug("Attempting to connect %r using WMI with user,password,lm hash,ntlm hash: ('%s','%s','%s','%s')",
- self.host, user, password, lm_hash, ntlm_hash)
+ password_hashed = self._config.hash_sensitive_data(password)
+ LOG.debug("Attempting to connect %r using WMI with "
+ "user,password (SHA-512),lm hash,ntlm hash: ('%s','%s','%s','%s')",
+ self.host, user, password_hashed, lm_hash, ntlm_hash)
wmi_connection = WmiTools.WmiConnection()
@@ -47,23 +49,23 @@ class WmiExploiter(HostExploiter):
self.report_login_attempt(False, user, password, lm_hash, ntlm_hash)
LOG.debug("Failed connecting to %r using WMI with "
"user,password,lm hash,ntlm hash: ('%s','%s','%s','%s')",
- self.host, user, password, lm_hash, ntlm_hash)
+ self.host, user, password_hashed, lm_hash, ntlm_hash)
continue
except DCERPCException:
self.report_login_attempt(False, user, password, lm_hash, ntlm_hash)
LOG.debug("Failed connecting to %r using WMI with "
"user,password,lm hash,ntlm hash: ('%s','%s','%s','%s')",
- self.host, user, password, lm_hash, ntlm_hash)
+ self.host, user, password_hashed, lm_hash, ntlm_hash)
continue
except socket.error:
LOG.debug("Network error in WMI connection to %r with "
"user,password,lm hash,ntlm hash: ('%s','%s','%s','%s')",
- self.host, user, password, lm_hash, ntlm_hash)
+ self.host, user, password_hashed, lm_hash, ntlm_hash)
return False
except Exception as exc:
LOG.debug("Unknown WMI connection error to %r with "
"user,password,lm hash,ntlm hash: ('%s','%s','%s','%s') (%s):\n%s",
- self.host, user, password, lm_hash, ntlm_hash, exc, traceback.format_exc())
+ self.host, user, password_hashed, lm_hash, ntlm_hash, exc, traceback.format_exc())
return False
self.report_login_attempt(True, user, password, lm_hash, ntlm_hash)
@@ -94,7 +96,8 @@ class WmiExploiter(HostExploiter):
# execute the remote dropper in case the path isn't final
elif remote_full_path.lower() != self._config.dropper_target_path_win_32.lower():
cmdline = DROPPER_CMDLINE_WINDOWS % {'dropper_path': remote_full_path} + \
- build_monkey_commandline(self.host, get_monkey_depth() - 1, self._config.dropper_target_path_win_32)
+ build_monkey_commandline(
+ self.host, get_monkey_depth() - 1, self._config.dropper_target_path_win_32)
else:
cmdline = MONKEY_CMDLINE_WINDOWS % {'monkey_path': remote_full_path} + \
build_monkey_commandline(self.host, get_monkey_depth() - 1)
@@ -121,3 +124,4 @@ class WmiExploiter(HostExploiter):
return success
return False
+
diff --git a/monkey/infection_monkey/main.py b/monkey/infection_monkey/main.py
index b8e292243..2ddf9127e 100644
--- a/monkey/infection_monkey/main.py
+++ b/monkey/infection_monkey/main.py
@@ -68,7 +68,7 @@ def main():
else:
print("Config file wasn't supplied and default path: %s wasn't found, using internal default" % (config_file,))
- print("Loaded Configuration: %r" % WormConfiguration.as_dict())
+ print("Loaded Configuration: %r" % WormConfiguration.hide_sensitive_info(WormConfiguration.as_dict()))
# Make sure we're not in a machine that has the kill file
kill_path = os.path.expandvars(
diff --git a/monkey/infection_monkey/monkey.py b/monkey/infection_monkey/monkey.py
index 50af09e4a..ce5ab2093 100644
--- a/monkey/infection_monkey/monkey.py
+++ b/monkey/infection_monkey/monkey.py
@@ -184,7 +184,7 @@ class InfectionMonkey(object):
(':'+self._default_server_port if self._default_server_port else ''))
else:
machine.set_default_server(self._default_server)
- LOG.debug("Default server: %s set to machine: %r" % (self._default_server, machine))
+ LOG.debug("Default server for machine: %r set to %s" % (machine, machine.default_server))
# Order exploits according to their type
if WormConfiguration.should_exploit:
@@ -255,6 +255,7 @@ class InfectionMonkey(object):
if WormConfiguration.self_delete_in_cleanup \
and -1 == sys.executable.find('python'):
try:
+ status = None
if "win32" == sys.platform:
from _subprocess import SW_HIDE, STARTF_USESHOWWINDOW, CREATE_NEW_CONSOLE
startupinfo = subprocess.STARTUPINFO()
@@ -265,10 +266,12 @@ class InfectionMonkey(object):
close_fds=True, startupinfo=startupinfo)
else:
os.remove(sys.executable)
- T1107Telem(ScanStatus.USED, sys.executable).send()
+ status = ScanStatus.USED
except Exception as exc:
LOG.error("Exception in self delete: %s", exc)
- T1107Telem(ScanStatus.SCANNED, sys.executable).send()
+ status = ScanStatus.SCANNED
+ if status:
+ T1107Telem(status, sys.executable).send()
def send_log(self):
monkey_log_path = utils.get_monkey_log_path()
diff --git a/monkey/infection_monkey/post_breach/actions/users_custom_pba.py b/monkey/infection_monkey/post_breach/actions/users_custom_pba.py
index d923cb60e..a388813ab 100644
--- a/monkey/infection_monkey/post_breach/actions/users_custom_pba.py
+++ b/monkey/infection_monkey/post_breach/actions/users_custom_pba.py
@@ -82,17 +82,22 @@ class UsersPBA(PBA):
pba_file_contents = ControlClient.get_pba_file(filename)
+ status = None
if not pba_file_contents or not pba_file_contents.content:
LOG.error("Island didn't respond with post breach file.")
- T1105Telem(ScanStatus.SCANNED,
- WormConfiguration.current_server.split(':')[0],
- get_interface_to_target(WormConfiguration.current_server.split(':')[0]),
- filename).send()
- return False
- T1105Telem(ScanStatus.USED,
+ status = ScanStatus.SCANNED
+
+ if not status:
+ status = ScanStatus.USED
+
+ T1105Telem(status,
WormConfiguration.current_server.split(':')[0],
get_interface_to_target(WormConfiguration.current_server.split(':')[0]),
filename).send()
+
+ if status == ScanStatus.SCANNED:
+ return False
+
try:
with open(os.path.join(dst_dir, filename), 'wb') as written_PBA_file:
written_PBA_file.write(pba_file_contents.content)
diff --git a/monkey/infection_monkey/system_info/mimikatz_collector.py b/monkey/infection_monkey/system_info/mimikatz_collector.py
index 96b53be35..2951b7ebc 100644
--- a/monkey/infection_monkey/system_info/mimikatz_collector.py
+++ b/monkey/infection_monkey/system_info/mimikatz_collector.py
@@ -5,7 +5,7 @@ import socket
import zipfile
import infection_monkey.config
-from common.utils.attack_utils import ScanStatus
+from common.utils.attack_utils import ScanStatus, UsageEnum
from infection_monkey.telemetry.attack.t1129_telem import T1129Telem
from infection_monkey.telemetry.attack.t1106_telem import T1106Telem
from infection_monkey.pyinstaller_utils import get_binary_file_path, get_binaries_dir_path
@@ -47,16 +47,16 @@ class MimikatzCollector(object):
collect_proto = ctypes.WINFUNCTYPE(ctypes.c_int)
get_proto = ctypes.WINFUNCTYPE(MimikatzCollector.LogonData)
get_text_output_proto = ctypes.WINFUNCTYPE(ctypes.c_wchar_p)
- T1106Telem(ScanStatus.USED, "WinAPI was called to load mimikatz.").send()
self._collect = collect_proto(("collect", self._dll))
self._get = get_proto(("get", self._dll))
self._get_text_output_proto = get_text_output_proto(("getTextOutput", self._dll))
self._isInit = True
- T1129Telem(ScanStatus.USED, "Windows module loader was used to load Mimikatz DLL.").send()
+ status = ScanStatus.USED
except Exception:
LOG.exception("Error initializing mimikatz collector")
- T1129Telem(ScanStatus.SCANNED, "Monkey tried to load Mimikatz DLL, but failed.").send()
- T1106Telem(ScanStatus.SCANNED, "Monkey tried to call WinAPI to load mimikatz.").send()
+ status = ScanStatus.SCANNED
+ T1106Telem(status, UsageEnum.MIMIKATZ_WINAPI).send()
+ T1129Telem(status, UsageEnum.MIMIKATZ).send()
def get_logon_info(self):
"""
diff --git a/monkey/infection_monkey/system_singleton.py b/monkey/infection_monkey/system_singleton.py
index 06a2ea689..50fa6363b 100644
--- a/monkey/infection_monkey/system_singleton.py
+++ b/monkey/infection_monkey/system_singleton.py
@@ -5,7 +5,7 @@ from abc import ABCMeta, abstractmethod
from infection_monkey.config import WormConfiguration
from infection_monkey.telemetry.attack.t1106_telem import T1106Telem
-from common.utils.attack_utils import ScanStatus
+from common.utils.attack_utils import ScanStatus, UsageEnum
__author__ = 'itamar'
@@ -45,22 +45,25 @@ class WindowsSystemSingleton(_SystemSingleton):
ctypes.c_bool(True),
ctypes.c_char_p(self._mutex_name))
last_error = ctypes.windll.kernel32.GetLastError()
+
+ status = None
if not handle:
LOG.error("Cannot acquire system singleton %r, unknown error %d",
self._mutex_name, last_error)
- T1106Telem(ScanStatus.SCANNED, "WinAPI call to acquire system singleton "
- "for monkey process wasn't successful.").send()
-
- return False
+ status = ScanStatus.SCANNED
if winerror.ERROR_ALREADY_EXISTS == last_error:
+ status = ScanStatus.SCANNED
LOG.debug("Cannot acquire system singleton %r, mutex already exist",
self._mutex_name)
+ if not status:
+ status = ScanStatus.USED
+ T1106Telem(status, UsageEnum.SINGLETON_WINAPI).send()
+ if status == ScanStatus.SCANNED:
return False
self._mutex_handle = handle
- T1106Telem(ScanStatus.USED, "WinAPI was called to acquire system singleton for monkey's process.").send()
LOG.debug("Global singleton mutex %r acquired",
self._mutex_name)
diff --git a/monkey/infection_monkey/telemetry/attack/t1035_telem.py b/monkey/infection_monkey/telemetry/attack/t1035_telem.py
index b3d7c90de..4ca9dc93c 100644
--- a/monkey/infection_monkey/telemetry/attack/t1035_telem.py
+++ b/monkey/infection_monkey/telemetry/attack/t1035_telem.py
@@ -6,6 +6,6 @@ class T1035Telem(UsageTelem):
"""
T1035 telemetry.
:param status: ScanStatus of technique
- :param usage: Usage string
+ :param usage: Enum of UsageEnum type
"""
super(T1035Telem, self).__init__('T1035', status, usage)
diff --git a/monkey/infection_monkey/telemetry/attack/t1106_telem.py b/monkey/infection_monkey/telemetry/attack/t1106_telem.py
index 30cad6072..422313540 100644
--- a/monkey/infection_monkey/telemetry/attack/t1106_telem.py
+++ b/monkey/infection_monkey/telemetry/attack/t1106_telem.py
@@ -4,8 +4,8 @@ from infection_monkey.telemetry.attack.usage_telem import UsageTelem
class T1106Telem(UsageTelem):
def __init__(self, status, usage):
"""
- T1129 telemetry.
+ T1106 telemetry.
:param status: ScanStatus of technique
- :param usage: Usage string
+ :param usage: Enum name of UsageEnum
"""
super(T1106Telem, self).__init__("T1106", status, usage)
diff --git a/monkey/infection_monkey/telemetry/attack/t1129_telem.py b/monkey/infection_monkey/telemetry/attack/t1129_telem.py
index fb7d776c6..4e7a12ce8 100644
--- a/monkey/infection_monkey/telemetry/attack/t1129_telem.py
+++ b/monkey/infection_monkey/telemetry/attack/t1129_telem.py
@@ -6,6 +6,6 @@ class T1129Telem(UsageTelem):
"""
T1129 telemetry.
:param status: ScanStatus of technique
- :param usage: Usage string
+ :param usage: Enum of UsageEnum type
"""
super(T1129Telem, self).__init__("T1129", status, usage)
diff --git a/monkey/infection_monkey/telemetry/attack/usage_telem.py b/monkey/infection_monkey/telemetry/attack/usage_telem.py
index 48ff5431c..4b47d8be3 100644
--- a/monkey/infection_monkey/telemetry/attack/usage_telem.py
+++ b/monkey/infection_monkey/telemetry/attack/usage_telem.py
@@ -5,12 +5,12 @@ class UsageTelem(AttackTelem):
def __init__(self, technique, status, usage):
"""
- T1035 telemetry.
+ :param technique: Id of technique
:param status: ScanStatus of technique
- :param usage: Usage string
+ :param usage: Enum of UsageEnum type
"""
super(UsageTelem, self).__init__(technique, status)
- self.usage = usage
+ self.usage = usage.name
def get_data(self):
data = super(UsageTelem, self).get_data()
diff --git a/monkey/monkey_island/cc/consts.py b/monkey/monkey_island/cc/consts.py
index deb1db449..c302f6fb7 100644
--- a/monkey/monkey_island/cc/consts.py
+++ b/monkey/monkey_island/cc/consts.py
@@ -3,3 +3,4 @@ import os
__author__ = 'itay.mizeretz'
MONKEY_ISLAND_ABS_PATH = os.path.join(os.getcwd(), 'monkey_island')
+DEFAULT_MONKEY_TTL_EXPIRY_DURATION_IN_SECONDS = 60 * 5
diff --git a/monkey/monkey_island/cc/models/monkey.py b/monkey/monkey_island/cc/models/monkey.py
index f9f556844..5b2fff620 100644
--- a/monkey/monkey_island/cc/models/monkey.py
+++ b/monkey/monkey_island/cc/models/monkey.py
@@ -1,11 +1,11 @@
"""
Define a Document Schema for the Monkey document.
"""
-import mongoengine
from mongoengine import Document, StringField, ListField, BooleanField, EmbeddedDocumentField, ReferenceField, \
- DateTimeField
+ DateTimeField, DynamicField, DoesNotExist
-from monkey_island.cc.models.monkey_ttl import MonkeyTtl
+from monkey_island.cc.models.monkey_ttl import MonkeyTtl, create_monkey_ttl_document
+from monkey_island.cc.consts import DEFAULT_MONKEY_TTL_EXPIRY_DURATION_IN_SECONDS
class Monkey(Document):
@@ -26,8 +26,11 @@ class Monkey(Document):
ip_addresses = ListField(StringField())
keepalive = DateTimeField()
modifytime = DateTimeField()
- # TODO change this to an embedded document as well - RN it's an unnamed tuple which is confusing.
- parent = ListField(ListField(StringField()))
+ # TODO make "parent" an embedded document, so this can be removed and the schema explained (and validated) verbosly.
+ # This is a temporary fix, since mongoengine doesn't allow for lists of strings to be null
+ # (even with required=False of null=True).
+ # See relevant issue: https://github.com/MongoEngine/mongoengine/issues/1904
+ parent = ListField(ListField(DynamicField()))
config_error = BooleanField()
critical_services = ListField(StringField())
pba_results = ListField()
@@ -38,13 +41,22 @@ class Monkey(Document):
@staticmethod
def get_single_monkey_by_id(db_id):
try:
- return Monkey.objects(id=db_id)[0]
- except IndexError:
- raise MonkeyNotFoundError("id: {0}".format(str(db_id)))
+ return Monkey.objects.get(id=db_id)
+ except DoesNotExist as ex:
+ raise MonkeyNotFoundError("info: {0} | id: {1}".format(ex.message, str(db_id)))
+
+ @staticmethod
+ def get_single_monkey_by_guid(monkey_guid):
+ try:
+ return Monkey.objects.get(guid=monkey_guid)
+ except DoesNotExist as ex:
+ raise MonkeyNotFoundError("info: {0} | guid: {1}".format(ex.message, str(monkey_guid)))
@staticmethod
def get_latest_modifytime():
- return Monkey.objects.order_by('-modifytime').first().modifytime
+ if Monkey.objects.count() > 0:
+ return Monkey.objects.order_by('-modifytime').first().modifytime
+ return None
def is_dead(self):
monkey_is_dead = False
@@ -55,7 +67,7 @@ class Monkey(Document):
if MonkeyTtl.objects(id=self.ttl_ref.id).count() == 0:
# No TTLs - monkey has timed out. The monkey is MIA.
monkey_is_dead = True
- except (mongoengine.DoesNotExist, AttributeError):
+ except (DoesNotExist, AttributeError):
# Trying to dereference unknown document - the monkey is MIA.
monkey_is_dead = True
return monkey_is_dead
@@ -79,6 +91,10 @@ class Monkey(Document):
def get_tunneled_monkeys():
return Monkey.objects(tunnel__exists=True)
+ def renew_ttl(self, duration=DEFAULT_MONKEY_TTL_EXPIRY_DURATION_IN_SECONDS):
+ self.ttl_ref = create_monkey_ttl_document(duration)
+ self.save()
+
class MonkeyNotFoundError(Exception):
pass
diff --git a/monkey/monkey_island/cc/models/monkey_ttl.py b/monkey/monkey_island/cc/models/monkey_ttl.py
index 9ccf77974..b3e59d5ed 100644
--- a/monkey/monkey_island/cc/models/monkey_ttl.py
+++ b/monkey/monkey_island/cc/models/monkey_ttl.py
@@ -38,3 +38,16 @@ class MonkeyTtl(Document):
}
expire_at = DateTimeField()
+
+
+def create_monkey_ttl_document(expiry_duration_in_seconds):
+ """
+ Create a new Monkey TTL document and save it as a document.
+ :param expiry_duration_in_seconds: How long should the TTL last for. THIS IS A LOWER BOUND - depends on mongodb
+ performance.
+ :return: The TTL document. To get its ID use `.id`.
+ """
+ # The TTL data uses the new `models` module which depends on mongoengine.
+ current_ttl = MonkeyTtl.create_ttl_expire_in(expiry_duration_in_seconds)
+ current_ttl.save()
+ return current_ttl
diff --git a/monkey/monkey_island/cc/models/test_monkey.py b/monkey/monkey_island/cc/models/test_monkey.py
index ba8ff10fc..6115386ea 100644
--- a/monkey/monkey_island/cc/models/test_monkey.py
+++ b/monkey/monkey_island/cc/models/test_monkey.py
@@ -46,6 +46,19 @@ class TestMonkey(IslandTestCase):
self.assertTrue(mia_monkey.is_dead())
self.assertFalse(alive_monkey.is_dead())
+ def test_ttl_renewal(self):
+ self.fail_if_not_testing_env()
+ self.clean_monkey_db()
+
+ # Arrange
+ monkey = Monkey(guid=str(uuid.uuid4()))
+ monkey.save()
+ self.assertIsNone(monkey.ttl_ref)
+
+ # act + assert
+ monkey.renew_ttl()
+ self.assertIsNotNone(monkey.ttl_ref)
+
def test_get_single_monkey_by_id(self):
self.fail_if_not_testing_env()
self.clean_monkey_db()
diff --git a/monkey/monkey_island/cc/resources/monkey.py b/monkey/monkey_island/cc/resources/monkey.py
index 36720e465..8e523a8a7 100644
--- a/monkey/monkey_island/cc/resources/monkey.py
+++ b/monkey/monkey_island/cc/resources/monkey.py
@@ -5,26 +5,17 @@ import dateutil.parser
import flask_restful
from flask import request
+from monkey_island.cc.consts import DEFAULT_MONKEY_TTL_EXPIRY_DURATION_IN_SECONDS
from monkey_island.cc.database import mongo
-from monkey_island.cc.models.monkey_ttl import MonkeyTtl
+from monkey_island.cc.models.monkey_ttl import create_monkey_ttl_document
from monkey_island.cc.services.config import ConfigService
from monkey_island.cc.services.node import NodeService
-MONKEY_TTL_EXPIRY_DURATION_IN_SECONDS = 60 * 5
-
__author__ = 'Barak'
# TODO: separate logic from interface
-def create_monkey_ttl():
- # The TTL data uses the new `models` module which depends on mongoengine.
- current_ttl = MonkeyTtl.create_ttl_expire_in(MONKEY_TTL_EXPIRY_DURATION_IN_SECONDS)
- current_ttl.save()
- ttlid = current_ttl.id
- return ttlid
-
-
class Monkey(flask_restful.Resource):
# Used by monkey. can't secure.
@@ -58,8 +49,8 @@ class Monkey(flask_restful.Resource):
tunnel_host_ip = monkey_json['tunnel'].split(":")[-2].replace("//", "")
NodeService.set_monkey_tunnel(monkey["_id"], tunnel_host_ip)
- ttlid = create_monkey_ttl()
- update['$set']['ttl_ref'] = ttlid
+ ttl = create_monkey_ttl_document(DEFAULT_MONKEY_TTL_EXPIRY_DURATION_IN_SECONDS)
+ update['$set']['ttl_ref'] = ttl.id
return mongo.db.monkey.update({"_id": monkey["_id"]}, update, upsert=False)
@@ -120,7 +111,8 @@ class Monkey(flask_restful.Resource):
tunnel_host_ip = monkey_json['tunnel'].split(":")[-2].replace("//", "")
monkey_json.pop('tunnel')
- monkey_json['ttl_ref'] = create_monkey_ttl()
+ ttl = create_monkey_ttl_document(DEFAULT_MONKEY_TTL_EXPIRY_DURATION_IN_SECONDS)
+ monkey_json['ttl_ref'] = ttl.id
mongo.db.monkey.update({"guid": monkey_json["guid"]},
{"$set": monkey_json},
diff --git a/monkey/monkey_island/cc/resources/telemetry.py b/monkey/monkey_island/cc/resources/telemetry.py
index d4aaa72df..279547dc1 100644
--- a/monkey/monkey_island/cc/resources/telemetry.py
+++ b/monkey/monkey_island/cc/resources/telemetry.py
@@ -15,10 +15,10 @@ from monkey_island.cc.services.edge import EdgeService
from monkey_island.cc.services.node import NodeService
from monkey_island.cc.encryptor import encryptor
from monkey_island.cc.services.wmi_handler import WMIHandler
+from monkey_island.cc.models.monkey import Monkey
__author__ = 'Barak'
-
logger = logging.getLogger(__name__)
@@ -49,6 +49,9 @@ class Telemetry(flask_restful.Resource):
telemetry_json = json.loads(request.data)
telemetry_json['timestamp'] = datetime.now()
+ # Monkey communicated, so it's alive. Update the TTL.
+ Monkey.get_single_monkey_by_guid(telemetry_json['monkey_guid']).renew_ttl()
+
monkey = NodeService.get_monkey_by_guid(telemetry_json['monkey_guid'])
try:
@@ -59,7 +62,7 @@ class Telemetry(flask_restful.Resource):
else:
logger.info('Got unknown type of telemetry: %s' % telem_category)
except Exception as ex:
- logger.error("Exception caught while processing telemetry", exc_info=True)
+ logger.error("Exception caught while processing telemetry. Info: {}".format(ex.message), exc_info=True)
telem_id = mongo.db.telemetry.insert(telemetry_json)
return mongo.db.telemetry.find_one_or_404({"_id": telem_id})
@@ -188,7 +191,7 @@ class Telemetry(flask_restful.Resource):
Telemetry.add_system_info_creds_to_config(creds)
Telemetry.replace_user_dot_with_comma(creds)
if 'mimikatz' in telemetry_json['data']:
- users_secrets = mimikatz_utils.MimikatzSecrets.\
+ users_secrets = mimikatz_utils.MimikatzSecrets. \
extract_secrets_from_mimikatz(telemetry_json['data'].get('mimikatz', ''))
if 'wmi' in telemetry_json['data']:
wmi_handler = WMIHandler(monkey_id, telemetry_json['data']['wmi'], users_secrets)
diff --git a/monkey/monkey_island/cc/resources/telemetry_feed.py b/monkey/monkey_island/cc/resources/telemetry_feed.py
index a4f090758..e271c45c5 100644
--- a/monkey/monkey_island/cc/resources/telemetry_feed.py
+++ b/monkey/monkey_island/cc/resources/telemetry_feed.py
@@ -1,3 +1,4 @@
+import logging
from datetime import datetime
import dateutil
@@ -9,6 +10,8 @@ from monkey_island.cc.auth import jwt_required
from monkey_island.cc.database import mongo
from monkey_island.cc.services.node import NodeService
+logger = logging.getLogger(__name__)
+
__author__ = 'itay.mizeretz'
@@ -23,11 +26,15 @@ class TelemetryFeed(flask_restful.Resource):
telemetries = telemetries.sort([('timestamp', flask_pymongo.ASCENDING)])
- return \
- {
- 'telemetries': [TelemetryFeed.get_displayed_telemetry(telem) for telem in telemetries],
- 'timestamp': datetime.now().isoformat()
- }
+ try:
+ return \
+ {
+ 'telemetries': [TelemetryFeed.get_displayed_telemetry(telem) for telem in telemetries],
+ 'timestamp': datetime.now().isoformat()
+ }
+ except KeyError as err:
+ logger.error("Failed parsing telemetries. Error: {0}.".format(err.message))
+ return {'telemetries': [], 'timestamp': datetime.now().isoformat()}
@staticmethod
def get_displayed_telemetry(telem):
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1035.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1035.py
index a651a8288..fcc230be5 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/T1035.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1035.py
@@ -1,10 +1,10 @@
from monkey_island.cc.database import mongo
-from monkey_island.cc.services.attack.technique_reports import AttackTechnique
+from monkey_island.cc.services.attack.technique_reports import UsageTechnique
__author__ = "VakarisZ"
-class T1035(AttackTechnique):
+class T1035(UsageTechnique):
tech_id = "T1035"
unscanned_msg = "Monkey didn't try to interact with Windows services."
scanned_msg = "Monkey tried to interact with Windows services, but failed."
@@ -13,5 +13,5 @@ class T1035(AttackTechnique):
@staticmethod
def get_report_data():
data = T1035.get_tech_base_data()
- data.update({'services': list(mongo.db.telemetry.aggregate(T1035.get_usage_query()))})
+ data.update({'services': T1035.get_usage_data()})
return data
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1106.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1106.py
index b24d10bd9..b50b19883 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/T1106.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1106.py
@@ -1,10 +1,9 @@
-from monkey_island.cc.database import mongo
-from monkey_island.cc.services.attack.technique_reports import AttackTechnique
+from monkey_island.cc.services.attack.technique_reports import UsageTechnique
__author__ = "VakarisZ"
-class T1106(AttackTechnique):
+class T1106(UsageTechnique):
tech_id = "T1106"
unscanned_msg = "Monkey didn't try to directly use WinAPI."
scanned_msg = "Monkey tried to use WinAPI, but failed."
@@ -13,5 +12,5 @@ class T1106(AttackTechnique):
@staticmethod
def get_report_data():
data = T1106.get_tech_base_data()
- data.update({'api_uses': list(mongo.db.telemetry.aggregate(T1106.get_usage_query()))})
+ data.update({'api_uses': T1106.get_usage_data()})
return data
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1129.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1129.py
index 7d9fa9dd0..f1a4d1b83 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/T1129.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1129.py
@@ -1,10 +1,10 @@
from monkey_island.cc.database import mongo
-from monkey_island.cc.services.attack.technique_reports import AttackTechnique
+from monkey_island.cc.services.attack.technique_reports import UsageTechnique
__author__ = "VakarisZ"
-class T1129(AttackTechnique):
+class T1129(UsageTechnique):
tech_id = "T1129"
unscanned_msg = "Monkey didn't try to load any DLL's."
scanned_msg = "Monkey tried to load DLL's, but failed."
@@ -13,5 +13,5 @@ class T1129(AttackTechnique):
@staticmethod
def get_report_data():
data = T1129.get_tech_base_data()
- data.update({'dlls': list(mongo.db.telemetry.aggregate(T1129.get_usage_query()))})
+ data.update({'dlls': T1129.get_usage_data()})
return data
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py b/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py
index de55cd08c..ec5ee7781 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py
@@ -1,10 +1,13 @@
import abc
+import logging
from monkey_island.cc.database import mongo
-from common.utils.attack_utils import ScanStatus
+from common.utils.attack_utils import ScanStatus, UsageEnum
from monkey_island.cc.services.attack.attack_config import AttackConfig
from common.utils.code_utils import abstractstatic
+logger = logging.getLogger(__name__)
+
class AttackTechnique(object):
""" Abstract class for ATT&CK report components """
@@ -113,6 +116,29 @@ class AttackTechnique(object):
data.update({'title': cls.technique_title()})
return data
+
+class UsageTechnique(AttackTechnique):
+ __metaclass__ = abc.ABCMeta
+
+ @staticmethod
+ def parse_usages(usage):
+ """
+ Parses data from database and translates usage enums into strings
+ :param usage: Usage telemetry that contains fields: {'usage': 'SMB', 'status': 1}
+ :return: usage string
+ """
+ try:
+ usage['usage'] = UsageEnum[usage['usage']].value[usage['status']]
+ except KeyError:
+ logger.error("Error translating usage enum. into string. "
+ "Check if usage enum field exists and covers all telem. statuses.")
+ return usage
+
+ @classmethod
+ def get_usage_data(cls):
+ data = list(mongo.db.telemetry.aggregate(cls.get_usage_query()))
+ return list(map(cls.parse_usages, data))
+
@classmethod
def get_usage_query(cls):
"""
@@ -131,4 +157,5 @@ class AttackTechnique(object):
{'$addFields': {'_id': 0,
'machine': {'hostname': '$monkey.hostname', 'ips': '$monkey.ip_addresses'},
'monkey': 0}},
- {'$group': {'_id': {'machine': '$machine', 'status': '$status', 'usage': '$usage'}}}]
+ {'$group': {'_id': {'machine': '$machine', 'status': '$status', 'usage': '$usage'}}},
+ {"$replaceRoot": {"newRoot": "$_id"}}]
diff --git a/monkey/monkey_island/cc/services/config_schema.py b/monkey/monkey_island/cc/services/config_schema.py
index 07596cf51..2fa1a3aff 100644
--- a/monkey/monkey_island/cc/services/config_schema.py
+++ b/monkey/monkey_island/cc/services/config_schema.py
@@ -389,7 +389,7 @@ SCHEMA = {
"self_delete_in_cleanup": {
"title": "Self delete on cleanup",
"type": "boolean",
- "default": False,
+ "default": True,
"description": "Should the monkey delete its executable when going down"
},
"use_file_logging": {
diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/Helpers.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/Helpers.js
index 18df4b58f..07f289150 100644
--- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/Helpers.js
+++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/Helpers.js
@@ -28,16 +28,16 @@ export function getUsageColumns() {
columns: [
{Header: 'Machine',
id: 'machine',
- accessor: x => renderMachineFromSystemData(x._id.machine),
+ accessor: x => renderMachineFromSystemData(x.machine),
style: { 'whiteSpace': 'unset' },
width: 300},
{Header: 'Usage',
id: 'usage',
- accessor: x => x._id.usage,
+ accessor: x => x.usage,
style: { 'whiteSpace': 'unset' }}]
}])}
-export const scanStatus = {
+export const ScanStatus = {
UNSCANNED: 0,
SCANNED: 1,
USED: 2
diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1003.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1003.js
index 208840cf3..07fd4a400 100644
--- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1003.js
+++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1003.js
@@ -2,7 +2,7 @@ import React from 'react';
import '../../../styles/Collapse.scss'
import '../../report-components/StolenPasswords'
import StolenPasswordsComponent from "../../report-components/StolenPasswords";
-import {scanStatus} from "./Helpers"
+import {ScanStatus} from "./Helpers"
class T1003 extends React.Component {
@@ -16,7 +16,7 @@ class T1003 extends React.Component {
- Not sure what this is? Not seeing your AWS EC2 instances? Read the documentation! + Not sure what this is? Not seeing your AWS EC2 instances? Read the documentation!