Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate report with remediation_suggestion #2885

Merged
merged 30 commits into from
Jan 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
725a380
UI: Add react-markdown
shreyamalviya Jan 25, 2023
6ae6aa2
UI: Show remediation_suggestions for issues in security report
shreyamalviya Jan 25, 2023
7d64588
UI: Add TODO comment about react-markdown
shreyamalviya Jan 25, 2023
d82fa37
UI: Use hard-coded report component generators if issue isn't in reme…
shreyamalviya Jan 25, 2023
42a97c3
UI: Remove unused imports in SecurityReport.js
shreyamalviya Jan 25, 2023
cc400de
UI: Remove issue overview functions from SecurityReport.js
shreyamalviya Jan 25, 2023
f7806cd
UI: Remove unused report functions
shreyamalviya Jan 25, 2023
2116cbd
UI: Remove exploiter report issue files
shreyamalviya Jan 25, 2023
ccb9b6d
UI: Add machines IPs to bullet header in security report
shreyamalviya Jan 25, 2023
1ab3fe7
UI: Add collapsible component to plugin remediations in security report
shreyamalviya Jan 25, 2023
aae368d
UI: Add remark-breaks package to support line-breaks in markdown
VakarisZ Jan 26, 2023
e5694d2
UI: Improve remediation code
VakarisZ Jan 26, 2023
b260b9f
UI: Style markdown links in security report
VakarisZ Jan 26, 2023
03c5c76
UI: Display plugin description in the report
VakarisZ Jan 26, 2023
0867b93
UI: Fix a bug in remediation generation
VakarisZ Jan 26, 2023
e969f65
UI: Remove unused paragraph in security report overview
VakarisZ Jan 27, 2023
cc3db43
Common: Fix a typo in SSH manifest
VakarisZ Jan 27, 2023
045b73a
UI: Reintroduce segmentation issues into report
VakarisZ Jan 27, 2023
06d0172
Island: Remove "issue_set" from report
VakarisZ Jan 27, 2023
6af6998
UI: Remove unused issue code
VakarisZ Jan 27, 2023
58a2de7
Island: Remove island cross-segmentation issue
VakarisZ Jan 27, 2023
4954577
Island: Fix zerologon password restoration view
VakarisZ Jan 27, 2023
cb3aa60
Island: Remove some unused code
VakarisZ Jan 27, 2023
d53d402
UT: Fix add_remediation_to_issue tests
VakarisZ Jan 27, 2023
260a3e0
CHANGELOG: Add entry about report refactoring
VakarisZ Jan 27, 2023
efc8ea0
UI: Change double-quotes to single-quotes in SecurityReport.js
ilija-lazoroski Jan 27, 2023
778154e
UI: Remove children prop from ReactMarkdown and add data between tags
ilija-lazoroski Jan 27, 2023
78dcccd
UI: Remove leftover overview issues logic in SecurityReport.js
shreyamalviya Jan 31, 2023
fa8eb9d
UI: Make headings of sub-sections in security report uniform in size
shreyamalviya Jan 31, 2023
b21d995
UI: Fix eslint warnings in SecurityReport.js
shreyamalviya Jan 31, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ Changelog](https://keepachangelog.com/en/1.0.0/).
- Reset workflow. Now it's possible to delete data gathered by agents without
resetting the configuration and reset procedure requires fewer clicks. #957
- Reduced the map refresh rate from 5 seconds to 1.
- Cleaned up and removed duplication in security report. #2885
- The setup procedure for custom server_config.json files to be simpler. #1576
- The order and content of Monkey Island's initialization logging to give
clearer instructions to the user and avoid confusion. #1684
Expand Down
2 changes: 1 addition & 1 deletion monkey/common/hard_coded_exploiter_manifests.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@
target_operating_systems=(OperatingSystem.LINUX,),
title="SSH Exploiter",
version="1.0.0",
description="Attempts a brute-force attack against SMB using known credentials, "
description="Attempts a brute-force attack against SSH using known credentials, "
"including SSH keys",
link_to_documentation="https://www.guardicore.com/infectionmonkey/docs/reference/"
"exploiters/sshexec/",
Expand Down
4 changes: 0 additions & 4 deletions monkey/common/network/network_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@
from netifaces import AF_INET, ifaddresses, interfaces


def get_my_ip_addresses_legacy() -> Sequence[str]:
return [str(ip) for ip in get_my_ip_addresses()]


def get_my_ip_addresses() -> Sequence[IPv4Address]:
return [interface.ip for interface in get_network_interfaces()]

Expand Down

This file was deleted.

76 changes: 15 additions & 61 deletions monkey/monkey_island/cc/services/reporting/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
)
from common.agent_plugins import AgentPluginManifest, AgentPluginType
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_if_in_subnet
from common.types import PortStatus
from monkey_island.cc.models import CommunicationType, Machine
Expand All @@ -37,7 +36,6 @@
get_monkey_exploited,
)

from .issue_processing.exploit_processing.exploiter_descriptor_enum import ExploiterDescriptorEnum
from .issue_processing.exploit_processing.exploiter_report_info import ExploiterReportInfo

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -73,9 +71,6 @@ class ReportService:
_report: Dict[str, Dict] = {}
_report_generation_lock: Lock = Lock()

class DerivedIssueEnum:
ZEROLOGON_PASS_RESTORE_FAILED = "zerologon_pass_restore_failed"

@classmethod
def initialize(
cls,
Expand Down Expand Up @@ -229,35 +224,6 @@ def get_exploits(cls) -> List[dict]:
# Convert the ExploitationEvent into an ExploiterReportInfo
return [asdict(cls.process_exploit_event(e, password_restored)) for e in filtered_exploits]

@classmethod
def get_island_cross_segment_issues(cls):
issues = []
island_ips = get_my_ip_addresses_legacy()
island_machines = [m for m in cls._machine_repository.get_machines() if m.island]
for island_machine in island_machines:
found_good_ip = False
island_subnets = island_machine.network_interfaces
for subnet in island_subnets:
if str(subnet.ip) in island_ips:
found_good_ip = True
break
if found_good_ip:
break
if not found_good_ip:
issues.append(
{
"machine_id": island_machine.id,
"type": "island_cross_segment",
"machine": island_machine.hostname,
"networks": [str(subnet) for subnet in island_subnets],
"server_networks": [
str(interface.network) for interface in get_network_interfaces()
],
}
)

return issues

@classmethod
def get_cross_segment_issues_of_single_machine(
cls, source_subnet_range: NetworkRange, target_subnet_range: NetworkRange
Expand Down Expand Up @@ -466,26 +432,6 @@ def get_config_scan(cls):
agent_configuration = cls._agent_configuration_repository.get_configuration()
return agent_configuration.propagation.network_scan.targets.scan_my_networks

@staticmethod
def get_issue_set(issues):
issue_set = set()

for machine in issues:
for issue in issues[machine]:
if ReportService._is_zerologon_pass_restore_failed(issue):
issue_set.add(ReportService.DerivedIssueEnum.ZEROLOGON_PASS_RESTORE_FAILED)

issue_set.add(issue["type"])

return issue_set

@staticmethod
def _is_zerologon_pass_restore_failed(issue: dict):
return (
issue["type"] == ExploiterDescriptorEnum.ZEROLOGON.value.class_name
and not issue["password_restored"]
)

@classmethod
def is_report_generated(cls) -> bool:
return bool(cls._report)
Expand All @@ -498,7 +444,6 @@ def generate_report(cls):
return RuntimeError("Machine repository does not exist")

issues = ReportService.get_issues()
issue_set = ReportService.get_issue_set(issues)
cross_segment_issues = ReportService.get_cross_segment_issues()
latest_event_timestamp = ReportService.get_latest_event_timestamp()

Expand All @@ -517,9 +462,8 @@ def generate_report(cls):
"%d/%m/%Y %H:%M:%S"
),
"monkey_duration": ReportService.get_monkey_duration(),
"issues": issue_set,
"cross_segment_issues": cross_segment_issues,
},
"cross_segment_issues": cross_segment_issues,
"glance": {
"scanned": scanned_nodes,
"exploited_cnt": exploited_cnt,
Expand All @@ -534,14 +478,15 @@ def generate_report(cls):
def get_issues(cls):
ISSUE_GENERATORS = [
ReportService.get_exploits,
ReportService.get_island_cross_segment_issues,
]

issues = functools.reduce(lambda acc, issue_gen: acc + issue_gen(), ISSUE_GENERATORS, [])

issues_dict = {}
for issue in issues:
issue = cls.add_remediation_to_issue(issue)
manifest = cls._get_exploiter_manifests().get(issue["type"])
issue = cls.add_remediation_to_issue(issue, manifest)
issue = cls.add_description_to_issue(issue, manifest)
if issue.get("is_local", True):
machine_id = issue.get("machine_id")
if machine_id not in issues_dict:
Expand All @@ -551,12 +496,21 @@ def get_issues(cls):
return issues_dict

@classmethod
def add_remediation_to_issue(cls, issue: Dict[str, Any]) -> Dict[str, Any]:
manifest = cls._get_exploiter_manifests().get(issue["type"])
def add_remediation_to_issue(
cls, issue: Dict[str, Any], manifest: Optional[AgentPluginManifest]
) -> Dict[str, Any]:
if manifest:
issue["remediation_suggestion"] = manifest.remediation_suggestion
return issue

@classmethod
def add_description_to_issue(
cls, issue: Dict[str, Any], manifest: Optional[AgentPluginManifest]
) -> Dict[str, Any]:
if manifest:
issue["description"] = manifest.description
return issue

@classmethod
def get_latest_event_timestamp(cls) -> Optional[float]:
if not cls._agent_event_repository:
Expand Down
Loading