diff --git a/monkey/common/utils/attack_utils.py b/monkey/common/utils/attack_utils.py index cb3c8f029..3edb0dc28 100644 --- a/monkey/common/utils/attack_utils.py +++ b/monkey/common/utils/attack_utils.py @@ -10,6 +10,13 @@ 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."} + + # 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/exploit/smbexec.py b/monkey/infection_monkey/exploit/smbexec.py index 6f1667c64..74354108e 100644 --- a/monkey/infection_monkey/exploit/smbexec.py +++ b/monkey/infection_monkey/exploit/smbexec.py @@ -11,7 +11,7 @@ from infection_monkey.network.tools import check_tcp_port from infection_monkey.exploit.tools import build_monkey_commandline 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__) @@ -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.name).send() scmr.hRDeleteService(scmr_rpc, service) scmr.hRCloseServiceHandle(scmr_rpc, service) diff --git a/monkey/infection_monkey/system_info/mimikatz_collector.py b/monkey/infection_monkey/system_info/mimikatz_collector.py index 4f2348531..47fa0d431 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.pyinstaller_utils import get_binary_file_path, get_binaries_dir_path @@ -50,10 +50,11 @@ class MimikatzCollector(object): 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() + status = ScanStatus.SCANNED + T1129Telem(status, UsageEnum.MIMIKATZ.name).send() def get_logon_info(self): """ @@ -70,7 +71,7 @@ class MimikatzCollector(object): logon_data_dictionary = {} hostname = socket.gethostname() - + self.mimikatz_text = self._get_text_output_proto() for i in range(entry_count): @@ -105,7 +106,7 @@ class MimikatzCollector(object): except Exception: LOG.exception("Error getting logon info") return {} - + def get_mimikatz_text(self): return self.mimikatz_text diff --git a/monkey/infection_monkey/telemetry/attack/t1035_telem.py b/monkey/infection_monkey/telemetry/attack/t1035_telem.py index b3d7c90de..13d0bcc59 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 name of UsageEnum """ super(T1035Telem, self).__init__('T1035', status, usage) diff --git a/monkey/infection_monkey/telemetry/attack/t1129_telem.py b/monkey/infection_monkey/telemetry/attack/t1129_telem.py index fb7d776c6..a04834959 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 name of UsageEnum """ 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..d493c64d8 100644 --- a/monkey/infection_monkey/telemetry/attack/usage_telem.py +++ b/monkey/infection_monkey/telemetry/attack/usage_telem.py @@ -5,9 +5,9 @@ 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 name of UsageEnum """ super(UsageTelem, self).__init__(technique, status) self.usage = usage 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..4651f3c25 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,7 @@ 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()))}) + services = list(mongo.db.telemetry.aggregate(T1035.get_usage_query())) + services = list(map(T1035.parse_usages, services)) + data.update({'services': services}) 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..17abd4dd3 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,7 @@ 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()))}) + dlls = list(mongo.db.telemetry.aggregate(T1129.get_usage_query())) + dlls = list(map(T1129.parse_usages, dlls)) + data.update({'dlls': dlls}) 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..9b0c23d50 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,24 @@ 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: + :return: + """ + 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_query(cls): """ @@ -131,4 +152,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/ui/src/components/attack/techniques/Helpers.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/Helpers.js index 775d453da..9cb0de635 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 @@ -27,12 +27,12 @@ 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' }}] }])}