From 1528b00a1b31af5c25befde7724ec268d7899e87 Mon Sep 17 00:00:00 2001 From: Shreya Date: Fri, 26 Feb 2021 23:38:45 +0530 Subject: [PATCH 1/6] Change origin of creds stolen using exploits from host machine to exploited machine --- monkey/monkey_island/cc/services/reporting/report.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/monkey/monkey_island/cc/services/reporting/report.py b/monkey/monkey_island/cc/services/reporting/report.py index 8b57eaec2..eabbfb051 100644 --- a/monkey/monkey_island/cc/services/reporting/report.py +++ b/monkey/monkey_island/cc/services/reporting/report.py @@ -198,7 +198,8 @@ class ReportService: for telem in mongo.db.telemetry.find({'telem_category': 'system_info', 'data.credentials': {'$exists': True}}, {'data.credentials': 1, 'monkey_guid': 1}): creds = telem['data']['credentials'] - formatted_creds.extend(ReportService._format_creds_for_reporting(telem, creds)) + origin = NodeService.get_monkey_by_guid(telem['monkey_guid'])['hostname'] + formatted_creds.extend(ReportService._format_creds_for_reporting(telem, creds, origin)) return formatted_creds @staticmethod @@ -207,16 +208,17 @@ class ReportService: for telem in mongo.db.telemetry.find({'telem_category': 'exploit', 'data.info.credentials': {'$exists': True}}, {'data.info.credentials': 1, 'monkey_guid': 1}): creds = telem['data']['info']['credentials'] - formatted_creds.extend(ReportService._format_creds_for_reporting(telem, creds)) + origin = telem['data']['machine']['domain_name'] + formatted_creds.extend(ReportService._format_creds_for_reporting(telem, creds, origin)) return formatted_creds @staticmethod - def _format_creds_for_reporting(telem, monkey_creds): + def _format_creds_for_reporting(telem, monkey_creds, origin): creds = [] CRED_TYPE_DICT = {'password': 'Clear Password', 'lm_hash': 'LM hash', 'ntlm_hash': 'NTLM hash'} if len(monkey_creds) == 0: return [] - origin = NodeService.get_monkey_by_guid(telem['monkey_guid'])['hostname'] + for user in monkey_creds: for cred_type in CRED_TYPE_DICT: if cred_type not in monkey_creds[user] or not monkey_creds[user][cred_type]: From 8d2e530eaab3db9c602ce1ab9ff140dbebb8e9d0 Mon Sep 17 00:00:00 2001 From: Shreya Date: Sat, 27 Feb 2021 01:04:52 +0530 Subject: [PATCH 2/6] Show IP if domain name isn't available --- monkey/monkey_island/cc/services/reporting/report.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/monkey/monkey_island/cc/services/reporting/report.py b/monkey/monkey_island/cc/services/reporting/report.py index eabbfb051..fa3bd5f94 100644 --- a/monkey/monkey_island/cc/services/reporting/report.py +++ b/monkey/monkey_island/cc/services/reporting/report.py @@ -206,9 +206,11 @@ class ReportService: def _get_credentials_from_exploit_telems(): formatted_creds = [] for telem in mongo.db.telemetry.find({'telem_category': 'exploit', 'data.info.credentials': {'$exists': True}}, - {'data.info.credentials': 1, 'monkey_guid': 1}): + {'data.info.credentials': 1, 'data.machine': 1, 'monkey_guid': 1}): creds = telem['data']['info']['credentials'] - origin = telem['data']['machine']['domain_name'] + _domain_name = telem['data']['machine']['domain_name'] + _ip = telem['data']['machine']['ip_addr'] + origin = _domain_name if _domain_name else _ip formatted_creds.extend(ReportService._format_creds_for_reporting(telem, creds, origin)) return formatted_creds From eecee86d923027ef604d3b940a8a961fc38fc3a8 Mon Sep 17 00:00:00 2001 From: Shreya Date: Mon, 1 Mar 2021 14:13:37 +0530 Subject: [PATCH 3/6] Remove preceeding underscore from variables --- monkey/monkey_island/cc/services/reporting/report.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/monkey/monkey_island/cc/services/reporting/report.py b/monkey/monkey_island/cc/services/reporting/report.py index fa3bd5f94..5970a33b7 100644 --- a/monkey/monkey_island/cc/services/reporting/report.py +++ b/monkey/monkey_island/cc/services/reporting/report.py @@ -208,9 +208,9 @@ class ReportService: for telem in mongo.db.telemetry.find({'telem_category': 'exploit', 'data.info.credentials': {'$exists': True}}, {'data.info.credentials': 1, 'data.machine': 1, 'monkey_guid': 1}): creds = telem['data']['info']['credentials'] - _domain_name = telem['data']['machine']['domain_name'] - _ip = telem['data']['machine']['ip_addr'] - origin = _domain_name if _domain_name else _ip + domain_name = telem['data']['machine']['domain_name'] + ip = telem['data']['machine']['ip_addr'] + origin = domain_name if domain_name else ip formatted_creds.extend(ReportService._format_creds_for_reporting(telem, creds, origin)) return formatted_creds From d772760ace514d8e0ba1955ec4598d56e62f351d Mon Sep 17 00:00:00 2001 From: Shreya Date: Wed, 3 Mar 2021 16:47:18 +0530 Subject: [PATCH 4/6] Add unit tests for get_stolen_creds() --- .../cc/services/reporting/report.py | 1 + .../services/tests/reporting/test_report.py | 125 ++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 monkey/monkey_island/cc/services/tests/reporting/test_report.py diff --git a/monkey/monkey_island/cc/services/reporting/report.py b/monkey/monkey_island/cc/services/reporting/report.py index 5970a33b7..d4e3886b9 100644 --- a/monkey/monkey_island/cc/services/reporting/report.py +++ b/monkey/monkey_island/cc/services/reporting/report.py @@ -181,6 +181,7 @@ class ReportService: @staticmethod def get_stolen_creds(): + print(f"\n\n{list(mongo.db.telemetry.find())}\n\n") creds = [] stolen_system_info_creds = ReportService._get_credentials_from_system_info_telems() diff --git a/monkey/monkey_island/cc/services/tests/reporting/test_report.py b/monkey/monkey_island/cc/services/tests/reporting/test_report.py new file mode 100644 index 000000000..9c0321059 --- /dev/null +++ b/monkey/monkey_island/cc/services/tests/reporting/test_report.py @@ -0,0 +1,125 @@ +import mongomock +import pytest +from bson import ObjectId + +import monkey_island.cc.database + +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" +EXPLOITER_CLASS_NAME = "exploiter-name" + +# 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", + "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", + "data": { + "machine": { + "ip_addr": VICTIM_IP, + "domain_name": VICTIM_DOMAIN_NAME, + }, + "info": {"credentials": {}} + } +} + +MONKEY_TELEM = {"_id": TELEM_ID["monkey"], "guid": MONKEY_GUID, "hostname": HOSTNAME} + + +@pytest.fixture +def fake_mongo(monkeypatch): + mongo = mongomock.MongoClient() + monkeypatch.setattr("monkey_island.cc.database.mongo", mongo) + return mongo + + +@pytest.fixture +def report_service(): + # can't be imported before monkeypatching since mongo connection is made at module level + # see https://stackoverflow.com/a/51994349/ + from monkey_island.cc.services.reporting.report import ReportService + + return ReportService + + +def test_get_stolen_creds_exploit(fake_mongo, report_service): + fake_mongo.db.telemetry.insert_one(EXPLOIT_TELEMETRY_TELEM) + + stolen_creds_exploit = report_service.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 + + +def test_get_stolen_creds_system_info(fake_mongo, report_service): + fake_mongo.db.monkey.insert_one(MONKEY_TELEM) + fake_mongo.db.telemetry.insert_one(SYSTEM_INFO_TELEMETRY_TELEM) + + expected_stolen_creds_system_info = [ + {"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_system_info == stolen_creds_system_info + + +def test_get_stolen_creds_no_creds(fake_mongo, report_service): + fake_mongo.db.telemetry.insert_one(NO_CREDS_TELEMETRY_TELEM) + + stolen_creds_no_creds = report_service.get_stolen_creds() + expected_stolen_creds_no_creds = [] + + assert expected_stolen_creds_no_creds == stolen_creds_no_creds From d60ce37c5d86016f7939c88dce616f148ce4a86e Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Wed, 3 Mar 2021 08:22:32 -0500 Subject: [PATCH 5/6] cc: use fresh mongomock in each report test --- .../services/tests/reporting/test_report.py | 25 +++++++------------ 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/monkey/monkey_island/cc/services/tests/reporting/test_report.py b/monkey/monkey_island/cc/services/tests/reporting/test_report.py index 9c0321059..cc0ea321e 100644 --- a/monkey/monkey_island/cc/services/tests/reporting/test_report.py +++ b/monkey/monkey_island/cc/services/tests/reporting/test_report.py @@ -2,7 +2,7 @@ import mongomock import pytest from bson import ObjectId -import monkey_island.cc.database +from monkey_island.cc.services.reporting.report import ReportService TELEM_ID = { "exploit_creds": ObjectId(b"123456789000"), @@ -78,23 +78,15 @@ MONKEY_TELEM = {"_id": TELEM_ID["monkey"], "guid": MONKEY_GUID, "hostname": HOST @pytest.fixture def fake_mongo(monkeypatch): mongo = mongomock.MongoClient() - monkeypatch.setattr("monkey_island.cc.database.mongo", mongo) + monkeypatch.setattr("monkey_island.cc.services.reporting.report.mongo", mongo) + monkeypatch.setattr("monkey_island.cc.services.node.mongo", mongo) return mongo -@pytest.fixture -def report_service(): - # can't be imported before monkeypatching since mongo connection is made at module level - # see https://stackoverflow.com/a/51994349/ - from monkey_island.cc.services.reporting.report import ReportService - - return ReportService - - -def test_get_stolen_creds_exploit(fake_mongo, report_service): +def test_get_stolen_creds_exploit(fake_mongo): fake_mongo.db.telemetry.insert_one(EXPLOIT_TELEMETRY_TELEM) - stolen_creds_exploit = report_service.get_stolen_creds() + 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}, @@ -103,10 +95,11 @@ def test_get_stolen_creds_exploit(fake_mongo, report_service): assert expected_stolen_creds_exploit == stolen_creds_exploit -def test_get_stolen_creds_system_info(fake_mongo, report_service): +def test_get_stolen_creds_system_info(fake_mongo): fake_mongo.db.monkey.insert_one(MONKEY_TELEM) fake_mongo.db.telemetry.insert_one(SYSTEM_INFO_TELEMETRY_TELEM) + stolen_creds_system_info = ReportService.get_stolen_creds() expected_stolen_creds_system_info = [ {"origin": HOSTNAME, "type": "Clear Password", "username": USER}, {"origin": HOSTNAME, "type": "LM hash", "username": USER}, @@ -116,10 +109,10 @@ def test_get_stolen_creds_system_info(fake_mongo, report_service): assert expected_stolen_creds_system_info == stolen_creds_system_info -def test_get_stolen_creds_no_creds(fake_mongo, report_service): +def test_get_stolen_creds_no_creds(fake_mongo): fake_mongo.db.telemetry.insert_one(NO_CREDS_TELEMETRY_TELEM) - stolen_creds_no_creds = report_service.get_stolen_creds() + stolen_creds_no_creds = ReportService.get_stolen_creds() expected_stolen_creds_no_creds = [] assert expected_stolen_creds_no_creds == stolen_creds_no_creds From 243e07768747183b3c63918e297ed5e5acb4fc6e Mon Sep 17 00:00:00 2001 From: Shreya Date: Wed, 3 Mar 2021 18:59:47 +0530 Subject: [PATCH 6/6] Remove accidental debug statement --- monkey/monkey_island/cc/services/reporting/report.py | 1 - 1 file changed, 1 deletion(-) diff --git a/monkey/monkey_island/cc/services/reporting/report.py b/monkey/monkey_island/cc/services/reporting/report.py index d4e3886b9..5970a33b7 100644 --- a/monkey/monkey_island/cc/services/reporting/report.py +++ b/monkey/monkey_island/cc/services/reporting/report.py @@ -181,7 +181,6 @@ class ReportService: @staticmethod def get_stolen_creds(): - print(f"\n\n{list(mongo.db.telemetry.find())}\n\n") creds = [] stolen_system_info_creds = ReportService._get_credentials_from_system_info_telems()