From da3a2c1a02f7e6174f520911b548a55c1bebcec8 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Fri, 23 Jul 2021 11:13:54 -0400 Subject: [PATCH] UI: Display encrypted file paths in ransomware report table --- .../cc/ui/src/components/pages/ReportPage.js | 15 ++- .../report-components/RansomwareReport.js | 2 +- .../ransomware/FileEncryptionTable.tsx | 106 ++++++++++++------ 3 files changed, 89 insertions(+), 34 deletions(-) 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 c45dbe7e7..b2d1446b3 100644 --- a/monkey/monkey_island/cc/ui/src/components/pages/ReportPage.js +++ b/monkey/monkey_island/cc/ui/src/components/pages/ReportPage.js @@ -22,6 +22,7 @@ class ReportPageComponent extends AuthComponent { attackReport: {}, zeroTrustReport: {}, ransomwareReport: {}, + ransomwareTelemetry: {}, allMonkeysAreDead: false, runStarted: true, selectedSection: ReportPageComponent.selectReport(this.sections), @@ -67,6 +68,13 @@ class ReportPageComponent extends AuthComponent { ransomwareReport: res }); }); + this.authFetch('/api/telemetry?telem_category=file_encryption') + .then(res => res.json()) + .then(res => { + this.setState({ + ransomwareTelemetry: res + }); + }); } } @@ -156,7 +164,12 @@ class ReportPageComponent extends AuthComponent { case 'zeroTrust': return (); case 'ransomware': - return (); + return ( + + ); } } diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/RansomwareReport.js b/monkey/monkey_island/cc/ui/src/components/report-components/RansomwareReport.js index 3e7a96311..94a4f331e 100644 --- a/monkey/monkey_island/cc/ui/src/components/report-components/RansomwareReport.js +++ b/monkey/monkey_island/cc/ui/src/components/report-components/RansomwareReport.js @@ -19,7 +19,7 @@ class RansomwareReport extends React.Component {
- +
) } diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/ransomware/FileEncryptionTable.tsx b/monkey/monkey_island/cc/ui/src/components/report-components/ransomware/FileEncryptionTable.tsx index 340238891..891fdfd87 100644 --- a/monkey/monkey_island/cc/ui/src/components/report-components/ransomware/FileEncryptionTable.tsx +++ b/monkey/monkey_island/cc/ui/src/components/report-components/ransomware/FileEncryptionTable.tsx @@ -1,25 +1,36 @@ import React from 'react'; import ReactTable from 'react-table'; -import {renderArray} from '../common/RenderArrays'; type Props = { - tableData: [TableRow] + telemetry: object, } type TableRow = { - exploits: [string], - total_attempts: number, - successful_encryptions: number, - hostname: string + hostname: string, + file_path: number, } -const pageSize = 10; - +const PAGE_SIZE = 10; +const HOSTNAME_REGEX = /^(.* - )?(\S+) :.*$/ +const columns = [ + { + Header: 'Encrypted Files', + columns: [ + {Header: 'Host', id: 'host', accessor: x => x.hostname}, + {Header: 'File Path', id: 'file_path', accessor: x => x.file_path}, + {Header: 'Encryption Algorithm', + id: 'encryption_algorithm', + accessor: () => {return 'Bit Flip'}} + ] + } +]; const FileEncryptionTable = (props: Props) => { - let defaultPageSize = props.tableData.length > pageSize ? pageSize : props.tableData.length; - let showPagination = props.tableData.length > pageSize; + let tableData = processTelemetry(props.telemetry); + let defaultPageSize = tableData.length > PAGE_SIZE ? PAGE_SIZE : tableData.length; + let showPagination = tableData.length > PAGE_SIZE; + return ( <>

@@ -28,7 +39,7 @@ const FileEncryptionTable = (props: Props) => {
@@ -37,30 +48,61 @@ const FileEncryptionTable = (props: Props) => { ); } -const columns = [ - { - Header: 'Ransomware info', - columns: [ - {Header: 'Machine', id: 'machine', accessor: x => x.hostname}, - {Header: 'Exploits', id: 'exploits', accessor: x => renderArray(x.exploits)}, - {Header: 'Files encrypted', - id: 'files_encrypted', - accessor: x => renderFileEncryptionStats(x.successful_encryptions, x.total_attempts)} - ] - } -]; +function processTelemetry(telemetry): Array { + // Sort ascending so that newer telemetry records overwrite older ones. + sortTelemetry(telemetry); -function renderFileEncryptionStats(successful: number, total: number) { - let textClassName = '' + let latestTelemetry = getLatestTelemetry(telemetry); + let tableData = getDataForTable(latestTelemetry); - if(successful > 0) { - textClassName = 'text-danger' - } else { - textClassName = 'text-dark' - } - - return (

{successful} out of {total}

); + return tableData; } +function sortTelemetry(telemetry): void { + telemetry.objects.sort((a, b) => { + if (a.timestamp > b.timestamp) { + return 1; + } else if (a.timestamp > b.timestamp) { + return -1; + } + + return 0; + }); +} + +function getLatestTelemetry(telemetry) { + let latestTelemetry = {}; + for (let i = 0; i < telemetry.objects.length; i++) { + let monkey = telemetry.objects[i].monkey + + if (! (monkey in latestTelemetry)) { + latestTelemetry[monkey] = {}; + } + + telemetry.objects[i].data.files.forEach((file_encryption_telemetry) => { + latestTelemetry[monkey][file_encryption_telemetry.path] = file_encryption_telemetry.success + }); + } + + return latestTelemetry +} + +function getDataForTable(telemetry): Array { + let tableData = []; + + for (const monkey in telemetry) { + for (const path in telemetry[monkey]) { + if (telemetry[monkey][path]) { + tableData.push({'hostname': parseHostname(monkey), 'file_path': path}); + } + } + } + + return tableData; +} + +function parseHostname(monkey) { + return monkey.match(HOSTNAME_REGEX)[2] +} export default FileEncryptionTable;