From fc28135e00f384e3f258370b541a603ea3c289a5 Mon Sep 17 00:00:00 2001 From: itay Date: Sun, 2 Jun 2019 17:44:56 +0300 Subject: [PATCH 01/27] Changed attack telemetry to be regular telemetry. Made telemetries OOP (not retroactively) --- monkey/infection_monkey/monkey.py | 6 +-- monkey/infection_monkey/telemetry/__init__.py | 0 .../telemetry/attack/__init__.py | 0 .../telemetry/attack/attack_telem.py | 28 +++++++++++++ .../telemetry/attack/victim_host_telem.py | 21 ++++++++++ .../infection_monkey/telemetry/base_telem.py | 39 ++++++++++++++++++ .../transport/attack_telems/__init__.py | 1 - .../transport/attack_telems/base_telem.py | 41 ------------------- .../attack_telems/victim_host_telem.py | 18 -------- monkey/monkey_island/cc/app.py | 2 - .../cc/resources/attack_telem.py | 24 ----------- .../cc/services/attack/attack_telem.py | 24 ----------- 12 files changed, 91 insertions(+), 113 deletions(-) create mode 100644 monkey/infection_monkey/telemetry/__init__.py create mode 100644 monkey/infection_monkey/telemetry/attack/__init__.py create mode 100644 monkey/infection_monkey/telemetry/attack/attack_telem.py create mode 100644 monkey/infection_monkey/telemetry/attack/victim_host_telem.py create mode 100644 monkey/infection_monkey/telemetry/base_telem.py delete mode 100644 monkey/infection_monkey/transport/attack_telems/__init__.py delete mode 100644 monkey/infection_monkey/transport/attack_telems/base_telem.py delete mode 100644 monkey/infection_monkey/transport/attack_telems/victim_host_telem.py delete mode 100644 monkey/monkey_island/cc/resources/attack_telem.py delete mode 100644 monkey/monkey_island/cc/services/attack/attack_telem.py diff --git a/monkey/infection_monkey/monkey.py b/monkey/infection_monkey/monkey.py index 912386d4c..6cb9c13ae 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,11 +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.value, machine=machine).send() + VictimHostTelem('T1210', ScanStatus.USED, machine).send() break if not host_exploited: self._fail_exploitation_machines.add(machine) - VictimHostTelem('T1210', ScanStatus.SCANNED.value, machine=machine).send() + VictimHostTelem('T1210', ScanStatus.SCANNED, 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..6dc6a4ca9 --- /dev/null +++ b/monkey/infection_monkey/telemetry/attack/attack_telem.py @@ -0,0 +1,28 @@ +import logging + +from infection_monkey.telemetry.base_telem import BaseTelem + +__author__ = "VakarisZ" + +LOG = logging.getLogger(__name__) + + +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_type = 'attack' + + def get_data(self): + return { + 'status': self.status.value, + 'technique': self.technique + } 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..211ab7eb1 --- /dev/null +++ b/monkey/infection_monkey/telemetry/attack/victim_host_telem.py @@ -0,0 +1,21 @@ +from infection_monkey.telemetry.attack.attack_telem import AttackTelem + +__author__ = "VakarisZ" + + +class VictimHostTelem(AttackTelem): + + def __init__(self, technique, status, machine): + """ + ATT&CK telemetry that parses and sends 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): + return super(VictimHostTelem, self).get_data().update({ + 'machine': self.machine + }) diff --git a/monkey/infection_monkey/telemetry/base_telem.py b/monkey/infection_monkey/telemetry/base_telem.py new file mode 100644 index 000000000..7bec9e890 --- /dev/null +++ b/monkey/infection_monkey/telemetry/base_telem.py @@ -0,0 +1,39 @@ +import abc + +from infection_monkey.control import ControlClient +import logging + +__author__ = 'itay.mizeretz' + +LOG = logging.getLogger(__name__) + + +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_type, self.get_data()) + + @abc.abstractproperty + def telem_type(self): + """ + :return: Telemetry type + """ + pass + + @abc.abstractmethod + def get_data(self): + """ + :return: Telemetry type + """ + 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 9d0275356..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: Other data relevant to the attack technique - """ - 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 ecab5a648..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 = {'hostname': machine.domain_name, 'ip': 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 69557c31c..3a19a4b07 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_telem import AttackTelem from monkey_island.cc.resources.attack_config import AttackConfiguration __author__ = 'Barak' @@ -132,7 +131,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(VersionUpdate, '/api/version-update', '/api/version-update/') diff --git a/monkey/monkey_island/cc/resources/attack_telem.py b/monkey/monkey_island/cc/resources/attack_telem.py deleted file mode 100644 index 8c30bb13c..000000000 --- a/monkey/monkey_island/cc/resources/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/services/attack/attack_telem.py b/monkey/monkey_island/cc/services/attack/attack_telem.py deleted file mode 100644 index d1255e4e9..000000000 --- a/monkey/monkey_island/cc/services/attack/attack_telem.py +++ /dev/null @@ -1,24 +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) From b2eef282913c90b588099e28eb07a073c4aa66ed Mon Sep 17 00:00:00 2001 From: itay Date: Tue, 11 Jun 2019 16:13:26 +0300 Subject: [PATCH 02/27] Fix VictimHost's getData --- monkey/infection_monkey/telemetry/attack/victim_host_telem.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/monkey/infection_monkey/telemetry/attack/victim_host_telem.py b/monkey/infection_monkey/telemetry/attack/victim_host_telem.py index 211ab7eb1..3fbbeb3a1 100644 --- a/monkey/infection_monkey/telemetry/attack/victim_host_telem.py +++ b/monkey/infection_monkey/telemetry/attack/victim_host_telem.py @@ -16,6 +16,8 @@ class VictimHostTelem(AttackTelem): self.machine = {'domain_name': machine.domain_name, 'ip_addr': machine.ip_addr} def get_data(self): - return super(VictimHostTelem, self).get_data().update({ + data = super(VictimHostTelem, self).get_data() + data.update({ 'machine': self.machine }) + return data From 93d6280d1acf2854dc7883562967bf5dcdd9dc4b Mon Sep 17 00:00:00 2001 From: itay Date: Tue, 11 Jun 2019 16:16:36 +0300 Subject: [PATCH 03/27] Fix CR comments --- .../telemetry/attack/attack_telem.py | 4 ---- .../telemetry/attack/test_victimHostTelem.py | 20 +++++++++++++++++++ .../telemetry/attack/victim_host_telem.py | 3 ++- .../infection_monkey/telemetry/base_telem.py | 5 +---- 4 files changed, 23 insertions(+), 9 deletions(-) create mode 100644 monkey/infection_monkey/telemetry/attack/test_victimHostTelem.py diff --git a/monkey/infection_monkey/telemetry/attack/attack_telem.py b/monkey/infection_monkey/telemetry/attack/attack_telem.py index 6dc6a4ca9..ab11adecc 100644 --- a/monkey/infection_monkey/telemetry/attack/attack_telem.py +++ b/monkey/infection_monkey/telemetry/attack/attack_telem.py @@ -1,11 +1,7 @@ -import logging - from infection_monkey.telemetry.base_telem import BaseTelem __author__ = "VakarisZ" -LOG = logging.getLogger(__name__) - class AttackTelem(BaseTelem): diff --git a/monkey/infection_monkey/telemetry/attack/test_victimHostTelem.py b/monkey/infection_monkey/telemetry/attack/test_victimHostTelem.py new file mode 100644 index 000000000..0feb33b75 --- /dev/null +++ b/monkey/infection_monkey/telemetry/attack/test_victimHostTelem.py @@ -0,0 +1,20 @@ +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.technique, technique) + self.assertEqual(telem.status, status) + self.assertEqual(telem.telem_type, 'attack') + self.assertEqual(telem.machine['domain_name'], machine.domain_name) + self.assertEqual(telem.machine['ip_addr'], machine.ip_addr) diff --git a/monkey/infection_monkey/telemetry/attack/victim_host_telem.py b/monkey/infection_monkey/telemetry/attack/victim_host_telem.py index 3fbbeb3a1..9e277926c 100644 --- a/monkey/infection_monkey/telemetry/attack/victim_host_telem.py +++ b/monkey/infection_monkey/telemetry/attack/victim_host_telem.py @@ -7,7 +7,8 @@ class VictimHostTelem(AttackTelem): def __init__(self, technique, status, machine): """ - ATT&CK telemetry that parses and sends VictimHost's (remote machine's) data + 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 diff --git a/monkey/infection_monkey/telemetry/base_telem.py b/monkey/infection_monkey/telemetry/base_telem.py index 7bec9e890..d280ebfee 100644 --- a/monkey/infection_monkey/telemetry/base_telem.py +++ b/monkey/infection_monkey/telemetry/base_telem.py @@ -1,12 +1,9 @@ import abc from infection_monkey.control import ControlClient -import logging __author__ = 'itay.mizeretz' -LOG = logging.getLogger(__name__) - class BaseTelem(object): """ @@ -34,6 +31,6 @@ class BaseTelem(object): @abc.abstractmethod def get_data(self): """ - :return: Telemetry type + :return: Data of telemetry (should be dict) """ pass From 4d962feafe575e502d6f1382f84f9f3788807da8 Mon Sep 17 00:00:00 2001 From: itay Date: Tue, 11 Jun 2019 16:34:54 +0300 Subject: [PATCH 04/27] Rename test victim host telem file Create new T1197Telem class for new telemetries --- monkey/common/utils/attack_utils.py | 3 ++- .../infection_monkey/exploit/elasticgroovy.py | 4 ++-- monkey/infection_monkey/exploit/rdpgrinder.py | 4 ++-- monkey/infection_monkey/exploit/web_rce.py | 4 ++-- .../telemetry/attack/t1197_telem.py | 22 +++++++++++++++++++ ...HostTelem.py => test_victim_host_telem.py} | 0 6 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 monkey/infection_monkey/telemetry/attack/t1197_telem.py rename monkey/infection_monkey/telemetry/attack/{test_victimHostTelem.py => test_victim_host_telem.py} (100%) 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/exploit/elasticgroovy.py b/monkey/infection_monkey/exploit/elasticgroovy.py index 8b5759c8f..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.telemetry.attack.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, 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 1e2937d7e..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.telemetry.attack.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, 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 c594df8f4..134ea4817 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.telemetry.attack.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' @@ -307,7 +307,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, 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/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_victimHostTelem.py b/monkey/infection_monkey/telemetry/attack/test_victim_host_telem.py similarity index 100% rename from monkey/infection_monkey/telemetry/attack/test_victimHostTelem.py rename to monkey/infection_monkey/telemetry/attack/test_victim_host_telem.py From 22815b7e0273085eb00e924987bfe009a7d5cf8a Mon Sep 17 00:00:00 2001 From: itay Date: Tue, 11 Jun 2019 16:42:55 +0300 Subject: [PATCH 05/27] Fix test --- .../telemetry/attack/test_victim_host_telem.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/monkey/infection_monkey/telemetry/attack/test_victim_host_telem.py b/monkey/infection_monkey/telemetry/attack/test_victim_host_telem.py index 0feb33b75..753236131 100644 --- a/monkey/infection_monkey/telemetry/attack/test_victim_host_telem.py +++ b/monkey/infection_monkey/telemetry/attack/test_victim_host_telem.py @@ -13,8 +13,17 @@ class TestVictimHostTelem(TestCase): telem = VictimHostTelem(technique, status, machine) - self.assertEqual(telem.technique, technique) - self.assertEqual(telem.status, status) self.assertEqual(telem.telem_type, 'attack') - self.assertEqual(telem.machine['domain_name'], machine.domain_name) - self.assertEqual(telem.machine['ip_addr'], machine.ip_addr) + + 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) From 63e64cbd7e45dde60a32e8c283ca805ae01ef8c1 Mon Sep 17 00:00:00 2001 From: itay Date: Tue, 11 Jun 2019 17:33:55 +0300 Subject: [PATCH 06/27] Add attack telemetries to feed and preprocessing dicts Fix 1197 report processing --- monkey/monkey_island/cc/resources/telemetry.py | 9 ++++++++- monkey/monkey_island/cc/resources/telemetry_feed.py | 7 ++++++- .../cc/services/attack/technique_reports/T1197.py | 12 ++++++------ .../cc/services/attack/technique_reports/__init__.py | 4 ++-- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/monkey/monkey_island/cc/resources/telemetry.py b/monkey/monkey_island/cc/resources/telemetry.py index 04a6ddbd1..fd21104d1 100644 --- a/monkey/monkey_island/cc/resources/telemetry.py +++ b/monkey/monkey_island/cc/resources/telemetry.py @@ -263,6 +263,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, @@ -271,5 +277,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..de5ded887 100644 --- a/monkey/monkey_island/cc/resources/telemetry_feed.py +++ b/monkey/monkey_island/cc/resources/telemetry_feed.py @@ -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/technique_reports/T1197.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1197.py index 0aaab082b..dcad5bfd5 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_type': '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/__init__.py b/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py index 0346a1857..d194fc221 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_type': '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_type': 'attack', 'data.status': ScanStatus.SCANNED.value, 'data.technique': technique}): return ScanStatus.SCANNED else: return ScanStatus.UNSCANNED From f2d25c44810d3c19464396a1eb9fafd11c36dcec Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Wed, 12 Jun 2019 11:51:20 +0300 Subject: [PATCH 07/27] fixed PR comments --- .../attack/technique_reports/T1110.py | 38 ++++++++++++------- .../attack/technique_reports/__init__.py | 9 +++++ 2 files changed, 34 insertions(+), 13 deletions(-) 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 040b05be2..977fb860a 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: - data = {'message': T1110.used_msg, 'status': ScanStatus.USED.name} + data = T1110.get_message_and_status(T1110, ScanStatus.USED) elif attempts: - data = {'message': T1110.scanned_msg, 'status': ScanStatus.SCANNED.name} + data = T1110.get_message_and_status(T1110, ScanStatus.SCANNED) else: - data = {'message': T1110.unscanned_msg, 'status': ScanStatus.UNSCANNED.name} + data = T1110.get_message_and_status(T1110, ScanStatus.UNSCANNED) data.update({'services': attempts, 'title': T1110.technique_title(T1110.tech_id)}) return data @@ -51,21 +51,33 @@ class T1110(AttackTechnique): :return: string with username and used password/hash """ username = attempt['user'] - if attempt['lm_hash']: - return '%s ; LM hash %s ...' % (username, encryptor.dec(attempt['lm_hash'])[0:5]) - if attempt['ntlm_hash']: - return '%s ; NTLM hash %s ...' % (username, encryptor.dec(attempt['ntlm_hash'])[0:20]) - if attempt['ssh_key']: - return '%s ; SSH key %s ...' % (username, encryptor.dec(attempt['ssh_key'])[0:15]) - if attempt['password']: - return '%s : %s' % (username, T1110.obfuscate_password(encryptor.dec(attempt['password']))) + creds = {'lm_hash': {'type': 'LM hash', 'shown_chars': 5, 'funct': T1110.censor_hash}, + 'ntlm_hash': {'type': 'NTLM hash', 'shown_chars': 20, 'funct': T1110.censor_hash}, + 'ssh_key': {'type': 'SSH key', 'shown_chars': 15, 'funct': T1110.censor_hash}, + 'password': {'type': 'Plaintext password', 'shown_chars': 3, 'funct': T1110.censor_password}} + for key, cred in creds.items(): + if attempt[key]: + return '%s ; %s : %s' % (username, + cred['type'], + cred['funct'](encryptor.dec(attempt[key]), cred['shown_chars'])) @staticmethod - def obfuscate_password(password, plain_chars=3): + def censor_password(password, plain_chars=3, secret_chars=5): """ Obfuscates password by changing characters to * :param password: Password or string to obfuscate :param plain_chars: How many plain-text characters should be kept at the start of the string + :param secret_chars: How many * symbols should be used to hide the remainder of the password :return: Obfuscated string e.g. Pass**** """ - return password[0:plain_chars] + '*' * (len(password) - plain_chars) + return password[0:plain_chars] + '*' * secret_chars + + @staticmethod + def censor_hash(hash_, plain_chars=5): + """ + Obfuscates hash by only showing a part of it + :param hash_: Hash to obfuscate + :param plain_chars: How many chars of hash should be shown + :return: Obfuscated string + """ + return hash_[0: plain_chars] + ' ...' 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 0346a1857..782ca389d 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py @@ -60,6 +60,15 @@ class AttackTechnique(object): else: return ScanStatus.UNSCANNED + @staticmethod + def get_message_and_status(technique, status): + if status == ScanStatus.UNSCANNED: + return {'message': technique.unscanned_msg, 'status': ScanStatus.UNSCANNED.name} + elif status == ScanStatus.SCANNED: + return {'message': technique.scanned_msg, 'status': ScanStatus.SCANNED.name} + else: + return {'message': technique.used_msg, 'status': ScanStatus.USED.name} + @staticmethod def technique_title(technique): """ From e6c3cdb3611fe4d20158501e8adc48eebddee393 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Fri, 14 Jun 2019 09:09:34 +0300 Subject: [PATCH 08/27] Hook method for exploiters implemented --- monkey/infection_monkey/exploit/__init__.py | 6 ++++++ monkey/infection_monkey/exploit/hadoop.py | 2 +- monkey/infection_monkey/exploit/mssqlexec.py | 2 +- monkey/infection_monkey/exploit/rdpgrinder.py | 2 +- monkey/infection_monkey/exploit/sambacry.py | 2 +- monkey/infection_monkey/exploit/shellshock.py | 2 +- monkey/infection_monkey/exploit/smbexec.py | 2 +- monkey/infection_monkey/exploit/sshexec.py | 2 +- monkey/infection_monkey/exploit/vsftpd.py | 2 +- monkey/infection_monkey/exploit/web_rce.py | 2 +- monkey/infection_monkey/exploit/win_ms08_067.py | 6 +++--- monkey/infection_monkey/exploit/wmiexec.py | 2 +- monkey/infection_monkey/monkey.py | 2 -- 13 files changed, 19 insertions(+), 15 deletions(-) diff --git a/monkey/infection_monkey/exploit/__init__.py b/monkey/infection_monkey/exploit/__init__.py index 7353d77bc..ea1909f68 100644 --- a/monkey/infection_monkey/exploit/__init__.py +++ b/monkey/infection_monkey/exploit/__init__.py @@ -50,6 +50,12 @@ class HostExploiter(object): @abstractmethod def exploit_host(self): + self.set_start_time() + self._exploit_host() + self.set_finish_time() + + @abstractmethod + def _exploit_host(self): raise NotImplementedError() def add_vuln_url(self, url): diff --git a/monkey/infection_monkey/exploit/hadoop.py b/monkey/infection_monkey/exploit/hadoop.py index f02c4f3d3..43336420c 100644 --- a/monkey/infection_monkey/exploit/hadoop.py +++ b/monkey/infection_monkey/exploit/hadoop.py @@ -31,7 +31,7 @@ class HadoopExploiter(WebRCE): def __init__(self, host): super(HadoopExploiter, self).__init__(host) - def exploit_host(self): + def _exploit_host(self): # Try to get exploitable url urls = self.build_potential_urls(self.HADOOP_PORTS) self.add_vulnerable_urls(urls, True) diff --git a/monkey/infection_monkey/exploit/mssqlexec.py b/monkey/infection_monkey/exploit/mssqlexec.py index c7d29c8c2..3bfda397f 100644 --- a/monkey/infection_monkey/exploit/mssqlexec.py +++ b/monkey/infection_monkey/exploit/mssqlexec.py @@ -29,7 +29,7 @@ class MSSQLExploiter(HostExploiter): def __init__(self, host): super(MSSQLExploiter, self).__init__(host) - def exploit_host(self): + def _exploit_host(self): # Brute force to get connection username_passwords_pairs_list = self._config.get_exploit_user_password_pairs() cursor = self.brute_force(self.host.ip_addr, self.SQL_DEFAULT_TCP_PORT, username_passwords_pairs_list) diff --git a/monkey/infection_monkey/exploit/rdpgrinder.py b/monkey/infection_monkey/exploit/rdpgrinder.py index 8e219b5c8..f5b863080 100644 --- a/monkey/infection_monkey/exploit/rdpgrinder.py +++ b/monkey/infection_monkey/exploit/rdpgrinder.py @@ -255,7 +255,7 @@ class RdpExploiter(HostExploiter): return True return False - def exploit_host(self): + def _exploit_host(self): global g_reactor is_open, _ = check_tcp_port(self.host.ip_addr, RDP_PORT) diff --git a/monkey/infection_monkey/exploit/sambacry.py b/monkey/infection_monkey/exploit/sambacry.py index 7c49f51ae..7d9ed1010 100644 --- a/monkey/infection_monkey/exploit/sambacry.py +++ b/monkey/infection_monkey/exploit/sambacry.py @@ -57,7 +57,7 @@ class SambaCryExploiter(HostExploiter): def __init__(self, host): super(SambaCryExploiter, self).__init__(host) - def exploit_host(self): + def _exploit_host(self): if not self.is_vulnerable(): return False diff --git a/monkey/infection_monkey/exploit/shellshock.py b/monkey/infection_monkey/exploit/shellshock.py index 2f6e3516f..337e0ec03 100644 --- a/monkey/infection_monkey/exploit/shellshock.py +++ b/monkey/infection_monkey/exploit/shellshock.py @@ -36,7 +36,7 @@ class ShellShockExploiter(HostExploiter): ) for _ in range(20)) self.skip_exist = self._config.skip_exploit_if_file_exist - def exploit_host(self): + def _exploit_host(self): # start by picking ports candidate_services = { service: self.host.services[service] for service in self.host.services if diff --git a/monkey/infection_monkey/exploit/smbexec.py b/monkey/infection_monkey/exploit/smbexec.py index 1b4071312..d49e66ae8 100644 --- a/monkey/infection_monkey/exploit/smbexec.py +++ b/monkey/infection_monkey/exploit/smbexec.py @@ -43,7 +43,7 @@ class SmbExploiter(HostExploiter): return self.host.os.get('type') in self._TARGET_OS_TYPE return False - def exploit_host(self): + def _exploit_host(self): src_path = get_target_monkey(self.host) if not src_path: diff --git a/monkey/infection_monkey/exploit/sshexec.py b/monkey/infection_monkey/exploit/sshexec.py index 09982876d..e8b933589 100644 --- a/monkey/infection_monkey/exploit/sshexec.py +++ b/monkey/infection_monkey/exploit/sshexec.py @@ -94,7 +94,7 @@ class SSHExploiter(HostExploiter): continue return exploited - def exploit_host(self): + def _exploit_host(self): ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.WarningPolicy()) diff --git a/monkey/infection_monkey/exploit/vsftpd.py b/monkey/infection_monkey/exploit/vsftpd.py index 3f6a7c304..d60c336ca 100644 --- a/monkey/infection_monkey/exploit/vsftpd.py +++ b/monkey/infection_monkey/exploit/vsftpd.py @@ -60,7 +60,7 @@ class VSFTPDExploiter(HostExploiter): LOG.error('Failed to send payload to %s', self.host.ip_addr) return False - def exploit_host(self): + def _exploit_host(self): LOG.info("Attempting to trigger the Backdoor..") ftp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) diff --git a/monkey/infection_monkey/exploit/web_rce.py b/monkey/infection_monkey/exploit/web_rce.py index 2b08575c3..529af2209 100644 --- a/monkey/infection_monkey/exploit/web_rce.py +++ b/monkey/infection_monkey/exploit/web_rce.py @@ -66,7 +66,7 @@ class WebRCE(HostExploiter): return exploit_config - def exploit_host(self): + def _exploit_host(self): """ Method that contains default exploitation workflow :return: True if exploited, False otherwise diff --git a/monkey/infection_monkey/exploit/win_ms08_067.py b/monkey/infection_monkey/exploit/win_ms08_067.py index 41b3820d5..557b43970 100644 --- a/monkey/infection_monkey/exploit/win_ms08_067.py +++ b/monkey/infection_monkey/exploit/win_ms08_067.py @@ -92,7 +92,7 @@ class SRVSVC_Exploit(object): def get_telnet_port(self): """get_telnet_port() - + The port on which the Telnet service will listen. """ @@ -100,7 +100,7 @@ class SRVSVC_Exploit(object): def start(self): """start() -> socket - + Exploit the target machine and return a socket connected to it's listening Telnet service. """ @@ -174,7 +174,7 @@ class Ms08_067_Exploiter(HostExploiter): self.host.os.get('version') in self._windows_versions.keys() return False - def exploit_host(self): + def _exploit_host(self): src_path = get_target_monkey(self.host) if not src_path: diff --git a/monkey/infection_monkey/exploit/wmiexec.py b/monkey/infection_monkey/exploit/wmiexec.py index 29bc08981..feff1df70 100644 --- a/monkey/infection_monkey/exploit/wmiexec.py +++ b/monkey/infection_monkey/exploit/wmiexec.py @@ -23,7 +23,7 @@ class WmiExploiter(HostExploiter): super(WmiExploiter, self).__init__(host) @WmiTools.dcom_wrap - def exploit_host(self): + def _exploit_host(self): src_path = get_target_monkey(self.host) if not src_path: diff --git a/monkey/infection_monkey/monkey.py b/monkey/infection_monkey/monkey.py index b152e58be..ff35be3d9 100644 --- a/monkey/infection_monkey/monkey.py +++ b/monkey/infection_monkey/monkey.py @@ -283,9 +283,7 @@ class InfectionMonkey(object): result = False try: - exploiter.set_start_time() result = exploiter.exploit_host() - exploiter.set_finish_time() if result: self.successfully_exploited(machine, exploiter) return True From 74042b4f29127fb8062aab3680b3f1dc7ad2ea79 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Fri, 14 Jun 2019 09:15:55 +0300 Subject: [PATCH 09/27] _EXPLOITED_SERVICE var added to win_ms08_067 exploiter --- monkey/infection_monkey/exploit/win_ms08_067.py | 1 + 1 file changed, 1 insertion(+) diff --git a/monkey/infection_monkey/exploit/win_ms08_067.py b/monkey/infection_monkey/exploit/win_ms08_067.py index 41b3820d5..d576af3cd 100644 --- a/monkey/infection_monkey/exploit/win_ms08_067.py +++ b/monkey/infection_monkey/exploit/win_ms08_067.py @@ -153,6 +153,7 @@ class SRVSVC_Exploit(object): class Ms08_067_Exploiter(HostExploiter): _TARGET_OS_TYPE = ['windows'] + _EXPLOITED_SERVICE = 'Microsoft Server Service' _windows_versions = {'Windows Server 2003 3790 Service Pack 2': WindowsVersion.Windows2003_SP2, 'Windows Server 2003 R2 3790 Service Pack 2': WindowsVersion.Windows2003_SP2} From 09c62b7ccfd87d80953143e3b29416d3c295e2f9 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Fri, 14 Jun 2019 10:17:16 +0300 Subject: [PATCH 10/27] minor bugfix --- monkey/infection_monkey/exploit/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/monkey/infection_monkey/exploit/__init__.py b/monkey/infection_monkey/exploit/__init__.py index ea1909f68..661433b97 100644 --- a/monkey/infection_monkey/exploit/__init__.py +++ b/monkey/infection_monkey/exploit/__init__.py @@ -48,7 +48,6 @@ class HostExploiter(object): self._exploit_attempts.append({'result': result, 'user': user, 'password': password, 'lm_hash': lm_hash, 'ntlm_hash': ntlm_hash, 'ssh_key': ssh_key}) - @abstractmethod def exploit_host(self): self.set_start_time() self._exploit_host() From 0422cd32dbecfb3e33635af945af5ce84604dc31 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Fri, 14 Jun 2019 15:52:49 +0300 Subject: [PATCH 11/27] Bugfix --- .../attack/technique_reports/T1110.py | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) 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 977fb860a..7fe5ac90f 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py @@ -40,6 +40,10 @@ class T1110(AttackTechnique): data = T1110.get_message_and_status(T1110, ScanStatus.SCANNED) else: data = T1110.get_message_and_status(T1110, ScanStatus.UNSCANNED) + + # Remove data with no successful brute force attempts + attempts = [attempt for attempt in attempts if attempt['attempts']] + data.update({'services': attempts, 'title': T1110.technique_title(T1110.tech_id)}) return data @@ -51,33 +55,39 @@ class T1110(AttackTechnique): :return: string with username and used password/hash """ username = attempt['user'] - creds = {'lm_hash': {'type': 'LM hash', 'shown_chars': 5, 'funct': T1110.censor_hash}, - 'ntlm_hash': {'type': 'NTLM hash', 'shown_chars': 20, 'funct': T1110.censor_hash}, - 'ssh_key': {'type': 'SSH key', 'shown_chars': 15, 'funct': T1110.censor_hash}, - 'password': {'type': 'Plaintext password', 'shown_chars': 3, 'funct': T1110.censor_password}} + creds = {'lm_hash': {'type': 'LM hash', 'output': T1110.censor_hash(attempt['lm_hash'])}, + 'ntlm_hash': {'type': 'NTLM hash', 'output': T1110.censor_hash(attempt['ntlm_hash'], 20)}, + 'ssh_key': {'type': 'SSH key', 'output': attempt['ssh_key']}, + 'password': {'type': 'Plaintext password', 'output': T1110.censor_password(attempt['password'])}} for key, cred in creds.items(): if attempt[key]: return '%s ; %s : %s' % (username, cred['type'], - cred['funct'](encryptor.dec(attempt[key]), cred['shown_chars'])) + cred['output']) @staticmethod def censor_password(password, plain_chars=3, secret_chars=5): """ - Obfuscates password by changing characters to * + Decrypts and obfuscates password by changing characters to * :param password: Password or string to obfuscate :param plain_chars: How many plain-text characters should be kept at the start of the string :param secret_chars: How many * symbols should be used to hide the remainder of the password :return: Obfuscated string e.g. Pass**** """ + if not password: + return "" + password = encryptor.dec(password) return password[0:plain_chars] + '*' * secret_chars @staticmethod def censor_hash(hash_, plain_chars=5): """ - Obfuscates hash by only showing a part of it + Decrypts and obfuscates hash by only showing a part of it :param hash_: Hash to obfuscate :param plain_chars: How many chars of hash should be shown :return: Obfuscated string """ + if not hash_: + return "" + hash_ = encryptor.dec(hash_) return hash_[0: plain_chars] + ' ...' From 985d3ea1886086840f330061351b04de2fd2418f Mon Sep 17 00:00:00 2001 From: itay Date: Tue, 18 Jun 2019 12:19:29 +0300 Subject: [PATCH 12/27] rename telem_type to telem_catagory --- monkey/infection_monkey/control.py | 4 ++-- .../telemetry/attack/attack_telem.py | 2 +- .../telemetry/attack/test_victim_host_telem.py | 2 +- monkey/infection_monkey/telemetry/base_telem.py | 4 ++-- monkey/monkey_island/cc/resources/monkey.py | 4 ++-- monkey/monkey_island/cc/resources/telemetry.py | 16 ++++++++-------- .../monkey_island/cc/resources/telemetry_feed.py | 2 +- .../cc/services/attack/attack_report.py | 2 +- .../services/attack/technique_reports/T1197.py | 2 +- .../services/attack/technique_reports/T1210.py | 4 ++-- .../attack/technique_reports/__init__.py | 4 ++-- monkey/monkey_island/cc/services/report.py | 12 ++++++------ .../cc/ui/src/components/pages/TelemetryPage.js | 2 +- 13 files changed, 30 insertions(+), 30 deletions(-) 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/telemetry/attack/attack_telem.py b/monkey/infection_monkey/telemetry/attack/attack_telem.py index ab11adecc..efbedcaff 100644 --- a/monkey/infection_monkey/telemetry/attack/attack_telem.py +++ b/monkey/infection_monkey/telemetry/attack/attack_telem.py @@ -15,7 +15,7 @@ class AttackTelem(BaseTelem): self.technique = technique self.status = status - telem_type = 'attack' + telem_catagory = 'attack' def get_data(self): return { diff --git a/monkey/infection_monkey/telemetry/attack/test_victim_host_telem.py b/monkey/infection_monkey/telemetry/attack/test_victim_host_telem.py index 753236131..6b5bbcb73 100644 --- a/monkey/infection_monkey/telemetry/attack/test_victim_host_telem.py +++ b/monkey/infection_monkey/telemetry/attack/test_victim_host_telem.py @@ -13,7 +13,7 @@ class TestVictimHostTelem(TestCase): telem = VictimHostTelem(technique, status, machine) - self.assertEqual(telem.telem_type, 'attack') + self.assertEqual(telem.telem_catagory, 'attack') expected_data = { 'machine': { diff --git a/monkey/infection_monkey/telemetry/base_telem.py b/monkey/infection_monkey/telemetry/base_telem.py index d280ebfee..eaafc6aa8 100644 --- a/monkey/infection_monkey/telemetry/base_telem.py +++ b/monkey/infection_monkey/telemetry/base_telem.py @@ -19,10 +19,10 @@ class BaseTelem(object): """ Sends telemetry to island """ - ControlClient.send_telemetry(self.telem_type, self.get_data()) + ControlClient.send_telemetry(self.telem_catagory, self.get_data()) @abc.abstractproperty - def telem_type(self): + def telem_catagory(self): """ :return: Telemetry type """ 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 fd21104d1..87ca49906 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(',', '.') diff --git a/monkey/monkey_island/cc/resources/telemetry_feed.py b/monkey/monkey_island/cc/resources/telemetry_feed.py index de5ded887..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 diff --git a/monkey/monkey_island/cc/services/attack/attack_report.py b/monkey/monkey_island/cc/services/attack/attack_report.py index 0d0df38ca..58ba37008 100644 --- a/monkey/monkey_island/cc/services/attack/attack_report.py +++ b/monkey/monkey_island/cc/services/attack/attack_report.py @@ -41,7 +41,7 @@ class AttackReportService: Gets timestamp of latest attack telem :return: timestamp of latest attack telem """ - return [x['timestamp'] for x in mongo.db.telemetry.find({'telem_type': 'attack'}).sort('timestamp', -1).limit(1)][0] + return [x['timestamp'] for x in mongo.db.telemetry.find({'telem_catagory': 'attack'}).sort('timestamp', -1).limit(1)][0] @staticmethod def get_latest_report(): 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 dcad5bfd5..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,7 +13,7 @@ class T1197(AttackTechnique): @staticmethod def get_report_data(): data = T1197.get_tech_base_data(T1197) - bits_results = mongo.db.telemetry.aggregate([{'$match': {'telem_type': 'attack', 'data.technique': T1197.tech_id}}, + 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'}, 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 9d5ff4cfd..624656e1b 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1210.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1210.py @@ -35,7 +35,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'}, @@ -45,7 +45,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 d194fc221..5e9a98a55 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.telemetry.find_one({'telem_type': 'attack', 'data.status': ScanStatus.USED.value, 'data.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.telemetry.find_one({'telem_type': 'attack', 'data.status': ScanStatus.SCANNED.value, 'data.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 21dcea0bc..32d8e25f7 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%' } ]; From dc2755173d6416a6530aea343f271cbb1d4fd17c Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Tue, 18 Jun 2019 14:15:13 +0300 Subject: [PATCH 13/27] Refactored technique report basic data generation methods --- .../attack/technique_reports/__init__.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) 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 782ca389d..8d60e963f 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py @@ -62,12 +62,16 @@ class AttackTechnique(object): @staticmethod def get_message_and_status(technique, status): + return {'message': technique.get_message_by_status(technique, status), 'status': status.name} + + @staticmethod + def get_message_by_status(technique, status): if status == ScanStatus.UNSCANNED: - return {'message': technique.unscanned_msg, 'status': ScanStatus.UNSCANNED.name} + return technique.unscanned_msg elif status == ScanStatus.SCANNED: - return {'message': technique.scanned_msg, 'status': ScanStatus.SCANNED.name} + return technique.scanned_msg else: - return {'message': technique.used_msg, 'status': ScanStatus.USED.name} + return technique.used_msg @staticmethod def technique_title(technique): @@ -87,11 +91,7 @@ class AttackTechnique(object): data = {} status = AttackTechnique.technique_status(technique.tech_id) title = AttackTechnique.technique_title(technique.tech_id) - data.update({'status': status.name, 'title': title}) - if status == ScanStatus.UNSCANNED: - data.update({'message': technique.unscanned_msg}) - elif status == ScanStatus.SCANNED: - data.update({'message': technique.scanned_msg}) - else: - data.update({'message': technique.used_msg}) + data.update({'status': status.name, + 'title': title, + 'message': technique.get_message_by_status(technique, status)}) return data From 8505ad0ca80d1a4a19a2350e1bd209d4b6be0542 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Tue, 18 Jun 2019 16:36:37 +0300 Subject: [PATCH 14/27] Refactored AttackTechnique methods to use @classmethod and minor improvenets in UI --- .../attack/technique_reports/T1075.py | 8 +-- .../attack/technique_reports/T1110.py | 6 +- .../attack/technique_reports/T1197.py | 2 +- .../attack/technique_reports/__init__.py | 63 +++++++++++-------- .../components/attack/techniques/Helpers.js | 2 +- .../src/components/attack/techniques/T1075.js | 20 +++--- .../src/components/attack/techniques/T1110.js | 4 +- .../src/components/attack/techniques/T1197.js | 4 +- .../src/components/attack/techniques/T1210.js | 6 +- 9 files changed, 63 insertions(+), 52 deletions(-) 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 2ac3d5420..18082dfc1 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1075.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1075.py @@ -16,7 +16,7 @@ class T1075(AttackTechnique): {'lm_hash': {'$ne': ''}}]}}} # Gets data about successful PTH logins - query = [{'$match': {'telem_type': 'exploit', + query = [{'$match': {'telem_category': 'exploit', 'data.attempts': {'$not': {'$size': 0}, '$elemMatch': {'$and': [{'$or': [{'ntlm_hash': {'$ne': ''}}, {'lm_hash': {'$ne': ''}}]}, @@ -35,9 +35,9 @@ class T1075(AttackTechnique): successful_logins = list(mongo.db.telemetry.aggregate(T1075.query)) data.update({'successful_logins': successful_logins}) if successful_logins: - data.update({'message': T1075.used_msg, 'status': ScanStatus.USED.name}) + data.update(T1075.get_message_and_status(ScanStatus.USED)) elif mongo.db.telemetry.count_documents(T1075.login_attempt_query): - data.update({'message': T1075.scanned_msg, 'status': ScanStatus.SCANNED.name}) + data.update(T1075.get_message_and_status(ScanStatus.SCANNED)) else: - data.update({'message': T1075.unscanned_msg, 'status': ScanStatus.UNSCANNED.name}) + data.update(T1075.get_message_and_status(ScanStatus.UNSCANNED)) 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 7fe5ac90f..e8e4a62c3 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: - data = T1110.get_message_and_status(T1110, ScanStatus.USED) + data = T1110.get_message_and_status(ScanStatus.USED) elif attempts: - data = T1110.get_message_and_status(T1110, ScanStatus.SCANNED) + data = T1110.get_message_and_status(ScanStatus.SCANNED) else: - data = T1110.get_message_and_status(T1110, ScanStatus.UNSCANNED) + data = T1110.get_message_and_status(ScanStatus.UNSCANNED) # 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/T1197.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1197.py index 0aaab082b..11e79877b 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1197.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1197.py @@ -12,7 +12,7 @@ class T1197(AttackTechnique): @staticmethod def get_report_data(): - data = T1197.get_tech_base_data(T1197) + data = T1197.get_tech_base_data() 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'}, 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..f37f4e082 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py @@ -47,51 +47,60 @@ class AttackTechnique(object): pass @staticmethod - def technique_status(technique): + def technique_status(tech_id): """ Gets the status of a certain attack technique. - :param technique: technique's id. + :param tech_id: ID of attack technique, for e.g. T1110 :return: ScanStatus Enum object """ - if mongo.db.attack_results.find_one({'status': ScanStatus.USED.value, 'technique': technique}): + if mongo.db.attack_results.find_one({'status': ScanStatus.USED.value, 'technique': tech_id}): return ScanStatus.USED - elif mongo.db.attack_results.find_one({'status': ScanStatus.SCANNED.value, 'technique': technique}): + elif mongo.db.attack_results.find_one({'status': ScanStatus.SCANNED.value, 'technique': tech_id}): return ScanStatus.SCANNED else: return ScanStatus.UNSCANNED - @staticmethod - def get_message_and_status(technique, status): - return {'message': technique.get_message_by_status(technique, status), 'status': status.name} - - @staticmethod - def get_message_by_status(technique, status): - if status == ScanStatus.UNSCANNED: - return technique.unscanned_msg - elif status == ScanStatus.SCANNED: - return technique.scanned_msg - else: - return technique.used_msg - - @staticmethod - def technique_title(technique): + @classmethod + def get_message_and_status(cls, status): """ - :param technique: Technique's id. E.g. T1110 + Returns a dict with attack technique's message and status. + :param status: Enum type value from common/attack_utils.py + :return: Dict with message and status + """ + return {'message': cls.get_message_by_status(status), 'status': status.name} + + @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 + :return: message string + """ + if status == ScanStatus.UNSCANNED: + return cls.unscanned_msg + elif status == ScanStatus.SCANNED: + return cls.scanned_msg + else: + return cls.used_msg + + @staticmethod + def technique_title(tech_id): + """ + :param tech_id: Technique's id. E.g. T1110 :return: techniques title. E.g. "T1110 Brute force" """ - return AttackConfig.get_technique(technique)['title'] + return AttackConfig.get_technique(tech_id)['title'] - @staticmethod - def get_tech_base_data(technique): + @classmethod + def get_tech_base_data(cls): """ Gathers basic attack technique data into a dict. - :param technique: Technique's id. E.g. T1110 :return: dict E.g. {'message': 'Brute force used', 'status': 'Used', 'title': 'T1110 Brute force'} """ data = {} - status = AttackTechnique.technique_status(technique.tech_id) - title = AttackTechnique.technique_title(technique.tech_id) + status = AttackTechnique.technique_status(cls.tech_id) + title = AttackTechnique.technique_title(cls.tech_id) data.update({'status': status.name, 'title': title, - 'message': technique.get_message_by_status(technique, status)}) + 'message': cls.get_message_by_status(status)}) return data 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 b15bba693..785e4a295 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 @@ -1,6 +1,6 @@ import React from "react"; -export function RenderMachine(val){ +export function renderMachine(val){ return ( {val.ip_addr} {(val.domain_name ? " (".concat(val.domain_name, ")") : "")} ) diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1075.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1075.js index 6e80c9196..35fd0cbaa 100644 --- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1075.js +++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1075.js @@ -1,26 +1,28 @@ import React from 'react'; import '../../../styles/Collapse.scss' import ReactTable from "react-table"; -import { RenderMachine } from "./Helpers" +import { renderMachine } from "./Helpers" class T1075 extends React.Component { constructor(props) { super(props); - this.props.data.successful_logins.forEach((login) => { - if(login.attempts[0].ntlm_hash !== ""){ - login.attempts[0].hashType = 'NTLM'; - } else if(login.attempts[0].lm_hash !== ""){ - login.attempts[0].hashType = 'LM'; - } - }) + this.props.data.successful_logins.forEach((login) => this.setLoginHashType(login)) + } + + setLoginHashType(login){ + if(login.attempts[0].ntlm_hash !== ""){ + login.attempts[0].hashType = 'NTLM'; + } else if(login.attempts[0].lm_hash !== ""){ + login.attempts[0].hashType = 'LM'; + } } static getHashColumns() { return ([{ columns: [ - {Header: 'Machine', id: 'machine', accessor: x => RenderMachine(x.machine), style: { 'whiteSpace': 'unset' }}, + {Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.machine), style: { 'whiteSpace': 'unset' }}, {Header: 'Service', id: 'service', accessor: x => x.info.display_name, style: { 'whiteSpace': 'unset' }}, {Header: 'Username', id: 'attempts', accessor: x => x.attempts[0].user, style: { 'whiteSpace': 'unset' }}, {Header: 'Hash type', id: 'credentials', accessor: x => x.attempts[0].hashType, style: { 'whiteSpace': 'unset' }}, diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1110.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1110.js index 468a9e79a..294606d25 100644 --- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1110.js +++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1110.js @@ -1,7 +1,7 @@ import React from 'react'; import '../../../styles/Collapse.scss' import ReactTable from "react-table"; -import { RenderMachine } from "./Helpers" +import { renderMachine } from "./Helpers" class T1110 extends React.Component { @@ -13,7 +13,7 @@ class T1110 extends React.Component { static getServiceColumns() { return ([{ columns: [ - {Header: 'Machine', id: 'machine', accessor: x => RenderMachine(x.machine), + {Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.machine), style: { 'whiteSpace': 'unset' }, width: 160}, {Header: 'Service', id: 'service', accessor: x => x.info.display_name, style: { 'whiteSpace': 'unset' }, width: 100}, {Header: 'Started', id: 'started', accessor: x => x.info.started, style: { 'whiteSpace': 'unset' }}, diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1197.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1197.js index e4c7d841d..8dc655aee 100644 --- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1197.js +++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1197.js @@ -1,7 +1,7 @@ import React from 'react'; import '../../../styles/Collapse.scss' import ReactTable from "react-table"; -import { RenderMachine } from "./Helpers" +import { renderMachine } from "./Helpers" class T1210 extends React.Component { @@ -9,7 +9,7 @@ class T1210 extends React.Component { constructor(props) { super(props); this.columns = [ {Header: 'Machine', - id: 'machine', accessor: x => RenderMachine(x), + id: 'machine', accessor: x => renderMachine(x), style: { 'whiteSpace': 'unset' }, width: 200}, {Header: 'Time', diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1210.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1210.js index 76bc5d196..1b3daa86c 100644 --- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1210.js +++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1210.js @@ -1,7 +1,7 @@ import React from 'react'; import '../../../styles/Collapse.scss' import ReactTable from "react-table"; -import { RenderMachine } from "./Helpers" +import { renderMachine } from "./Helpers" class T1210 extends React.Component { @@ -13,7 +13,7 @@ class T1210 extends React.Component { static getScanColumns() { return ([{ columns: [ - {Header: 'Machine', id: 'machine', accessor: x => RenderMachine(x.machine), + {Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.machine), style: { 'whiteSpace': 'unset' }, width: 200}, {Header: 'Time', id: 'time', accessor: x => x.time, style: { 'whiteSpace': 'unset' }, width: 170}, {Header: 'Port', id: 'port', accessor: x =>x.service.port, style: { 'whiteSpace': 'unset' }}, @@ -24,7 +24,7 @@ class T1210 extends React.Component { static getExploitColumns() { return ([{ columns: [ - {Header: 'Machine', id: 'machine', accessor: x => RenderMachine(x.machine), + {Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.machine), style: { 'whiteSpace': 'unset' }, width: 200}, {Header: 'Time', id: 'time', accessor: x => x.time, style: { 'whiteSpace': 'unset' }, width: 170}, {Header: 'Port/url', id: 'port', accessor: x =>this.renderEndpoint(x.service), style: { 'whiteSpace': 'unset' }}, From c2a00daed6442728454bb79e5d00499dff3f9f3d Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Wed, 19 Jun 2019 09:22:29 +0300 Subject: [PATCH 15/27] HTTP servers bugfix --- monkey/infection_monkey/transport/http.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/monkey/infection_monkey/transport/http.py b/monkey/infection_monkey/transport/http.py index e54445d52..0f01cf64a 100644 --- a/monkey/infection_monkey/transport/http.py +++ b/monkey/infection_monkey/transport/http.py @@ -49,7 +49,8 @@ class FileServHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): start_range += chunk if f.tell() == monkeyfs.getsize(self.filename): - self.report_download(self.client_address) + if self.report_download(self.client_address): + self.close_connection = 1 f.close() @@ -171,7 +172,8 @@ class HTTPServer(threading.Thread): LOG.info('File downloaded from (%s,%s)' % (dest[0], dest[1])) self.downloads += 1 if not self.downloads < self.max_downloads: - self.close_connection = 1 + return True + return False httpd = BaseHTTPServer.HTTPServer((self._local_ip, self._local_port), TempHandler) httpd.timeout = 0.5 # this is irrelevant? @@ -217,7 +219,8 @@ class LockedHTTPServer(threading.Thread): LOG.info('File downloaded from (%s,%s)' % (dest[0], dest[1])) self.downloads += 1 if not self.downloads < self.max_downloads: - self.close_connection = 1 + return True + return False httpd = BaseHTTPServer.HTTPServer((self._local_ip, self._local_port), TempHandler) self.lock.release() From eded13f610f39b4248bf576f2004ae9de0dda873 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Wed, 19 Jun 2019 10:38:59 +0300 Subject: [PATCH 16/27] Refactored HostExploiter to have pre_exploit and post_exploit methods --- monkey/infection_monkey/exploit/__init__.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/monkey/infection_monkey/exploit/__init__.py b/monkey/infection_monkey/exploit/__init__.py index 661433b97..126b3f579 100644 --- a/monkey/infection_monkey/exploit/__init__.py +++ b/monkey/infection_monkey/exploit/__init__.py @@ -49,8 +49,14 @@ class HostExploiter(object): 'lm_hash': lm_hash, 'ntlm_hash': ntlm_hash, 'ssh_key': ssh_key}) def exploit_host(self): - self.set_start_time() + self.pre_exploit() self._exploit_host() + self.post_exploit() + + def pre_exploit(self): + self.set_start_time() + + def post_exploit(self): self.set_finish_time() @abstractmethod From ab4bbd437f6592c4461a8fe6d71db85a3045036f Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Wed, 19 Jun 2019 11:54:58 +0300 Subject: [PATCH 17/27] Readability improvements --- .../attack/technique_reports/T1075.py | 7 ++++--- .../attack/technique_reports/T1110.py | 8 ++++---- .../attack/technique_reports/T1210.py | 7 ++++--- .../attack/technique_reports/__init__.py | 20 +++++++++---------- 4 files changed, 21 insertions(+), 21 deletions(-) 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 18082dfc1..09eee9d44 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1075.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1075.py @@ -35,9 +35,10 @@ class T1075(AttackTechnique): successful_logins = list(mongo.db.telemetry.aggregate(T1075.query)) data.update({'successful_logins': successful_logins}) if successful_logins: - data.update(T1075.get_message_and_status(ScanStatus.USED)) + status = ScanStatus.USED elif mongo.db.telemetry.count_documents(T1075.login_attempt_query): - data.update(T1075.get_message_and_status(ScanStatus.SCANNED)) + status = ScanStatus.SCANNED else: - data.update(T1075.get_message_and_status(ScanStatus.UNSCANNED)) + status = ScanStatus.UNSCANNED + data.update(T1075.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 e8e4a62c3..fe236f487 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py @@ -35,12 +35,12 @@ class T1110(AttackTechnique): result['successful_creds'].append(T1110.parse_creds(attempt)) if succeeded: - data = T1110.get_message_and_status(ScanStatus.USED) + status = ScanStatus.USED elif attempts: - data = T1110.get_message_and_status(ScanStatus.SCANNED) + status = ScanStatus.SCANNED else: - data = T1110.get_message_and_status(ScanStatus.UNSCANNED) - + status = ScanStatus.UNSCANNED + data = T1110.get_message_and_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/T1210.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1210.py index 677495c10..ff5d1caa0 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,12 @@ class T1210(AttackTechnique): scanned_services = T1210.get_scanned_services() exploited_services = T1210.get_exploited_services() if exploited_services: - data.update({'status': ScanStatus.USED.name, 'message': T1210.used_msg}) + status = ScanStatus.USED elif scanned_services: - data.update({'status': ScanStatus.SCANNED.name, 'message': T1210.scanned_msg}) + status = ScanStatus.SCANNED else: - data.update({'status': ScanStatus.UNSCANNED.name, 'message': T1210.unscanned_msg}) + status = ScanStatus.UNSCANNED.name + 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 7faaf5afd..fe2beb424 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py @@ -46,20 +46,19 @@ class AttackTechnique(object): """ pass - @staticmethod - def technique_status(tech_id): + @classmethod + def technique_status(cls): """ Gets the status of a certain attack technique. - :param tech_id: ID of attack technique, for e.g. T1110 :return: ScanStatus Enum object """ if mongo.db.attack_results.find_one({'telem_catagory': 'attack', 'status': ScanStatus.USED.value, - 'technique': tech_id}): + 'technique': cls.tech_id}): return ScanStatus.USED elif mongo.db.attack_results.find_one({'telem_catagory': 'attack', 'status': ScanStatus.SCANNED.value, - 'technique': tech_id}): + 'technique': cls.tech_id}): return ScanStatus.SCANNED else: return ScanStatus.UNSCANNED @@ -87,13 +86,12 @@ class AttackTechnique(object): else: return cls.used_msg - @staticmethod - def technique_title(tech_id): + @classmethod + def technique_title(cls): """ - :param tech_id: Technique's id. E.g. T1110 :return: techniques title. E.g. "T1110 Brute force" """ - return AttackConfig.get_technique(tech_id)['title'] + return AttackConfig.get_technique(cls.tech_id)['title'] @classmethod def get_tech_base_data(cls): @@ -102,8 +100,8 @@ class AttackTechnique(object): :return: dict E.g. {'message': 'Brute force used', 'status': 'Used', 'title': 'T1110 Brute force'} """ data = {} - status = AttackTechnique.technique_status(cls.tech_id) - title = AttackTechnique.technique_title(cls.tech_id) + status = cls.technique_status() + title = cls.technique_title() data.update({'status': status.name, 'title': title, 'message': cls.get_message_by_status(status)}) From b3c6baf214d3fb124d0420c9d217957fb905b102 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Wed, 19 Jun 2019 11:54:58 +0300 Subject: [PATCH 18/27] Readability improvements --- .../attack/technique_reports/T1075.py | 9 +++++---- .../attack/technique_reports/T1110.py | 10 +++++----- .../attack/technique_reports/T1210.py | 9 +++++---- .../attack/technique_reports/__init__.py | 20 +++++++++---------- 4 files changed, 24 insertions(+), 24 deletions(-) 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 18082dfc1..fa65a66c2 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1075.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1075.py @@ -31,13 +31,14 @@ class T1075(AttackTechnique): @staticmethod def get_report_data(): - data = {'title': T1075.technique_title(T1075.tech_id)} + data = {'title': T1075.technique_title()} successful_logins = list(mongo.db.telemetry.aggregate(T1075.query)) data.update({'successful_logins': successful_logins}) if successful_logins: - data.update(T1075.get_message_and_status(ScanStatus.USED)) + status = ScanStatus.USED elif mongo.db.telemetry.count_documents(T1075.login_attempt_query): - data.update(T1075.get_message_and_status(ScanStatus.SCANNED)) + status = ScanStatus.SCANNED else: - data.update(T1075.get_message_and_status(ScanStatus.UNSCANNED)) + status = ScanStatus.UNSCANNED + data.update(T1075.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 e8e4a62c3..0f09fb0fe 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py @@ -35,16 +35,16 @@ class T1110(AttackTechnique): result['successful_creds'].append(T1110.parse_creds(attempt)) if succeeded: - data = T1110.get_message_and_status(ScanStatus.USED) + status = ScanStatus.USED elif attempts: - data = T1110.get_message_and_status(ScanStatus.SCANNED) + status = ScanStatus.SCANNED else: - data = T1110.get_message_and_status(ScanStatus.UNSCANNED) - + status = ScanStatus.UNSCANNED + data = T1110.get_message_and_status(status) # Remove data with no successful brute force attempts attempts = [attempt for attempt in attempts if attempt['attempts']] - data.update({'services': attempts, 'title': T1110.technique_title(T1110.tech_id)}) + data.update({'services': attempts, 'title': T1110.technique_title()}) return data @staticmethod 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 677495c10..08019699b 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1210.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1210.py @@ -14,15 +14,16 @@ class T1210(AttackTechnique): @staticmethod def get_report_data(): - data = {'title': T1210.technique_title(T1210.tech_id)} + data = {'title': T1210.technique_title()} scanned_services = T1210.get_scanned_services() exploited_services = T1210.get_exploited_services() if exploited_services: - data.update({'status': ScanStatus.USED.name, 'message': T1210.used_msg}) + status = ScanStatus.USED elif scanned_services: - data.update({'status': ScanStatus.SCANNED.name, 'message': T1210.scanned_msg}) + status = ScanStatus.SCANNED else: - data.update({'status': ScanStatus.UNSCANNED.name, 'message': T1210.unscanned_msg}) + status = ScanStatus.UNSCANNED.name + 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 7faaf5afd..fe2beb424 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py @@ -46,20 +46,19 @@ class AttackTechnique(object): """ pass - @staticmethod - def technique_status(tech_id): + @classmethod + def technique_status(cls): """ Gets the status of a certain attack technique. - :param tech_id: ID of attack technique, for e.g. T1110 :return: ScanStatus Enum object """ if mongo.db.attack_results.find_one({'telem_catagory': 'attack', 'status': ScanStatus.USED.value, - 'technique': tech_id}): + 'technique': cls.tech_id}): return ScanStatus.USED elif mongo.db.attack_results.find_one({'telem_catagory': 'attack', 'status': ScanStatus.SCANNED.value, - 'technique': tech_id}): + 'technique': cls.tech_id}): return ScanStatus.SCANNED else: return ScanStatus.UNSCANNED @@ -87,13 +86,12 @@ class AttackTechnique(object): else: return cls.used_msg - @staticmethod - def technique_title(tech_id): + @classmethod + def technique_title(cls): """ - :param tech_id: Technique's id. E.g. T1110 :return: techniques title. E.g. "T1110 Brute force" """ - return AttackConfig.get_technique(tech_id)['title'] + return AttackConfig.get_technique(cls.tech_id)['title'] @classmethod def get_tech_base_data(cls): @@ -102,8 +100,8 @@ class AttackTechnique(object): :return: dict E.g. {'message': 'Brute force used', 'status': 'Used', 'title': 'T1110 Brute force'} """ data = {} - status = AttackTechnique.technique_status(cls.tech_id) - title = AttackTechnique.technique_title(cls.tech_id) + status = cls.technique_status() + title = cls.technique_title() data.update({'status': status.name, 'title': title, 'message': cls.get_message_by_status(status)}) From 7c01aab58c6245056ea98bb8ad8d94de592d2222 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Wed, 19 Jun 2019 12:43:44 +0300 Subject: [PATCH 19/27] CR improvements --- .../cc/services/attack/technique_reports/T1003.py | 7 ++++--- .../cc/services/attack/technique_reports/T1059.py | 7 ++++--- .../cc/ui/src/components/attack/techniques/T1059.js | 4 ++-- 3 files changed, 10 insertions(+), 8 deletions(-) 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 002e2eeb7..abe1963f3 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py @@ -17,9 +17,10 @@ class T1003(AttackTechnique): @staticmethod def get_report_data(): - data = {'title': T1003.technique_title(T1003.tech_id)} + data = {'title': T1003.technique_title()} if mongo.db.telemetry.count_documents(T1003.query): - data.update({'message': T1003.used_msg, 'status': ScanStatus.USED.name}) + status = ScanStatus.USED else: - data.update({'message': T1003.unscanned_msg, 'status': ScanStatus.UNSCANNED.name}) + status = ScanStatus.UNSCANNED + data.update(T1003.get_message_and_status(status)) 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 e85e27415..6f126b175 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py @@ -22,9 +22,10 @@ class T1059(AttackTechnique): @staticmethod def get_report_data(): cmd_data = list(mongo.db.telemetry.aggregate(T1059.query)) - data = {'title': T1059.technique_title(T1059.tech_id), 'cmds': cmd_data} + data = {'title': T1059.technique_title(), 'cmds': cmd_data} if cmd_data: - data.update({'message': T1059.used_msg, 'status': ScanStatus.USED.name}) + status = ScanStatus.USED else: - data.update({'message': T1059.unscanned_msg, 'status': ScanStatus.UNSCANNED.name}) + status = ScanStatus.UNSCANNED + data.update(T1059.get_message_and_status(status)) return data diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js index d1c809651..5678b8c14 100644 --- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js +++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js @@ -10,7 +10,7 @@ class T1059 extends React.Component { super(props); } - static getHashColumns() { + static getCommandColumns() { return ([{ Header: 'Example commands used', columns: [ @@ -27,7 +27,7 @@ class T1059 extends React.Component {
{this.props.data.status === 'USED' ? Date: Wed, 19 Jun 2019 12:43:44 +0300 Subject: [PATCH 20/27] CR improvements --- monkey/infection_monkey/exploit/__init__.py | 2 +- monkey/infection_monkey/exploit/hadoop.py | 2 +- monkey/infection_monkey/exploit/mssqlexec.py | 2 +- monkey/infection_monkey/exploit/rdpgrinder.py | 2 +- monkey/infection_monkey/exploit/shellshock.py | 2 +- monkey/infection_monkey/exploit/sshexec.py | 2 +- monkey/infection_monkey/exploit/vsftpd.py | 2 +- monkey/infection_monkey/exploit/web_rce.py | 4 ++-- monkey/infection_monkey/exploit/wmiexec.py | 2 +- .../cc/services/attack/technique_reports/T1003.py | 9 +++++---- .../cc/services/attack/technique_reports/T1059.py | 7 ++++--- .../cc/ui/src/components/attack/techniques/T1059.js | 4 ++-- 12 files changed, 21 insertions(+), 19 deletions(-) diff --git a/monkey/infection_monkey/exploit/__init__.py b/monkey/infection_monkey/exploit/__init__.py index 7cf1ac4cf..962240665 100644 --- a/monkey/infection_monkey/exploit/__init__.py +++ b/monkey/infection_monkey/exploit/__init__.py @@ -59,7 +59,7 @@ class HostExploiter(object): def add_vuln_port(self, port): self._exploit_info['vulnerable_ports'].append(port) - def add_example_cmd(self, cmd): + def set_example_cmd(self, cmd): self._exploit_info['executed_cmds']['example'] = cmd diff --git a/monkey/infection_monkey/exploit/hadoop.py b/monkey/infection_monkey/exploit/hadoop.py index 570575423..39edf0262 100644 --- a/monkey/infection_monkey/exploit/hadoop.py +++ b/monkey/infection_monkey/exploit/hadoop.py @@ -49,7 +49,7 @@ class HadoopExploiter(WebRCE): return False http_thread.join(self.DOWNLOAD_TIMEOUT) http_thread.stop() - self.add_example_cmd(command) + self.set_example_cmd(command) return True def exploit(self, url, command): diff --git a/monkey/infection_monkey/exploit/mssqlexec.py b/monkey/infection_monkey/exploit/mssqlexec.py index 1bf7f90d5..c1409ec6c 100644 --- a/monkey/infection_monkey/exploit/mssqlexec.py +++ b/monkey/infection_monkey/exploit/mssqlexec.py @@ -77,7 +77,7 @@ class MSSQLExploiter(HostExploiter): commands.extend(monkey_args) MSSQLExploiter.execute_command(cursor, commands) MSSQLExploiter.run_file(cursor, tmp_file_path) - self.add_example_cmd(commands[-1]) + self.set_example_cmd(commands[-1]) return True @staticmethod diff --git a/monkey/infection_monkey/exploit/rdpgrinder.py b/monkey/infection_monkey/exploit/rdpgrinder.py index 819ff00fb..828b03c20 100644 --- a/monkey/infection_monkey/exploit/rdpgrinder.py +++ b/monkey/infection_monkey/exploit/rdpgrinder.py @@ -343,5 +343,5 @@ class RdpExploiter(HostExploiter): LOG.info("Executed monkey '%s' on remote victim %r", os.path.basename(src_path), self.host) - self.add_example_cmd(command) + self.set_example_cmd(command) return True diff --git a/monkey/infection_monkey/exploit/shellshock.py b/monkey/infection_monkey/exploit/shellshock.py index 9db770905..26e9a743b 100644 --- a/monkey/infection_monkey/exploit/shellshock.py +++ b/monkey/infection_monkey/exploit/shellshock.py @@ -144,7 +144,7 @@ class ShellShockExploiter(HostExploiter): if not (self.check_remote_file_exists(url, header, exploit, self._config.monkey_log_path_linux)): LOG.info("Log file does not exist, monkey might not have run") continue - self.add_example_cmd(cmdline) + self.set_example_cmd(cmdline) return True return False diff --git a/monkey/infection_monkey/exploit/sshexec.py b/monkey/infection_monkey/exploit/sshexec.py index 226ad8943..e65d3cb19 100644 --- a/monkey/infection_monkey/exploit/sshexec.py +++ b/monkey/infection_monkey/exploit/sshexec.py @@ -178,7 +178,7 @@ class SSHExploiter(HostExploiter): self._config.dropper_target_path_linux, self.host, cmdline) ssh.close() - self.add_example_cmd(cmdline) + self.set_example_cmd(cmdline) return True except Exception as exc: diff --git a/monkey/infection_monkey/exploit/vsftpd.py b/monkey/infection_monkey/exploit/vsftpd.py index f3f13c073..eddac620c 100644 --- a/monkey/infection_monkey/exploit/vsftpd.py +++ b/monkey/infection_monkey/exploit/vsftpd.py @@ -138,7 +138,7 @@ class VSFTPDExploiter(HostExploiter): if backdoor_socket.send(run_monkey): LOG.info("Executed monkey '%s' on remote victim %r (cmdline=%r)", self._config.dropper_target_path_linux, self.host, run_monkey) - self.add_example_cmd(run_monkey) + self.set_example_cmd(run_monkey) return True else: return False diff --git a/monkey/infection_monkey/exploit/web_rce.py b/monkey/infection_monkey/exploit/web_rce.py index 43c1b5749..351eb7c17 100644 --- a/monkey/infection_monkey/exploit/web_rce.py +++ b/monkey/infection_monkey/exploit/web_rce.py @@ -408,7 +408,7 @@ class WebRCE(HostExploiter): # If exploiter returns True / False if type(resp) is bool: LOG.info("Execution attempt successfully finished") - self.add_example_cmd(command) + self.set_example_cmd(command) return resp # If exploiter returns command output, we can check for execution errors if 'is not recognized' in resp or 'command not found' in resp: @@ -422,7 +422,7 @@ class WebRCE(HostExploiter): return False LOG.info("Execution attempt finished") - self.add_example_cmd(command) + self.set_example_cmd(command) return resp def get_monkey_upload_path(self, url_to_monkey): diff --git a/monkey/infection_monkey/exploit/wmiexec.py b/monkey/infection_monkey/exploit/wmiexec.py index b9decf433..648fb233d 100644 --- a/monkey/infection_monkey/exploit/wmiexec.py +++ b/monkey/infection_monkey/exploit/wmiexec.py @@ -114,7 +114,7 @@ class WmiExploiter(HostExploiter): result.RemRelease() wmi_connection.close() - self.add_example_cmd(cmdline) + self.set_example_cmd(cmdline) return success return False 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 002e2eeb7..d30197e9a 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py @@ -9,7 +9,7 @@ class T1003(AttackTechnique): tech_id = "T1003" unscanned_msg = "Monkey tried to obtain credentials from systems in the network but didn't find any or failed." - scanned_msg = "Monkey tried to obtain credentials from systems in the network but didn't find any or failed." + scanned_msg = "" used_msg = "Monkey successfully obtained some credentials from systems on the network." query = {'telem_type': 'system_info_collection', '$and': [{'data.credentials': {'$exists': True}}, @@ -17,9 +17,10 @@ class T1003(AttackTechnique): @staticmethod def get_report_data(): - data = {'title': T1003.technique_title(T1003.tech_id)} + data = {'title': T1003.technique_title()} if mongo.db.telemetry.count_documents(T1003.query): - data.update({'message': T1003.used_msg, 'status': ScanStatus.USED.name}) + status = ScanStatus.USED else: - data.update({'message': T1003.unscanned_msg, 'status': ScanStatus.UNSCANNED.name}) + status = ScanStatus.UNSCANNED + data.update(T1003.get_message_and_status(status)) 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 e85e27415..6f126b175 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py @@ -22,9 +22,10 @@ class T1059(AttackTechnique): @staticmethod def get_report_data(): cmd_data = list(mongo.db.telemetry.aggregate(T1059.query)) - data = {'title': T1059.technique_title(T1059.tech_id), 'cmds': cmd_data} + data = {'title': T1059.technique_title(), 'cmds': cmd_data} if cmd_data: - data.update({'message': T1059.used_msg, 'status': ScanStatus.USED.name}) + status = ScanStatus.USED else: - data.update({'message': T1059.unscanned_msg, 'status': ScanStatus.UNSCANNED.name}) + status = ScanStatus.UNSCANNED + data.update(T1059.get_message_and_status(status)) return data diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js index d1c809651..5678b8c14 100644 --- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js +++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js @@ -10,7 +10,7 @@ class T1059 extends React.Component { super(props); } - static getHashColumns() { + static getCommandColumns() { return ([{ Header: 'Example commands used', columns: [ @@ -27,7 +27,7 @@ class T1059 extends React.Component {
{this.props.data.status === 'USED' ? Date: Sun, 23 Jun 2019 14:07:48 +0300 Subject: [PATCH 21/27] fix variable type 'catagory' -> 'category' --- monkey/infection_monkey/control.py | 4 ++-- .../telemetry/attack/attack_telem.py | 2 +- .../telemetry/attack/test_victim_host_telem.py | 2 +- monkey/infection_monkey/telemetry/base_telem.py | 4 ++-- monkey/monkey_island/cc/resources/monkey.py | 4 ++-- monkey/monkey_island/cc/resources/telemetry.py | 16 ++++++++-------- .../monkey_island/cc/resources/telemetry_feed.py | 2 +- .../cc/services/attack/attack_report.py | 2 +- .../services/attack/technique_reports/T1197.py | 2 +- .../services/attack/technique_reports/T1210.py | 4 ++-- .../attack/technique_reports/__init__.py | 4 ++-- monkey/monkey_island/cc/services/report.py | 12 ++++++------ 12 files changed, 29 insertions(+), 29 deletions(-) diff --git a/monkey/infection_monkey/control.py b/monkey/infection_monkey/control.py index 6ce94451d..f34784041 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_catagory, data): + def send_telemetry(telem_category, data): if not WormConfiguration.current_server: return try: - telemetry = {'monkey_guid': GUID, 'telem_catagory': telem_catagory, 'data': data} + telemetry = {'monkey_guid': GUID, 'telem_category': telem_category, '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/telemetry/attack/attack_telem.py b/monkey/infection_monkey/telemetry/attack/attack_telem.py index efbedcaff..893f4492a 100644 --- a/monkey/infection_monkey/telemetry/attack/attack_telem.py +++ b/monkey/infection_monkey/telemetry/attack/attack_telem.py @@ -15,7 +15,7 @@ class AttackTelem(BaseTelem): self.technique = technique self.status = status - telem_catagory = 'attack' + telem_category = 'attack' def get_data(self): return { diff --git a/monkey/infection_monkey/telemetry/attack/test_victim_host_telem.py b/monkey/infection_monkey/telemetry/attack/test_victim_host_telem.py index 6b5bbcb73..2ccab7483 100644 --- a/monkey/infection_monkey/telemetry/attack/test_victim_host_telem.py +++ b/monkey/infection_monkey/telemetry/attack/test_victim_host_telem.py @@ -13,7 +13,7 @@ class TestVictimHostTelem(TestCase): telem = VictimHostTelem(technique, status, machine) - self.assertEqual(telem.telem_catagory, 'attack') + self.assertEqual(telem.telem_category, 'attack') expected_data = { 'machine': { diff --git a/monkey/infection_monkey/telemetry/base_telem.py b/monkey/infection_monkey/telemetry/base_telem.py index eaafc6aa8..c232ab975 100644 --- a/monkey/infection_monkey/telemetry/base_telem.py +++ b/monkey/infection_monkey/telemetry/base_telem.py @@ -19,10 +19,10 @@ class BaseTelem(object): """ Sends telemetry to island """ - ControlClient.send_telemetry(self.telem_catagory, self.get_data()) + ControlClient.send_telemetry(self.telem_category, self.get_data()) @abc.abstractproperty - def telem_catagory(self): + def telem_category(self): """ :return: Telemetry type """ diff --git a/monkey/monkey_island/cc/resources/monkey.py b/monkey/monkey_island/cc/resources/monkey.py index 9a96abe3b..36720e465 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_catagory': {'$eq': 'exploit'}, 'data.result': {'$eq': True}, + mongo.db.telemetry.find({'telem_category': {'$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_catagory': {'$eq': 'exploit'}, 'data.result': {'$eq': True}, + mongo.db.telemetry.find({'telem_category': {'$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 69b6bcdd4..e69c5d6b0 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_catagory = request.args.get('telem_catagory') + telem_category = request.args.get('telem_category') 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_catagory: - find_filter["telem_catagory"] = {'$eq': telem_catagory} + if telem_category: + find_filter["telem_category"] = {'$eq': telem_category} 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_catagory = telemetry_json.get('telem_catagory') - if telem_catagory in TELEM_PROCESS_DICT: - TELEM_PROCESS_DICT[telem_catagory](telemetry_json) + telem_category = telemetry_json.get('telem_category') + if telem_category in TELEM_PROCESS_DICT: + TELEM_PROCESS_DICT[telem_category](telemetry_json) else: - logger.info('Got unknown type of telemetry: %s' % telem_catagory) + logger.info('Got unknown type of telemetry: %s' % telem_category) 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_catagory'] == 'system_info_collection' and 'credentials' in x['data']: + if x['telem_category'] == 'system_info_collection' and 'credentials' in x['data']: for user in x['data']['credentials']: if -1 != user.find(','): new_user = user.replace(',', '.') diff --git a/monkey/monkey_island/cc/resources/telemetry_feed.py b/monkey/monkey_island/cc/resources/telemetry_feed.py index 57a655297..b98d650c8 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_catagory']](telem) + 'brief': TELEM_PROCESS_DICT[telem['telem_category']](telem) } @staticmethod diff --git a/monkey/monkey_island/cc/services/attack/attack_report.py b/monkey/monkey_island/cc/services/attack/attack_report.py index 314a2e4df..95136b946 100644 --- a/monkey/monkey_island/cc/services/attack/attack_report.py +++ b/monkey/monkey_island/cc/services/attack/attack_report.py @@ -42,7 +42,7 @@ class AttackReportService: 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] + return [x['timestamp'] for x in mongo.db.telemetry.find({'telem_category': 'attack'}).sort('timestamp', -1).limit(1)][0] @staticmethod def get_latest_report(): 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 7146fde8b..a4546f31c 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1197.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1197.py @@ -13,7 +13,7 @@ class T1197(AttackTechnique): @staticmethod def get_report_data(): data = T1197.get_tech_base_data(T1197) - bits_results = mongo.db.telemetry.aggregate([{'$match': {'telem_catagory': 'attack', 'data.technique': T1197.tech_id}}, + bits_results = mongo.db.telemetry.aggregate([{'$match': {'telem_category': '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'}, 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 677495c10..e8d0a64d4 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_catagory': 'scan'}}, + results = mongo.db.telemetry.aggregate([{'$match': {'telem_category': '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_catagory': 'exploit', 'data.result': True}}, + results = mongo.db.telemetry.aggregate([{'$match': {'telem_category': '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 1990b61e7..7a14f9da8 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.telemetry.find_one({'telem_catagory': 'attack', 'data.status': ScanStatus.USED.value, 'data.technique': technique}): + if mongo.db.telemetry.find_one({'telem_category': 'attack', 'data.status': ScanStatus.USED.value, 'data.technique': technique}): return ScanStatus.USED - elif mongo.db.telemetry.find_one({'telem_catagory': 'attack', 'data.status': ScanStatus.SCANNED.value, 'data.technique': technique}): + elif mongo.db.telemetry.find_one({'telem_category': '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 2cd0e82fa..2a1a58d2e 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_catagory': 'system_info_collection', 'data.credentials': {'$exists': True}}, + {'telem_category': '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_catagory': 'system_info_collection', 'data.ssh_info': {'$exists': True}}, + {'telem_category': '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_catagory': 'system_info_collection', 'data.Azure': {'$exists': True}}, + {'telem_category': '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_catagory': 'exploit', 'data.result': True}): + for exploit in mongo.db.telemetry.find({'telem_category': '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_catagory': 'system_info_collection', 'monkey_guid': monkey_guid}, + {'telem_category': '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_catagory': 'scan'}, + scans = mongo.db.telemetry.find({'telem_category': 'scan'}, {'monkey_guid': 1, 'data.machine.ip_addr': 1, 'data.machine.services': 1}) cross_segment_issues = [] From 78b8ef4bd331676f854a3941f3b60d88cbc0d430 Mon Sep 17 00:00:00 2001 From: itay Date: Sun, 23 Jun 2019 14:45:36 +0300 Subject: [PATCH 22/27] exploit_host returns '_exploit_host''s return value --- monkey/infection_monkey/exploit/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/monkey/infection_monkey/exploit/__init__.py b/monkey/infection_monkey/exploit/__init__.py index 126b3f579..6aa77733c 100644 --- a/monkey/infection_monkey/exploit/__init__.py +++ b/monkey/infection_monkey/exploit/__init__.py @@ -50,8 +50,9 @@ class HostExploiter(object): def exploit_host(self): self.pre_exploit() - self._exploit_host() + result = self._exploit_host() self.post_exploit() + return result def pre_exploit(self): self.set_start_time() From c4c53f732af9af3130398c9d17118aa4ca7b7039 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Tue, 25 Jun 2019 08:36:21 +0300 Subject: [PATCH 23/27] powershell command storage refactor --- monkey/infection_monkey/exploit/__init__.py | 5 ++--- .../cc/services/attack/technique_reports/T1086.py | 9 +++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/monkey/infection_monkey/exploit/__init__.py b/monkey/infection_monkey/exploit/__init__.py index 0a445b7ed..611599970 100644 --- a/monkey/infection_monkey/exploit/__init__.py +++ b/monkey/infection_monkey/exploit/__init__.py @@ -60,7 +60,8 @@ class HostExploiter(object): self._exploit_info['vulnerable_ports'].append(port) def set_example_cmd(self, cmd): - self._exploit_info['executed_cmds']['example'] = cmd + powershell = True if "powershell" in cmd.lower() else False + self._exploit_info['executed_cmds']['example'].append({'command': cmd, 'powershell': powershell}) def add_powershell_cmd(self, cmd): """ @@ -68,8 +69,6 @@ class HostExploiter(object): :param cmd: Command used :return: None """ - if "powershell" in cmd.lower(): - self._exploit_info['executed_cmds']['powershell'] = cmd from infection_monkey.exploit.win_ms08_067 import Ms08_067_Exploiter 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 1dc2e9a67..8e550cfcf 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1086.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1086.py @@ -13,7 +13,7 @@ class T1086(AttackTechnique): used_msg = "Monkey successfully ran powershell commands on exploited machines in the network." query = [{'$match': {'telem_type': 'exploit', - 'data.info.executed_cmds.powershell': {'$exists': True}}}, + 'data.info.executed_cmds.example': {'$elemMatch': {'powershell': True}}}}, {'$project': {'_id': 0, 'machine': '$data.machine', 'info': '$data.info'}}, @@ -22,9 +22,10 @@ class T1086(AttackTechnique): @staticmethod def get_report_data(): cmd_data = list(mongo.db.telemetry.aggregate(T1086.query)) - data = {'title': T1086.technique_title(T1086.tech_id), 'cmds': cmd_data} + data = {'title': T1086.technique_title(), 'cmds': cmd_data} if cmd_data: - data.update({'message': T1086.used_msg, 'status': ScanStatus.USED.name}) + status = ScanStatus.USED else: - data.update({'message': T1086.unscanned_msg, 'status': ScanStatus.UNSCANNED.name}) + status = ScanStatus.UNSCANNED + data.update(T1086.get_message_and_status(status)) return data From 8ec5a6ac4323b7f35ef98a6649e3d5de5da0713e Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Wed, 19 Jun 2019 11:54:58 +0300 Subject: [PATCH 24/27] Readability improvements --- .../attack/technique_reports/T1075.py | 9 +++++---- .../attack/technique_reports/T1110.py | 10 +++++----- .../attack/technique_reports/T1210.py | 9 +++++---- .../attack/technique_reports/__init__.py | 20 +++++++++---------- 4 files changed, 24 insertions(+), 24 deletions(-) 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 18082dfc1..fa65a66c2 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1075.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1075.py @@ -31,13 +31,14 @@ class T1075(AttackTechnique): @staticmethod def get_report_data(): - data = {'title': T1075.technique_title(T1075.tech_id)} + data = {'title': T1075.technique_title()} successful_logins = list(mongo.db.telemetry.aggregate(T1075.query)) data.update({'successful_logins': successful_logins}) if successful_logins: - data.update(T1075.get_message_and_status(ScanStatus.USED)) + status = ScanStatus.USED elif mongo.db.telemetry.count_documents(T1075.login_attempt_query): - data.update(T1075.get_message_and_status(ScanStatus.SCANNED)) + status = ScanStatus.SCANNED else: - data.update(T1075.get_message_and_status(ScanStatus.UNSCANNED)) + status = ScanStatus.UNSCANNED + data.update(T1075.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 e8e4a62c3..0f09fb0fe 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py @@ -35,16 +35,16 @@ class T1110(AttackTechnique): result['successful_creds'].append(T1110.parse_creds(attempt)) if succeeded: - data = T1110.get_message_and_status(ScanStatus.USED) + status = ScanStatus.USED elif attempts: - data = T1110.get_message_and_status(ScanStatus.SCANNED) + status = ScanStatus.SCANNED else: - data = T1110.get_message_and_status(ScanStatus.UNSCANNED) - + status = ScanStatus.UNSCANNED + data = T1110.get_message_and_status(status) # Remove data with no successful brute force attempts attempts = [attempt for attempt in attempts if attempt['attempts']] - data.update({'services': attempts, 'title': T1110.technique_title(T1110.tech_id)}) + data.update({'services': attempts, 'title': T1110.technique_title()}) return data @staticmethod 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 677495c10..ed4a9a787 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1210.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1210.py @@ -14,15 +14,16 @@ class T1210(AttackTechnique): @staticmethod def get_report_data(): - data = {'title': T1210.technique_title(T1210.tech_id)} + data = {'title': T1210.technique_title()} scanned_services = T1210.get_scanned_services() exploited_services = T1210.get_exploited_services() if exploited_services: - data.update({'status': ScanStatus.USED.name, 'message': T1210.used_msg}) + status = ScanStatus.USED elif scanned_services: - data.update({'status': ScanStatus.SCANNED.name, 'message': T1210.scanned_msg}) + status = ScanStatus.SCANNED else: - data.update({'status': ScanStatus.UNSCANNED.name, 'message': T1210.unscanned_msg}) + status = ScanStatus.UNSCANNED + 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 7faaf5afd..fe2beb424 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py @@ -46,20 +46,19 @@ class AttackTechnique(object): """ pass - @staticmethod - def technique_status(tech_id): + @classmethod + def technique_status(cls): """ Gets the status of a certain attack technique. - :param tech_id: ID of attack technique, for e.g. T1110 :return: ScanStatus Enum object """ if mongo.db.attack_results.find_one({'telem_catagory': 'attack', 'status': ScanStatus.USED.value, - 'technique': tech_id}): + 'technique': cls.tech_id}): return ScanStatus.USED elif mongo.db.attack_results.find_one({'telem_catagory': 'attack', 'status': ScanStatus.SCANNED.value, - 'technique': tech_id}): + 'technique': cls.tech_id}): return ScanStatus.SCANNED else: return ScanStatus.UNSCANNED @@ -87,13 +86,12 @@ class AttackTechnique(object): else: return cls.used_msg - @staticmethod - def technique_title(tech_id): + @classmethod + def technique_title(cls): """ - :param tech_id: Technique's id. E.g. T1110 :return: techniques title. E.g. "T1110 Brute force" """ - return AttackConfig.get_technique(tech_id)['title'] + return AttackConfig.get_technique(cls.tech_id)['title'] @classmethod def get_tech_base_data(cls): @@ -102,8 +100,8 @@ class AttackTechnique(object): :return: dict E.g. {'message': 'Brute force used', 'status': 'Used', 'title': 'T1110 Brute force'} """ data = {} - status = AttackTechnique.technique_status(cls.tech_id) - title = AttackTechnique.technique_title(cls.tech_id) + status = cls.technique_status() + title = cls.technique_title() data.update({'status': status.name, 'title': title, 'message': cls.get_message_by_status(status)}) From f9bf3ef9f0f8070db8db15b10441e16716045b32 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Tue, 25 Jun 2019 10:42:03 +0300 Subject: [PATCH 25/27] Executed cmds info variable refactored --- monkey/infection_monkey/exploit/__init__.py | 11 ++++++++--- monkey/infection_monkey/exploit/hadoop.py | 2 +- monkey/infection_monkey/exploit/mssqlexec.py | 2 +- monkey/infection_monkey/exploit/rdpgrinder.py | 2 +- monkey/infection_monkey/exploit/shellshock.py | 2 +- monkey/infection_monkey/exploit/sshexec.py | 2 +- monkey/infection_monkey/exploit/vsftpd.py | 2 +- monkey/infection_monkey/exploit/web_rce.py | 4 ++-- monkey/infection_monkey/exploit/wmiexec.py | 2 +- .../monkey_island/cc/services/attack/attack_report.py | 1 - .../cc/services/attack/technique_reports/T1003.py | 1 + .../cc/services/attack/technique_reports/T1059.py | 2 +- .../cc/ui/src/components/attack/techniques/T1059.js | 2 +- 13 files changed, 20 insertions(+), 15 deletions(-) diff --git a/monkey/infection_monkey/exploit/__init__.py b/monkey/infection_monkey/exploit/__init__.py index 962240665..95a199923 100644 --- a/monkey/infection_monkey/exploit/__init__.py +++ b/monkey/infection_monkey/exploit/__init__.py @@ -25,7 +25,7 @@ class HostExploiter(object): 'finished': '', 'vulnerable_urls': [], 'vulnerable_ports': [], - 'executed_cmds': {}} + 'executed_cmds': []} self._exploit_attempts = [] self.host = host @@ -59,8 +59,13 @@ class HostExploiter(object): def add_vuln_port(self, port): self._exploit_info['vulnerable_ports'].append(port) - def set_example_cmd(self, cmd): - self._exploit_info['executed_cmds']['example'] = cmd + def add_executed_cmd(self, cmd): + """ + Appends command to exploiter's info. + :param cmd: String of executed command. e.g. 'echo Example' + """ + command = {'cmd': cmd} + self._exploit_info['executed_cmds'].append(command) from infection_monkey.exploit.win_ms08_067 import Ms08_067_Exploiter diff --git a/monkey/infection_monkey/exploit/hadoop.py b/monkey/infection_monkey/exploit/hadoop.py index 39edf0262..ac1cf784a 100644 --- a/monkey/infection_monkey/exploit/hadoop.py +++ b/monkey/infection_monkey/exploit/hadoop.py @@ -49,7 +49,7 @@ class HadoopExploiter(WebRCE): return False http_thread.join(self.DOWNLOAD_TIMEOUT) http_thread.stop() - self.set_example_cmd(command) + self.add_executed_cmd(command) return True def exploit(self, url, command): diff --git a/monkey/infection_monkey/exploit/mssqlexec.py b/monkey/infection_monkey/exploit/mssqlexec.py index c1409ec6c..4b5b258b9 100644 --- a/monkey/infection_monkey/exploit/mssqlexec.py +++ b/monkey/infection_monkey/exploit/mssqlexec.py @@ -77,7 +77,7 @@ class MSSQLExploiter(HostExploiter): commands.extend(monkey_args) MSSQLExploiter.execute_command(cursor, commands) MSSQLExploiter.run_file(cursor, tmp_file_path) - self.set_example_cmd(commands[-1]) + self.add_executed_cmd(commands[-1]) return True @staticmethod diff --git a/monkey/infection_monkey/exploit/rdpgrinder.py b/monkey/infection_monkey/exploit/rdpgrinder.py index 828b03c20..ea2bbb3f6 100644 --- a/monkey/infection_monkey/exploit/rdpgrinder.py +++ b/monkey/infection_monkey/exploit/rdpgrinder.py @@ -343,5 +343,5 @@ class RdpExploiter(HostExploiter): LOG.info("Executed monkey '%s' on remote victim %r", os.path.basename(src_path), self.host) - self.set_example_cmd(command) + self.add_executed_cmd(command) return True diff --git a/monkey/infection_monkey/exploit/shellshock.py b/monkey/infection_monkey/exploit/shellshock.py index 26e9a743b..5686be5d7 100644 --- a/monkey/infection_monkey/exploit/shellshock.py +++ b/monkey/infection_monkey/exploit/shellshock.py @@ -144,7 +144,7 @@ class ShellShockExploiter(HostExploiter): if not (self.check_remote_file_exists(url, header, exploit, self._config.monkey_log_path_linux)): LOG.info("Log file does not exist, monkey might not have run") continue - self.set_example_cmd(cmdline) + self.add_executed_cmd(cmdline) return True return False diff --git a/monkey/infection_monkey/exploit/sshexec.py b/monkey/infection_monkey/exploit/sshexec.py index e65d3cb19..e4b7a313c 100644 --- a/monkey/infection_monkey/exploit/sshexec.py +++ b/monkey/infection_monkey/exploit/sshexec.py @@ -178,7 +178,7 @@ class SSHExploiter(HostExploiter): self._config.dropper_target_path_linux, self.host, cmdline) ssh.close() - self.set_example_cmd(cmdline) + self.add_executed_cmd(cmdline) return True except Exception as exc: diff --git a/monkey/infection_monkey/exploit/vsftpd.py b/monkey/infection_monkey/exploit/vsftpd.py index eddac620c..ced79f208 100644 --- a/monkey/infection_monkey/exploit/vsftpd.py +++ b/monkey/infection_monkey/exploit/vsftpd.py @@ -138,7 +138,7 @@ class VSFTPDExploiter(HostExploiter): if backdoor_socket.send(run_monkey): LOG.info("Executed monkey '%s' on remote victim %r (cmdline=%r)", self._config.dropper_target_path_linux, self.host, run_monkey) - self.set_example_cmd(run_monkey) + self.add_executed_cmd(run_monkey) return True else: return False diff --git a/monkey/infection_monkey/exploit/web_rce.py b/monkey/infection_monkey/exploit/web_rce.py index 351eb7c17..d138e4cca 100644 --- a/monkey/infection_monkey/exploit/web_rce.py +++ b/monkey/infection_monkey/exploit/web_rce.py @@ -408,7 +408,7 @@ class WebRCE(HostExploiter): # If exploiter returns True / False if type(resp) is bool: LOG.info("Execution attempt successfully finished") - self.set_example_cmd(command) + self.add_executed_cmd(command) return resp # If exploiter returns command output, we can check for execution errors if 'is not recognized' in resp or 'command not found' in resp: @@ -422,7 +422,7 @@ class WebRCE(HostExploiter): return False LOG.info("Execution attempt finished") - self.set_example_cmd(command) + self.add_executed_cmd(command) return resp def get_monkey_upload_path(self, url_to_monkey): diff --git a/monkey/infection_monkey/exploit/wmiexec.py b/monkey/infection_monkey/exploit/wmiexec.py index 648fb233d..88246ba76 100644 --- a/monkey/infection_monkey/exploit/wmiexec.py +++ b/monkey/infection_monkey/exploit/wmiexec.py @@ -114,7 +114,7 @@ class WmiExploiter(HostExploiter): result.RemRelease() wmi_connection.close() - self.set_example_cmd(cmdline) + self.add_executed_cmd(cmdline) return success return False diff --git a/monkey/monkey_island/cc/services/attack/attack_report.py b/monkey/monkey_island/cc/services/attack/attack_report.py index 27fe53392..711f5103a 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, T1075, T1003, T1059 -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 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 d30197e9a..bd9e31c92 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py @@ -13,6 +13,7 @@ class T1003(AttackTechnique): used_msg = "Monkey successfully obtained some credentials from systems on the network." query = {'telem_type': 'system_info_collection', '$and': [{'data.credentials': {'$exists': True}}, + # $gt: {} checks if field is not an empty object {'data.credentials': {'$gt': {}}}]} @staticmethod 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 6f126b175..5f0fa4433 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py @@ -13,7 +13,7 @@ class T1059(AttackTechnique): used_msg = "Monkey successfully ran commands on exploited machines in the network." query = [{'$match': {'telem_type': 'exploit', - 'data.info.executed_cmds.example': {'$exists': True}}}, + 'data.info.executed_cmds': {'$exists': True, '$ne': []}}}, {'$project': {'_id': 0, 'machine': '$data.machine', 'info': '$data.info'}}, diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js index 5678b8c14..2352772c0 100644 --- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js +++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js @@ -16,7 +16,7 @@ class T1059 extends React.Component { columns: [ {Header: 'Machine', id: 'machine', accessor: x => RenderMachine(x.data[0].machine), style: { 'whiteSpace': 'unset'}, width: 160 }, {Header: 'Approx. Time', id: 'time', accessor: x => x.data[0].info.finished, style: { 'whiteSpace': 'unset' }}, - {Header: 'Command', id: 'command', accessor: x => x.data[0].info.executed_cmds.example, style: { 'whiteSpace': 'unset' }}, + {Header: 'Command', id: 'command', accessor: x => x.data[0].info.executed_cmds[0].cmd, style: { 'whiteSpace': 'unset' }}, ] }])}; From 36f917bc8dddbb8bffc51aff22d912fe60ac651e Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Tue, 25 Jun 2019 15:43:02 +0300 Subject: [PATCH 26/27] Updated branch according to changes in dev. --- .../services/attack/technique_reports/T1003.py | 2 +- .../services/attack/technique_reports/T1059.py | 2 +- .../services/attack/technique_reports/T1110.py | 2 +- .../services/attack/technique_reports/T1197.py | 16 +++++++++------- .../ui/src/components/attack/techniques/T1059.js | 5 +++-- 5 files changed, 15 insertions(+), 12 deletions(-) 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 bd9e31c92..cd1a538cb 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py @@ -12,7 +12,7 @@ class T1003(AttackTechnique): scanned_msg = "" used_msg = "Monkey successfully obtained some credentials from systems on the network." - query = {'telem_type': 'system_info_collection', '$and': [{'data.credentials': {'$exists': True}}, + query = {'telem_category': 'system_info_collection', '$and': [{'data.credentials': {'$exists': True}}, # $gt: {} checks if field is not an empty object {'data.credentials': {'$gt': {}}}]} 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 5f0fa4433..488a8f547 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py @@ -12,7 +12,7 @@ class T1059(AttackTechnique): scanned_msg = "" used_msg = "Monkey successfully ran commands on exploited machines in the network." - query = [{'$match': {'telem_type': 'exploit', + query = [{'$match': {'telem_category': 'exploit', 'data.info.executed_cmds': {'$exists': True, '$ne': []}}}, {'$project': {'_id': 0, 'machine': '$data.machine', 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 0f09fb0fe..60ae14c0b 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1110.py @@ -13,7 +13,7 @@ class T1110(AttackTechnique): used_msg = "Monkey successfully used brute force in the network." # Gets data about brute force attempts - query = [{'$match': {'telem_type': 'exploit', + query = [{'$match': {'telem_category': 'exploit', 'data.attempts': {'$not': {'$size': 0}}}}, {'$project': {'_id': 0, 'machine': '$data.machine', 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 9a968e998..b6bd316af 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1197.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1197.py @@ -13,13 +13,15 @@ class T1197(AttackTechnique): @staticmethod def get_report_data(): data = T1197.get_tech_base_data() - bits_results = mongo.db.telemetry.aggregate([{'$match': {'telem_category': '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 = mongo.db.telemetry.aggregate([{'$match': {'telem_category': '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}) return data diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js index 2352772c0..abca8987a 100644 --- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js +++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js @@ -1,7 +1,7 @@ import React from 'react'; import '../../../styles/Collapse.scss' import ReactTable from "react-table"; -import { RenderMachine } from "./Helpers" +import { renderMachine } from "./Helpers" class T1059 extends React.Component { @@ -14,13 +14,14 @@ class T1059 extends React.Component { return ([{ Header: 'Example commands used', columns: [ - {Header: 'Machine', id: 'machine', accessor: x => RenderMachine(x.data[0].machine), style: { 'whiteSpace': 'unset'}, width: 160 }, + {Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.data[0].machine), style: { 'whiteSpace': 'unset'}, width: 160 }, {Header: 'Approx. Time', id: 'time', accessor: x => x.data[0].info.finished, style: { 'whiteSpace': 'unset' }}, {Header: 'Command', id: 'command', accessor: x => x.data[0].info.executed_cmds[0].cmd, style: { 'whiteSpace': 'unset' }}, ] }])}; render() { + console.log(this.props.data); return (
{this.props.data.message}
From 3e9dcd3646bc8474d473611349dc38b5b667debb Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Wed, 26 Jun 2019 14:58:07 +0300 Subject: [PATCH 27/27] Powershell query changed to parse array of executed command dicts --- monkey/infection_monkey/exploit/mssqlexec.py | 2 +- monkey/infection_monkey/exploit/web_rce.py | 2 +- monkey/infection_monkey/exploit/weblogic.py | 4 ++-- .../cc/services/attack/technique_reports/T1003.py | 4 ++-- .../cc/services/attack/technique_reports/T1059.py | 5 ++++- .../cc/services/attack/technique_reports/T1086.py | 13 +++++++++---- .../cc/ui/src/components/attack/techniques/T1059.js | 7 +++---- .../cc/ui/src/components/attack/techniques/T1086.js | 6 +++--- 8 files changed, 25 insertions(+), 18 deletions(-) diff --git a/monkey/infection_monkey/exploit/mssqlexec.py b/monkey/infection_monkey/exploit/mssqlexec.py index 7bbd0e4ad..9d1dcb2d6 100644 --- a/monkey/infection_monkey/exploit/mssqlexec.py +++ b/monkey/infection_monkey/exploit/mssqlexec.py @@ -66,7 +66,7 @@ class MSSQLExploiter(HostExploiter): "xp_cmdshell \">%s\"" % (dst_path, tmp_file_path)] MSSQLExploiter.execute_command(cursor, commands) MSSQLExploiter.run_file(cursor, tmp_file_path) - self.add_powershell_cmd(' '.join(commands)) + self.add_executed_cmd(' '.join(commands)) # Form monkey's command in a file monkey_args = tools.build_monkey_commandline(self.host, tools.get_monkey_depth() - 1, diff --git a/monkey/infection_monkey/exploit/web_rce.py b/monkey/infection_monkey/exploit/web_rce.py index 58068fe91..fe45c65ce 100644 --- a/monkey/infection_monkey/exploit/web_rce.py +++ b/monkey/infection_monkey/exploit/web_rce.py @@ -338,7 +338,7 @@ class WebRCE(HostExploiter): command = self.get_command(paths['dest_path'], http_path, commands) resp = self.exploit(url, command) - self.add_powershell_cmd(command) + self.add_executed_cmd(command) resp = self.run_backup_commands(resp, url, paths['dest_path'], http_path) http_thread.join(DOWNLOAD_TIMEOUT) diff --git a/monkey/infection_monkey/exploit/weblogic.py b/monkey/infection_monkey/exploit/weblogic.py index f6df5f0fa..4c99f82b9 100644 --- a/monkey/infection_monkey/exploit/weblogic.py +++ b/monkey/infection_monkey/exploit/weblogic.py @@ -20,8 +20,8 @@ __author__ = "VakarisZ" LOG = logging.getLogger(__name__) # How long server waits for get request in seconds SERVER_TIMEOUT = 4 -# How long should we wait after each request in seconds -REQUEST_DELAY = 0.1 +# How long should be wait after each request in seconds +REQUEST_DELAY = 0.0001 # How long to wait for a sign(request from host) that server is vulnerable. In seconds REQUEST_TIMEOUT = 5 # How long to wait for response in exploitation. In seconds 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 cd1a538cb..a92758cbc 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1003.py @@ -13,8 +13,8 @@ class T1003(AttackTechnique): used_msg = "Monkey successfully obtained some credentials from systems on the network." query = {'telem_category': 'system_info_collection', '$and': [{'data.credentials': {'$exists': True}}, - # $gt: {} checks if field is not an empty object - {'data.credentials': {'$gt': {}}}]} + # $gt: {} checks if field is not an empty object + {'data.credentials': {'$gt': {}}}]} @staticmethod def get_report_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 488a8f547..328c11112 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1059.py @@ -14,10 +14,13 @@ class T1059(AttackTechnique): query = [{'$match': {'telem_category': 'exploit', 'data.info.executed_cmds': {'$exists': True, '$ne': []}}}, + {'$unwind': '$data.info.executed_cmds'}, + {'$sort': {'data.info.executed_cmds.powershell': 1}}, {'$project': {'_id': 0, 'machine': '$data.machine', 'info': '$data.info'}}, - {'$group': {'_id': '$machine', 'data': {'$push': '$$ROOT'}}}] + {'$group': {'_id': '$machine', 'data': {'$push': '$$ROOT'}}}, + {'$project': {'_id': 0, 'data': {'$arrayElemAt': ['$data', 0]}}}] @staticmethod def get_report_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 8e550cfcf..4114047c5 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/T1086.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1086.py @@ -12,11 +12,16 @@ class T1086(AttackTechnique): scanned_msg = "" used_msg = "Monkey successfully ran powershell commands on exploited machines in the network." - query = [{'$match': {'telem_type': 'exploit', - 'data.info.executed_cmds.example': {'$elemMatch': {'powershell': True}}}}, - {'$project': {'_id': 0, - 'machine': '$data.machine', + query = [{'$match': {'telem_category': 'exploit', + 'data.info.executed_cmds': {'$elemMatch': {'powershell': True}}}}, + {'$project': {'machine': '$data.machine', 'info': '$data.info'}}, + {'$project': {'_id': 0, + 'machine': 1, + 'info.finished': 1, + 'info.executed_cmds': {'$filter': {'input': '$info.executed_cmds', + 'as': 'command', + 'cond': {'$eq': ['$$command.powershell', True]}}}}}, {'$group': {'_id': '$machine', 'data': {'$push': '$$ROOT'}}}] @staticmethod diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js index abca8987a..57d5bcb2c 100644 --- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js +++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1059.js @@ -14,14 +14,13 @@ class T1059 extends React.Component { return ([{ Header: 'Example commands used', columns: [ - {Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.data[0].machine), style: { 'whiteSpace': 'unset'}, width: 160 }, - {Header: 'Approx. Time', id: 'time', accessor: x => x.data[0].info.finished, style: { 'whiteSpace': 'unset' }}, - {Header: 'Command', id: 'command', accessor: x => x.data[0].info.executed_cmds[0].cmd, style: { 'whiteSpace': 'unset' }}, + {Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.data.machine), style: { 'whiteSpace': 'unset'}, width: 160 }, + {Header: 'Approx. Time', id: 'time', accessor: x => x.data.info.finished, style: { 'whiteSpace': 'unset' }}, + {Header: 'Command', id: 'command', accessor: x => x.data.info.executed_cmds.cmd, style: { 'whiteSpace': 'unset' }}, ] }])}; render() { - console.log(this.props.data); return (
{this.props.data.message}
diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1086.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1086.js index d0b7c2928..d6d22c093 100644 --- a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1086.js +++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1086.js @@ -1,7 +1,7 @@ import React from 'react'; import '../../../styles/Collapse.scss' import ReactTable from "react-table"; -import { RenderMachine } from "./Helpers" +import { renderMachine } from "./Helpers" class T1086 extends React.Component { @@ -14,9 +14,9 @@ class T1086 extends React.Component { return ([{ Header: 'Example Powershell commands used', columns: [ - {Header: 'Machine', id: 'machine', accessor: x => RenderMachine(x.data[0].machine), style: { 'whiteSpace': 'unset'}, width: 160 }, + {Header: 'Machine', id: 'machine', accessor: x => renderMachine(x.data[0].machine), style: { 'whiteSpace': 'unset'}, width: 160 }, {Header: 'Approx. Time', id: 'time', accessor: x => x.data[0].info.finished, style: { 'whiteSpace': 'unset' }}, - {Header: 'Command', id: 'command', accessor: x => x.data[0].info.executed_cmds.powershell, style: { 'whiteSpace': 'unset' }}, + {Header: 'Command', id: 'command', accessor: x => x.data[0].info.executed_cmds[0].cmd, style: { 'whiteSpace': 'unset' }}, ] }])};