forked from p15670423/monkey
Agent: Change scanners to use the config object
This commit is contained in:
parent
6b406ef686
commit
ffe8c3451b
|
@ -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,
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Reference in New Issue