diff --git a/.gitmodules b/.gitmodules
index b898f160a..2fb33dd37 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -4,6 +4,3 @@
[submodule "docs/themes/learn"]
path = docs/themes/learn
url = https://github.com/guardicode/hugo-theme-learn.git
-[submodule "monkey/infection_monkey/system_info/collectors/scoutsuite"]
- path = monkey/common/cloud/scoutsuite
- url = https://github.com/guardicode/ScoutSuite.git
diff --git a/.travis.yml b/.travis.yml
index 668d9cdc3..8ac8db204 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -27,7 +27,6 @@ install:
- pip install flake8 pytest pytest-cov dlint isort # for next stages
- pip install coverage # for code coverage
- pip install -r monkey/infection_monkey/requirements.txt # for unit tests
-- pip install -r monkey/common/cloud/scoutsuite/requirements.txt
- pip install pipdeptree
# Fail builds on possible conflicting dependencies.
- pipdeptree --warn fail
@@ -56,7 +55,7 @@ install:
script:
# Check Python code
## Check syntax errors and fail the build if any are found.
-- flake8 ./monkey --exclude=monkey/common/cloud/scoutsuite --config=./ci_scripts/flake8_syntax_check.ini
+- flake8 ./monkey --config=./ci_scripts/flake8_syntax_check.ini
## Warn about linter issues.
### --exit-zero forces Flake8 to use the exit status code 0 even if there are errors, which means this will NOT fail the build.
diff --git a/deployment_scripts/deploy_linux.sh b/deployment_scripts/deploy_linux.sh
index 718773fad..408aa3148 100755
--- a/deployment_scripts/deploy_linux.sh
+++ b/deployment_scripts/deploy_linux.sh
@@ -66,7 +66,6 @@ MONGO_PATH="$ISLAND_PATH/bin/mongodb"
ISLAND_BINARIES_PATH="$ISLAND_PATH/cc/binaries"
INFECTION_MONKEY_DIR="$monkey_home/monkey/infection_monkey"
MONKEY_BIN_DIR="$INFECTION_MONKEY_DIR/bin"
-SCOUTSUITE_DIR="$monkey_home/monkey/common/cloud/scoutsuite"
if ! has_sudo; then
log_message "You need root permissions for some of this script operations. \
@@ -142,10 +141,6 @@ sudo apt-get install -y libffi-dev upx libssl-dev libc++1
requirements_monkey="$INFECTION_MONKEY_DIR/requirements.txt"
${python_cmd} -m pip install -r "${requirements_monkey}" --user --upgrade || handle_error
-log_message "Installing ScoutSuite requirements"
-requirements_scoutsuite="$SCOUTSUITE_DIR/requirements.txt"
-${python_cmd} -m pip install -r "${requirements_scoutsuite}" --user --upgrade || handle_error
-
agents=${3:-true}
# Download binaries
if [ "$agents" = true ] ; then
diff --git a/docs/content/FAQ/_index.md b/docs/content/FAQ/_index.md
index 89bbf8aba..2d46310cd 100644
--- a/docs/content/FAQ/_index.md
+++ b/docs/content/FAQ/_index.md
@@ -7,7 +7,7 @@ pre: " "
Here are some of the most common questions we receive about the Infection Monkey. If the answer you're looking for isn't here, talk with us [on our Slack channel](https://infectionmonkey.slack.com/join/shared_invite/enQtNDU5MjAxMjg1MjU1LWM0NjVmNWE2ZTMzYzAxOWJiYmMxMzU0NWU3NmUxYjcyNjk0YWY2MDkwODk4NGMyNDU4NzA4MDljOWNmZWViNDU), email us at [support@infectionmonkey.com](mailto:support@infectionmonkey.com) or [open an issue on GitHub](https://github.com/guardicore/monkey).
-- [Where can I get the latest Monkey version? π°](#where-can-i-get-the-latest-monkey-version)
+- [Where can I get the latest Monkey version?](#where-can-i-get-the-latest-monkey-version)
- [How long does a single Monkey run for? Is there a time limit?](#how-long-does-a-single-monkey-run-for-is-there-a-time-limit)
- [How to reset the password?](#how-to-reset-the-password)
- [Should I run the Monkey continuously?](#should-i-run-the-monkey-continuously)
@@ -24,9 +24,9 @@ Here are some of the most common questions we receive about the Infection Monkey
- [After I've set up Monkey Island, how can I execute the Monkey?](#after-ive-set-up-monkey-island-how-can-i-execute-the-monkey)
- [How can I make the monkey propagate βdeeperβ into the network?](#how-can-i-make-the-monkey-propagate-deeper-into-the-network)
- [The report returns a blank screen](#the-report-returns-a-blank-screen)
-- [How can I get involved with the project? π©βπ»π¨βπ»](#how-can-i-get-involved-with-the-project)
+- [How can I get involved with the project?](#how-can-i-get-involved-with-the-project)
-## Where can I get the latest Monkey version? π°
+## Where can I get the latest Monkey version?
For the latest **stable** release for users, visit [our downloads page](https://www.guardicore.com/infectionmonkey/#download). **This is the recommended and supported version**!
@@ -167,7 +167,7 @@ This is sometimes caused when Monkey Island is installed with an old version of
- **Linux**: First, uninstall the current version with `sudo apt uninstall mongodb` and then install the latest version using the [official mongodb manual](https://docs.mongodb.com/manual/administration/install-community/).
- **Windows**: First, remove the MongoDB binaries from the `monkey\monkey_island\bin\mongodb` folder. Download and install the latest version of mongodb using the [official mongodb manual](https://docs.mongodb.com/manual/administration/install-community/). After installation is complete, copy the files from the `C:\Program Files\MongoDB\Server\4.2\bin` folder to the `monkey\monkey_island\bin\mongodb folder`. Try to run the Island again and everything should work.
-## How can I get involved with the project? π©βπ»π¨βπ»
+## How can I get involved with the project?
The Monkey is an open-source project, and we weclome contributions and contributors. Check out the [contribution documentation](../development) for more information.
diff --git a/docs/content/setup/debian.md b/docs/content/setup/debian.md
index c2e875b68..b76d27ec0 100644
--- a/docs/content/setup/debian.md
+++ b/docs/content/setup/debian.md
@@ -8,33 +8,48 @@ disableToc: false
tags: ["setup", "debian", "linux"]
---
+
+## Supported Distros
+
+This Debian package has been tested on Ubuntu Bionic 18.04 LTS and Ubuntu Focal 20.04 LTS.
+
## Deployment
-To extract the `tar.gz` file, run `tar -xvzf monkey-island-debian.tar.gz`.
+1. Update your package list by running:
+ ```sh
+ sudo apt update
+ ```
+1. If you are using Ubuntu Focal 20.04, run the following commands to install
+ Python 3.7:
+ ```sh
+ sudo apt install software-properties-common
+ sudo add-apt-repository ppa:deadsnakes/ppa
+ sudo apt install python3.7 python3.7-dev
+ ```
+1. Extract the tarball by running:
+ ```sh
+ tar -xvzf monkey-island-debian.tgz
+ ```
+1. Install the Monkey Island Debian package:
+ ```sh
+ sudo dpkg -i monkey_island.deb # this might print errors
+ ```
+1. If, at this point, you receive dpkg errors that look like this:
-Once you've extracted the package, deploy it using run the following commands:
+ ```sh
+ dpkg: error processing package gc-monkey-island (--install):
+ dependency problems - leaving unconfigured
+ Errors were encountered while processing:
+ gc-monkey-island
+ ```
-```sh
-sudo apt update
-sudo dpkg -i monkey_island.deb # this might print errors
-```
+ It just means that not all dependencies were pre-installed on your system.
+ That's no problem! Just run the following command, which will install all
+ dependencies, and then install the Monkey Island:
-If, at this point, you receive dpkg printed errors that look like this:
-
-```sh
-dpkg: error processing package gc-monkey-island (--install):
- dependency problems - leaving unconfigured
-Errors were encountered while processing:
- gc-monkey-island
-```
-
-It just means that not all dependencies were pre-installed on your system.
-That's no problem! Just run the following command, which will install all
-dependencies, and then install the Monkey Island:
-
-```sh
-sudo apt install -f
-```
+ ```sh
+ sudo apt install -f
+ ```
## Troubleshooting
diff --git a/docs/content/setup/docker.md b/docs/content/setup/docker.md
index fb70347f2..14454bdc6 100644
--- a/docs/content/setup/docker.md
+++ b/docs/content/setup/docker.md
@@ -14,11 +14,11 @@ To extract the `tar.gz` file, run `tar -xvzf monkey-island-docker.tar.gz`.
Once you've extracted the container from the tar.gz file, run the following commands:
```sh
-sudo docker load -i dk.monkeyisland.1.9.0.tar
-sudo docker pull mongo
+sudo docker load -i dk.monkeyisland.1.10.0.tar
+sudo docker pull mongo:4.2
sudo mkdir -p /var/monkey-mongo/data/db
-sudo docker run --name monkey-mongo --network=host -v /var/monkey-mongo/data/db:/data/db -d mongo
-sudo docker run --name monkey-island --network=host -d guardicore/monkey-island:1.9.0
+sudo docker run --name monkey-mongo --network=host -v /var/monkey-mongo/data/db:/data/db -d mongo:4.2
+sudo docker run --name monkey-island --network=host -d guardicore/monkey-island:1.10.0
```
## Upgrading
diff --git a/docs/content/setup/vmware.md b/docs/content/setup/vmware.md
index 21522f820..c6519672b 100644
--- a/docs/content/setup/vmware.md
+++ b/docs/content/setup/vmware.md
@@ -16,8 +16,9 @@ tags: ["setup", "vmware"]
1. Log in to the machine with the following credentials:
1. Username: **monkeyuser**
1. Password: **Noon.Earth.Always**
-1. It's recommended you change the machine passwords by running the following
- commands: `sudo passwd monkeyuser`, `sudo passwd root`.
+1. For security purposes, it's recommended that you change the machine
+ passwords by running the following commands: `sudo passwd monkeyuser`, `sudo
+ passwd root`.
## OVA network modes
@@ -26,37 +27,43 @@ You can use the OVA in one of two modes:
1. In a network with the DHCP configured β In this case, the Monkey Island will
automatically query and receive an IP address from the network.
1. With a static IP address β In this case, you should log in to the VM console
- with the username `root` and the password `G3aJ9szrvkxTmfAG`. After logging
- in, edit the interfaces file by entering the following command in the
+ with the username `monkeyuser` and the password `Noon.Earth.Always`. After logging
+ in, edit the Netplan configuration by entering the following command in the
prompt:
```sh
- sudo nano /etc/network/interfaces
+ sudo nano /etc/netplan/00-installer-config.yaml
```
- Change the lines:
+ Make the following changes:
- ```sh
- auto ens160
- iface ens160 inet dhcp
+ ```diff
+ # This is the network config written by 'subiquity'
+ network:
+ ethernets:
+ ens160:
+ - dhcp4: true
+ + dhcp4: false
+ + addresses: [XXX.XXX.XXX.XXX/24]
+ + gateway4: YYY.YYY.YYY.YYY
+ + nameservers:
+ + addresses: [1.1.1.1]
+ version: 2
```
- to the following:
-
- ```sh
- auto ens160
- iface ens160 inet static
- address AAA.BBB.CCC.DDD
- netmask XXX.XXX.XXX.XXX
- gateway YYY.YYY.YYY.YYY
- ```
+ Replace `XXX.XXX.XXX.XXX` with the desired IP addess of the VM. Replace
+ `YYY.YYY.YYY.YYY` with the default gateway.
Save the changes then run the command:
```sh
- sudo ifdown ens160 && ifup ens160
+ sudo netplan apply
```
+ If this configuration does not suit your needs, see
+ https://netplan.io/examples/ for more information about how to configure
+ Netplan.
+
## Upgrading
Currently, there's no "upgrade-in-place" option when a new version is released.
diff --git a/docs/content/usage/file-checksums.md b/docs/content/usage/file-checksums.md
index 9c09f570f..b063550ed 100644
--- a/docs/content/usage/file-checksums.md
+++ b/docs/content/usage/file-checksums.md
@@ -35,6 +35,24 @@ $ sha256sum monkey-linux-64
## Latest version checksums
+| Filename | Type | Version | SHA256 |
+|------------------------------------------------------|-------------------|---------|--------------------------------------------------------------------|
+| monkey-windows-64.exe | Windows Agent | 1.10.0 | `3b499a4cf1a67a33a91c73b05884e4d6749e990e444fa1d2a3281af4db833fa1` |
+| monkey-windows-32.exe | Windows Agent | 1.10.0 | `8e891e90b11b97fbbef27f1408c1fcad486b19c612773f2d6a9edac5d4cdb47f` |
+| monkey-linux-64 | Linux Agent | 1.10.0 | `932f703510b6484c3824fc797f90f99722e38a7f8956cf6fa58fdecb3790ab93` |
+| monkey-linux-32 | Linux Agent | 1.10.0 | `a6de7d571051292b9db966afe025413dc20b214c4aab53e48d90d8e04264f4f5` |
+| infection_monkey_deb.tgz | Debian Package | 1.10.0 | `534d85c4abc78e2c86a74d8b88759b091b62077dd9e32f02eeb43d716d359ff6` |
+| infection_monkey_debzt.tgz | Debian Package | 1.10.0 | `bd01d8482f80990e6cc0ed654c07dbd80da71eebe3dd244365e9bc00f86b1c03` |
+| Monkey Island v1.10.0_3593_windows.exe | Windows Installer | 1.10.0 | `ebd2c5627d21dd8670def02c3a5a995f9e799ba567cf4caacd702654264ddf06` |
+| Monkey Island v1.10.0_3593_windowszt.exe | Windows Installer | 1.10.0 | `60aaf3b32e5d06c91fe0d4f1b950529517ac33796f67e9ccfef0e8ce1c5372d8` |
+| infection_monkey_docker_docker_20210326_171631.tgz | Docker | 1.10.0 | `e4f9c7c5aafe7e38b33d2927a9c0cf6a3ac27858d3d0e3f2252c2e91809a78db` |
+| infection_monkey_docker_dockerzt_20210326_172035.tgz | Docker | 1.10.0 | `248640e9eaa18e4c27f67237f0594d9533732f372ba4674d5d1bea43ab498cf5` |
+| monkey-island-vmware.ova | OVA | 1.10.0 | `3472ad4ae557ddad7d7db8fbbfcfd33c4f2d95d870b18fa4cab49af6b562009c` |
+| monkey-island-vmwarezt.ova | OVA | 1.10.0 | `3472ad4ae557ddad7d7db8fbbfcfd33c4f2d95d870b18fa4cab49af6b562009c` |
+
+
+## Older checksums
+
| Filename | Type | Version | SHA256 |
|------------------------------------------------------|-------------------|---------|--------------------------------------------------------------------|
| monkey-windows-64.exe | Windows Agent | 1.9.0 | `24622cb8dbabb0cf4b25ecd3c13800c72ec5b59b76895b737ece509640d4c068` |
@@ -49,12 +67,6 @@ $ sha256sum monkey-linux-64
| infection_monkey_docker_dockerzt_20200806_154742.tgz | Docker | 1.9.0 | `a84dbaad32ae42cc2d359ffbe062aec493a7253cf706a2d45f0d0b1c230f9348` |
| monkey-island-vmware.ova | OVA | 1.9.0 | `3861d46518e8a92e49992b26dbff9fe8e8a4ac5fd24d68e68b13e7fd3fa22247` |
| monkey-island-vmwarezt.ova | OVA | 1.9.0 | `03d356eb35e6515146f5bd798bb62cb15c56fcdf83a5281cf6cdc9b901586026` |
-
-
-## Older checksums
-
-| Filename | Type | Version | SHA256 |
-|------------------------------------------------------|-------------------|---------|--------------------------------------------------------------------|
| monkey-windows-64.exe | Windows Agent | 1.8.2 | `2e6a1cb5523d87ddfd48f75b10114617343fbac8125fa950ba7f00289b38b550` |
| monkey-windows-32.exe | Windows Agent | 1.8.2 | `86a7d7065e73b795e38f2033be0c53f3ac808cc67478aed794a7a6c89123979f` |
| monkey-linux-64 | Linux Agent | 1.8.2 | `4dce4a115d41b43adffc11672fae2164265f8902267f1355d02bebb802bd45c5` |
diff --git a/envs/monkey_zoo/blackbox/README.md b/envs/monkey_zoo/blackbox/README.md
index 30855b855..808a0a5cb 100644
--- a/envs/monkey_zoo/blackbox/README.md
+++ b/envs/monkey_zoo/blackbox/README.md
@@ -19,10 +19,10 @@ instead will just test performance of endpoints in already present island state.
Example run command:
-`monkey\envs\monkey_zoo\blackbox>python -m pytest -s --island=35.207.152.72:5000 test_blackbox.py`
+`monkey\monkey>python -m pytest -s --island=35.207.152.72:5000 ..\envs\monkey_zoo\blackbox\test_blackbox.py`
#### Running in PyCharm
-Configure a PyTest configuration with the additional arguments `-s --island=35.207.152.72`, and to run from
+Configure a PyTest configuration with the additional arguments `-s --island=35.207.152.72:5000`, and to run from
directory `monkey\envs\monkey_zoo\blackbox`.
### Running telemetry performance test
diff --git a/envs/monkey_zoo/blackbox/analyzers/analyzer.py b/envs/monkey_zoo/blackbox/analyzers/analyzer.py
index d6043feeb..13db46cb3 100644
--- a/envs/monkey_zoo/blackbox/analyzers/analyzer.py
+++ b/envs/monkey_zoo/blackbox/analyzers/analyzer.py
@@ -4,5 +4,5 @@ from abc import ABCMeta, abstractmethod
class Analyzer(object, metaclass=ABCMeta):
@abstractmethod
- def analyze_test_results(self):
+ def analyze_test_results(self) -> bool:
raise NotImplementedError()
diff --git a/envs/monkey_zoo/blackbox/analyzers/zerologon_analyzer.py b/envs/monkey_zoo/blackbox/analyzers/zerologon_analyzer.py
new file mode 100644
index 000000000..f5da3a2e1
--- /dev/null
+++ b/envs/monkey_zoo/blackbox/analyzers/zerologon_analyzer.py
@@ -0,0 +1,70 @@
+from typing import List
+from pprint import pformat
+
+import dpath.util
+
+from common.config_value_paths import USER_LIST_PATH, PASSWORD_LIST_PATH, NTLM_HASH_LIST_PATH, LM_HASH_LIST_PATH
+from envs.monkey_zoo.blackbox.analyzers.analyzer import Analyzer
+from envs.monkey_zoo.blackbox.analyzers.analyzer_log import AnalyzerLog
+from envs.monkey_zoo.blackbox.island_client.monkey_island_client import MonkeyIslandClient
+
+# Query for telemetry collection to see if password restoration was successful
+TELEM_QUERY = {'telem_category': 'exploit',
+ 'data.exploiter': 'ZerologonExploiter',
+ 'data.info.password_restored': True}
+
+
+class ZerologonAnalyzer(Analyzer):
+
+ def __init__(self, island_client: MonkeyIslandClient, expected_credentials: List[str]):
+ self.island_client = island_client
+ self.expected_credentials = expected_credentials
+ self.log = AnalyzerLog(self.__class__.__name__)
+
+ def analyze_test_results(self):
+ self.log.clear()
+ is_creds_gathered = self._analyze_credential_gathering()
+ is_creds_restored = self._analyze_credential_restore()
+ return is_creds_gathered and is_creds_restored
+
+ def _analyze_credential_gathering(self) -> bool:
+ config = self.island_client.get_config()
+ credentials_on_island = ZerologonAnalyzer._get_relevant_credentials(config)
+ return self._is_all_credentials_in_list(credentials_on_island)
+
+ @staticmethod
+ def _get_relevant_credentials(config: dict):
+ credentials_on_island = []
+ credentials_on_island.extend(dpath.util.get(config['configuration'], USER_LIST_PATH))
+ credentials_on_island.extend(dpath.util.get(config['configuration'], NTLM_HASH_LIST_PATH))
+ credentials_on_island.extend(dpath.util.get(config['configuration'], LM_HASH_LIST_PATH))
+ return credentials_on_island
+
+ def _is_all_credentials_in_list(self,
+ all_creds: List[str]) -> bool:
+ credentials_missing = [cred for cred in self.expected_credentials if cred not in all_creds]
+ self._log_creds_not_gathered(credentials_missing)
+ return not credentials_missing
+
+ def _log_creds_not_gathered(self, missing_creds: List[str]):
+ if not missing_creds:
+ self.log.add_entry("Zerologon exploiter gathered all credentials expected.")
+ else:
+ for cred in missing_creds:
+ self.log.add_entry(f"Credential Zerologon exploiter failed to gathered:{cred}.")
+
+ def _analyze_credential_restore(self) -> bool:
+ cred_restore_telems = self.island_client.find_telems_in_db(TELEM_QUERY)
+ self._log_credential_restore(cred_restore_telems)
+ return bool(cred_restore_telems)
+
+ def _log_credential_restore(self, telem_list: List[dict]):
+ if telem_list:
+ self.log.add_entry("Zerologon exploiter telemetry contains indicators that credentials "
+ "were successfully restored.")
+ else:
+ self.log.add_entry("Credential restore failed or credential restore "
+ "telemetry not found on the Monkey Island.")
+ self.log.add_entry(f"Query for credential restore telem: {pformat(TELEM_QUERY)}")
+
+
diff --git a/envs/monkey_zoo/blackbox/island_configs/__init__.py b/envs/monkey_zoo/blackbox/config_templates/__init__.py
similarity index 100%
rename from envs/monkey_zoo/blackbox/island_configs/__init__.py
rename to envs/monkey_zoo/blackbox/config_templates/__init__.py
diff --git a/envs/monkey_zoo/blackbox/island_configs/base_template.py b/envs/monkey_zoo/blackbox/config_templates/base_template.py
similarity index 85%
rename from envs/monkey_zoo/blackbox/island_configs/base_template.py
rename to envs/monkey_zoo/blackbox/config_templates/base_template.py
index 13a480286..9ebea6f1f 100644
--- a/envs/monkey_zoo/blackbox/island_configs/base_template.py
+++ b/envs/monkey_zoo/blackbox/config_templates/base_template.py
@@ -1,4 +1,4 @@
-from envs.monkey_zoo.blackbox.island_configs.config_template import ConfigTemplate
+from envs.monkey_zoo.blackbox.config_templates.config_template import ConfigTemplate
# Disables a lot of config values not required for a specific feature test
diff --git a/envs/monkey_zoo/blackbox/island_configs/config_template.py b/envs/monkey_zoo/blackbox/config_templates/config_template.py
similarity index 100%
rename from envs/monkey_zoo/blackbox/island_configs/config_template.py
rename to envs/monkey_zoo/blackbox/config_templates/config_template.py
diff --git a/envs/monkey_zoo/blackbox/config_templates/drupal.py b/envs/monkey_zoo/blackbox/config_templates/drupal.py
new file mode 100644
index 000000000..e202219dc
--- /dev/null
+++ b/envs/monkey_zoo/blackbox/config_templates/drupal.py
@@ -0,0 +1,14 @@
+from copy import copy
+
+from envs.monkey_zoo.blackbox.config_templates.base_template import BaseTemplate
+from envs.monkey_zoo.blackbox.config_templates.config_template import ConfigTemplate
+
+
+class Drupal(ConfigTemplate):
+ config_values = copy(BaseTemplate.config_values)
+
+ config_values.update({
+ "internal.classes.finger_classes": ["PingScanner", "HTTPFinger"],
+ "basic.exploiters.exploiter_classes": ["DrupalExploiter"],
+ "basic_network.scope.subnet_scan_list": ["10.2.2.28"]
+ })
diff --git a/envs/monkey_zoo/blackbox/island_configs/elastic.py b/envs/monkey_zoo/blackbox/config_templates/elastic.py
similarity index 53%
rename from envs/monkey_zoo/blackbox/island_configs/elastic.py
rename to envs/monkey_zoo/blackbox/config_templates/elastic.py
index 97598f718..56021e959 100644
--- a/envs/monkey_zoo/blackbox/island_configs/elastic.py
+++ b/envs/monkey_zoo/blackbox/config_templates/elastic.py
@@ -1,7 +1,7 @@
from copy import copy
-from envs.monkey_zoo.blackbox.island_configs.base_template import BaseTemplate
-from envs.monkey_zoo.blackbox.island_configs.config_template import ConfigTemplate
+from envs.monkey_zoo.blackbox.config_templates.base_template import BaseTemplate
+from envs.monkey_zoo.blackbox.config_templates.config_template import ConfigTemplate
class Elastic(ConfigTemplate):
@@ -10,5 +10,6 @@ class Elastic(ConfigTemplate):
config_values.update({
"basic.exploiters.exploiter_classes": ["ElasticGroovyExploiter"],
+ "internal.classes.finger_classes": ["PingScanner", "HTTPFinger", "ElasticFinger"],
"basic_network.scope.subnet_scan_list": ["10.2.2.4", "10.2.2.5"]
})
diff --git a/envs/monkey_zoo/blackbox/island_configs/hadoop.py b/envs/monkey_zoo/blackbox/config_templates/hadoop.py
similarity index 56%
rename from envs/monkey_zoo/blackbox/island_configs/hadoop.py
rename to envs/monkey_zoo/blackbox/config_templates/hadoop.py
index 8c42b8ee3..d136068e5 100644
--- a/envs/monkey_zoo/blackbox/island_configs/hadoop.py
+++ b/envs/monkey_zoo/blackbox/config_templates/hadoop.py
@@ -1,9 +1,10 @@
from copy import copy
-from envs.monkey_zoo.blackbox.island_configs.base_template import BaseTemplate
+from envs.monkey_zoo.blackbox.config_templates.base_template import BaseTemplate
+from envs.monkey_zoo.blackbox.config_templates.config_template import ConfigTemplate
-class Hadoop(BaseTemplate):
+class Hadoop(ConfigTemplate):
config_values = copy(BaseTemplate.config_values)
diff --git a/envs/monkey_zoo/blackbox/island_configs/mssql.py b/envs/monkey_zoo/blackbox/config_templates/mssql.py
similarity index 77%
rename from envs/monkey_zoo/blackbox/island_configs/mssql.py
rename to envs/monkey_zoo/blackbox/config_templates/mssql.py
index 5406494ee..003f9f8d3 100644
--- a/envs/monkey_zoo/blackbox/island_configs/mssql.py
+++ b/envs/monkey_zoo/blackbox/config_templates/mssql.py
@@ -1,9 +1,10 @@
from copy import copy
-from envs.monkey_zoo.blackbox.island_configs.base_template import BaseTemplate
+from envs.monkey_zoo.blackbox.config_templates.base_template import BaseTemplate
+from envs.monkey_zoo.blackbox.config_templates.config_template import ConfigTemplate
-class Mssql(BaseTemplate):
+class Mssql(ConfigTemplate):
config_values = copy(BaseTemplate.config_values)
config_values.update({
diff --git a/envs/monkey_zoo/blackbox/island_configs/performance.py b/envs/monkey_zoo/blackbox/config_templates/performance.py
similarity index 97%
rename from envs/monkey_zoo/blackbox/island_configs/performance.py
rename to envs/monkey_zoo/blackbox/config_templates/performance.py
index 3a9a48e9f..e9e34727d 100644
--- a/envs/monkey_zoo/blackbox/island_configs/performance.py
+++ b/envs/monkey_zoo/blackbox/config_templates/performance.py
@@ -1,4 +1,4 @@
-from envs.monkey_zoo.blackbox.island_configs.config_template import ConfigTemplate
+from envs.monkey_zoo.blackbox.config_templates.config_template import ConfigTemplate
class Performance(ConfigTemplate):
diff --git a/envs/monkey_zoo/blackbox/island_configs/shellshock.py b/envs/monkey_zoo/blackbox/config_templates/shellshock.py
similarity index 55%
rename from envs/monkey_zoo/blackbox/island_configs/shellshock.py
rename to envs/monkey_zoo/blackbox/config_templates/shellshock.py
index 27e0dc34d..71d968e0b 100644
--- a/envs/monkey_zoo/blackbox/island_configs/shellshock.py
+++ b/envs/monkey_zoo/blackbox/config_templates/shellshock.py
@@ -1,9 +1,10 @@
from copy import copy
-from envs.monkey_zoo.blackbox.island_configs.base_template import BaseTemplate
+from envs.monkey_zoo.blackbox.config_templates.base_template import BaseTemplate
+from envs.monkey_zoo.blackbox.config_templates.config_template import ConfigTemplate
-class ShellShock(BaseTemplate):
+class ShellShock(ConfigTemplate):
config_values = copy(BaseTemplate.config_values)
config_values.update({
diff --git a/envs/monkey_zoo/blackbox/island_configs/smb_mimikatz.py b/envs/monkey_zoo/blackbox/config_templates/smb_mimikatz.py
similarity index 80%
rename from envs/monkey_zoo/blackbox/island_configs/smb_mimikatz.py
rename to envs/monkey_zoo/blackbox/config_templates/smb_mimikatz.py
index aed4ee9c7..f563bc8d1 100644
--- a/envs/monkey_zoo/blackbox/island_configs/smb_mimikatz.py
+++ b/envs/monkey_zoo/blackbox/config_templates/smb_mimikatz.py
@@ -1,9 +1,10 @@
from copy import copy
-from envs.monkey_zoo.blackbox.island_configs.base_template import BaseTemplate
+from envs.monkey_zoo.blackbox.config_templates.base_template import BaseTemplate
+from envs.monkey_zoo.blackbox.config_templates.config_template import ConfigTemplate
-class SmbMimikatz(BaseTemplate):
+class SmbMimikatz(ConfigTemplate):
config_values = copy(BaseTemplate.config_values)
config_values.update({
diff --git a/envs/monkey_zoo/blackbox/island_configs/smb_pth.py b/envs/monkey_zoo/blackbox/config_templates/smb_pth.py
similarity index 81%
rename from envs/monkey_zoo/blackbox/island_configs/smb_pth.py
rename to envs/monkey_zoo/blackbox/config_templates/smb_pth.py
index 3bb92347e..edee4cdbd 100644
--- a/envs/monkey_zoo/blackbox/island_configs/smb_pth.py
+++ b/envs/monkey_zoo/blackbox/config_templates/smb_pth.py
@@ -1,9 +1,10 @@
from copy import copy
-from envs.monkey_zoo.blackbox.island_configs.base_template import BaseTemplate
+from envs.monkey_zoo.blackbox.config_templates.base_template import BaseTemplate
+from envs.monkey_zoo.blackbox.config_templates.config_template import ConfigTemplate
-class SmbPth(BaseTemplate):
+class SmbPth(ConfigTemplate):
config_values = copy(BaseTemplate.config_values)
config_value_list = {
diff --git a/envs/monkey_zoo/blackbox/island_configs/ssh.py b/envs/monkey_zoo/blackbox/config_templates/ssh.py
similarity index 74%
rename from envs/monkey_zoo/blackbox/island_configs/ssh.py
rename to envs/monkey_zoo/blackbox/config_templates/ssh.py
index f6a5b1762..90871e52b 100644
--- a/envs/monkey_zoo/blackbox/island_configs/ssh.py
+++ b/envs/monkey_zoo/blackbox/config_templates/ssh.py
@@ -1,8 +1,11 @@
-from envs.monkey_zoo.blackbox.island_configs.base_template import BaseTemplate
+from copy import copy
+
+from envs.monkey_zoo.blackbox.config_templates.base_template import BaseTemplate
+from envs.monkey_zoo.blackbox.config_templates.config_template import ConfigTemplate
-class Ssh(BaseTemplate):
- config_values = BaseTemplate.config_values
+class Ssh(ConfigTemplate):
+ config_values = copy(BaseTemplate.config_values)
config_values.update({
"basic.exploiters.exploiter_classes": ["SSHExploiter"],
diff --git a/envs/monkey_zoo/blackbox/config_templates/struts2.py b/envs/monkey_zoo/blackbox/config_templates/struts2.py
new file mode 100644
index 000000000..6eb399568
--- /dev/null
+++ b/envs/monkey_zoo/blackbox/config_templates/struts2.py
@@ -0,0 +1,14 @@
+from copy import copy
+
+from envs.monkey_zoo.blackbox.config_templates.base_template import BaseTemplate
+from envs.monkey_zoo.blackbox.config_templates.config_template import ConfigTemplate
+
+
+class Struts2(ConfigTemplate):
+
+ config_values = copy(BaseTemplate.config_values)
+
+ config_values.update({
+ "basic.exploiters.exploiter_classes": ["Struts2Exploiter"],
+ "basic_network.scope.subnet_scan_list": ["10.2.2.23", "10.2.2.24"]
+ })
diff --git a/envs/monkey_zoo/blackbox/island_configs/tunneling.py b/envs/monkey_zoo/blackbox/config_templates/tunneling.py
similarity index 77%
rename from envs/monkey_zoo/blackbox/island_configs/tunneling.py
rename to envs/monkey_zoo/blackbox/config_templates/tunneling.py
index 458b89794..ac46eb110 100644
--- a/envs/monkey_zoo/blackbox/island_configs/tunneling.py
+++ b/envs/monkey_zoo/blackbox/config_templates/tunneling.py
@@ -1,8 +1,11 @@
-from envs.monkey_zoo.blackbox.island_configs.base_template import BaseTemplate
+from copy import copy
+
+from envs.monkey_zoo.blackbox.config_templates.base_template import BaseTemplate
+from envs.monkey_zoo.blackbox.config_templates.config_template import ConfigTemplate
-class Tunneling(BaseTemplate):
- config_values = BaseTemplate.config_values
+class Tunneling(ConfigTemplate):
+ config_values = copy(BaseTemplate.config_values)
config_values.update({
"basic.exploiters.exploiter_classes": ["SmbExploiter",
@@ -13,6 +16,8 @@ class Tunneling(BaseTemplate):
"10.2.1.10",
"10.2.0.11",
"10.2.0.12"],
+ "basic_network.scope.depth": 3,
+ "internal.general.keep_tunnel_open_time": 180,
"basic.credentials.exploit_password_list": ["Password1!",
"3Q=(Ge(+&w]*",
"`))jU7L(w}",
diff --git a/envs/monkey_zoo/blackbox/config_templates/weblogic.py b/envs/monkey_zoo/blackbox/config_templates/weblogic.py
new file mode 100644
index 000000000..482f7abf9
--- /dev/null
+++ b/envs/monkey_zoo/blackbox/config_templates/weblogic.py
@@ -0,0 +1,14 @@
+from copy import copy
+
+from envs.monkey_zoo.blackbox.config_templates.base_template import BaseTemplate
+from envs.monkey_zoo.blackbox.config_templates.config_template import ConfigTemplate
+
+
+class Weblogic(ConfigTemplate):
+
+ config_values = copy(BaseTemplate.config_values)
+
+ config_values.update({
+ "basic.exploiters.exploiter_classes": ["WebLogicExploiter"],
+ "basic_network.scope.subnet_scan_list": ["10.2.2.18", "10.2.2.19"]
+ })
diff --git a/envs/monkey_zoo/blackbox/island_configs/wmi_mimikatz.py b/envs/monkey_zoo/blackbox/config_templates/wmi_mimikatz.py
similarity index 75%
rename from envs/monkey_zoo/blackbox/island_configs/wmi_mimikatz.py
rename to envs/monkey_zoo/blackbox/config_templates/wmi_mimikatz.py
index 73bd913cd..b6dbc0c88 100644
--- a/envs/monkey_zoo/blackbox/island_configs/wmi_mimikatz.py
+++ b/envs/monkey_zoo/blackbox/config_templates/wmi_mimikatz.py
@@ -1,8 +1,11 @@
-from envs.monkey_zoo.blackbox.island_configs.base_template import BaseTemplate
+from copy import copy
+
+from envs.monkey_zoo.blackbox.config_templates.base_template import BaseTemplate
+from envs.monkey_zoo.blackbox.config_templates.config_template import ConfigTemplate
-class WmiMimikatz(BaseTemplate):
- config_values = BaseTemplate.config_values
+class WmiMimikatz(ConfigTemplate):
+ config_values = copy(BaseTemplate.config_values)
config_values.update({
"basic.exploiters.exploiter_classes": ["WmiExploiter"],
diff --git a/envs/monkey_zoo/blackbox/config_templates/wmi_pth.py b/envs/monkey_zoo/blackbox/config_templates/wmi_pth.py
new file mode 100644
index 000000000..92746c3df
--- /dev/null
+++ b/envs/monkey_zoo/blackbox/config_templates/wmi_pth.py
@@ -0,0 +1,22 @@
+from copy import copy
+
+from envs.monkey_zoo.blackbox.config_templates.base_template import BaseTemplate
+from envs.monkey_zoo.blackbox.config_templates.config_template import ConfigTemplate
+
+
+class WmiPth(ConfigTemplate):
+ config_values = copy(BaseTemplate.config_values)
+
+ config_values.update(
+ {
+ "basic.exploiters.exploiter_classes": ["WmiExploiter"],
+ "basic_network.scope.subnet_scan_list": ["10.2.2.15"],
+ "basic.credentials.exploit_password_list": ["Password1!"],
+ "basic.credentials.exploit_user_list": ["Administrator", "m0nk3y", "user"],
+ "internal.classes.finger_classes": ["PingScanner", "HTTPFinger"],
+ "internal.exploits.exploit_ntlm_hash_list": [
+ "5da0889ea2081aa79f6852294cba4a5e",
+ "50c9987a6bf1ac59398df9f911122c9b",
+ ],
+ }
+ )
diff --git a/envs/monkey_zoo/blackbox/config_templates/zerologon.py b/envs/monkey_zoo/blackbox/config_templates/zerologon.py
new file mode 100644
index 000000000..28afa281f
--- /dev/null
+++ b/envs/monkey_zoo/blackbox/config_templates/zerologon.py
@@ -0,0 +1,16 @@
+from copy import copy
+
+from envs.monkey_zoo.blackbox.config_templates.base_template import BaseTemplate
+from envs.monkey_zoo.blackbox.config_templates.config_template import ConfigTemplate
+
+
+class Zerologon(ConfigTemplate):
+
+ config_values = copy(BaseTemplate.config_values)
+
+ config_values.update({
+ "basic.exploiters.exploiter_classes": ["ZerologonExploiter"],
+ "basic_network.scope.subnet_scan_list": ["10.2.2.25"],
+ # Empty list to make sure ZeroLogon adds "Administrator" username
+ "basic.credentials.exploit_user_list": []
+ })
diff --git a/envs/monkey_zoo/blackbox/island_client/island_config_parser.py b/envs/monkey_zoo/blackbox/island_client/island_config_parser.py
index d9e81957e..5b7211f87 100644
--- a/envs/monkey_zoo/blackbox/island_client/island_config_parser.py
+++ b/envs/monkey_zoo/blackbox/island_client/island_config_parser.py
@@ -4,7 +4,7 @@ import dpath.util
from typing_extensions import Type
from envs.monkey_zoo.blackbox.island_client.monkey_island_client import MonkeyIslandClient
-from envs.monkey_zoo.blackbox.island_configs.config_template import ConfigTemplate
+from envs.monkey_zoo.blackbox.config_templates.config_template import ConfigTemplate
class IslandConfigParser:
diff --git a/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py b/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py
index 050cfe04c..304996ebd 100644
--- a/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py
+++ b/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py
@@ -1,6 +1,7 @@
import json
import logging
from time import sleep
+from typing import Union
from bson import json_util
@@ -8,6 +9,7 @@ from envs.monkey_zoo.blackbox.island_client.monkey_island_requests import Monkey
SLEEP_BETWEEN_REQUESTS_SECONDS = 0.5
MONKEY_TEST_ENDPOINT = 'api/test/monkey'
+TELEMETRY_TEST_ENDPOINT = 'api/test/telemetry'
LOG_TEST_ENDPOINT = 'api/test/log'
LOGGER = logging.getLogger(__name__)
@@ -67,6 +69,13 @@ class MonkeyIslandClient(object):
MonkeyIslandClient.form_find_query_for_request(query))
return MonkeyIslandClient.get_test_query_results(response)
+ def find_telems_in_db(self, query: dict):
+ if query is None:
+ raise TypeError
+ response = self.requests.get(TELEMETRY_TEST_ENDPOINT,
+ MonkeyIslandClient.form_find_query_for_request(query))
+ return MonkeyIslandClient.get_test_query_results(response)
+
def get_all_monkeys_from_db(self):
response = self.requests.get(MONKEY_TEST_ENDPOINT,
MonkeyIslandClient.form_find_query_for_request(None))
@@ -78,7 +87,7 @@ class MonkeyIslandClient(object):
return MonkeyIslandClient.get_test_query_results(response)
@staticmethod
- def form_find_query_for_request(query):
+ def form_find_query_for_request(query: Union[dict, None]) -> dict:
return {'find_query': json_util.dumps(query)}
@staticmethod
diff --git a/envs/monkey_zoo/blackbox/island_configs/struts2.py b/envs/monkey_zoo/blackbox/island_configs/struts2.py
deleted file mode 100644
index e88c0899f..000000000
--- a/envs/monkey_zoo/blackbox/island_configs/struts2.py
+++ /dev/null
@@ -1,11 +0,0 @@
-from envs.monkey_zoo.blackbox.island_configs.base_template import BaseTemplate
-
-
-class Struts2(BaseTemplate):
-
- config_values = BaseTemplate.config_values
-
- config_values.update({
- "basic.exploiters.exploiter_classes": ["Struts2Exploiter"],
- "basic_network.scope.subnet_scan_list": ["10.2.2.23", "10.2.2.24"]
- })
diff --git a/envs/monkey_zoo/blackbox/island_configs/weblogic.py b/envs/monkey_zoo/blackbox/island_configs/weblogic.py
deleted file mode 100644
index 433067cb9..000000000
--- a/envs/monkey_zoo/blackbox/island_configs/weblogic.py
+++ /dev/null
@@ -1,11 +0,0 @@
-from envs.monkey_zoo.blackbox.island_configs.base_template import BaseTemplate
-
-
-class Weblogic(BaseTemplate):
-
- config_values = BaseTemplate.config_values
-
- config_values.update({
- "basic.exploiters.exploiter_classes": ["WebLogicExploiter"],
- "basic_network.scope.subnet_scan_list": ["10.2.2.18", "10.2.2.19"]
- })
diff --git a/envs/monkey_zoo/blackbox/island_configs/wmi_pth.py b/envs/monkey_zoo/blackbox/island_configs/wmi_pth.py
deleted file mode 100644
index dcb735c78..000000000
--- a/envs/monkey_zoo/blackbox/island_configs/wmi_pth.py
+++ /dev/null
@@ -1,18 +0,0 @@
-from envs.monkey_zoo.blackbox.island_configs.base_template import BaseTemplate
-
-
-class WmiPth(BaseTemplate):
- config_values = BaseTemplate.config_values
-
- config_values.update({
- "basic.exploiters.exploiter_classes": ["WmiExploiter"],
- "basic_network.scope.subnet_scan_list": ["10.2.2.15"],
- "basic.credentials.exploit_password_list": ["Password1!"],
- "basic.credentials.exploit_user_list": ["Administrator",
- "m0nk3y",
- "user"],
- "internal.classes.finger_classes": ["PingScanner",
- "HTTPFinger"],
- "internal.classes.exploits.exploit_ntlm_hash_list": ["5da0889ea2081aa79f6852294cba4a5e",
- "50c9987a6bf1ac59398df9f911122c9b"]
- })
diff --git a/envs/monkey_zoo/blackbox/test_blackbox.py b/envs/monkey_zoo/blackbox/test_blackbox.py
index e5a77ef45..bfcf32fba 100644
--- a/envs/monkey_zoo/blackbox/test_blackbox.py
+++ b/envs/monkey_zoo/blackbox/test_blackbox.py
@@ -7,24 +7,27 @@ from typing_extensions import Type
from envs.monkey_zoo.blackbox.analyzers.communication_analyzer import \
CommunicationAnalyzer
+from envs.monkey_zoo.blackbox.analyzers.zerologon_analyzer import ZerologonAnalyzer
from envs.monkey_zoo.blackbox.island_client.island_config_parser import \
IslandConfigParser
from envs.monkey_zoo.blackbox.island_client.monkey_island_client import \
MonkeyIslandClient
-from envs.monkey_zoo.blackbox.island_configs.config_template import ConfigTemplate
-from envs.monkey_zoo.blackbox.island_configs.elastic import Elastic
-from envs.monkey_zoo.blackbox.island_configs.hadoop import Hadoop
-from envs.monkey_zoo.blackbox.island_configs.mssql import Mssql
-from envs.monkey_zoo.blackbox.island_configs.performance import Performance
-from envs.monkey_zoo.blackbox.island_configs.shellshock import ShellShock
-from envs.monkey_zoo.blackbox.island_configs.smb_mimikatz import SmbMimikatz
-from envs.monkey_zoo.blackbox.island_configs.smb_pth import SmbPth
-from envs.monkey_zoo.blackbox.island_configs.ssh import Ssh
-from envs.monkey_zoo.blackbox.island_configs.struts2 import Struts2
-from envs.monkey_zoo.blackbox.island_configs.tunneling import Tunneling
-from envs.monkey_zoo.blackbox.island_configs.weblogic import Weblogic
-from envs.monkey_zoo.blackbox.island_configs.wmi_mimikatz import WmiMimikatz
-from envs.monkey_zoo.blackbox.island_configs.wmi_pth import WmiPth
+from envs.monkey_zoo.blackbox.config_templates.config_template import ConfigTemplate
+from envs.monkey_zoo.blackbox.config_templates.drupal import Drupal
+from envs.monkey_zoo.blackbox.config_templates.elastic import Elastic
+from envs.monkey_zoo.blackbox.config_templates.hadoop import Hadoop
+from envs.monkey_zoo.blackbox.config_templates.mssql import Mssql
+from envs.monkey_zoo.blackbox.config_templates.performance import Performance
+from envs.monkey_zoo.blackbox.config_templates.shellshock import ShellShock
+from envs.monkey_zoo.blackbox.config_templates.smb_mimikatz import SmbMimikatz
+from envs.monkey_zoo.blackbox.config_templates.smb_pth import SmbPth
+from envs.monkey_zoo.blackbox.config_templates.ssh import Ssh
+from envs.monkey_zoo.blackbox.config_templates.struts2 import Struts2
+from envs.monkey_zoo.blackbox.config_templates.tunneling import Tunneling
+from envs.monkey_zoo.blackbox.config_templates.weblogic import Weblogic
+from envs.monkey_zoo.blackbox.config_templates.wmi_mimikatz import WmiMimikatz
+from envs.monkey_zoo.blackbox.config_templates.wmi_pth import WmiPth
+from envs.monkey_zoo.blackbox.config_templates.zerologon import Zerologon
from envs.monkey_zoo.blackbox.log_handlers.test_logs_handler import \
TestLogsHandler
from envs.monkey_zoo.blackbox.tests.exploitation import ExploitationTest
@@ -44,8 +47,10 @@ DEFAULT_TIMEOUT_SECONDS = 5*60
MACHINE_BOOTUP_WAIT_SECONDS = 30
GCP_TEST_MACHINE_LIST = ['sshkeys-11', 'sshkeys-12', 'elastic-4', 'elastic-5', 'hadoop-2', 'hadoop-3', 'mssql-16',
'mimikatz-14', 'mimikatz-15', 'struts2-23', 'struts2-24', 'tunneling-9', 'tunneling-10',
- 'tunneling-11', 'tunneling-12', 'weblogic-18', 'weblogic-19', 'shellshock-8', 'zerologon-25']
+ 'tunneling-11', 'tunneling-12', 'weblogic-18', 'weblogic-19', 'shellshock-8', 'zerologon-25',
+ 'drupal-28']
LOG_DIR_PATH = "./logs"
+logging.basicConfig(level=logging.INFO)
LOGGER = logging.getLogger(__name__)
@@ -138,6 +143,9 @@ class TestMonkeyBlackbox:
def test_smb_pth(self, island_client):
TestMonkeyBlackbox.run_exploitation_test(island_client, SmbPth, "SMB_PTH")
+ def test_drupal_exploiter(self, island_client):
+ TestMonkeyBlackbox.run_exploitation_test(island_client, Drupal, "Drupal_exploiter")
+
def test_elastic_exploiter(self, island_client):
TestMonkeyBlackbox.run_exploitation_test(island_client, Elastic, "Elastic_exploiter")
@@ -159,6 +167,22 @@ class TestMonkeyBlackbox:
def test_wmi_pth(self, island_client):
TestMonkeyBlackbox.run_exploitation_test(island_client, WmiPth, "WMI_PTH")
+ def test_zerologon_exploiter(self, island_client):
+ test_name = "Zerologon_exploiter"
+ expected_creds = ["Administrator",
+ "aad3b435b51404eeaad3b435b51404ee",
+ "2864b62ea4496934a5d6e86f50b834a5"]
+ raw_config = IslandConfigParser.get_raw_config(Zerologon, island_client)
+ analyzer = ZerologonAnalyzer(island_client, expected_creds)
+ log_handler = TestLogsHandler(test_name, island_client, TestMonkeyBlackbox.get_log_dir_path())
+ ExploitationTest(
+ name=test_name,
+ island_client=island_client,
+ raw_config=raw_config,
+ analyzers=[analyzer],
+ timeout=DEFAULT_TIMEOUT_SECONDS,
+ log_handler=log_handler).run()
+
@pytest.mark.skip(reason="Perfomance test that creates env from fake telemetries is faster, use that instead.")
def test_report_generation_performance(self, island_client, quick_performance_tests):
"""
diff --git a/envs/monkey_zoo/blackbox/utils/README.md b/envs/monkey_zoo/blackbox/utils/README.md
new file mode 100644
index 000000000..69a6b8930
--- /dev/null
+++ b/envs/monkey_zoo/blackbox/utils/README.md
@@ -0,0 +1,13 @@
+# BlackBox utility scripts
+
+## Config generation script
+
+This script is used to generate config files for manual tests.
+Config file will be generated according to the templates in `envs/monkey_zoo/blackbox/config_templates`.
+
+1. Reset the Island config to contain default configuration.
+2. Run `envs/monkey_zoo/blackbox/utils/config_generation_script.py island_ip:5000` to populate
+`envs/monkey_zoo/blackbox/utils/generated_configs` directory with configuration files.
+
+!! It's important to target the Island you'll be testing, because configs contain Island's IPs
+in the configuration !!
diff --git a/envs/monkey_zoo/blackbox/utils/config_generation_script.py b/envs/monkey_zoo/blackbox/utils/config_generation_script.py
new file mode 100644
index 000000000..603e9fe4d
--- /dev/null
+++ b/envs/monkey_zoo/blackbox/utils/config_generation_script.py
@@ -0,0 +1,78 @@
+import argparse
+import pathlib
+from typing import Type
+
+from envs.monkey_zoo.blackbox.config_templates.config_template import ConfigTemplate
+from envs.monkey_zoo.blackbox.config_templates.drupal import Drupal
+from envs.monkey_zoo.blackbox.config_templates.elastic import Elastic
+from envs.monkey_zoo.blackbox.config_templates.hadoop import Hadoop
+from envs.monkey_zoo.blackbox.config_templates.mssql import Mssql
+from envs.monkey_zoo.blackbox.config_templates.performance import Performance
+from envs.monkey_zoo.blackbox.config_templates.shellshock import ShellShock
+from envs.monkey_zoo.blackbox.config_templates.smb_mimikatz import SmbMimikatz
+from envs.monkey_zoo.blackbox.config_templates.smb_pth import SmbPth
+from envs.monkey_zoo.blackbox.config_templates.ssh import Ssh
+from envs.monkey_zoo.blackbox.config_templates.struts2 import Struts2
+from envs.monkey_zoo.blackbox.config_templates.tunneling import Tunneling
+from envs.monkey_zoo.blackbox.config_templates.weblogic import Weblogic
+from envs.monkey_zoo.blackbox.config_templates.wmi_mimikatz import WmiMimikatz
+from envs.monkey_zoo.blackbox.config_templates.wmi_pth import WmiPth
+from envs.monkey_zoo.blackbox.config_templates.zerologon import Zerologon
+from envs.monkey_zoo.blackbox.island_client.island_config_parser import (
+ IslandConfigParser,
+)
+from envs.monkey_zoo.blackbox.island_client.monkey_island_client import (
+ MonkeyIslandClient,
+)
+
+DST_DIR_NAME = "generated_configs"
+DST_DIR_PATH = pathlib.Path(pathlib.Path(__file__).parent.absolute(), DST_DIR_NAME)
+
+parser = argparse.ArgumentParser(description="Generate config files.")
+parser.add_argument(
+ "island_ip",
+ metavar="IP:PORT",
+ help="Island endpoint. Example: 123.123.123.123:5000",
+)
+
+args = parser.parse_args()
+island_client = MonkeyIslandClient(args.island_ip)
+
+
+CONFIG_TEMPLATES = [
+ Elastic,
+ Hadoop,
+ Mssql,
+ Performance,
+ ShellShock,
+ SmbMimikatz,
+ SmbPth,
+ Ssh,
+ Struts2,
+ Tunneling,
+ Weblogic,
+ WmiMimikatz,
+ WmiPth,
+ Zerologon,
+ Drupal,
+]
+
+
+def generate_templates():
+ for template in CONFIG_TEMPLATES:
+ save_template_as_config(template)
+
+
+def save_template_as_config(template: Type[ConfigTemplate]):
+ file_path = pathlib.Path(DST_DIR_PATH, f"{template.__name__}.conf")
+ file_contents = IslandConfigParser.get_raw_config(template, island_client)
+ save_to_file(file_path, file_contents)
+
+
+def save_to_file(file_path, contents):
+ with open(file_path, "w") as file:
+ file.write(contents)
+
+
+if __name__ == "__main__":
+ generate_templates()
diff --git a/envs/monkey_zoo/blackbox/utils/generated_configs/.gitignore b/envs/monkey_zoo/blackbox/utils/generated_configs/.gitignore
new file mode 100644
index 000000000..9c558e357
--- /dev/null
+++ b/envs/monkey_zoo/blackbox/utils/generated_configs/.gitignore
@@ -0,0 +1 @@
+.
diff --git a/envs/monkey_zoo/terraform/images.tf b/envs/monkey_zoo/terraform/images.tf
index a402842b8..866a4f174 100644
--- a/envs/monkey_zoo/terraform/images.tf
+++ b/envs/monkey_zoo/terraform/images.tf
@@ -89,6 +89,10 @@ data "google_compute_image" "zerologon-25" {
name = "zerologon-25"
project = local.monkeyzoo_project
}
+data "google_compute_image" "drupal-28" {
+ name = "drupal-28"
+ project = local.monkeyzoo_project
+}
data "google_compute_image" "island-linux-250" {
name = "island-linux-250"
project = local.monkeyzoo_project
diff --git a/envs/monkey_zoo/terraform/monkey_zoo.tf b/envs/monkey_zoo/terraform/monkey_zoo.tf
index 6c3a49b2e..5eabc160b 100644
--- a/envs/monkey_zoo/terraform/monkey_zoo.tf
+++ b/envs/monkey_zoo/terraform/monkey_zoo.tf
@@ -447,6 +447,21 @@ resource "google_compute_instance_from_template" "zerologon-25" {
}
}
+resource "google_compute_instance_from_template" "drupal-28" {
+ name = "${local.resource_prefix}drupal-28"
+ source_instance_template = local.default_windows
+ boot_disk{
+ initialize_params {
+ image = data.google_compute_image.drupal-28.self_link
+ }
+ auto_delete = true
+ }
+ network_interface {
+ subnetwork="${local.resource_prefix}monkeyzoo-main"
+ network_ip="10.2.2.28"
+ }
+}
+
resource "google_compute_instance_from_template" "island-linux-250" {
name = "${local.resource_prefix}island-linux-250"
machine_type = "n1-standard-2"
diff --git a/monkey/common/cloud/scoutsuite b/monkey/common/cloud/scoutsuite
deleted file mode 160000
index 9de1e78ba..000000000
--- a/monkey/common/cloud/scoutsuite
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 9de1e78ba475f925c66c5b645564ec9eb08e2309
diff --git a/monkey/monkey_island/cc/services/config_schema/config_value_paths.py b/monkey/common/config_value_paths.py
similarity index 100%
rename from monkey/monkey_island/cc/services/config_schema/config_value_paths.py
rename to monkey/common/config_value_paths.py
diff --git a/monkey/common/utils/code_utils.py b/monkey/common/utils/code_utils.py
index 214e6d108..d9ad573b1 100644
--- a/monkey/common/utils/code_utils.py
+++ b/monkey/common/utils/code_utils.py
@@ -1,5 +1,8 @@
# abstract, static method decorator
# noinspection PyPep8Naming
+from typing import List
+
+
class abstractstatic(staticmethod):
__slots__ = ()
@@ -8,3 +11,10 @@ class abstractstatic(staticmethod):
function.__isabstractmethod__ = True
__isabstractmethod__ = True
+
+
+def get_value_from_dict(dict_data: dict, path: List[str]):
+ current_data = dict_data
+ for key in path:
+ current_data = current_data[key]
+ return current_data
diff --git a/monkey/common/version.py b/monkey/common/version.py
index c4e38239e..5e8dd4bf4 100644
--- a/monkey/common/version.py
+++ b/monkey/common/version.py
@@ -3,7 +3,7 @@ import argparse
from pathlib import Path
MAJOR = "1"
-MINOR = "9"
+MINOR = "10"
PATCH = "0"
build_file_path = Path(__file__).parent.joinpath("BUILD")
with open(build_file_path, "r") as build_file:
diff --git a/monkey/infection_monkey/dropper.py b/monkey/infection_monkey/dropper.py
index cb7be181d..9b374c9f1 100644
--- a/monkey/infection_monkey/dropper.py
+++ b/monkey/infection_monkey/dropper.py
@@ -134,7 +134,9 @@ class MonkeyDrops(object):
'monkey_commandline': inner_monkey_cmdline}
monkey_process = subprocess.Popen(monkey_cmdline, shell=True,
- stdin=None, stdout=None, stderr=None,
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
close_fds=True, creationflags=DETACHED_PROCESS)
LOG.info("Executed monkey process (PID=%d) with command line: %s",
@@ -145,6 +147,8 @@ class MonkeyDrops(object):
LOG.warning("Seems like monkey died too soon")
def cleanup(self):
+ LOG.info("Cleaning up the dropper")
+
try:
if (self._config['source_path'].lower() != self._config['destination_path'].lower()) and \
os.path.exists(self._config['source_path']) and \
@@ -166,5 +170,7 @@ class MonkeyDrops(object):
LOG.debug("Dropper source file '%s' is marked for deletion on next boot",
self._config['source_path'])
T1106Telem(ScanStatus.USED, UsageEnum.DROPPER_WINAPI).send()
+
+ LOG.info("Dropper cleanup complete")
except AttributeError:
LOG.error("Invalid configuration options. Failing")
diff --git a/monkey/infection_monkey/exploit/drupal.py b/monkey/infection_monkey/exploit/drupal.py
index 5872f4703..04b0ce431 100644
--- a/monkey/infection_monkey/exploit/drupal.py
+++ b/monkey/infection_monkey/exploit/drupal.py
@@ -36,6 +36,7 @@ class DrupalExploiter(WebRCE):
exploit_config = super(DrupalExploiter, self).get_exploit_config()
exploit_config['url_extensions'] = ['node/', # In Linux, no path is added
'drupal/node/'] # However, Bitnami installations are under /drupal
+ exploit_config['dropper'] = True
return exploit_config
def add_vulnerable_urls(self, potential_urls, stop_checking=False):
diff --git a/monkey/infection_monkey/monkey.py b/monkey/infection_monkey/monkey.py
index f5af73d43..3a5c5619f 100644
--- a/monkey/infection_monkey/monkey.py
+++ b/monkey/infection_monkey/monkey.py
@@ -252,9 +252,12 @@ class InfectionMonkey(object):
def collect_system_info_if_configured(self):
LOG.debug("Calling for system info collection")
- system_info_collector = SystemInfoCollector()
- system_info = system_info_collector.get_info()
- SystemInfoTelem(system_info).send()
+ try:
+ system_info_collector = SystemInfoCollector()
+ system_info = system_info_collector.get_info()
+ SystemInfoTelem(system_info).send()
+ except Exception as e:
+ LOG.exception(f"Exception encountered during system info collection: {str(e)}")
def shutdown_by_not_alive_config(self):
if not WormConfiguration.alive:
diff --git a/monkey/infection_monkey/monkey.spec b/monkey/infection_monkey/monkey.spec
index 51bd4bb83..6248f4d2b 100644
--- a/monkey/infection_monkey/monkey.spec
+++ b/monkey/infection_monkey/monkey.spec
@@ -1,24 +1,24 @@
# -*- mode: python -*-
import os
-import sys
import platform
-
+import sys
__author__ = 'itay.mizeretz'
+from PyInstaller.utils.hooks import collect_data_files
+
block_cipher = None
def main():
+ print(collect_data_files('policyuniverse'))
a = Analysis(['main.py'],
pathex=['..'],
hiddenimports=get_hidden_imports(),
hookspath=['./pyinstaller_hooks'],
runtime_hooks=None,
binaries=None,
- datas=[
- ("../common/BUILD", "/common")
- ],
+ datas=[("../common/BUILD", "/common")],
excludes=None,
win_no_prefer_redirects=None,
win_private_assemblies=None,
@@ -48,7 +48,7 @@ def is_windows():
def is_32_bit():
- return sys.maxsize <= 2**32
+ return sys.maxsize <= 2 ** 32
def get_bin_folder():
@@ -79,7 +79,10 @@ def get_linux_only_binaries():
def get_hidden_imports():
- return ['_cffi_backend', 'queue', '_mssql'] if is_windows() else ['_cffi_backend','_mssql']
+ imports = ['_cffi_backend', '_mssql']
+ if is_windows():
+ imports.append('queue')
+ return imports
def get_sc_binaries():
@@ -94,15 +97,15 @@ def get_traceroute_binaries():
def get_monkey_filename():
name = 'monkey-'
if is_windows():
- name = name+"windows-"
+ name = name + "windows-"
else:
- name = name+"linux-"
+ name = name + "linux-"
if is_32_bit():
- name = name+"32"
+ name = name + "32"
else:
- name = name+"64"
+ name = name + "64"
if is_windows():
- name = name+".exe"
+ name = name + ".exe"
return name
diff --git a/monkey/infection_monkey/network/httpfinger.py b/monkey/infection_monkey/network/httpfinger.py
index 26e362a5f..86c48cbde 100644
--- a/monkey/infection_monkey/network/httpfinger.py
+++ b/monkey/infection_monkey/network/httpfinger.py
@@ -43,8 +43,8 @@ class HTTPFinger(HostFinger):
LOG.info("Port %d is open on host %s " % (port[0], host))
break # https will be the same on the same port
except Timeout:
- pass
+ LOG.debug(f"Timout while requesting headers from {url}")
except ConnectionError: # Someone doesn't like us
- pass
+ LOG.debug(f"Connection error while requesting headers from {url}")
return True
diff --git a/monkey/infection_monkey/post_breach/actions/users_custom_pba.py b/monkey/infection_monkey/post_breach/actions/users_custom_pba.py
index 175d6b215..dd723c14d 100644
--- a/monkey/infection_monkey/post_breach/actions/users_custom_pba.py
+++ b/monkey/infection_monkey/post_breach/actions/users_custom_pba.py
@@ -15,10 +15,6 @@ LOG = logging.getLogger(__name__)
__author__ = 'VakarisZ'
-# Default commands for executing PBA file and then removing it
-DEFAULT_LINUX_COMMAND = "chmod +x {0} ; {0} ; rm {0}"
-DEFAULT_WINDOWS_COMMAND = "{0} & del {0}"
-
DIR_CHANGE_WINDOWS = 'cd %s & '
DIR_CHANGE_LINUX = 'cd %s ; '
@@ -31,30 +27,23 @@ class UsersPBA(PBA):
def __init__(self):
super(UsersPBA, self).__init__(POST_BREACH_FILE_EXECUTION)
self.filename = ''
+
if not is_windows_os():
# Add linux commands to PBA's
if WormConfiguration.PBA_linux_filename:
+ self.filename = WormConfiguration.PBA_linux_filename
if WormConfiguration.custom_PBA_linux_cmd:
# Add change dir command, because user will try to access his file
self.command = (DIR_CHANGE_LINUX % get_monkey_dir_path()) + WormConfiguration.custom_PBA_linux_cmd
- self.filename = WormConfiguration.PBA_linux_filename
- else:
- file_path = os.path.join(get_monkey_dir_path(), WormConfiguration.PBA_linux_filename)
- self.command = DEFAULT_LINUX_COMMAND.format(file_path)
- self.filename = WormConfiguration.PBA_linux_filename
elif WormConfiguration.custom_PBA_linux_cmd:
self.command = WormConfiguration.custom_PBA_linux_cmd
else:
# Add windows commands to PBA's
if WormConfiguration.PBA_windows_filename:
+ self.filename = WormConfiguration.PBA_windows_filename
if WormConfiguration.custom_PBA_windows_cmd:
# Add change dir command, because user will try to access his file
self.command = (DIR_CHANGE_WINDOWS % get_monkey_dir_path()) + WormConfiguration.custom_PBA_windows_cmd
- self.filename = WormConfiguration.PBA_windows_filename
- else:
- file_path = os.path.join(get_monkey_dir_path(), WormConfiguration.PBA_windows_filename)
- self.command = DEFAULT_WINDOWS_COMMAND.format(file_path)
- self.filename = WormConfiguration.PBA_windows_filename
elif WormConfiguration.custom_PBA_windows_cmd:
self.command = WormConfiguration.custom_PBA_windows_cmd
diff --git a/monkey/infection_monkey/post_breach/tests/actions/test_users_custom_pba.py b/monkey/infection_monkey/post_breach/tests/actions/test_users_custom_pba.py
new file mode 100644
index 000000000..83af6e00a
--- /dev/null
+++ b/monkey/infection_monkey/post_breach/tests/actions/test_users_custom_pba.py
@@ -0,0 +1,152 @@
+import pytest
+
+from infection_monkey.post_breach.actions.users_custom_pba import (
+ DIR_CHANGE_LINUX, DIR_CHANGE_WINDOWS, UsersPBA)
+
+MONKEY_DIR_PATH = "/dir/to/monkey/"
+CUSTOM_LINUX_CMD = "command-for-linux"
+CUSTOM_LINUX_FILENAME = "filename-for-linux"
+CUSTOM_WINDOWS_CMD = "command-for-windows"
+CUSTOM_WINDOWS_FILENAME = "filename-for-windows"
+
+
+@pytest.fixture
+def fake_monkey_dir_path(monkeypatch):
+ monkeypatch.setattr(
+ "infection_monkey.post_breach.actions.users_custom_pba.get_monkey_dir_path",
+ lambda: MONKEY_DIR_PATH,
+ )
+
+
+@pytest.fixture
+def set_os_linux(monkeypatch):
+ monkeypatch.setattr(
+ "infection_monkey.post_breach.actions.users_custom_pba.is_windows_os",
+ lambda: False,
+ )
+
+
+@pytest.fixture
+def set_os_windows(monkeypatch):
+ monkeypatch.setattr(
+ "infection_monkey.post_breach.actions.users_custom_pba.is_windows_os",
+ lambda: True,
+ )
+
+
+@pytest.fixture
+def mock_UsersPBA_linux_custom_file_and_cmd(
+ set_os_linux, fake_monkey_dir_path, monkeypatch
+):
+ monkeypatch.setattr(
+ "infection_monkey.config.WormConfiguration.custom_PBA_linux_cmd",
+ CUSTOM_LINUX_CMD,
+ )
+ monkeypatch.setattr(
+ "infection_monkey.config.WormConfiguration.PBA_linux_filename",
+ CUSTOM_LINUX_FILENAME,
+ )
+ return UsersPBA()
+
+
+def test_command_linux_custom_file_and_cmd(
+ mock_UsersPBA_linux_custom_file_and_cmd,
+):
+ expected_command = f"cd {MONKEY_DIR_PATH} ; {CUSTOM_LINUX_CMD}"
+ assert mock_UsersPBA_linux_custom_file_and_cmd.command == expected_command
+
+
+@pytest.fixture
+def mock_UsersPBA_windows_custom_file_and_cmd(
+ set_os_windows, fake_monkey_dir_path, monkeypatch
+):
+ monkeypatch.setattr(
+ "infection_monkey.config.WormConfiguration.custom_PBA_windows_cmd",
+ CUSTOM_WINDOWS_CMD,
+ )
+ monkeypatch.setattr(
+ "infection_monkey.config.WormConfiguration.PBA_windows_filename",
+ CUSTOM_WINDOWS_FILENAME,
+ )
+ return UsersPBA()
+
+
+def test_command_windows_custom_file_and_cmd(
+ mock_UsersPBA_windows_custom_file_and_cmd,
+):
+ expected_command = f"cd {MONKEY_DIR_PATH} & {CUSTOM_WINDOWS_CMD}"
+ assert mock_UsersPBA_windows_custom_file_and_cmd.command == expected_command
+
+
+@pytest.fixture
+def mock_UsersPBA_linux_custom_file(set_os_linux, fake_monkey_dir_path, monkeypatch):
+
+ monkeypatch.setattr(
+ "infection_monkey.config.WormConfiguration.custom_PBA_linux_cmd", None
+ )
+ monkeypatch.setattr(
+ "infection_monkey.config.WormConfiguration.PBA_linux_filename",
+ CUSTOM_LINUX_FILENAME,
+ )
+ return UsersPBA()
+
+
+def test_command_linux_custom_file(mock_UsersPBA_linux_custom_file):
+ expected_command = ""
+ assert mock_UsersPBA_linux_custom_file.command == expected_command
+
+
+@pytest.fixture
+def mock_UsersPBA_windows_custom_file(
+ set_os_windows, fake_monkey_dir_path, monkeypatch
+):
+
+ monkeypatch.setattr(
+ "infection_monkey.config.WormConfiguration.custom_PBA_windows_cmd", None
+ )
+ monkeypatch.setattr(
+ "infection_monkey.config.WormConfiguration.PBA_windows_filename",
+ CUSTOM_WINDOWS_FILENAME,
+ )
+ return UsersPBA()
+
+
+def test_command_windows_custom_file(mock_UsersPBA_windows_custom_file):
+ expected_command = ""
+ assert mock_UsersPBA_windows_custom_file.command == expected_command
+
+
+@pytest.fixture
+def mock_UsersPBA_linux_custom_cmd(set_os_linux, fake_monkey_dir_path, monkeypatch):
+
+ monkeypatch.setattr(
+ "infection_monkey.config.WormConfiguration.custom_PBA_linux_cmd",
+ CUSTOM_LINUX_CMD,
+ )
+ monkeypatch.setattr(
+ "infection_monkey.config.WormConfiguration.PBA_linux_filename", None
+ )
+ return UsersPBA()
+
+
+def test_command_linux_custom_cmd(mock_UsersPBA_linux_custom_cmd):
+ expected_command = CUSTOM_LINUX_CMD
+ assert mock_UsersPBA_linux_custom_cmd.command == expected_command
+
+
+@pytest.fixture
+def mock_UsersPBA_windows_custom_cmd(set_os_windows, fake_monkey_dir_path, monkeypatch):
+
+ monkeypatch.setattr(
+ "infection_monkey.config.WormConfiguration.custom_PBA_windows_cmd",
+ CUSTOM_WINDOWS_CMD,
+ )
+ monkeypatch.setattr(
+ "infection_monkey.config.WormConfiguration.PBA_windows_filename", None
+ )
+ return UsersPBA()
+
+
+def test_command_windows_custom_cmd(mock_UsersPBA_windows_custom_cmd):
+ expected_command = CUSTOM_WINDOWS_CMD
+ assert mock_UsersPBA_windows_custom_cmd.command == expected_command
diff --git a/monkey/infection_monkey/requirements.txt b/monkey/infection_monkey/requirements.txt
index 0a1dbd282..069d1ce07 100644
--- a/monkey/infection_monkey/requirements.txt
+++ b/monkey/infection_monkey/requirements.txt
@@ -1,3 +1,4 @@
+cryptography==2.5
WinSys-3.x>=0.5.2
cffi>=1.14
ecdsa==0.15
@@ -15,3 +16,6 @@ pypykatz==0.3.12
pysmb==1.2.5
requests>=2.24
wmi==1.5.1 ; sys_platform == 'win32'
+urllib3==1.25.8
+git+https://github.com/guardicode/ScoutSuite
+simplejson
diff --git a/monkey/infection_monkey/system_info/collectors/scoutsuite_collector/__init__.py b/monkey/infection_monkey/system_info/collectors/scoutsuite_collector/__init__.py
deleted file mode 100644
index 97e736b4b..000000000
--- a/monkey/infection_monkey/system_info/collectors/scoutsuite_collector/__init__.py
+++ /dev/null
@@ -1,15 +0,0 @@
-import pkgutil
-import sys
-from pathlib import PurePath
-
-_scoutsuite_api_package = pkgutil.get_loader('common.cloud.scoutsuite.ScoutSuite.__main__')
-
-
-def _add_scoutsuite_to_python_path():
- scoutsuite_path = PurePath(_scoutsuite_api_package.path).parent.parent.__str__()
- sys.path.append(scoutsuite_path)
-
-
-# Add ScoutSuite to python path because this way
-# we don't need to change any imports in ScoutSuite code
-_add_scoutsuite_to_python_path()
diff --git a/monkey/infection_monkey/system_info/collectors/scoutsuite_collector/scoutsuite_api.py b/monkey/infection_monkey/system_info/collectors/scoutsuite_collector/scoutsuite_api.py
deleted file mode 100644
index 88ef32293..000000000
--- a/monkey/infection_monkey/system_info/collectors/scoutsuite_collector/scoutsuite_api.py
+++ /dev/null
@@ -1,5 +0,0 @@
-import common.cloud.scoutsuite.ScoutSuite.api_run as scoutsuite_api
-
-
-def run(*args, **kwargs):
- return scoutsuite_api.run(*args, **kwargs)
diff --git a/monkey/infection_monkey/system_info/collectors/scoutsuite_collector/scoutsuite_collector.py b/monkey/infection_monkey/system_info/collectors/scoutsuite_collector/scoutsuite_collector.py
index c637e3593..79aabea56 100644
--- a/monkey/infection_monkey/system_info/collectors/scoutsuite_collector/scoutsuite_collector.py
+++ b/monkey/infection_monkey/system_info/collectors/scoutsuite_collector/scoutsuite_collector.py
@@ -1,8 +1,9 @@
import logging
from typing import Union
-import infection_monkey.system_info.collectors.scoutsuite_collector.scoutsuite_api as scoutsuite_api
-from common.cloud.scoutsuite.ScoutSuite.providers.base.provider import BaseProvider
+import ScoutSuite.api_run
+from ScoutSuite.providers.base.provider import BaseProvider
+
from common.cloud.scoutsuite_consts import CloudProviders
from common.utils.exceptions import ScoutSuiteScanError
from infection_monkey.config import WormConfiguration
@@ -22,10 +23,10 @@ def scan_cloud_security(cloud_type: CloudProviders):
def run_scoutsuite(cloud_type: str) -> Union[BaseProvider, dict]:
- return scoutsuite_api.run(provider=cloud_type,
- aws_access_key_id=WormConfiguration.aws_access_key_id,
- aws_secret_access_key=WormConfiguration.aws_secret_access_key,
- aws_session_token=WormConfiguration.aws_session_token)
+ return ScoutSuite.api_run.run(provider=cloud_type,
+ aws_access_key_id=WormConfiguration.aws_access_key_id,
+ aws_secret_access_key=WormConfiguration.aws_secret_access_key,
+ aws_session_token=WormConfiguration.aws_session_token)
def send_scoutsuite_run_results(run_results: BaseProvider):
diff --git a/monkey/infection_monkey/system_info/windows_info_collector.py b/monkey/infection_monkey/system_info/windows_info_collector.py
index 38feb6815..8a53898c7 100644
--- a/monkey/infection_monkey/system_info/windows_info_collector.py
+++ b/monkey/infection_monkey/system_info/windows_info_collector.py
@@ -1,5 +1,5 @@
import logging
-import os
+import subprocess
import sys
from common.common_consts.system_info_collectors_names import MIMIKATZ_COLLECTOR
@@ -46,16 +46,21 @@ class WindowsInfoCollector(InfoCollector):
return self.info
def get_installed_packages(self):
- LOG.info('getting installed packages')
- self.info["installed_packages"] = os.popen("dism /online /get-packages").read()
- self.info["installed_features"] = os.popen("dism /online /get-features").read()
+ LOG.info('Getting installed packages')
+
+ packages = subprocess.check_output("dism /online /get-packages", shell=True)
+ self.info["installed_packages"] = packages.decode('utf-8', errors='ignore')
+
+ features = subprocess.check_output("dism /online /get-features", shell=True)
+ self.info["installed_features"] = features.decode('utf-8', errors='ignore')
+
LOG.debug('Got installed packages')
def get_wmi_info(self):
- LOG.info('getting wmi info')
+ LOG.info('Getting wmi info')
for wmi_class_name in WMI_CLASSES:
self.info['wmi'][wmi_class_name] = WMIUtils.get_wmi_class(wmi_class_name)
- LOG.debug('finished get_wmi_info')
+ LOG.debug('Finished get_wmi_info')
def get_mimikatz_info(self):
LOG.info("Gathering mimikatz info")
diff --git a/monkey/infection_monkey/telemetry/scoutsuite_telem.py b/monkey/infection_monkey/telemetry/scoutsuite_telem.py
index 16cf47bdd..ba112f8b9 100644
--- a/monkey/infection_monkey/telemetry/scoutsuite_telem.py
+++ b/monkey/infection_monkey/telemetry/scoutsuite_telem.py
@@ -1,5 +1,5 @@
-from common.cloud.scoutsuite.ScoutSuite.output.result_encoder import ScoutJsonEncoder
-from common.cloud.scoutsuite.ScoutSuite.providers.base.provider import BaseProvider
+from ScoutSuite.output.result_encoder import ScoutJsonEncoder
+from ScoutSuite.providers.base.provider import BaseProvider
from common.common_consts.telem_categories import TelemCategoryEnum
from infection_monkey.telemetry.base_telem import BaseTelem
diff --git a/monkey/monkey_island/cc/app.py b/monkey/monkey_island/cc/app.py
index c53c04caa..c7fd0006f 100644
--- a/monkey/monkey_island/cc/app.py
+++ b/monkey/monkey_island/cc/app.py
@@ -7,6 +7,7 @@ from werkzeug.exceptions import NotFound
import monkey_island.cc.environment.environment_singleton as env_singleton
from common.common_consts.api_url_consts import T1216_PBA_FILE_DOWNLOAD_PATH
+from monkey_island.cc.resources.test.telemetry_test import TelemetryTest
from monkey_island.cc.resources.zero_trust.zero_trust_report import ZeroTrustReport
from monkey_island.cc.server_utils.consts import MONKEY_ISLAND_ABS_PATH
from monkey_island.cc.server_utils.custom_json_encoder import CustomJSONEncoder
@@ -145,9 +146,11 @@ def init_api_resources(api):
api.add_resource(ScoutSuiteAuth, '/api/scoutsuite_auth/')
api.add_resource(AWSKeys, '/api/aws_keys')
+ # Resources used by black box tests
api.add_resource(MonkeyTest, '/api/test/monkey')
api.add_resource(ClearCaches, '/api/test/clear_caches')
api.add_resource(LogTest, '/api/test/log')
+ api.add_resource(TelemetryTest, '/api/test/telemetry')
def init_app(mongo_url):
diff --git a/monkey/monkey_island/cc/resources/test/telemetry_test.py b/monkey/monkey_island/cc/resources/test/telemetry_test.py
new file mode 100644
index 000000000..29108070e
--- /dev/null
+++ b/monkey/monkey_island/cc/resources/test/telemetry_test.py
@@ -0,0 +1,13 @@
+import flask_restful
+from bson import json_util
+from flask import request
+
+from monkey_island.cc.database import mongo
+from monkey_island.cc.resources.auth.auth import jwt_required
+
+
+class TelemetryTest(flask_restful.Resource):
+ @jwt_required
+ def get(self, **kw):
+ find_query = json_util.loads(request.args.get('find_query'))
+ return {'results': list(mongo.db.telemetry.find(find_query))}
diff --git a/monkey/monkey_island/cc/services/attack/technique_reports/T1065.py b/monkey/monkey_island/cc/services/attack/technique_reports/T1065.py
index c3fcd03e8..3b18be488 100644
--- a/monkey/monkey_island/cc/services/attack/technique_reports/T1065.py
+++ b/monkey/monkey_island/cc/services/attack/technique_reports/T1065.py
@@ -4,7 +4,7 @@ from monkey_island.cc.services.config import ConfigService
__author__ = "VakarisZ"
-from monkey_island.cc.services.config_schema.config_value_paths import CURRENT_SERVER_PATH
+from common.config_value_paths import CURRENT_SERVER_PATH
class T1065(AttackTechnique):
diff --git a/monkey/monkey_island/cc/services/config.py b/monkey/monkey_island/cc/services/config.py
index b4370a63b..390380131 100644
--- a/monkey/monkey_island/cc/services/config.py
+++ b/monkey/monkey_island/cc/services/config.py
@@ -14,10 +14,10 @@ from monkey_island.cc.services.config_schema.config_schema import SCHEMA
__author__ = "itay.mizeretz"
-from monkey_island.cc.services.config_schema.config_value_paths import (AWS_KEYS_PATH, EXPORT_MONKEY_TELEMS_PATH,
- LM_HASH_LIST_PATH, NTLM_HASH_LIST_PATH,
- PASSWORD_LIST_PATH, SSH_KEYS_PATH,
- STARTED_ON_ISLAND_PATH, USER_LIST_PATH)
+from common.config_value_paths import (AWS_KEYS_PATH, EXPORT_MONKEY_TELEMS_PATH,
+ LM_HASH_LIST_PATH, NTLM_HASH_LIST_PATH,
+ PASSWORD_LIST_PATH, SSH_KEYS_PATH,
+ STARTED_ON_ISLAND_PATH, USER_LIST_PATH)
logger = logging.getLogger(__name__)
diff --git a/monkey/monkey_island/cc/services/config_schema/internal.py b/monkey/monkey_island/cc/services/config_schema/internal.py
index 156dae7ad..f6b3523f0 100644
--- a/monkey/monkey_island/cc/services/config_schema/internal.py
+++ b/monkey/monkey_island/cc/services/config_schema/internal.py
@@ -159,7 +159,8 @@ INTERNAL = {
8080,
443,
8008,
- 7001
+ 7001,
+ 9200
],
"description": "List of ports the monkey will check if are being used for HTTP"
},
@@ -181,7 +182,6 @@ INTERNAL = {
443,
8008,
3306,
- 9200,
7001,
8088
],
diff --git a/monkey/monkey_island/cc/services/config_schema/monkey.py b/monkey/monkey_island/cc/services/config_schema/monkey.py
index 01d463672..82a394b65 100644
--- a/monkey/monkey_island/cc/services/config_schema/monkey.py
+++ b/monkey/monkey_island/cc/services/config_schema/monkey.py
@@ -11,33 +11,39 @@ MONKEY = {
"type": "object",
"properties": {
"custom_PBA_linux_cmd": {
- "title": "Linux post breach command",
+ "title": "Linux post-breach command",
"type": "string",
"default": "",
- "description": "Linux command to be executed after breaching."
+ "description": "Command to be executed after breaching. "
+ "Use this field to run custom commands or execute uploaded "
+ "files on exploited machines.\nExample: "
+ "\"chmod +x ./my_script.sh; ./my_script.sh ; rm ./my_script.sh\""
},
"PBA_linux_file": {
- "title": "Linux post breach file",
+ "title": "Linux post-breach file",
"type": "string",
"format": "data-url",
- "description": "File to be executed after breaching. "
- "If you want custom execution behavior, "
- "specify it in 'Linux post breach command' field. "
+ "description": "File to be uploaded after breaching. "
+ "Use the 'Linux post-breach command' field to "
+ "change permissions, run, or delete the file. "
"Reference your file by filename."
},
"custom_PBA_windows_cmd": {
- "title": "Windows post breach command",
+ "title": "Windows post-breach command",
"type": "string",
"default": "",
- "description": "Windows command to be executed after breaching."
+ "description": "Command to be executed after breaching. "
+ "Use this field to run custom commands or execute uploaded "
+ "files on exploited machines.\nExample: "
+ "\"my_script.bat & del my_script.bat\""
},
"PBA_windows_file": {
- "title": "Windows post breach file",
+ "title": "Windows post-breach file",
"type": "string",
"format": "data-url",
- "description": "File to be executed after breaching. "
- "If you want custom execution behavior, "
- "specify it in 'Windows post breach command' field. "
+ "description": "File to be uploaded after breaching. "
+ "Use the 'Windows post-breach command' field to "
+ "change permissions, run, or delete the file. "
"Reference your file by filename."
},
"PBA_windows_filename": {
diff --git a/monkey/monkey_island/cc/services/configuration/utils.py b/monkey/monkey_island/cc/services/configuration/utils.py
index 48857e2e3..493d5af03 100644
--- a/monkey/monkey_island/cc/services/configuration/utils.py
+++ b/monkey/monkey_island/cc/services/configuration/utils.py
@@ -1,5 +1,5 @@
from monkey_island.cc.services.config import ConfigService
-from monkey_island.cc.services.config_schema.config_value_paths import INACCESSIBLE_SUBNETS_PATH
+from common.config_value_paths import INACCESSIBLE_SUBNETS_PATH
def get_config_network_segments_as_subnet_groups():
diff --git a/monkey/monkey_island/cc/services/reporting/report.py b/monkey/monkey_island/cc/services/reporting/report.py
index 5970a33b7..a23aa6d85 100644
--- a/monkey/monkey_island/cc/services/reporting/report.py
+++ b/monkey/monkey_island/cc/services/reporting/report.py
@@ -12,9 +12,9 @@ from monkey_island.cc.database import mongo
from monkey_island.cc.models import Monkey
from monkey_island.cc.services.utils.network_utils import get_subnets, local_ip_addresses
from monkey_island.cc.services.config import ConfigService
-from monkey_island.cc.services.config_schema.config_value_paths import (EXPLOITER_CLASSES_PATH, LOCAL_NETWORK_SCAN_PATH,
- PASSWORD_LIST_PATH, SUBNET_SCAN_LIST_PATH,
- USER_LIST_PATH)
+from common.config_value_paths import (EXPLOITER_CLASSES_PATH, LOCAL_NETWORK_SCAN_PATH,
+ PASSWORD_LIST_PATH, SUBNET_SCAN_LIST_PATH,
+ USER_LIST_PATH)
from monkey_island.cc.services.configuration.utils import get_config_network_segments_as_subnet_groups
from monkey_island.cc.services.node import NodeService
from monkey_island.cc.services.reporting.pth_report import PTHReportService
diff --git a/monkey/monkey_island/cc/services/telemetry/processing/scoutsuite.py b/monkey/monkey_island/cc/services/telemetry/processing/scoutsuite.py
index 8ee4737e8..9160861ea 100644
--- a/monkey/monkey_island/cc/services/telemetry/processing/scoutsuite.py
+++ b/monkey/monkey_island/cc/services/telemetry/processing/scoutsuite.py
@@ -3,6 +3,7 @@ import json
from monkey_island.cc.database import mongo
from monkey_island.cc.models.zero_trust.scoutsuite_data_json import ScoutSuiteRawDataJson
from monkey_island.cc.services.zero_trust.scoutsuite.consts.scoutsuite_findings_list import SCOUTSUITE_FINDINGS
+from monkey_island.cc.services.zero_trust.scoutsuite.consts.service_consts import SERVICES
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_parser import RuleParser
from monkey_island.cc.services.zero_trust.scoutsuite.scoutsuite_rule_service import ScoutSuiteRuleService
from monkey_island.cc.services.zero_trust.scoutsuite.scoutsuite_zt_finding_service import ScoutSuiteZTFindingService
@@ -13,14 +14,14 @@ def process_scoutsuite_telemetry(telemetry_json):
telemetry_json['data'] = json.dumps(telemetry_json['data'])
ScoutSuiteRawDataJson.add_scoutsuite_data(telemetry_json['data'])
scoutsuite_data = json.loads(telemetry_json['data'])['data']
- create_scoutsuite_findings(scoutsuite_data)
+ create_scoutsuite_findings(scoutsuite_data[SERVICES])
update_data(telemetry_json)
-def create_scoutsuite_findings(scoutsuite_data):
+def create_scoutsuite_findings(cloud_services: dict):
for finding in SCOUTSUITE_FINDINGS:
for rule in finding.rules:
- rule_data = RuleParser.get_rule_data(scoutsuite_data, rule)
+ rule_data = RuleParser.get_rule_data(cloud_services, rule)
rule = ScoutSuiteRuleService.get_rule_from_rule_data(rule_data)
ScoutSuiteZTFindingService.process_rule(finding, rule)
diff --git a/monkey/monkey_island/cc/services/zero_trust/scoutsuite/__init__.py b/monkey/monkey_island/cc/services/zero_trust/scoutsuite/__init__.py
deleted file mode 100644
index e8a36338b..000000000
--- a/monkey/monkey_island/cc/services/zero_trust/scoutsuite/__init__.py
+++ /dev/null
@@ -1,13 +0,0 @@
-import pkgutil
-import sys
-from pathlib import PurePath
-
-_scoutsuite_api_package = pkgutil.get_loader('common.cloud.scoutsuite.ScoutSuite.__main__')
-
-
-def _add_scoutsuite_to_python_path():
- scoutsuite_path = PurePath(_scoutsuite_api_package.path).parent.parent.__str__()
- sys.path.append(scoutsuite_path)
-
-
-_add_scoutsuite_to_python_path()
diff --git a/monkey/monkey_island/cc/services/zero_trust/scoutsuite/data_parsing/rule_parser.py b/monkey/monkey_island/cc/services/zero_trust/scoutsuite/data_parsing/rule_parser.py
index e07431541..935f1c989 100644
--- a/monkey/monkey_island/cc/services/zero_trust/scoutsuite/data_parsing/rule_parser.py
+++ b/monkey/monkey_island/cc/services/zero_trust/scoutsuite/data_parsing/rule_parser.py
@@ -1,7 +1,6 @@
from enum import Enum
-import dpath.util
-
+from common.utils.code_utils import get_value_from_dict
from common.utils.exceptions import RulePathCreatorNotFound
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_path_building.rule_path_creators_list import \
RULE_PATH_CREATORS_LIST
@@ -23,7 +22,7 @@ class RuleParser:
@staticmethod
def get_rule_data(scoutsuite_data: dict, rule_name: Enum) -> dict:
rule_path = RuleParser._get_rule_path(rule_name)
- return dpath.util.get(scoutsuite_data, rule_path)
+ return get_value_from_dict(scoutsuite_data, rule_path)
@staticmethod
def _get_rule_path(rule_name: Enum):
diff --git a/monkey/monkey_island/cc/services/zero_trust/scoutsuite/data_parsing/rule_path_building/abstract_rule_path_creator.py b/monkey/monkey_island/cc/services/zero_trust/scoutsuite/data_parsing/rule_path_building/abstract_rule_path_creator.py
index b4767124b..ee7f7c38b 100644
--- a/monkey/monkey_island/cc/services/zero_trust/scoutsuite/data_parsing/rule_path_building/abstract_rule_path_creator.py
+++ b/monkey/monkey_island/cc/services/zero_trust/scoutsuite/data_parsing/rule_path_building/abstract_rule_path_creator.py
@@ -3,7 +3,7 @@ from enum import Enum
from typing import List, Type
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.rule_name_enum import RuleNameEnum
-from monkey_island.cc.services.zero_trust.scoutsuite.consts.service_consts import FINDINGS, SERVICES, SERVICE_TYPES
+from monkey_island.cc.services.zero_trust.scoutsuite.consts.service_consts import FINDINGS, SERVICE_TYPES
class AbstractRulePathCreator(ABC):
@@ -21,4 +21,4 @@ class AbstractRulePathCreator(ABC):
@classmethod
def build_rule_path(cls, rule_name: Enum) -> List[str]:
assert(rule_name in cls.supported_rules)
- return [SERVICES, cls.service_type.value, FINDINGS, rule_name.value]
+ return [cls.service_type.value, FINDINGS, rule_name.value]
diff --git a/monkey/monkey_island/cc/services/zero_trust/scoutsuite/data_parsing/test_rule_parser.py b/monkey/monkey_island/cc/services/zero_trust/scoutsuite/data_parsing/test_rule_parser.py
index 5a7572eb0..afe14c54c 100644
--- a/monkey/monkey_island/cc/services/zero_trust/scoutsuite/data_parsing/test_rule_parser.py
+++ b/monkey/monkey_island/cc/services/zero_trust/scoutsuite/data_parsing/test_rule_parser.py
@@ -4,6 +4,7 @@ import pytest
from common.utils.exceptions import RulePathCreatorNotFound
from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.ec2_rules import EC2Rules
+from monkey_island.cc.services.zero_trust.scoutsuite.consts.service_consts import SERVICES
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_parser import RuleParser
from monkey_island.cc.services.zero_trust.test_common.raw_scoutsute_data import RAW_SCOUTSUITE_DATA
@@ -28,9 +29,9 @@ EXPECTED_RESULT = {'description': 'Security Group Opens All Ports to All',
def test_get_rule_data():
# Test proper parsing of the raw data to rule
- results = RuleParser.get_rule_data(RAW_SCOUTSUITE_DATA, ALL_PORTS_OPEN)
+ results = RuleParser.get_rule_data(RAW_SCOUTSUITE_DATA[SERVICES], ALL_PORTS_OPEN)
assert results == EXPECTED_RESULT
with pytest.raises(RulePathCreatorNotFound):
- RuleParser.get_rule_data(RAW_SCOUTSUITE_DATA, ExampleRules.NON_EXSISTENT_RULE)
+ RuleParser.get_rule_data(RAW_SCOUTSUITE_DATA[SERVICES], ExampleRules.NON_EXSISTENT_RULE)
pass
diff --git a/monkey/monkey_island/cc/services/zero_trust/scoutsuite/scoutsuite_auth_service.py b/monkey/monkey_island/cc/services/zero_trust/scoutsuite/scoutsuite_auth_service.py
index dc3f8d5ee..701598168 100644
--- a/monkey/monkey_island/cc/services/zero_trust/scoutsuite/scoutsuite_auth_service.py
+++ b/monkey/monkey_island/cc/services/zero_trust/scoutsuite/scoutsuite_auth_service.py
@@ -6,7 +6,7 @@ from common.cloud.scoutsuite_consts import CloudProviders
from common.utils.exceptions import InvalidAWSKeys
from monkey_island.cc.server_utils.encryptor import encryptor
from monkey_island.cc.services.config import ConfigService
-from monkey_island.cc.services.config_schema.config_value_paths import AWS_KEYS_PATH
+from common.config_value_paths import AWS_KEYS_PATH
def is_cloud_authentication_setup(provider: CloudProviders) -> Tuple[bool, str]:
@@ -14,7 +14,7 @@ def is_cloud_authentication_setup(provider: CloudProviders) -> Tuple[bool, str]:
if is_aws_keys_setup():
return True, "AWS keys already setup."
- import common.cloud.scoutsuite.ScoutSuite.providers.aws.authentication_strategy as auth_strategy
+ import ScoutSuite.providers.aws.authentication_strategy as auth_strategy
try:
profile = auth_strategy.AWSAuthenticationStrategy().authenticate()
return True, f" Profile \"{profile.session.profile_name}\" is already setup. "
diff --git a/monkey/monkey_island/cc/services/zero_trust/scoutsuite/test_scoutsuite_auth_service.py b/monkey/monkey_island/cc/services/zero_trust/scoutsuite/test_scoutsuite_auth_service.py
index 24e700ce6..c35e55a8f 100644
--- a/monkey/monkey_island/cc/services/zero_trust/scoutsuite/test_scoutsuite_auth_service.py
+++ b/monkey/monkey_island/cc/services/zero_trust/scoutsuite/test_scoutsuite_auth_service.py
@@ -6,7 +6,7 @@ import dpath.util
from monkey_island.cc.database import mongo
from monkey_island.cc.server_utils import encryptor
from monkey_island.cc.services.config import ConfigService
-from monkey_island.cc.services.config_schema.config_value_paths import AWS_KEYS_PATH
+from common.config_value_paths import AWS_KEYS_PATH
from monkey_island.cc.services.zero_trust.scoutsuite.scoutsuite_auth_service import is_aws_keys_setup
from monkey_island.cc.test_common.fixtures import FixtureEnum
diff --git a/monkey/monkey_island/cc/test_common/profiling/README.md b/monkey/monkey_island/cc/test_common/profiling/README.md
index 1c1446b2f..d0cb92bfa 100644
--- a/monkey/monkey_island/cc/test_common/profiling/README.md
+++ b/monkey/monkey_island/cc/test_common/profiling/README.md
@@ -2,7 +2,7 @@
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
+Use it as a parameterised decorator(`@profile()`). 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
diff --git a/monkey/monkey_island/cc/ui/package.json b/monkey/monkey_island/cc/ui/package.json
index 618f02d5e..1cc781c03 100644
--- a/monkey/monkey_island/cc/ui/package.json
+++ b/monkey/monkey_island/cc/ui/package.json
@@ -1,6 +1,6 @@
{
"private": true,
- "version": "1.9.0",
+ "version": "1.10.0",
"name": "infection-monkey",
"description": "Infection Monkey C&C UI",
"scripts": {
diff --git a/monkey/monkey_island/cc/ui/src/components/ui-components/AdvancedMultiSelect.js b/monkey/monkey_island/cc/ui/src/components/ui-components/AdvancedMultiSelect.js
index 8503a74fc..193cb40b0 100644
--- a/monkey/monkey_island/cc/ui/src/components/ui-components/AdvancedMultiSelect.js
+++ b/monkey/monkey_island/cc/ui/src/components/ui-components/AdvancedMultiSelect.js
@@ -43,7 +43,7 @@ class AdvancedMultiSelect extends React.Component {
infoPaneParams: getDefaultPaneParams(
this.infoPaneRefString,
this.registry,
- this.isUnsafeOptionSelected(this.props.value)
+ this.isUnsafeOptionSelected(props.value)
)
};
}
@@ -94,9 +94,11 @@ class AdvancedMultiSelect extends React.Component {
}
setMasterCheckboxState(selectValues) {
- this.setState(() => ({
- masterCheckboxState: this.getMasterCheckboxState(selectValues)
- }));
+ let newState = this.getMasterCheckboxState(selectValues);
+
+ if (newState != this.state.masterCheckboxState) {
+ this.setState({masterCheckboxState: newState});
+ }
}
getMasterCheckboxState(selectValues) {
@@ -162,11 +164,12 @@ class AdvancedMultiSelect extends React.Component {
render() {
const {
- schema,
+ autofocus,
id,
- required,
multiple,
- autofocus
+ required,
+ schema,
+ value
} = this.props;
return (
@@ -179,7 +182,7 @@ class AdvancedMultiSelect extends React.Component {
+ selectedValues={value} enumOptions={this.enumOptions}/>
);
}
+
+ componentDidUpdate(_prevProps) {
+ this.setMasterCheckboxState(this.props.value);
+ }
}
export default AdvancedMultiSelect;
diff --git a/monkey/monkey_island/requirements.txt b/monkey/monkey_island/requirements.txt
index 3cb3a4e42..b5be47a88 100644
--- a/monkey/monkey_island/requirements.txt
+++ b/monkey/monkey_island/requirements.txt
@@ -26,5 +26,6 @@ tqdm>=4.47
virtualenv>=20.0.26
werkzeug>=1.0.1
wheel>=0.34.2
+git+https://github.com/guardicode/ScoutSuite
-pyjwt>=1.5.1 # not directly required, pinned by Snyk to avoid a vulnerability
+pyjwt==1.7 # not directly required, pinned by Snyk to avoid a vulnerability