diff --git a/monkey/common/utils/attack_utils.py b/monkey/common/utils/attack_utils.py index 3edb0dc28..77d813351 100644 --- a/monkey/common/utils/attack_utils.py +++ b/monkey/common/utils/attack_utils.py @@ -15,6 +15,9 @@ class UsageEnum(Enum): 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."} # Dict that describes what BITS job was used for diff --git a/monkey/infection_monkey/control.py b/monkey/infection_monkey/control.py index f6c52be55..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} diff --git a/monkey/infection_monkey/dropper.py b/monkey/infection_monkey/dropper.py index cc065a745..230ebc567 100644 --- a/monkey/infection_monkey/dropper.py +++ b/monkey/infection_monkey/dropper.py @@ -14,6 +14,8 @@ from infection_monkey.config import WormConfiguration from infection_monkey.exploit.tools import build_monkey_commandline_explicitly 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, UsageEnum if "win32" == sys.platform: from win32process import DETACHED_PROCESS @@ -156,5 +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, UsageEnum.DROPPER.name).send() except AttributeError: LOG.error("Invalid configuration options. Failing") diff --git a/monkey/infection_monkey/system_info/mimikatz_collector.py b/monkey/infection_monkey/system_info/mimikatz_collector.py index 0ad0d692f..7843d1108 100644 --- a/monkey/infection_monkey/system_info/mimikatz_collector.py +++ b/monkey/infection_monkey/system_info/mimikatz_collector.py @@ -7,6 +7,7 @@ import zipfile import infection_monkey.config 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 __author__ = 'itay.mizeretz' @@ -54,8 +55,10 @@ class MimikatzCollector(object): except Exception: LOG.exception("Error initializing mimikatz collector") status = ScanStatus.SCANNED + T1106Telem(status, UsageEnum.MIMIKATZ_WINAPI.name).send() T1129Telem(status, UsageEnum.MIMIKATZ).send() + def get_logon_info(self): """ Gets the logon info from mimikatz. diff --git a/monkey/infection_monkey/system_singleton.py b/monkey/infection_monkey/system_singleton.py index 9f56c238e..d8c3ec51c 100644 --- a/monkey/infection_monkey/system_singleton.py +++ b/monkey/infection_monkey/system_singleton.py @@ -46,17 +46,14 @@ class WindowsSystemSingleton(_SystemSingleton): if not handle: LOG.error("Cannot acquire system singleton %r, unknown error %d", self._mutex_name, last_error) - return False if winerror.ERROR_ALREADY_EXISTS == last_error: LOG.debug("Cannot acquire system singleton %r, mutex already exist", self._mutex_name) - return False self._mutex_handle = handle - LOG.debug("Global singleton mutex %r acquired", self._mutex_name) diff --git a/monkey/infection_monkey/telemetry/attack/t1106_telem.py b/monkey/infection_monkey/telemetry/attack/t1106_telem.py new file mode 100644 index 000000000..422313540 --- /dev/null +++ b/monkey/infection_monkey/telemetry/attack/t1106_telem.py @@ -0,0 +1,11 @@ +from infection_monkey.telemetry.attack.usage_telem import UsageTelem + + +class T1106Telem(UsageTelem): + def __init__(self, status, usage): + """ + T1106 telemetry. + :param status: ScanStatus of technique + :param usage: Enum name of UsageEnum + """ + super(T1106Telem, self).__init__("T1106", status, usage) diff --git a/monkey/monkey_island/cc/services/attack/attack_report.py b/monkey/monkey_island/cc/services/attack/attack_report.py index 11cadb068..f1382b9d5 100644 --- a/monkey/monkey_island/cc/services/attack/attack_report.py +++ b/monkey/monkey_island/cc/services/attack/attack_report.py @@ -1,7 +1,7 @@ import logging from monkey_island.cc.models import Monkey from monkey_island.cc.services.attack.technique_reports import T1210, T1197, T1110, T1075, T1003, T1059, T1086, T1082 -from monkey_island.cc.services.attack.technique_reports import T1145, T1107, T1065, T1035, T1129 +from monkey_island.cc.services.attack.technique_reports import T1145, T1035, T1129, T1106, T1107, T1065 from monkey_island.cc.services.attack.attack_config import AttackConfig from monkey_island.cc.database import mongo @@ -21,6 +21,7 @@ TECHNIQUES = {'T1210': T1210.T1210, 'T1145': T1145.T1145, 'T1035': T1035.T1035, 'T1129': T1129.T1129, + 'T1106': T1106.T1106, 'T1107': T1107.T1107, 'T1065': T1065.T1065} diff --git a/monkey/monkey_island/cc/services/attack/attack_schema.py b/monkey/monkey_island/cc/services/attack/attack_schema.py index 1e4ba5467..ad3e6e54c 100644 --- a/monkey/monkey_island/cc/services/attack/attack_schema.py +++ b/monkey/monkey_island/cc/services/attack/attack_schema.py @@ -125,6 +125,15 @@ SCHEMA = { "local paths and arbitrary Universal Naming Convention (UNC) network paths.", "depends_on": ["T1078", "T1003"] }, + "T1106": { + "title": "T1106 Execution through API", + "type": "bool", + "value": True, + "necessary": False, + "description": "Adversary tools may directly use the Windows application " + "programming interface (API) to execute binaries.", + "depends_on": ["T1210"] + }, "T1059": { "title": "T1059 Command line interface", "type": "bool", 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 4651f3c25..fcc230be5 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1035.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1035.py @@ -13,7 +13,5 @@ class T1035(UsageTechnique): @staticmethod def get_report_data(): data = T1035.get_tech_base_data() - services = list(mongo.db.telemetry.aggregate(T1035.get_usage_query())) - services = list(map(T1035.parse_usages, services)) - data.update({'services': services}) + 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 new file mode 100644 index 000000000..b50b19883 --- /dev/null +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1106.py @@ -0,0 +1,16 @@ +from monkey_island.cc.services.attack.technique_reports import UsageTechnique + +__author__ = "VakarisZ" + + +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." + used_msg = "Monkey successfully used WinAPI." + + @staticmethod + def get_report_data(): + data = T1106.get_tech_base_data() + 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 17abd4dd3..f1a4d1b83 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1129.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1129.py @@ -13,7 +13,5 @@ class T1129(UsageTechnique): @staticmethod def get_report_data(): data = T1129.get_tech_base_data() - dlls = list(mongo.db.telemetry.aggregate(T1129.get_usage_query())) - dlls = list(map(T1129.parse_usages, dlls)) - data.update({'dlls': dlls}) + 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 30c73f609..ec5ee7781 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py @@ -134,6 +134,11 @@ class UsageTechnique(AttackTechnique): "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): """ diff --git a/monkey/monkey_island/cc/services/config_schema.py b/monkey/monkey_island/cc/services/config_schema.py index fcc182da1..2fa1a3aff 100644 --- a/monkey/monkey_island/cc/services/config_schema.py +++ b/monkey/monkey_island/cc/services/config_schema.py @@ -22,7 +22,7 @@ SCHEMA = { "WmiExploiter" ], "title": "WMI Exploiter", - "attack_techniques": ["T1110"] + "attack_techniques": ["T1110", "T1106"] }, { "type": "string", @@ -54,7 +54,7 @@ SCHEMA = { "SSHExploiter" ], "title": "SSH Exploiter", - "attack_techniques": ["T1110", "T1145"] + "attack_techniques": ["T1110", "T1145", "T1106"] }, { "type": "string", diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1106.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1106.js new file mode 100644 index 000000000..a3210b73c --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1106.js @@ -0,0 +1,30 @@ +import React from 'react'; +import '../../../styles/Collapse.scss' +import ReactTable from "react-table"; +import { getUsageColumns } from "./Helpers" + + +class T1106 extends React.Component { + + constructor(props) { + super(props); + } + + render() { + return ( +