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"]
|
[submodule "docs/themes/learn"]
|
||||||
path = docs/themes/learn
|
path = docs/themes/learn
|
||||||
url = https://github.com/guardicode/hugo-theme-learn.git
|
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 flake8 pytest pytest-cov dlint isort # for next stages
|
||||||
- pip install coverage # for code coverage
|
- pip install coverage # for code coverage
|
||||||
- pip install -r monkey/infection_monkey/requirements.txt # for unit tests
|
- pip install -r monkey/infection_monkey/requirements.txt # for unit tests
|
||||||
- pip install -r monkey/common/cloud/scoutsuite/requirements.txt
|
|
||||||
- pip install pipdeptree
|
- pip install pipdeptree
|
||||||
# Fail builds on possible conflicting dependencies.
|
# Fail builds on possible conflicting dependencies.
|
||||||
- pipdeptree --warn fail
|
- pipdeptree --warn fail
|
||||||
|
@ -56,7 +55,7 @@ install:
|
||||||
script:
|
script:
|
||||||
# Check Python code
|
# Check Python code
|
||||||
## Check syntax errors and fail the build if any are found.
|
## 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.
|
## 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.
|
### --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"
|
ISLAND_BINARIES_PATH="$ISLAND_PATH/cc/binaries"
|
||||||
INFECTION_MONKEY_DIR="$monkey_home/monkey/infection_monkey"
|
INFECTION_MONKEY_DIR="$monkey_home/monkey/infection_monkey"
|
||||||
MONKEY_BIN_DIR="$INFECTION_MONKEY_DIR/bin"
|
MONKEY_BIN_DIR="$INFECTION_MONKEY_DIR/bin"
|
||||||
SCOUTSUITE_DIR="$monkey_home/monkey/common/cloud/scoutsuite"
|
|
||||||
|
|
||||||
if ! has_sudo; then
|
if ! has_sudo; then
|
||||||
log_message "You need root permissions for some of this script operations. \
|
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"
|
requirements_monkey="$INFECTION_MONKEY_DIR/requirements.txt"
|
||||||
${python_cmd} -m pip install -r "${requirements_monkey}" --user --upgrade || handle_error
|
${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}
|
agents=${3:-true}
|
||||||
# Download binaries
|
# Download binaries
|
||||||
if [ "$agents" = true ] ; then
|
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).
|
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 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)
|
- [How to reset the password?](#how-to-reset-the-password)
|
||||||
- [Should I run the Monkey continuously?](#should-i-run-the-monkey-continuously)
|
- [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)
|
- [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)
|
- [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)
|
- [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**!
|
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/).
|
- **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.
|
- **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.
|
The Monkey is an open-source project, and we weclome contributions and contributors. Check out the [contribution documentation](../development) for more information.
|
||||||
|
|
||||||
|
|
|
@ -8,33 +8,48 @@ disableToc: false
|
||||||
tags: ["setup", "debian", "linux"]
|
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
|
## 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):
|
||||||
```sh
|
|
||||||
sudo apt update
|
|
||||||
sudo dpkg -i monkey_island.deb # this might print errors
|
|
||||||
```
|
|
||||||
|
|
||||||
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
|
dependency problems - leaving unconfigured
|
||||||
Errors were encountered while processing:
|
Errors were encountered while processing:
|
||||||
gc-monkey-island
|
gc-monkey-island
|
||||||
```
|
```
|
||||||
|
|
||||||
It just means that not all dependencies were pre-installed on your system.
|
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
|
That's no problem! Just run the following command, which will install all
|
||||||
dependencies, and then install the Monkey Island:
|
dependencies, and then install the Monkey Island:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo apt install -f
|
sudo apt install -f
|
||||||
```
|
```
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
|
|
|
@ -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:
|
Once you've extracted the container from the tar.gz file, run the following commands:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo docker load -i dk.monkeyisland.1.9.0.tar
|
sudo docker load -i dk.monkeyisland.1.10.0.tar
|
||||||
sudo docker pull mongo
|
sudo docker pull mongo:4.2
|
||||||
sudo mkdir -p /var/monkey-mongo/data/db
|
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-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.9.0
|
sudo docker run --name monkey-island --network=host -d guardicore/monkey-island:1.10.0
|
||||||
```
|
```
|
||||||
|
|
||||||
## Upgrading
|
## Upgrading
|
||||||
|
|
|
@ -16,8 +16,9 @@ tags: ["setup", "vmware"]
|
||||||
1. Log in to the machine with the following credentials:
|
1. Log in to the machine with the following credentials:
|
||||||
1. Username: **monkeyuser**
|
1. Username: **monkeyuser**
|
||||||
1. Password: **Noon.Earth.Always**
|
1. Password: **Noon.Earth.Always**
|
||||||
1. It's recommended you change the machine passwords by running the following
|
1. For security purposes, it's recommended that you change the machine
|
||||||
commands: `sudo passwd monkeyuser`, `sudo passwd root`.
|
passwords by running the following commands: `sudo passwd monkeyuser`, `sudo
|
||||||
|
passwd root`.
|
||||||
|
|
||||||
## OVA network modes
|
## 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
|
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.
|
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
|
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
|
with the username `monkeyuser` and the password `Noon.Earth.Always`. After logging
|
||||||
in, edit the interfaces file by entering the following command in the
|
in, edit the Netplan configuration by entering the following command in the
|
||||||
prompt:
|
prompt:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo nano /etc/network/interfaces
|
sudo nano /etc/netplan/00-installer-config.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
Change the lines:
|
Make the following changes:
|
||||||
|
|
||||||
```sh
|
```diff
|
||||||
auto ens160
|
# This is the network config written by 'subiquity'
|
||||||
iface ens160 inet dhcp
|
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:
|
Replace `XXX.XXX.XXX.XXX` with the desired IP addess of the VM. Replace
|
||||||
|
`YYY.YYY.YYY.YYY` with the default gateway.
|
||||||
```sh
|
|
||||||
auto ens160
|
|
||||||
iface ens160 inet static
|
|
||||||
address AAA.BBB.CCC.DDD
|
|
||||||
netmask XXX.XXX.XXX.XXX
|
|
||||||
gateway YYY.YYY.YYY.YYY
|
|
||||||
```
|
|
||||||
|
|
||||||
Save the changes then run the command:
|
Save the changes then run the command:
|
||||||
|
|
||||||
```sh
|
```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
|
## Upgrading
|
||||||
|
|
||||||
Currently, there's no "upgrade-in-place" option when a new version is released.
|
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
|
## 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 |
|
| Filename | Type | Version | SHA256 |
|
||||||
|------------------------------------------------------|-------------------|---------|--------------------------------------------------------------------|
|
|------------------------------------------------------|-------------------|---------|--------------------------------------------------------------------|
|
||||||
| monkey-windows-64.exe | Windows Agent | 1.9.0 | `24622cb8dbabb0cf4b25ecd3c13800c72ec5b59b76895b737ece509640d4c068` |
|
| 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` |
|
| infection_monkey_docker_dockerzt_20200806_154742.tgz | Docker | 1.9.0 | `a84dbaad32ae42cc2d359ffbe062aec493a7253cf706a2d45f0d0b1c230f9348` |
|
||||||
| monkey-island-vmware.ova | OVA | 1.9.0 | `3861d46518e8a92e49992b26dbff9fe8e8a4ac5fd24d68e68b13e7fd3fa22247` |
|
| monkey-island-vmware.ova | OVA | 1.9.0 | `3861d46518e8a92e49992b26dbff9fe8e8a4ac5fd24d68e68b13e7fd3fa22247` |
|
||||||
| monkey-island-vmwarezt.ova | OVA | 1.9.0 | `03d356eb35e6515146f5bd798bb62cb15c56fcdf83a5281cf6cdc9b901586026` |
|
| 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-64.exe | Windows Agent | 1.8.2 | `2e6a1cb5523d87ddfd48f75b10114617343fbac8125fa950ba7f00289b38b550` |
|
||||||
| monkey-windows-32.exe | Windows Agent | 1.8.2 | `86a7d7065e73b795e38f2033be0c53f3ac808cc67478aed794a7a6c89123979f` |
|
| monkey-windows-32.exe | Windows Agent | 1.8.2 | `86a7d7065e73b795e38f2033be0c53f3ac808cc67478aed794a7a6c89123979f` |
|
||||||
| monkey-linux-64 | Linux Agent | 1.8.2 | `4dce4a115d41b43adffc11672fae2164265f8902267f1355d02bebb802bd45c5` |
|
| 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:
|
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
|
#### 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`.
|
directory `monkey\envs\monkey_zoo\blackbox`.
|
||||||
|
|
||||||
### Running telemetry performance test
|
### Running telemetry performance test
|
||||||
|
|
|
@ -4,5 +4,5 @@ from abc import ABCMeta, abstractmethod
|
||||||
class Analyzer(object, metaclass=ABCMeta):
|
class Analyzer(object, metaclass=ABCMeta):
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def analyze_test_results(self):
|
def analyze_test_results(self) -> bool:
|
||||||
raise NotImplementedError()
|
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
|
# 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 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.island_configs.config_template import ConfigTemplate
|
from envs.monkey_zoo.blackbox.config_templates.config_template import ConfigTemplate
|
||||||
|
|
||||||
|
|
||||||
class Elastic(ConfigTemplate):
|
class Elastic(ConfigTemplate):
|
||||||
|
@ -10,5 +10,6 @@ class Elastic(ConfigTemplate):
|
||||||
|
|
||||||
config_values.update({
|
config_values.update({
|
||||||
"basic.exploiters.exploiter_classes": ["ElasticGroovyExploiter"],
|
"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"]
|
"basic_network.scope.subnet_scan_list": ["10.2.2.4", "10.2.2.5"]
|
||||||
})
|
})
|
|
@ -1,9 +1,10 @@
|
||||||
from copy import copy
|
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)
|
config_values = copy(BaseTemplate.config_values)
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
from copy import copy
|
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 = copy(BaseTemplate.config_values)
|
||||||
|
|
||||||
config_values.update({
|
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):
|
class Performance(ConfigTemplate):
|
|
@ -1,9 +1,10 @@
|
||||||
from copy import copy
|
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 = copy(BaseTemplate.config_values)
|
||||||
|
|
||||||
config_values.update({
|
config_values.update({
|
|
@ -1,9 +1,10 @@
|
||||||
from copy import copy
|
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 = copy(BaseTemplate.config_values)
|
||||||
|
|
||||||
config_values.update({
|
config_values.update({
|
|
@ -1,9 +1,10 @@
|
||||||
from copy import copy
|
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_values = copy(BaseTemplate.config_values)
|
||||||
|
|
||||||
config_value_list = {
|
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):
|
class Ssh(ConfigTemplate):
|
||||||
config_values = BaseTemplate.config_values
|
config_values = copy(BaseTemplate.config_values)
|
||||||
|
|
||||||
config_values.update({
|
config_values.update({
|
||||||
"basic.exploiters.exploiter_classes": ["SSHExploiter"],
|
"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):
|
class Tunneling(ConfigTemplate):
|
||||||
config_values = BaseTemplate.config_values
|
config_values = copy(BaseTemplate.config_values)
|
||||||
|
|
||||||
config_values.update({
|
config_values.update({
|
||||||
"basic.exploiters.exploiter_classes": ["SmbExploiter",
|
"basic.exploiters.exploiter_classes": ["SmbExploiter",
|
||||||
|
@ -13,6 +16,8 @@ class Tunneling(BaseTemplate):
|
||||||
"10.2.1.10",
|
"10.2.1.10",
|
||||||
"10.2.0.11",
|
"10.2.0.11",
|
||||||
"10.2.0.12"],
|
"10.2.0.12"],
|
||||||
|
"basic_network.scope.depth": 3,
|
||||||
|
"internal.general.keep_tunnel_open_time": 180,
|
||||||
"basic.credentials.exploit_password_list": ["Password1!",
|
"basic.credentials.exploit_password_list": ["Password1!",
|
||||||
"3Q=(Ge(+&w]*",
|
"3Q=(Ge(+&w]*",
|
||||||
"`))jU7L(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):
|
class WmiMimikatz(ConfigTemplate):
|
||||||
config_values = BaseTemplate.config_values
|
config_values = copy(BaseTemplate.config_values)
|
||||||
|
|
||||||
config_values.update({
|
config_values.update({
|
||||||
"basic.exploiters.exploiter_classes": ["WmiExploiter"],
|
"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 typing_extensions import Type
|
||||||
|
|
||||||
from envs.monkey_zoo.blackbox.island_client.monkey_island_client import MonkeyIslandClient
|
from envs.monkey_zoo.blackbox.island_client.monkey_island_client import MonkeyIslandClient
|
||||||
from envs.monkey_zoo.blackbox.island_configs.config_template import ConfigTemplate
|
from envs.monkey_zoo.blackbox.config_templates.config_template import ConfigTemplate
|
||||||
|
|
||||||
|
|
||||||
class IslandConfigParser:
|
class IslandConfigParser:
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
from time import sleep
|
from time import sleep
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
from bson import json_util
|
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
|
SLEEP_BETWEEN_REQUESTS_SECONDS = 0.5
|
||||||
MONKEY_TEST_ENDPOINT = 'api/test/monkey'
|
MONKEY_TEST_ENDPOINT = 'api/test/monkey'
|
||||||
|
TELEMETRY_TEST_ENDPOINT = 'api/test/telemetry'
|
||||||
LOG_TEST_ENDPOINT = 'api/test/log'
|
LOG_TEST_ENDPOINT = 'api/test/log'
|
||||||
LOGGER = logging.getLogger(__name__)
|
LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -67,6 +69,13 @@ class MonkeyIslandClient(object):
|
||||||
MonkeyIslandClient.form_find_query_for_request(query))
|
MonkeyIslandClient.form_find_query_for_request(query))
|
||||||
return MonkeyIslandClient.get_test_query_results(response)
|
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):
|
def get_all_monkeys_from_db(self):
|
||||||
response = self.requests.get(MONKEY_TEST_ENDPOINT,
|
response = self.requests.get(MONKEY_TEST_ENDPOINT,
|
||||||
MonkeyIslandClient.form_find_query_for_request(None))
|
MonkeyIslandClient.form_find_query_for_request(None))
|
||||||
|
@ -78,7 +87,7 @@ class MonkeyIslandClient(object):
|
||||||
return MonkeyIslandClient.get_test_query_results(response)
|
return MonkeyIslandClient.get_test_query_results(response)
|
||||||
|
|
||||||
@staticmethod
|
@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)}
|
return {'find_query': json_util.dumps(query)}
|
||||||
|
|
||||||
@staticmethod
|
@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 \
|
from envs.monkey_zoo.blackbox.analyzers.communication_analyzer import \
|
||||||
CommunicationAnalyzer
|
CommunicationAnalyzer
|
||||||
|
from envs.monkey_zoo.blackbox.analyzers.zerologon_analyzer import ZerologonAnalyzer
|
||||||
from envs.monkey_zoo.blackbox.island_client.island_config_parser import \
|
from envs.monkey_zoo.blackbox.island_client.island_config_parser import \
|
||||||
IslandConfigParser
|
IslandConfigParser
|
||||||
from envs.monkey_zoo.blackbox.island_client.monkey_island_client import \
|
from envs.monkey_zoo.blackbox.island_client.monkey_island_client import \
|
||||||
MonkeyIslandClient
|
MonkeyIslandClient
|
||||||
from envs.monkey_zoo.blackbox.island_configs.config_template import ConfigTemplate
|
from envs.monkey_zoo.blackbox.config_templates.config_template import ConfigTemplate
|
||||||
from envs.monkey_zoo.blackbox.island_configs.elastic import Elastic
|
from envs.monkey_zoo.blackbox.config_templates.drupal import Drupal
|
||||||
from envs.monkey_zoo.blackbox.island_configs.hadoop import Hadoop
|
from envs.monkey_zoo.blackbox.config_templates.elastic import Elastic
|
||||||
from envs.monkey_zoo.blackbox.island_configs.mssql import Mssql
|
from envs.monkey_zoo.blackbox.config_templates.hadoop import Hadoop
|
||||||
from envs.monkey_zoo.blackbox.island_configs.performance import Performance
|
from envs.monkey_zoo.blackbox.config_templates.mssql import Mssql
|
||||||
from envs.monkey_zoo.blackbox.island_configs.shellshock import ShellShock
|
from envs.monkey_zoo.blackbox.config_templates.performance import Performance
|
||||||
from envs.monkey_zoo.blackbox.island_configs.smb_mimikatz import SmbMimikatz
|
from envs.monkey_zoo.blackbox.config_templates.shellshock import ShellShock
|
||||||
from envs.monkey_zoo.blackbox.island_configs.smb_pth import SmbPth
|
from envs.monkey_zoo.blackbox.config_templates.smb_mimikatz import SmbMimikatz
|
||||||
from envs.monkey_zoo.blackbox.island_configs.ssh import Ssh
|
from envs.monkey_zoo.blackbox.config_templates.smb_pth import SmbPth
|
||||||
from envs.monkey_zoo.blackbox.island_configs.struts2 import Struts2
|
from envs.monkey_zoo.blackbox.config_templates.ssh import Ssh
|
||||||
from envs.monkey_zoo.blackbox.island_configs.tunneling import Tunneling
|
from envs.monkey_zoo.blackbox.config_templates.struts2 import Struts2
|
||||||
from envs.monkey_zoo.blackbox.island_configs.weblogic import Weblogic
|
from envs.monkey_zoo.blackbox.config_templates.tunneling import Tunneling
|
||||||
from envs.monkey_zoo.blackbox.island_configs.wmi_mimikatz import WmiMimikatz
|
from envs.monkey_zoo.blackbox.config_templates.weblogic import Weblogic
|
||||||
from envs.monkey_zoo.blackbox.island_configs.wmi_pth import WmiPth
|
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 \
|
from envs.monkey_zoo.blackbox.log_handlers.test_logs_handler import \
|
||||||
TestLogsHandler
|
TestLogsHandler
|
||||||
from envs.monkey_zoo.blackbox.tests.exploitation import ExploitationTest
|
from envs.monkey_zoo.blackbox.tests.exploitation import ExploitationTest
|
||||||
|
@ -44,8 +47,10 @@ DEFAULT_TIMEOUT_SECONDS = 5*60
|
||||||
MACHINE_BOOTUP_WAIT_SECONDS = 30
|
MACHINE_BOOTUP_WAIT_SECONDS = 30
|
||||||
GCP_TEST_MACHINE_LIST = ['sshkeys-11', 'sshkeys-12', 'elastic-4', 'elastic-5', 'hadoop-2', 'hadoop-3', 'mssql-16',
|
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',
|
'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"
|
LOG_DIR_PATH = "./logs"
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
LOGGER = logging.getLogger(__name__)
|
LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@ -138,6 +143,9 @@ class TestMonkeyBlackbox:
|
||||||
def test_smb_pth(self, island_client):
|
def test_smb_pth(self, island_client):
|
||||||
TestMonkeyBlackbox.run_exploitation_test(island_client, SmbPth, "SMB_PTH")
|
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):
|
def test_elastic_exploiter(self, island_client):
|
||||||
TestMonkeyBlackbox.run_exploitation_test(island_client, Elastic, "Elastic_exploiter")
|
TestMonkeyBlackbox.run_exploitation_test(island_client, Elastic, "Elastic_exploiter")
|
||||||
|
|
||||||
|
@ -159,6 +167,22 @@ class TestMonkeyBlackbox:
|
||||||
def test_wmi_pth(self, island_client):
|
def test_wmi_pth(self, island_client):
|
||||||
TestMonkeyBlackbox.run_exploitation_test(island_client, WmiPth, "WMI_PTH")
|
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.")
|
@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):
|
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"
|
name = "zerologon-25"
|
||||||
project = local.monkeyzoo_project
|
project = local.monkeyzoo_project
|
||||||
}
|
}
|
||||||
|
data "google_compute_image" "drupal-28" {
|
||||||
|
name = "drupal-28"
|
||||||
|
project = local.monkeyzoo_project
|
||||||
|
}
|
||||||
data "google_compute_image" "island-linux-250" {
|
data "google_compute_image" "island-linux-250" {
|
||||||
name = "island-linux-250"
|
name = "island-linux-250"
|
||||||
project = local.monkeyzoo_project
|
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" {
|
resource "google_compute_instance_from_template" "island-linux-250" {
|
||||||
name = "${local.resource_prefix}island-linux-250"
|
name = "${local.resource_prefix}island-linux-250"
|
||||||
machine_type = "n1-standard-2"
|
machine_type = "n1-standard-2"
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit 9de1e78ba475f925c66c5b645564ec9eb08e2309
|
|
|
@ -1,5 +1,8 @@
|
||||||
# abstract, static method decorator
|
# abstract, static method decorator
|
||||||
# noinspection PyPep8Naming
|
# noinspection PyPep8Naming
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
|
||||||
class abstractstatic(staticmethod):
|
class abstractstatic(staticmethod):
|
||||||
__slots__ = ()
|
__slots__ = ()
|
||||||
|
|
||||||
|
@ -8,3 +11,10 @@ class abstractstatic(staticmethod):
|
||||||
function.__isabstractmethod__ = True
|
function.__isabstractmethod__ = True
|
||||||
|
|
||||||
__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
|
from pathlib import Path
|
||||||
|
|
||||||
MAJOR = "1"
|
MAJOR = "1"
|
||||||
MINOR = "9"
|
MINOR = "10"
|
||||||
PATCH = "0"
|
PATCH = "0"
|
||||||
build_file_path = Path(__file__).parent.joinpath("BUILD")
|
build_file_path = Path(__file__).parent.joinpath("BUILD")
|
||||||
with open(build_file_path, "r") as build_file:
|
with open(build_file_path, "r") as build_file:
|
||||||
|
|
|
@ -134,7 +134,9 @@ class MonkeyDrops(object):
|
||||||
'monkey_commandline': inner_monkey_cmdline}
|
'monkey_commandline': inner_monkey_cmdline}
|
||||||
|
|
||||||
monkey_process = subprocess.Popen(monkey_cmdline, shell=True,
|
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)
|
close_fds=True, creationflags=DETACHED_PROCESS)
|
||||||
|
|
||||||
LOG.info("Executed monkey process (PID=%d) with command line: %s",
|
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")
|
LOG.warning("Seems like monkey died too soon")
|
||||||
|
|
||||||
def cleanup(self):
|
def cleanup(self):
|
||||||
|
LOG.info("Cleaning up the dropper")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if (self._config['source_path'].lower() != self._config['destination_path'].lower()) and \
|
if (self._config['source_path'].lower() != self._config['destination_path'].lower()) and \
|
||||||
os.path.exists(self._config['source_path']) 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",
|
LOG.debug("Dropper source file '%s' is marked for deletion on next boot",
|
||||||
self._config['source_path'])
|
self._config['source_path'])
|
||||||
T1106Telem(ScanStatus.USED, UsageEnum.DROPPER_WINAPI).send()
|
T1106Telem(ScanStatus.USED, UsageEnum.DROPPER_WINAPI).send()
|
||||||
|
|
||||||
|
LOG.info("Dropper cleanup complete")
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
LOG.error("Invalid configuration options. Failing")
|
LOG.error("Invalid configuration options. Failing")
|
||||||
|
|
|
@ -36,6 +36,7 @@ class DrupalExploiter(WebRCE):
|
||||||
exploit_config = super(DrupalExploiter, self).get_exploit_config()
|
exploit_config = super(DrupalExploiter, self).get_exploit_config()
|
||||||
exploit_config['url_extensions'] = ['node/', # In Linux, no path is added
|
exploit_config['url_extensions'] = ['node/', # In Linux, no path is added
|
||||||
'drupal/node/'] # However, Bitnami installations are under /drupal
|
'drupal/node/'] # However, Bitnami installations are under /drupal
|
||||||
|
exploit_config['dropper'] = True
|
||||||
return exploit_config
|
return exploit_config
|
||||||
|
|
||||||
def add_vulnerable_urls(self, potential_urls, stop_checking=False):
|
def add_vulnerable_urls(self, potential_urls, stop_checking=False):
|
||||||
|
|
|
@ -252,9 +252,12 @@ class InfectionMonkey(object):
|
||||||
|
|
||||||
def collect_system_info_if_configured(self):
|
def collect_system_info_if_configured(self):
|
||||||
LOG.debug("Calling for system info collection")
|
LOG.debug("Calling for system info collection")
|
||||||
|
try:
|
||||||
system_info_collector = SystemInfoCollector()
|
system_info_collector = SystemInfoCollector()
|
||||||
system_info = system_info_collector.get_info()
|
system_info = system_info_collector.get_info()
|
||||||
SystemInfoTelem(system_info).send()
|
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):
|
def shutdown_by_not_alive_config(self):
|
||||||
if not WormConfiguration.alive:
|
if not WormConfiguration.alive:
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
# -*- mode: python -*-
|
# -*- mode: python -*-
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
import platform
|
import platform
|
||||||
|
import sys
|
||||||
|
|
||||||
__author__ = 'itay.mizeretz'
|
__author__ = 'itay.mizeretz'
|
||||||
|
|
||||||
|
from PyInstaller.utils.hooks import collect_data_files
|
||||||
|
|
||||||
block_cipher = None
|
block_cipher = None
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
print(collect_data_files('policyuniverse'))
|
||||||
a = Analysis(['main.py'],
|
a = Analysis(['main.py'],
|
||||||
pathex=['..'],
|
pathex=['..'],
|
||||||
hiddenimports=get_hidden_imports(),
|
hiddenimports=get_hidden_imports(),
|
||||||
hookspath=['./pyinstaller_hooks'],
|
hookspath=['./pyinstaller_hooks'],
|
||||||
runtime_hooks=None,
|
runtime_hooks=None,
|
||||||
binaries=None,
|
binaries=None,
|
||||||
datas=[
|
datas=[("../common/BUILD", "/common")],
|
||||||
("../common/BUILD", "/common")
|
|
||||||
],
|
|
||||||
excludes=None,
|
excludes=None,
|
||||||
win_no_prefer_redirects=None,
|
win_no_prefer_redirects=None,
|
||||||
win_private_assemblies=None,
|
win_private_assemblies=None,
|
||||||
|
@ -48,7 +48,7 @@ def is_windows():
|
||||||
|
|
||||||
|
|
||||||
def is_32_bit():
|
def is_32_bit():
|
||||||
return sys.maxsize <= 2**32
|
return sys.maxsize <= 2 ** 32
|
||||||
|
|
||||||
|
|
||||||
def get_bin_folder():
|
def get_bin_folder():
|
||||||
|
@ -79,7 +79,10 @@ def get_linux_only_binaries():
|
||||||
|
|
||||||
|
|
||||||
def get_hidden_imports():
|
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():
|
def get_sc_binaries():
|
||||||
|
@ -94,15 +97,15 @@ def get_traceroute_binaries():
|
||||||
def get_monkey_filename():
|
def get_monkey_filename():
|
||||||
name = 'monkey-'
|
name = 'monkey-'
|
||||||
if is_windows():
|
if is_windows():
|
||||||
name = name+"windows-"
|
name = name + "windows-"
|
||||||
else:
|
else:
|
||||||
name = name+"linux-"
|
name = name + "linux-"
|
||||||
if is_32_bit():
|
if is_32_bit():
|
||||||
name = name+"32"
|
name = name + "32"
|
||||||
else:
|
else:
|
||||||
name = name+"64"
|
name = name + "64"
|
||||||
if is_windows():
|
if is_windows():
|
||||||
name = name+".exe"
|
name = name + ".exe"
|
||||||
return name
|
return name
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -43,8 +43,8 @@ class HTTPFinger(HostFinger):
|
||||||
LOG.info("Port %d is open on host %s " % (port[0], host))
|
LOG.info("Port %d is open on host %s " % (port[0], host))
|
||||||
break # https will be the same on the same port
|
break # https will be the same on the same port
|
||||||
except Timeout:
|
except Timeout:
|
||||||
pass
|
LOG.debug(f"Timout while requesting headers from {url}")
|
||||||
except ConnectionError: # Someone doesn't like us
|
except ConnectionError: # Someone doesn't like us
|
||||||
pass
|
LOG.debug(f"Connection error while requesting headers from {url}")
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -15,10 +15,6 @@ LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
__author__ = 'VakarisZ'
|
__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_WINDOWS = 'cd %s & '
|
||||||
DIR_CHANGE_LINUX = 'cd %s ; '
|
DIR_CHANGE_LINUX = 'cd %s ; '
|
||||||
|
|
||||||
|
@ -31,30 +27,23 @@ class UsersPBA(PBA):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(UsersPBA, self).__init__(POST_BREACH_FILE_EXECUTION)
|
super(UsersPBA, self).__init__(POST_BREACH_FILE_EXECUTION)
|
||||||
self.filename = ''
|
self.filename = ''
|
||||||
|
|
||||||
if not is_windows_os():
|
if not is_windows_os():
|
||||||
# Add linux commands to PBA's
|
# Add linux commands to PBA's
|
||||||
if WormConfiguration.PBA_linux_filename:
|
if WormConfiguration.PBA_linux_filename:
|
||||||
|
self.filename = WormConfiguration.PBA_linux_filename
|
||||||
if WormConfiguration.custom_PBA_linux_cmd:
|
if WormConfiguration.custom_PBA_linux_cmd:
|
||||||
# Add change dir command, because user will try to access his file
|
# 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.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:
|
elif WormConfiguration.custom_PBA_linux_cmd:
|
||||||
self.command = WormConfiguration.custom_PBA_linux_cmd
|
self.command = WormConfiguration.custom_PBA_linux_cmd
|
||||||
else:
|
else:
|
||||||
# Add windows commands to PBA's
|
# Add windows commands to PBA's
|
||||||
if WormConfiguration.PBA_windows_filename:
|
if WormConfiguration.PBA_windows_filename:
|
||||||
|
self.filename = WormConfiguration.PBA_windows_filename
|
||||||
if WormConfiguration.custom_PBA_windows_cmd:
|
if WormConfiguration.custom_PBA_windows_cmd:
|
||||||
# Add change dir command, because user will try to access his file
|
# 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.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:
|
elif WormConfiguration.custom_PBA_windows_cmd:
|
||||||
self.command = 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
|
WinSys-3.x>=0.5.2
|
||||||
cffi>=1.14
|
cffi>=1.14
|
||||||
ecdsa==0.15
|
ecdsa==0.15
|
||||||
|
@ -15,3 +16,6 @@ pypykatz==0.3.12
|
||||||
pysmb==1.2.5
|
pysmb==1.2.5
|
||||||
requests>=2.24
|
requests>=2.24
|
||||||
wmi==1.5.1 ; sys_platform == 'win32'
|
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
|
import logging
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
import infection_monkey.system_info.collectors.scoutsuite_collector.scoutsuite_api as scoutsuite_api
|
import ScoutSuite.api_run
|
||||||
from common.cloud.scoutsuite.ScoutSuite.providers.base.provider import BaseProvider
|
from ScoutSuite.providers.base.provider import BaseProvider
|
||||||
|
|
||||||
from common.cloud.scoutsuite_consts import CloudProviders
|
from common.cloud.scoutsuite_consts import CloudProviders
|
||||||
from common.utils.exceptions import ScoutSuiteScanError
|
from common.utils.exceptions import ScoutSuiteScanError
|
||||||
from infection_monkey.config import WormConfiguration
|
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]:
|
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_access_key_id=WormConfiguration.aws_access_key_id,
|
||||||
aws_secret_access_key=WormConfiguration.aws_secret_access_key,
|
aws_secret_access_key=WormConfiguration.aws_secret_access_key,
|
||||||
aws_session_token=WormConfiguration.aws_session_token)
|
aws_session_token=WormConfiguration.aws_session_token)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import logging
|
import logging
|
||||||
import os
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from common.common_consts.system_info_collectors_names import MIMIKATZ_COLLECTOR
|
from common.common_consts.system_info_collectors_names import MIMIKATZ_COLLECTOR
|
||||||
|
@ -46,16 +46,21 @@ class WindowsInfoCollector(InfoCollector):
|
||||||
return self.info
|
return self.info
|
||||||
|
|
||||||
def get_installed_packages(self):
|
def get_installed_packages(self):
|
||||||
LOG.info('getting installed packages')
|
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()
|
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')
|
LOG.debug('Got installed packages')
|
||||||
|
|
||||||
def get_wmi_info(self):
|
def get_wmi_info(self):
|
||||||
LOG.info('getting wmi info')
|
LOG.info('Getting wmi info')
|
||||||
for wmi_class_name in WMI_CLASSES:
|
for wmi_class_name in WMI_CLASSES:
|
||||||
self.info['wmi'][wmi_class_name] = WMIUtils.get_wmi_class(wmi_class_name)
|
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):
|
def get_mimikatz_info(self):
|
||||||
LOG.info("Gathering mimikatz info")
|
LOG.info("Gathering mimikatz info")
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from common.cloud.scoutsuite.ScoutSuite.output.result_encoder import ScoutJsonEncoder
|
from ScoutSuite.output.result_encoder import ScoutJsonEncoder
|
||||||
from common.cloud.scoutsuite.ScoutSuite.providers.base.provider import BaseProvider
|
from ScoutSuite.providers.base.provider import BaseProvider
|
||||||
from common.common_consts.telem_categories import TelemCategoryEnum
|
from common.common_consts.telem_categories import TelemCategoryEnum
|
||||||
from infection_monkey.telemetry.base_telem import BaseTelem
|
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
|
import monkey_island.cc.environment.environment_singleton as env_singleton
|
||||||
from common.common_consts.api_url_consts import T1216_PBA_FILE_DOWNLOAD_PATH
|
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.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.consts import MONKEY_ISLAND_ABS_PATH
|
||||||
from monkey_island.cc.server_utils.custom_json_encoder import CustomJSONEncoder
|
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(ScoutSuiteAuth, '/api/scoutsuite_auth/<string:provider>')
|
||||||
api.add_resource(AWSKeys, '/api/aws_keys')
|
api.add_resource(AWSKeys, '/api/aws_keys')
|
||||||
|
|
||||||
|
# Resources used by black box tests
|
||||||
api.add_resource(MonkeyTest, '/api/test/monkey')
|
api.add_resource(MonkeyTest, '/api/test/monkey')
|
||||||
api.add_resource(ClearCaches, '/api/test/clear_caches')
|
api.add_resource(ClearCaches, '/api/test/clear_caches')
|
||||||
api.add_resource(LogTest, '/api/test/log')
|
api.add_resource(LogTest, '/api/test/log')
|
||||||
|
api.add_resource(TelemetryTest, '/api/test/telemetry')
|
||||||
|
|
||||||
|
|
||||||
def init_app(mongo_url):
|
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"
|
__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):
|
class T1065(AttackTechnique):
|
||||||
|
|
|
@ -14,7 +14,7 @@ from monkey_island.cc.services.config_schema.config_schema import SCHEMA
|
||||||
|
|
||||||
__author__ = "itay.mizeretz"
|
__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,
|
LM_HASH_LIST_PATH, NTLM_HASH_LIST_PATH,
|
||||||
PASSWORD_LIST_PATH, SSH_KEYS_PATH,
|
PASSWORD_LIST_PATH, SSH_KEYS_PATH,
|
||||||
STARTED_ON_ISLAND_PATH, USER_LIST_PATH)
|
STARTED_ON_ISLAND_PATH, USER_LIST_PATH)
|
||||||
|
|
|
@ -159,7 +159,8 @@ INTERNAL = {
|
||||||
8080,
|
8080,
|
||||||
443,
|
443,
|
||||||
8008,
|
8008,
|
||||||
7001
|
7001,
|
||||||
|
9200
|
||||||
],
|
],
|
||||||
"description": "List of ports the monkey will check if are being used for HTTP"
|
"description": "List of ports the monkey will check if are being used for HTTP"
|
||||||
},
|
},
|
||||||
|
@ -181,7 +182,6 @@ INTERNAL = {
|
||||||
443,
|
443,
|
||||||
8008,
|
8008,
|
||||||
3306,
|
3306,
|
||||||
9200,
|
|
||||||
7001,
|
7001,
|
||||||
8088
|
8088
|
||||||
],
|
],
|
||||||
|
|
|
@ -11,33 +11,39 @@ MONKEY = {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"custom_PBA_linux_cmd": {
|
"custom_PBA_linux_cmd": {
|
||||||
"title": "Linux post breach command",
|
"title": "Linux post-breach command",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "",
|
"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": {
|
"PBA_linux_file": {
|
||||||
"title": "Linux post breach file",
|
"title": "Linux post-breach file",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "data-url",
|
"format": "data-url",
|
||||||
"description": "File to be executed after breaching. "
|
"description": "File to be uploaded after breaching. "
|
||||||
"If you want custom execution behavior, "
|
"Use the 'Linux post-breach command' field to "
|
||||||
"specify it in 'Linux post breach command' field. "
|
"change permissions, run, or delete the file. "
|
||||||
"Reference your file by filename."
|
"Reference your file by filename."
|
||||||
},
|
},
|
||||||
"custom_PBA_windows_cmd": {
|
"custom_PBA_windows_cmd": {
|
||||||
"title": "Windows post breach command",
|
"title": "Windows post-breach command",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "",
|
"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": {
|
"PBA_windows_file": {
|
||||||
"title": "Windows post breach file",
|
"title": "Windows post-breach file",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "data-url",
|
"format": "data-url",
|
||||||
"description": "File to be executed after breaching. "
|
"description": "File to be uploaded after breaching. "
|
||||||
"If you want custom execution behavior, "
|
"Use the 'Windows post-breach command' field to "
|
||||||
"specify it in 'Windows post breach command' field. "
|
"change permissions, run, or delete the file. "
|
||||||
"Reference your file by filename."
|
"Reference your file by filename."
|
||||||
},
|
},
|
||||||
"PBA_windows_filename": {
|
"PBA_windows_filename": {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from monkey_island.cc.services.config import ConfigService
|
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():
|
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.models import Monkey
|
||||||
from monkey_island.cc.services.utils.network_utils import get_subnets, local_ip_addresses
|
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 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,
|
PASSWORD_LIST_PATH, SUBNET_SCAN_LIST_PATH,
|
||||||
USER_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.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.database import mongo
|
||||||
from monkey_island.cc.models.zero_trust.scoutsuite_data_json import ScoutSuiteRawDataJson
|
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.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.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_rule_service import ScoutSuiteRuleService
|
||||||
from monkey_island.cc.services.zero_trust.scoutsuite.scoutsuite_zt_finding_service import ScoutSuiteZTFindingService
|
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'])
|
telemetry_json['data'] = json.dumps(telemetry_json['data'])
|
||||||
ScoutSuiteRawDataJson.add_scoutsuite_data(telemetry_json['data'])
|
ScoutSuiteRawDataJson.add_scoutsuite_data(telemetry_json['data'])
|
||||||
scoutsuite_data = json.loads(telemetry_json['data'])['data']
|
scoutsuite_data = json.loads(telemetry_json['data'])['data']
|
||||||
create_scoutsuite_findings(scoutsuite_data)
|
create_scoutsuite_findings(scoutsuite_data[SERVICES])
|
||||||
update_data(telemetry_json)
|
update_data(telemetry_json)
|
||||||
|
|
||||||
|
|
||||||
def create_scoutsuite_findings(scoutsuite_data):
|
def create_scoutsuite_findings(cloud_services: dict):
|
||||||
for finding in SCOUTSUITE_FINDINGS:
|
for finding in SCOUTSUITE_FINDINGS:
|
||||||
for rule in finding.rules:
|
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)
|
rule = ScoutSuiteRuleService.get_rule_from_rule_data(rule_data)
|
||||||
ScoutSuiteZTFindingService.process_rule(finding, rule)
|
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
|
from enum import Enum
|
||||||
|
|
||||||
import dpath.util
|
from common.utils.code_utils import get_value_from_dict
|
||||||
|
|
||||||
from common.utils.exceptions import RulePathCreatorNotFound
|
from common.utils.exceptions import RulePathCreatorNotFound
|
||||||
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_path_building.rule_path_creators_list import \
|
from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_path_building.rule_path_creators_list import \
|
||||||
RULE_PATH_CREATORS_LIST
|
RULE_PATH_CREATORS_LIST
|
||||||
|
@ -23,7 +22,7 @@ class RuleParser:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_rule_data(scoutsuite_data: dict, rule_name: Enum) -> dict:
|
def get_rule_data(scoutsuite_data: dict, rule_name: Enum) -> dict:
|
||||||
rule_path = RuleParser._get_rule_path(rule_name)
|
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
|
@staticmethod
|
||||||
def _get_rule_path(rule_name: Enum):
|
def _get_rule_path(rule_name: Enum):
|
||||||
|
|
|
@ -3,7 +3,7 @@ from enum import Enum
|
||||||
from typing import List, Type
|
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.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):
|
class AbstractRulePathCreator(ABC):
|
||||||
|
@ -21,4 +21,4 @@ class AbstractRulePathCreator(ABC):
|
||||||
@classmethod
|
@classmethod
|
||||||
def build_rule_path(cls, rule_name: Enum) -> List[str]:
|
def build_rule_path(cls, rule_name: Enum) -> List[str]:
|
||||||
assert(rule_name in cls.supported_rules)
|
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 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.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.scoutsuite.data_parsing.rule_parser import RuleParser
|
||||||
from monkey_island.cc.services.zero_trust.test_common.raw_scoutsute_data import RAW_SCOUTSUITE_DATA
|
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():
|
def test_get_rule_data():
|
||||||
# Test proper parsing of the raw data to rule
|
# 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
|
assert results == EXPECTED_RESULT
|
||||||
|
|
||||||
with pytest.raises(RulePathCreatorNotFound):
|
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
|
pass
|
||||||
|
|
|
@ -6,7 +6,7 @@ from common.cloud.scoutsuite_consts import CloudProviders
|
||||||
from common.utils.exceptions import InvalidAWSKeys
|
from common.utils.exceptions import InvalidAWSKeys
|
||||||
from monkey_island.cc.server_utils.encryptor import encryptor
|
from monkey_island.cc.server_utils.encryptor import encryptor
|
||||||
from monkey_island.cc.services.config import ConfigService
|
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]:
|
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():
|
if is_aws_keys_setup():
|
||||||
return True, "AWS keys already 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:
|
try:
|
||||||
profile = auth_strategy.AWSAuthenticationStrategy().authenticate()
|
profile = auth_strategy.AWSAuthenticationStrategy().authenticate()
|
||||||
return True, f" Profile \"{profile.session.profile_name}\" is already setup. "
|
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.database import mongo
|
||||||
from monkey_island.cc.server_utils import encryptor
|
from monkey_island.cc.server_utils import encryptor
|
||||||
from monkey_island.cc.services.config import ConfigService
|
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.services.zero_trust.scoutsuite.scoutsuite_auth_service import is_aws_keys_setup
|
||||||
from monkey_island.cc.test_common.fixtures import FixtureEnum
|
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])`
|
To profile specific methods on island a `@profile(sort_args=['cumulative'], print_args=[100])`
|
||||||
decorator can be used.
|
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
|
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`
|
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
|
was profiled, then the results of this profiling will appear in
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.9.0",
|
"version": "1.10.0",
|
||||||
"name": "infection-monkey",
|
"name": "infection-monkey",
|
||||||
"description": "Infection Monkey C&C UI",
|
"description": "Infection Monkey C&C UI",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
@ -43,7 +43,7 @@ class AdvancedMultiSelect extends React.Component {
|
||||||
infoPaneParams: getDefaultPaneParams(
|
infoPaneParams: getDefaultPaneParams(
|
||||||
this.infoPaneRefString,
|
this.infoPaneRefString,
|
||||||
this.registry,
|
this.registry,
|
||||||
this.isUnsafeOptionSelected(this.props.value)
|
this.isUnsafeOptionSelected(props.value)
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -94,9 +94,11 @@ class AdvancedMultiSelect extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
setMasterCheckboxState(selectValues) {
|
setMasterCheckboxState(selectValues) {
|
||||||
this.setState(() => ({
|
let newState = this.getMasterCheckboxState(selectValues);
|
||||||
masterCheckboxState: this.getMasterCheckboxState(selectValues)
|
|
||||||
}));
|
if (newState != this.state.masterCheckboxState) {
|
||||||
|
this.setState({masterCheckboxState: newState});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getMasterCheckboxState(selectValues) {
|
getMasterCheckboxState(selectValues) {
|
||||||
|
@ -162,11 +164,12 @@ class AdvancedMultiSelect extends React.Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
schema,
|
autofocus,
|
||||||
id,
|
id,
|
||||||
required,
|
|
||||||
multiple,
|
multiple,
|
||||||
autofocus
|
required,
|
||||||
|
schema,
|
||||||
|
value
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -179,7 +182,7 @@ class AdvancedMultiSelect extends React.Component {
|
||||||
<ChildCheckboxContainer id={id} multiple={multiple} required={required}
|
<ChildCheckboxContainer id={id} multiple={multiple} required={required}
|
||||||
autoFocus={autofocus} isSafe={this.isSafe}
|
autoFocus={autofocus} isSafe={this.isSafe}
|
||||||
onPaneClick={this.setPaneInfo} onCheckboxClick={this.onChildCheckboxClick}
|
onPaneClick={this.setPaneInfo} onCheckboxClick={this.onChildCheckboxClick}
|
||||||
selectedValues={this.props.value} enumOptions={this.enumOptions}/>
|
selectedValues={value} enumOptions={this.enumOptions}/>
|
||||||
|
|
||||||
<InfoPane title={this.state.infoPaneParams.title}
|
<InfoPane title={this.state.infoPaneParams.title}
|
||||||
body={this.state.infoPaneParams.content}
|
body={this.state.infoPaneParams.content}
|
||||||
|
@ -188,6 +191,10 @@ class AdvancedMultiSelect extends React.Component {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(_prevProps) {
|
||||||
|
this.setMasterCheckboxState(this.props.value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AdvancedMultiSelect;
|
export default AdvancedMultiSelect;
|
||||||
|
|
|
@ -26,5 +26,6 @@ tqdm>=4.47
|
||||||
virtualenv>=20.0.26
|
virtualenv>=20.0.26
|
||||||
werkzeug>=1.0.1
|
werkzeug>=1.0.1
|
||||||
wheel>=0.34.2
|
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