From 1e259fc13149c62bf4ecf5c3847dbc299865df85 Mon Sep 17 00:00:00 2001 From: ophirharpazg Date: Sun, 30 Aug 2020 18:04:26 +0300 Subject: [PATCH] Add a detailed issue to the security report --- .../cc/services/reporting/report.py | 26 ++- .../report-components/SecurityReport.js | 206 ++++++++++-------- 2 files changed, 132 insertions(+), 100 deletions(-) diff --git a/monkey/monkey_island/cc/services/reporting/report.py b/monkey/monkey_island/cc/services/reporting/report.py index e7b38b1d9..d60d53dec 100644 --- a/monkey/monkey_island/cc/services/reporting/report.py +++ b/monkey/monkey_island/cc/services/reporting/report.py @@ -1,22 +1,25 @@ import functools +import ipaddress import itertools import logging - -import ipaddress -from bson import json_util from enum import Enum +from bson import json_util + from common.network.network_range import NetworkRange 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.network_utils import get_subnets, local_ip_addresses from monkey_island.cc.services.config import ConfigService -from monkey_island.cc.services.configuration.utils import get_config_network_segments_as_subnet_groups +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.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 -from monkey_island.cc.network_utils import local_ip_addresses, get_subnets +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 __author__ = "itay.mizeretz" @@ -59,6 +62,7 @@ class ReportService: PTH_CRIT_SERVICES_ACCESS = 11 MSSQL = 12 VSFTPD = 13 + DRUPAL = 14 class WARNINGS_DICT(Enum): CROSS_SEGMENT = 0 @@ -623,7 +627,7 @@ class ReportService: @staticmethod def get_config_exploits(): - exploits_config_value = ['exploits', 'general', 'exploiter_classes'] + exploits_config_value = ['basic', 'exploiters', 'exploiter_classes'] default_exploits = ConfigService.get_default_config(False) for namespace in exploits_config_value: default_exploits = default_exploits[namespace] @@ -637,11 +641,11 @@ class ReportService: @staticmethod def get_config_ips(): - return ConfigService.get_config_value(['basic_network', 'general', 'subnet_scan_list'], True, True) + return ConfigService.get_config_value(['basic_network', 'scope', 'subnet_scan_list'], True, True) @staticmethod def get_config_scan(): - return ConfigService.get_config_value(['basic_network', 'general', 'local_network_scan'], True, True) + return ConfigService.get_config_value(['basic_network', 'scope', 'local_network_scan'], True, True) @staticmethod def get_issues_overview(issues, config_users, config_passwords): @@ -671,6 +675,8 @@ class ReportService: 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'].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 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 a3c29f163..d5bfff63a 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 @@ -161,25 +161,29 @@ class ReportPageComponent extends AuthComponent {

The monkey started propagating from the following machines where it was manually installed: -

+

The monkeys were run with the following configuration:

{ this.state.report.overview.config_users.length > 0 ? -

- Usernames used for brute-forcing: + <> +

+ Usernames used for brute-forcing: +

- Passwords used for brute-forcing: +

+ Passwords used for brute-forcing: +

-

+ :

Brute forcing uses stolen credentials only. No credentials were supplied during Monkey’s @@ -195,7 +199,7 @@ class ReportPageComponent extends AuthComponent {

The Monkey uses the following exploit methods:

) @@ -209,7 +213,7 @@ class ReportPageComponent extends AuthComponent {

The Monkey scans the following IPs:

: @@ -313,15 +317,15 @@ class ReportPageComponent extends AuthComponent { The Monkey uncovered the following possible set of issues: : @@ -443,21 +447,22 @@ class ReportPageComponent extends AuthComponent { } generateInfoBadges(data_array) { - return data_array.map(badge_data => {badge_data}); + return data_array.map(badge_data => {badge_data}); } generateCrossSegmentIssue(crossSegmentIssue) { - return
  • - {'Communication possible from ' + crossSegmentIssue['source_subnet'] + ' to ' + crossSegmentIssue['target_subnet']} + let crossSegmentIssueOverview = 'Communication possible from ' + crossSegmentIssue['source_subnet'] + ' to ' + crossSegmentIssue['target_subnet'] + return
  • + {crossSegmentIssueOverview}
      {crossSegmentIssue['issues'].map(x => x['is_self'] ? -
    • +
    • {'Machine ' + x['hostname'] + ' has both ips: ' + x['source'] + ' and ' + x['target']}
    • : -
    • +
    • {'IP ' + x['source'] + ' (' + x['hostname'] + ') connected to IP ' + x['target'] + ' using the services: ' + Object.keys(x['services']).join(', ')}
    • @@ -468,12 +473,12 @@ class ReportPageComponent extends AuthComponent { } generateShellshockPathListBadges(paths) { - return paths.map(path => {path}); + 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. @@ -484,13 +489,13 @@ class ReportPageComponent extends AuthComponent { 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. @@ -501,13 +506,13 @@ class ReportPageComponent extends AuthComponent { 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. @@ -518,13 +523,13 @@ class ReportPageComponent extends AuthComponent { 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. @@ -535,13 +540,13 @@ class ReportPageComponent extends AuthComponent { 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. @@ -552,13 +557,13 @@ class ReportPageComponent extends AuthComponent { 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.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.
      @@ -589,13 +594,13 @@ class ReportPageComponent extends AuthComponent { className="badge badge-success">{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} (here. -
    • + ); } generateElasticIssue(issue) { return ( -
    • + <> Update your Elastic Search server to version 1.4.3 and up. The machine {issue.machine} ( 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.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 here. -
    • + ); } generateConfickerIssue(issue) { return ( -
    • + <> Install the latest Windows updates or upgrade to a newer operating system. The machine {issue.machine} ( -
    • + ); } 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 -
    • + ); } 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. @@ -730,13 +735,13 @@ class ReportPageComponent extends AuthComponent { className="badge badge-primary">{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 @@ -744,26 +749,26 @@ class ReportPageComponent extends AuthComponent { 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} (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 possible workarounds and more info read here. +
      + ); } generateWebLogicIssue(issue) { return ( -
    • + <> Update Oracle WebLogic server to the latest supported version. Oracle WebLogic server at {issue.machine} ( CVE-2017-10271 or CVE-2019-2725 -
    • + ); } generateHadoopIssue(issue) { return ( -
    • + <> Run Hadoop in secure mode ( add Kerberos authentication). @@ -809,13 +832,13 @@ class ReportPageComponent extends AuthComponent {
      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} ( Microsoft's documentation. -
    • + ); } generateIssue = (issue) => { - let data; + let issueData; switch (issue.type) { case 'vsftp': - data = this.generateVsftpdBackdoorIssue(issue); + issueData = this.generateVsftpdBackdoorIssue(issue); break; case 'smb_password': - data = this.generateSmbPasswordIssue(issue); + issueData = this.generateSmbPasswordIssue(issue); break; case 'smb_pth': - data = this.generateSmbPthIssue(issue); + issueData = this.generateSmbPthIssue(issue); break; case 'wmi_password': - data = this.generateWmiPasswordIssue(issue); + issueData = this.generateWmiPasswordIssue(issue); break; case 'wmi_pth': - data = this.generateWmiPthIssue(issue); + issueData = this.generateWmiPthIssue(issue); break; case 'ssh': - data = this.generateSshIssue(issue); + issueData = this.generateSshIssue(issue); break; case 'ssh_key': - data = this.generateSshKeysIssue(issue); + issueData = this.generateSshKeysIssue(issue); break; case 'sambacry': - data = this.generateSambaCryIssue(issue); + issueData = this.generateSambaCryIssue(issue); break; case 'elastic': - data = this.generateElasticIssue(issue); + issueData = this.generateElasticIssue(issue); break; case 'shellshock': - data = this.generateShellshockIssue(issue); + issueData = this.generateShellshockIssue(issue); break; case 'conficker': - data = this.generateConfickerIssue(issue); + issueData = this.generateConfickerIssue(issue); break; case 'island_cross_segment': - data = this.generateIslandCrossSegmentIssue(issue); + issueData = this.generateIslandCrossSegmentIssue(issue); break; case 'shared_passwords': - data = this.generateSharedCredsIssue(issue); + issueData = this.generateSharedCredsIssue(issue); break; case 'shared_passwords_domain': - data = this.generateSharedCredsDomainIssue(issue); + issueData = this.generateSharedCredsDomainIssue(issue); break; case 'shared_admins_domain': - data = this.generateSharedLocalAdminsIssue(issue); + issueData = this.generateSharedLocalAdminsIssue(issue); break; case 'strong_users_on_crit': - data = this.generateStrongUsersOnCritIssue(issue); + issueData = this.generateStrongUsersOnCritIssue(issue); break; case 'tunnel': - data = this.generateTunnelIssue(issue); + issueData = this.generateTunnelIssue(issue); break; case 'azure_password': - data = this.generateAzureIssue(issue); + issueData = this.generateAzureIssue(issue); break; case 'struts2': - data = this.generateStruts2Issue(issue); + issueData = this.generateStruts2Issue(issue); break; case 'weblogic': - data = this.generateWebLogicIssue(issue); + issueData = this.generateWebLogicIssue(issue); break; case 'hadoop': - data = this.generateHadoopIssue(issue); + issueData = this.generateHadoopIssue(issue); break; case 'mssql': - data = this.generateMSSQLIssue(issue); + issueData = this.generateMSSQLIssue(issue); + break; + case 'drupal': + issueData = this.generateDrupalIssue(issue); break; } - return data; + return
    • {issueData}
    • ; }; generateIssues = (issues) => { let issuesDivArray = []; for (let machine of Object.keys(issues)) { issuesDivArray.push( -
    • +
    • {machine}

        {issues[machine].map(this.generateIssue)}