forked from p15670423/monkey
Merge pull request #1363 from guardicore/ransomware-table-v2
Ransomware table v2
This commit is contained in:
commit
475f46cd5a
|
@ -8,10 +8,8 @@ from monkey_island.cc.services.ransomware import ransomware_report
|
||||||
class RansomwareReport(flask_restful.Resource):
|
class RansomwareReport(flask_restful.Resource):
|
||||||
@jwt_required
|
@jwt_required
|
||||||
def get(self):
|
def get(self):
|
||||||
encrypted_files_table = ransomware_report.get_encrypted_files_table()
|
|
||||||
return jsonify(
|
return jsonify(
|
||||||
{
|
{
|
||||||
"encrypted_files_table": encrypted_files_table,
|
|
||||||
"propagation_stats": ransomware_report.get_propagation_stats(),
|
"propagation_stats": ransomware_report.get_propagation_stats(),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,85 +1,8 @@
|
||||||
from typing import Dict, List
|
from typing import Dict, List
|
||||||
|
|
||||||
from monkey_island.cc.database import mongo
|
|
||||||
from monkey_island.cc.services.reporting.report import ReportService
|
from monkey_island.cc.services.reporting.report import ReportService
|
||||||
|
|
||||||
|
|
||||||
def get_encrypted_files_table():
|
|
||||||
query = [
|
|
||||||
{"$match": {"telem_category": "file_encryption"}},
|
|
||||||
{"$addFields": {"total_attempts": {"$size": "$data.files"}}},
|
|
||||||
{
|
|
||||||
"$addFields": {
|
|
||||||
"successful_encryptions": {
|
|
||||||
"$filter": {
|
|
||||||
"input": "$data.files",
|
|
||||||
"as": "files",
|
|
||||||
"cond": {"$eq": ["$$files.success", True]},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{"$addFields": {"successful_encryptions": {"$size": "$successful_encryptions"}}},
|
|
||||||
{
|
|
||||||
"$group": {
|
|
||||||
"_id": {
|
|
||||||
"monkey_guid": "$monkey_guid",
|
|
||||||
"successful_encryptions": "$successful_encryptions",
|
|
||||||
"total_attempts": "$total_attempts",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{"$replaceRoot": {"newRoot": "$_id"}},
|
|
||||||
{"$sort": {"successful_encryptions": -1}},
|
|
||||||
{
|
|
||||||
"$group": {
|
|
||||||
"_id": {"monkey_guid": "$monkey_guid"},
|
|
||||||
"monkey_guid": {"$first": "$monkey_guid"},
|
|
||||||
"total_attempts": {"$first": "$total_attempts"},
|
|
||||||
"successful_encryptions": {"$first": "$successful_encryptions"},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"$lookup": {
|
|
||||||
"from": "monkey",
|
|
||||||
"localField": "_id.monkey_guid",
|
|
||||||
"foreignField": "guid",
|
|
||||||
"as": "monkey",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"$project": {
|
|
||||||
"monkey": {"$arrayElemAt": ["$monkey", 0]},
|
|
||||||
"total_attempts": "$total_attempts",
|
|
||||||
"successful_encryptions": "$successful_encryptions",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
monkeys = list(mongo.db.telemetry.aggregate(query))
|
|
||||||
exploited_nodes = ReportService.get_exploited()
|
|
||||||
for monkey in monkeys:
|
|
||||||
monkey["exploits"] = _get_monkey_origin_exploits(
|
|
||||||
monkey["monkey"]["hostname"], exploited_nodes
|
|
||||||
)
|
|
||||||
monkey["hostname"] = monkey["monkey"]["hostname"]
|
|
||||||
del monkey["monkey"]
|
|
||||||
del monkey["_id"]
|
|
||||||
return monkeys
|
|
||||||
|
|
||||||
|
|
||||||
def _get_monkey_origin_exploits(monkey_hostname, exploited_nodes):
|
|
||||||
origin_exploits = [
|
|
||||||
exploited_node["exploits"]
|
|
||||||
for exploited_node in exploited_nodes
|
|
||||||
if exploited_node["label"] == monkey_hostname
|
|
||||||
]
|
|
||||||
if origin_exploits:
|
|
||||||
return origin_exploits[0]
|
|
||||||
else:
|
|
||||||
return ["Manual execution"]
|
|
||||||
|
|
||||||
|
|
||||||
def get_propagation_stats() -> Dict:
|
def get_propagation_stats() -> Dict:
|
||||||
scanned = ReportService.get_scanned()
|
scanned = ReportService.get_scanned()
|
||||||
exploited = ReportService.get_exploited()
|
exploited = ReportService.get_exploited()
|
||||||
|
|
|
@ -156,7 +156,11 @@ 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}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||||
|
|
||||||
import ReportHeader, {ReportTypes} from './common/ReportHeader';
|
import ReportHeader, {ReportTypes} from './common/ReportHeader';
|
||||||
import ReportLoader from './common/ReportLoader';
|
import ReportLoader from './common/ReportLoader';
|
||||||
import FileEncryptionTable from './ransomware/FileEncryptionTable';
|
import AttackSection from './ransomware/AttackSection';
|
||||||
import LateralMovement from './ransomware/LateralMovement';
|
import LateralMovement from './ransomware/LateralMovement';
|
||||||
|
|
||||||
import '../../styles/pages/report/RansomwareReport.scss';
|
import '../../styles/pages/report/RansomwareReport.scss';
|
||||||
|
@ -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} />
|
<AttackSection />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
import React, {ReactElement, ReactFragment, useEffect, useState} from 'react';
|
||||||
|
import IslandHttpClient from '../../IslandHttpClient';
|
||||||
|
import {FileEncryptionTable, TableRow} from './FileEncryptionTable';
|
||||||
|
import NumberedReportSection from './NumberedReportSection';
|
||||||
|
import LoadingIcon from '../../ui-components/LoadingIcon';
|
||||||
|
|
||||||
|
const ATTACK_DESCRIPTION = 'After the attacker or malware has propagated through your network, \
|
||||||
|
your data is at risk on any machine the attacker can access. It can be \
|
||||||
|
encrypted and held for ransomware, exfiltrated, or manipulated in \
|
||||||
|
whatever way the attacker chooses.'
|
||||||
|
const HOSTNAME_REGEX = /^(.* - )?(\S+) :.*$/;
|
||||||
|
|
||||||
|
function AttackSection(): ReactElement {
|
||||||
|
const [tableData, setTableData] = useState(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
IslandHttpClient.get('/api/telemetry?telem_category=file_encryption')
|
||||||
|
.then(resp => setTableData(processTelemetry(resp.body)));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
|
if (tableData == null) {
|
||||||
|
return <LoadingIcon />
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NumberedReportSection
|
||||||
|
index={3}
|
||||||
|
title='Attack'
|
||||||
|
description={ATTACK_DESCRIPTION}
|
||||||
|
body={getBody(tableData)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBody(tableData): ReactFragment {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p>Infection Monkey has encrypted <strong>{tableData.length} files</strong> on your network.</p>
|
||||||
|
{(tableData.length > 0) && <FileEncryptionTable tableData={tableData} />}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function processTelemetry(telemetry): Array<TableRow> {
|
||||||
|
// Sort ascending so that newer telemetry records overwrite older ones.
|
||||||
|
sortTelemetry(telemetry);
|
||||||
|
|
||||||
|
let latestTelemetry = getLatestTelemetry(telemetry);
|
||||||
|
let tableData = getDataForTable(latestTelemetry);
|
||||||
|
|
||||||
|
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<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: string): string {
|
||||||
|
return monkey.match(HOSTNAME_REGEX)[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AttackSection;
|
|
@ -1,25 +1,30 @@
|
||||||
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 = {
|
|
||||||
tableData: [TableRow]
|
|
||||||
}
|
|
||||||
|
|
||||||
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 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 = ({tableData}: {tableData: Array<TableRow>}) => {
|
||||||
|
let defaultPageSize = tableData.length > PAGE_SIZE ? PAGE_SIZE : tableData.length;
|
||||||
|
let showPagination = tableData.length > PAGE_SIZE;
|
||||||
|
|
||||||
const FileEncryptionTable = (props: Props) => {
|
|
||||||
let defaultPageSize = props.tableData.length > pageSize ? pageSize : props.tableData.length;
|
|
||||||
let showPagination = props.tableData.length > pageSize;
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<h3 className={'report-section-header'}>
|
<h3 className={'report-section-header'}>
|
||||||
|
@ -28,7 +33,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 +42,4 @@ const FileEncryptionTable = (props: Props) => {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const columns = [
|
export {FileEncryptionTable, TableRow};
|
||||||
{
|
|
||||||
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 renderFileEncryptionStats(successful: number, total: number) {
|
|
||||||
let textClassName = ''
|
|
||||||
|
|
||||||
if(successful > 0) {
|
|
||||||
textClassName = 'text-danger'
|
|
||||||
} else {
|
|
||||||
textClassName = 'text-dark'
|
|
||||||
}
|
|
||||||
|
|
||||||
return (<p className={textClassName}>{successful} out of {total}</p>);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export default FileEncryptionTable;
|
|
||||||
|
|
|
@ -1,125 +0,0 @@
|
||||||
from mongomock import ObjectId
|
|
||||||
|
|
||||||
EDGE_EXPLOITED = {
|
|
||||||
"_id": ObjectId("60e541c07a6cdf66484ba504"),
|
|
||||||
"_cls": "Edge.EdgeService",
|
|
||||||
"src_node_id": ObjectId("60e541aab6732b49f4c564ea"),
|
|
||||||
"dst_node_id": ObjectId("60e541c6b6732b49f4c56622"),
|
|
||||||
"scans": [
|
|
||||||
{
|
|
||||||
"timestamp": "2021-07-07T08:55:12.866Z",
|
|
||||||
"data": {
|
|
||||||
"os": {"type": "windows"},
|
|
||||||
"services": {"tcp-445": {"display_name": "SMB", "port": 445}},
|
|
||||||
"icmp": True,
|
|
||||||
"monkey_exe": None,
|
|
||||||
"default_tunnel": None,
|
|
||||||
"default_server": None,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"exploits": [
|
|
||||||
{
|
|
||||||
"result": True,
|
|
||||||
"exploiter": "SmbExploiter",
|
|
||||||
"info": {
|
|
||||||
"display_name": "SMB",
|
|
||||||
"started": "2021-07-07T08:55:12.944Z",
|
|
||||||
"finished": "2021-07-07T08:55:14.376Z",
|
|
||||||
"vulnerable_urls": [],
|
|
||||||
"vulnerable_ports": ["139 or 445", "139 or 445"],
|
|
||||||
"executed_cmds": [],
|
|
||||||
},
|
|
||||||
"attempts": [
|
|
||||||
{
|
|
||||||
"result": False,
|
|
||||||
"user": "Administrator",
|
|
||||||
"password": "LydBuBjDAe/igLGS2FyeKL1zLoTt0r+CkaPH1v5/Vr7HmzcbBPW562Io+MQlrMey",
|
|
||||||
"lm_hash": "",
|
|
||||||
"ntlm_hash": "",
|
|
||||||
"ssh_key": "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"result": True,
|
|
||||||
"user": "user",
|
|
||||||
"password": "Evzzovf6QLOPUja78/nP6XgiNXH5bB1MrXqPBYmBgeQDOcBhJPUE32+8968zDlHy",
|
|
||||||
"lm_hash": "",
|
|
||||||
"ntlm_hash": "",
|
|
||||||
"ssh_key": "",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"timestamp": "2021-07-07T08:55:14.420Z",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"result": True,
|
|
||||||
"exploiter": "SmbExploiter",
|
|
||||||
"info": {
|
|
||||||
"display_name": "SMB",
|
|
||||||
"started": "2021-07-07T12:08:35.168Z",
|
|
||||||
"finished": "2021-07-07T12:08:36.612Z",
|
|
||||||
"vulnerable_urls": [],
|
|
||||||
"vulnerable_ports": ["139 or 445", "139 or 445"],
|
|
||||||
"executed_cmds": [],
|
|
||||||
},
|
|
||||||
"attempts": [
|
|
||||||
{
|
|
||||||
"result": False,
|
|
||||||
"user": "Administrator",
|
|
||||||
"password": "B4o8ujKpBfKyjCvb7c5bHr7a8CzwfOJi+i228WGv4/9OZZaEsKjps/5Zg1aHSEun",
|
|
||||||
"lm_hash": "",
|
|
||||||
"ntlm_hash": "",
|
|
||||||
"ssh_key": "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"result": True,
|
|
||||||
"user": "user",
|
|
||||||
"password": "Evzzovf6QLOPUja78/nP6XgiNXH5bB1MrXqPBYmBgeQDOcBhJPUE32+8968zDlHy",
|
|
||||||
"lm_hash": "",
|
|
||||||
"ntlm_hash": "",
|
|
||||||
"ssh_key": "",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"timestamp": "2021-07-07T12:08:36.650Z",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"tunnel": False,
|
|
||||||
"exploited": True,
|
|
||||||
"src_label": "MonkeyIsland - test-pc-2 : 192.168.56.1",
|
|
||||||
"dst_label": "WinDev2010Eval : 172.25.33.145",
|
|
||||||
"domain_name": "",
|
|
||||||
"ip_address": "172.25.33.145",
|
|
||||||
}
|
|
||||||
|
|
||||||
EDGE_SCANNED = {
|
|
||||||
"_id": ObjectId("60e6b24dc10b80a409c048a3"),
|
|
||||||
"_cls": "Edge.EdgeService",
|
|
||||||
"src_node_id": ObjectId("60e541aab6732b49f4c564ea"),
|
|
||||||
"dst_node_id": ObjectId("60e6b24dc10b80a409c048a2"),
|
|
||||||
"scans": [
|
|
||||||
{
|
|
||||||
"timestamp": "2021-07-08T11:07:41.407Z",
|
|
||||||
"data": {
|
|
||||||
"os": {"type": "linux", "version": "Ubuntu-4ubuntu0.3"},
|
|
||||||
"services": {
|
|
||||||
"tcp-22": {
|
|
||||||
"display_name": "SSH",
|
|
||||||
"port": 22,
|
|
||||||
"banner": "SSH-2.0-OpenSSH_7.6p1 Ubuntu-4ubuntu0.3\r\n",
|
|
||||||
"name": "ssh",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"icmp": True,
|
|
||||||
"monkey_exe": None,
|
|
||||||
"default_tunnel": None,
|
|
||||||
"default_server": None,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"exploits": [],
|
|
||||||
"tunnel": False,
|
|
||||||
"exploited": False,
|
|
||||||
"src_label": "MonkeyIsland - test-pc-2 : 192.168.56.1",
|
|
||||||
"dst_label": "Ubuntu-4ubuntu0.3 : 172.24.125.179",
|
|
||||||
"domain_name": "",
|
|
||||||
"ip_address": "172.24.125.179",
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
from mongomock import ObjectId
|
|
||||||
|
|
||||||
MONKEY_AT_ISLAND = {
|
|
||||||
"_id": ObjectId("60e541aab6732b49f4c564ea"),
|
|
||||||
"guid": "211375648895908",
|
|
||||||
"config": {},
|
|
||||||
"creds": [],
|
|
||||||
"dead": True,
|
|
||||||
"description": "Windows test-pc-2 10",
|
|
||||||
"hostname": "test-pc-2",
|
|
||||||
"internet_access": True,
|
|
||||||
"ip_addresses": [
|
|
||||||
"192.168.56.1",
|
|
||||||
"172.17.192.1",
|
|
||||||
"172.25.32.1",
|
|
||||||
"192.168.43.1",
|
|
||||||
"192.168.10.1",
|
|
||||||
"192.168.0.102",
|
|
||||||
],
|
|
||||||
"keepalive": "2021-07-07T12:08:13.164Z",
|
|
||||||
"modifytime": "2021-07-07T12:10:13.340Z",
|
|
||||||
"parent": [
|
|
||||||
["211375648895908", None],
|
|
||||||
["211375648895908", None],
|
|
||||||
["211375648895908", None],
|
|
||||||
["211375648895908", None],
|
|
||||||
],
|
|
||||||
"ttl_ref": ObjectId("60e56f757a6cdf66484ba5cc"),
|
|
||||||
"command_control_channel": {"src": "192.168.56.1", "dst": "192.168.56.1:5000"},
|
|
||||||
"pba_results": [],
|
|
||||||
}
|
|
||||||
|
|
||||||
MONKEY_AT_VICTIM = {
|
|
||||||
"_id": ObjectId("60e541c6b6732b49f4c56622"),
|
|
||||||
"guid": "91758264576",
|
|
||||||
"config": {},
|
|
||||||
"creds": [],
|
|
||||||
"dead": False,
|
|
||||||
"description": "Windows WinDev2010Eval 10 10.0.19041 AMD64 Intel64 Family 6 Model 165 "
|
|
||||||
"Stepping 2, GenuineIntel",
|
|
||||||
"hostname": "WinDev2010Eval",
|
|
||||||
"internet_access": True,
|
|
||||||
"ip_addresses": ["172.25.33.145"],
|
|
||||||
"keepalive": "2021-07-07T12:08:41.200Z",
|
|
||||||
"modifytime": "2021-07-07T12:08:47.144Z",
|
|
||||||
"parent": [["211375648895908", "SmbExploiter"], ["211375648895908", None]],
|
|
||||||
"ttl_ref": ObjectId("60e56f1f7a6cdf66484ba5c5"),
|
|
||||||
"command_control_channel": {"src": "172.25.33.145", "dst": "172.25.32.1:5000"},
|
|
||||||
"pba_results": [],
|
|
||||||
}
|
|
|
@ -1,59 +0,0 @@
|
||||||
from mongomock import ObjectId
|
|
||||||
|
|
||||||
ENCRYPTED = {
|
|
||||||
"_id": ObjectId("60e541c37a6cdf66484ba517"),
|
|
||||||
"monkey_guid": "211375648895908",
|
|
||||||
"telem_category": "file_encryption",
|
|
||||||
"data": {
|
|
||||||
"files": [
|
|
||||||
{"path": "infection_monkey.py", "success": True, "error": ""},
|
|
||||||
{"path": "monkey_island.py", "success": True, "error": ""},
|
|
||||||
{"path": "__init__.py", "success": True, "error": ""},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"timestamp": "2021-07-07T08:55:15.830Z",
|
|
||||||
"command_control_channel": {"src": "192.168.56.1", "dst": "192.168.56.1:5000"},
|
|
||||||
}
|
|
||||||
|
|
||||||
ENCRYPTED_2 = {
|
|
||||||
"_id": ObjectId("60e54fee7a6cdf66484ba559"),
|
|
||||||
"monkey_guid": "211375648895908",
|
|
||||||
"telem_category": "file_encryption",
|
|
||||||
"data": {
|
|
||||||
"files": [
|
|
||||||
{"path": "infection_monkey.py", "success": True, "error": ""},
|
|
||||||
{"path": "monkey_island.py", "success": True, "error": ""},
|
|
||||||
{"path": "__init__.py", "success": True, "error": ""},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"timestamp": "2021-07-07T09:55:42.311Z",
|
|
||||||
"command_control_channel": {"src": "192.168.56.1", "dst": "192.168.56.1:5000"},
|
|
||||||
}
|
|
||||||
|
|
||||||
ENCRYPTION_ERROR = {
|
|
||||||
"_id": ObjectId("60e56f167a6cdf66484ba5aa"),
|
|
||||||
"monkey_guid": "211375648895908",
|
|
||||||
"telem_category": "file_encryption",
|
|
||||||
"data": {
|
|
||||||
"files": [
|
|
||||||
{
|
|
||||||
"path": "C:\\w\\Dump\\README.txt",
|
|
||||||
"success": False,
|
|
||||||
"error": "[WinError 183] Cannot create a file when that "
|
|
||||||
"file already exists: 'C:\\\\w\\\\Dump\\\\README.txt'"
|
|
||||||
" -> 'C:\\\\w\\\\Dump\\\\README.txt.m0nk3y'",
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"timestamp": "2021-07-07T12:08:38.058Z",
|
|
||||||
"command_control_channel": {"src": "192.168.56.1", "dst": "192.168.56.1:5000"},
|
|
||||||
}
|
|
||||||
|
|
||||||
ENCRYPTION_ONE_FILE = {
|
|
||||||
"_id": ObjectId("60e56f1b7a6cdf66484ba5c0"),
|
|
||||||
"monkey_guid": "91758264576",
|
|
||||||
"telem_category": "file_encryption",
|
|
||||||
"data": {"files": [{"path": "C:\\w\\Dump\\README.txt", "success": True, "error": ""}]},
|
|
||||||
"timestamp": "2021-07-07T12:08:43.421Z",
|
|
||||||
"command_control_channel": {"src": "172.25.33.145", "dst": "172.25.32.1:5000"},
|
|
||||||
}
|
|
|
@ -1,105 +1,9 @@
|
||||||
import mongomock
|
|
||||||
import pytest
|
import pytest
|
||||||
from tests.data_for_tests.mongo_documents.edges import EDGE_EXPLOITED, EDGE_SCANNED
|
|
||||||
from tests.data_for_tests.mongo_documents.monkeys import MONKEY_AT_ISLAND, MONKEY_AT_VICTIM
|
|
||||||
from tests.data_for_tests.mongo_documents.telemetries.file_encryption import (
|
|
||||||
ENCRYPTED,
|
|
||||||
ENCRYPTED_2,
|
|
||||||
ENCRYPTION_ERROR,
|
|
||||||
ENCRYPTION_ONE_FILE,
|
|
||||||
)
|
|
||||||
|
|
||||||
from monkey_island.cc.services.ransomware import ransomware_report
|
from monkey_island.cc.services.ransomware import ransomware_report
|
||||||
from monkey_island.cc.services.ransomware.ransomware_report import get_encrypted_files_table
|
|
||||||
from monkey_island.cc.services.reporting.report import ReportService
|
from monkey_island.cc.services.reporting.report import ReportService
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def fake_mongo(monkeypatch):
|
|
||||||
mongo = mongomock.MongoClient()
|
|
||||||
monkeypatch.setattr("monkey_island.cc.services.ransomware.ransomware_report.mongo", mongo)
|
|
||||||
return mongo
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures("uses_database")
|
|
||||||
def test_get_encrypted_files_table(fake_mongo, monkeypatch):
|
|
||||||
fake_mongo.db.monkey.insert_one(MONKEY_AT_ISLAND)
|
|
||||||
fake_mongo.db.monkey.insert_one(MONKEY_AT_VICTIM)
|
|
||||||
fake_mongo.db.edge.insert_one(EDGE_EXPLOITED)
|
|
||||||
fake_mongo.db.edge.insert_one(EDGE_SCANNED)
|
|
||||||
fake_mongo.db.telemetry.insert_one(ENCRYPTED)
|
|
||||||
fake_mongo.db.telemetry.insert_one(ENCRYPTED_2)
|
|
||||||
fake_mongo.db.telemetry.insert_one(ENCRYPTION_ERROR)
|
|
||||||
fake_mongo.db.telemetry.insert_one(ENCRYPTION_ONE_FILE)
|
|
||||||
|
|
||||||
monkeypatch.setattr(
|
|
||||||
ReportService,
|
|
||||||
"get_exploited",
|
|
||||||
lambda: [{"label": "WinDev2010Eval", "exploits": ["SMB Exploiter"]}],
|
|
||||||
)
|
|
||||||
|
|
||||||
results = get_encrypted_files_table()
|
|
||||||
|
|
||||||
assert results == [
|
|
||||||
{
|
|
||||||
"hostname": "test-pc-2",
|
|
||||||
"exploits": ["Manual execution"],
|
|
||||||
"successful_encryptions": 3,
|
|
||||||
"total_attempts": 3,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hostname": "WinDev2010Eval",
|
|
||||||
"exploits": ["SMB Exploiter"],
|
|
||||||
"successful_encryptions": 1,
|
|
||||||
"total_attempts": 1,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures("uses_database")
|
|
||||||
def test_get_encrypted_files_table__only_errors(fake_mongo, monkeypatch):
|
|
||||||
fake_mongo.db.monkey.insert_one(MONKEY_AT_ISLAND)
|
|
||||||
fake_mongo.db.monkey.insert_one(MONKEY_AT_VICTIM)
|
|
||||||
fake_mongo.db.edge.insert_one(EDGE_EXPLOITED)
|
|
||||||
fake_mongo.db.edge.insert_one(EDGE_SCANNED)
|
|
||||||
fake_mongo.db.telemetry.insert_one(ENCRYPTION_ERROR)
|
|
||||||
|
|
||||||
monkeypatch.setattr(
|
|
||||||
ReportService,
|
|
||||||
"get_exploited",
|
|
||||||
lambda: [{"label": "WinDev2010Eval", "exploits": ["SMB Exploiter"]}],
|
|
||||||
)
|
|
||||||
|
|
||||||
results = get_encrypted_files_table()
|
|
||||||
|
|
||||||
assert results == [
|
|
||||||
{
|
|
||||||
"hostname": "test-pc-2",
|
|
||||||
"exploits": ["Manual execution"],
|
|
||||||
"successful_encryptions": 0,
|
|
||||||
"total_attempts": 1,
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures("uses_database")
|
|
||||||
def test_get_encrypted_files_table__no_telemetries(fake_mongo, monkeypatch):
|
|
||||||
fake_mongo.db.monkey.insert_one(MONKEY_AT_ISLAND)
|
|
||||||
fake_mongo.db.monkey.insert_one(MONKEY_AT_VICTIM)
|
|
||||||
fake_mongo.db.edge.insert_one(EDGE_EXPLOITED)
|
|
||||||
fake_mongo.db.edge.insert_one(EDGE_SCANNED)
|
|
||||||
|
|
||||||
monkeypatch.setattr(
|
|
||||||
ReportService,
|
|
||||||
"get_exploited",
|
|
||||||
lambda: [{"label": "WinDev2010Eval", "exploits": ["SMB Exploiter"]}],
|
|
||||||
)
|
|
||||||
|
|
||||||
results = get_encrypted_files_table()
|
|
||||||
|
|
||||||
assert results == []
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def patch_report_service_for_stats(monkeypatch):
|
def patch_report_service_for_stats(monkeypatch):
|
||||||
TEST_SCANNED_RESULTS = [{}, {}, {}, {}]
|
TEST_SCANNED_RESULTS = [{}, {}, {}, {}]
|
||||||
|
|
Loading…
Reference in New Issue