Agent: Decouple dropper target paths from the config
* Dropper target paths are now part of infection_monkey.model
This commit is contained in:
parent
49654d4dfe
commit
b8e943f7a8
|
@ -43,7 +43,7 @@ class HadoopExploiter(WebRCE):
|
||||||
return self.exploit_result
|
return self.exploit_result
|
||||||
|
|
||||||
try:
|
try:
|
||||||
monkey_path_on_victim = get_agent_dest_path(self.host, self.options)
|
monkey_path_on_victim = get_agent_dest_path(self.host)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return self.exploit_result
|
return self.exploit_result
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,7 @@ class Log4ShellExploiter(WebRCE):
|
||||||
self._agent_http_server_thread = None
|
self._agent_http_server_thread = None
|
||||||
|
|
||||||
def _start_servers(self):
|
def _start_servers(self):
|
||||||
target_path = get_agent_dest_path(self.host, self.options)
|
target_path = get_agent_dest_path(self.host)
|
||||||
|
|
||||||
# Start http server, to serve agent to victims
|
# Start http server, to serve agent to victims
|
||||||
agent_http_path = self._start_agent_http_server(target_path)
|
agent_http_path = self._start_agent_http_server(target_path)
|
||||||
|
|
|
@ -59,7 +59,7 @@ class MSSQLExploiter(HostExploiter):
|
||||||
Also, don't forget to start_monkey_server() before self.upload_monkey() and
|
Also, don't forget to start_monkey_server() before self.upload_monkey() and
|
||||||
self.stop_monkey_server() after
|
self.stop_monkey_server() after
|
||||||
"""
|
"""
|
||||||
monkey_path_on_victim = get_agent_dest_path(self.host, self.options)
|
monkey_path_on_victim = get_agent_dest_path(self.host)
|
||||||
|
|
||||||
# Brute force to get connection
|
# Brute force to get connection
|
||||||
creds = generate_identity_secret_pairs(
|
creds = generate_identity_secret_pairs(
|
||||||
|
|
|
@ -134,7 +134,7 @@ class PowerShellExploiter(HostExploiter):
|
||||||
raise ValueError(f"Unknown secret type {credentials.secret_type}")
|
raise ValueError(f"Unknown secret type {credentials.secret_type}")
|
||||||
|
|
||||||
def _execute_monkey_agent_on_victim(self):
|
def _execute_monkey_agent_on_victim(self):
|
||||||
monkey_path_on_victim = get_agent_dest_path(self.host, self.options)
|
monkey_path_on_victim = get_agent_dest_path(self.host)
|
||||||
|
|
||||||
self._copy_monkey_binary_to_victim(monkey_path_on_victim)
|
self._copy_monkey_binary_to_victim(monkey_path_on_victim)
|
||||||
logger.info("Successfully copied the monkey binary to the victim.")
|
logger.info("Successfully copied the monkey binary to the victim.")
|
||||||
|
|
|
@ -31,7 +31,7 @@ class SMBExploiter(HostExploiter):
|
||||||
|
|
||||||
def _exploit_host(self):
|
def _exploit_host(self):
|
||||||
agent_binary = self.agent_repository.get_agent_binary(self.host.os["type"])
|
agent_binary = self.agent_repository.get_agent_binary(self.host.os["type"])
|
||||||
dest_path = get_agent_dest_path(self.host, self.options)
|
dest_path = get_agent_dest_path(self.host)
|
||||||
creds = generate_brute_force_combinations(self.options["credentials"])
|
creds = generate_brute_force_combinations(self.options["credentials"])
|
||||||
|
|
||||||
for user, password, lm_hash, ntlm_hash in interruptible_iter(creds, self.interrupt):
|
for user, password, lm_hash, ntlm_hash in interruptible_iter(creds, self.interrupt):
|
||||||
|
|
|
@ -209,7 +209,7 @@ class SSHExploiter(HostExploiter):
|
||||||
self._set_interrupted()
|
self._set_interrupted()
|
||||||
return self.exploit_result
|
return self.exploit_result
|
||||||
|
|
||||||
monkey_path_on_victim = get_agent_dest_path(self.host, self.options)
|
monkey_path_on_victim = get_agent_dest_path(self.host)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with ssh.open_sftp() as ftp:
|
with ssh.open_sftp() as ftp:
|
||||||
|
|
|
@ -2,9 +2,8 @@ import logging
|
||||||
import random
|
import random
|
||||||
import string
|
import string
|
||||||
from pathlib import PurePath, PurePosixPath, PureWindowsPath
|
from pathlib import PurePath, PurePosixPath, PureWindowsPath
|
||||||
from typing import Any, Mapping
|
|
||||||
|
|
||||||
from infection_monkey.model import VictimHost
|
from infection_monkey.model import DROPPER_TARGET_PATH_LINUX, DROPPER_TARGET_PATH_WIN64, VictimHost
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -18,11 +17,11 @@ def get_random_file_suffix() -> str:
|
||||||
return random_string
|
return random_string
|
||||||
|
|
||||||
|
|
||||||
def get_agent_dest_path(host: VictimHost, options: Mapping[str, Any]) -> PurePath:
|
def get_agent_dest_path(host: VictimHost) -> PurePath:
|
||||||
if host.os["type"] == "windows":
|
if host.os["type"] == "windows":
|
||||||
path = PureWindowsPath(options["dropper_target_path_win_64"])
|
path = PureWindowsPath(DROPPER_TARGET_PATH_WIN64)
|
||||||
else:
|
else:
|
||||||
path = PurePosixPath(options["dropper_target_path_linux"])
|
path = PurePosixPath(DROPPER_TARGET_PATH_LINUX)
|
||||||
|
|
||||||
return _add_random_suffix(path)
|
return _add_random_suffix(path)
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,8 @@ from infection_monkey.model import (
|
||||||
CHMOD_MONKEY,
|
CHMOD_MONKEY,
|
||||||
DOWNLOAD_TIMEOUT,
|
DOWNLOAD_TIMEOUT,
|
||||||
DROPPER_ARG,
|
DROPPER_ARG,
|
||||||
|
DROPPER_TARGET_PATH_LINUX,
|
||||||
|
DROPPER_TARGET_PATH_WIN64,
|
||||||
ID_STRING,
|
ID_STRING,
|
||||||
MONKEY_ARG,
|
MONKEY_ARG,
|
||||||
POWERSHELL_HTTP_UPLOAD,
|
POWERSHELL_HTTP_UPLOAD,
|
||||||
|
@ -109,8 +111,8 @@ class WebRCE(HostExploiter):
|
||||||
def pre_exploit(self):
|
def pre_exploit(self):
|
||||||
if not self.monkey_target_paths:
|
if not self.monkey_target_paths:
|
||||||
self.monkey_target_paths = {
|
self.monkey_target_paths = {
|
||||||
"linux": self.options["dropper_target_path_linux"],
|
"linux": DROPPER_TARGET_PATH_LINUX,
|
||||||
"windows": self.options["dropper_target_path_win_64"],
|
"windows": DROPPER_TARGET_PATH_WIN64,
|
||||||
}
|
}
|
||||||
self.HTTP = [str(port) for port in self.options["http_ports"]]
|
self.HTTP = [str(port) for port in self.options["http_ports"]]
|
||||||
super().pre_exploit()
|
super().pre_exploit()
|
||||||
|
@ -405,7 +407,6 @@ class WebRCE(HostExploiter):
|
||||||
"""
|
"""
|
||||||
Gets default dropper path for the host.
|
Gets default dropper path for the host.
|
||||||
:return: Default monkey's destination path for corresponding host or False if failed.
|
:return: Default monkey's destination path for corresponding host or False if failed.
|
||||||
E.g. config.dropper_target_path_linux(/tmp/monkey.sh) for linux host
|
|
||||||
"""
|
"""
|
||||||
if not self.host.os.get("type") or (
|
if not self.host.os.get("type") or (
|
||||||
self.host.os["type"] != "linux" and self.host.os["type"] != "windows"
|
self.host.os["type"] != "linux" and self.host.os["type"] != "windows"
|
||||||
|
@ -413,9 +414,9 @@ class WebRCE(HostExploiter):
|
||||||
logger.error("Target's OS was either unidentified or not supported. Aborting")
|
logger.error("Target's OS was either unidentified or not supported. Aborting")
|
||||||
return False
|
return False
|
||||||
if self.host.os["type"] == "linux":
|
if self.host.os["type"] == "linux":
|
||||||
return self.options["dropper_target_path_linux"]
|
return DROPPER_TARGET_PATH_LINUX
|
||||||
if self.host.os["type"] == "windows":
|
if self.host.os["type"] == "windows":
|
||||||
return self.options["dropper_target_path_win_64"]
|
return DROPPER_TARGET_PATH_WIN64
|
||||||
|
|
||||||
def get_target_url(self):
|
def get_target_url(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -10,7 +10,11 @@ from infection_monkey.exploit.tools.helpers import get_agent_dest_path
|
||||||
from infection_monkey.exploit.tools.smb_tools import SmbTools
|
from infection_monkey.exploit.tools.smb_tools import SmbTools
|
||||||
from infection_monkey.exploit.tools.wmi_tools import AccessDeniedException, WmiTools
|
from infection_monkey.exploit.tools.wmi_tools import AccessDeniedException, WmiTools
|
||||||
from infection_monkey.i_puppet import ExploiterResultData
|
from infection_monkey.i_puppet import ExploiterResultData
|
||||||
from infection_monkey.model import DROPPER_CMDLINE_WINDOWS, MONKEY_CMDLINE_WINDOWS
|
from infection_monkey.model import (
|
||||||
|
DROPPER_CMDLINE_WINDOWS,
|
||||||
|
DROPPER_TARGET_PATH_WIN64,
|
||||||
|
MONKEY_CMDLINE_WINDOWS,
|
||||||
|
)
|
||||||
from infection_monkey.utils.brute_force import (
|
from infection_monkey.utils.brute_force import (
|
||||||
generate_brute_force_combinations,
|
generate_brute_force_combinations,
|
||||||
get_credential_string,
|
get_credential_string,
|
||||||
|
@ -74,7 +78,7 @@ class WmiExploiter(HostExploiter):
|
||||||
self._set_interrupted()
|
self._set_interrupted()
|
||||||
return self.exploit_result
|
return self.exploit_result
|
||||||
|
|
||||||
target_path = get_agent_dest_path(self.host, self.options)
|
target_path = get_agent_dest_path(self.host)
|
||||||
|
|
||||||
remote_full_path = SmbTools.copy_file(
|
remote_full_path = SmbTools.copy_file(
|
||||||
self.host,
|
self.host,
|
||||||
|
@ -91,13 +95,13 @@ class WmiExploiter(HostExploiter):
|
||||||
wmi_connection.close()
|
wmi_connection.close()
|
||||||
return self.exploit_result
|
return self.exploit_result
|
||||||
# execute the remote dropper in case the path isn't final
|
# execute the remote dropper in case the path isn't final
|
||||||
elif remote_full_path.lower() != self.options["dropper_target_path_win_64"]:
|
elif remote_full_path.lower() != DROPPER_TARGET_PATH_WIN64:
|
||||||
cmdline = DROPPER_CMDLINE_WINDOWS % {
|
cmdline = DROPPER_CMDLINE_WINDOWS % {
|
||||||
"dropper_path": remote_full_path
|
"dropper_path": remote_full_path
|
||||||
} + build_monkey_commandline(
|
} + build_monkey_commandline(
|
||||||
self.host,
|
self.host,
|
||||||
self.current_depth - 1,
|
self.current_depth - 1,
|
||||||
self.options["dropper_target_path_win_64"],
|
DROPPER_TARGET_PATH_WIN64,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
cmdline = MONKEY_CMDLINE_WINDOWS % {
|
cmdline = MONKEY_CMDLINE_WINDOWS % {
|
||||||
|
|
|
@ -5,6 +5,10 @@ MONKEY_ARG = "m0nk3y"
|
||||||
DROPPER_ARG = "dr0pp3r"
|
DROPPER_ARG = "dr0pp3r"
|
||||||
ID_STRING = "M0NK3Y3XPL0ITABLE"
|
ID_STRING = "M0NK3Y3XPL0ITABLE"
|
||||||
|
|
||||||
|
# Dropper target paths
|
||||||
|
DROPPER_TARGET_PATH_LINUX = "/tmp/monkey"
|
||||||
|
DROPPER_TARGET_PATH_WIN64 = r"C:\Windows\temp\monkey64.exe"
|
||||||
|
|
||||||
# Username prefix for users created by Infection Monkey
|
# Username prefix for users created by Infection Monkey
|
||||||
USERNAME_PREFIX = "somenewuser"
|
USERNAME_PREFIX = "somenewuser"
|
||||||
|
|
||||||
|
|
|
@ -21,8 +21,6 @@
|
||||||
"custom_PBA_linux_cmd": "bash test.sh",
|
"custom_PBA_linux_cmd": "bash test.sh",
|
||||||
"custom_PBA_windows_cmd": "powershell test.ps1",
|
"custom_PBA_windows_cmd": "powershell test.ps1",
|
||||||
"depth": 2,
|
"depth": 2,
|
||||||
"dropper_target_path_linux": "/tmp/monkey",
|
|
||||||
"dropper_target_path_win_64": "C:\\Windows\\temp\\monkey64.exe",
|
|
||||||
"exploit_lm_hash_list": ["lm_hash_1", "lm_hash_2"],
|
"exploit_lm_hash_list": ["lm_hash_1", "lm_hash_2"],
|
||||||
"exploit_ntlm_hash_list": ["nt_hash_1", "nt_hash_2", "nt_hash_3"],
|
"exploit_ntlm_hash_list": ["nt_hash_1", "nt_hash_2", "nt_hash_3"],
|
||||||
"exploit_password_list": [
|
"exploit_password_list": [
|
||||||
|
|
|
@ -96,10 +96,6 @@
|
||||||
"ElasticFinger"
|
"ElasticFinger"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"dropper": {
|
|
||||||
"dropper_target_path_linux": "/tmp/monkey",
|
|
||||||
"dropper_target_path_win_64": "C:\\Windows\\temp\\monkey64.exe"
|
|
||||||
},
|
|
||||||
"exploits": {
|
"exploits": {
|
||||||
"exploit_lm_hash_list": [],
|
"exploit_lm_hash_list": [],
|
||||||
"exploit_ntlm_hash_list": [],
|
"exploit_ntlm_hash_list": [],
|
||||||
|
|
|
@ -5,6 +5,8 @@ from unittest.mock import MagicMock
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from infection_monkey.exploit import powershell
|
from infection_monkey.exploit import powershell
|
||||||
|
from infection_monkey.exploit.tools.helpers import RAND_SUFFIX_LEN
|
||||||
|
from infection_monkey.model import DROPPER_TARGET_PATH_WIN64
|
||||||
from infection_monkey.model.host import VictimHost
|
from infection_monkey.model.host import VictimHost
|
||||||
|
|
||||||
# Use the path_win32api_get_user_name fixture for all tests in this module
|
# Use the path_win32api_get_user_name fixture for all tests in this module
|
||||||
|
@ -14,7 +16,6 @@ USER_LIST = ["user1", "user2"]
|
||||||
PASSWORD_LIST = ["pass1", "pass2"]
|
PASSWORD_LIST = ["pass1", "pass2"]
|
||||||
LM_HASH_LIST = ["bogo_lm_1"]
|
LM_HASH_LIST = ["bogo_lm_1"]
|
||||||
NT_HASH_LIST = ["bogo_nt_1", "bogo_nt_2"]
|
NT_HASH_LIST = ["bogo_nt_1", "bogo_nt_2"]
|
||||||
DROPPER_TARGET_PATH_64 = "C:\\agent64"
|
|
||||||
|
|
||||||
|
|
||||||
mock_agent_repository = MagicMock()
|
mock_agent_repository = MagicMock()
|
||||||
|
@ -24,7 +25,6 @@ mock_agent_repository.get_agent_binary.return_value = BytesIO(b"BINARY_EXECUTABL
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def powershell_arguments(http_and_https_both_enabled_host):
|
def powershell_arguments(http_and_https_both_enabled_host):
|
||||||
options = {
|
options = {
|
||||||
"dropper_target_path_win_64": DROPPER_TARGET_PATH_64,
|
|
||||||
"credentials": {
|
"credentials": {
|
||||||
"exploit_user_list": USER_LIST,
|
"exploit_user_list": USER_LIST,
|
||||||
"exploit_password_list": PASSWORD_LIST,
|
"exploit_password_list": PASSWORD_LIST,
|
||||||
|
@ -114,7 +114,10 @@ def test_successful_copy(monkeypatch, powershell_exploiter, powershell_arguments
|
||||||
|
|
||||||
exploit_result = powershell_exploiter.exploit_host(**powershell_arguments)
|
exploit_result = powershell_exploiter.exploit_host(**powershell_arguments)
|
||||||
|
|
||||||
assert DROPPER_TARGET_PATH_64 in str(mock_client.return_value.copy_file.call_args[0][1])
|
# Check if the copied agent name has randomness of 8 plus dash
|
||||||
|
assert len(str(DROPPER_TARGET_PATH_WIN64)) + RAND_SUFFIX_LEN + 1 == len(
|
||||||
|
str(mock_client.return_value.copy_file.call_args[0][1])
|
||||||
|
)
|
||||||
assert exploit_result.exploitation_success
|
assert exploit_result.exploitation_success
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,38 +3,39 @@ from unittest.mock import Mock
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from infection_monkey.exploit.tools.helpers import RAND_SUFFIX_LEN, get_agent_dest_path
|
from infection_monkey.exploit.tools.helpers import RAND_SUFFIX_LEN, get_agent_dest_path
|
||||||
|
from infection_monkey.model import DROPPER_TARGET_PATH_LINUX, DROPPER_TARGET_PATH_WIN64
|
||||||
|
|
||||||
|
|
||||||
def _get_host_and_options(os, path):
|
def _get_host(os):
|
||||||
host = Mock()
|
host = Mock()
|
||||||
host.os = {"type": os}
|
host.os = {"type": os}
|
||||||
options = {"dropper_target_path_win_64": path, "dropper_target_path_linux": path}
|
return host
|
||||||
return host, options
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("os", ["windows", "linux"])
|
@pytest.mark.parametrize(
|
||||||
@pytest.mark.parametrize("path", ["C:\\monkey.exe", "/tmp/monkey-linux-64", "mon.key.exe"])
|
"os, path", [("linux", DROPPER_TARGET_PATH_LINUX), ("windows", DROPPER_TARGET_PATH_WIN64)]
|
||||||
|
)
|
||||||
def test_get_agent_dest_path(os, path):
|
def test_get_agent_dest_path(os, path):
|
||||||
host, options = _get_host_and_options(os, path)
|
host = _get_host(os)
|
||||||
rand_path = get_agent_dest_path(host, options)
|
rand_path = get_agent_dest_path(host)
|
||||||
|
|
||||||
# Assert that filename got longer by RAND_SUFFIX_LEN and one dash
|
# Assert that filename got longer by RAND_SUFFIX_LEN and one dash
|
||||||
assert len(str(rand_path)) == (len(str(path)) + RAND_SUFFIX_LEN + 1)
|
assert len(str(rand_path)) == (len(str(path)) + RAND_SUFFIX_LEN + 1)
|
||||||
|
|
||||||
|
|
||||||
def test_get_agent_dest_path_randomness():
|
def test_get_agent_dest_path_randomness():
|
||||||
host, options = _get_host_and_options("windows", "monkey.exe")
|
host = _get_host("windows")
|
||||||
|
|
||||||
path1 = get_agent_dest_path(host, options)
|
path1 = get_agent_dest_path(host)
|
||||||
path2 = get_agent_dest_path(host, options)
|
path2 = get_agent_dest_path(host)
|
||||||
|
|
||||||
assert path1 != path2
|
assert path1 != path2
|
||||||
|
|
||||||
|
|
||||||
def test_get_agent_dest_path_str_place():
|
def test_get_agent_dest_path_str_place():
|
||||||
host, options = _get_host_and_options("windows", "C:\\abc\\monkey.exe")
|
host = _get_host("windows")
|
||||||
|
|
||||||
rand_path = get_agent_dest_path(host, options)
|
rand_path = get_agent_dest_path(host)
|
||||||
|
|
||||||
assert str(rand_path).startswith("C:\\abc\\monkey-")
|
assert str(rand_path).startswith(r"C:\Windows\temp\monkey")
|
||||||
assert str(rand_path).endswith(".exe")
|
assert str(rand_path).endswith(".exe")
|
||||||
|
|
Loading…
Reference in New Issue