diff --git a/monkey/monkey_island/cc/resources/attack/attack_config.py b/monkey/monkey_island/cc/resources/attack/attack_config.py index 9ed4c71b0..021663521 100644 --- a/monkey/monkey_island/cc/resources/attack/attack_config.py +++ b/monkey/monkey_island/cc/resources/attack/attack_config.py @@ -25,7 +25,7 @@ class AttackConfiguration(flask_restful.Resource): config_json = json.loads(request.data) if 'reset_attack_matrix' in config_json: AttackConfig.reset_config() - return jsonify(configuration=AttackConfig.get_config()['properties']) + return jsonify(configuration=AttackConfig.get_config()) else: AttackConfig.update_config({'properties': json.loads(request.data)}) AttackConfig.apply_to_monkey_config() diff --git a/monkey/monkey_island/cc/services/attack/attack_config.py b/monkey/monkey_island/cc/services/attack/attack_config.py index a92d448f8..6feff990e 100644 --- a/monkey/monkey_island/cc/services/attack/attack_config.py +++ b/monkey/monkey_island/cc/services/attack/attack_config.py @@ -26,7 +26,7 @@ class AttackConfig(object): :return: Technique object or None if technique is not found """ attack_config = AttackConfig.get_config() - for key, attack_type in list(attack_config['properties'].items()): + for key, attack_type in list(attack_config.items()): for key, technique in list(attack_type['properties'].items()): if key == technique_id: return technique @@ -169,7 +169,7 @@ class AttackConfig(object): """ attack_config = AttackConfig.get_config() techniques = {} - for type_name, attack_type in list(attack_config['properties'].items()): + for type_name, attack_type in list(attack_config.items()): for key, technique in list(attack_type['properties'].items()): techniques[key] = technique['value'] return techniques diff --git a/monkey/monkey_island/cc/ui/src/components/Main.js b/monkey/monkey_island/cc/ui/src/components/Main.js index 9f4b18bc8..b2a9c9789 100644 --- a/monkey/monkey_island/cc/ui/src/components/Main.js +++ b/monkey/monkey_island/cc/ui/src/components/Main.js @@ -10,7 +10,7 @@ import MapPage from 'components/pages/MapPage'; import TelemetryPage from 'components/pages/TelemetryPage'; import StartOverPage from 'components/pages/StartOverPage'; import ReportPage from 'components/pages/ReportPage'; -import ZeroTrustReportPage from 'components/pages/ZeroTrustReportPage'; +import ZeroTrustReportPage from 'components/report-components/ZeroTrustReport'; import LicensePage from 'components/pages/LicensePage'; import AuthComponent from 'components/AuthComponent'; import LoginPageComponent from 'components/pages/LoginPage'; @@ -152,16 +152,7 @@ class AppComponent extends AuthComponent {
  • 4. - Security Report - {this.state.completedSteps.report_done ? - - : ''} - -
  • -
  • - - 5. - Zero Trust Report + Security Reports {this.state.completedSteps.report_done ? : ''} @@ -201,7 +192,7 @@ class AppComponent extends AuthComponent { {this.renderRoute('/infection/map', )} {this.renderRoute('/infection/telemetry', )} {this.renderRoute('/start-over', )} - {this.renderRoute('/report/security', )} + {this.renderRoute('/report/security', )} {this.renderRoute(reportZeroTrustRoute, )} {this.renderRoute('/license', )} diff --git a/monkey/monkey_island/cc/ui/src/components/pages/ReportPage.js b/monkey/monkey_island/cc/ui/src/components/pages/ReportPage.js index 0cc17eb9f..cec7d7ea4 100644 --- a/monkey/monkey_island/cc/ui/src/components/pages/ReportPage.js +++ b/monkey/monkey_island/cc/ui/src/components/pages/ReportPage.js @@ -1,97 +1,76 @@ -import React, {Fragment} from 'react'; -import {Button, Col} from 'react-bootstrap'; -import BreachedServers from 'components/report-components/security/BreachedServers'; -import ScannedServers from 'components/report-components/security/ScannedServers'; -import PostBreach from 'components/report-components/security/PostBreach'; +import React from 'react'; +import {Col, Nav, NavItem} from 'react-bootstrap'; import {ReactiveGraph} from 'components/reactive-graph/ReactiveGraph'; import {edgeGroupToColor, options} 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 PassTheHashMapPageComponent from './PassTheHashMapPage'; -import StrongUsers from 'components/report-components/security/StrongUsers'; -import AttackReport from 'components/report-components/security/AttackReport'; -import ReportHeader, {ReportTypes} from '../report-components/common/ReportHeader'; -import MonkeysStillAliveWarning from '../report-components/common/MonkeysStillAliveWarning'; -import ReportLoader from '../report-components/common/ReportLoader'; import MustRunMonkeyWarning from '../report-components/common/MustRunMonkeyWarning'; -import SecurityIssuesGlance from '../report-components/common/SecurityIssuesGlance'; -import PrintReportButton from '../report-components/common/PrintReportButton'; -import {extractExecutionStatusFromServerResponse} from '../report-components/common/ExecutionStatus'; - -let guardicoreLogoImage = require('../../images/guardicore-logo.png'); +import AttackReport from '../report-components/AttackReport' +import SecurityReport from '../report-components/SecurityReport' +import ZeroTrustReport from '../report-components/ZeroTrustReport' +import {extractExecutionStatusFromServerResponse} from "../report-components/common/ExecutionStatus"; +import MonkeysStillAliveWarning from "../report-components/common/MonkeysStillAliveWarning"; 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 - }; - - Warning = - { - CROSS_SEGMENT: 0, - TUNNEL: 1, - SHARED_LOCAL_ADMIN: 2, - SHARED_PASSWORDS: 3, - SHARED_PASSWORDS_DOMAIN: 4 - }; - constructor(props) { super(props); + this.sectionsOrder = ['security', 'zeroTrust', 'attack']; this.state = { - report: {}, - graph: {nodes: [], edges: []}, + securityReport: {}, + attackReport: {}, + zeroTrustReport: {}, allMonkeysAreDead: false, - runStarted: true + runStarted: true, + selectedSection: 'security', + sections: [{key: 'security', title: 'Security report'}, + {key: 'zeroTrust', title: 'Zero trust report'}, + {key: 'attack', title: 'ATT&CK report'}] }; } - componentDidMount() { - this.updateMonkeysRunning().then(res => this.getReportFromServer(res)); - this.updateMapFromServer(); + getReportFromServer(res) { + if (res['completed_steps']['run_monkey']) { + this.authFetch('/api/report/security') + .then(res => res.json()) + .then(res => { + this.setState({ + securityReport: res + }); + }); + this.authFetch('/api/attack/report') + .then(res => res.json()) + .then(res => { + this.setState({ + attackReport: res + }); + }); + this.updateZeroTrustReportFromServer(); + } } + updateZeroTrustReportFromServer = async () => { + let ztReport = {findings: {}, principles: {}, pillars: {}}; + await this.authFetch('/api/report/zero_trust/findings') + .then(res => res.json()) + .then(res => { + ztReport.findings = res; + }); + await this.authFetch('/api/report/zero_trust/principles') + .then(res => res.json()) + .then(res => { + ztReport.principles = res; + }); + await this.authFetch('/api/report/zero_trust/pillars') + .then(res => res.json()) + .then(res => { + ztReport.pillars = res; + }).then(() => { + this.setState({zeroTrustReport: ztReport}) + })}; + componentWillUnmount() { - clearInterval(this.interval); - } - - render() { - let content; - - if (this.state.runStarted) { - content = this.generateReportContent(); - } else { - content = ; - } - - return ( - -

    4. Security Report

    -
    - {content} -
    - - ); - } - - stillLoadingDataFromServer() { - return Object.keys(this.state.report).length === 0; + clearInterval(this.state.ztReportRefreshInterval); } updateMonkeysRunning = () => { @@ -103,890 +82,57 @@ class ReportPageComponent extends AuthComponent { }); }; - updateMapFromServer = () => { - this.authFetch('/api/netmap') - .then(res => res.json()) - .then(res => { - res.edges.forEach(edge => { - edge.color = {'color': edgeGroupToColor(edge.group)}; - }); - this.setState({graph: res}); - this.props.onStatusChange(); - }); + componentDidMount() { + const ztReportRefreshInterval = setInterval(this.updateZeroTrustReportFromServer, 8000); + this.setState({ztReportRefreshInterval: ztReportRefreshInterval}); + this.updateMonkeysRunning().then(res => this.getReportFromServer(res)); + } + + setSelectedSection = (key) => { + this.setState({ + selectedSection: key + }); }; - getReportFromServer(res) { - if (res['completed_steps']['run_monkey']) { - this.authFetch('/api/report/security') - .then(res => res.json()) - .then(res => { - this.setState({ - report: res - }); - }); + renderNav = () => { + return () + }; + + getReportContent(){ + switch(this.state.selectedSection){ + case 'security': + return (); + case 'attack': + return (); + case 'zeroTrust': + return (); } } - generateReportContent() { + render() { let content; - if (this.stillLoadingDataFromServer()) { - content = ; + if (this.state.runStarted) { + content = this.getReportContent(); } else { - content = -
    - {this.generateReportOverviewSection()} - {this.generateReportFindingsSection()} - {this.generateReportRecommendationsSection()} - {this.generateReportGlanceSection()} - {this.generateAttackSection()} - {this.generateReportFooter()} -
    ; + content = ; } - return ( - -
    - { - print(); - }}/> -
    -
    - -
    + +

    4. Security Reports

    + {this.renderNav()} + +
    {content}
    -
    - { - print(); - }}/> -
    - + ); } - - generateReportOverviewSection() { - return ( -
    -

    - Overview -

    - 0}/> - - { - this.state.report.glance.exploited.length > 0 ? - '' - : -

    - - To improve the monkey's detection rates, try adding users and passwords and enable the "Local - network - scan" config value under Basic - Network. -

    - } -

    - The first monkey run was started on {this.state.report.overview.monkey_start_time}. After {this.state.report.overview.monkey_duration}, all monkeys finished - propagation attempts. -

    -

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

      - {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: -

      - {this.state.report.overview.config_users.map(x =>
    • {x}
    • )} -
    - Passwords used for brute-forcing: -
      - {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 - configuration. -

    - } - { - this.state.report.overview.config_exploits.length > 0 ? - ( - this.state.report.overview.config_exploits[0] === 'default' ? - '' - : -

    - The Monkey uses the following exploit methods: -

      - {this.state.report.overview.config_exploits.map(x =>
    • {x}
    • )} -
    -

    - ) - : -

    - No exploits are used by the Monkey. -

    - } - { - this.state.report.overview.config_ips.length > 0 ? -

    - The Monkey scans the following IPs: -

      - {this.state.report.overview.config_ips.map(x =>
    • {x}
    • )} -
    -

    - : - '' - } - { - this.state.report.overview.config_scan ? - '' - : -

    - Note: Monkeys were configured to avoid scanning of the local network. -

    - } -
    - ); - } - - generateReportFindingsSection() { - 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.state.report.overview.issues.filter(function (x) { - return x === true; - }).length} threats: -
      - {this.state.report.overview.issues[this.Issue.STOLEN_SSH_KEYS] ? -
    • Stolen SSH keys are used to exploit other machines.
    • : null} - {this.state.report.overview.issues[this.Issue.STOLEN_CREDS] ? -
    • Stolen credentials are used to exploit other machines.
    • : null} - {this.state.report.overview.issues[this.Issue.ELASTIC] ? -
    • Elasticsearch servers are vulnerable to CVE-2015-1427. -
    • : null} - {this.state.report.overview.issues[this.Issue.VSFTPD] ? -
    • VSFTPD is vulnerable to CVE-2011-2523. -
    • : null} - {this.state.report.overview.issues[this.Issue.SAMBACRY] ? -
    • Samba servers are vulnerable to ‘SambaCry’ (CVE-2017-7494).
    • : null} - {this.state.report.overview.issues[this.Issue.SHELLSHOCK] ? -
    • Machines are vulnerable to ‘Shellshock’ (CVE-2014-6271). -
    • : null} - {this.state.report.overview.issues[this.Issue.CONFICKER] ? -
    • Machines are vulnerable to ‘Conficker’ (MS08-067).
    • : null} - {this.state.report.overview.issues[this.Issue.WEAK_PASSWORD] ? -
    • Machines are accessible using passwords supplied by the user during the Monkey’s - configuration.
    • : null} - {this.state.report.overview.issues[this.Issue.AZURE] ? -
    • Azure machines expose plaintext passwords. (More info)
    • : null} - {this.state.report.overview.issues[this.Issue.STRUTS2] ? -
    • Struts2 servers are vulnerable to remote code execution. ( - CVE-2017-5638)
    • : null} - {this.state.report.overview.issues[this.Issue.WEBLOGIC] ? -
    • Oracle WebLogic servers are susceptible to a remote code execution vulnerability.
    • : null} - {this.state.report.overview.issues[this.Issue.HADOOP] ? -
    • Hadoop/Yarn servers are vulnerable to remote code execution.
    • : null} - {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.
    • : null} - {this.state.report.overview.issues[this.Issue.MSSQL] ? -
    • MS-SQL servers are vulnerable to remote code execution via xp_cmdshell command.
    • : null} -
    -
    - : -
    - During this simulated attack the Monkey uncovered 0 threats. -
    - } -
    -
    -

    - Potential Security Issues -

    - { - this.state.report.overview.warnings.filter(function (x) { - return x === true; - }).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} -
    -
    - : -
    - The Monkey did not find any issues. -
    - } -
    - {this.state.report.overview.cross_segment_issues.length > 0 ? -
    -

    - Segmentation Issues -

    -
    - The Monkey uncovered the following set of segmentation issues: -
      - {this.state.report.overview.cross_segment_issues.map(x => this.generateCrossSegmentIssue(x))} -
    -
    -
    - : - '' - } -
    - ); - } - - generateReportRecommendationsSection() { - return ( -
    - {/* Checks if there are any domain issues. If there are more then one: render the title. Otherwise, - * don't render it (since the issues themselves will be empty. */} - {Object.keys(this.state.report.recommendations.domain_issues).length !== 0 ? -

    Domain related recommendations

    : null} -
    - {this.generateIssues(this.state.report.recommendations.domain_issues)} -
    - {/* Checks if there are any issues. If there are more then one: render the title. Otherwise, - * don't render it (since the issues themselves will be empty. */} - {Object.keys(this.state.report.recommendations.issues).length !== 0 ? -

    Machine related recommendations

    : null} -
    - {this.generateIssues(this.state.report.recommendations.issues)} -
    -
    - ); - } - - - generateReportGlanceSection() { - let exploitPercentage = - (100 * this.state.report.glance.exploited.length) / this.state.report.glance.scanned.length; - return ( -
    -

    - The Network from the Monkey's Eyes -

    -
    -

    - The Monkey discovered {this.state.report.glance.scanned.length} machines and - successfully breached {this.state.report.glance.exploited.length} of them. -

    -
    - - {Math.round(exploitPercentage)}% of scanned machines exploited -
    -
    -

    - From the attacker's point of view, the network looks like this: -

    -
    - Legend: - Exploit - | - Scan - | - Tunnel - | - Island Communication -
    -
    - -
    -
    - -
    -
    - -
    -
    - -
    -
    - {this.generateReportPthMap()} -
    -
    - -
    -
    - -
    -
    - ); - } - - generateReportPthMap() { - return ( -
    -

    - Credentials Map -

    -

    - This map visualizes possible attack paths through the network using credential compromise. Paths represent lateral - movement opportunities by attackers. -

    -
    - Legend: - Access credentials | -
    -
    - -
    -
    -
    - ); - } - - generateAttackSection() { - return (
    -

    - ATT&CK report -

    -

    - This report shows information about ATT&CK techniques used by Infection Monkey. -

    -
    - -
    -
    -
    ) - } - - generateReportFooter() { - return ( - - ); - } - - generateInfoBadges(data_array) { - return data_array.map(badge_data => {badge_data}); - } - - generateCrossSegmentIssue(crossSegmentIssue) { - return
  • - {'Communication possible from ' + crossSegmentIssue['source_subnet'] + ' to ' + crossSegmentIssue['target_subnet']} - -
      - {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(', ')} -
    • - )} -
    -
    -
  • ; - } - - 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. -
    -
  • - ); - } - - 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 - Microsoft's documentation. -
    -
  • - ); - } - - generateIssue = (issue) => { - let data; - switch (issue.type) { - case 'vsftp': - data = this.generateVsftpdBackdoorIssue(issue); - break; - case 'smb_password': - data = this.generateSmbPasswordIssue(issue); - break; - case 'smb_pth': - data = this.generateSmbPthIssue(issue); - break; - case 'wmi_password': - data = this.generateWmiPasswordIssue(issue); - break; - case 'wmi_pth': - data = this.generateWmiPthIssue(issue); - break; - case 'ssh': - data = this.generateSshIssue(issue); - break; - case 'ssh_key': - data = this.generateSshKeysIssue(issue); - break; - case 'sambacry': - data = this.generateSambaCryIssue(issue); - break; - case 'elastic': - data = this.generateElasticIssue(issue); - break; - case 'shellshock': - data = this.generateShellshockIssue(issue); - break; - case 'conficker': - data = this.generateConfickerIssue(issue); - break; - case 'island_cross_segment': - data = this.generateIslandCrossSegmentIssue(issue); - break; - case 'shared_passwords': - data = this.generateSharedCredsIssue(issue); - break; - case 'shared_passwords_domain': - data = this.generateSharedCredsDomainIssue(issue); - break; - case 'shared_admins_domain': - data = this.generateSharedLocalAdminsIssue(issue); - break; - case 'strong_users_on_crit': - data = this.generateStrongUsersOnCritIssue(issue); - break; - case 'tunnel': - data = this.generateTunnelIssue(issue); - break; - case 'azure_password': - data = this.generateAzureIssue(issue); - break; - case 'struts2': - data = this.generateStruts2Issue(issue); - break; - case 'weblogic': - data = this.generateWebLogicIssue(issue); - break; - case 'hadoop': - data = this.generateHadoopIssue(issue); - break; - case 'mssql': - data = this.generateMSSQLIssue(issue); - break; - } - return data; - }; - - generateIssues = (issues) => { - let issuesDivArray = []; - for (let machine of Object.keys(issues)) { - issuesDivArray.push( -
  • -

    {machine}

    -
      - {issues[machine].map(this.generateIssue)} -
    -
  • - ); - } - return
      {issuesDivArray}
    ; - }; } export default ReportPageComponent; diff --git a/monkey/monkey_island/cc/ui/src/components/pages/ZeroTrustReportPage.js b/monkey/monkey_island/cc/ui/src/components/pages/ZeroTrustReportPage.js deleted file mode 100755 index 02502ee39..000000000 --- a/monkey/monkey_island/cc/ui/src/components/pages/ZeroTrustReportPage.js +++ /dev/null @@ -1,133 +0,0 @@ -import React, {Fragment} from 'react'; -import {Col} from 'react-bootstrap'; -import AuthComponent from '../AuthComponent'; -import ReportHeader, {ReportTypes} from '../report-components/common/ReportHeader'; -import ReportLoader from '../report-components/common/ReportLoader'; -import MustRunMonkeyWarning from '../report-components/common/MustRunMonkeyWarning'; -import PrintReportButton from '../report-components/common/PrintReportButton'; -import {extractExecutionStatusFromServerResponse} from '../report-components/common/ExecutionStatus'; -import SummarySection from '../report-components/zerotrust/SummarySection'; -import FindingsSection from '../report-components/zerotrust/FindingsSection'; -import PrinciplesSection from '../report-components/zerotrust/PrinciplesSection'; - -class ZeroTrustReportPageComponent extends AuthComponent { - - constructor(props) { - super(props); - - this.state = { - allMonkeysAreDead: false, - runStarted: true - }; - } - - componentDidMount() { - this.updatePageState(); - const refreshInterval = setInterval(this.updatePageState, 8000); - this.setState( - {refreshDataIntervalHandler: refreshInterval} - ) - } - - componentWillUnmount() { - clearInterval(this.state.refreshDataIntervalHandler); - } - - updateMonkeysRunning = () => { - return this.authFetch('/api') - .then(res => res.json()) - .then(res => { - this.setState(extractExecutionStatusFromServerResponse(res)); - return res; - }); - }; - - updatePageState = () => { - this.updateMonkeysRunning().then(res => this.getZeroTrustReportFromServer(res)); - }; - - render() { - let content; - if (this.state.runStarted) { - content = this.generateReportContent(); - } else { - content = ; - } - - return ( - -

    5. Zero Trust Report

    -
    - {content} -
    - - ); - } - - generateReportContent() { - let content; - - if (this.stillLoadingDataFromServer()) { - content = ; - } else { - content =
    - - - -
    ; - } - - return ( - -
    - { - print(); - }}/> -
    -
    - -
    - {content} -
    -
    - { - print(); - }}/> -
    -
    - ) - } - - stillLoadingDataFromServer() { - return typeof this.state.findings === 'undefined' - || typeof this.state.pillars === 'undefined' - || typeof this.state.principles === 'undefined'; - } - - getZeroTrustReportFromServer() { - this.authFetch('/api/report/zero_trust/findings') - .then(res => res.json()) - .then(res => { - this.setState({ - findings: res - }); - }); - this.authFetch('/api/report/zero_trust/principles') - .then(res => res.json()) - .then(res => { - this.setState({ - principles: res - }); - }); - this.authFetch('/api/report/zero_trust/pillars') - .then(res => res.json()) - .then(res => { - this.setState({ - pillars: res - }); - }); - } -} - -export default ZeroTrustReportPageComponent; diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/security/AttackReport.js b/monkey/monkey_island/cc/ui/src/components/report-components/AttackReport.js similarity index 55% rename from monkey/monkey_island/cc/ui/src/components/report-components/security/AttackReport.js rename to monkey/monkey_island/cc/ui/src/components/report-components/AttackReport.js index dfc3ff437..add32ad4a 100644 --- a/monkey/monkey_island/cc/ui/src/components/report-components/security/AttackReport.js +++ b/monkey/monkey_island/cc/ui/src/components/report-components/AttackReport.js @@ -2,36 +2,35 @@ import React from 'react'; import {Col} from 'react-bootstrap'; import {ReactiveGraph} from 'components/reactive-graph/ReactiveGraph'; import {edgeGroupToColor, options} from 'components/map/MapOptions'; -import '../../../styles/Collapse.scss'; -import AuthComponent from '../../AuthComponent'; -import {ScanStatus} from '../../attack/techniques/Helpers'; +import '../../styles/Collapse.scss'; +import AuthComponent from '../AuthComponent'; +import {ScanStatus} from '../attack/techniques/Helpers'; import Collapse from '@kunukn/react-collapse'; -import T1210 from '../../attack/techniques/T1210'; -import T1197 from '../../attack/techniques/T1197'; -import T1110 from '../../attack/techniques/T1110'; -import T1075 from '../../attack/techniques/T1075'; -import T1003 from '../../attack/techniques/T1003'; -import T1059 from '../../attack/techniques/T1059'; -import T1086 from '../../attack/techniques/T1086'; -import T1082 from '../../attack/techniques/T1082'; -import T1145 from '../../attack/techniques/T1145'; -import T1105 from '../../attack/techniques/T1105'; -import T1107 from '../../attack/techniques/T1107'; -import T1065 from '../../attack/techniques/T1065'; -import T1035 from '../../attack/techniques/T1035'; -import T1129 from '../../attack/techniques/T1129'; -import T1106 from '../../attack/techniques/T1106'; -import T1188 from '../../attack/techniques/T1188'; -import T1090 from '../../attack/techniques/T1090'; -import T1041 from '../../attack/techniques/T1041'; -import T1222 from '../../attack/techniques/T1222'; -import T1005 from '../../attack/techniques/T1005'; -import T1018 from '../../attack/techniques/T1018'; -import T1016 from '../../attack/techniques/T1016'; -import T1021 from '../../attack/techniques/T1021'; -import T1064 from '../../attack/techniques/T1064'; -import {extractExecutionStatusFromServerResponse} from '../common/ExecutionStatus'; +import T1210 from '../attack/techniques/T1210'; +import T1197 from '../attack/techniques/T1197'; +import T1110 from '../attack/techniques/T1110'; +import T1075 from '../attack/techniques/T1075'; +import T1003 from '../attack/techniques/T1003'; +import T1059 from '../attack/techniques/T1059'; +import T1086 from '../attack/techniques/T1086'; +import T1082 from '../attack/techniques/T1082'; +import T1145 from '../attack/techniques/T1145'; +import T1105 from '../attack/techniques/T1105'; +import T1107 from '../attack/techniques/T1107'; +import T1065 from '../attack/techniques/T1065'; +import T1035 from '../attack/techniques/T1035'; +import T1129 from '../attack/techniques/T1129'; +import T1106 from '../attack/techniques/T1106'; +import T1188 from '../attack/techniques/T1188'; +import T1090 from '../attack/techniques/T1090'; +import T1041 from '../attack/techniques/T1041'; +import T1222 from '../attack/techniques/T1222'; +import T1005 from '../attack/techniques/T1005'; +import T1018 from '../attack/techniques/T1018'; +import T1016 from '../attack/techniques/T1016'; +import T1021 from '../attack/techniques/T1021'; +import T1064 from '../attack/techniques/T1064'; const tech_components = { 'T1210': T1210, @@ -67,35 +66,14 @@ class AttackReportPageComponent extends AuthComponent { constructor(props) { super(props); this.state = { - report: false, - allMonkeysAreDead: false, - runStarted: true, + report: this.props.report, collapseOpen: '' }; } - componentDidMount() { - this.updateMonkeysRunning().then(res => this.getReportFromServer(res)); - } - - updateMonkeysRunning = () => { - return this.authFetch('/api') - .then(res => res.json()) - .then(res => { - this.setState(extractExecutionStatusFromServerResponse(res)); - return res; - }); - }; - - getReportFromServer(res) { - if (res['completed_steps']['run_monkey']) { - this.authFetch('/api/attack/report') - .then(res => res.json()) - .then(res => { - this.setState({ - report: res - }); - }); + componentDidUpdate(prevProps) { + if (this.props.report !== prevProps.report) { + this.setState({ report: this.props.report }) } } @@ -168,31 +146,28 @@ class AttackReportPageComponent extends AuthComponent { content.push(this.getTechniqueCollapse(tech_id)) }); return ( +
    +

    + ATT&CK report +

    +

    + This report shows information about ATT&CK techniques used by Infection Monkey. +

    {this.renderLegend()}
    {content}
    +
    +
    ) } render() { - let content; - if (!this.state.runStarted) { - content = -

    - - You have to run a monkey before generating a report! -

    ; - } else if (this.state.report === false) { - content = (

    Generating Report...

    ); - } else if (Object.keys(this.state.report).length === 0) { - if (this.state.runStarted) { - content = (

    No techniques were scanned

    ); - } + if (Object.keys(this.state.report).length === 0 && this.state.runStarted) { + return (

    No techniques were scanned

    ); } else { - content = this.generateReportContent(); + return (
    {this.generateReportContent()}
    ); } - return (
    {content}
    ); } } 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 new file mode 100644 index 000000000..cefa2d360 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/report-components/SecurityReport.js @@ -0,0 +1,932 @@ +import React, {Fragment} from 'react'; +import BreachedServers from 'components/report-components/security/BreachedServers'; +import ScannedServers from 'components/report-components/security/ScannedServers'; +import PostBreach from 'components/report-components/security/PostBreach'; +import {ReactiveGraph} from 'components/reactive-graph/ReactiveGraph'; +import {edgeGroupToColor, options} 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 PassTheHashMapPageComponent from '../pages/PassTheHashMapPage'; +import StrongUsers from 'components/report-components/security/StrongUsers'; +import ReportHeader, {ReportTypes} from './common/ReportHeader'; +import ReportLoader from './common/ReportLoader'; +import SecurityIssuesGlance from './common/SecurityIssuesGlance'; +import PrintReportButton from './common/PrintReportButton'; + +let guardicoreLogoImage = require('../../images/guardicore-logo.png'); + + +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 + }; + + Warning = + { + CROSS_SEGMENT: 0, + TUNNEL: 1, + SHARED_LOCAL_ADMIN: 2, + SHARED_PASSWORDS: 3, + SHARED_PASSWORDS_DOMAIN: 4 + }; + + constructor(props) { + super(props); + this.state = { + report: props.report, + graph: {nodes: [], edges: []} + }; + } + + componentDidMount() { + this.updateMapFromServer(); + } + + componentWillUnmount() { + clearInterval(this.interval); + } + + componentDidUpdate(prevProps) { + if (this.props.report !== prevProps.report) { + this.setState({ report: this.props.report }) + } + } + + render() { + let content; + + if (this.stillLoadingDataFromServer()) { + content = ; + } else { + content = +
    + {this.generateReportOverviewSection()} + {this.generateReportFindingsSection()} + {this.generateReportRecommendationsSection()} + {this.generateReportGlanceSection()} + {this.generateReportFooter()} +
    ; + } + + return ( + +
    + { + print(); + }}/> +
    +
    + +
    + {content} +
    +
    + { + print(); + }}/> +
    +
    + ); + } + + stillLoadingDataFromServer() { + return Object.keys(this.state.report).length === 0; + } + + updateMapFromServer = () => { + this.authFetch('/api/netmap') + .then(res => res.json()) + .then(res => { + res.edges.forEach(edge => { + edge.color = {'color': edgeGroupToColor(edge.group)}; + }); + this.setState({graph: res}); + }); + }; + + + generateReportOverviewSection() { + return ( +
    +

    + Overview +

    + 0}/> + { + this.state.report.glance.exploited.length > 0 ? + '' + : +

    + + To improve the monkey's detection rates, try adding users and passwords and enable the "Local + network + scan" config value under Basic - Network. +

    + } +

    + The first monkey run was started on {this.state.report.overview.monkey_start_time}. After {this.state.report.overview.monkey_duration}, all monkeys finished + propagation attempts. +

    +

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

      + {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: +

      + {this.state.report.overview.config_users.map(x =>
    • {x}
    • )} +
    + Passwords used for brute-forcing: +
      + {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 + configuration. +

    + } + { + this.state.report.overview.config_exploits.length > 0 ? + ( + this.state.report.overview.config_exploits[0] === 'default' ? + '' + : +

    + The Monkey uses the following exploit methods: +

      + {this.state.report.overview.config_exploits.map(x =>
    • {x}
    • )} +
    +

    + ) + : +

    + No exploits are used by the Monkey. +

    + } + { + this.state.report.overview.config_ips.length > 0 ? +

    + The Monkey scans the following IPs: +

      + {this.state.report.overview.config_ips.map(x =>
    • {x}
    • )} +
    +

    + : + '' + } + { + this.state.report.overview.config_scan ? + '' + : +

    + Note: Monkeys were configured to avoid scanning of the local network. +

    + } +
    + ); + } + + generateReportFindingsSection() { + 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.state.report.overview.issues.filter(function (x) { + return x === true; + }).length} threats: +
      + {this.state.report.overview.issues[this.Issue.STOLEN_SSH_KEYS] ? +
    • Stolen SSH keys are used to exploit other machines.
    • : null} + {this.state.report.overview.issues[this.Issue.STOLEN_CREDS] ? +
    • Stolen credentials are used to exploit other machines.
    • : null} + {this.state.report.overview.issues[this.Issue.ELASTIC] ? +
    • Elasticsearch servers are vulnerable to CVE-2015-1427. +
    • : null} + {this.state.report.overview.issues[this.Issue.VSFTPD] ? +
    • VSFTPD is vulnerable to CVE-2011-2523. +
    • : null} + {this.state.report.overview.issues[this.Issue.SAMBACRY] ? +
    • Samba servers are vulnerable to ‘SambaCry’ (CVE-2017-7494).
    • : null} + {this.state.report.overview.issues[this.Issue.SHELLSHOCK] ? +
    • Machines are vulnerable to ‘Shellshock’ (CVE-2014-6271). +
    • : null} + {this.state.report.overview.issues[this.Issue.CONFICKER] ? +
    • Machines are vulnerable to ‘Conficker’ (MS08-067).
    • : null} + {this.state.report.overview.issues[this.Issue.WEAK_PASSWORD] ? +
    • Machines are accessible using passwords supplied by the user during the Monkey’s + configuration.
    • : null} + {this.state.report.overview.issues[this.Issue.AZURE] ? +
    • Azure machines expose plaintext passwords. (More info)
    • : null} + {this.state.report.overview.issues[this.Issue.STRUTS2] ? +
    • Struts2 servers are vulnerable to remote code execution. ( + CVE-2017-5638)
    • : null} + {this.state.report.overview.issues[this.Issue.WEBLOGIC] ? +
    • Oracle WebLogic servers are susceptible to a remote code execution vulnerability.
    • : null} + {this.state.report.overview.issues[this.Issue.HADOOP] ? +
    • Hadoop/Yarn servers are vulnerable to remote code execution.
    • : null} + {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.
    • : null} + {this.state.report.overview.issues[this.Issue.MSSQL] ? +
    • MS-SQL servers are vulnerable to remote code execution via xp_cmdshell command.
    • : null} +
    +
    + : +
    + During this simulated attack the Monkey uncovered 0 threats. +
    + } +
    +
    +

    + Potential Security Issues +

    + { + this.state.report.overview.warnings.filter(function (x) { + return x === true; + }).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} +
    +
    + : +
    + The Monkey did not find any issues. +
    + } +
    + {this.state.report.overview.cross_segment_issues.length > 0 ? +
    +

    + Segmentation Issues +

    +
    + The Monkey uncovered the following set of segmentation issues: +
      + {this.state.report.overview.cross_segment_issues.map(x => this.generateCrossSegmentIssue(x))} +
    +
    +
    + : + '' + } +
    + ); + } + + generateReportRecommendationsSection() { + return ( +
    + {/* Checks if there are any domain issues. If there are more then one: render the title. Otherwise, + * don't render it (since the issues themselves will be empty. */} + {Object.keys(this.state.report.recommendations.domain_issues).length !== 0 ? +

    Domain related recommendations

    : null} +
    + {this.generateIssues(this.state.report.recommendations.domain_issues)} +
    + {/* Checks if there are any issues. If there are more then one: render the title. Otherwise, + * don't render it (since the issues themselves will be empty. */} + {Object.keys(this.state.report.recommendations.issues).length !== 0 ? +

    Machine related recommendations

    : null} +
    + {this.generateIssues(this.state.report.recommendations.issues)} +
    +
    + ); + } + + generateReportGlanceSection() { + let exploitPercentage = + (100 * this.state.report.glance.exploited.length) / this.state.report.glance.scanned.length; + return ( +
    +

    + The Network from the Monkey's Eyes +

    +
    +

    + The Monkey discovered {this.state.report.glance.scanned.length} machines and + successfully breached {this.state.report.glance.exploited.length} of them. +

    +
    + + {Math.round(exploitPercentage)}% of scanned machines exploited +
    +
    +

    + From the attacker's point of view, the network looks like this: +

    +
    + Legend: + Exploit + | + Scan + | + Tunnel + | + Island Communication +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + {this.generateReportPthMap()} +
    +
    + +
    +
    + +
    +
    + ); + } + + generateReportPthMap() { + return ( +
    +

    + Credentials Map +

    +

    + This map visualizes possible attack paths through the network using credential compromise. Paths represent lateral + movement opportunities by attackers. +

    +
    + Legend: + Access credentials | +
    +
    + +
    +
    +
    + ); + } + + generateReportFooter() { + return ( + + ); + } + + generateInfoBadges(data_array) { + return data_array.map(badge_data => {badge_data}); + } + + generateCrossSegmentIssue(crossSegmentIssue) { + return
  • + {'Communication possible from ' + crossSegmentIssue['source_subnet'] + ' to ' + crossSegmentIssue['target_subnet']} + +
      + {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(', ')} +
    • + )} +
    +
    +
  • ; + } + + 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. +
    +
  • + ); + } + + 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 + Microsoft's documentation. +
    +
  • + ); + } + + generateIssue = (issue) => { + let data; + switch (issue.type) { + case 'vsftp': + data = this.generateVsftpdBackdoorIssue(issue); + break; + case 'smb_password': + data = this.generateSmbPasswordIssue(issue); + break; + case 'smb_pth': + data = this.generateSmbPthIssue(issue); + break; + case 'wmi_password': + data = this.generateWmiPasswordIssue(issue); + break; + case 'wmi_pth': + data = this.generateWmiPthIssue(issue); + break; + case 'ssh': + data = this.generateSshIssue(issue); + break; + case 'ssh_key': + data = this.generateSshKeysIssue(issue); + break; + case 'sambacry': + data = this.generateSambaCryIssue(issue); + break; + case 'elastic': + data = this.generateElasticIssue(issue); + break; + case 'shellshock': + data = this.generateShellshockIssue(issue); + break; + case 'conficker': + data = this.generateConfickerIssue(issue); + break; + case 'island_cross_segment': + data = this.generateIslandCrossSegmentIssue(issue); + break; + case 'shared_passwords': + data = this.generateSharedCredsIssue(issue); + break; + case 'shared_passwords_domain': + data = this.generateSharedCredsDomainIssue(issue); + break; + case 'shared_admins_domain': + data = this.generateSharedLocalAdminsIssue(issue); + break; + case 'strong_users_on_crit': + data = this.generateStrongUsersOnCritIssue(issue); + break; + case 'tunnel': + data = this.generateTunnelIssue(issue); + break; + case 'azure_password': + data = this.generateAzureIssue(issue); + break; + case 'struts2': + data = this.generateStruts2Issue(issue); + break; + case 'weblogic': + data = this.generateWebLogicIssue(issue); + break; + case 'hadoop': + data = this.generateHadoopIssue(issue); + break; + case 'mssql': + data = this.generateMSSQLIssue(issue); + break; + } + return data; + }; + + generateIssues = (issues) => { + let issuesDivArray = []; + for (let machine of Object.keys(issues)) { + issuesDivArray.push( +
  • +

    {machine}

    +
      + {issues[machine].map(this.generateIssue)} +
    +
  • + ); + } + return
      {issuesDivArray}
    ; + }; +} + +export default ReportPageComponent; diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/ZeroTrustReport.js b/monkey/monkey_island/cc/ui/src/components/report-components/ZeroTrustReport.js new file mode 100644 index 000000000..772802c9d --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/report-components/ZeroTrustReport.js @@ -0,0 +1,66 @@ +import React, {Fragment} from 'react'; +import AuthComponent from '../AuthComponent'; +import ReportHeader, {ReportTypes} from './common/ReportHeader'; +import ReportLoader from './common/ReportLoader'; +import PrintReportButton from './common/PrintReportButton'; +import SummarySection from './zerotrust/SummarySection'; +import FindingsSection from './zerotrust/FindingsSection'; +import PrinciplesSection from './zerotrust/PrinciplesSection'; + +class ZeroTrustReportPageComponent extends AuthComponent { + + constructor(props) { + super(props); + this.state = this.props.report + } + + componentDidUpdate(prevProps) { + if (this.props.report !== prevProps.report) { + this.setState(this.props.report) + } + } + + render() { + let content; + if (this.stillLoadingDataFromServer()) { + content = ; + } else { + content =
    + + + +
    ; + } + + return ( + +
    + { + print(); + }}/> +
    +
    + +
    + {content} +
    +
    + { + print(); + }}/> +
    +
    + ) + } + + stillLoadingDataFromServer() { + return typeof this.state.findings === 'undefined' + || typeof this.state.pillars === 'undefined' + || typeof this.state.principles === 'undefined'; + } + + +} + +export default ZeroTrustReportPageComponent; diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/zerotrust/SummarySection.js b/monkey/monkey_island/cc/ui/src/components/report-components/zerotrust/SummarySection.js index b6693ab59..d765b9667 100644 --- a/monkey/monkey_island/cc/ui/src/components/report-components/zerotrust/SummarySection.js +++ b/monkey/monkey_island/cc/ui/src/components/report-components/zerotrust/SummarySection.js @@ -1,6 +1,5 @@ import React, {Component} from 'react'; import {Col, Grid, Row} from 'react-bootstrap'; -import MonkeysStillAliveWarning from '../common/MonkeysStillAliveWarning'; import PillarsOverview from './PillarOverview'; import ZeroTrustReportLegend from './ReportLegend'; import * as PropTypes from 'prop-types'; @@ -12,7 +11,6 @@ export default class SummarySection extends Component { -

    Get a quick glance at how your network aligns with the @@ -36,6 +34,5 @@ export default class SummarySection extends Component { } SummarySection.propTypes = { - allMonkeysAreDead: PropTypes.bool, pillars: PropTypes.object };