Merge pull request #1728 from guardicore/1605-modify-exploit-result-data

Modify ExploiterResultData
This commit is contained in:
Shreya Malviya 2022-02-22 20:38:22 +05:30 committed by GitHub
commit 96bd7bca24
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 87 additions and 50 deletions

View File

@ -1,7 +1,6 @@
import glob
import logging
import os
import pwd
from typing import Dict, Iterable
from common.utils.attack_utils import ScanStatus
@ -30,6 +29,8 @@ def get_ssh_info(telemetry_messenger: ITelemetryMessenger) -> Iterable[Dict]:
def _get_home_dirs() -> Iterable[Dict]:
import pwd
root_dir = _get_ssh_struct("root", "")
home_dirs = [
_get_ssh_struct(x.pw_name, x.pw_dir) for x in pwd.getpwall() if x.pw_dir.startswith("/home")

View File

@ -51,7 +51,7 @@ class HostExploiter:
def send_exploit_telemetry(self, name: str, result: bool):
from infection_monkey.telemetry.exploit_telem import ExploitTelem
ExploitTelem(
ExploitTelem( # stale code
name=name,
host=self.host,
result=result,

View File

@ -17,7 +17,8 @@ class UnknownPluginError(Exception):
ExploiterResultData = namedtuple(
"ExploiterResultData", ["success", "info", "attempts", "error_message"]
"ExploiterResultData",
["exploitation_success", "propagation_success", "os", "info", "attempts", "error_message"],
)
PingScanData = namedtuple("PingScanData", ["response_received", "os"])
PortScanData = namedtuple("PortScanData", ["port", "status", "banner", "service"])

View File

@ -104,7 +104,7 @@ class Exploiter:
)
results_callback(exploiter_name, victim_host, exploiter_results)
if exploiter_name != "ZerologonExploiter" and exploiter_results.success:
if exploiter_results.propagation_success:
break
def _run_exploiter(

View File

@ -101,20 +101,16 @@ class MockMaster(IMaster):
def _exploit(self):
logger.info("Exploiting victims")
result, info, attempts, error_message = self._puppet.exploit_host(
"PowerShellExploiter", "10.0.0.1", {}, None
)
logger.info(f"Attempts for exploiting {attempts}")
result = self._puppet.exploit_host("PowerShellExploiter", "10.0.0.1", {}, None)
logger.info(f"Attempts for exploiting {result.attempts}")
self._telemetry_messenger.send_telemetry(
ExploitTelem("PowerShellExploiter", self._hosts["10.0.0.1"], result, info, attempts)
ExploitTelem("PowerShellExploiter", self._hosts["10.0.0.1"], result)
)
result, info, attempts, error_message = self._puppet.exploit_host(
"SSHExploiter", "10.0.0.3", {}, None
)
logger.info(f"Attempts for exploiting {attempts}")
result = self._puppet.exploit_host("SSHExploiter", "10.0.0.3", {}, None)
logger.info(f"Attempts for exploiting {result.attempts}")
self._telemetry_messenger.send_telemetry(
ExploitTelem("SSHExploiter", self._hosts["10.0.0.3"], result, info, attempts)
ExploitTelem("SSHExploiter", self._hosts["10.0.0.3"], result)
)
logger.info("Finished exploiting victims")

View File

@ -153,13 +153,16 @@ class Propagator:
def _process_exploit_attempts(
self, exploiter_name: str, host: VictimHost, result: ExploiterResultData
):
if result.success:
if result.propagation_success:
logger.info(f"Successfully propagated to {host} using {exploiter_name}")
elif result.exploitation_success:
logger.info(
f"Successfully exploited (but did not propagate to) {host} using {exploiter_name}"
)
else:
logger.info(
f"Failed to propagate to {host} using {exploiter_name}: {result.error_message}"
f"Failed to exploit or propagate to {host} using {exploiter_name}: "
f"{result.error_message}"
)
self._telemetry_messenger.send_telemetry(
ExploitTelem(exploiter_name, host, result.success, result.info, result.attempts)
)
self._telemetry_messenger.send_telemetry(ExploitTelem(exploiter_name, host, result))

View File

@ -177,25 +177,43 @@ class MockPuppet(IPuppet):
"vulnerable_ports": [22],
"executed_cmds": [],
}
os_windows = "windows"
os_linux = "linux"
successful_exploiters = {
DOT_1: {
"PowerShellExploiter": ExploiterResultData(True, info_powershell, attempts, None),
"ZerologonExploiter": ExploiterResultData(False, {}, [], "Zerologon failed"),
"SSHExploiter": ExploiterResultData(False, info_ssh, attempts, "Failed exploiting"),
"PowerShellExploiter": ExploiterResultData(
True, True, os_windows, info_powershell, attempts, None
),
"ZerologonExploiter": ExploiterResultData(
False, False, os_windows, {}, [], "Zerologon failed"
),
"SSHExploiter": ExploiterResultData(
False, False, os_linux, info_ssh, attempts, "Failed exploiting"
),
},
DOT_3: {
"PowerShellExploiter": ExploiterResultData(
False, info_powershell, attempts, "PowerShell Exploiter Failed"
False,
False,
os_windows,
info_powershell,
attempts,
"PowerShell Exploiter Failed",
),
"SSHExploiter": ExploiterResultData(False, info_ssh, attempts, "Failed exploiting"),
"ZerologonExploiter": ExploiterResultData(True, {}, [], None),
"SSHExploiter": ExploiterResultData(
False, False, os_linux, info_ssh, attempts, "Failed exploiting"
),
"ZerologonExploiter": ExploiterResultData(True, False, os_windows, {}, [], None),
},
}
try:
return successful_exploiters[host][name]
except KeyError:
return ExploiterResultData(False, {}, [], f"{name} failed for host {host}")
return ExploiterResultData(
False, False, os_linux, {}, [], f"{name} failed for host {host}"
)
def run_payload(self, name: str, options: Dict, interrupt: threading.Event):
logger.debug(f"run_payload({name}, {options})")

View File

@ -1,33 +1,39 @@
from typing import Dict, List
from typing import Dict
from common.common_consts.telem_categories import TelemCategoryEnum
from infection_monkey.model.host import VictimHost
from infection_monkey.telemetry.base_telem import BaseTelem
from monkey.infection_monkey.i_puppet.i_puppet import ExploiterResultData
class ExploitTelem(BaseTelem):
def __init__(self, name: str, host: VictimHost, result: bool, info: Dict, attempts: List):
def __init__(
self,
name: str,
host: VictimHost,
result: ExploiterResultData,
):
"""
Default exploit telemetry constructor
:param name: The name of exploiter used
:param host: The host machine
:param result: The result from the 'exploit_host' method
:param info: Information about the exploiter
:param attempts: Information about the exploiter's attempts
:param result: Data about the exploitation (success status, info, attempts, etc)
"""
super(ExploitTelem, self).__init__()
self.name = name
self.host = host.__dict__
self.result = result
self.info = info
self.attempts = attempts
self.exploitation_result = result.exploitation_success
self.propagation_result = result.propagation_success
self.info = result.info
self.attempts = result.attempts
telem_category = TelemCategoryEnum.EXPLOIT
def get_data(self) -> Dict:
return {
"result": self.result,
"exploitation_result": self.exploitation_result,
"propagation_result": self.propagation_result,
"machine": self.host,
"exploiter": self.name,
"info": self.info,

View File

@ -78,7 +78,7 @@ class EdgeService(Edge):
def update_based_on_exploit(self, exploit: Dict):
self.exploits.append(exploit)
self.save()
if exploit["result"]:
if exploit["exploitation_success"]:
self.set_exploited()
def set_exploited(self):

View File

@ -24,7 +24,7 @@ def process_exploit_telemetry(telemetry_json):
check_machine_exploited(
current_monkey=Monkey.get_single_monkey_by_guid(telemetry_json["monkey_guid"]),
exploit_successful=telemetry_json["data"]["result"],
exploit_successful=telemetry_json["data"]["exploitation_success"],
exploiter=telemetry_json["data"]["exploiter"],
target_ip=telemetry_json["data"]["machine"]["ip_addr"],
timestamp=telemetry_json["timestamp"],
@ -65,7 +65,7 @@ def update_network_with_exploit(edge: EdgeService, telemetry_json):
new_exploit.pop("machine")
new_exploit["timestamp"] = telemetry_json["timestamp"]
edge.update_based_on_exploit(new_exploit)
if new_exploit["result"]:
if new_exploit["exploitation_success"]:
NodeService.set_node_exploited(edge.dst_node_id)

View File

@ -100,6 +100,10 @@ dot_3_services = {
},
}
os_windows = "windows"
os_linux = "linux"
@pytest.fixture
def mock_ip_scanner():
@ -184,34 +188,38 @@ class MockExploiter:
results_callback(
"PowerShellExploiter",
host,
ExploiterResultData(True, {}, {}, None),
ExploiterResultData(True, True, os_windows, {}, {}, None),
)
results_callback(
"SSHExploiter",
host,
ExploiterResultData(False, {}, {}, "SSH FAILED for .1"),
ExploiterResultData(False, False, os_linux, {}, {}, "SSH FAILED for .1"),
)
elif host.ip_addr.endswith(".2"):
results_callback(
"PowerShellExploiter",
host,
ExploiterResultData(False, {}, {}, "POWERSHELL FAILED for .2"),
ExploiterResultData(
False, False, os_windows, {}, {}, "POWERSHELL FAILED for .2"
),
)
results_callback(
"SSHExploiter",
host,
ExploiterResultData(False, {}, {}, "SSH FAILED for .2"),
ExploiterResultData(False, False, os_linux, {}, {}, "SSH FAILED for .2"),
)
elif host.ip_addr.endswith(".3"):
results_callback(
"PowerShellExploiter",
host,
ExploiterResultData(False, {}, {}, "POWERSHELL FAILED for .3"),
ExploiterResultData(
False, False, os_windows, {}, {}, "POWERSHELL FAILED for .3"
),
)
results_callback(
"SSHExploiter",
host,
ExploiterResultData(True, {}, {}, None),
ExploiterResultData(True, True, os_linux, {}, {}, None),
)
@ -246,14 +254,14 @@ def test_exploiter_result_processing(
if ip.endswith(".1"):
if data["exploiter"].startswith("PowerShell"):
assert data["result"]
assert data["propagation_result"]
else:
assert not data["result"]
assert not data["propagation_result"]
elif ip.endswith(".3"):
if data["exploiter"].startswith("PowerShell"):
assert not data["result"]
assert not data["propagation_result"]
else:
assert data["result"]
assert data["propagation_result"]
def test_scan_target_generation(telemetry_messenger_spy, mock_ip_scanner, mock_victim_host_factory):

View File

@ -5,6 +5,7 @@ import pytest
from infection_monkey.exploit.sshexec import SSHExploiter
from infection_monkey.model.host import VictimHost
from infection_monkey.telemetry.exploit_telem import ExploitTelem
from monkey.infection_monkey.i_puppet.i_puppet import ExploiterResultData
DOMAIN_NAME = "domain-name"
IP = "0.0.0.0"
@ -30,17 +31,20 @@ EXPLOITER_INFO = {
}
EXPLOITER_ATTEMPTS = []
RESULT = False
OS_LINUX = "linux"
ERROR_MSG = "failed because yolo"
@pytest.fixture
def exploit_telem_test_instance():
return ExploitTelem(EXPLOITER_NAME, HOST, RESULT, EXPLOITER_INFO, EXPLOITER_ATTEMPTS)
return ExploitTelem(EXPLOITER_NAME, HOST, ExploiterResultData(RESULT, RESULT, OS_LINUX, EXPLOITER_INFO, EXPLOITER_ATTEMPTS, ERROR_MSG))
def test_exploit_telem_send(exploit_telem_test_instance, spy_send_telemetry):
exploit_telem_test_instance.send()
expected_data = {
"result": RESULT,
"exploitation_result": RESULT,
"propagation_result": RESULT,
"machine": HOST_AS_DICT,
"exploiter": EXPLOITER_NAME,
"info": EXPLOITER_INFO,