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:
-
- {this.state.report.overview.manual_monkeys.map(x => - {x}
)}
-
+
+ {this.state.report.overview.manual_monkeys.map(x => - {x}
)}
+
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:
+
- {this.state.report.overview.config_users.map(x => - {x}
)}
+ {this.state.report.overview.config_users.map(x => - {x}
)}
- Passwords used for brute-forcing:
+
+ Passwords used for brute-forcing:
+
- {this.state.report.overview.config_passwords.map(x => - {x.substr(0, 3) + '******'}
)}
+ {this.state.report.overview.config_passwords.map(x => - {x.substr(0, 3) + '******'}
)}
-
+ >
:
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:
- {this.state.report.overview.config_exploits.map(x => - {x}
)}
+ {this.state.report.overview.config_exploits.map(x => - {x}
)}
)
@@ -209,7 +213,7 @@ class ReportPageComponent extends AuthComponent {
The Monkey scans the following IPs:
- {this.state.report.overview.config_ips.map(x => - {x}
)}
+ {this.state.report.overview.config_ips.map(x => - {x}
)}
:
@@ -313,15 +317,15 @@ class ReportPageComponent extends AuthComponent {
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
+
- 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}
+ - 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
+
- 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}
+ - Multiple users have the same password
: null}
:
@@ -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)}