diff --git a/monkey/common/utils/attack_status_enum.py b/monkey/common/utils/attack_status_enum.py new file mode 100644 index 000000000..c7d2dc62c --- /dev/null +++ b/monkey/common/utils/attack_status_enum.py @@ -0,0 +1,10 @@ +from enum import Enum + + +class ScanStatus(Enum): + # Technique wasn't scanned + UNSCANNED = 0 + # Technique was attempted/scanned + SCANNED = 1 + # Technique was attempted and succeeded + USED = 2 diff --git a/monkey/infection_monkey/monkey.py b/monkey/infection_monkey/monkey.py index e80e15396..841a5521d 100644 --- a/monkey/infection_monkey/monkey.py +++ b/monkey/infection_monkey/monkey.py @@ -17,6 +17,8 @@ from infection_monkey.system_info import SystemInfoCollector from infection_monkey.system_singleton import SystemSingleton from infection_monkey.windows_upgrader import WindowsUpgrader from infection_monkey.post_breach.post_breach_handler import PostBreach +from common.utils.attack_status_enum import ScanStatus +from infection_monkey.transport.attack_telems.victim_host_telem import VictimHostTelem __author__ = 'itamar' @@ -179,9 +181,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() break if not host_exploited: self._fail_exploitation_machines.add(machine) + VictimHostTelem('T1210', ScanStatus.SCANNED.value, machine=machine).send() if not self._keep_running: break diff --git a/monkey/infection_monkey/transport/attack_telems/__init__.py b/monkey/infection_monkey/transport/attack_telems/__init__.py new file mode 100644 index 000000000..98867ed4d --- /dev/null +++ b/monkey/infection_monkey/transport/attack_telems/__init__.py @@ -0,0 +1 @@ +__author__ = 'VakarisZ' diff --git a/monkey/infection_monkey/transport/attack_telems/base_telem.py b/monkey/infection_monkey/transport/attack_telems/base_telem.py new file mode 100644 index 000000000..9d0275356 --- /dev/null +++ b/monkey/infection_monkey/transport/attack_telems/base_telem.py @@ -0,0 +1,41 @@ +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 new file mode 100644 index 000000000..ecab5a648 --- /dev/null +++ b/monkey/infection_monkey/transport/attack_telems/victim_host_telem.py @@ -0,0 +1,18 @@ +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 d43930206..e8238185e 100644 --- a/monkey/monkey_island/cc/app.py +++ b/monkey/monkey_island/cc/app.py @@ -30,6 +30,7 @@ from cc.resources.telemetry_feed import TelemetryFeed from cc.resources.pba_file_download import PBAFileDownload from cc.services.config import ConfigService from cc.resources.pba_file_upload import FileUpload +from cc.resources.attack_telem import AttackTelem __author__ = 'Barak' @@ -123,5 +124,6 @@ def init_app(mongo_url): '/api/fileUpload/?load=', '/api/fileUpload/?restore=') api.add_resource(RemoteRun, '/api/remote-monkey', '/api/remote-monkey/') + api.add_resource(AttackTelem, '/api/attack/') return app diff --git a/monkey/monkey_island/cc/resources/attack_telem.py b/monkey/monkey_island/cc/resources/attack_telem.py new file mode 100644 index 000000000..0dfa013e8 --- /dev/null +++ b/monkey/monkey_island/cc/resources/attack_telem.py @@ -0,0 +1,24 @@ +import flask_restful +from flask import request +import json +from cc.services.attack.attack_telem import set_results +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) + set_results(technique, data) + return {} diff --git a/monkey/monkey_island/cc/services/attack/__init__.py b/monkey/monkey_island/cc/services/attack/__init__.py new file mode 100644 index 000000000..98867ed4d --- /dev/null +++ b/monkey/monkey_island/cc/services/attack/__init__.py @@ -0,0 +1 @@ +__author__ = 'VakarisZ' diff --git a/monkey/monkey_island/cc/services/attack/attack_telem.py b/monkey/monkey_island/cc/services/attack/attack_telem.py new file mode 100644 index 000000000..295100c23 --- /dev/null +++ b/monkey/monkey_island/cc/services/attack/attack_telem.py @@ -0,0 +1,19 @@ +""" +File that contains ATT&CK telemetry storing/retrieving logic +""" +import logging +from cc.database import mongo + +__author__ = "VakarisZ" + +logger = logging.getLogger(__name__) + + +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)