forked from p15670423/monkey
Merge branch 'zt_performance_fixes' into security_performance_fixes
# Conflicts: # envs/monkey_zoo/blackbox/test_blackbox.py # monkey/monkey_island/cc/ui/src/components/report-components/zerotrust/EventsModal.js
This commit is contained in:
commit
3d97cb3b61
|
@ -83,7 +83,10 @@ MonkeyZoo/*
|
||||||
!MonkeyZoo/MonkeyZooDocs.pdf
|
!MonkeyZoo/MonkeyZooDocs.pdf
|
||||||
|
|
||||||
# Exported monkey telemetries
|
# Exported monkey telemetries
|
||||||
/monkey/test_telems/
|
/monkey/telem_sample/
|
||||||
|
|
||||||
|
# Profiling logs
|
||||||
|
profiler_logs/
|
||||||
|
|
||||||
# vim swap files
|
# vim swap files
|
||||||
*.swp
|
*.swp
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
logs/
|
logs/
|
||||||
/blackbox/tests/performance/test_telems/*
|
/blackbox/tests/performance/telem_sample
|
||||||
|
|
|
@ -24,13 +24,14 @@ To run telemetry performance test follow these steps:
|
||||||
1. Enable "Export monkey telemetries" in Configuration -> Internal -> Tests if you don't have
|
1. Enable "Export monkey telemetries" in Configuration -> Internal -> Tests if you don't have
|
||||||
exported telemetries already.
|
exported telemetries already.
|
||||||
2. Run monkey and wait until infection is done.
|
2. Run monkey and wait until infection is done.
|
||||||
3. All telemetries are gathered in `monkey/test_telems`
|
3. All telemetries are gathered in `monkey/telem_sample`
|
||||||
2. Run telemetry performance test.
|
2. Run telemetry performance test.
|
||||||
1. Move directory `monkey/test_telems` to `envs/monkey_zoo/blackbox/tests/performance/test_telems`
|
1. Move directory `monkey/test_telems` to `envs/monkey_zoo/blackbox/tests/performance/test_telems`
|
||||||
2. (Optional) Use `envs/monkey_zoo/blackbox/tests/performance/utils/telem_parser.py` to multiply
|
2. (Optional) Use `envs/monkey_zoo/blackbox/tests/performance/utils/telem_parser.py` to multiply
|
||||||
telemetries gathered.
|
telemetries gathered.
|
||||||
1. Run `telem_parser.py` scrip with working directory set to `monkey\envs\monkey_zoo\blackbox`
|
1. Run `telem_parser.py` script with working directory set to `monkey\envs\monkey_zoo\blackbox`
|
||||||
2. Pass integer to indicate the multiplier. For example running `telem_parser.py 4` will replicate
|
2. Pass integer to indicate the multiplier. For example running `telem_parser.py 4` will replicate
|
||||||
telemetries 4 times.
|
telemetries 4 times.
|
||||||
3. If you're using pycharm check "Emulate terminal in output console" on debug/run configuraion.
|
3. If you're using pycharm check "Emulate terminal in output console" on debug/run configuraion.
|
||||||
3. Run blackbox tests, telemetry performance test will run as part of it.
|
3. Performance test will run as part of BlackBox tests or you can run it separately by adding
|
||||||
|
`-k 'test_telem_performance'` option.
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import json
|
import json
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from time import sleep
|
from time import sleep
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
from time import sleep
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
from time import sleep
|
||||||
|
|
||||||
from envs.monkey_zoo.blackbox.analyzers.communication_analyzer import CommunicationAnalyzer
|
from envs.monkey_zoo.blackbox.analyzers.communication_analyzer import CommunicationAnalyzer
|
||||||
from envs.monkey_zoo.blackbox.island_client.island_config_parser import IslandConfigParser
|
from envs.monkey_zoo.blackbox.island_client.island_config_parser import IslandConfigParser
|
||||||
|
@ -29,12 +29,11 @@ LOGGER = logging.getLogger(__name__)
|
||||||
@pytest.fixture(autouse=True, scope='session')
|
@pytest.fixture(autouse=True, scope='session')
|
||||||
def GCPHandler(request):
|
def GCPHandler(request):
|
||||||
GCPHandler = gcp_machine_handlers.GCPHandler()
|
GCPHandler = gcp_machine_handlers.GCPHandler()
|
||||||
#GCPHandler.start_machines(" ".join(GCP_TEST_MACHINE_LIST))
|
GCPHandler.start_machines(" ".join(GCP_TEST_MACHINE_LIST))
|
||||||
#wait_machine_bootup()
|
wait_machine_bootup()
|
||||||
|
|
||||||
def fin():
|
def fin():
|
||||||
#GCPHandler.stop_machines(" ".join(GCP_TEST_MACHINE_LIST))
|
GCPHandler.stop_machines(" ".join(GCP_TEST_MACHINE_LIST))
|
||||||
pass
|
|
||||||
|
|
||||||
request.addfinalizer(fin)
|
request.addfinalizer(fin)
|
||||||
|
|
||||||
|
@ -52,7 +51,7 @@ def wait_machine_bootup():
|
||||||
@pytest.fixture(scope='class')
|
@pytest.fixture(scope='class')
|
||||||
def island_client(island):
|
def island_client(island):
|
||||||
island_client_object = MonkeyIslandClient(island)
|
island_client_object = MonkeyIslandClient(island)
|
||||||
# island_client_object.reset_env()
|
island_client_object.reset_env()
|
||||||
yield island_client_object
|
yield island_client_object
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
from os import listdir, path
|
||||||
|
from typing import List, Dict
|
||||||
|
|
||||||
|
from tqdm import tqdm
|
||||||
|
|
||||||
|
TELEM_DIR_PATH = './tests/performance/telem_sample'
|
||||||
|
MAX_SAME_TYPE_TELEM_FILES = 10000
|
||||||
|
LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class SampleFileParser:
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def save_teletries_to_files(telems: List[Dict]):
|
||||||
|
for telem in (tqdm(telems, desc="Telemetries saved to files", position=3)):
|
||||||
|
SampleFileParser.save_telemetry_to_file(telem)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def save_telemetry_to_file(telem: Dict):
|
||||||
|
telem_filename = telem['name'] + telem['method']
|
||||||
|
for i in range(MAX_SAME_TYPE_TELEM_FILES):
|
||||||
|
if not path.exists(path.join(TELEM_DIR_PATH, (str(i) + telem_filename))):
|
||||||
|
telem_filename = str(i) + telem_filename
|
||||||
|
break
|
||||||
|
with open(path.join(TELEM_DIR_PATH, telem_filename), 'w') as file:
|
||||||
|
file.write(json.dumps(telem))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def read_telem_files() -> List[str]:
|
||||||
|
telems = []
|
||||||
|
try:
|
||||||
|
file_paths = [path.join(TELEM_DIR_PATH, f) for f in listdir(TELEM_DIR_PATH)
|
||||||
|
if path.isfile(path.join(TELEM_DIR_PATH, f))]
|
||||||
|
except FileNotFoundError:
|
||||||
|
raise FileNotFoundError("Telemetries to send not found. "
|
||||||
|
"Refer to readme to figure out how to generate telemetries and where to put them.")
|
||||||
|
for file_path in file_paths:
|
||||||
|
with open(file_path, 'r') as telem_file:
|
||||||
|
telem_string = "".join(telem_file.readlines()).replace("\n", "")
|
||||||
|
telems.append(telem_string)
|
||||||
|
return telems
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_all_telemetries() -> List[Dict]:
|
||||||
|
return [json.loads(t) for t in SampleFileParser.read_telem_files()]
|
|
@ -0,0 +1,25 @@
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
|
||||||
|
class FakeIpGenerator:
|
||||||
|
def __init__(self):
|
||||||
|
self.fake_ip_parts = [1, 1, 1, 1]
|
||||||
|
|
||||||
|
def generate_fake_ips_for_real_ips(self, real_ips: List[str]) -> List[str]:
|
||||||
|
fake_ips = []
|
||||||
|
for i in range(len(real_ips)):
|
||||||
|
fake_ips.append('.'.join(str(part) for part in self.fake_ip_parts))
|
||||||
|
self.increment_ip()
|
||||||
|
return fake_ips
|
||||||
|
|
||||||
|
def increment_ip(self):
|
||||||
|
self.fake_ip_parts[3] += 1
|
||||||
|
self.try_fix_ip_range()
|
||||||
|
|
||||||
|
def try_fix_ip_range(self):
|
||||||
|
for i in range(len(self.fake_ip_parts)):
|
||||||
|
if self.fake_ip_parts[i] > 256:
|
||||||
|
if i-1 < 0:
|
||||||
|
raise Exception("Fake IP's out of range.")
|
||||||
|
self.fake_ip_parts[i-1] += 1
|
||||||
|
self.fake_ip_parts[i] = 1
|
|
@ -1,6 +1,7 @@
|
||||||
import random
|
import random
|
||||||
|
|
||||||
from envs.monkey_zoo.blackbox.tests.performance.utils.fake_ip_generator import FakeIpGenerator
|
from envs.monkey_zoo.blackbox.tests.performance.\
|
||||||
|
telem_sample_parsing.sample_multiplier.fake_ip_generator import FakeIpGenerator
|
||||||
|
|
||||||
|
|
||||||
class FakeMonkey:
|
class FakeMonkey:
|
|
@ -2,35 +2,37 @@ import copy
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
from os import listdir, path
|
|
||||||
from typing import List, Dict
|
from typing import List, Dict
|
||||||
|
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
|
|
||||||
from envs.monkey_zoo.blackbox.tests.performance.utils.fake_ip_generator import FakeIpGenerator
|
from envs.monkey_zoo.blackbox.tests.performance.telem_sample_parsing.sample_file_parser import SampleFileParser
|
||||||
from envs.monkey_zoo.blackbox.tests.performance.utils.fake_monkey import FakeMonkey
|
from envs.monkey_zoo.blackbox.tests.performance.\
|
||||||
|
telem_sample_parsing.sample_multiplier.fake_ip_generator import FakeIpGenerator
|
||||||
|
from envs.monkey_zoo.blackbox.tests.performance.telem_sample_parsing.sample_multiplier.fake_monkey import FakeMonkey
|
||||||
|
|
||||||
TELEM_DIR_PATH = './tests/performance/test_telems'
|
TELEM_DIR_PATH = './tests/performance/telemetry_sample'
|
||||||
LOGGER = logging.getLogger(__name__)
|
LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class TelemParser:
|
class SampleMultiplier:
|
||||||
|
|
||||||
def __init__(self, multiplier: int):
|
def __init__(self, multiplier: int):
|
||||||
self.multiplier = multiplier
|
self.multiplier = multiplier
|
||||||
self.fake_ip_generator = FakeIpGenerator()
|
self.fake_ip_generator = FakeIpGenerator()
|
||||||
|
|
||||||
def multiply_telems(self):
|
def multiply_telems(self):
|
||||||
telems = TelemParser.get_all_telemetries()
|
telems = SampleFileParser.get_all_telemetries()
|
||||||
telem_contents = [json.loads(telem['content']) for telem in telems]
|
telem_contents = [json.loads(telem['content']) for telem in telems]
|
||||||
monkeys = self.get_monkeys_from_telems(telem_contents)
|
monkeys = self.get_monkeys_from_telems(telem_contents)
|
||||||
for i in tqdm(range(self.multiplier), desc="Batch of fabricated telemetries", position=1):
|
for i in tqdm(range(self.multiplier), desc="Batch of fabricated telemetries", position=1):
|
||||||
for monkey in monkeys:
|
for monkey in monkeys:
|
||||||
monkey.change_fake_data()
|
monkey.change_fake_data()
|
||||||
fake_telem_batch = copy.deepcopy(telems)
|
fake_telem_batch = copy.deepcopy(telems)
|
||||||
TelemParser.fabricate_monkeys_in_telems(fake_telem_batch, monkeys)
|
SampleMultiplier.fabricate_monkeys_in_telems(fake_telem_batch, monkeys)
|
||||||
TelemParser.offset_telem_times(iteration=i, telems=fake_telem_batch)
|
SampleMultiplier.offset_telem_times(iteration=i, telems=fake_telem_batch)
|
||||||
TelemParser.save_teletries_to_files(fake_telem_batch)
|
SampleFileParser.save_teletries_to_files(fake_telem_batch)
|
||||||
|
LOGGER.info("")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def fabricate_monkeys_in_telems(telems: List[Dict], monkeys: List[FakeMonkey]):
|
def fabricate_monkeys_in_telems(telems: List[Dict], monkeys: List[FakeMonkey]):
|
||||||
|
@ -38,7 +40,8 @@ class TelemParser:
|
||||||
for monkey in monkeys:
|
for monkey in monkeys:
|
||||||
if monkey.on_island:
|
if monkey.on_island:
|
||||||
continue
|
continue
|
||||||
if (monkey.original_guid in telem['content'] or monkey.original_guid in telem['endpoint']) and not monkey.on_island:
|
if (monkey.original_guid in telem['content'] or monkey.original_guid in telem['endpoint']) \
|
||||||
|
and not monkey.on_island:
|
||||||
telem['content'] = telem['content'].replace(monkey.original_guid, monkey.fake_guid)
|
telem['content'] = telem['content'].replace(monkey.original_guid, monkey.fake_guid)
|
||||||
telem['endpoint'] = telem['endpoint'].replace(monkey.original_guid, monkey.fake_guid)
|
telem['endpoint'] = telem['endpoint'].replace(monkey.original_guid, monkey.fake_guid)
|
||||||
for i in range(len(monkey.original_ips)):
|
for i in range(len(monkey.original_ips)):
|
||||||
|
@ -49,39 +52,11 @@ class TelemParser:
|
||||||
for telem in telems:
|
for telem in telems:
|
||||||
telem['time']['$date'] += iteration * 1000
|
telem['time']['$date'] += iteration * 1000
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def save_teletries_to_files(telems: List[Dict]):
|
|
||||||
for telem in (tqdm(telems, desc="Telemetries saved to files", position=3)):
|
|
||||||
TelemParser.save_telemetry_to_file(telem)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def save_telemetry_to_file(telem: Dict):
|
|
||||||
telem_filename = telem['name'] + telem['method']
|
|
||||||
for i in range(10000):
|
|
||||||
if not path.exists(path.join(TELEM_DIR_PATH, (str(i) + telem_filename))):
|
|
||||||
telem_filename = str(i) + telem_filename
|
|
||||||
break
|
|
||||||
with open(path.join(TELEM_DIR_PATH, telem_filename), 'w') as file:
|
|
||||||
file.write(json.dumps(telem))
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def read_telem_files() -> List[str]:
|
|
||||||
telems = []
|
|
||||||
file_paths = [path.join(TELEM_DIR_PATH, f) for f in listdir(TELEM_DIR_PATH)
|
|
||||||
if path.isfile(path.join(TELEM_DIR_PATH, f))]
|
|
||||||
for file_path in file_paths:
|
|
||||||
with open(file_path, 'r') as telem_file:
|
|
||||||
telems.append(telem_file.readline())
|
|
||||||
return telems
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_all_telemetries() -> List[Dict]:
|
|
||||||
return [json.loads(t) for t in TelemParser.read_telem_files()]
|
|
||||||
|
|
||||||
def get_monkeys_from_telems(self, telems: List[Dict]):
|
def get_monkeys_from_telems(self, telems: List[Dict]):
|
||||||
island_ips = TelemParser.get_island_ips_from_telems(telems)
|
island_ips = SampleMultiplier.get_island_ips_from_telems(telems)
|
||||||
monkeys = []
|
monkeys = []
|
||||||
for telem in [telem for telem in telems if 'telem_category' in telem and telem['telem_category'] == 'system_info']:
|
for telem in [telem for telem in telems
|
||||||
|
if 'telem_category' in telem and telem['telem_category'] == 'system_info']:
|
||||||
if 'network_info' not in telem['data']:
|
if 'network_info' not in telem['data']:
|
||||||
continue
|
continue
|
||||||
guid = telem['monkey_guid']
|
guid = telem['monkey_guid']
|
||||||
|
@ -111,4 +86,4 @@ class TelemParser:
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
TelemParser(multiplier=int(sys.argv[1])).multiply_telems()
|
SampleMultiplier(multiplier=int(sys.argv[1])).multiply_telems()
|
|
@ -0,0 +1,19 @@
|
||||||
|
from unittest import TestCase
|
||||||
|
|
||||||
|
from envs.monkey_zoo.blackbox.tests.performance.\
|
||||||
|
telem_sample_parsing.sample_multiplier.fake_ip_generator import FakeIpGenerator
|
||||||
|
|
||||||
|
|
||||||
|
class TestFakeIpGenerator(TestCase):
|
||||||
|
|
||||||
|
def test_fake_ip_generation(self):
|
||||||
|
fake_ip_gen = FakeIpGenerator()
|
||||||
|
self.assertListEqual([1, 1, 1, 1], fake_ip_gen.fake_ip_parts)
|
||||||
|
for i in range(256):
|
||||||
|
fake_ip_gen.generate_fake_ips_for_real_ips(['1.1.1.1'])
|
||||||
|
self.assertListEqual(['1.1.2.1'], fake_ip_gen.generate_fake_ips_for_real_ips(['1.1.1.1']))
|
||||||
|
fake_ip_gen.fake_ip_parts = [256, 256, 255, 256]
|
||||||
|
self.assertListEqual(['256.256.255.256', '256.256.256.1'],
|
||||||
|
fake_ip_gen.generate_fake_ips_for_real_ips(['1.1.1.1', '1.1.1.2']))
|
||||||
|
fake_ip_gen.fake_ip_parts = [256, 256, 256, 256]
|
||||||
|
self.assertRaises(Exception, fake_ip_gen.generate_fake_ips_for_real_ips(['1.1.1.1']))
|
|
@ -8,7 +8,7 @@ from envs.monkey_zoo.blackbox.analyzers.performance_analyzer import PerformanceA
|
||||||
from envs.monkey_zoo.blackbox.island_client.monkey_island_client import MonkeyIslandClient
|
from envs.monkey_zoo.blackbox.island_client.monkey_island_client import MonkeyIslandClient
|
||||||
from envs.monkey_zoo.blackbox.island_client.supported_request_method import SupportedRequestMethod
|
from envs.monkey_zoo.blackbox.island_client.supported_request_method import SupportedRequestMethod
|
||||||
from envs.monkey_zoo.blackbox.tests.performance.performance_test_config import PerformanceTestConfig
|
from envs.monkey_zoo.blackbox.tests.performance.performance_test_config import PerformanceTestConfig
|
||||||
from envs.monkey_zoo.blackbox.tests.performance.utils.telem_parser import TelemParser
|
from envs.monkey_zoo.blackbox.tests.performance.telem_sample_parsing.sample_file_parser import SampleFileParser
|
||||||
|
|
||||||
LOGGER = logging.getLogger(__name__)
|
LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -24,11 +24,10 @@ class TelemetryPerformanceTest:
|
||||||
def test_telemetry_performance(self):
|
def test_telemetry_performance(self):
|
||||||
LOGGER.info("Starting telemetry performance test.")
|
LOGGER.info("Starting telemetry performance test.")
|
||||||
try:
|
try:
|
||||||
all_telemetries = TelemParser.get_all_telemetries()
|
all_telemetries = SampleFileParser.get_all_telemetries()
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
LOGGER.error("Telemetries to send not found. Refer to readme to figure out how to generate telemetries "
|
raise FileNotFoundError("Telemetries to send not found. "
|
||||||
"and where to put them.")
|
"Refer to readme to figure out how to generate telemetries and where to put them.")
|
||||||
return False
|
|
||||||
LOGGER.info("Telemetries imported successfully.")
|
LOGGER.info("Telemetries imported successfully.")
|
||||||
all_telemetries.sort(key=lambda telem: telem['time']['$date'])
|
all_telemetries.sort(key=lambda telem: telem['time']['$date'])
|
||||||
telemetry_parse_times = {}
|
telemetry_parse_times = {}
|
||||||
|
|
|
@ -13,9 +13,8 @@ class TelemetryPerformanceTestWorkflow(BasicTest):
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
try:
|
try:
|
||||||
# TelemetryPerformanceTest(island_client=self.island_client).test_telemetry_performance()
|
TelemetryPerformanceTest(island_client=self.island_client).test_telemetry_performance()
|
||||||
performance_test = EndpointPerformanceTest(self.name, self.performance_config, self.island_client)
|
performance_test = EndpointPerformanceTest(self.name, self.performance_config, self.island_client)
|
||||||
assert performance_test.run()
|
assert performance_test.run()
|
||||||
finally:
|
finally:
|
||||||
pass
|
self.island_client.reset_env()
|
||||||
# self.island_client.reset_env()
|
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
class FakeIpGenerator:
|
|
||||||
def __init__(self):
|
|
||||||
self.fake_ip_parts = [1, 1, 1, 1]
|
|
||||||
|
|
||||||
def generate_fake_ips_for_real_ips(self, real_ips):
|
|
||||||
self.fake_ip_parts[2] += 1
|
|
||||||
fake_ips = []
|
|
||||||
for i in range(len(real_ips)):
|
|
||||||
fake_ips.append('.'.join(str(part) for part in self.fake_ip_parts))
|
|
||||||
self.fake_ip_parts[3] += 1
|
|
||||||
return fake_ips
|
|
|
@ -20,8 +20,7 @@ class AggregateFinding(Finding):
|
||||||
else:
|
else:
|
||||||
# Now we know for sure this is the only one
|
# Now we know for sure this is the only one
|
||||||
orig_finding = existing_findings[0]
|
orig_finding = existing_findings[0]
|
||||||
orig_finding.update(push_all__events=events)
|
orig_finding.add_events(events)
|
||||||
orig_finding.save()
|
|
||||||
|
|
||||||
|
|
||||||
def add_malicious_activity_to_timeline(events):
|
def add_malicious_activity_to_timeline(events):
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
"""
|
"""
|
||||||
Define a Document Schema for Zero Trust findings.
|
Define a Document Schema for Zero Trust findings.
|
||||||
"""
|
"""
|
||||||
|
from typing import List
|
||||||
|
|
||||||
from mongoengine import Document, StringField, EmbeddedDocumentListField
|
from mongoengine import Document, StringField, EmbeddedDocumentListField
|
||||||
|
|
||||||
|
@ -54,3 +55,6 @@ class Finding(Document):
|
||||||
finding.save()
|
finding.save()
|
||||||
|
|
||||||
return finding
|
return finding
|
||||||
|
|
||||||
|
def add_events(self, events: List) -> None:
|
||||||
|
self.update(push_all__events=events)
|
||||||
|
|
|
@ -6,7 +6,6 @@ from flask import jsonify
|
||||||
from monkey_island.cc.auth import jwt_required
|
from monkey_island.cc.auth import jwt_required
|
||||||
from monkey_island.cc.services.reporting.report import ReportService
|
from monkey_island.cc.services.reporting.report import ReportService
|
||||||
from monkey_island.cc.services.reporting.zero_trust_service import ZeroTrustService
|
from monkey_island.cc.services.reporting.zero_trust_service import ZeroTrustService
|
||||||
from monkey_island.cc.testing.profiler_decorator import profile
|
|
||||||
|
|
||||||
ZERO_TRUST_REPORT_TYPE = "zero_trust"
|
ZERO_TRUST_REPORT_TYPE = "zero_trust"
|
||||||
SECURITY_REPORT_TYPE = "security"
|
SECURITY_REPORT_TYPE = "security"
|
||||||
|
@ -22,7 +21,6 @@ __author__ = ["itay.mizeretz", "shay.nehmad"]
|
||||||
class Report(flask_restful.Resource):
|
class Report(flask_restful.Resource):
|
||||||
|
|
||||||
@jwt_required()
|
@jwt_required()
|
||||||
@profile()
|
|
||||||
def get(self, report_type=SECURITY_REPORT_TYPE, report_data=None):
|
def get(self, report_type=SECURITY_REPORT_TYPE, report_data=None):
|
||||||
if report_type == SECURITY_REPORT_TYPE:
|
if report_type == SECURITY_REPORT_TYPE:
|
||||||
return ReportService.get_report()
|
return ReportService.get_report()
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import logging
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from os import mkdir, path
|
from os import mkdir, path
|
||||||
import shutil
|
import shutil
|
||||||
|
@ -8,10 +9,14 @@ from flask import request
|
||||||
from monkey_island.cc.models.test_telem import TestTelem
|
from monkey_island.cc.models.test_telem import TestTelem
|
||||||
from monkey_island.cc.services.config import ConfigService
|
from monkey_island.cc.services.config import ConfigService
|
||||||
|
|
||||||
TEST_TELEM_DIR = "./test_telems"
|
TELEM_SAMPLE_DIR = "./telem_sample"
|
||||||
MAX_SAME_CATEGORY_TELEMS = 10000
|
MAX_SAME_CATEGORY_TELEMS = 10000
|
||||||
|
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class TestTelemStore:
|
class TestTelemStore:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -31,14 +36,17 @@ class TestTelemStore:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def export_test_telems():
|
def export_test_telems():
|
||||||
|
logger.info(f"Exporting all telemetries to {TELEM_SAMPLE_DIR}")
|
||||||
try:
|
try:
|
||||||
mkdir(TEST_TELEM_DIR)
|
mkdir(TELEM_SAMPLE_DIR)
|
||||||
except FileExistsError:
|
except FileExistsError:
|
||||||
shutil.rmtree(TEST_TELEM_DIR)
|
logger.info("Deleting all previous telemetries.")
|
||||||
mkdir(TEST_TELEM_DIR)
|
shutil.rmtree(TELEM_SAMPLE_DIR)
|
||||||
|
mkdir(TELEM_SAMPLE_DIR)
|
||||||
for test_telem in TestTelem.objects():
|
for test_telem in TestTelem.objects():
|
||||||
with open(TestTelemStore.get_unique_file_path_for_test_telem(TEST_TELEM_DIR, test_telem), 'w') as file:
|
with open(TestTelemStore.get_unique_file_path_for_test_telem(TELEM_SAMPLE_DIR, test_telem), 'w') as file:
|
||||||
file.write(test_telem.to_json())
|
file.write(test_telem.to_json(indent=2))
|
||||||
|
logger.info("Telemetries exported!")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_unique_file_path_for_test_telem(target_dir: str, test_telem: TestTelem):
|
def get_unique_file_path_for_test_telem(target_dir: str, test_telem: TestTelem):
|
||||||
|
|
|
@ -3,12 +3,10 @@ import json
|
||||||
|
|
||||||
from monkey_island.cc.auth import jwt_required
|
from monkey_island.cc.auth import jwt_required
|
||||||
from monkey_island.cc.services.reporting.zero_trust_service import ZeroTrustService
|
from monkey_island.cc.services.reporting.zero_trust_service import ZeroTrustService
|
||||||
from monkey_island.cc.testing.profiler_decorator import profile
|
|
||||||
|
|
||||||
|
|
||||||
class ZeroTrustFindingEvent(flask_restful.Resource):
|
class ZeroTrustFindingEvent(flask_restful.Resource):
|
||||||
|
|
||||||
@jwt_required()
|
@jwt_required()
|
||||||
@profile()
|
|
||||||
def get(self, finding_id: str):
|
def get(self, finding_id: str):
|
||||||
return {'events_json': json.dumps(ZeroTrustService.get_events_by_finding(finding_id), default=str)}
|
return {'events_json': json.dumps(ZeroTrustService.get_events_by_finding(finding_id), default=str)}
|
||||||
|
|
|
@ -319,9 +319,9 @@ class TestZeroTrustService(IslandTestCase):
|
||||||
|
|
||||||
def test_get_events_without_overlap(self):
|
def test_get_events_without_overlap(self):
|
||||||
monkey_island.cc.services.reporting.zero_trust_service.EVENT_FETCH_CNT = 5
|
monkey_island.cc.services.reporting.zero_trust_service.EVENT_FETCH_CNT = 5
|
||||||
self.assertListEqual([], ZeroTrustService._ZeroTrustService__get_events_without_overlap(5, [1, 2, 3]))
|
self.assertListEqual([], ZeroTrustService._get_events_without_overlap(5, [1, 2, 3]))
|
||||||
self.assertListEqual([3], ZeroTrustService._ZeroTrustService__get_events_without_overlap(6, [1, 2, 3]))
|
self.assertListEqual([3], ZeroTrustService._get_events_without_overlap(6, [1, 2, 3]))
|
||||||
self.assertListEqual([1, 2, 3, 4, 5], ZeroTrustService._ZeroTrustService__get_events_without_overlap(10, [1, 2, 3, 4, 5]))
|
self.assertListEqual([1, 2, 3, 4, 5], ZeroTrustService._get_events_without_overlap(10, [1, 2, 3, 4, 5]))
|
||||||
|
|
||||||
|
|
||||||
def compare_lists_no_order(s, t):
|
def compare_lists_no_order(s, t):
|
||||||
|
|
|
@ -109,28 +109,27 @@ class ZeroTrustService(object):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_all_findings():
|
def get_all_findings():
|
||||||
pipeline = [{'$match': {}},
|
pipeline = [{'$addFields': {'oldest_events': {'$slice': ['$events', EVENT_FETCH_CNT]},
|
||||||
{'$addFields': {'oldest_events': {'$slice': ['$events', EVENT_FETCH_CNT]},
|
|
||||||
'latest_events': {'$slice': ['$events', -1*EVENT_FETCH_CNT]},
|
'latest_events': {'$slice': ['$events', -1*EVENT_FETCH_CNT]},
|
||||||
'event_count': {'$size': '$events'}}},
|
'event_count': {'$size': '$events'}}},
|
||||||
{'$unset': ['events']}]
|
{'$unset': ['events']}]
|
||||||
all_findings = list(Finding.objects.aggregate(*pipeline))
|
all_findings = list(Finding.objects.aggregate(*pipeline))
|
||||||
for finding in all_findings:
|
for finding in all_findings:
|
||||||
finding['latest_events'] = ZeroTrustService.__get_events_without_overlap(finding['event_count'],
|
finding['latest_events'] = ZeroTrustService._get_events_without_overlap(finding['event_count'],
|
||||||
finding['latest_events'])
|
finding['latest_events'])
|
||||||
|
|
||||||
enriched_findings = [ZeroTrustService.__get_enriched_finding(f) for f in all_findings]
|
enriched_findings = [ZeroTrustService.__get_enriched_finding(f) for f in all_findings]
|
||||||
return enriched_findings
|
return enriched_findings
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def __get_events_without_overlap(event_count: int, events: List[object]) -> List[object]:
|
def _get_events_without_overlap(event_count: int, events: List[object]) -> List[object]:
|
||||||
overlap_count = event_count - EVENT_FETCH_CNT
|
overlap_count = event_count - EVENT_FETCH_CNT
|
||||||
if overlap_count >= EVENT_FETCH_CNT:
|
if overlap_count >= EVENT_FETCH_CNT:
|
||||||
return events
|
return events
|
||||||
elif overlap_count <= 0:
|
elif overlap_count <= 0:
|
||||||
return []
|
return []
|
||||||
else:
|
else:
|
||||||
return events[ -overlap_count :]
|
return events[-1 * overlap_count:]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def __get_enriched_finding(finding):
|
def __get_enriched_finding(finding):
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Profiling island
|
||||||
|
|
||||||
|
To profile specific methods on island a `@profile(sort_args=['cumulative'], print_args=[100])`
|
||||||
|
decorator can be used.
|
||||||
|
Use it as any other decorator. After decorated method is used, a file will appear in a
|
||||||
|
directory provided in `profiler_decorator.py`. Filename describes the path of
|
||||||
|
the method that was profiled. For example if method `monkey_island/cc/resources/netmap.get`
|
||||||
|
was profiled, then the results of this profiling will appear in
|
||||||
|
`monkey_island_cc_resources_netmap_get`.
|
|
@ -1,4 +1,4 @@
|
||||||
import React, {Component} from 'react';
|
import React from 'react';
|
||||||
import {Modal} from 'react-bootstrap';
|
import {Modal} from 'react-bootstrap';
|
||||||
import EventsTimeline from './EventsTimeline';
|
import EventsTimeline from './EventsTimeline';
|
||||||
import * as PropTypes from 'prop-types';
|
import * as PropTypes from 'prop-types';
|
||||||
|
@ -6,7 +6,7 @@ import saveJsonToFile from '../../utils/SaveJsonToFile';
|
||||||
import EventsModalButtons from './EventsModalButtons';
|
import EventsModalButtons from './EventsModalButtons';
|
||||||
import AuthComponent from '../../AuthComponent';
|
import AuthComponent from '../../AuthComponent';
|
||||||
import Pluralize from 'pluralize';
|
import Pluralize from 'pluralize';
|
||||||
import SkippedEventsTimeline from "./SkippedEventsTimeline";
|
import SkippedEventsTimeline from './SkippedEventsTimeline';
|
||||||
|
|
||||||
const FINDING_EVENTS_URL = '/api/zero-trust/finding-event/';
|
const FINDING_EVENTS_URL = '/api/zero-trust/finding-event/';
|
||||||
|
|
||||||
|
|
|
@ -23,4 +23,4 @@ requests
|
||||||
dpath
|
dpath
|
||||||
ring
|
ring
|
||||||
stix2
|
stix2
|
||||||
tcdm
|
tqdm
|
||||||
|
|
Loading…
Reference in New Issue