forked from p15670423/monkey
Add unit tests and for ransomware report, which get skipped because of a bug in mongomock
This commit is contained in:
parent
f6eda771b2
commit
9492b14c95
|
@ -1,8 +1,91 @@
|
||||||
|
from monkey_island.cc.database import mongo
|
||||||
from typing import Dict, List
|
from typing import Dict, List
|
||||||
|
|
||||||
from monkey_island.cc.services.reporting.report import ReportService
|
from monkey_island.cc.services.reporting.report import ReportService
|
||||||
|
|
||||||
|
|
||||||
|
class RansomwareReportService:
|
||||||
|
@staticmethod
|
||||||
|
def get_encrypted_files_table():
|
||||||
|
query = [
|
||||||
|
{"$match": {"telem_category": "file_encryption"}},
|
||||||
|
{"$unwind": "$data.files"},
|
||||||
|
{
|
||||||
|
"$group": {
|
||||||
|
"_id": {"monkey_guid": "$monkey_guid", "files_encrypted": "$data.files.success"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{"$replaceRoot": {"newRoot": "$_id"}},
|
||||||
|
{"$sort": {"files_encrypted": -1}},
|
||||||
|
{
|
||||||
|
"$group": {
|
||||||
|
"_id": {"monkey_guid": "$monkey_guid"},
|
||||||
|
"monkey_guid": {"$first": "$monkey_guid"},
|
||||||
|
"files_encrypted": {"$first": "$files_encrypted"},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$lookup": {
|
||||||
|
"from": "monkey",
|
||||||
|
"localField": "_id.monkey_guid",
|
||||||
|
"foreignField": "guid",
|
||||||
|
"as": "monkey",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$project": {
|
||||||
|
"monkey": {"$arrayElemAt": ["$monkey", 0]},
|
||||||
|
"files_encrypted": "$files_encrypted",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$lookup": {
|
||||||
|
"from": "edge",
|
||||||
|
"localField": "monkey._id",
|
||||||
|
"foreignField": "dst_node_id",
|
||||||
|
"as": "edge",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$project": {
|
||||||
|
"monkey": "$monkey",
|
||||||
|
"files_encrypted": "$files_encrypted",
|
||||||
|
"edge": {"$arrayElemAt": ["$edge", 0]},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$project": {
|
||||||
|
"hostname": "$monkey.hostname",
|
||||||
|
"successful_exploits": {
|
||||||
|
"$filter": {
|
||||||
|
"input": "$edge.exploits",
|
||||||
|
"as": "exploit",
|
||||||
|
"cond": {"$eq": ["$$exploit.result", True]},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"files_encrypted": "$files_encrypted",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$addFields": {
|
||||||
|
"successful_exploit": {"$arrayElemAt": ["$successful_exploits", 0]},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$project": {
|
||||||
|
"hostname": "$hostname",
|
||||||
|
"exploiter": "$successful_exploit.info.display_name",
|
||||||
|
"files_encrypted": "$files_encrypted",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
table_data = list(mongo.db.telemetry.aggregate(query))
|
||||||
|
for encryption_entry in table_data:
|
||||||
|
if "exploiter" not in encryption_entry:
|
||||||
|
encryption_entry["exploiter"] = "Manual run"
|
||||||
|
return table_data
|
||||||
|
|
||||||
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()
|
||||||
|
|
|
@ -0,0 +1,125 @@
|
||||||
|
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",
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
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": [],
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
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,8 +1,78 @@
|
||||||
|
import mongomock
|
||||||
|
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,
|
||||||
|
)
|
||||||
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.report import ReportService
|
from monkey_island.cc.services.reporting.report import ReportService
|
||||||
|
|
||||||
|
from monkey_island.cc.services.ransomware.ransomware_report import RansomwareReportService
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def fake_mongo(monkeypatch):
|
||||||
|
mongo = mongomock.MongoClient()
|
||||||
|
monkeypatch.setattr("monkey_island.cc.services.ransomware.ransomware_report.mongo", mongo)
|
||||||
|
return mongo
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skip(
|
||||||
|
reason="A bug in mongomock prevents " "projecting the first element of an empty array"
|
||||||
|
)
|
||||||
|
@pytest.mark.usefixtures("uses_database")
|
||||||
|
def test_get_encrypted_files_table(fake_mongo):
|
||||||
|
fake_mongo.db.monkey.insert(MONKEY_AT_ISLAND)
|
||||||
|
fake_mongo.db.monkey.insert(MONKEY_AT_VICTIM)
|
||||||
|
fake_mongo.db.edge.insert(EDGE_EXPLOITED)
|
||||||
|
fake_mongo.db.edge.insert(EDGE_SCANNED)
|
||||||
|
fake_mongo.db.telemetry.insert(ENCRYPTED)
|
||||||
|
fake_mongo.db.telemetry.insert(ENCRYPTED_2)
|
||||||
|
fake_mongo.db.telemetry.insert(ENCRYPTION_ERROR)
|
||||||
|
fake_mongo.db.telemetry.insert(ENCRYPTION_ONE_FILE)
|
||||||
|
|
||||||
|
results = RansomwareReportService.get_encrypted_files_table()
|
||||||
|
|
||||||
|
assert results == [
|
||||||
|
{"hostname": "test-pc-2", "exploit": "Manual execution", "files_encrypted": True},
|
||||||
|
{"hostname": "WinDev2010Eval", "exploit": "SMB", "files_encrypted": True},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skip(
|
||||||
|
reason="A bug in mongomock prevents " "projecting the first element of an empty array"
|
||||||
|
)
|
||||||
|
@pytest.mark.usefixtures("uses_database")
|
||||||
|
def test_get_encrypted_files_table__only_errors(fake_mongo):
|
||||||
|
fake_mongo.db.monkey.insert(MONKEY_AT_ISLAND)
|
||||||
|
fake_mongo.db.monkey.insert(MONKEY_AT_VICTIM)
|
||||||
|
fake_mongo.db.edge.insert(EDGE_EXPLOITED)
|
||||||
|
fake_mongo.db.edge.insert(EDGE_SCANNED)
|
||||||
|
fake_mongo.db.telemetry.insert(ENCRYPTION_ERROR)
|
||||||
|
|
||||||
|
results = RansomwareReportService.get_encrypted_files_table()
|
||||||
|
|
||||||
|
assert results == []
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skip(
|
||||||
|
reason="A bug in mongomock prevents " "projecting the first element of an empty array"
|
||||||
|
)
|
||||||
|
@pytest.mark.usefixtures("uses_database")
|
||||||
|
def test_get_encrypted_files_table__no_telemetries(fake_mongo):
|
||||||
|
fake_mongo.db.monkey.insert(MONKEY_AT_ISLAND)
|
||||||
|
fake_mongo.db.monkey.insert(MONKEY_AT_VICTIM)
|
||||||
|
fake_mongo.db.edge.insert(EDGE_EXPLOITED)
|
||||||
|
fake_mongo.db.edge.insert(EDGE_SCANNED)
|
||||||
|
|
||||||
|
results = RansomwareReportService.get_encrypted_files_table()
|
||||||
|
|
||||||
|
assert results == []
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def patch_report_service_for_stats(monkeypatch):
|
def patch_report_service_for_stats(monkeypatch):
|
||||||
|
|
Loading…
Reference in New Issue