UI: Display encrypted file paths in ransomware report table

This commit is contained in:
Mike Salvatore 2021-07-23 11:13:54 -04:00
parent d4d055ed95
commit da3a2c1a02
3 changed files with 89 additions and 34 deletions

View File

@ -22,6 +22,7 @@ class ReportPageComponent extends AuthComponent {
attackReport: {}, attackReport: {},
zeroTrustReport: {}, zeroTrustReport: {},
ransomwareReport: {}, ransomwareReport: {},
ransomwareTelemetry: {},
allMonkeysAreDead: false, allMonkeysAreDead: false,
runStarted: true, runStarted: true,
selectedSection: ReportPageComponent.selectReport(this.sections), selectedSection: ReportPageComponent.selectReport(this.sections),
@ -67,6 +68,13 @@ class ReportPageComponent extends AuthComponent {
ransomwareReport: res 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': case 'zeroTrust':
return (<ZeroTrustReport report={this.state.zeroTrustReport}/>); return (<ZeroTrustReport report={this.state.zeroTrustReport}/>);
case 'ransomware': case 'ransomware':
return (<RansomwareReport report={this.state.ransomwareReport}/>); return (
<RansomwareReport
report={this.state.ransomwareReport}
telemetry={this.state.ransomwareTelemetry}
/>
);
} }
} }

View File

@ -19,7 +19,7 @@ class RansomwareReport extends React.Component {
<div> <div>
<BreachSection/> <BreachSection/>
<LateralMovement propagationStats={this.props.report.propagation_stats} /> <LateralMovement propagationStats={this.props.report.propagation_stats} />
<FileEncryptionTable tableData={this.props.report.encrypted_files_table} /> <FileEncryptionTable telemetry={this.props.telemetry} />
</div> </div>
) )
} }

View File

@ -1,25 +1,36 @@
import React from 'react'; import React from 'react';
import ReactTable from 'react-table'; import ReactTable from 'react-table';
import {renderArray} from '../common/RenderArrays';
type Props = { type Props = {
tableData: [TableRow] telemetry: object,
} }
type TableRow = { type TableRow = {
exploits: [string], hostname: string,
total_attempts: number, file_path: number,
successful_encryptions: number,
hostname: string
} }
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) => { const FileEncryptionTable = (props: Props) => {
let defaultPageSize = props.tableData.length > pageSize ? pageSize : props.tableData.length; let tableData = processTelemetry(props.telemetry);
let showPagination = props.tableData.length > pageSize; let defaultPageSize = tableData.length > PAGE_SIZE ? PAGE_SIZE : tableData.length;
let showPagination = tableData.length > PAGE_SIZE;
return ( return (
<> <>
<h3 className={'report-section-header'}> <h3 className={'report-section-header'}>
@ -28,7 +39,7 @@ const FileEncryptionTable = (props: Props) => {
<div className="data-table-container"> <div className="data-table-container">
<ReactTable <ReactTable
columns={columns} columns={columns}
data={props.tableData} data={tableData}
showPagination={showPagination} showPagination={showPagination}
defaultPageSize={defaultPageSize} defaultPageSize={defaultPageSize}
/> />
@ -37,30 +48,61 @@ const FileEncryptionTable = (props: Props) => {
); );
} }
const columns = [ function processTelemetry(telemetry): Array<TableRow> {
{ // Sort ascending so that newer telemetry records overwrite older ones.
Header: 'Ransomware info', sortTelemetry(telemetry);
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 renderFileEncryptionStats(successful: number, total: number) { let latestTelemetry = getLatestTelemetry(telemetry);
let textClassName = '' let tableData = getDataForTable(latestTelemetry);
if(successful > 0) { return tableData;
textClassName = 'text-danger'
} else {
textClassName = 'text-dark'
} }
return (<p className={textClassName}>{successful} out of {total}</p>); 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<TableRow> {
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; export default FileEncryptionTable;