forked from p15670423/monkey
Merge branch 'release/1.10.0' into develop
This commit is contained in:
commit
176ad01c14
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -7,7 +7,7 @@ pre: "<i class='fas fa-question'></i> "
|
|||
|
||||
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.
|
||||
|
||||
|
|
|
@ -8,18 +8,33 @@ 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`.
|
||||
|
||||
Once you've extracted the package, deploy it using run the following commands:
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
If, at this point, you receive dpkg printed errors that look like this:
|
||||
1. If, at this point, you receive dpkg errors that look like this:
|
||||
|
||||
```sh
|
||||
dpkg: error processing package gc-monkey-island (--install):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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` |
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)}")
|
||||
|
||||
|
|
@ -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
|
|
@ -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"]
|
||||
})
|
|
@ -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"]
|
||||
})
|
|
@ -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)
|
||||
|
|
@ -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({
|
|
@ -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):
|
|
@ -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({
|
|
@ -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({
|
|
@ -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 = {
|
|
@ -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"],
|
|
@ -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"]
|
||||
})
|
|
@ -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}",
|
|
@ -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"]
|
||||
})
|
|
@ -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"],
|
|
@ -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",
|
||||
],
|
||||
}
|
||||
)
|
|
@ -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": []
|
||||
})
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"]
|
||||
})
|
|
@ -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"]
|
||||
})
|
|
@ -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"]
|
||||
})
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
@ -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 !!
|
|
@ -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()
|
|
@ -0,0 +1 @@
|
|||
.
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 9de1e78ba475f925c66c5b645564ec9eb08e2309
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -252,9 +252,12 @@ class InfectionMonkey(object):
|
|||
|
||||
def collect_system_info_if_configured(self):
|
||||
LOG.debug("Calling for system info collection")
|
||||
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:
|
||||
|
|
|
@ -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,
|
||||
|
@ -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():
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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()
|
|
@ -1,5 +0,0 @@
|
|||
import common.cloud.scoutsuite.ScoutSuite.api_run as scoutsuite_api
|
||||
|
||||
|
||||
def run(*args, **kwargs):
|
||||
return scoutsuite_api.run(*args, **kwargs)
|
|
@ -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,7 +23,7 @@ def scan_cloud_security(cloud_type: CloudProviders):
|
|||
|
||||
|
||||
def run_scoutsuite(cloud_type: str) -> Union[BaseProvider, dict]:
|
||||
return scoutsuite_api.run(provider=cloud_type,
|
||||
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)
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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/<string:provider>')
|
||||
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):
|
||||
|
|
|
@ -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))}
|
|
@ -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):
|
||||
|
|
|
@ -14,7 +14,7 @@ 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,
|
||||
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)
|
||||
|
|
|
@ -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
|
||||
],
|
||||
|
|
|
@ -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": {
|
||||
|
|
|
@ -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():
|
||||
|
|
|
@ -12,7 +12,7 @@ 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,
|
||||
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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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()
|
|
@ -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):
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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. "
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"private": true,
|
||||
"version": "1.9.0",
|
||||
"version": "1.10.0",
|
||||
"name": "infection-monkey",
|
||||
"description": "Infection Monkey C&C UI",
|
||||
"scripts": {
|
||||
|
|
|
@ -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 {
|
|||
<ChildCheckboxContainer id={id} multiple={multiple} required={required}
|
||||
autoFocus={autofocus} isSafe={this.isSafe}
|
||||
onPaneClick={this.setPaneInfo} onCheckboxClick={this.onChildCheckboxClick}
|
||||
selectedValues={this.props.value} enumOptions={this.enumOptions}/>
|
||||
selectedValues={value} enumOptions={this.enumOptions}/>
|
||||
|
||||
<InfoPane title={this.state.infoPaneParams.title}
|
||||
body={this.state.infoPaneParams.content}
|
||||
|
@ -188,6 +191,10 @@ class AdvancedMultiSelect extends React.Component {
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
componentDidUpdate(_prevProps) {
|
||||
this.setMasterCheckboxState(this.props.value);
|
||||
}
|
||||
}
|
||||
|
||||
export default AdvancedMultiSelect;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue