From 52c041379765d41ef3767c0c3bea9bf12b28972d Mon Sep 17 00:00:00 2001 From: vakarisz Date: Tue, 1 Mar 2022 11:31:47 +0200 Subject: [PATCH] Island, UT: remove credential processing from exploit telemetry Credentials should be sent via credential telemetry, not exploit telemetry. This will remove the need to maintain duplicate code of credential extraction --- monkey/infection_monkey/exploit/zerologon.py | 2 + .../services/telemetry/processing/exploit.py | 15 -- .../exploitations/test_monkey_exploitation.py | 134 ++++++++++++- .../cc/services/reporting/test_report.py | 183 ------------------ 4 files changed, 131 insertions(+), 203 deletions(-) delete mode 100644 monkey/tests/unit_tests/monkey_island/cc/services/reporting/test_report.py diff --git a/monkey/infection_monkey/exploit/zerologon.py b/monkey/infection_monkey/exploit/zerologon.py index a882b17de..f05983d92 100644 --- a/monkey/infection_monkey/exploit/zerologon.py +++ b/monkey/infection_monkey/exploit/zerologon.py @@ -276,6 +276,8 @@ class ZerologonExploiter(HostExploiter): ) def add_extracted_creds_to_exploit_info(self, user: str, lmhash: str, nthash: str) -> None: + # TODO exploit_info["credentials"] is discontinued, + # refactor to send a credential telemetry self.exploit_info["credentials"].update( { user: { diff --git a/monkey/monkey_island/cc/services/telemetry/processing/exploit.py b/monkey/monkey_island/cc/services/telemetry/processing/exploit.py index a867267d0..d035dedd3 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/exploit.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/exploit.py @@ -4,7 +4,6 @@ import dateutil from monkey_island.cc.models import Monkey from monkey_island.cc.server_utils.encryption import get_datastore_encryptor -from monkey_island.cc.services.config import ConfigService from monkey_island.cc.services.edge.displayed_edge import EdgeService from monkey_island.cc.services.node import NodeService from monkey_island.cc.services.telemetry.processing.utils import ( @@ -20,7 +19,6 @@ def process_exploit_telemetry(telemetry_json): edge = get_edge_by_scan_or_exploit_telemetry(telemetry_json) update_network_with_exploit(edge, telemetry_json) update_node_credentials_from_successful_attempts(edge, telemetry_json) - add_exploit_extracted_creds_to_config(telemetry_json) check_machine_exploited( current_monkey=Monkey.get_single_monkey_by_guid(telemetry_json["monkey_guid"]), @@ -31,19 +29,6 @@ def process_exploit_telemetry(telemetry_json): ) -def add_exploit_extracted_creds_to_config(telemetry_json): - if "credentials" in telemetry_json["data"]["info"]: - creds = telemetry_json["data"]["info"]["credentials"] - for user in creds: - ConfigService.creds_add_username(creds[user]["username"]) - if "password" in creds[user] and creds[user]["password"]: - ConfigService.creds_add_password(creds[user]["password"]) - if "lm_hash" in creds[user] and creds[user]["lm_hash"]: - ConfigService.creds_add_lm_hash(creds[user]["lm_hash"]) - if "ntlm_hash" in creds[user] and creds[user]["ntlm_hash"]: - ConfigService.creds_add_ntlm_hash(creds[user]["ntlm_hash"]) - - def update_node_credentials_from_successful_attempts(edge: EdgeService, telemetry_json): for attempt in telemetry_json["data"]["attempts"]: if attempt["result"]: diff --git a/monkey/tests/unit_tests/monkey_island/cc/services/reporting/exploitations/test_monkey_exploitation.py b/monkey/tests/unit_tests/monkey_island/cc/services/reporting/exploitations/test_monkey_exploitation.py index 1c0377807..9995ba795 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/services/reporting/exploitations/test_monkey_exploitation.py +++ b/monkey/tests/unit_tests/monkey_island/cc/services/reporting/exploitations/test_monkey_exploitation.py @@ -1,13 +1,137 @@ -from tests.unit_tests.monkey_island.cc.services.reporting.test_report import ( - NODE_DICT, - NODE_DICT_DUPLICATE_EXPLOITS, - NODE_DICT_FAILED_EXPLOITS, -) +import datetime +from copy import deepcopy + +from bson import ObjectId from monkey_island.cc.services.reporting.exploitations.monkey_exploitation import ( get_exploits_used_on_node, ) +TELEM_ID = { + "exploit_creds": ObjectId(b"123456789000"), + "system_info_creds": ObjectId(b"987654321000"), + "no_creds": ObjectId(b"112233445566"), + "monkey": ObjectId(b"665544332211"), +} +MONKEY_GUID = "67890" +USER = "user-name" +PWD = "password123" +LM_HASH = "e52cac67419a9a22664345140a852f61" +NT_HASH = "a9fdfa038c4b75ebc76dc855dd74f0da" +VICTIM_IP = "0.0.0.0" +VICTIM_DOMAIN_NAME = "domain-name" +HOSTNAME = "name-of-host" + +# Below telem constants only contain fields relevant to current tests + +EXPLOIT_TELEMETRY_TELEM = { + "_id": TELEM_ID["exploit_creds"], + "monkey_guid": MONKEY_GUID, + "telem_category": "exploit", + "data": { + "machine": { + "ip_addr": VICTIM_IP, + "domain_name": VICTIM_DOMAIN_NAME, + }, + "info": { + "credentials": { + USER: { + "username": USER, + "lm_hash": LM_HASH, + "ntlm_hash": NT_HASH, + } + } + }, + }, +} + +SYSTEM_INFO_TELEMETRY_TELEM = { + "_id": TELEM_ID["system_info_creds"], + "monkey_guid": MONKEY_GUID, + "telem_category": "system_info", + "timestamp": datetime.datetime(2021, 2, 19, 9, 0, 14, 984000), + "command_control_channel": { + "src": "192.168.56.1", + "dst": "192.168.56.2", + }, + "data": { + "credentials": { + USER: { + "password": PWD, + "lm_hash": LM_HASH, + "ntlm_hash": NT_HASH, + } + } + }, +} + +NO_CREDS_TELEMETRY_TELEM = { + "_id": TELEM_ID["no_creds"], + "monkey_guid": MONKEY_GUID, + "telem_category": "exploit", + "timestamp": datetime.datetime(2021, 2, 19, 9, 0, 14, 984000), + "command_control_channel": { + "src": "192.168.56.1", + "dst": "192.168.56.2", + }, + "data": { + "machine": { + "ip_addr": VICTIM_IP, + "domain_name": VICTIM_DOMAIN_NAME, + }, + "info": {"credentials": {}}, + }, +} + +MONKEY_TELEM = {"_id": TELEM_ID["monkey"], "guid": MONKEY_GUID, "hostname": HOSTNAME} + +NODE_DICT = { + "id": "602f62118e30cf35830ff8e4", + "label": "WinDev2010Eval.mshome.net", + "group": "monkey_windows", + "os": "windows", + "dead": True, + "exploits": [ + { + "exploitation_result": True, + "exploiter": "DrupalExploiter", + "info": { + "display_name": "Drupal Server", + "started": datetime.datetime(2021, 2, 19, 9, 0, 14, 950000), + "finished": datetime.datetime(2021, 2, 19, 9, 0, 14, 950000), + "vulnerable_urls": [], + "vulnerable_ports": [], + "executed_cmds": [], + }, + "attempts": [], + "timestamp": datetime.datetime(2021, 2, 19, 9, 0, 14, 984000), + "origin": "MonkeyIsland : 192.168.56.1", + }, + { + "exploitation_result": True, + "exploiter": "ZerologonExploiter", + "info": { + "display_name": "Zerologon", + "started": datetime.datetime(2021, 2, 19, 9, 0, 15, 16000), + "finished": datetime.datetime(2021, 2, 19, 9, 0, 15, 17000), + "vulnerable_urls": [], + "vulnerable_ports": [], + "executed_cmds": [], + }, + "attempts": [], + "timestamp": datetime.datetime(2021, 2, 19, 9, 0, 15, 60000), + "origin": "MonkeyIsland : 192.168.56.1", + }, + ], +} + +NODE_DICT_DUPLICATE_EXPLOITS = deepcopy(NODE_DICT) +NODE_DICT_DUPLICATE_EXPLOITS["exploits"][1] = NODE_DICT_DUPLICATE_EXPLOITS["exploits"][0] + +NODE_DICT_FAILED_EXPLOITS = deepcopy(NODE_DICT) +NODE_DICT_FAILED_EXPLOITS["exploits"][0]["exploitation_result"] = False +NODE_DICT_FAILED_EXPLOITS["exploits"][1]["exploitation_result"] = False + def test_get_exploits_used_on_node__2_exploits(): exploits = get_exploits_used_on_node(NODE_DICT) diff --git a/monkey/tests/unit_tests/monkey_island/cc/services/reporting/test_report.py b/monkey/tests/unit_tests/monkey_island/cc/services/reporting/test_report.py deleted file mode 100644 index bfe19ea83..000000000 --- a/monkey/tests/unit_tests/monkey_island/cc/services/reporting/test_report.py +++ /dev/null @@ -1,183 +0,0 @@ -import datetime -from copy import deepcopy - -import mongoengine -import pytest -from bson import ObjectId - -from monkey_island.cc.models.telemetries import save_telemetry -from monkey_island.cc.services.reporting.report import ReportService - -TELEM_ID = { - "exploit_creds": ObjectId(b"123456789000"), - "system_info_creds": ObjectId(b"987654321000"), - "no_creds": ObjectId(b"112233445566"), - "monkey": ObjectId(b"665544332211"), -} -MONKEY_GUID = "67890" -USER = "user-name" -PWD = "password123" -LM_HASH = "e52cac67419a9a22664345140a852f61" -NT_HASH = "a9fdfa038c4b75ebc76dc855dd74f0da" -VICTIM_IP = "0.0.0.0" -VICTIM_DOMAIN_NAME = "domain-name" -HOSTNAME = "name-of-host" - -# Below telem constants only contain fields relevant to current tests - -EXPLOIT_TELEMETRY_TELEM = { - "_id": TELEM_ID["exploit_creds"], - "monkey_guid": MONKEY_GUID, - "telem_category": "exploit", - "data": { - "machine": { - "ip_addr": VICTIM_IP, - "domain_name": VICTIM_DOMAIN_NAME, - }, - "info": { - "credentials": { - USER: { - "username": USER, - "lm_hash": LM_HASH, - "ntlm_hash": NT_HASH, - } - } - }, - }, -} - -SYSTEM_INFO_TELEMETRY_TELEM = { - "_id": TELEM_ID["system_info_creds"], - "monkey_guid": MONKEY_GUID, - "telem_category": "system_info", - "timestamp": datetime.datetime(2021, 2, 19, 9, 0, 14, 984000), - "command_control_channel": { - "src": "192.168.56.1", - "dst": "192.168.56.2", - }, - "data": { - "credentials": { - USER: { - "password": PWD, - "lm_hash": LM_HASH, - "ntlm_hash": NT_HASH, - } - } - }, -} - -NO_CREDS_TELEMETRY_TELEM = { - "_id": TELEM_ID["no_creds"], - "monkey_guid": MONKEY_GUID, - "telem_category": "exploit", - "timestamp": datetime.datetime(2021, 2, 19, 9, 0, 14, 984000), - "command_control_channel": { - "src": "192.168.56.1", - "dst": "192.168.56.2", - }, - "data": { - "machine": { - "ip_addr": VICTIM_IP, - "domain_name": VICTIM_DOMAIN_NAME, - }, - "info": {"credentials": {}}, - }, -} - -MONKEY_TELEM = {"_id": TELEM_ID["monkey"], "guid": MONKEY_GUID, "hostname": HOSTNAME} - -NODE_DICT = { - "id": "602f62118e30cf35830ff8e4", - "label": "WinDev2010Eval.mshome.net", - "group": "monkey_windows", - "os": "windows", - "dead": True, - "exploits": [ - { - "exploitation_result": True, - "exploiter": "DrupalExploiter", - "info": { - "display_name": "Drupal Server", - "started": datetime.datetime(2021, 2, 19, 9, 0, 14, 950000), - "finished": datetime.datetime(2021, 2, 19, 9, 0, 14, 950000), - "vulnerable_urls": [], - "vulnerable_ports": [], - "executed_cmds": [], - }, - "attempts": [], - "timestamp": datetime.datetime(2021, 2, 19, 9, 0, 14, 984000), - "origin": "MonkeyIsland : 192.168.56.1", - }, - { - "exploitation_result": True, - "exploiter": "ZerologonExploiter", - "info": { - "display_name": "Zerologon", - "started": datetime.datetime(2021, 2, 19, 9, 0, 15, 16000), - "finished": datetime.datetime(2021, 2, 19, 9, 0, 15, 17000), - "vulnerable_urls": [], - "vulnerable_ports": [], - "executed_cmds": [], - }, - "attempts": [], - "timestamp": datetime.datetime(2021, 2, 19, 9, 0, 15, 60000), - "origin": "MonkeyIsland : 192.168.56.1", - }, - ], -} - -NODE_DICT_DUPLICATE_EXPLOITS = deepcopy(NODE_DICT) -NODE_DICT_DUPLICATE_EXPLOITS["exploits"][1] = NODE_DICT_DUPLICATE_EXPLOITS["exploits"][0] - -NODE_DICT_FAILED_EXPLOITS = deepcopy(NODE_DICT) -NODE_DICT_FAILED_EXPLOITS["exploits"][0]["exploitation_result"] = False -NODE_DICT_FAILED_EXPLOITS["exploits"][1]["exploitation_result"] = False - - -@pytest.fixture -def fake_mongo(monkeypatch): - mongo = mongoengine.connection.get_connection() - monkeypatch.setattr("monkey_island.cc.services.reporting.report.mongo", mongo) - monkeypatch.setattr("monkey_island.cc.models.telemetries.telemetry_dal.mongo", mongo) - monkeypatch.setattr("monkey_island.cc.services.node.mongo", mongo) - return mongo - - -@pytest.mark.usefixtures("uses_database") -def test_get_stolen_creds_exploit(fake_mongo): - fake_mongo.db.telemetry.insert_one(EXPLOIT_TELEMETRY_TELEM) - - stolen_creds_exploit = ReportService.get_stolen_creds() - expected_stolen_creds_exploit = [ - {"origin": VICTIM_DOMAIN_NAME, "type": "LM hash", "username": USER}, - {"origin": VICTIM_DOMAIN_NAME, "type": "NTLM hash", "username": USER}, - ] - - assert expected_stolen_creds_exploit == stolen_creds_exploit - - -@pytest.mark.slow -@pytest.mark.usefixtures("uses_database", "uses_encryptor") -def test_get_stolen_creds_from_db(fake_mongo): - fake_mongo.db.monkey.insert_one(MONKEY_TELEM) - save_telemetry(SYSTEM_INFO_TELEMETRY_TELEM) - - stolen_creds_system_info = ReportService.get_stolen_creds() - expected_stolen_creds_from_db = [ - {"origin": HOSTNAME, "type": "Clear Password", "username": USER}, - {"origin": HOSTNAME, "type": "LM hash", "username": USER}, - {"origin": HOSTNAME, "type": "NTLM hash", "username": USER}, - ] - - assert expected_stolen_creds_from_db == stolen_creds_system_info - - -@pytest.mark.usefixtures("uses_database") -def test_get_stolen_creds_no_creds(fake_mongo): - fake_mongo.db.monkey.insert_one(MONKEY_TELEM) - save_telemetry(NO_CREDS_TELEMETRY_TELEM) - - stolen_creds_no_creds = ReportService.get_stolen_creds() - expected_stolen_creds_no_creds = [] - - assert expected_stolen_creds_no_creds == stolen_creds_no_creds