diff --git a/monkey/infection_monkey/exploit/smbexec.py b/monkey/infection_monkey/exploit/smbexec.py index 0bc8fc783..3f86401e7 100644 --- a/monkey/infection_monkey/exploit/smbexec.py +++ b/monkey/infection_monkey/exploit/smbexec.py @@ -10,6 +10,8 @@ from infection_monkey.network import SMBFinger 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 LOG = getLogger(__name__) @@ -129,10 +131,12 @@ class SmbExploiter(HostExploiter): resp = scmr.hRCreateServiceW(scmr_rpc, sc_handle, self._config.smb_service_name, self._config.smb_service_name, lpBinaryPathName=cmdline) 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() except: + T1035Telem(ScanStatus.SCANNED, + "SMB exploiter failed to run the monkey by creating a service via MS-SCMR.").send() pass scmr.hRDeleteService(scmr_rpc, service) scmr.hRCloseServiceHandle(scmr_rpc, service) diff --git a/monkey/infection_monkey/telemetry/attack/t1035_telem.py b/monkey/infection_monkey/telemetry/attack/t1035_telem.py new file mode 100644 index 000000000..3b0846609 --- /dev/null +++ b/monkey/infection_monkey/telemetry/attack/t1035_telem.py @@ -0,0 +1,19 @@ +from infection_monkey.telemetry.attack.attack_telem import AttackTelem + + +class T1035Telem(AttackTelem): + def __init__(self, status, usage): + """ + T1035 telemetry. + :param status: ScanStatus of technique + :param usage: Usage string + """ + super(T1035Telem, self).__init__('T1035', status) + self.usage = usage + + def get_data(self): + data = super(T1035Telem, self).get_data() + data.update({ + 'usage': self.usage + }) + return data diff --git a/monkey/monkey_island/cc/services/attack/attack_report.py b/monkey/monkey_island/cc/services/attack/attack_report.py index ebd046e46..dbe778936 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 +from monkey_island.cc.services.attack.technique_reports import T1145, T1107, T1065, T1035 from monkey_island.cc.services.attack.attack_config import AttackConfig from monkey_island.cc.database import mongo @@ -20,7 +20,8 @@ TECHNIQUES = {'T1210': T1210.T1210, 'T1082': T1082.T1082, 'T1145': T1145.T1145, 'T1107': T1107.T1107, - 'T1065': T1065.T1065} + 'T1065': T1065.T1065, + 'T1035': T1035.T1035} REPORT_NAME = 'new_report' diff --git a/monkey/monkey_island/cc/services/attack/attack_schema.py b/monkey/monkey_island/cc/services/attack/attack_schema.py index 1e24d7294..3cb5e32d1 100644 --- a/monkey/monkey_island/cc/services/attack/attack_schema.py +++ b/monkey/monkey_island/cc/services/attack/attack_schema.py @@ -107,6 +107,15 @@ SCHEMA = { "title": "Execution", "type": "object", "properties": { + "T1035": { + "title": "T1035 Service execution", + "type": "bool", + "value": True, + "necessary": False, + "description": "Adversaries may execute a binary, command, or script via a method " + "that interacts with Windows services, such as the Service Control Manager.", + "depends_on": ["T1210"] + }, "T1059": { "title": "T1059 Command line interface", "type": "bool", diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py index a92758cbc..d9aaeaa47 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py @@ -20,8 +20,8 @@ class T1003(AttackTechnique): def get_report_data(): data = {'title': T1003.technique_title()} if mongo.db.telemetry.count_documents(T1003.query): - status = ScanStatus.USED + status = ScanStatus.USED.value else: - status = ScanStatus.UNSCANNED + status = ScanStatus.UNSCANNED.value data.update(T1003.get_message_and_status(status)) return data diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1035.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1035.py new file mode 100644 index 000000000..4dd2b7652 --- /dev/null +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1035.py @@ -0,0 +1,31 @@ +from monkey_island.cc.database import mongo +from monkey_island.cc.services.attack.technique_reports import AttackTechnique + +__author__ = "VakarisZ" + + +class T1035(AttackTechnique): + 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." + used_msg = "Monkey successfully interacted with Windows services." + + query = [{'$match': {'telem_category': 'attack', + 'data.technique': tech_id}}, + {'$lookup': {'from': 'monkey', + 'localField': 'monkey_guid', + 'foreignField': 'guid', + 'as': 'monkey'}}, + {'$project': {'monkey': {'$arrayElemAt': ['$monkey', 0]}, + 'status': '$data.status', + 'usage': '$data.usage'}}, + {'$addFields': {'_id': 0, + 'machine': {'hostname': '$monkey.hostname', 'ips': '$monkey.ip_addresses'}, + 'monkey': 0}}, + {'$group': {'_id': {'machine': '$machine', 'status': '$status', 'usage': '$usage'}}}] + + @staticmethod + def get_report_data(): + data = T1035.get_tech_base_data() + data.update({'services': list(mongo.db.telemetry.aggregate(T1035.query))}) + return data diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py index 328c11112..ef15dd9fd 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py @@ -27,8 +27,8 @@ class T1059(AttackTechnique): cmd_data = list(mongo.db.telemetry.aggregate(T1059.query)) data = {'title': T1059.technique_title(), 'cmds': cmd_data} if cmd_data: - status = ScanStatus.USED + status = ScanStatus.USED.value else: - status = ScanStatus.UNSCANNED + status = ScanStatus.UNSCANNED.value data.update(T1059.get_message_and_status(status)) return data diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1065.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1065.py index fd34e80e9..7d8ceb93e 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1065.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1065.py @@ -17,4 +17,4 @@ class T1065(AttackTechnique): def get_report_data(): port = ConfigService.get_config_value(['cnc', 'servers', 'current_server']).split(':')[1] T1065.used_msg = T1065.message % port - return T1065.get_base_data_by_status(ScanStatus.USED) + return T1065.get_base_data_by_status(ScanStatus.USED.value) diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1075.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1075.py index fa65a66c2..623d157ae 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1075.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1075.py @@ -35,10 +35,10 @@ class T1075(AttackTechnique): successful_logins = list(mongo.db.telemetry.aggregate(T1075.query)) data.update({'successful_logins': successful_logins}) if successful_logins: - status = ScanStatus.USED + status = ScanStatus.USED.value elif mongo.db.telemetry.count_documents(T1075.login_attempt_query): - status = ScanStatus.SCANNED + status = ScanStatus.SCANNED.value else: - status = ScanStatus.UNSCANNED + status = ScanStatus.UNSCANNED.value data.update(T1075.get_message_and_status(status)) return data diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1082.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1082.py index 79020c048..f59b63286 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1082.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1082.py @@ -40,8 +40,8 @@ class T1082(AttackTechnique): system_info = list(mongo.db.telemetry.aggregate(T1082.query)) data.update({'system_info': system_info}) if system_info: - status = ScanStatus.USED + status = ScanStatus.USED.value else: - status = ScanStatus.UNSCANNED + status = ScanStatus.UNSCANNED.value data.update(T1082.get_message_and_status(status)) return data diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1086.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1086.py index 4114047c5..dd5d64d25 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1086.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1086.py @@ -29,8 +29,8 @@ class T1086(AttackTechnique): cmd_data = list(mongo.db.telemetry.aggregate(T1086.query)) data = {'title': T1086.technique_title(), 'cmds': cmd_data} if cmd_data: - status = ScanStatus.USED + status = ScanStatus.USED.value else: - status = ScanStatus.UNSCANNED + status = ScanStatus.UNSCANNED.value data.update(T1086.get_message_and_status(status)) return data diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py index 91d785bc3..b918de7f4 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py @@ -35,11 +35,11 @@ class T1110(AttackTechnique): result['successful_creds'].append(T1110.parse_creds(attempt)) if succeeded: - status = ScanStatus.USED + status = ScanStatus.USED.value elif attempts: - status = ScanStatus.SCANNED + status = ScanStatus.SCANNED.value else: - status = ScanStatus.UNSCANNED + status = ScanStatus.UNSCANNED.value data = T1110.get_base_data_by_status(status) # Remove data with no successful brute force attempts attempts = [attempt for attempt in attempts if attempt['attempts']] diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1145.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1145.py index 9b525873f..89ac44117 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1145.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1145.py @@ -23,9 +23,9 @@ class T1145(AttackTechnique): ssh_info = list(mongo.db.telemetry.aggregate(T1145.query)) if ssh_info: - status = ScanStatus.USED + status = ScanStatus.USED.value else: - status = ScanStatus.UNSCANNED + status = ScanStatus.UNSCANNED.value data = T1145.get_base_data_by_status(status) data.update({'ssh_info': ssh_info}) return data diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1210.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1210.py index 6e89bc6ab..eeae183f5 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1210.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1210.py @@ -18,11 +18,11 @@ class T1210(AttackTechnique): scanned_services = T1210.get_scanned_services() exploited_services = T1210.get_exploited_services() if exploited_services: - status = ScanStatus.USED + status = ScanStatus.USED.value elif scanned_services: - status = ScanStatus.SCANNED + status = ScanStatus.SCANNED.value else: - status = ScanStatus.UNSCANNED + status = ScanStatus.UNSCANNED.value data.update(T1210.get_message_and_status(status)) data.update({'scanned_services': scanned_services, 'exploited_services': exploited_services}) 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 d765b5f09..3e92417d3 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py @@ -67,21 +67,21 @@ class AttackTechnique(object): def get_message_and_status(cls, status): """ Returns a dict with attack technique's message and status. - :param status: Enum type value from common/attack_utils.py + :param status: Enum from common/attack_utils.py integer value :return: Dict with message and status """ - return {'message': cls.get_message_by_status(status), 'status': status.value} + return {'message': cls.get_message_by_status(status), 'status': status} @classmethod def get_message_by_status(cls, status): """ Picks a message to return based on status. - :param status: Enum type value from common/attack_utils.py + :param status: Enum from common/attack_utils.py integer value :return: message string """ - if status == ScanStatus.UNSCANNED: + if status == ScanStatus.UNSCANNED.value: return cls.unscanned_msg - elif status == ScanStatus.SCANNED: + elif status == ScanStatus.SCANNED.value: return cls.scanned_msg else: return cls.used_msg diff --git a/monkey/monkey_island/cc/services/config_schema.py b/monkey/monkey_island/cc/services/config_schema.py index cd417f8e4..fcc182da1 100644 --- a/monkey/monkey_island/cc/services/config_schema.py +++ b/monkey/monkey_island/cc/services/config_schema.py @@ -14,7 +14,7 @@ SCHEMA = { "SmbExploiter" ], "title": "SMB Exploiter", - "attack_techniques": ["T1110", "T1075"] + "attack_techniques": ["T1110", "T1075", "T1035"] }, { "type": "string", diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1035.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1035.js new file mode 100644 index 000000000..b760226b8 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1035.js @@ -0,0 +1,44 @@ +import React from 'react'; +import '../../../styles/Collapse.scss' +import ReactTable from "react-table"; +import { renderMachineFromSystemData } from "./Helpers" + + +class T1035 extends React.Component { + + constructor(props) { + super(props); + } + + static getServiceColumns() { + return ([{ + columns: [ + {Header: 'Machine', + id: 'machine', + accessor: x => renderMachineFromSystemData(x._id.machine), + style: { 'whiteSpace': 'unset' }, + width: 300}, + {Header: 'Usage', + id: 'usage', + accessor: x => x._id.usage, + style: { 'whiteSpace': 'unset' }}] + }])}; + + render() { + return ( +
+
{this.props.data.message}
+
+ {this.props.data.services.length !== 0 ? + : ""} +
+ ); + } +} + +export default T1035; diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/AttackReport.js b/monkey/monkey_island/cc/ui/src/components/report-components/AttackReport.js index f3bf7d9ce..6a1e04c28 100644 --- a/monkey/monkey_island/cc/ui/src/components/report-components/AttackReport.js +++ b/monkey/monkey_island/cc/ui/src/components/report-components/AttackReport.js @@ -17,6 +17,7 @@ import T1082 from "../attack/techniques/T1082"; import T1145 from "../attack/techniques/T1145"; import T1107 from "../attack/techniques/T1107"; import T1065 from "../attack/techniques/T1065"; +import T1035 from "../attack/techniques/T1035"; const tech_components = { 'T1210': T1210, @@ -29,7 +30,8 @@ const tech_components = { 'T1082': T1082, 'T1145': T1145, 'T1107': T1107, - 'T1065': T1065 + 'T1065': T1065, + 'T1035': T1035 }; const classNames = require('classnames');