diff --git a/monkey/monkey_island/cc/services/reporting/issue_processing/__init__.py b/monkey/monkey_island/cc/services/reporting/issue_processing/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/monkey/monkey_island/cc/services/reporting/issue_processing/exploit_processing/__init__.py b/monkey/monkey_island/cc/services/reporting/issue_processing/exploit_processing/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/monkey/monkey_island/cc/services/reporting/issue_processing/exploit_processing/exploiter_descriptor_enum.py b/monkey/monkey_island/cc/services/reporting/issue_processing/exploit_processing/exploiter_descriptor_enum.py new file mode 100644 index 000000000..e6820b178 --- /dev/null +++ b/monkey/monkey_island/cc/services/reporting/issue_processing/exploit_processing/exploiter_descriptor_enum.py @@ -0,0 +1,32 @@ +from dataclasses import dataclass +from enum import Enum +from typing import Type + +from monkey_island.cc.services.reporting.issue_processing.exploit_processing import CredExploitProcessor +from monkey_island.cc.services.reporting.issue_processing.exploit_processing import ExploitProcessor +from monkey_island.cc.services.reporting.issue_processing.exploit_processing import \ + ShellShockExploitProcessor + + +@dataclass +class ExploiterDescriptor: + # Must match with class names of exploiters in Infection Monkey code + class_name: str + display_name: str + processor: Type[ExploitProcessor] + + +class ExploiterDescriptorEnum(Enum): + SMB = ExploiterDescriptor('SmbExploiter', 'SMB Exploiter', CredExploitProcessor) + WMI = ExploiterDescriptor('WmiExploiter', 'WMI Exploiter', CredExploitProcessor) + SSH = ExploiterDescriptor('SSHExploiter', 'SSH Exploiter', CredExploitProcessor) + SAMBACRY = ExploiterDescriptor('SambaCryExploiter', 'SambaCry Exploiter', CredExploitProcessor) + ELASTIC = ExploiterDescriptor('ElasticGroovyExploiter', 'Elastic Groovy Exploiter', ExploitProcessor) + MS08_067 = ExploiterDescriptor('Ms08_067_Exploiter', 'Conficker Exploiter', ExploitProcessor) + SHELLSHOCK = ExploiterDescriptor('ShellShockExploiter', 'ShellShock Exploiter', ShellShockExploitProcessor) + STRUTS2 = ExploiterDescriptor('Struts2Exploiter', 'Struts2 Exploiter', ExploitProcessor) + WEBLOGIC = ExploiterDescriptor('WebLogicExploiter', 'Oracle WebLogic Exploiter', ExploitProcessor) + HADOOP = ExploiterDescriptor('HadoopExploiter', 'Hadoop/Yarn Exploiter', ExploitProcessor) + MSSQL = ExploiterDescriptor('MSSQLExploiter', 'MSSQL Exploiter', ExploitProcessor) + VSFTPD = ExploiterDescriptor('VSFTPDExploiter', 'VSFTPD Backdoor Exploiter', CredExploitProcessor) + DRUPAL = ExploiterDescriptor('DrupalExploiter', 'Drupal Server Exploiter', ExploitProcessor) diff --git a/monkey/monkey_island/cc/services/reporting/issue_processing/exploit_processing/processors/__init__.py b/monkey/monkey_island/cc/services/reporting/issue_processing/exploit_processing/processors/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/monkey/monkey_island/cc/services/reporting/issue_processing/exploit_processing/processors/cred_exploit.py b/monkey/monkey_island/cc/services/reporting/issue_processing/exploit_processing/processors/cred_exploit.py new file mode 100644 index 000000000..fc61676b8 --- /dev/null +++ b/monkey/monkey_island/cc/services/reporting/issue_processing/exploit_processing/processors/cred_exploit.py @@ -0,0 +1,33 @@ +from __future__ import annotations + +from enum import Enum + +from monkey_island.cc.services.reporting.issue_processing.exploit_processing import ExploitProcessor, \ + ExploiterReportInfo + + +class CredentialType(Enum): + PASSWORD = 'password' + HASH = 'hash' + KEY = 'key' + + +class CredExploitProcessor(ExploitProcessor): + + @staticmethod + def get_exploit_info_by_dict(class_name: str, exploit_dict: dict) -> ExploiterReportInfo: + exploit_info = ExploitProcessor.get_exploit_info_by_dict(class_name, exploit_dict) + + for attempt in exploit_dict['data']['attempts']: + if attempt['result']: + exploit_info.username = attempt['user'] + if attempt['password']: + exploit_info.credential_type = CredentialType.PASSWORD.value + exploit_info.password = attempt['password'] + elif attempt['ssh_key']: + exploit_info.credential_type = CredentialType.KEY.value + exploit_info.ssh_key = attempt['ssh_key'] + else: + exploit_info.credential_type = CredentialType.HASH.value + return exploit_info + return exploit_info diff --git a/monkey/monkey_island/cc/services/reporting/issue_processing/exploit_processing/processors/exploit.py b/monkey/monkey_island/cc/services/reporting/issue_processing/exploit_processing/processors/exploit.py new file mode 100644 index 000000000..79ebb2dfb --- /dev/null +++ b/monkey/monkey_island/cc/services/reporting/issue_processing/exploit_processing/processors/exploit.py @@ -0,0 +1,21 @@ +from __future__ import annotations + +from dataclasses import dataclass + +from monkey_island.cc.services.node import NodeService + + +@dataclass +class ExploiterReportInfo: + machine: str + ip_address: str + type: str + + +class ExploitProcessor: + + @staticmethod + def get_exploit_info_by_dict(class_name: str, exploit_dict: dict) -> ExploiterReportInfo: + ip_addr = exploit_dict['data']['machine']['ip_addr'] + machine = NodeService.get_node_hostname(NodeService.get_node_or_monkey_by_ip(ip_addr)) + return ExploiterReportInfo(ip_address=ip_addr, machine=machine, type=class_name) diff --git a/monkey/monkey_island/cc/services/reporting/issue_processing/exploit_processing/processors/shellshock_exploit.py b/monkey/monkey_island/cc/services/reporting/issue_processing/exploit_processing/processors/shellshock_exploit.py new file mode 100644 index 000000000..181a19f41 --- /dev/null +++ b/monkey/monkey_island/cc/services/reporting/issue_processing/exploit_processing/processors/shellshock_exploit.py @@ -0,0 +1,16 @@ +from __future__ import annotations + +from monkey_island.cc.services.reporting.issue_processing.exploit_processing import ExploitProcessor, \ + ExploiterReportInfo + + +class ShellShockExploitProcessor(ExploitProcessor): + + @staticmethod + def get_exploit_info_by_dict(class_name: str, exploit_dict: dict) -> ExploiterReportInfo: + exploit_info = ExploitProcessor.get_exploit_info_by_dict(class_name, exploit_dict) + + urls = exploit_dict['data']['info']['vulnerable_urls'] + exploit_info.port = urls[0].split(':')[2].split('/')[0] + exploit_info.paths = ['/' + url.split(':')[2].split('/')[1] for url in urls] + return exploit_info diff --git a/monkey/monkey_island/cc/services/reporting/issue_processing/issue.py b/monkey/monkey_island/cc/services/reporting/issue_processing/issue.py new file mode 100644 index 000000000..e69de29bb diff --git a/monkey/monkey_island/cc/services/reporting/issue_processing/issue_processor.py b/monkey/monkey_island/cc/services/reporting/issue_processing/issue_processor.py new file mode 100644 index 000000000..e69de29bb diff --git a/monkey/monkey_island/cc/services/reporting/report.py b/monkey/monkey_island/cc/services/reporting/report.py index a23aa6d85..30f096fb7 100644 --- a/monkey/monkey_island/cc/services/reporting/report.py +++ b/monkey/monkey_island/cc/services/reporting/report.py @@ -2,7 +2,7 @@ import functools import ipaddress import itertools import logging -from enum import Enum +from typing import Dict, List from bson import json_util @@ -17,6 +17,10 @@ from common.config_value_paths import (EXPLOITER_CLASSES_PATH, LOCAL_NETWORK_SCA USER_LIST_PATH) from monkey_island.cc.services.configuration.utils import get_config_network_segments_as_subnet_groups from monkey_island.cc.services.node import NodeService +from monkey_island.cc.services.reporting.issue_processing.exploit_processing.exploiter_descriptor_enum import ExploiterDescriptorEnum, \ + ExploiterDescriptor +from monkey_island.cc.services.reporting.issue_processing.exploit_processing import CredentialType +from monkey_island.cc.services.reporting.issue_processing.exploit_processing import ExploiterReportInfo from monkey_island.cc.services.reporting.pth_report import PTHReportService from monkey_island.cc.services.reporting.report_exporter_manager import ReportExporterManager from monkey_island.cc.services.reporting.report_generation_synchronisation import safe_generate_regular_report @@ -26,52 +30,19 @@ __author__ = "itay.mizeretz" logger = logging.getLogger(__name__) +def build_exploiter_descriptor_dict() -> Dict[str, ExploiterDescriptor]: + descriptor_dict = {} + for descriptor in ExploiterDescriptorEnum: + descriptor_dict[descriptor.value.class_name] = descriptor + return descriptor_dict + + class ReportService: - def __init__(self): - pass + exploiter_descriptors = build_exploiter_descriptor_dict() - EXPLOIT_DISPLAY_DICT = \ - { - 'SmbExploiter': 'SMB Exploiter', - 'WmiExploiter': 'WMI Exploiter', - 'SSHExploiter': 'SSH Exploiter', - 'SambaCryExploiter': 'SambaCry Exploiter', - 'ElasticGroovyExploiter': 'Elastic Groovy Exploiter', - 'Ms08_067_Exploiter': 'Conficker Exploiter', - 'ShellShockExploiter': 'ShellShock Exploiter', - 'Struts2Exploiter': 'Struts2 Exploiter', - 'WebLogicExploiter': 'Oracle WebLogic Exploiter', - 'HadoopExploiter': 'Hadoop/Yarn Exploiter', - 'MSSQLExploiter': 'MSSQL Exploiter', - 'VSFTPDExploiter': 'VSFTPD Backdoor Exploiter', - 'DrupalExploiter': 'Drupal Server Exploiter', - 'ZerologonExploiter': 'Windows Server Zerologon Exploiter' - } - - class ISSUES_DICT(Enum): - WEAK_PASSWORD = 0 - STOLEN_CREDS = 1 - ELASTIC = 2 - SAMBACRY = 3 - SHELLSHOCK = 4 - CONFICKER = 5 - AZURE = 6 - STOLEN_SSH_KEYS = 7 - STRUTS2 = 8 - WEBLOGIC = 9 - HADOOP = 10 - PTH_CRIT_SERVICES_ACCESS = 11 - MSSQL = 12 - VSFTPD = 13 - DRUPAL = 14 - ZEROLOGON = 15 - ZEROLOGON_PASSWORD_RESTORE_FAILED = 16 - - class WARNINGS_DICT(Enum): - CROSS_SEGMENT = 0 - TUNNEL = 1 - SHARED_LOCAL_ADMIN = 2 - SHARED_PASSWORDS = 3 + class DerivedIssueEnum: + WEAK_PASSWORD = "weak_password" + STOLEN_CREDS = "stolen_creds" @staticmethod def get_first_monkey_time(): @@ -169,9 +140,7 @@ class ReportService: 'label': exploited_node['label'], 'ip_addresses': exploited_node['ip_addresses'], 'domain_name': exploited_node['domain_name'], - 'exploits': list(set( - [ReportService.EXPLOIT_DISPLAY_DICT[exploit['exploiter']] for exploit in exploited_node['exploits'] - if exploit['result']])) + 'exploits': ReportService.get_exploits_used_on_node(exploited_node) } for exploited_node in exploited] @@ -179,6 +148,10 @@ class ReportService: return exploited + @staticmethod + def get_exploits_used_on_node(node: dict) -> List[str]: + return list(set([exploit['exploiter'] for exploit in node['exploits'] if exploit['result']])) + @staticmethod def get_stolen_creds(): creds = [] @@ -281,148 +254,12 @@ class ReportService: return creds @staticmethod - def process_general_exploit(exploit): - ip_addr = exploit['data']['machine']['ip_addr'] - return {'machine': NodeService.get_node_hostname(NodeService.get_node_or_monkey_by_ip(ip_addr)), - 'ip_address': ip_addr} - - @staticmethod - def process_general_creds_exploit(exploit): - processed_exploit = ReportService.process_general_exploit(exploit) - - for attempt in exploit['data']['attempts']: - if attempt['result']: - processed_exploit['username'] = attempt['user'] - if attempt['password']: - processed_exploit['type'] = 'password' - processed_exploit['password'] = attempt['password'] - elif attempt['ssh_key']: - processed_exploit['type'] = 'ssh_key' - processed_exploit['ssh_key'] = attempt['ssh_key'] - else: - processed_exploit['type'] = 'hash' - return processed_exploit - return processed_exploit - - @staticmethod - def process_smb_exploit(exploit): - processed_exploit = ReportService.process_general_creds_exploit(exploit) - if processed_exploit['type'] == 'password': - processed_exploit['type'] = 'smb_password' - else: - processed_exploit['type'] = 'smb_pth' - return processed_exploit - - @staticmethod - def process_wmi_exploit(exploit): - processed_exploit = ReportService.process_general_creds_exploit(exploit) - if processed_exploit['type'] == 'password': - processed_exploit['type'] = 'wmi_password' - else: - processed_exploit['type'] = 'wmi_pth' - return processed_exploit - - @staticmethod - def process_ssh_exploit(exploit): - processed_exploit = ReportService.process_general_creds_exploit(exploit) - # Check if it's ssh key or ssh login credentials exploit - if processed_exploit['type'] == 'ssh_key': - return processed_exploit - else: - processed_exploit['type'] = 'ssh' - return processed_exploit - - @staticmethod - def process_vsftpd_exploit(exploit): - processed_exploit = ReportService.process_general_creds_exploit(exploit) - processed_exploit['type'] = 'vsftp' - return processed_exploit - - @staticmethod - def process_sambacry_exploit(exploit): - processed_exploit = ReportService.process_general_creds_exploit(exploit) - processed_exploit['type'] = 'sambacry' - return processed_exploit - - @staticmethod - def process_elastic_exploit(exploit): - processed_exploit = ReportService.process_general_exploit(exploit) - processed_exploit['type'] = 'elastic' - return processed_exploit - - @staticmethod - def process_conficker_exploit(exploit): - processed_exploit = ReportService.process_general_exploit(exploit) - processed_exploit['type'] = 'conficker' - return processed_exploit - - @staticmethod - def process_shellshock_exploit(exploit): - processed_exploit = ReportService.process_general_exploit(exploit) - processed_exploit['type'] = 'shellshock' - urls = exploit['data']['info']['vulnerable_urls'] - processed_exploit['port'] = urls[0].split(':')[2].split('/')[0] - processed_exploit['paths'] = ['/' + url.split(':')[2].split('/')[1] for url in urls] - return processed_exploit - - @staticmethod - def process_struts2_exploit(exploit): - processed_exploit = ReportService.process_general_exploit(exploit) - processed_exploit['type'] = 'struts2' - return processed_exploit - - @staticmethod - def process_weblogic_exploit(exploit): - processed_exploit = ReportService.process_general_exploit(exploit) - processed_exploit['type'] = 'weblogic' - return processed_exploit - - @staticmethod - def process_hadoop_exploit(exploit): - processed_exploit = ReportService.process_general_exploit(exploit) - processed_exploit['type'] = 'hadoop' - return processed_exploit - - @staticmethod - def process_mssql_exploit(exploit): - processed_exploit = ReportService.process_general_exploit(exploit) - processed_exploit['type'] = 'mssql' - return processed_exploit - - @staticmethod - def process_drupal_exploit(exploit): - processed_exploit = ReportService.process_general_exploit(exploit) - processed_exploit['type'] = 'drupal' - return processed_exploit - - @staticmethod - def process_zerologon_exploit(exploit): - processed_exploit = ReportService.process_general_exploit(exploit) - processed_exploit['type'] = 'zerologon' - processed_exploit['password_restored'] = exploit['data']['info']['password_restored'] - return processed_exploit - - @staticmethod - def process_exploit(exploit): + def process_exploit(exploit) -> ExploiterReportInfo: exploiter_type = exploit['data']['exploiter'] - EXPLOIT_PROCESS_FUNCTION_DICT = { - 'SmbExploiter': ReportService.process_smb_exploit, - 'WmiExploiter': ReportService.process_wmi_exploit, - 'SSHExploiter': ReportService.process_ssh_exploit, - 'SambaCryExploiter': ReportService.process_sambacry_exploit, - 'ElasticGroovyExploiter': ReportService.process_elastic_exploit, - 'Ms08_067_Exploiter': ReportService.process_conficker_exploit, - 'ShellShockExploiter': ReportService.process_shellshock_exploit, - 'Struts2Exploiter': ReportService.process_struts2_exploit, - 'WebLogicExploiter': ReportService.process_weblogic_exploit, - 'HadoopExploiter': ReportService.process_hadoop_exploit, - 'MSSQLExploiter': ReportService.process_mssql_exploit, - 'VSFTPDExploiter': ReportService.process_vsftpd_exploit, - 'DrupalExploiter': ReportService.process_drupal_exploit, - 'ZerologonExploiter': ReportService.process_zerologon_exploit - } - - return EXPLOIT_PROCESS_FUNCTION_DICT[exploiter_type](exploit) + exploiter_descriptor = ReportService.exploiter_descriptors[exploiter_type].value + processor = exploiter_descriptor.processor() + exploiter_info = processor.get_exploit_info_by_dict(exploiter_descriptor.class_name, exploit) + return exploiter_info @staticmethod def get_exploits(): @@ -585,7 +422,8 @@ class ReportService: @staticmethod def get_cross_segment_issues(): scans = mongo.db.telemetry.find({'telem_category': 'scan'}, - {'monkey_guid': 1, 'data.machine.ip_addr': 1, 'data.machine.services': 1, 'data.machine.icmp': 1}) + {'monkey_guid': 1, 'data.machine.ip_addr': 1, 'data.machine.services': 1, + 'data.machine.icmp': 1}) cross_segment_issues = [] @@ -627,32 +465,6 @@ class ReportService: else: return None - @staticmethod - def get_issues(): - ISSUE_GENERATORS = [ - ReportService.get_exploits, - ReportService.get_tunnels, - ReportService.get_island_cross_segment_issues, - ReportService.get_azure_issues, - PTHReportService.get_duplicated_passwords_issues, - PTHReportService.get_strong_users_on_crit_issues - ] - - issues = functools.reduce(lambda acc, issue_gen: acc + issue_gen(), ISSUE_GENERATORS, []) - - issues_dict = {} - for issue in issues: - if issue.get('is_local', True): - machine = issue.get('machine').upper() - aws_instance_id = ReportService.get_machine_aws_instance_id(issue.get('machine')) - if machine not in issues_dict: - issues_dict[machine] = [] - if aws_instance_id: - issue['aws_instance_id'] = aws_instance_id - issues_dict[machine].append(issue) - logger.info('Issues generated for reporting') - return issues_dict - @staticmethod def get_manual_monkeys(): return [monkey['hostname'] for monkey in mongo.db.monkey.find({}, {'hostname': 1, 'parent': 1, 'guid': 1}) if @@ -677,8 +489,8 @@ class ReportService: if exploits == default_exploits: return ['default'] - return [ReportService.EXPLOIT_DISPLAY_DICT[exploit] for exploit in - exploits] + # TODO investigate strange code + return [exploit for exploit in exploits] @staticmethod def get_config_ips(): @@ -689,68 +501,37 @@ class ReportService: return ConfigService.get_config_value(LOCAL_NETWORK_SCAN_PATH, True, True) @staticmethod - def get_issues_overview(issues, config_users, config_passwords): - issues_byte_array = [False] * len(ReportService.ISSUES_DICT) + def get_issue_set(issues, config_users, config_passwords): + issue_set = set() for machine in issues: for issue in issues[machine]: - if issue['type'] == 'elastic': - issues_byte_array[ReportService.ISSUES_DICT.ELASTIC.value] = True - elif issue['type'] == 'sambacry': - issues_byte_array[ReportService.ISSUES_DICT.SAMBACRY.value] = True - elif issue['type'] == 'vsftp': - issues_byte_array[ReportService.ISSUES_DICT.VSFTPD.value] = True - elif issue['type'] == 'shellshock': - issues_byte_array[ReportService.ISSUES_DICT.SHELLSHOCK.value] = True - elif issue['type'] == 'conficker': - issues_byte_array[ReportService.ISSUES_DICT.CONFICKER.value] = True - elif issue['type'] == 'azure_password': - issues_byte_array[ReportService.ISSUES_DICT.AZURE.value] = True - elif issue['type'] == 'ssh_key': - issues_byte_array[ReportService.ISSUES_DICT.STOLEN_SSH_KEYS.value] = True - elif issue['type'] == 'struts2': - issues_byte_array[ReportService.ISSUES_DICT.STRUTS2.value] = True - elif issue['type'] == 'weblogic': - issues_byte_array[ReportService.ISSUES_DICT.WEBLOGIC.value] = True - elif issue['type'] == 'mssql': - issues_byte_array[ReportService.ISSUES_DICT.MSSQL.value] = True - elif issue['type'] == 'hadoop': - issues_byte_array[ReportService.ISSUES_DICT.HADOOP.value] = True - elif issue['type'] == 'drupal': - issues_byte_array[ReportService.ISSUES_DICT.DRUPAL.value] = True - elif issue['type'] == 'zerologon': - if not issue['password_restored']: - issues_byte_array[ReportService.ISSUES_DICT.ZEROLOGON_PASSWORD_RESTORE_FAILED.value] = True - issues_byte_array[ReportService.ISSUES_DICT.ZEROLOGON.value] = True - elif issue['type'].endswith('_password') and issue['password'] in config_passwords and \ - issue['username'] in config_users or issue['type'] == 'ssh': - issues_byte_array[ReportService.ISSUES_DICT.WEAK_PASSWORD.value] = True - elif issue['type'] == 'strong_users_on_crit': - issues_byte_array[ReportService.ISSUES_DICT.PTH_CRIT_SERVICES_ACCESS.value] = True - elif issue['type'].endswith('_pth') or issue['type'].endswith('_password'): - issues_byte_array[ReportService.ISSUES_DICT.STOLEN_CREDS.value] = True + # TODO check if this actually works, because stolen passwords get added to config + # so any password will be in config. We need to separate stolen passwords from initial + # passwords in config. + if ReportService._is_weak_credential_issue(issue, config_users, config_passwords): + issue_set.add(ReportService.DerivedIssueEnum.WEAK_PASSWORD) + elif ReportService._is_stolen_credential_issue(issue): + issue_set.add(ReportService.DerivedIssueEnum.STOLEN_CREDS) - return issues_byte_array + issue_set.add(issue['type']) + + return issue_set @staticmethod - def get_warnings_overview(issues, cross_segment_issues): - warnings_byte_array = [False] * len(ReportService.WARNINGS_DICT) + def _is_weak_credential_issue(issue: dict, config_usernames: List[str], config_passwords: List[str]) -> bool: + # Only credential exploiter issues have 'credential_type' + return 'credential_type' in issue and \ + issue['credential_type'] == CredentialType.PASSWORD.value and \ + issue['password'] in config_passwords and \ + issue['username'] in config_usernames - for machine in issues: - for issue in issues[machine]: - if issue['type'] == 'island_cross_segment': - warnings_byte_array[ReportService.WARNINGS_DICT.CROSS_SEGMENT.value] = True - elif issue['type'] == 'tunnel': - warnings_byte_array[ReportService.WARNINGS_DICT.TUNNEL.value] = True - elif issue['type'] == 'shared_admins': - warnings_byte_array[ReportService.WARNINGS_DICT.SHARED_LOCAL_ADMIN.value] = True - elif issue['type'] == 'shared_passwords': - warnings_byte_array[ReportService.WARNINGS_DICT.SHARED_PASSWORDS.value] = True - - if len(cross_segment_issues) != 0: - warnings_byte_array[ReportService.WARNINGS_DICT.CROSS_SEGMENT.value] = True - - return warnings_byte_array + @staticmethod + def _is_stolen_credential_issue(issue: dict) -> bool: + # Only credential exploiter issues have 'credential_type' + return 'credential_type' in issue and \ + (issue['credential_type'] == CredentialType.PASSWORD.value or + issue['credential_type'] == CredentialType.HASH.value) @staticmethod def is_report_generated(): @@ -780,8 +561,7 @@ class ReportService: 'config_scan': ReportService.get_config_scan(), 'monkey_start_time': ReportService.get_first_monkey_time().strftime("%d/%m/%Y %H:%M:%S"), 'monkey_duration': ReportService.get_monkey_duration(), - 'issues': ReportService.get_issues_overview(issues, config_users, config_passwords), - 'warnings': ReportService.get_warnings_overview(issues, cross_segment_issues), + 'issues': ReportService.get_issue_set(issues, config_users, config_passwords), 'cross_segment_issues': cross_segment_issues }, 'glance': diff --git a/monkey/monkey_island/cc/services/reporting/test_report.py b/monkey/monkey_island/cc/services/reporting/test_report.py new file mode 100644 index 000000000..9983371a4 --- /dev/null +++ b/monkey/monkey_island/cc/services/reporting/test_report.py @@ -0,0 +1,51 @@ +import datetime +from copy import deepcopy + +from monkey_island.cc.services.reporting.report import ReportService + +NODE_DICT = { + 'id': '602f62118e30cf35830ff8e4', + 'label': 'WinDev2010Eval.mshome.net', + 'group': 'monkey_windows', + 'os': 'windows', + 'dead': True, + 'exploits': [{'result': True, + 'exploiter': 'DrupalExploiter', + 'info': {'display_name': 'Drupal Server', + 'started': datetime.datetime(2021, 2, 19, 9, 0, 14, 950000), + 'finished': datetime.datetime(2021, 2, 19, 9, 0, 14, 950000), + 'vulnerable_urls': [], + 'vulnerable_ports': [], + 'executed_cmds': []}, + 'attempts': [], + 'timestamp': datetime.datetime(2021, 2, 19, 9, 0, 14, 984000), + 'origin': 'MonkeyIsland : 192.168.56.1'}, + + {'result': True, + 'exploiter': 'ElasticGroovyExploiter', + 'info': {'display_name': 'Elastic search', + 'started': datetime.datetime(2021, 2, 19, 9, 0, 15, 16000), + 'finished': datetime.datetime(2021, 2, 19, 9, 0, 15, 17000), + 'vulnerable_urls': [], 'vulnerable_ports': [], 'executed_cmds': []}, + 'attempts': [], + 'timestamp': datetime.datetime(2021, 2, 19, 9, 0, 15, 60000), + 'origin': 'MonkeyIsland : 192.168.56.1'}] +} + +NODE_DICT_DUPLICATE_EXPLOITS = deepcopy(NODE_DICT) +NODE_DICT_DUPLICATE_EXPLOITS['exploits'][1] = NODE_DICT_DUPLICATE_EXPLOITS['exploits'][0] + +NODE_DICT_FAILED_EXPLOITS = deepcopy(NODE_DICT) +NODE_DICT_FAILED_EXPLOITS['exploits'][0]['result'] = False +NODE_DICT_FAILED_EXPLOITS['exploits'][1]['result'] = False + + +def test_get_exploits_used_on_node(): + exploits = ReportService.get_exploits_used_on_node(NODE_DICT) + assert sorted(exploits) == sorted(['ElasticGroovyExploiter', 'DrupalExploiter']) + + exploits = ReportService.get_exploits_used_on_node(NODE_DICT_DUPLICATE_EXPLOITS) + assert exploits == ['DrupalExploiter'] + + exploits = ReportService.get_exploits_used_on_node(NODE_DICT_FAILED_EXPLOITS) + assert exploits == [] 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 e3a1621eb..bd5ae3a30 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 @@ -5,7 +5,6 @@ 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'; -import CollapsibleWellComponent from 'components/report-components/security/CollapsibleWell'; import {Line} from 'rc-progress'; import AuthComponent from '../AuthComponent'; import StrongUsers from 'components/report-components/security/StrongUsers'; @@ -21,41 +20,141 @@ import {faMinus} from '@fortawesome/free-solid-svg-icons/faMinus'; import guardicoreLogoImage from '../../images/guardicore-logo.png' import {faExclamationTriangle} from '@fortawesome/free-solid-svg-icons'; import '../../styles/App.css'; +import {generateSmbPasswordReport, generateSmbPthReport} from './security/issues/SmbIssue'; +import {Struts2IssueOverview, Struts2IssueReport} from './security/issues/Struts2Issue'; +import {WebLogicIssueOverview, WebLogicIssueReport} from './security/issues/WebLogicIssue'; +import {HadoopIssueOverview, HadoopIssueReport} from './security/issues/HadoopIssue'; +import {MssqlIssueOverview, MssqlIssueReport} from './security/issues/MssqlIssue'; +import {DrupalIssueOverview, DrupalIssueReport} from './security/issues/DrupalIssue'; +import {VsftpdIssueOverview, VsftpdIssueReport} from './security/issues/VsftpdIssue'; +import {generateWmiPasswordIssue, generateWmiPthIssue} from './security/issues/WmiIssue'; +import {ShhIssueReport, SshIssueOverview} from './security/issues/SshIssue'; +import {SambacryIssueOverview, SambacryIssueReport} from './security/issues/SambacryIssue'; +import {ElasticIssueOverview, ElasticIssueReport} from './security/issues/ElasticIssue'; +import {ShellShockIssueOverview, ShellShockIssueReport} from './security/issues/ShellShockIssue'; +import {MS08_067IssueOverview, MS08_067IssueReport} from './security/issues/MS08_067Issue'; +import { + crossSegmentIssueOverview, + generateCrossSegmentIssue +} from './security/issues/CrossSegmentIssue'; +import {sharedAdminsDomainIssueOverview, sharedPasswordsIssueOverview} from './security/issues/SharedPasswordsIssue'; +import {generateTunnelIssue, generateTunnelIssueOverview} from './security/issues/TunnelIssue'; class ReportPageComponent extends AuthComponent { - Issue = - { - WEAK_PASSWORD: 0, - STOLEN_CREDS: 1, - ELASTIC: 2, - SAMBACRY: 3, - SHELLSHOCK: 4, - CONFICKER: 5, - AZURE: 6, - STOLEN_SSH_KEYS: 7, - STRUTS2: 8, - WEBLOGIC: 9, - HADOOP: 10, - PTH_CRIT_SERVICES_ACCESS: 11, - MSSQL: 12, - VSFTPD: 13, - DRUPAL: 14, - ZEROLOGON: 15, - ZEROLOGON_PASSWORD_RESTORE_FAILED: 16 - }; + credentialTypes = { + PASSWORD: 'password', + HASH: 'hash', + KEY: 'key', + } - NotThreats = [this.Issue.ZEROLOGON_PASSWORD_RESTORE_FAILED]; + issueContentTypes = { + OVERVIEW: 'overview', + REPORT: 'report', + TYPE: 'type' + } - Warning = + issueTypes = { + WARNING: 'warning', + DANGER: 'danger' + } + + IssueDescriptorEnum = { - CROSS_SEGMENT: 0, - TUNNEL: 1, - SHARED_LOCAL_ADMIN: 2, - SHARED_PASSWORDS: 3, - SHARED_PASSWORDS_DOMAIN: 4 - }; + 'SmbExploiter': { + [this.issueContentTypes.REPORT]: { + [this.credentialTypes.PASSWORD]: generateSmbPasswordReport, + [this.credentialTypes.HASH]: generateSmbPthReport + }, + [this.issueContentTypes.TYPE]: this.issueTypes.DANGER + }, + 'Struts2Exploiter': { + [this.issueContentTypes.OVERVIEW]: Struts2IssueOverview, + [this.issueContentTypes.REPORT]: Struts2IssueReport, + [this.issueContentTypes.TYPE]: this.issueTypes.DANGER + }, + 'WebLogicExploiter': { + [this.issueContentTypes.OVERVIEW]: WebLogicIssueOverview, + [this.issueContentTypes.REPORT]: WebLogicIssueReport, + [this.issueContentTypes.TYPE]: this.issueTypes.DANGER + }, + 'HadoopExploiter': { + [this.issueContentTypes.OVERVIEW]: HadoopIssueOverview, + [this.issueContentTypes.REPORT]: HadoopIssueReport, + [this.issueContentTypes.TYPE]: this.issueTypes.DANGER + }, + 'MSSQLExploiter': { + [this.issueContentTypes.OVERVIEW]: MssqlIssueOverview, + [this.issueContentTypes.REPORT]: MssqlIssueReport, + [this.issueContentTypes.TYPE]: this.issueTypes.DANGER + }, + 'DrupalExploiter': { + [this.issueContentTypes.OVERVIEW]: DrupalIssueOverview, + [this.issueContentTypes.REPORT]: DrupalIssueReport, + [this.issueContentTypes.TYPE]: this.issueTypes.DANGER + }, + 'VSFTPDExploiter': { + [this.issueContentTypes.OVERVIEW]: VsftpdIssueOverview, + [this.issueContentTypes.REPORT]: VsftpdIssueReport, + [this.issueContentTypes.TYPE]: this.issueTypes.DANGER + }, + 'WmiExploiter': { + [this.issueContentTypes.REPORT]: { + [this.credentialTypes.PASSWORD]: generateWmiPasswordIssue, + [this.credentialTypes.HASH]: generateWmiPthIssue + }, + [this.issueContentTypes.TYPE]: this.issueTypes.DANGER + }, + 'SSHExploiter': { + [this.issueContentTypes.OVERVIEW]: SshIssueOverview, + [this.issueContentTypes.REPORT]: ShhIssueReport, + [this.issueContentTypes.TYPE]: this.issueTypes.DANGER + }, + 'SambaCryExploiter': { + [this.issueContentTypes.OVERVIEW]: SambacryIssueOverview, + [this.issueContentTypes.REPORT]: SambacryIssueReport, + [this.issueContentTypes.TYPE]: this.issueTypes.DANGER + }, + 'ElasticGroovyExploiter': { + [this.issueContentTypes.OVERVIEW]: ElasticIssueOverview, + [this.issueContentTypes.REPORT]: ElasticIssueReport, + [this.issueContentTypes.TYPE]: this.issueTypes.DANGER + }, + 'ShellShockExploiter': { + [this.issueContentTypes.OVERVIEW]: ShellShockIssueOverview, + [this.issueContentTypes.REPORT]: ShellShockIssueReport, + [this.issueContentTypes.TYPE]: this.issueTypes.DANGER + }, + 'Ms08_067_Exploiter': { + [this.issueContentTypes.OVERVIEW]: MS08_067IssueOverview, + [this.issueContentTypes.REPORT]: MS08_067IssueReport, + [this.issueContentTypes.TYPE]: this.issueTypes.DANGER + }, + 'island_cross_segment': { + [this.issueContentTypes.OVERVIEW]: crossSegmentIssueOverview, + [this.issueContentTypes.REPORT]: generateCrossSegmentIssue, + [this.issueContentTypes.TYPE]: this.issueTypes.WARNING + }, + 'tunnel': { + [this.issueContentTypes.OVERVIEW]: generateTunnelIssueOverview, + [this.issueContentTypes.REPORT]: generateTunnelIssue, + [this.issueContentTypes.TYPE]: this.issueTypes.WARNING + }, + 'shared_passwords': { + [this.issueContentTypes.OVERVIEW]: sharedPasswordsIssueOverview, + [this.issueContentTypes.TYPE]: this.issueTypes.WARNING + }, + 'shared_admins_domain': { + [this.issueContentTypes.OVERVIEW]: sharedAdminsDomainIssueOverview, + [this.issueContentTypes.TYPE]: this.issueTypes.WARNING + }, + 'shared_passwords_domain': {}, + 'strong_users_on_crit': {}, + 'azure_password': {}, + 'weak_password': {}, + 'stolen_creds': {} + } constructor(props) { super(props); @@ -92,6 +191,8 @@ class ReportPageComponent extends AuthComponent { render() { let content; + console.log(this.state.report); + if (this.stillLoadingDataFromServer()) { content = ; } else { @@ -239,156 +340,24 @@ class ReportPageComponent extends AuthComponent { } generateReportFindingsSection() { + let overviews = this.getPotentialSecurityIssuesOverviews() + return (

Security Findings

-
-

- Immediate Threats -

- { - this.state.report.overview.issues.filter(function (x) { - return x === true; - }).length > 0 ? -
- During this simulated attack the Monkey uncovered - {this.getThreatCount()} - : -
    - {this.state.report.overview.issues[this.Issue.STOLEN_SSH_KEYS] && -
  • Stolen SSH keys are used to exploit other machines.
  • } - {this.state.report.overview.issues[this.Issue.STOLEN_CREDS] && -
  • Stolen credentials are used to exploit other machines.
  • } - {this.state.report.overview.issues[this.Issue.ELASTIC] && -
  • Elasticsearch servers are vulnerable to - . -
  • } - {this.state.report.overview.issues[this.Issue.VSFTPD] && -
  • VSFTPD is vulnerable to - . -
  • } - {this.state.report.overview.issues[this.Issue.SAMBACRY] && -
  • Samba servers are vulnerable to ‘SambaCry’ ( - ). -
  • } - {this.state.report.overview.issues[this.Issue.SHELLSHOCK] && -
  • Machines are vulnerable to ‘Shellshock’ ( - ). -
  • } - {this.state.report.overview.issues[this.Issue.CONFICKER] && -
  • Machines are vulnerable to ‘Conficker’ ( - ). -
  • } - {this.state.report.overview.issues[this.Issue.WEAK_PASSWORD] && -
  • Machines are accessible using passwords supplied by the user during the Monkey’s - configuration.
  • } - {this.state.report.overview.issues[this.Issue.AZURE] && -
  • Azure machines expose plaintext passwords ( - ). -
  • } - {this.state.report.overview.issues[this.Issue.STRUTS2] && -
  • Struts2 servers are vulnerable to remote code execution ( - ). -
  • } - {this.state.report.overview.issues[this.Issue.WEBLOGIC] && -
  • Oracle WebLogic servers are susceptible to a remote code execution vulnerability.
  • } - {this.state.report.overview.issues[this.Issue.HADOOP] && -
  • Hadoop/Yarn servers are vulnerable to remote code execution.
  • } - {this.state.report.overview.issues[this.Issue.PTH_CRIT_SERVICES_ACCESS] && -
  • Mimikatz found login credentials of a user who has admin access to a server defined as - critical.
  • } - {this.state.report.overview.issues[this.Issue.MSSQL] && -
  • MS-SQL servers are vulnerable to remote code execution via xp_cmdshell command.
  • } - {this.state.report.overview.issues[this.Issue.DRUPAL] && -
  • Drupal servers are susceptible to a remote code execution vulnerability - (). -
  • - } - {this.generateZerologonOverview()} -
-
- : -
- During this simulated attack the Monkey uncovered 0 threats. -
- } -
+ {this.getImmediateThreats()}

Potential Security Issues

{ - this.state.report.overview.warnings.filter(function (x) { - return x === true; - }).length > 0 ? + overviews.length > 0 ?
The Monkey uncovered the following possible set of issues:
    - {this.state.report.overview.warnings[this.Warning.CROSS_SEGMENT] ? -
  • Weak segmentation - Machines from different segments are able - to - communicate.
  • : null} - {this.state.report.overview.warnings[this.Warning.TUNNEL] ? -
  • Weak segmentation - Machines were able to communicate over unused - ports.
  • : null} - {this.state.report.overview.warnings[this.Warning.SHARED_LOCAL_ADMIN] ? -
  • Shared local administrator account - Different machines - have the same account as a local - administrator.
  • : null} - {this.state.report.overview.warnings[this.Warning.SHARED_PASSWORDS] ? -
  • Multiple users have the same password
  • : null} + {overviews}
: @@ -405,7 +374,7 @@ class ReportPageComponent extends AuthComponent {
The Monkey uncovered the following set of segmentation issues:
    - {this.state.report.overview.cross_segment_issues.map(x => this.generateCrossSegmentIssue(x))} + {this.state.report.overview.cross_segment_issues.map(x => generateCrossSegmentIssue(x))}
@@ -416,53 +385,40 @@ class ReportPageComponent extends AuthComponent { ); } - getThreatCount() { - let threatCount = this.state.report.overview.issues.filter(function (x) { - return x === true; - }).length + getPotentialSecurityIssuesOverviews(){ + let overviews = []; - this.NotThreats.forEach(x => { - if (this.state.report.overview.issues[x] === true) { - threatCount -= 1; + for( let key of this.IssueDescriptorEnum) { + if(this.WARNING_ISSUE_LIST[i] in this.state.report.issues) { + overviews.push(this.IssueDescriptorEnum[this.WARNING_ISSUE_LIST[i]][this.issueContentTypes.OVERVIEW]) } - }); - - if (threatCount === 1) - return '1 threat' - else - return threatCount + ' threats' + } + return overviews; } - generateZerologonOverview() { - let zerologonOverview = []; - if (this.state.report.overview.issues[this.Issue.ZEROLOGON]) { - zerologonOverview.push(<> - Some Windows domain controllers are vulnerable to 'Zerologon' ( - ). - ) - } - if (this.state.report.overview.issues[this.Issue.ZEROLOGON_PASSWORD_RESTORE_FAILED]) { - zerologonOverview.push( -
- - Automatic password restoration on a domain controller failed! - -
) - } - else { - return null; - } - return (
  • {zerologonOverview}
  • ) + getImmediateThreats() { + return ( +
    +

    + Immediate Threats +

    +
    During this simulated attack the Monkey uncovered + { + this.state.report.overview.issues.length > 0 ? + <> + + {this.state.report.overview.issues.length} threats: + + + : + <> + 0 threats. + + } +
    +
    ) } generateReportRecommendationsSection() { @@ -558,578 +514,17 @@ class ReportPageComponent extends AuthComponent { ); } - generateInfoBadges(data_array) { - return data_array.map(badge_data => {badge_data}); - } - - generateCrossSegmentIssue(crossSegmentIssue) { - let crossSegmentIssueOverview = 'Communication possible from ' - + `${crossSegmentIssue['source_subnet']} to ${crossSegmentIssue['target_subnet']}`; - - return ( -
  • - {crossSegmentIssueOverview} - -
      - {crossSegmentIssue['issues'].map( - issue => this.generateCrossSegmentIssueListItem(issue) - )} -
    -
    -
  • - ); - } - - generateCrossSegmentIssueListItem(issue) { - if (issue['is_self']) { - return this.generateCrossSegmentSingleHostMessage(issue); - } - - return this.generateCrossSegmentMultiHostMessage(issue); - } - - generateCrossSegmentSingleHostMessage(issue) { - return ( -
  • - {`Machine ${issue['hostname']} has both ips: ${issue['source']} and ${issue['target']}`} -
  • - ); - } - - generateCrossSegmentMultiHostMessage(issue) { - return ( -
  • - IP {issue['source']} ({issue['hostname']}) was able to communicate with - IP {issue['target']} using: -
      - {issue['icmp'] &&
    • ICMP
    • } - {this.generateCrossSegmentServiceListItems(issue)} -
    -
  • - ); - } - - generateCrossSegmentServiceListItems(issue) { - let service_list_items = []; - - for (const [service, info] of Object.entries(issue['services'])) { - service_list_items.push( -
  • - {service} ({info['display_name']}) -
  • - ); - } - - return service_list_items; - } - - generateShellshockPathListBadges(paths) { - return paths.map(path => {path}); - } - - generateSmbPasswordIssue(issue) { - return ( - <> - Change {issue.username}'s password to a complex one-use password - that is not shared with other computers on the network. - - The machine {issue.machine} ({issue.ip_address}) is vulnerable to a SMB attack. -
    - The Monkey authenticated over the SMB protocol with user {issue.username} and its password. -
    - - ); - } - - generateSmbPthIssue(issue) { - return ( - <> - Change {issue.username}'s password to a complex one-use password - that is not shared with other computers on the network. - - The machine {issue.machine} ({issue.ip_address}) is vulnerable to a SMB attack. -
    - The Monkey used a pass-the-hash attack over SMB protocol with user {issue.username}. -
    - - ); - } - - generateWmiPasswordIssue(issue) { - return ( - <> - Change {issue.username}'s password to a complex one-use password - that is not shared with other computers on the network. - - The machine {issue.machine} ({issue.ip_address}) is vulnerable to a WMI attack. -
    - The Monkey authenticated over the WMI protocol with user {issue.username} and its password. -
    - - ); - } - - generateWmiPthIssue(issue) { - return ( - <> - Change {issue.username}'s password to a complex one-use password - that is not shared with other computers on the network. - - The machine {issue.machine} ({issue.ip_address}) is vulnerable to a WMI attack. -
    - The Monkey used a pass-the-hash attack over WMI protocol with user {issue.username}. -
    - - ); - } - - generateSshIssue(issue) { - return ( - <> - Change {issue.username}'s password to a complex one-use password - that is not shared with other computers on the network. - - The machine {issue.machine} ({issue.ip_address}) is vulnerable to a SSH attack. -
    - The Monkey authenticated over the SSH protocol with user {issue.username} and its password. -
    - - ); - } - - generateSshKeysIssue(issue) { - return ( - <> - Protect {issue.ssh_key} private key with a pass phrase. - - The machine {issue.machine} ({issue.ip_address}) is vulnerable to a SSH attack. -
    - The Monkey authenticated over the SSH protocol with private key {issue.ssh_key}. -
    - - ); - } - - - generateSambaCryIssue(issue) { - return ( - <> - Change {issue.username}'s password to a complex one-use password - that is not shared with other computers on the network. -
    - Update your Samba server to 4.4.14 and up, 4.5.10 and up, or 4.6.4 and up. - - The machine {issue.machine} ({issue.ip_address}) is vulnerable to a SambaCry attack. -
    - The Monkey authenticated over the SMB protocol with user {issue.username} and its password, and used the SambaCry - vulnerability. -
    - - ); - } - - generateVsftpdBackdoorIssue(issue) { - return ( - <> - Update your VSFTPD server to the latest version vsftpd-3.0.3. - - The machine {issue.machine} ({issue.ip_address}) has a backdoor running at - port 6200. -
    - The attack was made possible because the VSFTPD server was not patched against CVE-2011-2523. -

    In July 2011, it was discovered that vsftpd version 2.3.4 downloadable from the master site had been - compromised. - Users logging into a compromised vsftpd-2.3.4 server may issue a ":)" smileyface as the username and gain a - command - shell on port 6200. -

    - The Monkey executed commands by first logging in with ":)" in the username and then sending commands to the - backdoor - at port 6200. -

    Read more about the security issue and remediation here. -
    - - ); - } - - generateElasticIssue(issue) { - return ( - <> - Update your Elastic Search server to version 1.4.3 and up. - - The machine {issue.machine} ({issue.ip_address}) is vulnerable to an Elastic Groovy attack. -
    - The attack was made possible because the Elastic Search server was not patched against CVE-2015-1427. -
    - - ); - } - - generateShellshockIssue(issue) { - return ( - <> - Update your Bash to a ShellShock-patched version. - - The machine {issue.machine} ({issue.ip_address}) is vulnerable to a ShellShock attack. -
    - The attack was made possible because the HTTP server running on TCP port {issue.port} was vulnerable to a shell injection attack on the - paths: {this.generateShellshockPathListBadges(issue.paths)}. -
    - - ); - } - - generateAzureIssue(issue) { - return ( - <> - Delete VM Access plugin configuration files. - - Credentials could be stolen from {issue.machine} for the following users {issue.users}. Read more about the security issue and remediation here. - - - ); - } - - generateConfickerIssue(issue) { - return ( - <> - Install the latest Windows updates or upgrade to a newer operating system. - - The machine {issue.machine} ({issue.ip_address}) is vulnerable to a Conficker attack. -
    - The attack was made possible because the target machine used an outdated and unpatched operating system - vulnerable to Conficker. -
    - - ); - } - - generateIslandCrossSegmentIssue(issue) { - return ( - <> - Segment your network and make sure there is no communication between machines from different segments. - - The network can probably be segmented. A monkey instance on {issue.machine} in the - networks {this.generateInfoBadges(issue.networks)} - could directly access the Monkey Island server in the - networks {this.generateInfoBadges(issue.server_networks)}. - - - ); - } - - generateSharedCredsDomainIssue(issue) { - return ( - <> - Some domain users are sharing passwords, this should be fixed by changing passwords. - - These users are sharing access password: - {this.generateInfoBadges(issue.shared_with)}. - - - ); - } - - generateSharedCredsIssue(issue) { - return ( - <> - Some users are sharing passwords, this should be fixed by changing passwords. - - These users are sharing access password: - {this.generateInfoBadges(issue.shared_with)}. - - - ); - } - - generateSharedLocalAdminsIssue(issue) { - return ( - <> - Make sure the right administrator accounts are managing the right machines, and that there isn’t an - unintentional local - admin sharing. - - Here is a list of machines which the account {issue.username} is defined as an administrator: - {this.generateInfoBadges(issue.shared_machines)} - - - ); - } - - generateStrongUsersOnCritIssue(issue) { - return ( - <> - This critical machine is open to attacks via strong users with access to it. - - The services: {this.generateInfoBadges(issue.services)} have been found on the machine - thus classifying it as a critical machine. - These users has access to it: - {this.generateInfoBadges(issue.threatening_users)}. - - - ); - } - - generateTunnelIssue(issue) { - return ( - <> - Use micro-segmentation policies to disable communication other than the required. - - Machines are not locked down at port level. Network tunnel was set up from {issue.machine} to {issue.dest}. - - - ); - } - - generateStruts2Issue(issue) { - return ( - <> - Upgrade Struts2 to version 2.3.32 or 2.5.10.1 or any later versions. - - Struts2 server at {issue.machine} ({issue.ip_address}) is vulnerable to remote code execution attack. -
    - The attack was made possible because the server is using an old version of Jakarta based file upload - Multipart parser. For possible work-arounds and more info read here. -
    - - ); - } - - generateDrupalIssue(issue) { - return ( - <> - Upgrade Drupal server to versions 8.5.11, 8.6.10, or later. - - Drupal server at {issue.machine} ({issue.ip_address}) is vulnerable to remote command execution attack. -
    - The attack was made possible because the server is using an old version of Drupal, for which REST API is - enabled. For possible workarounds, fixes and more info read - here. -
    - - ); - } - - generateWebLogicIssue(issue) { - return ( - <> - Update Oracle WebLogic server to the latest supported version. - - Oracle WebLogic server at {issue.machine} ({issue.ip_address}) is vulnerable to one of remote code execution attacks. -
    - The attack was made possible due to one of the following vulnerabilities: - CVE-2017-10271 or - CVE-2019-2725 -
    - - ); - } - - generateHadoopIssue(issue) { - return ( - <> - Run Hadoop in secure mode ( - add Kerberos authentication). - - The Hadoop server at {issue.machine} ({issue.ip_address}) is vulnerable to remote code execution attack. -
    - The attack was made possible due to default Hadoop/Yarn configuration being insecure. -
    - - ); - } - - generateMSSQLIssue(issue) { - return ( - <> - Disable the xp_cmdshell option. - - The machine {issue.machine} ({issue.ip_address}) is vulnerable to a MSSQL exploit attack. -
    - The attack was made possible because the target machine used an outdated MSSQL server configuration allowing - the usage of the xp_cmdshell command. To learn more about how to disable this feature, read - . -
    - - ); - } - - generateZerologonIssue(issue) { - return ( - <> - Install Windows security updates. - - The machine {issue.machine} ({issue.ip_address}) is vulnerable to a Zerologon exploit. -
    - The attack was possible because the latest security updates from Microsoft - have not been applied to this machine. For more information about this - vulnerability, read - . - {!issue.password_restored && -
    -
    - - The domain controller's password was changed during the exploit and could not be restored successfully. - Instructions on how to manually reset the domain controller's password can be found - . - -
    } -
    - - ); - } - generateIssue = (issue) => { - let issueData; - switch (issue.type) { - case 'vsftp': - issueData = this.generateVsftpdBackdoorIssue(issue); - break; - case 'smb_password': - issueData = this.generateSmbPasswordIssue(issue); - break; - case 'smb_pth': - issueData = this.generateSmbPthIssue(issue); - break; - case 'wmi_password': - issueData = this.generateWmiPasswordIssue(issue); - break; - case 'wmi_pth': - issueData = this.generateWmiPthIssue(issue); - break; - case 'ssh': - issueData = this.generateSshIssue(issue); - break; - case 'ssh_key': - issueData = this.generateSshKeysIssue(issue); - break; - case 'sambacry': - issueData = this.generateSambaCryIssue(issue); - break; - case 'elastic': - issueData = this.generateElasticIssue(issue); - break; - case 'shellshock': - issueData = this.generateShellshockIssue(issue); - break; - case 'conficker': - issueData = this.generateConfickerIssue(issue); - break; - case 'island_cross_segment': - issueData = this.generateIslandCrossSegmentIssue(issue); - break; - case 'shared_passwords': - issueData = this.generateSharedCredsIssue(issue); - break; - case 'shared_passwords_domain': - issueData = this.generateSharedCredsDomainIssue(issue); - break; - case 'shared_admins_domain': - issueData = this.generateSharedLocalAdminsIssue(issue); - break; - case 'strong_users_on_crit': - issueData = this.generateStrongUsersOnCritIssue(issue); - break; - case 'tunnel': - issueData = this.generateTunnelIssue(issue); - break; - case 'azure_password': - issueData = this.generateAzureIssue(issue); - break; - case 'struts2': - issueData = this.generateStruts2Issue(issue); - break; - case 'weblogic': - issueData = this.generateWebLogicIssue(issue); - break; - case 'hadoop': - issueData = this.generateHadoopIssue(issue); - break; - case 'mssql': - issueData = this.generateMSSQLIssue(issue); - break; - case 'drupal': - issueData = this.generateDrupalIssue(issue); - break; - case 'zerologon': - issueData = this.generateZerologonIssue(issue); - break; + let issueDescriptor = this.IssueDescriptorEnum[issue.type]; + + let reportFnc = (issue) => {}; + if(issue.hasOwnProperty('credential_type')) { + reportFnc = issueDescriptor[this.issueContentTypes.REPORT][issue.credential_type]; + } else { + reportFnc = issueDescriptor[this.issueContentTypes.REPORT]; } - return
  • {issueData}
  • ; + let reportContents = reportFnc(issue); + return
  • {reportContents}
  • ; }; generateIssues = (issues) => { diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/security/IssueDescriptor.js b/monkey/monkey_island/cc/ui/src/components/report-components/security/IssueDescriptor.js new file mode 100644 index 000000000..330bf3828 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/report-components/security/IssueDescriptor.js @@ -0,0 +1,7 @@ +class IssueDescriptor { + constructor(name, overviewComponent, reportComponent) { + this.name = name; + this.overviewComponent = overviewComponent; + this.reportComponent = reportComponent; + } +} diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/AzurePasswordIssue.js b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/AzurePasswordIssue.js new file mode 100644 index 000000000..5c849b1c6 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/AzurePasswordIssue.js @@ -0,0 +1,22 @@ +import React from 'react'; + +export function AzurePasswordIssueOverview() { + return (
  • Azure machines expose plaintext passwords. (More info)
  • ) +} + +export function AzurePasswordIssueReport(issue) { + return ( + <> + Delete VM Access plugin configuration files. + + Credentials could be stolen from {issue.machine} for the following users {issue.users}. Read more about the security issue and remediation here. + + + ); +} diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/CrossSegmentIssue.js b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/CrossSegmentIssue.js new file mode 100644 index 000000000..48ffffb59 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/CrossSegmentIssue.js @@ -0,0 +1,84 @@ +import React from 'react'; +import CollapsibleWellComponent from '../CollapsibleWell'; +import {generateInfoBadges} from './utils'; + +export function crossSegmentIssueOverview() { + return (
  • Weak segmentation - Machines from + different segments are able to communicate.
  • ) +} + +export function generateCrossSegmentIssue(crossSegmentIssue) { + let crossSegmentIssueOverview = 'Communication possible from ' + + `${crossSegmentIssue['source_subnet']} to ${crossSegmentIssue['target_subnet']}`; + + return ( +
  • + {crossSegmentIssueOverview} + +
      + {crossSegmentIssue['issues'].map( + issue => generateCrossSegmentIssueListItem(issue) + )} +
    +
    +
  • + ); + } + +export function generateCrossSegmentIssueListItem(issue) { + if (issue['is_self']) { + return this.generateCrossSegmentSingleHostMessage(issue); + } + + return this.generateCrossSegmentMultiHostMessage(issue); + } + +export function generateCrossSegmentSingleHostMessage(issue) { + return ( +
  • + {`Machine ${issue['hostname']} has both ips: ${issue['source']} and ${issue['target']}`} +
  • + ); + } + +export function generateCrossSegmentMultiHostMessage(issue) { + return ( +
  • + IP {issue['source']} ({issue['hostname']}) was able to communicate with + IP {issue['target']} using: +
      + {issue['icmp'] &&
    • ICMP
    • } + {this.generateCrossSegmentServiceListItems(issue)} +
    +
  • + ); + } + +export function generateCrossSegmentServiceListItems(issue) { + let service_list_items = []; + + for (const [service, info] of Object.entries(issue['services'])) { + service_list_items.push( +
  • + {service} ({info['display_name']}) +
  • + ); + } + + return service_list_items; + } + +export function generateIslandCrossSegmentIssue(issue) { + return ( + <> + Segment your network and make sure there is no communication between machines from different segments. + + The network can probably be segmented. A monkey instance on {issue.machine} in the + networks {generateInfoBadges(issue.networks)} + could directly access the Monkey Island server in the + networks {generateInfoBadges(issue.server_networks)}. + + + ); + } diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/DrupalIssue.js b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/DrupalIssue.js new file mode 100644 index 000000000..eefe69ea3 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/DrupalIssue.js @@ -0,0 +1,23 @@ +import React from 'react'; + +export function DrupalIssueOverview() { + return (
  • Drupal server/s are vulnerable to CVE-2019-6340.
  • ) +} + +export function DrupalIssueReport(issue) { + return ( + <> + Upgrade Drupal server to versions 8.5.11, 8.6.10, or later. + + Drupal server at {issue.machine} ({issue.ip_address}) is vulnerable to remote command execution attack. +
    + The attack was made possible because the server is using an old version of Drupal, for which REST API is + enabled. For possible workarounds, fixes and more info read + here. +
    + + ); +} diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/ElasticIssue.js b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/ElasticIssue.js new file mode 100644 index 000000000..60f42fe64 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/ElasticIssue.js @@ -0,0 +1,22 @@ +import React from 'react'; + +export function ElasticIssueOverview() { + return (
  • Elasticsearch servers are vulnerable to CVE-2015-1427. +
  • ) +} + +export function ElasticIssueReport(issue) { + return ( + <> + Update your Elastic Search server to version 1.4.3 and up. + + The machine {issue.machine} ({issue.ip_address}) is vulnerable to an Elastic Groovy attack. +
    + The attack was made possible because the Elastic Search server was not patched against CVE-2015-1427. +
    + + ); +} diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/HadoopIssue.js b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/HadoopIssue.js new file mode 100644 index 000000000..dfcf55226 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/HadoopIssue.js @@ -0,0 +1,22 @@ +import React from 'react'; + +export function HadoopIssueOverview() { + return (
  • Hadoop/Yarn servers are vulnerable to remote code execution.
  • ) +} + +export function HadoopIssueReport(issue) { + return ( + <> + Run Hadoop in secure mode ( + add Kerberos authentication). + + The Hadoop server at {issue.machine} ({issue.ip_address}) is vulnerable to remote code execution attack. +
    + The attack was made possible due to default Hadoop/Yarn configuration being insecure. +
    + + ); +} diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/MS08_067Issue.js b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/MS08_067Issue.js new file mode 100644 index 000000000..fb679b420 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/MS08_067Issue.js @@ -0,0 +1,23 @@ +import React from 'react'; + +export function MS08_067IssueOverview() { + return (
  • Machines are vulnerable to ‘Conficker’ (MS08-067).
  • ) +} + +export function MS08_067IssueReport(issue) { + return ( + <> + Install the latest Windows updates or upgrade to a newer operating system. + + The machine {issue.machine} ({issue.ip_address}) is vulnerable to a Conficker attack. +
    + The attack was made possible because the target machine used an outdated and unpatched operating system + vulnerable to Conficker. +
    + + ); +} diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/MssqlIssue.js b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/MssqlIssue.js new file mode 100644 index 000000000..2bc4ef14a --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/MssqlIssue.js @@ -0,0 +1,23 @@ +import React from 'react'; + +export function MssqlIssueOverview() { + return (
  • MS-SQL servers are vulnerable to remote code execution via xp_cmdshell command.
  • ) +} + +export function MssqlIssueReport(issue) { + return ( + <> + Disable the xp_cmdshell option. + + The machine {issue.machine} ({issue.ip_address}) is vulnerable to a MSSQL exploit attack. +
    + The attack was made possible because the target machine used an outdated MSSQL server configuration allowing + the usage of the xp_cmdshell command. To learn more about how to disable this feature, read + Microsoft's documentation. +
    + + ); +} diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/PthCriticalServiceIssue.js b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/PthCriticalServiceIssue.js new file mode 100644 index 000000000..3a78c3008 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/PthCriticalServiceIssue.js @@ -0,0 +1,6 @@ +import React from 'react'; + +export function PthCriticalServiceIssueOverview() { + return (
  • Mimikatz found login credentials of a user who has admin access to a server defined as + critical.
  • ) +} diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/SambacryIssue.js b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/SambacryIssue.js new file mode 100644 index 000000000..cce80d2ed --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/SambacryIssue.js @@ -0,0 +1,27 @@ +import React from 'react'; + +export function SambacryIssueOverview() { + return (
  • Samba servers are vulnerable to ‘SambaCry’ (CVE-2017-7494).
  • ) +} + +export function SambacryIssueReport(issue) { + return ( + <> + Change {issue.username}'s password to a complex one-use password + that is not shared with other computers on the network. +
    + Update your Samba server to 4.4.14 and up, 4.5.10 and up, or 4.6.4 and up. + + The machine {issue.machine} ({issue.ip_address}) is vulnerable to a SambaCry attack. +
    + The Monkey authenticated over the SMB protocol with user {issue.username} and its password, and used the SambaCry + vulnerability. +
    + + ); +} diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/SharedPasswordsIssue.js b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/SharedPasswordsIssue.js new file mode 100644 index 000000000..cd9dd2fbd --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/SharedPasswordsIssue.js @@ -0,0 +1,49 @@ +import React from 'react'; + +export function sharedPasswordsIssueOverview() { + return (
  • Multiple users have the same password
  • ) +} + +export function sharedAdminsDomainIssueOverview() { + return (
  • Shared local administrator account - Different machines have the same account as a local + administrator.
  • ) +} + +export function generateSharedCredsDomainIssue(issue) { + return ( + <> + Some domain users are sharing passwords, this should be fixed by changing passwords. + + These users are sharing access password: + {this.generateInfoBadges(issue.shared_with)}. + + + ); + } + +export function generateSharedCredsIssue(issue) { + return ( + <> + Some users are sharing passwords, this should be fixed by changing passwords. + + These users are sharing access password: + {this.generateInfoBadges(issue.shared_with)}. + + + ); + } + +export function generateSharedLocalAdminsIssue(issue) { + return ( + <> + Make sure the right administrator accounts are managing the right machines, and that there isn’t an + unintentional local + admin sharing. + + Here is a list of machines which the account {issue.username} is defined as an administrator: + {this.generateInfoBadges(issue.shared_machines)} + + + ); + } diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/ShellShockIssue.js b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/ShellShockIssue.js new file mode 100644 index 000000000..1d143d221 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/ShellShockIssue.js @@ -0,0 +1,29 @@ +import React from 'react'; + +export function ShellShockIssueOverview() { + return (
  • Machines are vulnerable to ‘Shellshock’ (CVE-2014-6271). +
  • ) +} + + +function generateShellshockPathListBadges(paths) { + return paths.map(path => {path}); +} + +export function ShellShockIssueReport(issue) { + return ( + <> + Update your Bash to a ShellShock-patched version. + + The machine {issue.machine} ({issue.ip_address}) is vulnerable to a ShellShock attack. +
    + The attack was made possible because the HTTP server running on TCP port {issue.port} was vulnerable to a shell injection attack on the + paths: {generateShellshockPathListBadges(issue.paths)}. +
    + + ); +} diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/SmbIssue.js b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/SmbIssue.js new file mode 100644 index 000000000..eec516a3e --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/SmbIssue.js @@ -0,0 +1,36 @@ +import React from 'react'; +import CollapsibleWellComponent from '../CollapsibleWell'; + +export function generateSmbPasswordReport(issue) { + return ( + <> + Change {issue.username}'s password to a complex one-use password + that is not shared with other computers on the network. + + The machine {issue.machine} ({issue.ip_address}) is vulnerable to a SMB attack. +
    + The Monkey authenticated over the SMB protocol with user {issue.username} and its password. +
    + + ); +} + +export function generateSmbPthReport(issue) { + return ( + <> + Change {issue.username}'s password to a complex one-use password + that is not shared with other computers on the network. + + The machine {issue.machine} ({issue.ip_address}) is vulnerable to a SMB attack. +
    + The Monkey used a pass-the-hash attack over SMB protocol with user {issue.username}. +
    + + ); +} diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/SshIssue.js b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/SshIssue.js new file mode 100644 index 000000000..baf92bfb7 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/SshIssue.js @@ -0,0 +1,38 @@ +import React from 'react'; + +export function SshIssueOverview() { + return (
  • Stolen SSH keys are used to exploit other machines.
  • ) +} + +export function ShhIssueReport(issue) { + return ( + <> + Change {issue.username}'s password to a complex one-use password + that is not shared with other computers on the network. + + The machine {issue.machine} ({issue.ip_address}) is vulnerable to a SSH attack. +
    + The Monkey authenticated over the SSH protocol with user {issue.username} and its password. +
    + + ); +} + +export function generateSshKeysReport(issue) { + return ( + <> + Protect {issue.ssh_key} private key with a pass phrase. + + The machine {issue.machine} ({issue.ip_address}) is vulnerable to a SSH attack. +
    + The Monkey authenticated over the SSH protocol with private key {issue.ssh_key}. +
    + + ); + } diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/StolenCredsIssue.js b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/StolenCredsIssue.js new file mode 100644 index 000000000..62d92ccc3 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/StolenCredsIssue.js @@ -0,0 +1,5 @@ +import React from 'react'; + +export function StolenCredsIssueOverview() { + return (
  • Stolen credentials are used to exploit other machines.
  • ) +} diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/StrongUsersOnCritIssue.js b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/StrongUsersOnCritIssue.js new file mode 100644 index 000000000..218a8704d --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/StrongUsersOnCritIssue.js @@ -0,0 +1,15 @@ +import React from 'react'; + +export function generateStrongUsersOnCritIssue(issue) { + return ( + <> + This critical machine is open to attacks via strong users with access to it. + + The services: {this.generateInfoBadges(issue.services)} have been found on the machine + thus classifying it as a critical machine. + These users has access to it: + {this.generateInfoBadges(issue.threatening_users)}. + + + ); + } diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/Struts2Issue.js b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/Struts2Issue.js new file mode 100644 index 000000000..7847f447e --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/Struts2Issue.js @@ -0,0 +1,25 @@ +import React from 'react'; + +export function Struts2IssueOverview() { + return (
  • Struts2 servers are vulnerable to remote code execution. ( + CVE-2017-5638)
  • ) +} + +export function Struts2IssueReport(issue) { + return ( + <> + Upgrade Struts2 to version 2.3.32 or 2.5.10.1 or any later versions. + + Struts2 server at {issue.machine} ({issue.ip_address}) is vulnerable to remote code execution attack. +
    + The attack was made possible because the server is using an old version of Jakarta based file upload + Multipart parser. For possible work-arounds and more info read here. +
    + + ); +} diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/TunnelIssue.js b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/TunnelIssue.js new file mode 100644 index 000000000..6d0accd56 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/TunnelIssue.js @@ -0,0 +1,18 @@ +import React from 'react'; + +export function generateTunnelIssueOverview(){ + return (
  • Weak segmentation - Machines were able to communicate over unused ports.
  • ) +} + +export function generateTunnelIssue(issue) { + return ( + <> + Use micro-segmentation policies to disable communication other than the required. + + Machines are not locked down at port level. Network tunnel was set up from {issue.machine} to {issue.dest}. + + + ); + } diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/VsftpdIssue.js b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/VsftpdIssue.js new file mode 100644 index 000000000..0dae286e1 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/VsftpdIssue.js @@ -0,0 +1,35 @@ +import React from 'react'; + +export function VsftpdIssueOverview() { + return (
  • VSFTPD is vulnerable to CVE-2011-2523. +
  • ) +} + +export function VsftpdIssueReport(issue) { + return ( + <> + Update your VSFTPD server to the latest version vsftpd-3.0.3. + + The machine {issue.machine} ({issue.ip_address}) has a backdoor running at + port 6200. +
    + The attack was made possible because the VSFTPD server was not patched against CVE-2011-2523. +

    In July 2011, it was discovered that vsftpd version 2.3.4 downloadable from the master site had been + compromised. + Users logging into a compromised vsftpd-2.3.4 server may issue a ":)" smileyface as the username and gain a + command + shell on port 6200. +

    + The Monkey executed commands by first logging in with ":)" in the username and then sending commands to the + backdoor + at port 6200. +

    Read more about the security issue and remediation here. +
    + + ); +} diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/WeakPasswordIssue.js b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/WeakPasswordIssue.js new file mode 100644 index 000000000..0a7ba30b1 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/WeakPasswordIssue.js @@ -0,0 +1,6 @@ +import React from 'react'; + +export function WeakPasswordIssueOverview() { + return (
  • Machines are accessible using passwords supplied by the user during the Monkey’s + configuration.
  • ) +} diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/WebLogicIssue.js b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/WebLogicIssue.js new file mode 100644 index 000000000..88d0112fa --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/WebLogicIssue.js @@ -0,0 +1,22 @@ +import React from 'react'; + +export function WebLogicIssueOverview() { + return (
  • Oracle WebLogic servers are susceptible to a remote code execution vulnerability.
  • ) +} + +export function WebLogicIssueReport(issue) { + return ( + <> + Update Oracle WebLogic server to the latest supported version. + + Oracle WebLogic server at {issue.machine} ({issue.ip_address}) is vulnerable to one of remote code execution attacks. +
    + The attack was made possible due to one of the following vulnerabilities: + CVE-2017-10271 or + CVE-2019-2725 +
    + + ); +} diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/WmiIssue.js b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/WmiIssue.js new file mode 100644 index 000000000..401f8a9d9 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/WmiIssue.js @@ -0,0 +1,36 @@ +import React from 'react'; +import CollapsibleWellComponent from '../CollapsibleWell'; + +export function generateWmiPasswordIssue(issue) { + return ( + <> + Change {issue.username}'s password to a complex one-use password + that is not shared with other computers on the network. + + The machine {issue.machine} ({issue.ip_address}) is vulnerable to a WMI attack. +
    + The Monkey authenticated over the WMI protocol with user {issue.username} and its password. +
    + + ); + } + +export function generateWmiPthIssue(issue) { + return ( + <> + Change {issue.username}'s password to a complex one-use password + that is not shared with other computers on the network. + + The machine {issue.machine} ({issue.ip_address}) is vulnerable to a WMI attack. +
    + The Monkey used a pass-the-hash attack over WMI protocol with user {issue.username}. +
    + + ); + } diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/utils.js b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/utils.js new file mode 100644 index 000000000..6bc891201 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/report-components/security/issues/utils.js @@ -0,0 +1,6 @@ +import React from 'react'; + +export function generateInfoBadges(data_array) { + return data_array.map(badge_data => {badge_data}); + }