Skip to content

Commit

Permalink
Merge branch 'release/2.2.0'
Browse files Browse the repository at this point in the history
Release Infection Monkey v2.2.0
  • Loading branch information
mssalvatore committed May 31, 2023
2 parents da83f6e + 06cbb84 commit 08a0f41
Show file tree
Hide file tree
Showing 406 changed files with 15,544 additions and 5,161 deletions.
4 changes: 3 additions & 1 deletion .flake8
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ max-line-length = 100
per-file-ignores =
__init__.py:F401
monkey/tests/unit_tests/infection_monkey/island_api_client/configuration_validation_constants.py:E501
monkey/agent_plugins/exploiters/zerologon/src/zerologon.py:C901
monkey/monkey_island/cc/services/reporting/report.py:C901

### ignore "whitespace before ':'", "line break before binary operator" for
### compatibility with black, and cyclomatic complexity (for now).
extend-ignore = E203, W503, C901
extend-ignore = E203, W503

### --statistics Count the number of occurrences of each error/warning code and print a report.
statistics = True
Expand Down
36 changes: 36 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,42 @@ file.
The format is based on [Keep a
Changelog](https://keepachangelog.com/en/1.0.0/).

## [2.2.0 - 2023-05-31]
### Added
- `PortScanData.open` property. #3238
- `{GET,PUT} /api/agent-binaries/<string:os>/masque`. #3249
- Placeholder values for empty plugin configuration fields having defaults. #3310
- Malware masquerading. #3241, #3242, #3243
- Support for plugin manifest files with the "yml" extension. #3097
- Randomize Agent binary hash (polymorphism) feature. #3244
- Agent binary's SHA256 to `AgentRegistrationData`. #3244
- `EmailAddress` identity type. #3270
- SNMP exploiter (CVE-2020-15862). #3234
- A plugin interface for credentials collectors. #3167

### Changed
- Renamed "Credential collector" to "Credentials collector". #3167
- Hard-coded WMI exploiter to a plugin. #3163
- Hard-coded Mimikatz credentials collector to a plugin. #3168
- Hard-coded Zerologon exploiter to a plugin. #3164
- Hard-coded SSH credentials collector to a plugin. #3169
- SSH credentials collector's private-key search algorithm. #1882
- Manual run command includes all Island IP addresses. #2593
- Hard-coded MSSQL exploiter to a plugin. #3171
- Hard-coded PowerShell exploiter to a plugin. #3165

### Fixed
- Plugins are now being checked for local OS compatibility. #3275
- A bug that could prevent multi-hop propagation via SMB. #3173
- Exceptions being raised when WMI and Zerologon are used together. #1774
- A bug that caused failing configuration imports to be marked as successful. #3341
- A bug where target hostnames with dashes were not being scanned. #3231
- A bug in URL sanitization. #3318

### Security
- Fixes a bug where OTPs can be leaked by the hadoop exploiter. #3296
- Fixes pypykatz leaking sensitive information into the logs. #3168, #3293

## [2.1.0] - 2023-04-19
### Added
- Logout button. #3063
Expand Down
17 changes: 17 additions & 0 deletions docs/content/reference/exploiters/SNMP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
title: "SNMP"
date: 2023-05-15T12:53:22+00:00
draft: false
tags: ["exploit", "linux"]
---

The SNMP exploiter exploits [CVE-2020-15862](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-15862).


### Description

If a community is configured with read-write access, the machine is vulnerable to an attack using NET-SNMP-EXTEND-MIB to run arbitrary commands on the victim.

In versions 1 and 2c of the SNMP protocol the only means of authentication is the community string. In these versions of SNMP, community strings are sent as plaintext in all requests. Version 3 adds user-based authentication and encryption to the SNMP protocol.

This exploiter uses version 2c of the SNMP protocol. It brute-forces machines by using usernames and passwords provided by the user (see [configuration]({{< ref "/usage/configuration" >}}) for instructions) as SNMP community strings.
14 changes: 7 additions & 7 deletions docs/content/setup/linux.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ On Windows, AppImage can be run in WSL 2.

1. Make the AppImage package executable:
```bash
chmod u+x InfectionMonkey-v2.0.0.AppImage
chmod u+x InfectionMonkey-v2.2.0.AppImage
```
1. Start Monkey Island by running the Infection Monkey AppImage package:
```bash
./InfectionMonkey-v2.0.0.AppImage
./InfectionMonkey-v2.2.0.AppImage
```

If you get errors related to FUSE, you may need to install FUSE 2.X first:
Expand All @@ -58,12 +58,12 @@ The Infection Monkey can be installed as a service and run on boot by running th
with the following parameters. This requires root permissions, so run `sudo -v` and enter your
password before running the script, if required.
```bash
./InfectionMonkey-v2.0.0.AppImage service --install --user <USERNAME>
./InfectionMonkey-v2.2.0.AppImage service --install --user <USERNAME>
```

To uninstall it, run:
```bash
./InfectionMonkey-v2.0.0.AppImage service --uninstall
./InfectionMonkey-v2.2.0.AppImage service --uninstall
```

{{% notice info %}}
Expand All @@ -77,7 +77,7 @@ You can configure the server by creating
a [server configuration file](../../reference/server_configuration) and
providing a path to it via command line parameters:

`./InfectionMonkey-v2.0.0.AppImage --server-config="/path/to/server_config.json"`
`./InfectionMonkey-v2.2.0.AppImage --server-config="/path/to/server_config.json"`

### Start Monkey Island with user-provided certificate

Expand Down Expand Up @@ -113,7 +113,7 @@ The server configuration file should look something like:
1. Start Monkey Island by running the Infection Monkey AppImage package:
```bash
./InfectionMonkey-v2.0.0.AppImage --server-config="/path/to/server_config.json"
./InfectionMonkey-v2.2.0.AppImage --server-config="/path/to/server_config.json"
```
1. Access the Monkey Island web UI by pointing your browser at
Expand All @@ -134,7 +134,7 @@ The server configuration file should look something like:

1. Start Monkey Island by running the Infection Monkey AppImage package:
```bash
./InfectionMonkey-v2.0.0.AppImage --server-config="/path/to/server_config.json"
./InfectionMonkey-v2.2.0.AppImage --server-config="/path/to/server_config.json"
```

1. Access the Monkey Island web UI by pointing your browser at
Expand Down
2 changes: 1 addition & 1 deletion docs/content/usage/configuration/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ title: "Configuration"
date: 2020-06-07T19:08:51+03:00
draft: false
chapter: true
weight: 3
weight: 6
pre: "<i class='fas fa-sliders-h'></i> "
---

Expand Down
15 changes: 10 additions & 5 deletions docs/content/usage/file-checksums.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,22 @@ $ sha256sum <FILE_NAME>

| Filename | Type | Version | SHA256 |
|------------------------------------------------------|-------------------|---------|--------------------------------------------------------------------|
| monkey-windows-64.exe | Windows Agent | 2.1.0 | `883b16c9f8d9a532da6787a1a088bef6fabba782058bcedbd1e02afc613b88c2` |
| monkey-linux-64 | Linux Agent | 2.1.0 | `d7217665f714fbde6657f3b4ac60182779dfd2668fc9a308a77fc595be711252` |
| InfectionMonkey-v2.1.0.AppImage | Linux Package | 2.1.0 | `a788e693d4e785e039aad513ebd626be1d265e961a2f44dc06df3c9eae33cd8e` |
| InfectionMonkey-docker-v2.1.0.tgz | Docker | 2.1.0 | `d78c8bcc71988932c22b867f74ec71e5c5b99e204e959ad0fe55e7552a1b8928` |
| InfectionMonkey-v2.1.0.exe | Windows Installer | 2.1.0 | `62095752eee71776f050712670c42c57d2fa439ca5f842cb1ff0830e52b2bdc0` |
| InfectionMonkey-docker-v2.2.0.tgz | Docker | 2.2.0 | `486c92ac892f98f8248b5460008d9d4397cb28e6c2f73f12fcecc109ab2412f7` |
| InfectionMonkey-v2.2.0.AppImage | Linux Package | 2.2.0 | `bc54f74c0745bb0dc453e3916f0eaaf6ded4a023df3180569e1953fd69c9520e` |
| InfectionMonkey-v2.2.0.exe | Windows Installer | 2.2.0 | `06677c33e741e549c6a45716338c56cbdc7209db1338bd8c2cae5cff9d80b69c` |
| monkey-linux-64 | Linux Agent | 2.2.0 | `18ce2217edcc240d11c96bf7ff05bebf4fd4af9fa1b43246badf12b4d4a3a0c2` |
| monkey-windows-64.exe | Windows Agent | 2.2.0 | `c6cb10d1a206d9b08cef4a383a7941cf39e0b7e956d4d272cf8f6e775cfca6ac` |


## Older checksums

| Filename | Type | Version | SHA256 |
|------------------------------------------------------|-------------------|---------|--------------------------------------------------------------------|
| monkey-windows-64.exe | Windows Agent | 2.1.0 | `883b16c9f8d9a532da6787a1a088bef6fabba782058bcedbd1e02afc613b88c2` |
| monkey-linux-64 | Linux Agent | 2.1.0 | `d7217665f714fbde6657f3b4ac60182779dfd2668fc9a308a77fc595be711252` |
| InfectionMonkey-v2.1.0.AppImage | Linux Package | 2.1.0 | `a788e693d4e785e039aad513ebd626be1d265e961a2f44dc06df3c9eae33cd8e` |
| InfectionMonkey-docker-v2.1.0.tgz | Docker | 2.1.0 | `d78c8bcc71988932c22b867f74ec71e5c5b99e204e959ad0fe55e7552a1b8928` |
| InfectionMonkey-v2.1.0.exe | Windows Installer | 2.1.0 | `62095752eee71776f050712670c42c57d2fa439ca5f842cb1ff0830e52b2bdc0` |
| monkey-windows-64.exe | Windows Agent | 2.0.0 | `7d848e1cc4855b8476b27e81dfb01b4e38a2d0a421f80507b08a99ab7c71e4ea` |
| monkey-linux-64 | Linux Agent | 2.0.0 | `07c8ed75f1a83ace2d018f4645b7a147c31075f41963a1d801e4e5133014189a` |
| InfectionMonkey-v2.0.0.AppImage | Linux Package | 2.0.0 | `b40ffde3e55f2b2198e8f26c44a1beb33a84a0979764a47ffb5ce26f07f4fa8e` |
Expand Down
39 changes: 39 additions & 0 deletions docs/content/usage/malware-masquerade.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
title: "Malware Masquerade"
date: 2023-05-08T13:57:22-04:00
draft: false
weight: 4
pre: "<i class='fas fa-mask'></i> "
tags: ["usage"]
---

## Description
**Masquerade** - to assume the appearance of something one is not
[[1](https://www.merriam-webster.com/dictionary/masquerade)]

A common way of detecting and identifying an executable as malware is to write
a detection rule (such as for a tool like YARA) that checks for the existence
of strings or unique byte sequences within a file. The Malware Masquerade
feature allows users to specify strings or arbitrary data (bytes) that will be
injected into the Agent binaries. This enables Infection Monkey Agents to
masquerade as specific types of malware. This is particularly useful for anyone
who writes their own detection rules and needs a way to test them, or anyone
looking to improve the fidelity of malware simulations.

## Using Malware Masquerade

![Malware Masquerade Configuration](/images/island/configuration_page/malware_masquerade_configuration.png "Malware masquerade configuration")

### Configuring Strings

The UI allows you to specify any number of strings to include within the Linux
or Windows Agent binaries. It's as simple as adding these strings to either
list in the "Masquerade" tab of the "Configuration" screen and clicking
"Submit". You can verify the success of this operation by downloading the
binary and using the Linux `strings` command.
[[2](https://linux.die.net/man/1/strings)]


```bash
curl https://<SERVER_IP>:5000/api/agent-binaries/linux -k -o monkey-linux-64 && strings monkey-linux-64 | grep <MY_STRING>
```
21 changes: 21 additions & 0 deletions docs/content/usage/polymorphism.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
title: "Polymorphism"
date: 2023-05-16T15:19:06+05:30
draft: false
weight: 5
pre: "<i class='fas fa-file-signature'></i> "
tags: ["usage", "polymorphism"]
---


## Description
Polymorphic malware, or metamorphic malware, is a kind of malware that repeatedly
modifies its appearance or signature. As a result, no two copies of the malware share
the same hash. This helps the malware evade detection.

Infection Monkey is not truly metamorphic, but it has the ability to emulate this
property by adding random bytes to each Agent before propagation.

## Using Polymorphism

![Polymorphism Configuration](/images/island/configuration_page/polymorphism_configuration.png "Polymorphism configuration")
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions envs/monkey_zoo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,20 @@ Terraform scripts allows you to quickly setup a network that’s full of
vulnerable machines to regression test monkey’s exploiters, evaluate
scanning times in a real-world scenario and many more.

## Building MonkeyZoo Images

### Requirements
- [Packer](https://developer.hashicorp.com/packer/downloads)
- [Ansible](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html#installing-ansible)
- A [GCP Service Account](https://developers.google.com/identity/protocols/oauth2/service-account#creatinganaccount) for the project in which to create the images
- This account should have `Service Account User` and `Compute Instance Admin` permissions
- A GCP key file for the service account

Run envs/monkey_zoo/build_images.sh to build the images for the MonkeyZoo. These are the images from which the zoo will be deployed.

Example:
./build_images.sh --project my-gcp-project --account-file /path/to/gcp_key.json packer/tunneling.pkr.hcl

## MonkeyZoo network

Check [MonkeyZoo network](docs/zoo_network.md) documentation on how machines are setup
Expand Down
2 changes: 1 addition & 1 deletion envs/monkey_zoo/blackbox/analyzers/analyzer_log.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def clear(self):
self.contents = ""

def add_entry(self, message):
self.contents = "{}\n{}".format(self.contents, message)
self.contents = "{}\n\t{}".format(self.contents, message)

def get_contents(self):
return "{}: {}\n".format(self.name, self.contents)
37 changes: 37 additions & 0 deletions envs/monkey_zoo/blackbox/analyzers/stolen_credentials_analyzer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from typing import Set

from common.credentials import Credentials
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


class StolenCredentialsAnalyzer(Analyzer):
def __init__(
self, island_client: MonkeyIslandClient, expected_stolen_credentials: Set[Credentials]
):
self.island_client = island_client
self.expected_stolen_credentials = set(expected_stolen_credentials)

self.log = AnalyzerLog(self.__class__.__name__)

def analyze_test_results(self) -> bool:
self.log.clear()

stolen_credentials = set(self.island_client.get_stolen_credentials())

if self.expected_stolen_credentials == stolen_credentials:
self.log.add_entry("All expected credentials were stolen")
return True

if len(stolen_credentials) != len(self.expected_stolen_credentials):
self.log.add_entry(
f"Expected {len(self.expected_stolen_credentials)} credentials to be stolen but "
f"{len(stolen_credentials)} were stolen"
)
elif self.expected_stolen_credentials != stolen_credentials:
self.log.add_entry(
"The contents of the stolen credentials did not match the expected credentials"
)

return False
10 changes: 2 additions & 8 deletions envs/monkey_zoo/blackbox/gcp_test_machine_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"log4j-solr-50",
"log4j-tomcat-51",
"log4j-tomcat-52",
"snmp-20",
],
}

Expand All @@ -53,6 +54,7 @@
"log4j-solr-50",
"log4j-tomcat-51",
"log4j-tomcat-52",
"snmp-20",
],
}

Expand Down Expand Up @@ -93,13 +95,6 @@
],
}

WMI_AND_MIMIKATZ = {
"europe-west3-a": [
"mimikatz-14",
"mimikatz-15",
]
}

SMB_PTH = {"europe-west3-a": ["mimikatz-15"]}

GCP_SINGLE_TEST_LIST = {
Expand All @@ -109,6 +104,5 @@
"test_depth_4_a": DEPTH_4_A,
"test_zerologon_exploiter": ZEROLOGON,
"test_credentials_reuse_ssh_key": CREDENTIALS_REUSE_SSH_KEY,
"test_wmi_and_mimikatz_exploiters": WMI_AND_MIMIKATZ,
"test_smb_pth": SMB_PTH,
}
21 changes: 21 additions & 0 deletions envs/monkey_zoo/blackbox/island_client/monkey_island_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from http import HTTPStatus
from typing import List, Mapping, Optional, Sequence

from common import OperatingSystem
from common.credentials import Credentials
from common.types import AgentID, MachineID
from envs.monkey_zoo.blackbox.island_client.i_monkey_island_requests import IMonkeyIslandRequests
Expand Down Expand Up @@ -34,10 +35,29 @@ def __init__(self, requests: IMonkeyIslandRequests):
def get_api_status(self):
return self.requests.get("api")

@avoid_race_condition
def set_masque(self, masque):
masque = b"" if masque is None else masque
for operating_system in [operating_system.name for operating_system in OperatingSystem]:
if self.requests.put(f"api/agent-binaries/{operating_system}/masque", data=masque).ok:
formatted_masque = masque if len(masque) <= 64 else (masque[:64] + b"...")
LOGGER.info(f'Setting {operating_system} masque to "{formatted_masque}"')
else:
LOGGER.error(f"Failed to set {operating_system} masque")
assert False

def get_agent_binary(self, operating_system: OperatingSystem) -> bytes:
response = self.requests.get(f"api/agent-binaries/{operating_system.name}")
return response.content

def get_propagation_credentials(self) -> Sequence[Credentials]:
response = self.requests.get("api/propagation-credentials")
return [Credentials(**credentials) for credentials in response.json()]

def get_stolen_credentials(self) -> Sequence[Credentials]:
response = self.requests.get("api/propagation-credentials/stolen-credentials")
return [Credentials(**credentials) for credentials in response.json()]

@avoid_race_condition
def import_config(self, test_configuration: TestConfiguration):
self._set_island_mode()
Expand Down Expand Up @@ -113,6 +133,7 @@ def reset_island(self):
self._reset_simulation_data()
self._reset_credentials()
self._reset_island_mode()
self.set_masque(b"")

def _reset_agent_configuration(self):
if self.requests.post("api/reset-agent-configuration", data=None).ok:
Expand Down
Loading

0 comments on commit 08a0f41

Please sign in to comment.