diff --git a/monkey/common/utils/attack_utils.py b/monkey/common/utils/attack_utils.py index 28feaa537..cb3c8f029 100644 --- a/monkey/common/utils/attack_utils.py +++ b/monkey/common/utils/attack_utils.py @@ -9,8 +9,9 @@ class ScanStatus(Enum): # Technique was attempted and succeeded USED = 2 + # Dict that describes what BITS job was used for -BITS_UPLOAD_STRING = {"usage": "BITS job was used to upload monkey to a remote system."} +BITS_UPLOAD_STRING = "BITS job was used to upload monkey to a remote system." def format_time(time): diff --git a/monkey/infection_monkey/control.py b/monkey/infection_monkey/control.py index 3fae277e8..6ce94451d 100644 --- a/monkey/infection_monkey/control.py +++ b/monkey/infection_monkey/control.py @@ -123,11 +123,11 @@ class ControlClient(object): return {} @staticmethod - def send_telemetry(telem_type, data): + def send_telemetry(telem_catagory, data): if not WormConfiguration.current_server: return try: - telemetry = {'monkey_guid': GUID, 'telem_type': telem_type, 'data': data} + telemetry = {'monkey_guid': GUID, 'telem_catagory': telem_catagory, 'data': data} reply = requests.post("https://%s/api/telemetry" % (WormConfiguration.current_server,), data=json.dumps(telemetry), headers={'content-type': 'application/json'}, diff --git a/monkey/infection_monkey/exploit/elasticgroovy.py b/monkey/infection_monkey/exploit/elasticgroovy.py index 3a129ebc0..24a902eea 100644 --- a/monkey/infection_monkey/exploit/elasticgroovy.py +++ b/monkey/infection_monkey/exploit/elasticgroovy.py @@ -11,7 +11,7 @@ from infection_monkey.exploit.web_rce import WebRCE from infection_monkey.model import WGET_HTTP_UPLOAD, RDP_CMDLINE_HTTP, CHECK_COMMAND, ID_STRING, CMD_PREFIX,\ DOWNLOAD_TIMEOUT from infection_monkey.network.elasticfinger import ES_PORT, ES_SERVICE -from infection_monkey.transport.attack_telems.victim_host_telem import VictimHostTelem +from infection_monkey.telemetry.attack.t1197_telem import T1197Telem from common.utils.attack_utils import ScanStatus, BITS_UPLOAD_STRING import re @@ -64,7 +64,7 @@ class ElasticGroovyExploiter(WebRCE): def upload_monkey(self, url, commands=None): result = super(ElasticGroovyExploiter, self).upload_monkey(url, commands) if 'windows' in self.host.os['type'] and result: - VictimHostTelem("T1197", ScanStatus.USED.value, self.host, BITS_UPLOAD_STRING).send() + T1197Telem(ScanStatus.USED, self.host, BITS_UPLOAD_STRING).send() return result def get_results(self, response): diff --git a/monkey/infection_monkey/exploit/rdpgrinder.py b/monkey/infection_monkey/exploit/rdpgrinder.py index 8e219b5c8..bb8db1d46 100644 --- a/monkey/infection_monkey/exploit/rdpgrinder.py +++ b/monkey/infection_monkey/exploit/rdpgrinder.py @@ -15,9 +15,9 @@ from infection_monkey.exploit.tools import get_target_monkey 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.exploit.tools import build_monkey_commandline +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 infection_monkey.transport.attack_telems.victim_host_telem import VictimHostTelem from common.utils.attack_utils import ScanStatus, BITS_UPLOAD_STRING __author__ = 'hoffer' @@ -316,7 +316,7 @@ class RdpExploiter(HostExploiter): if client_factory.success: if not self._config.rdp_use_vbs_download: - VictimHostTelem("T1197", ScanStatus.USED.value, self.host, BITS_UPLOAD_STRING).send() + T1197Telem(ScanStatus.USED, self.host, BITS_UPLOAD_STRING).send() self.add_vuln_port(RDP_PORT) exploited = True self.report_login_attempt(True, user, password) diff --git a/monkey/infection_monkey/exploit/web_rce.py b/monkey/infection_monkey/exploit/web_rce.py index d31df7c21..ed4d595b7 100644 --- a/monkey/infection_monkey/exploit/web_rce.py +++ b/monkey/infection_monkey/exploit/web_rce.py @@ -7,7 +7,7 @@ from infection_monkey.exploit import HostExploiter from infection_monkey.model import * from infection_monkey.exploit.tools import get_target_monkey, get_monkey_depth, build_monkey_commandline, HTTPTools from infection_monkey.network.tools import check_tcp_port, tcp_port_to_service -from infection_monkey.transport.attack_telems.victim_host_telem import VictimHostTelem +from infection_monkey.telemetry.attack.t1197_telem import T1197Telem from common.utils.attack_utils import ScanStatus, BITS_UPLOAD_STRING __author__ = 'VakarisZ' @@ -308,7 +308,7 @@ class WebRCE(HostExploiter): if not isinstance(resp, bool) and POWERSHELL_NOT_FOUND in resp: LOG.info("Powershell not found in host. Using bitsadmin to download.") backup_command = RDP_CMDLINE_HTTP % {'monkey_path': dest_path, 'http_path': http_path} - VictimHostTelem("T1197", ScanStatus.USED.value, self.host, BITS_UPLOAD_STRING).send() + T1197Telem(ScanStatus.USED, self.host, BITS_UPLOAD_STRING).send() resp = self.exploit(url, backup_command) return resp diff --git a/monkey/infection_monkey/monkey.py b/monkey/infection_monkey/monkey.py index b152e58be..92714c7d6 100644 --- a/monkey/infection_monkey/monkey.py +++ b/monkey/infection_monkey/monkey.py @@ -15,10 +15,10 @@ from infection_monkey.network.firewall import app as firewall from infection_monkey.network.network_scanner import NetworkScanner from infection_monkey.system_info import SystemInfoCollector from infection_monkey.system_singleton import SystemSingleton +from infection_monkey.telemetry.attack.victim_host_telem import VictimHostTelem from infection_monkey.windows_upgrader import WindowsUpgrader from infection_monkey.post_breach.post_breach_handler import PostBreach from common.utils.attack_utils import ScanStatus -from infection_monkey.transport.attack_telems.victim_host_telem import VictimHostTelem from infection_monkey.exploit.tools import get_interface_to_target __author__ = 'itamar' @@ -186,9 +186,11 @@ class InfectionMonkey(object): for exploiter in [exploiter(machine) for exploiter in self._exploiters]: if self.try_exploiting(machine, exploiter): host_exploited = True + VictimHostTelem('T1210', ScanStatus.USED, machine=machine).send() break if not host_exploited: self._fail_exploitation_machines.add(machine) + VictimHostTelem('T1210', ScanStatus.SCANNED, machine=machine).send() if not self._keep_running: break diff --git a/monkey/infection_monkey/telemetry/__init__.py b/monkey/infection_monkey/telemetry/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/monkey/infection_monkey/telemetry/attack/__init__.py b/monkey/infection_monkey/telemetry/attack/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/monkey/infection_monkey/telemetry/attack/attack_telem.py b/monkey/infection_monkey/telemetry/attack/attack_telem.py new file mode 100644 index 000000000..efbedcaff --- /dev/null +++ b/monkey/infection_monkey/telemetry/attack/attack_telem.py @@ -0,0 +1,24 @@ +from infection_monkey.telemetry.base_telem import BaseTelem + +__author__ = "VakarisZ" + + +class AttackTelem(BaseTelem): + + def __init__(self, technique, status): + """ + Default ATT&CK telemetry constructor + :param technique: Technique ID. E.g. T111 + :param status: ScanStatus of technique + """ + super(AttackTelem, self).__init__() + self.technique = technique + self.status = status + + telem_catagory = 'attack' + + def get_data(self): + return { + 'status': self.status.value, + 'technique': self.technique + } diff --git a/monkey/infection_monkey/telemetry/attack/t1197_telem.py b/monkey/infection_monkey/telemetry/attack/t1197_telem.py new file mode 100644 index 000000000..387c3aa13 --- /dev/null +++ b/monkey/infection_monkey/telemetry/attack/t1197_telem.py @@ -0,0 +1,22 @@ +from infection_monkey.telemetry.attack.victim_host_telem import VictimHostTelem + +__author__ = "itay.mizeretz" + + +class T1197Telem(VictimHostTelem): + def __init__(self, status, machine, usage): + """ + T1197 telemetry. + :param status: ScanStatus of technique + :param machine: VictimHost obj from model/host.py + :param usage: Usage string + """ + super(T1197Telem, self).__init__('T1197', status, machine) + self.usage = usage + + def get_data(self): + data = super(T1197Telem, self).get_data() + data.update({ + 'usage': self.usage + }) + return data diff --git a/monkey/infection_monkey/telemetry/attack/test_victim_host_telem.py b/monkey/infection_monkey/telemetry/attack/test_victim_host_telem.py new file mode 100644 index 000000000..6b5bbcb73 --- /dev/null +++ b/monkey/infection_monkey/telemetry/attack/test_victim_host_telem.py @@ -0,0 +1,29 @@ +from unittest import TestCase + +from common.utils.attack_utils import ScanStatus +from infection_monkey.model import VictimHost +from infection_monkey.telemetry.attack.victim_host_telem import VictimHostTelem + + +class TestVictimHostTelem(TestCase): + def test_get_data(self): + machine = VictimHost('127.0.0.1') + status = ScanStatus.USED + technique = 'T1210' + + telem = VictimHostTelem(technique, status, machine) + + self.assertEqual(telem.telem_catagory, 'attack') + + expected_data = { + 'machine': { + 'domain_name': machine.domain_name, + 'ip_addr': machine.ip_addr + }, + 'status': status.value, + 'technique': technique + } + + actual_data = telem.get_data() + + self.assertEqual(actual_data, expected_data) diff --git a/monkey/infection_monkey/telemetry/attack/victim_host_telem.py b/monkey/infection_monkey/telemetry/attack/victim_host_telem.py new file mode 100644 index 000000000..9e277926c --- /dev/null +++ b/monkey/infection_monkey/telemetry/attack/victim_host_telem.py @@ -0,0 +1,24 @@ +from infection_monkey.telemetry.attack.attack_telem import AttackTelem + +__author__ = "VakarisZ" + + +class VictimHostTelem(AttackTelem): + + def __init__(self, technique, status, machine): + """ + ATT&CK telemetry. + When `send` is called, it will parse and send the VictimHost's (remote machine's) data. + :param technique: Technique ID. E.g. T111 + :param status: ScanStatus of technique + :param machine: VictimHost obj from model/host.py + """ + super(VictimHostTelem, self).__init__(technique, status) + self.machine = {'domain_name': machine.domain_name, 'ip_addr': machine.ip_addr} + + def get_data(self): + data = super(VictimHostTelem, self).get_data() + data.update({ + 'machine': self.machine + }) + return data diff --git a/monkey/infection_monkey/telemetry/base_telem.py b/monkey/infection_monkey/telemetry/base_telem.py new file mode 100644 index 000000000..eaafc6aa8 --- /dev/null +++ b/monkey/infection_monkey/telemetry/base_telem.py @@ -0,0 +1,36 @@ +import abc + +from infection_monkey.control import ControlClient + +__author__ = 'itay.mizeretz' + + +class BaseTelem(object): + """ + Abstract base class for telemetry. + """ + + __metaclass__ = abc.ABCMeta + + def __init__(self): + pass + + def send(self): + """ + Sends telemetry to island + """ + ControlClient.send_telemetry(self.telem_catagory, self.get_data()) + + @abc.abstractproperty + def telem_catagory(self): + """ + :return: Telemetry type + """ + pass + + @abc.abstractmethod + def get_data(self): + """ + :return: Data of telemetry (should be dict) + """ + pass diff --git a/monkey/infection_monkey/transport/attack_telems/__init__.py b/monkey/infection_monkey/transport/attack_telems/__init__.py deleted file mode 100644 index 98867ed4d..000000000 --- a/monkey/infection_monkey/transport/attack_telems/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__author__ = 'VakarisZ' diff --git a/monkey/infection_monkey/transport/attack_telems/base_telem.py b/monkey/infection_monkey/transport/attack_telems/base_telem.py deleted file mode 100644 index 93d5bbbf7..000000000 --- a/monkey/infection_monkey/transport/attack_telems/base_telem.py +++ /dev/null @@ -1,41 +0,0 @@ -from infection_monkey.config import WormConfiguration, GUID -import requests -import json -from infection_monkey.control import ControlClient -import logging - -__author__ = "VakarisZ" - -LOG = logging.getLogger(__name__) - - -class AttackTelem(object): - - def __init__(self, technique, status, data=None): - """ - Default ATT&CK telemetry constructor - :param technique: Technique ID. E.g. T111 - :param status: int from ScanStatus Enum - :param data: Dictionary of other relevant info. E.g. {'brute_force_blocked': True} - """ - self.technique = technique - self.result = status - self.data = {'status': status, 'id': GUID} - if data: - self.data.update(data) - - def send(self): - """ - Sends telemetry to island - """ - if not WormConfiguration.current_server: - return - try: - requests.post("https://%s/api/attack/%s" % (WormConfiguration.current_server, self.technique), - data=json.dumps(self.data), - headers={'content-type': 'application/json'}, - verify=False, - proxies=ControlClient.proxies) - except Exception as exc: - LOG.warn("Error connecting to control server %s: %s", - WormConfiguration.current_server, exc) diff --git a/monkey/infection_monkey/transport/attack_telems/victim_host_telem.py b/monkey/infection_monkey/transport/attack_telems/victim_host_telem.py deleted file mode 100644 index fc0da7fbf..000000000 --- a/monkey/infection_monkey/transport/attack_telems/victim_host_telem.py +++ /dev/null @@ -1,18 +0,0 @@ -from infection_monkey.transport.attack_telems.base_telem import AttackTelem - -__author__ = "VakarisZ" - - -class VictimHostTelem(AttackTelem): - - def __init__(self, technique, status, machine, data=None): - """ - ATT&CK telemetry that parses and sends VictimHost's (remote machine's) data - :param technique: Technique ID. E.g. T111 - :param status: int from ScanStatus Enum - :param machine: VictimHost obj from model/host.py - :param data: Other data relevant to the attack technique - """ - super(VictimHostTelem, self).__init__(technique, status, data) - victim_host = {'domain_name': machine.domain_name, 'ip_addr': machine.ip_addr} - self.data.update({'machine': victim_host}) diff --git a/monkey/monkey_island/cc/app.py b/monkey/monkey_island/cc/app.py index 82392a7b4..2e04ef0be 100644 --- a/monkey/monkey_island/cc/app.py +++ b/monkey/monkey_island/cc/app.py @@ -33,7 +33,6 @@ from monkey_island.cc.services.database import Database from monkey_island.cc.consts import MONKEY_ISLAND_ABS_PATH from monkey_island.cc.services.remote_run_aws import RemoteRunAwsService from monkey_island.cc.resources.pba_file_upload import FileUpload -from monkey_island.cc.resources.attack.attack_telem import AttackTelem from monkey_island.cc.resources.attack.attack_config import AttackConfiguration from monkey_island.cc.resources.attack.attack_report import AttackReport @@ -133,7 +132,6 @@ def init_api_resources(api): '/api/fileUpload/?restore=') api.add_resource(RemoteRun, '/api/remote-monkey', '/api/remote-monkey/') api.add_resource(AttackConfiguration, '/api/attack') - api.add_resource(AttackTelem, '/api/attack/') api.add_resource(AttackReport, '/api/attack/report') api.add_resource(VersionUpdate, '/api/version-update', '/api/version-update/') diff --git a/monkey/monkey_island/cc/resources/attack/attack_telem.py b/monkey/monkey_island/cc/resources/attack/attack_telem.py deleted file mode 100644 index 8c30bb13c..000000000 --- a/monkey/monkey_island/cc/resources/attack/attack_telem.py +++ /dev/null @@ -1,24 +0,0 @@ -import flask_restful -from flask import request -import json -from monkey_island.cc.services.attack.attack_telem import AttackTelemService -import logging - -__author__ = 'VakarisZ' - -LOG = logging.getLogger(__name__) - - -class AttackTelem(flask_restful.Resource): - """ - ATT&CK endpoint used to retrieve matrix related info from monkey - """ - - def post(self, technique): - """ - Gets ATT&CK telemetry data and stores it in the database - :param technique: Technique ID, e.g. T1111 - """ - data = json.loads(request.data) - AttackTelemService.set_results(technique, data) - return {} diff --git a/monkey/monkey_island/cc/resources/monkey.py b/monkey/monkey_island/cc/resources/monkey.py index 2f464f068..9a96abe3b 100644 --- a/monkey/monkey_island/cc/resources/monkey.py +++ b/monkey/monkey_island/cc/resources/monkey.py @@ -95,7 +95,7 @@ class Monkey(flask_restful.Resource): parent_to_add = (monkey_json.get('guid'), None) # default values in case of manual run if parent and parent != monkey_json.get('guid'): # current parent is known exploit_telem = [x for x in - mongo.db.telemetry.find({'telem_type': {'$eq': 'exploit'}, 'data.result': {'$eq': True}, + mongo.db.telemetry.find({'telem_catagory': {'$eq': 'exploit'}, 'data.result': {'$eq': True}, 'data.machine.ip_addr': {'$in': monkey_json['ip_addresses']}, 'monkey_guid': {'$eq': parent}})] if 1 == len(exploit_telem): @@ -104,7 +104,7 @@ class Monkey(flask_restful.Resource): parent_to_add = (parent, None) elif (not parent or parent == monkey_json.get('guid')) and 'ip_addresses' in monkey_json: exploit_telem = [x for x in - mongo.db.telemetry.find({'telem_type': {'$eq': 'exploit'}, 'data.result': {'$eq': True}, + mongo.db.telemetry.find({'telem_catagory': {'$eq': 'exploit'}, 'data.result': {'$eq': True}, 'data.machine.ip_addr': {'$in': monkey_json['ip_addresses']}})] if 1 == len(exploit_telem): diff --git a/monkey/monkey_island/cc/resources/telemetry.py b/monkey/monkey_island/cc/resources/telemetry.py index 5d63a96ca..69b6bcdd4 100644 --- a/monkey/monkey_island/cc/resources/telemetry.py +++ b/monkey/monkey_island/cc/resources/telemetry.py @@ -26,7 +26,7 @@ class Telemetry(flask_restful.Resource): @jwt_required() def get(self, **kw): monkey_guid = request.args.get('monkey_guid') - telem_type = request.args.get('telem_type') + telem_catagory = request.args.get('telem_catagory') timestamp = request.args.get('timestamp') if "null" == timestamp: # special case to avoid ugly JS code... timestamp = None @@ -36,8 +36,8 @@ class Telemetry(flask_restful.Resource): if monkey_guid: find_filter["monkey_guid"] = {'$eq': monkey_guid} - if telem_type: - find_filter["telem_type"] = {'$eq': telem_type} + if telem_catagory: + find_filter["telem_catagory"] = {'$eq': telem_catagory} if timestamp: find_filter['timestamp'] = {'$gt': dateutil.parser.parse(timestamp)} @@ -53,11 +53,11 @@ class Telemetry(flask_restful.Resource): try: NodeService.update_monkey_modify_time(monkey["_id"]) - telem_type = telemetry_json.get('telem_type') - if telem_type in TELEM_PROCESS_DICT: - TELEM_PROCESS_DICT[telem_type](telemetry_json) + telem_catagory = telemetry_json.get('telem_catagory') + if telem_catagory in TELEM_PROCESS_DICT: + TELEM_PROCESS_DICT[telem_catagory](telemetry_json) else: - logger.info('Got unknown type of telemetry: %s' % telem_type) + logger.info('Got unknown type of telemetry: %s' % telem_catagory) except Exception as ex: logger.error("Exception caught while processing telemetry", exc_info=True) @@ -79,7 +79,7 @@ class Telemetry(flask_restful.Resource): monkey_label = telem_monkey_guid x["monkey"] = monkey_label objects.append(x) - if x['telem_type'] == 'system_info_collection' and 'credentials' in x['data']: + if x['telem_catagory'] == 'system_info_collection' and 'credentials' in x['data']: for user in x['data']['credentials']: if -1 != user.find(','): new_user = user.replace(',', '.') @@ -265,6 +265,12 @@ class Telemetry(flask_restful.Resource): {'guid': telemetry_json['monkey_guid']}, {'$push': {'pba_results': telemetry_json['data']}}) + @staticmethod + def process_attack_telemetry(telemetry_json): + # No processing required + pass + + TELEM_PROCESS_DICT = \ { 'tunnel': Telemetry.process_tunnel_telemetry, @@ -273,5 +279,6 @@ TELEM_PROCESS_DICT = \ 'scan': Telemetry.process_scan_telemetry, 'system_info_collection': Telemetry.process_system_info_telemetry, 'trace': Telemetry.process_trace_telemetry, - 'post_breach': Telemetry.process_post_breach_telemetry + 'post_breach': Telemetry.process_post_breach_telemetry, + 'attack': Telemetry.process_attack_telemetry } diff --git a/monkey/monkey_island/cc/resources/telemetry_feed.py b/monkey/monkey_island/cc/resources/telemetry_feed.py index 01fdcc51c..57a655297 100644 --- a/monkey/monkey_island/cc/resources/telemetry_feed.py +++ b/monkey/monkey_island/cc/resources/telemetry_feed.py @@ -38,7 +38,7 @@ class TelemetryFeed(flask_restful.Resource): 'id': telem['_id'], 'timestamp': telem['timestamp'].strftime('%d/%m/%Y %H:%M:%S'), 'hostname': monkey.get('hostname', default_hostname) if monkey else default_hostname, - 'brief': TELEM_PROCESS_DICT[telem['telem_type']](telem) + 'brief': TELEM_PROCESS_DICT[telem['telem_catagory']](telem) } @staticmethod @@ -86,6 +86,10 @@ class TelemetryFeed(flask_restful.Resource): telem['data']['hostname'], telem['data']['ip']) + @staticmethod + def get_attack_telem_brief(telem): + return 'Monkey collected MITRE ATT&CK info.' + TELEM_PROCESS_DICT = \ { @@ -95,5 +99,6 @@ TELEM_PROCESS_DICT = \ 'scan': TelemetryFeed.get_scan_telem_brief, 'system_info_collection': TelemetryFeed.get_systeminfo_telem_brief, 'trace': TelemetryFeed.get_trace_telem_brief, - 'post_breach': TelemetryFeed.get_post_breach_telem_brief + 'post_breach': TelemetryFeed.get_post_breach_telem_brief, + 'attack': TelemetryFeed.get_attack_telem_brief } diff --git a/monkey/monkey_island/cc/services/attack/attack_report.py b/monkey/monkey_island/cc/services/attack/attack_report.py index 6801bcd64..314a2e4df 100644 --- a/monkey/monkey_island/cc/services/attack/attack_report.py +++ b/monkey/monkey_island/cc/services/attack/attack_report.py @@ -1,6 +1,5 @@ import logging from monkey_island.cc.services.attack.technique_reports import T1210, T1197, T1110 -from monkey_island.cc.services.attack.attack_telem import AttackTelemService from monkey_island.cc.services.attack.attack_config import AttackConfig from monkey_island.cc.database import mongo @@ -26,7 +25,7 @@ class AttackReportService: Generates new report based on telemetries, replaces old report in db with new one. :return: Report object """ - report = {'techniques': {}, 'meta': AttackTelemService.get_latest_telem(), 'name': REPORT_NAME} + report = {'techniques': {}, 'latest_telem_time': AttackReportService.get_latest_attack_telem_time(), 'name': REPORT_NAME} for tech_id, value in AttackConfig.get_technique_values().items(): if value: try: @@ -37,6 +36,14 @@ class AttackReportService: mongo.db.attack_report.replace_one({'name': REPORT_NAME}, report, upsert=True) return report + @staticmethod + def get_latest_attack_telem_time(): + """ + Gets timestamp of latest attack telem + :return: timestamp of latest attack telem + """ + return [x['timestamp'] for x in mongo.db.telemetry.find({'telem_catagory': 'attack'}).sort('timestamp', -1).limit(1)][0] + @staticmethod def get_latest_report(): """ @@ -44,9 +51,9 @@ class AttackReportService: :return: report dict. """ if AttackReportService.is_report_generated(): - telem_time = AttackTelemService.get_latest_telem() + telem_time = AttackReportService.get_latest_attack_telem_time() latest_report = mongo.db.attack_report.find_one({'name': REPORT_NAME}) - if telem_time and latest_report['meta'] and telem_time['time'] == latest_report['meta']['time']: + if telem_time and latest_report['latest_telem_time'] and telem_time == latest_report['latest_telem_time']: return latest_report return AttackReportService.generate_new_report() diff --git a/monkey/monkey_island/cc/services/attack/attack_telem.py b/monkey/monkey_island/cc/services/attack/attack_telem.py deleted file mode 100644 index b402bda56..000000000 --- a/monkey/monkey_island/cc/services/attack/attack_telem.py +++ /dev/null @@ -1,30 +0,0 @@ -""" -File that contains ATT&CK telemetry storing/retrieving logic -""" -import logging -from monkey_island.cc.database import mongo - -__author__ = "VakarisZ" - -logger = logging.getLogger(__name__) - - -class AttackTelemService(object): - def __init__(self): - pass - - @staticmethod - def set_results(technique, data): - """ - Adds ATT&CK technique results(telemetry) to the database - :param technique: technique ID string e.g. T1110 - :param data: Data, relevant to the technique - """ - data.update({'technique': technique}) - mongo.db.attack_results.insert(data) - mongo.db.attack_results.update({'name': 'latest'}, {'name': 'latest', 'time': data['time']}, upsert=True) - - - @staticmethod - def get_latest_telem(): - return mongo.db.attack_results.find_one({'name': 'latest'}) diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1197.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1197.py index 0aaab082b..7146fde8b 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1197.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1197.py @@ -13,12 +13,12 @@ class T1197(AttackTechnique): @staticmethod def get_report_data(): data = T1197.get_tech_base_data(T1197) - bits_results = mongo.db.attack_results.aggregate([{'$match': {'technique': T1197.tech_id}}, - {'$group': {'_id': {'ip_addr': '$machine.ip_addr', 'usage': '$usage'}, - 'ip_addr': {'$first': '$machine.ip_addr'}, - 'domain_name': {'$first': '$machine.domain_name'}, - 'usage': {'$first': '$usage'}, - 'time': {'$first': '$time'}} + bits_results = mongo.db.telemetry.aggregate([{'$match': {'telem_catagory': 'attack', 'data.technique': T1197.tech_id}}, + {'$group': {'_id': {'ip_addr': '$data.machine.ip_addr', 'usage': '$data.usage'}, + 'ip_addr': {'$first': '$data.machine.ip_addr'}, + 'domain_name': {'$first': '$data.machine.domain_name'}, + 'usage': {'$first': '$data.usage'}, + 'time': {'$first': '$timestamp'}} }]) bits_results = list(bits_results) data.update({'bits_jobs': bits_results}) 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 b6335422f..677495c10 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1210.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1210.py @@ -28,7 +28,7 @@ class T1210(AttackTechnique): @staticmethod def get_scanned_services(): - results = mongo.db.telemetry.aggregate([{'$match': {'telem_type': 'scan'}}, + results = mongo.db.telemetry.aggregate([{'$match': {'telem_catagory': 'scan'}}, {'$sort': {'data.service_count': -1}}, {'$group': { '_id': {'ip_addr': '$data.machine.ip_addr'}, @@ -38,7 +38,7 @@ class T1210(AttackTechnique): @staticmethod def get_exploited_services(): - results = mongo.db.telemetry.aggregate([{'$match': {'telem_type': 'exploit', 'data.result': True}}, + results = mongo.db.telemetry.aggregate([{'$match': {'telem_catagory': 'exploit', 'data.result': True}}, {'$group': { '_id': {'ip_addr': '$data.machine.ip_addr'}, 'service': {'$first': '$data.info'}, 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 8d60e963f..1990b61e7 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py @@ -53,9 +53,9 @@ class AttackTechnique(object): :param technique: technique's id. :return: ScanStatus Enum object """ - if mongo.db.attack_results.find_one({'status': ScanStatus.USED.value, 'technique': technique}): + if mongo.db.telemetry.find_one({'telem_catagory': 'attack', 'data.status': ScanStatus.USED.value, 'data.technique': technique}): return ScanStatus.USED - elif mongo.db.attack_results.find_one({'status': ScanStatus.SCANNED.value, 'technique': technique}): + elif mongo.db.telemetry.find_one({'telem_catagory': 'attack', 'data.status': ScanStatus.SCANNED.value, 'data.technique': technique}): return ScanStatus.SCANNED else: return ScanStatus.UNSCANNED diff --git a/monkey/monkey_island/cc/services/report.py b/monkey/monkey_island/cc/services/report.py index 702a42cd1..2cd0e82fa 100644 --- a/monkey/monkey_island/cc/services/report.py +++ b/monkey/monkey_island/cc/services/report.py @@ -171,7 +171,7 @@ class ReportService: PASS_TYPE_DICT = {'password': 'Clear Password', 'lm_hash': 'LM hash', 'ntlm_hash': 'NTLM hash'} creds = [] for telem in mongo.db.telemetry.find( - {'telem_type': 'system_info_collection', 'data.credentials': {'$exists': True}}, + {'telem_catagory': 'system_info_collection', 'data.credentials': {'$exists': True}}, {'data.credentials': 1, 'monkey_guid': 1} ): monkey_creds = telem['data']['credentials'] @@ -199,7 +199,7 @@ class ReportService: """ creds = [] for telem in mongo.db.telemetry.find( - {'telem_type': 'system_info_collection', 'data.ssh_info': {'$exists': True}}, + {'telem_catagory': 'system_info_collection', 'data.ssh_info': {'$exists': True}}, {'data.ssh_info': 1, 'monkey_guid': 1} ): origin = NodeService.get_monkey_by_guid(telem['monkey_guid'])['hostname'] @@ -220,7 +220,7 @@ class ReportService: """ creds = [] for telem in mongo.db.telemetry.find( - {'telem_type': 'system_info_collection', 'data.Azure': {'$exists': True}}, + {'telem_catagory': 'system_info_collection', 'data.Azure': {'$exists': True}}, {'data.Azure': 1, 'monkey_guid': 1} ): azure_users = telem['data']['Azure']['usernames'] @@ -373,7 +373,7 @@ class ReportService: @staticmethod def get_exploits(): exploits = [] - for exploit in mongo.db.telemetry.find({'telem_type': 'exploit', 'data.result': True}): + for exploit in mongo.db.telemetry.find({'telem_catagory': 'exploit', 'data.result': True}): new_exploit = ReportService.process_exploit(exploit) if new_exploit not in exploits: exploits.append(new_exploit) @@ -382,7 +382,7 @@ class ReportService: @staticmethod def get_monkey_subnets(monkey_guid): network_info = mongo.db.telemetry.find_one( - {'telem_type': 'system_info_collection', 'monkey_guid': monkey_guid}, + {'telem_catagory': 'system_info_collection', 'monkey_guid': monkey_guid}, {'data.network_info.networks': 1} ) if network_info is None: @@ -540,7 +540,7 @@ class ReportService: @staticmethod def get_cross_segment_issues(): - scans = mongo.db.telemetry.find({'telem_type': 'scan'}, + scans = mongo.db.telemetry.find({'telem_catagory': 'scan'}, {'monkey_guid': 1, 'data.machine.ip_addr': 1, 'data.machine.services': 1}) cross_segment_issues = [] diff --git a/monkey/monkey_island/cc/ui/src/components/pages/TelemetryPage.js b/monkey/monkey_island/cc/ui/src/components/pages/TelemetryPage.js index a23dd1d36..120344eea 100644 --- a/monkey/monkey_island/cc/ui/src/components/pages/TelemetryPage.js +++ b/monkey/monkey_island/cc/ui/src/components/pages/TelemetryPage.js @@ -11,7 +11,7 @@ const renderTime = (val) => val.split('.')[0]; const columns = [ { title: 'Time', prop: 'timestamp', render: renderTime}, { title: 'Monkey', prop: 'monkey'}, - { title: 'Type', prop: 'telem_type'}, + { title: 'Type', prop: 'telem_catagory'}, { title: 'Details', prop: 'data', render: renderJson, width: '40%' } ];