Agent: Change scanners to use the config object

This commit is contained in:
vakarisz 2022-06-21 16:15:54 +03:00 committed by Mike Salvatore
parent 6b406ef686
commit ffe8c3451b
6 changed files with 130 additions and 87 deletions

View File

@ -2,6 +2,18 @@ from .agent_configuration import (
AgentConfiguration,
AgentConfigurationSchema,
)
from .agent_sub_configurations import (
CustomPBAConfiguration,
PluginConfiguration,
ScanTargetConfiguration,
ICMPScanConfiguration,
TCPScanConfiguration,
NetworkScanConfiguration,
ExploitationOptionsConfiguration,
ExploiterConfiguration,
ExploitationConfiguration,
PropagationConfiguration,
)
from .default_agent_configuration import (
DEFAULT_AGENT_CONFIGURATION_JSON,
build_default_agent_configuration,

View File

@ -174,7 +174,7 @@ class AutomatedMaster(IMaster):
logger.info(f"Current depth is {current_depth}")
if should_propagate(self._control_channel.get_config(), self._current_depth):
self._propagator.propagate(config["propagation"], current_depth, self._stop)
self._propagator.propagate(config.propagation, current_depth, self._stop)
else:
logger.info("Skipping propagation: maximum depth reached")

View File

@ -3,8 +3,13 @@ import queue
import threading
from queue import Queue
from threading import Event
from typing import Any, Callable, Dict, List
from typing import Callable, Dict, List
from common.configuration.agent_sub_configurations import (
NetworkScanConfiguration,
PluginConfiguration,
ScanTargetConfiguration,
)
from infection_monkey.i_puppet import (
FingerprintData,
IPuppet,
@ -30,7 +35,7 @@ class IPScanner:
def scan(
self,
addresses_to_scan: List[NetworkAddress],
options: Dict,
options: ScanTargetConfiguration,
results_callback: Callback,
stop: Event,
):
@ -49,12 +54,16 @@ class IPScanner:
)
def _scan_addresses(
self, addresses: Queue, options: Dict, results_callback: Callback, stop: Event
self,
addresses: Queue,
options: NetworkScanConfiguration,
results_callback: Callback,
stop: Event,
):
logger.debug(f"Starting scan thread -- Thread ID: {threading.get_ident()}")
icmp_timeout = options["icmp"]["timeout_ms"] / 1000
tcp_timeout = options["tcp"]["timeout_ms"] / 1000
tcp_ports = options["tcp"]["ports"]
logger.debug(f"Starting scan .read -- Thread ID: {threading.get_ident()}")
icmp_timeout = options.icmp.timeout
tcp_timeout = options.tcp.timeout
tcp_ports = options.tcp.ports
try:
while not stop.is_set():
@ -66,7 +75,7 @@ class IPScanner:
fingerprint_data = {}
if IPScanner.port_scan_found_open_port(port_scan_data):
fingerprinters = options["fingerprinters"]
fingerprinters = options.fingerprinters
fingerprint_data = self._run_fingerprinters(
address.ip, fingerprinters, ping_scan_data, port_scan_data, stop
)
@ -90,7 +99,7 @@ class IPScanner:
def _run_fingerprinters(
self,
ip: str,
fingerprinters: List[Dict[str, Any]],
fingerprinters: List[PluginConfiguration],
ping_scan_data: PingScanData,
port_scan_data: Dict[int, PortScanData],
stop: Event,
@ -98,8 +107,8 @@ class IPScanner:
fingerprint_data = {}
for f in interruptible_iter(fingerprinters, stop):
fingerprint_data[f["name"]] = self._puppet.fingerprint(
f["name"], ip, ping_scan_data, port_scan_data, f["options"]
fingerprint_data[f.name] = self._puppet.fingerprint(
f.name, ip, ping_scan_data, port_scan_data, f.options
)
return fingerprint_data

View File

@ -3,6 +3,8 @@ from queue import Queue
from threading import Event
from typing import Dict, List
from common.configuration import PropagationConfiguration,\
NetworkScanConfiguration, ScanTargetConfiguration
from infection_monkey.i_puppet import (
ExploiterResultData,
FingerprintData,
@ -39,14 +41,18 @@ class Propagator:
self._local_network_interfaces = local_network_interfaces
self._hosts_to_exploit = None
def propagate(self, propagation_config: Dict, current_depth: int, stop: Event):
def propagate(
self, propagation_config: PropagationConfiguration, current_depth: int, stop: Event
):
logger.info("Attempting to propagate")
network_scan_completed = Event()
self._hosts_to_exploit = Queue()
scan_thread = create_daemon_thread(
target=self._scan_network, name="PropagatorScanThread", args=(propagation_config, stop)
target=self._scan_network,
name="PropagatorScanThread",
args=(propagation_config.network_scan, stop),
)
exploit_thread = create_daemon_thread(
target=self._exploit_hosts,
@ -64,22 +70,21 @@ class Propagator:
logger.info("Finished attempting to propagate")
def _scan_network(self, propagation_config: Dict, stop: Event):
def _scan_network(self, scan_config: NetworkScanConfiguration, stop: Event):
logger.info("Starting network scan")
target_config = propagation_config["targets"]
scan_config = propagation_config["network_scan"]
addresses_to_scan = self._compile_scan_target_list(target_config)
addresses_to_scan = self._compile_scan_target_list(scan_config.targets)
self._ip_scanner.scan(addresses_to_scan, scan_config, self._process_scan_results, stop)
logger.info("Finished network scan")
def _compile_scan_target_list(self, target_config: Dict) -> List[NetworkAddress]:
ranges_to_scan = target_config["subnet_scan_list"]
inaccessible_subnets = target_config["inaccessible_subnets"]
blocklisted_ips = target_config["blocked_ips"]
enable_local_network_scan = target_config["local_network_scan"]
def _compile_scan_target_list(
self, target_config: ScanTargetConfiguration
) -> List[NetworkAddress]:
ranges_to_scan = target_config.subnets
inaccessible_subnets = target_config.inaccessible_subnets
blocklisted_ips = target_config.blocked_ips
enable_local_network_scan = target_config.local_network_scan
return compile_scan_target_list(
self._local_network_interfaces,

View File

@ -5,6 +5,12 @@ from unittest.mock import MagicMock
import pytest
from tests.unit_tests.infection_monkey.master.mock_puppet import MockPuppet
from common.configuration.agent_sub_configurations import (
ICMPScanConfiguration,
NetworkScanConfiguration,
PluginConfiguration,
TCPScanConfiguration,
)
from infection_monkey.i_puppet import FingerprintData, PortScanData, PortStatus
from infection_monkey.master import IPScanner
from infection_monkey.network import NetworkAddress
@ -14,28 +20,31 @@ LINUX_OS = "linux"
@pytest.fixture
def scan_config():
return {
"tcp": {
"timeout_ms": 3000,
"ports": [
22,
445,
3389,
443,
8008,
3306,
],
},
"icmp": {
"timeout_ms": 1000,
},
"fingerprinters": [
{"name": "HTTPFinger", "options": {}},
{"name": "SMBFinger", "options": {}},
{"name": "SSHFinger", "options": {}},
def scan_config(default_agent_config):
tcp_config = TCPScanConfiguration(
timeout=3,
ports=[
22,
445,
3389,
443,
8008,
3306,
],
}
)
icmp_config = ICMPScanConfiguration(timeout=1)
fingerprinter_config = [
PluginConfiguration(name="HTTPFinger", options={}),
PluginConfiguration(name="SMBFinger", options={}),
PluginConfiguration(name="SSHFinger", options={}),
]
scan_config = NetworkScanConfiguration(
tcp_config,
icmp_config,
fingerprinter_config,
default_agent_config.propagation.network_scan.targets,
)
return scan_config
@pytest.fixture

View File

@ -3,6 +3,11 @@ from unittest.mock import MagicMock
import pytest
from common.configuration.agent_sub_configurations import (
NetworkScanConfiguration,
PropagationConfiguration,
ScanTargetConfiguration,
)
from infection_monkey.i_puppet import (
ExploiterResultData,
FingerprintData,
@ -135,24 +140,35 @@ class StubExploiter:
pass
def test_scan_result_processing(telemetry_messenger_spy, mock_ip_scanner, mock_victim_host_factory):
def get_propagation_config(default_agent_config, scan_target_config: ScanTargetConfiguration):
network_scan = NetworkScanConfiguration(
default_agent_config.propagation.network_scan.tcp,
default_agent_config.propagation.network_scan.icmp,
default_agent_config.propagation.network_scan.fingerprinters,
scan_target_config,
)
propagation_config = PropagationConfiguration(
default_agent_config.propagation.maximum_depth,
network_scan,
default_agent_config.propagation.exploitation,
)
return propagation_config
def test_scan_result_processing(
telemetry_messenger_spy, mock_ip_scanner, mock_victim_host_factory, default_agent_config
):
p = Propagator(
telemetry_messenger_spy, mock_ip_scanner, StubExploiter(), mock_victim_host_factory, []
)
p.propagate(
{
"targets": {
"subnet_scan_list": ["10.0.0.1", "10.0.0.2", "10.0.0.3"],
"local_network_scan": False,
"inaccessible_subnets": [],
"blocked_ips": [],
},
"network_scan": {}, # This is empty since MockIPscanner ignores it
"exploiters": {}, # This is empty since StubExploiter ignores it
},
1,
Event(),
targets = ScanTargetConfiguration(
blocked_ips=[],
inaccessible_subnets=[],
local_network_scan=False,
subnets=["10.0.0.1", "10.0.0.2", "10.0.0.3"],
)
propagation_config = get_propagation_config(default_agent_config, targets)
p.propagate(propagation_config, 1, Event())
assert len(telemetry_messenger_spy.telemetries) == 3
@ -237,25 +253,20 @@ class MockExploiter:
def test_exploiter_result_processing(
telemetry_messenger_spy, mock_ip_scanner, mock_victim_host_factory
telemetry_messenger_spy, mock_ip_scanner, mock_victim_host_factory, default_agent_config
):
p = Propagator(
telemetry_messenger_spy, mock_ip_scanner, MockExploiter(), mock_victim_host_factory, []
)
p.propagate(
{
"targets": {
"subnet_scan_list": ["10.0.0.1", "10.0.0.2", "10.0.0.3"],
"local_network_scan": False,
"inaccessible_subnets": [],
"blocked_ips": [],
},
"network_scan": {}, # This is empty since MockIPscanner ignores it
"exploiters": {}, # This is empty since MockExploiter ignores it
},
1,
Event(),
targets = ScanTargetConfiguration(
blocked_ips=[],
inaccessible_subnets=[],
local_network_scan=False,
subnets=["10.0.0.1", "10.0.0.2", "10.0.0.3"],
)
propagation_config = get_propagation_config(default_agent_config, targets)
p.propagate(propagation_config, 1, Event())
exploit_telems = [t for t in telemetry_messenger_spy.telemetries if isinstance(t, ExploitTelem)]
assert len(exploit_telems) == 4
@ -278,7 +289,9 @@ def test_exploiter_result_processing(
assert data["propagation_result"]
def test_scan_target_generation(telemetry_messenger_spy, mock_ip_scanner, mock_victim_host_factory):
def test_scan_target_generation(
telemetry_messenger_spy, mock_ip_scanner, mock_victim_host_factory, default_agent_config
):
local_network_interfaces = [NetworkInterface("10.0.0.9", "/29")]
p = Propagator(
telemetry_messenger_spy,
@ -287,20 +300,15 @@ def test_scan_target_generation(telemetry_messenger_spy, mock_ip_scanner, mock_v
mock_victim_host_factory,
local_network_interfaces,
)
p.propagate(
{
"targets": {
"subnet_scan_list": ["10.0.0.0/29", "172.10.20.30"],
"local_network_scan": True,
"blocked_ips": ["10.0.0.3"],
"inaccessible_subnets": ["10.0.0.128/30", "10.0.0.8/29"],
},
"network_scan": {}, # This is empty since MockIPscanner ignores it
"exploiters": {}, # This is empty since MockExploiter ignores it
},
1,
Event(),
targets = ScanTargetConfiguration(
blocked_ips=["10.0.0.3"],
inaccessible_subnets=["10.0.0.128/30", "10.0.0.8/29"],
local_network_scan=True,
subnets=["10.0.0.0/29", "172.10.20.30"],
)
propagation_config = get_propagation_config(default_agent_config, targets)
p.propagate(propagation_config, 1, Event())
expected_ip_scan_list = [
"10.0.0.0",
"10.0.0.1",