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
This commit is contained in:
vakarisz 2022-03-01 11:31:47 +02:00
parent 4f58a69c54
commit 52c0413797
4 changed files with 131 additions and 203 deletions

View File

@ -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: {

View File

@ -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"]:

View File

@ -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)

View File

@ -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