Island: Simplify the report of scanned machines

This commit is contained in:
vakarisz 2022-09-30 11:46:05 +03:00 committed by Kekoa Kaaikala
parent 9a82e46799
commit 3d27e42ff3
2 changed files with 76 additions and 50 deletions

View File

@ -1,8 +1,8 @@
import functools import functools
import ipaddress import ipaddress
import logging import logging
from itertools import chain, filterfalse, product, tee from itertools import chain, product
from typing import Iterable, List, Optional from typing import List, Optional
from common.network.network_range import NetworkRange from common.network.network_range import NetworkRange
from common.network.network_utils import get_my_ip_addresses_legacy, get_network_interfaces from common.network.network_utils import get_my_ip_addresses_legacy, get_network_interfaces
@ -35,7 +35,6 @@ logger = logging.getLogger(__name__)
class ReportService: class ReportService:
_aws_service: Optional[AWSService] = None _aws_service: Optional[AWSService] = None
_agent_configuration_repository: Optional[IAgentConfigurationRepository] = None _agent_configuration_repository: Optional[IAgentConfigurationRepository] = None
_credentials_repository: Optional[ICredentialsRepository] = None _credentials_repository: Optional[ICredentialsRepository] = None
@ -113,58 +112,42 @@ class ReportService:
def get_scanned(): def get_scanned():
formatted_nodes = [] formatted_nodes = []
machines = ReportService.get_all_machines() machines = ReportService._machine_repository.get_machines()
for machine in machines: for machine in machines:
# This information should be evident from the map, not sure a table/list is a good way accessible_from = ReportService.get_scanners_of_machine(machine)
# to display it anyways if accessible_from:
addresses = [str(iface.ip) for iface in machine.network_interfaces] formatted_nodes.append(
accessible_machines = [ {
m.hostname for m in ReportService.get_accessible_machines(machine) "hostname": machine.hostname,
] "ip_addresses": machine.network_interfaces,
formatted_nodes.append( "accessible_from_nodes": accessible_from,
{ "domain_name": "",
"label": machine.hostname, # TODO add services
"ip_addresses": addresses, "services": [],
"accessible_from_nodes": accessible_machines, }
"services": [], )
"domain_name": "",
"pba_results": "None",
}
)
logger.info("Scanned nodes generated for reporting")
return formatted_nodes return formatted_nodes
@classmethod @classmethod
def get_accessible_machines(cls, machine: Machine): def get_scanners_of_machine(cls, machine: Machine) -> List[Machine]:
if cls._node_repository is None: if not cls._node_repository:
raise RuntimeError("Node repository does not exist") raise RuntimeError("Node repository does not exist")
elif cls._machine_repository is None: if not cls._machine_repository:
raise RuntimeError("Machine repository does not exist") raise RuntimeError("Machine repository does not exist")
nodes = cls._node_repository.get_nodes() nodes = cls._node_repository.get_nodes()
machine_iter = (node for node in nodes if node.machine_id == machine.id) scanner_machines = set()
accessible_machines = set() for node in nodes:
for source in machine_iter: for dest, conn in node.connections.items():
for dest, conn in source.connections.items(): if CommunicationType.SCANNED in conn and dest == machine.id:
if CommunicationType.SCANNED in conn: scanner_machine = ReportService._machine_repository.get_machine_by_id(
accessible_machines.add(dest) node.machine_id
)
scanner_machines.add(scanner_machine)
return [cls._machine_repository.get_machine_by_id(id) for id in accessible_machines] return list(scanner_machines)
@classmethod
def get_all_machines(cls) -> Iterable[Machine]:
if cls._machine_repository is None:
raise RuntimeError("Machine repository does not exist")
machines = cls._machine_repository.get_machines()
t1, t2 = tee(machines)
def is_island(machine: Machine):
return machine.island
return chain(filter(is_island, t1), filterfalse(is_island, t2))
@staticmethod @staticmethod
def process_exploit(exploit) -> ExploiterReportInfo: def process_exploit(exploit) -> ExploiterReportInfo:

View File

@ -1,34 +1,77 @@
from ipaddress import IPv4Interface from ipaddress import IPv4Interface
from unittest.mock import MagicMock
from monkey_island.cc.models import CommunicationType, Machine, Node from monkey_island.cc.models import CommunicationType, Machine, Node
from monkey_island.cc.services.reporting.report import ReportService
ISLAND_MACHINE = Machine( ISLAND_MACHINE = Machine(
id=99, id=99,
island=True, island=True,
hostname="Island",
hardware_id=5, hardware_id=5,
network_interfaces=[IPv4Interface("10.10.10.99/24")], network_interfaces=[IPv4Interface("10.10.10.99/24")],
) )
MACHINE_A = Machine( MACHINE_1 = Machine(
id=1, id=1,
hardware_id=9, hardware_id=9,
hostname="machine_1",
network_interfaces=[IPv4Interface("10.10.10.1/24")], network_interfaces=[IPv4Interface("10.10.10.1/24")],
) )
MACHINE_B = Machine( MACHINE_2 = Machine(
id=2, id=2,
hardware_id=9, hardware_id=9,
network_interfaces=[IPv4Interface("10.10.10.2/24")], network_interfaces=[IPv4Interface("10.10.10.2/24")],
) )
MACHINE_C = Machine( MACHINE_3 = Machine(
id=3, id=3,
hardware_id=9, hardware_id=9,
network_interfaces=[IPv4Interface("10.10.10.3/24")], network_interfaces=[IPv4Interface("10.10.10.3/24")],
) )
NODES = [ NODES = [
Node(machine_id=1, connections={"2": {CommunicationType.EXPLOITED}}), Node(
Node(machine_id=99, connections={"1": {CommunicationType.SCANNED}}), machine_id=1,
Node(machine_id=3, connections={"99": {CommunicationType.CC}}), connections={"2": frozenset([CommunicationType.EXPLOITED, CommunicationType.SCANNED])},
),
Node(machine_id=99, connections={"1": frozenset([CommunicationType.SCANNED])}),
Node(
machine_id=3,
connections={"99": frozenset([CommunicationType.CC, CommunicationType.EXPLOITED])},
),
] ]
MACHINES = [MACHINE_1, MACHINE_2, MACHINE_3, ISLAND_MACHINE]
EXPECTED_SCANNED_MACHINES = [
{
"hostname": MACHINE_1.hostname,
"ip_addresses": MACHINE_1.network_interfaces,
"accessible_from_nodes": [ISLAND_MACHINE],
"services": [],
"domain_name": "",
},
{
"hostname": MACHINE_2.hostname,
"ip_addresses": MACHINE_2.network_interfaces,
"accessible_from_nodes": [MACHINE_1],
"services": [],
"domain_name": "",
},
]
def get_machine_by_id(machine_id):
return [machine for machine in MACHINES if machine_id == machine.id][0]
def test_get_scanned():
ReportService._node_repository = MagicMock()
ReportService._node_repository.get_nodes.return_value = NODES
ReportService._machine_repository = MagicMock()
ReportService._machine_repository.get_machines.return_value = MACHINES
ReportService._machine_repository.get_machine_by_id = get_machine_by_id
scanned = ReportService.get_scanned()
assert scanned == EXPECTED_SCANNED_MACHINES