From c8b4089bd2a11b158059f3601195a5c67da7355d Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Mon, 1 Feb 2021 17:06:11 -0500 Subject: [PATCH 1/5] ui: display cross-segment issues as "pinged" if no services/ports Issue #819 --- .../report-components/SecurityReport.js | 70 ++++++++++++++----- 1 file changed, 52 insertions(+), 18 deletions(-) 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 63749ced1..9a4e2120a 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 @@ -452,24 +452,58 @@ class ReportPageComponent extends AuthComponent { generateCrossSegmentIssue(crossSegmentIssue) { 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(', ')} -
    • - )} -
    -
    -
  • ; + + return ( +
  • + {crossSegmentIssueOverview} + +
      + {crossSegmentIssue['issues'].map(issue => this.generateCrossSegmentIssueListItem(issue))} +
    +
    +
  • + ); + } + + generateCrossSegmentIssueListItem(issue) { + if (issue['is_self']) { + return this.generateCrossSegmentSingleHostMessage(issue); + } + + return this.generateCrossSegmentMultiHostMessage(issue); + } + + generateCrossSegmentSingleHostMessage(issue) { + return ( +
  • + {'Machine ' + issue['hostname'] + ' has both ips: ' + issue['source'] + ' and ' + issue['target']} +
  • + ); + } + + generateCrossSegmentMultiHostMessage(issue) { + return ( +
  • + { + Object.keys(issue['services']).length > 0 ? + this.generateCrossSegmentServiceMessage(issue) : + this.generateCrossSegmentPingMessage(issue) + } +
  • + ); + } + + generateCrossSegmentServiceMessage(issue) { + return ( + 'IP ' + issue['source'] + ' (' + issue['hostname'] + ') connected to IP ' + issue['target'] + + ' using the services: ' + Object.keys(issue['services']).join(', ') + ); + } + + generateCrossSegmentPingMessage(issue) { + return ( + `IP ${issue['source']} (${issue['hostname']}) successfully pinged IP ${issue['target']}` + ); } generateShellshockPathListBadges(paths) { From 458e01cf247b066019afbb12ff0897078469f1eb Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Tue, 2 Feb 2021 06:49:21 -0500 Subject: [PATCH 2/5] ui: use template strings when generating cross-segment report --- .../src/components/report-components/SecurityReport.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) 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 9a4e2120a..f8c8fa192 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 @@ -451,7 +451,8 @@ class ReportPageComponent extends AuthComponent { } generateCrossSegmentIssue(crossSegmentIssue) { - let crossSegmentIssueOverview = 'Communication possible from ' + crossSegmentIssue['source_subnet'] + ' to ' + crossSegmentIssue['target_subnet'] + let crossSegmentIssueOverview = 'Communication possible from ' + + `${crossSegmentIssue['source_subnet']} to ${crossSegmentIssue['target_subnet']}`; return (
  • @@ -476,7 +477,7 @@ class ReportPageComponent extends AuthComponent { generateCrossSegmentSingleHostMessage(issue) { return (
  • - {'Machine ' + issue['hostname'] + ' has both ips: ' + issue['source'] + ' and ' + issue['target']} + {`Machine ${issue['hostname']} has both ips: ${issue['source']} and ${issue['target']}`}
  • ); } @@ -495,8 +496,8 @@ class ReportPageComponent extends AuthComponent { generateCrossSegmentServiceMessage(issue) { return ( - 'IP ' + issue['source'] + ' (' + issue['hostname'] + ') connected to IP ' + issue['target'] - + ' using the services: ' + Object.keys(issue['services']).join(', ') + `IP ${issue['source']} (${issue['hostname']}) connected to IP ${issue['target']}` + + ` using the services: ${Object.keys(issue['services']).join(', ')}` ); } From c7a1f246cbfdf4162cd8fca07c2db6505cc4d073 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Tue, 2 Feb 2021 11:00:59 -0500 Subject: [PATCH 3/5] agent: add icmp property to VictimHost Keep track of whether or not PingScanner was successful by storing a boolean in VictimHost objects. This information is communicated back to the Monkey Island via telemetry. --- monkey/infection_monkey/model/host.py | 3 ++- monkey/infection_monkey/network/ping_scanner.py | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/monkey/infection_monkey/model/host.py b/monkey/infection_monkey/model/host.py index 1a4fef1c8..d71446108 100644 --- a/monkey/infection_monkey/model/host.py +++ b/monkey/infection_monkey/model/host.py @@ -7,6 +7,7 @@ class VictimHost(object): self.domain_name = str(domain_name) self.os = {} self.services = {} + self.icmp = False self.monkey_exe = None self.default_tunnel = None self.default_server = None @@ -40,7 +41,7 @@ class VictimHost(object): victim += "] Services - [" for k, v in list(self.services.items()): victim += "%s-%s " % (k, v) - victim += '] ' + victim += '] ICMP: %s ' % (self.icmp) victim += "target monkey: %s" % self.monkey_exe return victim diff --git a/monkey/infection_monkey/network/ping_scanner.py b/monkey/infection_monkey/network/ping_scanner.py index 27c814593..fd19550a3 100644 --- a/monkey/infection_monkey/network/ping_scanner.py +++ b/monkey/infection_monkey/network/ping_scanner.py @@ -62,6 +62,9 @@ class PingScanner(HostScanner, HostFinger): host.os['type'] = 'linux' else: # as far we we know, could also be OSX/BSD but lets handle that when it comes up. host.os['type'] = 'windows' + + host.icmp = True + return True except Exception as exc: LOG.debug("Error parsing ping fingerprint: %s", exc) From c6bec1335cf7f8590289927766a01314299ed182 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Tue, 2 Feb 2021 11:03:39 -0500 Subject: [PATCH 4/5] island: include 'icmp' from scan telemetry in report --- monkey/monkey_island/cc/services/reporting/report.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/monkey/monkey_island/cc/services/reporting/report.py b/monkey/monkey_island/cc/services/reporting/report.py index d60d53dec..1e77065d4 100644 --- a/monkey/monkey_island/cc/services/reporting/report.py +++ b/monkey/monkey_island/cc/services/reporting/report.py @@ -510,6 +510,7 @@ class ReportService: 'hostname': monkey['hostname'], 'target': target_ip, 'services': scan['data']['machine']['services'], + 'icmp': scan['data']['machine']['icmp'], 'is_self': False }) @@ -544,7 +545,7 @@ class ReportService: @staticmethod def get_cross_segment_issues(): scans = mongo.db.telemetry.find({'telem_category': 'scan'}, - {'monkey_guid': 1, 'data.machine.ip_addr': 1, 'data.machine.services': 1}) + {'monkey_guid': 1, 'data.machine.ip_addr': 1, 'data.machine.services': 1, 'data.machine.icmp': 1}) cross_segment_issues = [] From 919c51b9202342e0c705fedc815499be121838a3 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Tue, 2 Feb 2021 11:06:27 -0500 Subject: [PATCH 5/5] ui: display ICMP in cross-segment issues report --- .../report-components/SecurityReport.js | 38 ++++++++++--------- .../src/styles/pages/report/ReportPage.scss | 9 +++++ 2 files changed, 30 insertions(+), 17 deletions(-) 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 f8c8fa192..1d6072ece 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 @@ -458,8 +458,10 @@ class ReportPageComponent extends AuthComponent {
  • {crossSegmentIssueOverview} -
      - {crossSegmentIssue['issues'].map(issue => this.generateCrossSegmentIssueListItem(issue))} +
        + {crossSegmentIssue['issues'].map( + issue => this.generateCrossSegmentIssueListItem(issue) + )}
      @@ -485,26 +487,28 @@ class ReportPageComponent extends AuthComponent { generateCrossSegmentMultiHostMessage(issue) { return (
    • - { - Object.keys(issue['services']).length > 0 ? - this.generateCrossSegmentServiceMessage(issue) : - this.generateCrossSegmentPingMessage(issue) - } + IP {issue['source']} ({issue['hostname']}) was able to communicate with + IP {issue['target']} using: +
        + {issue['icmp'] &&
      • ICMP
      • } + {this.generateCrossSegmentServiceListItems(issue)} +
    • ); } - generateCrossSegmentServiceMessage(issue) { - return ( - `IP ${issue['source']} (${issue['hostname']}) connected to IP ${issue['target']}` - + ` using the services: ${Object.keys(issue['services']).join(', ')}` - ); - } + generateCrossSegmentServiceListItems(issue) { + let service_list_items = []; - generateCrossSegmentPingMessage(issue) { - return ( - `IP ${issue['source']} (${issue['hostname']}) successfully pinged IP ${issue['target']}` - ); + for (const [service, info] of Object.entries(issue['services'])) { + service_list_items.push( +
    • + {service} ({info['display_name']}) +
    • + ); + } + + return service_list_items; } generateShellshockPathListBadges(paths) { diff --git a/monkey/monkey_island/cc/ui/src/styles/pages/report/ReportPage.scss b/monkey/monkey_island/cc/ui/src/styles/pages/report/ReportPage.scss index 5fb8252fe..088e012f3 100644 --- a/monkey/monkey_island/cc/ui/src/styles/pages/report/ReportPage.scss +++ b/monkey/monkey_island/cc/ui/src/styles/pages/report/ReportPage.scss @@ -76,3 +76,12 @@ div.report-wrapper .nav-tabs > .nav-item > a:hover:not(.active), .nav-tabs > .n text-decoration: none; background-color: $light-gray; } + +ul.cross-segment-issues { + list-style-type: none; + padding: 0px; + margin: 0px; +} +span.cross-segment-service { + text-transform: uppercase; +}