Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions nxc/helpers/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,20 @@ def gen_random_string(length=10):
return "".join(random.sample(string.ascii_letters, int(length)))


_HOSTNAME_SANITIZE_RE = re.compile(r"[^\w\-.]")


def sanitize_hostname(hostname, logger=None):
Comment thread
NeffIsBack marked this conversation as resolved.
Outdated
"""Strip characters from a server-provided hostname that could cause path
traversal, newline injection, or format-string issues when used in file
paths or output content. Logs a warning when the value is modified.
"""
sanitized = _HOSTNAME_SANITIZE_RE.sub("_", hostname)
if sanitized != hostname and logger:
logger.display(f"Hostname contained invalid characters (received: {hostname!r}), sanitized to: {sanitized!r}")
Comment thread
NeffIsBack marked this conversation as resolved.
Outdated
return sanitized


def validate_ntlm(data):
allowed = re.compile(r"^[0-9a-f]{32}", re.IGNORECASE)
return bool(allowed.match(data))
Expand Down
4 changes: 2 additions & 2 deletions nxc/protocols/mssql.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from nxc.config import process_secret, host_info_colors
from nxc.connection import connection
from nxc.connection import requires_admin
from nxc.helpers.misc import gen_random_string
from nxc.helpers.misc import gen_random_string, sanitize_hostname
from nxc.logger import NXCAdapter
from nxc.helpers.bloodhound import add_user_bh
from nxc.helpers.negotiate_parser import parse_challenge, login7_integrated_auth_error_message
Expand Down Expand Up @@ -138,7 +138,7 @@ def enum_host_info(self):
if challenge.startswith(b"NTLMSSP\x00"):
ntlm_info = parse_challenge(challenge)
self.targetDomain = self.domain = ntlm_info["domain"]
self.hostname = ntlm_info["hostname"]
self.hostname = sanitize_hostname(ntlm_info["hostname"], self.logger)
self.server_os = ntlm_info["os_version"]
self.logger.extra["hostname"] = self.hostname
else:
Expand Down
3 changes: 2 additions & 1 deletion nxc/protocols/rdp.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from impacket.krb5.ccache import CCache

from nxc.connection import connection
from nxc.helpers.misc import sanitize_hostname
from nxc.helpers.bloodhound import add_user_bh
from nxc.logger import NXCAdapter
from nxc.config import host_info_colors, process_secret
Expand Down Expand Up @@ -142,7 +143,7 @@ def create_conn_obj(self):
pass
else:
self.domain = info_domain["dnsdomainname"]
self.hostname = info_domain["computername"]
self.hostname = sanitize_hostname(info_domain["computername"], self.logger)
self.server_os = info_domain["os_guess"] + " Build " + str(info_domain["os_build"])
self.logger.extra["hostname"] = self.hostname
break
Expand Down
2 changes: 2 additions & 0 deletions nxc/protocols/smb.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import ipaddress
from Cryptodome.Hash import MD4
from textwrap import dedent
from nxc.helpers.misc import sanitize_hostname

from impacket.smbconnection import SMBConnection, SessionError
from impacket.smb import SMB_DIALECT
Expand Down Expand Up @@ -200,6 +201,7 @@ def enum_host_info(self):
self.hostname = dns_hostname
else:
self.hostname = self.conn.getServerName()
self.hostname = sanitize_hostname(self.hostname, self.logger)
self.targetDomain = self.conn.getServerDNSDomainName()
if not self.targetDomain: # Not sure if that can even happen but now we are safe
self.targetDomain = self.hostname
Expand Down
3 changes: 2 additions & 1 deletion nxc/protocols/winrm.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import xml.etree.ElementTree as ET

from pypsrp.wsman import NAMESPACES
from nxc.helpers.misc import sanitize_hostname
from pypsrp.client import Client
from pypsrp.powershell import PSDataStreams
from termcolor import colored
Expand Down Expand Up @@ -68,7 +69,7 @@ def enum_host_info(self):
return False

self.targetDomain = self.domain = ntlm_info["domain"]
self.hostname = ntlm_info["hostname"]
self.hostname = sanitize_hostname(ntlm_info["hostname"], self.logger)
self.server_os = ntlm_info["os_version"]
self.logger.extra["hostname"] = self.hostname

Expand Down
3 changes: 2 additions & 1 deletion nxc/protocols/wmi.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from io import StringIO

from nxc.helpers.negotiate_parser import parse_challenge
from nxc.helpers.misc import sanitize_hostname
from nxc.config import process_secret
from nxc.connection import connection, dcom_FirewallChecker, requires_admin
from nxc.logger import NXCAdapter
Expand Down Expand Up @@ -130,7 +131,7 @@ def enum_host_info(self):
bindResp = MSRPCBindAck(response.getData())
ntlm_info = parse_challenge(bindResp["auth_data"])
self.targetDomain = self.domain = ntlm_info["domain"]
self.hostname = ntlm_info["hostname"]
self.hostname = sanitize_hostname(ntlm_info["hostname"], self.logger)
self.server_os = ntlm_info["os_version"]
self.logger.extra["hostname"] = self.hostname
else:
Expand Down