forked from p15670423/monkey
Merge pull request #1375 from guardicore/ransomware_exploits_table
Ransomware report: Exploits table in lateral movement section
This commit is contained in:
commit
fceb52ba38
|
@ -25,6 +25,7 @@ from monkey_island.cc.resources.configuration_import import ConfigurationImport
|
||||||
from monkey_island.cc.resources.edge import Edge
|
from monkey_island.cc.resources.edge import Edge
|
||||||
from monkey_island.cc.resources.environment import Environment
|
from monkey_island.cc.resources.environment import Environment
|
||||||
from monkey_island.cc.resources.exploitations.manual_exploitation import ManualExploitation
|
from monkey_island.cc.resources.exploitations.manual_exploitation import ManualExploitation
|
||||||
|
from monkey_island.cc.resources.exploitations.monkey_exploitation import MonkeyExploitation
|
||||||
from monkey_island.cc.resources.island_configuration import IslandConfiguration
|
from monkey_island.cc.resources.island_configuration import IslandConfiguration
|
||||||
from monkey_island.cc.resources.island_logs import IslandLog
|
from monkey_island.cc.resources.island_logs import IslandLog
|
||||||
from monkey_island.cc.resources.island_mode import IslandMode
|
from monkey_island.cc.resources.island_mode import IslandMode
|
||||||
|
@ -154,6 +155,7 @@ def init_api_resources(api):
|
||||||
api.add_resource(AttackReport, "/api/report/attack")
|
api.add_resource(AttackReport, "/api/report/attack")
|
||||||
api.add_resource(RansomwareReport, "/api/report/ransomware")
|
api.add_resource(RansomwareReport, "/api/report/ransomware")
|
||||||
api.add_resource(ManualExploitation, "/api/exploitations/manual")
|
api.add_resource(ManualExploitation, "/api/exploitations/manual")
|
||||||
|
api.add_resource(MonkeyExploitation, "/api/exploitations/monkey")
|
||||||
|
|
||||||
api.add_resource(ZeroTrustFindingEvent, "/api/zero-trust/finding-event/<string:finding_id>")
|
api.add_resource(ZeroTrustFindingEvent, "/api/zero-trust/finding-event/<string:finding_id>")
|
||||||
api.add_resource(TelemetryFeed, "/api/telemetry-feed", "/api/telemetry-feed/")
|
api.add_resource(TelemetryFeed, "/api/telemetry-feed", "/api/telemetry-feed/")
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
import flask_restful
|
import flask_restful
|
||||||
|
|
||||||
from monkey_island.cc.resources.auth.auth import jwt_required
|
from monkey_island.cc.resources.auth.auth import jwt_required
|
||||||
from monkey_island.cc.services.exploitations.manual_exploitation import get_manual_exploitations
|
from monkey_island.cc.services.reporting.exploitations.manual_exploitation import (
|
||||||
|
get_manual_exploitations,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ManualExploitation(flask_restful.Resource):
|
class ManualExploitation(flask_restful.Resource):
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
import flask_restful
|
||||||
|
|
||||||
|
from monkey_island.cc.resources.auth.auth import jwt_required
|
||||||
|
from monkey_island.cc.services.reporting.exploitations.monkey_exploitation import (
|
||||||
|
get_monkey_exploited,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class MonkeyExploitation(flask_restful.Resource):
|
||||||
|
@jwt_required
|
||||||
|
def get(self):
|
||||||
|
monkey_exploitations = [exploitation.__dict__ for exploitation in get_monkey_exploited()]
|
||||||
|
return {"monkey_exploitations": monkey_exploitations}
|
|
@ -1,11 +1,15 @@
|
||||||
from typing import Dict, List
|
from typing import Dict, List
|
||||||
|
|
||||||
|
from monkey_island.cc.services.reporting.exploitations.monkey_exploitation import (
|
||||||
|
MonkeyExploitation,
|
||||||
|
get_monkey_exploited,
|
||||||
|
)
|
||||||
from monkey_island.cc.services.reporting.report import ReportService
|
from monkey_island.cc.services.reporting.report import ReportService
|
||||||
|
|
||||||
|
|
||||||
def get_propagation_stats() -> Dict:
|
def get_propagation_stats() -> Dict:
|
||||||
scanned = ReportService.get_scanned()
|
scanned = ReportService.get_scanned()
|
||||||
exploited = ReportService.get_exploited()
|
exploited = get_monkey_exploited()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"num_scanned_nodes": len(scanned),
|
"num_scanned_nodes": len(scanned),
|
||||||
|
@ -14,11 +18,11 @@ def get_propagation_stats() -> Dict:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _get_exploit_counts(exploited: List[Dict]) -> Dict:
|
def _get_exploit_counts(exploited: List[MonkeyExploitation]) -> Dict:
|
||||||
exploit_counts = {}
|
exploit_counts = {}
|
||||||
|
|
||||||
for node in exploited:
|
for node in exploited:
|
||||||
for exploit in node["exploits"]:
|
for exploit in node.exploits:
|
||||||
exploit_counts[exploit] = exploit_counts.get(exploit, 0) + 1
|
exploit_counts[exploit] = exploit_counts.get(exploit, 0) + 1
|
||||||
|
|
||||||
return exploit_counts
|
return exploit_counts
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
import logging
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
from monkey_island.cc.database import mongo
|
||||||
|
from monkey_island.cc.services.node import NodeService
|
||||||
|
from monkey_island.cc.services.reporting.issue_processing.exploit_processing.exploiter_descriptor_enum import ( # noqa: E501
|
||||||
|
ExploiterDescriptorEnum,
|
||||||
|
)
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class MonkeyExploitation:
|
||||||
|
label: str
|
||||||
|
ip_addresses: List[str]
|
||||||
|
domain_name: str
|
||||||
|
exploits: List[str]
|
||||||
|
|
||||||
|
|
||||||
|
def get_monkey_exploited() -> List[MonkeyExploitation]:
|
||||||
|
exploited_nodes_monkeys_launched = [
|
||||||
|
NodeService.get_displayed_node_by_id(monkey["_id"], True)
|
||||||
|
for monkey in mongo.db.monkey.find({}, {"_id": 1})
|
||||||
|
if not NodeService.get_monkey_manual_run(NodeService.get_monkey_by_id(monkey["_id"]))
|
||||||
|
]
|
||||||
|
|
||||||
|
# The node got exploited, but no monkeys got launched.
|
||||||
|
# For example the exploited machine was too old.
|
||||||
|
exploited_nodes_monkeys_failed = [
|
||||||
|
NodeService.get_displayed_node_by_id(node["_id"], True)
|
||||||
|
for node in mongo.db.node.find({"exploited": True}, {"_id": 1})
|
||||||
|
]
|
||||||
|
|
||||||
|
exploited = exploited_nodes_monkeys_launched + exploited_nodes_monkeys_failed
|
||||||
|
|
||||||
|
exploited = [
|
||||||
|
MonkeyExploitation(
|
||||||
|
label=exploited_node["label"],
|
||||||
|
ip_addresses=exploited_node["ip_addresses"],
|
||||||
|
domain_name=exploited_node["domain_name"],
|
||||||
|
exploits=get_exploits_used_on_node(exploited_node),
|
||||||
|
)
|
||||||
|
for exploited_node in exploited
|
||||||
|
]
|
||||||
|
|
||||||
|
logger.info("Exploited nodes generated for reporting")
|
||||||
|
|
||||||
|
return exploited
|
||||||
|
|
||||||
|
|
||||||
|
def get_exploits_used_on_node(node: dict) -> List[str]:
|
||||||
|
return list(
|
||||||
|
set(
|
||||||
|
[
|
||||||
|
ExploiterDescriptorEnum.get_by_class_name(exploit["exploiter"]).display_name
|
||||||
|
for exploit in node["exploits"]
|
||||||
|
if exploit["result"]
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
|
@ -21,8 +21,11 @@ from monkey_island.cc.services.config import ConfigService
|
||||||
from monkey_island.cc.services.configuration.utils import (
|
from monkey_island.cc.services.configuration.utils import (
|
||||||
get_config_network_segments_as_subnet_groups,
|
get_config_network_segments_as_subnet_groups,
|
||||||
)
|
)
|
||||||
from monkey_island.cc.services.exploitations.manual_exploitation import get_manual_monkeys
|
|
||||||
from monkey_island.cc.services.node import NodeService
|
from monkey_island.cc.services.node import NodeService
|
||||||
|
from monkey_island.cc.services.reporting.exploitations.manual_exploitation import get_manual_monkeys
|
||||||
|
from monkey_island.cc.services.reporting.exploitations.monkey_exploitation import (
|
||||||
|
get_monkey_exploited,
|
||||||
|
)
|
||||||
from monkey_island.cc.services.reporting.issue_processing.exploit_processing.exploiter_descriptor_enum import ( # noqa: E501
|
from monkey_island.cc.services.reporting.issue_processing.exploit_processing.exploiter_descriptor_enum import ( # noqa: E501
|
||||||
ExploiterDescriptorEnum,
|
ExploiterDescriptorEnum,
|
||||||
)
|
)
|
||||||
|
@ -148,47 +151,6 @@ class ReportService:
|
||||||
nodes = nodes_without_monkeys + nodes_with_monkeys
|
nodes = nodes_without_monkeys + nodes_with_monkeys
|
||||||
return nodes
|
return nodes
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_exploited():
|
|
||||||
exploited_with_monkeys = [
|
|
||||||
NodeService.get_displayed_node_by_id(monkey["_id"], True)
|
|
||||||
for monkey in mongo.db.monkey.find({}, {"_id": 1})
|
|
||||||
if not NodeService.get_monkey_manual_run(NodeService.get_monkey_by_id(monkey["_id"]))
|
|
||||||
]
|
|
||||||
|
|
||||||
exploited_without_monkeys = [
|
|
||||||
NodeService.get_displayed_node_by_id(node["_id"], True)
|
|
||||||
for node in mongo.db.node.find({"exploited": True}, {"_id": 1})
|
|
||||||
]
|
|
||||||
|
|
||||||
exploited = exploited_with_monkeys + exploited_without_monkeys
|
|
||||||
|
|
||||||
exploited = [
|
|
||||||
{
|
|
||||||
"label": exploited_node["label"],
|
|
||||||
"ip_addresses": exploited_node["ip_addresses"],
|
|
||||||
"domain_name": exploited_node["domain_name"],
|
|
||||||
"exploits": ReportService.get_exploits_used_on_node(exploited_node),
|
|
||||||
}
|
|
||||||
for exploited_node in exploited
|
|
||||||
]
|
|
||||||
|
|
||||||
logger.info("Exploited nodes generated for reporting")
|
|
||||||
|
|
||||||
return exploited
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_exploits_used_on_node(node: dict) -> List[str]:
|
|
||||||
return list(
|
|
||||||
set(
|
|
||||||
[
|
|
||||||
ExploiterDescriptorEnum.get_by_class_name(exploit["exploiter"]).display_name
|
|
||||||
for exploit in node["exploits"]
|
|
||||||
if exploit["result"]
|
|
||||||
]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_stolen_creds():
|
def get_stolen_creds():
|
||||||
creds = []
|
creds = []
|
||||||
|
@ -646,7 +608,7 @@ class ReportService:
|
||||||
monkey_latest_modify_time = Monkey.get_latest_modifytime()
|
monkey_latest_modify_time = Monkey.get_latest_modifytime()
|
||||||
|
|
||||||
scanned_nodes = ReportService.get_scanned()
|
scanned_nodes = ReportService.get_scanned()
|
||||||
exploited_nodes = ReportService.get_exploited()
|
exploited_cnt = len(get_monkey_exploited())
|
||||||
report = {
|
report = {
|
||||||
"overview": {
|
"overview": {
|
||||||
"manual_monkeys": ReportService.get_manual_monkey_hostnames(),
|
"manual_monkeys": ReportService.get_manual_monkey_hostnames(),
|
||||||
|
@ -664,7 +626,7 @@ class ReportService:
|
||||||
},
|
},
|
||||||
"glance": {
|
"glance": {
|
||||||
"scanned": scanned_nodes,
|
"scanned": scanned_nodes,
|
||||||
"exploited": exploited_nodes,
|
"exploited_cnt": exploited_cnt,
|
||||||
"stolen_creds": ReportService.get_stolen_creds(),
|
"stolen_creds": ReportService.get_stolen_creds(),
|
||||||
"azure_passwords": ReportService.get_azure_creds(),
|
"azure_passwords": ReportService.get_azure_creds(),
|
||||||
"ssh_keys": ReportService.get_ssh_keys(),
|
"ssh_keys": ReportService.get_ssh_keys(),
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import React, {Fragment} from 'react';
|
import React, {Fragment} from 'react';
|
||||||
|
import Pluralize from 'pluralize';
|
||||||
import BreachedServers from 'components/report-components/security/BreachedServers';
|
import BreachedServers from 'components/report-components/security/BreachedServers';
|
||||||
import ScannedServers from 'components/report-components/security/ScannedServers';
|
import ScannedServers from 'components/report-components/security/ScannedServers';
|
||||||
import PostBreach from 'components/report-components/security/PostBreach';
|
import PostBreach from 'components/report-components/security/PostBreach';
|
||||||
|
@ -288,9 +289,9 @@ class ReportPageComponent extends AuthComponent {
|
||||||
<h2>
|
<h2>
|
||||||
Overview
|
Overview
|
||||||
</h2>
|
</h2>
|
||||||
<SecurityIssuesGlance issuesFound={this.state.report.glance.exploited.length > 0}/>
|
<SecurityIssuesGlance issuesFound={this.state.report.glance.exploited_cnt > 0}/>
|
||||||
{
|
{
|
||||||
this.state.report.glance.exploited.length > 0 ?
|
this.state.report.glance.exploited_cnt > 0 ?
|
||||||
''
|
''
|
||||||
:
|
:
|
||||||
<p className='alert alert-info'>
|
<p className='alert alert-info'>
|
||||||
|
@ -524,7 +525,7 @@ class ReportPageComponent extends AuthComponent {
|
||||||
|
|
||||||
generateReportGlanceSection() {
|
generateReportGlanceSection() {
|
||||||
let exploitPercentage =
|
let exploitPercentage =
|
||||||
(100 * this.state.report.glance.exploited.length) / this.state.report.glance.scanned.length;
|
(100 * this.state.report.glance.exploited_cnt) / this.state.report.glance.scanned.length;
|
||||||
return (
|
return (
|
||||||
<div id='glance'>
|
<div id='glance'>
|
||||||
<h3>
|
<h3>
|
||||||
|
@ -535,7 +536,7 @@ class ReportPageComponent extends AuthComponent {
|
||||||
The Monkey discovered <span
|
The Monkey discovered <span
|
||||||
className='badge badge-warning'>{this.state.report.glance.scanned.length}</span> machines and
|
className='badge badge-warning'>{this.state.report.glance.scanned.length}</span> machines and
|
||||||
successfully breached <span
|
successfully breached <span
|
||||||
className='badge badge-danger'>{this.state.report.glance.exploited.length}</span> of them.
|
className='badge badge-danger'>{this.state.report.glance.exploited_cnt}</span> of them.
|
||||||
</p>
|
</p>
|
||||||
<div className='text-center' style={{margin: '10px'}}>
|
<div className='text-center' style={{margin: '10px'}}>
|
||||||
<Line style={{width: '300px', marginRight: '5px'}} percent={exploitPercentage} strokeWidth='4'
|
<Line style={{width: '300px', marginRight: '5px'}} percent={exploitPercentage} strokeWidth='4'
|
||||||
|
@ -566,7 +567,13 @@ class ReportPageComponent extends AuthComponent {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{marginBottom: '20px'}}>
|
<div style={{marginBottom: '20px'}}>
|
||||||
<BreachedServers data={this.state.report.glance.exploited}/>
|
<p>
|
||||||
|
The Monkey successfully breached
|
||||||
|
<span className="badge badge-danger">
|
||||||
|
{this.state.report.glance.exploited_cnt}
|
||||||
|
</span> {Pluralize('machine', this.state.report.glance.exploited_cnt)}:
|
||||||
|
</p>
|
||||||
|
<BreachedServers />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{marginBottom: '20px'}}>
|
<div style={{marginBottom: '20px'}}>
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import React, {ReactElement} from 'react';
|
import React, {ReactElement} from 'react';
|
||||||
import NumberedReportSection from './NumberedReportSection';
|
import NumberedReportSection from './NumberedReportSection';
|
||||||
import pluralize from 'pluralize'
|
import pluralize from 'pluralize'
|
||||||
|
import BreachedServersComponent from '../security/BreachedServers';
|
||||||
|
|
||||||
const LATERAL_MOVEMENT_DESCRIPTION = 'After the initial breach, the attacker will begin the Lateral \
|
const LATERAL_MOVEMENT_DESCRIPTION = 'After the initial breach, the attacker will begin the Lateral \
|
||||||
Movement phase of the attack. They will employ various \
|
Movement phase of the attack. They will employ various \
|
||||||
techniques in order to compromise other systems in your \
|
techniques in order to compromise other systems in your \
|
||||||
network and encrypt as many files as possible.'
|
network.'
|
||||||
|
|
||||||
type PropagationStats = {
|
type PropagationStats = {
|
||||||
num_scanned_nodes: number,
|
num_scanned_nodes: number,
|
||||||
|
@ -18,6 +19,8 @@ function LateralMovement({propagationStats}: {propagationStats: PropagationStats
|
||||||
<>
|
<>
|
||||||
{getScannedVsExploitedStats(propagationStats.num_scanned_nodes, propagationStats.num_exploited_nodes)}
|
{getScannedVsExploitedStats(propagationStats.num_scanned_nodes, propagationStats.num_exploited_nodes)}
|
||||||
{getExploitationStatsPerExploit(propagationStats.num_exploited_per_exploit)}
|
{getExploitationStatsPerExploit(propagationStats.num_exploited_per_exploit)}
|
||||||
|
<br/>
|
||||||
|
<BreachedServersComponent />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import ReactTable from 'react-table';
|
|
||||||
import Pluralize from 'pluralize';
|
|
||||||
import {renderArray, renderIpAddresses} from '../common/RenderArrays';
|
|
||||||
|
|
||||||
|
|
||||||
const columns = [
|
|
||||||
{
|
|
||||||
Header: 'Breached Servers',
|
|
||||||
columns: [
|
|
||||||
{Header: 'Machine', accessor: 'label'},
|
|
||||||
{
|
|
||||||
Header: 'IP Addresses', id: 'ip_addresses',
|
|
||||||
accessor: x => renderIpAddresses(x)
|
|
||||||
},
|
|
||||||
{Header: 'Exploits', id: 'exploits', accessor: x => renderArray(x.exploits)}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const pageSize = 10;
|
|
||||||
|
|
||||||
class BreachedServersComponent extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
let defaultPageSize = this.props.data.length > pageSize ? pageSize : this.props.data.length;
|
|
||||||
let showPagination = this.props.data.length > pageSize;
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<p>
|
|
||||||
The Monkey successfully breached <span
|
|
||||||
className="badge badge-danger">{this.props.data.length}</span> {Pluralize('machine', this.props.data.length)}:
|
|
||||||
</p>
|
|
||||||
<div className="data-table-container">
|
|
||||||
<ReactTable
|
|
||||||
columns={columns}
|
|
||||||
data={this.props.data}
|
|
||||||
showPagination={showPagination}
|
|
||||||
defaultPageSize={defaultPageSize}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default BreachedServersComponent;
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
import React, {useEffect, useState} from 'react';
|
||||||
|
import ReactTable from 'react-table';
|
||||||
|
import {renderArray, renderIpAddresses} from '../common/RenderArrays';
|
||||||
|
import LoadingIcon from '../../ui-components/LoadingIcon';
|
||||||
|
import IslandHttpClient from '../../IslandHttpClient';
|
||||||
|
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
Header: 'Breached Servers',
|
||||||
|
columns: [
|
||||||
|
{Header: 'Machine', accessor: 'label'},
|
||||||
|
{
|
||||||
|
Header: 'IP Addresses', id: 'ip_addresses',
|
||||||
|
accessor: x => renderIpAddresses(x)
|
||||||
|
},
|
||||||
|
{Header: 'Exploits', id: 'exploits', accessor: x => renderArray(x.exploits)}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const pageSize = 10;
|
||||||
|
|
||||||
|
function BreachedServersComponent() {
|
||||||
|
|
||||||
|
const [exploitations, setExploitations] = useState(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
IslandHttpClient.get('/api/exploitations/monkey')
|
||||||
|
.then(res => setExploitations(res.body['monkey_exploitations']))
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if(exploitations === null){
|
||||||
|
return <LoadingIcon />
|
||||||
|
}
|
||||||
|
|
||||||
|
let defaultPageSize = exploitations.length > pageSize ? pageSize : exploitations.length;
|
||||||
|
let showPagination = exploitations.length > pageSize;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="data-table-container">
|
||||||
|
<ReactTable
|
||||||
|
columns={columns}
|
||||||
|
data={exploitations}
|
||||||
|
showPagination={showPagination}
|
||||||
|
defaultPageSize={defaultPageSize}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default BreachedServersComponent;
|
|
@ -1,6 +1,7 @@
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from monkey_island.cc.services.ransomware import ransomware_report
|
from monkey_island.cc.services.ransomware import ransomware_report
|
||||||
|
from monkey_island.cc.services.reporting.exploitations.monkey_exploitation import MonkeyExploitation
|
||||||
from monkey_island.cc.services.reporting.report import ReportService
|
from monkey_island.cc.services.reporting.report import ReportService
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,13 +9,13 @@ from monkey_island.cc.services.reporting.report import ReportService
|
||||||
def patch_report_service_for_stats(monkeypatch):
|
def patch_report_service_for_stats(monkeypatch):
|
||||||
TEST_SCANNED_RESULTS = [{}, {}, {}, {}]
|
TEST_SCANNED_RESULTS = [{}, {}, {}, {}]
|
||||||
TEST_EXPLOITED_RESULTS = [
|
TEST_EXPLOITED_RESULTS = [
|
||||||
{"exploits": ["SSH Exploiter"]},
|
MonkeyExploitation("", [], "", exploits=["SSH Exploiter"]),
|
||||||
{"exploits": ["SSH Exploiter", "SMB Exploiter"]},
|
MonkeyExploitation("", [], "", exploits=["SSH Exploiter", "SMB Exploiter"]),
|
||||||
{"exploits": ["WMI Exploiter"]},
|
MonkeyExploitation("", [], "", exploits=["WMI Exploiter"]),
|
||||||
]
|
]
|
||||||
|
|
||||||
monkeypatch.setattr(ReportService, "get_scanned", lambda: TEST_SCANNED_RESULTS)
|
monkeypatch.setattr(ReportService, "get_scanned", lambda: TEST_SCANNED_RESULTS)
|
||||||
monkeypatch.setattr(ReportService, "get_exploited", lambda: TEST_EXPLOITED_RESULTS)
|
monkeypatch.setattr(ransomware_report, "get_monkey_exploited", lambda: TEST_EXPLOITED_RESULTS)
|
||||||
|
|
||||||
|
|
||||||
def test_get_propagation_stats__num_scanned(patch_report_service_for_stats):
|
def test_get_propagation_stats__num_scanned(patch_report_service_for_stats):
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
from tests.unit_tests.monkey_island.cc.services.reporting.test_report import (
|
||||||
|
NODE_DICT,
|
||||||
|
NODE_DICT_DUPLICATE_EXPLOITS,
|
||||||
|
NODE_DICT_FAILED_EXPLOITS,
|
||||||
|
)
|
||||||
|
|
||||||
|
from monkey_island.cc.services.reporting.exploitations.monkey_exploitation import (
|
||||||
|
get_exploits_used_on_node,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_exploits_used_on_node__2_exploits():
|
||||||
|
exploits = get_exploits_used_on_node(NODE_DICT)
|
||||||
|
assert sorted(exploits) == sorted(["Elastic Groovy Exploiter", "Drupal Server Exploiter"])
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_exploits_used_on_node__duplicate_exploits():
|
||||||
|
exploits = get_exploits_used_on_node(NODE_DICT_DUPLICATE_EXPLOITS)
|
||||||
|
assert exploits == ["Drupal Server Exploiter"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_exploits_used_on_node__failed():
|
||||||
|
exploits = get_exploits_used_on_node(NODE_DICT_FAILED_EXPLOITS)
|
||||||
|
assert exploits == []
|
|
@ -164,14 +164,3 @@ def test_get_stolen_creds_no_creds(fake_mongo):
|
||||||
expected_stolen_creds_no_creds = []
|
expected_stolen_creds_no_creds = []
|
||||||
|
|
||||||
assert expected_stolen_creds_no_creds == stolen_creds_no_creds
|
assert expected_stolen_creds_no_creds == stolen_creds_no_creds
|
||||||
|
|
||||||
|
|
||||||
def test_get_exploits_used_on_node():
|
|
||||||
exploits = ReportService.get_exploits_used_on_node(NODE_DICT)
|
|
||||||
assert sorted(exploits) == sorted(["Elastic Groovy Exploiter", "Drupal Server Exploiter"])
|
|
||||||
|
|
||||||
exploits = ReportService.get_exploits_used_on_node(NODE_DICT_DUPLICATE_EXPLOITS)
|
|
||||||
assert exploits == ["Drupal Server Exploiter"]
|
|
||||||
|
|
||||||
exploits = ReportService.get_exploits_used_on_node(NODE_DICT_FAILED_EXPLOITS)
|
|
||||||
assert exploits == []
|
|
||||||
|
|
Loading…
Reference in New Issue