diff --git a/monkey/infection_monkey/agent_event_forwarder.py b/monkey/infection_monkey/agent_event_forwarder.py
index f253255d3..cf585a4bb 100644
--- a/monkey/infection_monkey/agent_event_forwarder.py
+++ b/monkey/infection_monkey/agent_event_forwarder.py
@@ -79,8 +79,8 @@ class BatchingAgentEventForwarder:
try:
logger.debug(f"Sending Agent events to Island: {events}")
self._island_api_client.send_events(events)
- except Exception as err:
- logger.warning(f"Exception caught when connecting to the Island: {err}")
+ except Exception:
+ logger.exception("Exception caught when connecting to the Island")
def _send_remaining_events(self):
self._send_events_to_island()
diff --git a/monkey/monkey_island/cc/models/machine.py b/monkey/monkey_island/cc/models/machine.py
index 99d4ae5eb..ece877b9e 100644
--- a/monkey/monkey_island/cc/models/machine.py
+++ b/monkey/monkey_island/cc/models/machine.py
@@ -38,3 +38,6 @@ class Machine(MutableInfectionMonkeyBaseModel):
_make_immutable_sequence = validator("network_interfaces", pre=True, allow_reuse=True)(
make_immutable_sequence
)
+
+ def __hash__(self):
+ return self.id
diff --git a/monkey/monkey_island/cc/services/initialize.py b/monkey/monkey_island/cc/services/initialize.py
index 40839c388..9e205e820 100644
--- a/monkey/monkey_island/cc/services/initialize.py
+++ b/monkey/monkey_island/cc/services/initialize.py
@@ -94,6 +94,8 @@ def initialize_services(container: DIContainer, data_dir: Path):
container.resolve(AWSService),
container.resolve(IAgentConfigurationRepository),
container.resolve(ICredentialsRepository),
+ container.resolve(IMachineRepository),
+ container.resolve(INodeRepository),
)
diff --git a/monkey/monkey_island/cc/services/reporting/report.py b/monkey/monkey_island/cc/services/reporting/report.py
index 52ed04df9..b3673dd90 100644
--- a/monkey/monkey_island/cc/services/reporting/report.py
+++ b/monkey/monkey_island/cc/services/reporting/report.py
@@ -2,15 +2,20 @@ import functools
import ipaddress
import logging
from itertools import chain, product
-from typing import List
+from typing import List, Optional
from common.network.network_range import NetworkRange
from common.network.network_utils import get_my_ip_addresses_legacy, get_network_interfaces
from common.network.segmentation_utils import get_ip_in_src_and_not_in_dst
from monkey_island.cc.database import mongo
-from monkey_island.cc.models import Monkey
+from monkey_island.cc.models import CommunicationType, Machine, Monkey
from monkey_island.cc.models.report import get_report, save_report
-from monkey_island.cc.repository import IAgentConfigurationRepository, ICredentialsRepository
+from monkey_island.cc.repository import (
+ IAgentConfigurationRepository,
+ ICredentialsRepository,
+ IMachineRepository,
+ INodeRepository,
+)
from monkey_island.cc.services.node import NodeService
from monkey_island.cc.services.reporting.exploitations.manual_exploitation import get_manual_monkeys
from monkey_island.cc.services.reporting.exploitations.monkey_exploitation import (
@@ -30,10 +35,11 @@ logger = logging.getLogger(__name__)
class ReportService:
-
- _aws_service = None
- _agent_configuration_repository = None
- _credentials_repository = None
+ _aws_service: Optional[AWSService] = None
+ _agent_configuration_repository: Optional[IAgentConfigurationRepository] = None
+ _credentials_repository: Optional[ICredentialsRepository] = None
+ _machine_repository: Optional[IMachineRepository] = None
+ _node_repository: Optional[INodeRepository] = None
class DerivedIssueEnum:
ZEROLOGON_PASS_RESTORE_FAILED = "zerologon_pass_restore_failed"
@@ -44,10 +50,14 @@ class ReportService:
aws_service: AWSService,
agent_configuration_repository: IAgentConfigurationRepository,
credentials_repository: ICredentialsRepository,
+ machine_repository: IMachineRepository,
+ node_repository: INodeRepository,
):
cls._aws_service = aws_service
cls._agent_configuration_repository = agent_configuration_repository
cls._credentials_repository = credentials_repository
+ cls._machine_repository = machine_repository
+ cls._node_repository = node_repository
# This should pull from Simulation entity
@staticmethod
@@ -102,39 +112,42 @@ class ReportService:
def get_scanned():
formatted_nodes = []
- nodes = ReportService.get_all_displayed_nodes()
+ machines = ReportService._machine_repository.get_machines()
- for node in nodes:
- # This information should be evident from the map, not sure a table/list is a good way
- # to display it anyways
- nodes_that_can_access_current_node = node["accessible_from_nodes_hostnames"]
- formatted_nodes.append(
- {
- "label": node["label"],
- "ip_addresses": node["ip_addresses"],
- "accessible_from_nodes": nodes_that_can_access_current_node,
- "services": node["services"],
- "domain_name": node["domain_name"],
- "pba_results": node["pba_results"] if "pba_results" in node else "None",
- }
- )
-
- logger.info("Scanned nodes generated for reporting")
+ for machine in machines:
+ accessible_from = ReportService.get_scanners_of_machine(machine)
+ if accessible_from:
+ formatted_nodes.append(
+ {
+ "hostname": machine.hostname,
+ "ip_addresses": [str(iface.ip) for iface in machine.network_interfaces],
+ "accessible_from_nodes": [m.dict(simplify=True) for m in accessible_from],
+ "domain_name": "",
+ # TODO add services
+ "services": [],
+ }
+ )
return formatted_nodes
- @staticmethod
- def get_all_displayed_nodes():
- nodes_without_monkeys = [
- NodeService.get_displayed_node_by_id(node["_id"], True)
- for node in mongo.db.node.find({}, {"_id": 1})
- ]
- nodes_with_monkeys = [
- NodeService.get_displayed_node_by_id(monkey["_id"], True)
- for monkey in mongo.db.monkey.find({}, {"_id": 1})
- ]
- nodes = nodes_without_monkeys + nodes_with_monkeys
- return nodes
+ @classmethod
+ def get_scanners_of_machine(cls, machine: Machine) -> List[Machine]:
+ if not cls._node_repository:
+ raise RuntimeError("Node repository does not exist")
+ if not cls._machine_repository:
+ raise RuntimeError("Machine repository does not exist")
+
+ nodes = cls._node_repository.get_nodes()
+ scanner_machines = set()
+ for node in nodes:
+ for dest, conn in node.connections.items():
+ if CommunicationType.SCANNED in conn and dest == machine.id:
+ scanner_machine = ReportService._machine_repository.get_machine_by_id(
+ node.machine_id
+ )
+ scanner_machines.add(scanner_machine)
+
+ return list(scanner_machines)
@staticmethod
def process_exploit(exploit) -> ExploiterReportInfo:
diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/SecurityReport.js b/monkey/monkey_island/cc/ui/src/components/report-components/SecurityReport.js
index fd1accfb8..ba3f53232 100644
--- a/monkey/monkey_island/cc/ui/src/components/report-components/SecurityReport.js
+++ b/monkey/monkey_island/cc/ui/src/components/report-components/SecurityReport.js
@@ -2,7 +2,6 @@ import React, {Fragment} from 'react';
import Pluralize from 'pluralize';
import BreachedServers from 'components/report-components/security/BreachedServers';
import ScannedServers from 'components/report-components/security/ScannedServers';
-import PostBreach from 'components/report-components/security/PostBreach';
import {ReactiveGraph} from 'components/reactive-graph/ReactiveGraph';
import {edgeGroupToColor, getOptions} from 'components/map/MapOptions';
import StolenPasswords from 'components/report-components/security/StolenPasswords';
@@ -23,7 +22,7 @@ import {smbPasswordReport, smbPthReport} from './security/issues/SmbIssue';
import {hadoopIssueOverview, hadoopIssueReport} from './security/issues/HadoopIssue';
import {mssqlIssueOverview, mssqlIssueReport} from './security/issues/MssqlIssue';
import {wmiPasswordIssueReport, wmiPthIssueReport} from './security/issues/WmiIssue';
-import {sshKeysReport, shhIssueReport, sshIssueOverview} from './security/issues/SshIssue';
+import {shhIssueReport, sshIssueOverview, sshKeysReport} from './security/issues/SshIssue';
import {log4shellIssueOverview, log4shellIssueReport} from './security/issues/Log4ShellIssue';
import {
crossSegmentIssueOverview,
@@ -31,11 +30,13 @@ import {
islandCrossSegmentIssueReport
} from './security/issues/CrossSegmentIssue';
import {
- sharedCredsDomainIssueReport, sharedCredsIssueReport, sharedLocalAdminsIssueReport,
sharedAdminsDomainIssueOverview,
+ sharedCredsDomainIssueReport,
+ sharedCredsIssueReport,
+ sharedLocalAdminsIssueReport,
sharedPasswordsIssueOverview
} from './security/issues/SharedPasswordsIssue';
-import {tunnelIssueReport, tunnelIssueOverview} from './security/issues/TunnelIssue';
+import {tunnelIssueOverview, tunnelIssueReport} from './security/issues/TunnelIssue';
import {stolenCredsIssueOverview} from './security/issues/StolenCredsIssue';
import {strongUsersOnCritIssueReport} from './security/issues/StrongUsersOnCritIssue';
import {
@@ -538,9 +539,11 @@ class ReportPageComponent extends AuthComponent {