diff --git a/monkey/infection_monkey/monkey.py b/monkey/infection_monkey/monkey.py index 06e0f267b..c6c5ee8b5 100644 --- a/monkey/infection_monkey/monkey.py +++ b/monkey/infection_monkey/monkey.py @@ -16,6 +16,7 @@ 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.telemetry.attack.t1107_telem import T1107Telem from infection_monkey.windows_upgrader import WindowsUpgrader from infection_monkey.post_breach.post_breach_handler import PostBreach from common.utils.attack_utils import ScanStatus @@ -230,7 +231,6 @@ class InfectionMonkey(object): self.send_log() self._singleton.unlock() - utils.remove_monkey_dir() InfectionMonkey.self_delete() LOG.info("Monkey is shutting down") @@ -243,6 +243,11 @@ class InfectionMonkey(object): @staticmethod def self_delete(): + if utils.remove_monkey_dir(): + T1107Telem(ScanStatus.USED, utils.get_monkey_dir_path()).send() + else: + T1107Telem(ScanStatus.SCANNED, utils.get_monkey_dir_path()).send() + if WormConfiguration.self_delete_in_cleanup \ and -1 == sys.executable.find('python'): try: @@ -256,8 +261,10 @@ class InfectionMonkey(object): close_fds=True, startupinfo=startupinfo) else: os.remove(sys.executable) + T1107Telem(ScanStatus.USED, sys.executable).send() except Exception as exc: LOG.error("Exception in self delete: %s", exc) + T1107Telem(ScanStatus.SCANNED, sys.executable).send() def send_log(self): monkey_log_path = utils.get_monkey_log_path() diff --git a/monkey/infection_monkey/telemetry/attack/t1107_telem.py b/monkey/infection_monkey/telemetry/attack/t1107_telem.py new file mode 100644 index 000000000..ffb69b698 --- /dev/null +++ b/monkey/infection_monkey/telemetry/attack/t1107_telem.py @@ -0,0 +1,19 @@ +from infection_monkey.telemetry.attack.attack_telem import AttackTelem + + +class T1107Telem(AttackTelem): + def __init__(self, status, path): + """ + T1107 telemetry. + :param status: ScanStatus of technique + :param path: Path of deleted dir/file + """ + super(T1107Telem, self).__init__('T1107', status) + self.path = path + + def get_data(self): + data = super(T1107Telem, self).get_data() + data.update({ + 'path': self.path + }) + return data diff --git a/monkey/infection_monkey/utils.py b/monkey/infection_monkey/utils.py index 6eb3aefb5..f8b5cc56a 100644 --- a/monkey/infection_monkey/utils.py +++ b/monkey/infection_monkey/utils.py @@ -49,8 +49,13 @@ def create_monkey_dir(): def remove_monkey_dir(): """ Removes monkey's root directory + :return True if removed without errors and False otherwise """ - shutil.rmtree(get_monkey_dir_path(), ignore_errors=True) + try: + shutil.rmtree(get_monkey_dir_path()) + return True + except Exception: + return False def get_monkey_dir_path(): diff --git a/monkey/monkey_island/cc/services/attack/attack_report.py b/monkey/monkey_island/cc/services/attack/attack_report.py index 7bec85a32..ff038c092 100644 --- a/monkey/monkey_island/cc/services/attack/attack_report.py +++ b/monkey/monkey_island/cc/services/attack/attack_report.py @@ -1,6 +1,6 @@ import logging from monkey_island.cc.services.attack.technique_reports import T1210, T1197, T1110, T1075, T1003, T1059, T1086, T1082 -from monkey_island.cc.services.attack.technique_reports import T1145 +from monkey_island.cc.services.attack.technique_reports import T1145, T1107 from monkey_island.cc.services.attack.attack_config import AttackConfig from monkey_island.cc.database import mongo @@ -17,7 +17,8 @@ TECHNIQUES = {'T1210': T1210.T1210, 'T1059': T1059.T1059, 'T1086': T1086.T1086, 'T1082': T1082.T1082, - 'T1145': T1145.T1145} + 'T1145': T1145.T1145, + 'T1107': T1107.T1107} REPORT_NAME = 'new_report' @@ -57,12 +58,12 @@ class AttackReportService: Gets latest report (by retrieving it from db or generating a new one). :return: report dict. """ + return AttackReportService.generate_new_report() if AttackReportService.is_report_generated(): telem_time = AttackReportService.get_latest_attack_telem_time() latest_report = mongo.db.attack_report.find_one({'name': REPORT_NAME}) if telem_time and latest_report['latest_telem_time'] and telem_time == latest_report['latest_telem_time']: return latest_report - return AttackReportService.generate_new_report() @staticmethod def is_report_generated(): diff --git a/monkey/monkey_island/cc/services/attack/attack_schema.py b/monkey/monkey_island/cc/services/attack/attack_schema.py index 00d3e9536..7a8cc7727 100644 --- a/monkey/monkey_island/cc/services/attack/attack_schema.py +++ b/monkey/monkey_island/cc/services/attack/attack_schema.py @@ -91,6 +91,15 @@ SCHEMA = { "necessary": True, "description": "Adversaries may abuse BITS to download, execute, " "and even clean up after running malicious code." + }, + "T1107": { + "title": "T1107 File Deletion", + "type": "bool", + "value": True, + "necessary": True, + "description": "Adversaries may remove files over the course of an intrusion " + "to keep their footprint low or remove them at the end as part " + "of the post-intrusion cleanup process." } } }, diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1107.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1107.py new file mode 100644 index 000000000..fd9f1ad10 --- /dev/null +++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1107.py @@ -0,0 +1,32 @@ +from monkey_island.cc.database import mongo +from monkey_island.cc.services.attack.technique_reports import AttackTechnique + +__author__ = "VakarisZ" + + +class T1107(AttackTechnique): + tech_id = "T1107" + unscanned_msg = "" + scanned_msg = "Monkey tried to delete files on a system in the network but failed." + used_msg = "Monkey successfully deleted files on systems in the network." + + query = [{'$match': {'telem_category': 'attack', + 'data.technique': 'T1107'}}, + {'$lookup': {'from': 'monkey', + 'localField': 'monkey_guid', + 'foreignField': 'guid', + 'as': 'monkey'}}, + {'$project': {'monkey': {'$arrayElemAt': ['$monkey', 0]}, + 'status': '$data.status', + 'path': '$data.path'}}, + {'$addFields': {'_id': 0, + 'machine': {'hostname': '$monkey.hostname', 'ips': '$monkey.ip_addresses'}, + 'monkey': 0}}, + {'$group': {'_id': {'machine': '$machine', 'status': '$status', 'path': '$path'}}}] + + @staticmethod + def get_report_data(): + data = T1107.get_tech_base_data() + deleted_files = list(mongo.db.telemetry.aggregate(T1107.query)) + data.update({'deleted_files': deleted_files}) + 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 edd180d50..81b7dd6bf 100644 --- a/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py +++ b/monkey/monkey_island/cc/services/attack/technique_reports/__init__.py @@ -52,13 +52,13 @@ class AttackTechnique(object): Gets the status of a certain attack technique. :return: ScanStatus Enum object """ - if mongo.db.attack_results.find_one({'telem_category': 'attack', - 'status': ScanStatus.USED.value, - 'technique': cls.tech_id}): + if mongo.db.telemetry.find_one({'telem_category': 'attack', + 'data.status': ScanStatus.USED.value, + 'data.technique': cls.tech_id}): return ScanStatus.USED - elif mongo.db.attack_results.find_one({'telem_category': 'attack', - 'status': ScanStatus.SCANNED.value, - 'technique': cls.tech_id}): + elif mongo.db.telemetry.find_one({'telem_category': 'attack', + 'data.status': ScanStatus.SCANNED.value, + 'data.technique': cls.tech_id}): return ScanStatus.SCANNED else: return ScanStatus.UNSCANNED 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 9885219ad..1060f4b2d 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 @@ -11,7 +11,11 @@ export function renderMachine(val){ export function renderMachineFromSystemData(data) { let machineStr = data['hostname'] + " ( "; data['ips'].forEach(function(ipInfo){ - machineStr += ipInfo['addr'] + " "; + if(typeof ipInfo === "object"){ + machineStr += ipInfo['addr'] + " "; + } else { + machineStr += ipInfo + " "; + } }); return machineStr + ")" } diff --git a/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1107.js b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1107.js new file mode 100644 index 000000000..acf513c2f --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/attack/techniques/T1107.js @@ -0,0 +1,47 @@ +import React from 'react'; +import '../../../styles/Collapse.scss' +import ReactTable from "react-table"; +import { renderMachineFromSystemData } from "./Helpers" + + +class T1107 extends React.Component { + + constructor(props) { + super(props); + } + + static renderDelete(status){ + if(status === 2){ + return Yes + } else { + return No + } + } + + static getDeletedFileColumns() { + return ([{ + columns: [ + {Header: 'Machine', id: 'machine', accessor: x => renderMachineFromSystemData(x._id.machine), style: { 'whiteSpace': 'unset' }}, + {Header: 'Path', id: 'path', accessor: x => x._id.path, style: { 'whiteSpace': 'unset' }}, + {Header: 'Deleted?', id: 'deleted', accessor: x => this.renderDelete(x._id.status), + style: { 'whiteSpace': 'unset' }, width: 160}] + }])}; + + render() { + return ( +