-
Notifications
You must be signed in to change notification settings - Fork 648
Description
Describe the bug
When connecting to an MSSQL instance that does not support Windows authentication, NetExec attempts NTLM negotiation and crashes while parsing the server response as an NTLMSSP challenge. The server instead returns a valid TDS error packet stating that Windows logins are not supported.
This results in an unhandled exception during enum_host_info().
Microsoft SQL Server 2014 (12.00.924.00, Pre‑RTM)
TCP 1433 open
SQL Authentication only? (Windows auth disabled?)
Encryption required (TLS)
To Reproduce
Steps to reproduce the behavior i.e.:
Command: nxc mssql 10.179.2.11 -u testuser -p testpass
Resulted in:
[22:37:07] ERROR Exception while calling proto_flow() on target 10.179.2.11: ("Unpacked data doesn't match constant value 'b'\\x9f\\x9e\\x00\\x00\\x01\\x14?\\x00'' should be ''NTLMSSP\\x00''", 'When unpacking field \' | "NTLMSSP\x00 | b\'\\x9f\\x9e\\x00\\x00\\x01\\x14?\\x00W\\x00i\\x00n\\x00d\\x00o\\x00w\\x00s\\x00 \\x00l\\x00o\\x00g\\x00i\\x00n\\x00s\\x00 \\x00a\\x00r\\x00e\\x00 connection.py:187
\\x00n\\x00o\\x00t\\x00 \\x00s\\x00u\\x00p\\x00p\\x00o\\x00r\\x00t\\x00e\\x00d\\x00 \\x00i\\x00n\\x00 \\x00t\\x00h\\x00i\\x00s\\x00 \\x00v\\x00e\\x00r\\x00s\\x00i\\x00o\\x00n\\x00 \\x00o\\x00f\\x00 \\x00S\\x00Q\\x00L\\x00
\\x00S\\x00e\\x00r\\x00v\\x00e\\x00r\\x00.\\x00\\x0b1\\x000\\x00.\\x001\\x007\\x009\\x00.\\x002\\x00.\\x001\\x001\\x00\\x00\\x00\\x00\\xfd\\x02\\x00\\x00\\x00\\x00\\x00\\x00\\x00\'[:8]\'')
╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── Traceback (most recent call last) ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ /home/pciaudit/.local/share/pipx/venvs/netexec/lib/python3.13/site-packages/nxc/connection.py:177 in __init__ │
│ │
│ 174 │ │ self.logger.info(f"Socket info: host={self.host}, hostname={self.hostname}, │
│ kerberos={self.kerberos}, ipv6={self.is_ipv6}, link-local │
│ ipv6={self.is_link_local_ipv6}") │
│ 175 │ │ │
│ 176 │ │ try: │
│ ❱ 177 │ │ │ self.proto_flow() │
│ 178 │ │ except FileNotFoundError as e: │
│ 179 │ │ │ self.logger.error(f"File not found error on target {target}: {e}") │
│ 180 │ │ except Exception as e: │
│ │
│ /home/pciaudit/.local/share/pipx/venvs/netexec/lib/python3.13/site-packages/nxc/connection.py:244 in proto_flow │
│ │
│ 241 │ │ │ self.logger.info(f"Failed to create connection object for target │
│ {self.host}, exiting...") │
│ 242 │ │ else: │
│ 243 │ │ │ self.logger.debug("Created connection object") │
│ ❱ 244 │ │ │ self.enum_host_info() │
│ 245 │ │ │ │
│ 246 │ │ │ # Construct the output file template using os.path.join for OS compatibility │
│ 247 │ │ │ base_log_dir = os.path.join(NXC_PATH, "logs") │
│ │
│ /home/pciaudit/.local/share/pipx/venvs/netexec/lib/python3.13/site-packages/nxc/protocols/mssql.py:77 in wrapper │
│ │
│ 74 │ │ │ with contextlib.suppress(Exception): │
│ 75 │ │ │ │ self.conn.disconnect() │
│ 76 │ │ │ self.create_conn_obj() │
│ ❱ 77 │ │ │ return func(self, *args, **kwargs) │
│ 78 │ │ return wrapper │
│ 79 │ │
│ 80 │ def check_if_admin(self): │
│ │
│ /home/pciaudit/.local/share/pipx/venvs/netexec/lib/python3.13/site-packages/nxc/protocols/mssql.py:136 in enum_host_info │
│ │
│ 133 │ │ │ self.logger.info(f"Failed to receive NTLM challenge, reason: {e!s}") │
│ 134 │ │ │ return False │
│ 135 │ │ else: │
│ ❱ 136 │ │ │ ntlm_info = parse_challenge(challenge) │
│ 137 │ │ │ self.targetDomain = self.domain = ntlm_info["domain"] │
│ 138 │ │ │ self.hostname = ntlm_info["hostname"] │
│ 139 │ │ │ self.server_os = ntlm_info["os_version"] │
│ │
│ /home/pciaudit/.local/share/pipx/venvs/netexec/lib/python3.13/site-packages/nxc/helpers/ntlm_parser.py:16 in parse_challenge │
│ │
│ 13 │ │ "domain": None, │
│ 14 │ │ "os_version": None │
│ 15 │ } │
│ ❱ 16 │ challange = ntlm.NTLMAuthChallenge(challange) │
│ 17 │ av_pairs = │
│ ntlm.AV_PAIRS(challange["TargetInfoFields"][:challange["TargetInfoFields_len"]]) │
│ 18 │ if av_pairs[ntlm.NTLMSSP_AV_HOSTNAME] is not None: │
│ 19 │ │ with contextlib.suppress(Exception): │
│ │
│ /home/pciaudit/.local/share/pipx/venvs/netexec/lib/python3.13/site-packages/impacket/structure.py:104 in __init__ │
│ │
│ 101 │ │ self.b = lambda x: six.ensure_binary(x, encoding=self.ENCODING) │
│ 102 │ │ │
│ 103 │ │ if data is not None: │
│ ❱ 104 │ │ │ self.fromString(data) │
│ 105 │ │ else: │
│ 106 │ │ │ self.data = None │
│ 107 │
│ │
│ /home/pciaudit/.local/share/pipx/venvs/netexec/lib/python3.13/site-packages/impacket/ntlm.py:390 in fromString │
│ │
│ 387 │ │ return Structure.getData(self) │
│ 388 │ │
│ 389 │ def fromString(self,data): │
│ ❱ 390 │ │ Structure.fromString(self,data) │
│ 391 │ │ self['domain_name'] = data[self['domain_offset']:][:self['domain_len']] │
│ 392 │ │ self['TargetInfoFields'] = │
│ data[self['TargetInfoFields_offset']:][:self['TargetInfoFields_len']] │
│ 393 │ │ return self │
│ │
│ /home/pciaudit/.local/share/pipx/venvs/netexec/lib/python3.13/site-packages/impacket/structure.py:169 in fromString │
│ │
│ 166 │ │ │ if len(field) > 2: │
│ 167 │ │ │ │ dataClassOrCode = field[2] │
│ 168 │ │ │ try: │
│ ❱ 169 │ │ │ │ self[field[0]] = self.unpack(field[1], data[:size], dataClassOrCode = │
│ dataClassOrCode, field = field[0]) │
│ 170 │ │ │ except Exception as e: │
│ 171 │ │ │ │ e.args += ("When unpacking field '%s | %s | %r[:%d]'" % (field[0], │
│ field[1], data, size),) │
│ 172 │ │ │ │ raise │
│ │
│ /home/pciaudit/.local/share/pipx/venvs/netexec/lib/python3.13/site-packages/impacket/structure.py:332 in unpack │
│ │
│ 329 │ │ if format[:1] == "'" or format[:1] == '"': │
│ 330 │ │ │ answer = format[1:] │
│ 331 │ │ │ if self.b(answer) != data: │
│ ❱ 332 │ │ │ │ raise Exception("Unpacked data doesn't match constant value '%r' should │
│ be '%r'" % (data, answer)) │
│ 333 │ │ │ return answer │
│ 334 │ │ │
│ 335 │ │ # address specifier │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
Exception: ("Unpacked data doesn't match constant value 'b'\\x9f\\x9e\\x00\\x00\\x01\\x14?\\x00'' should be ''NTLMSSP\\x00''", 'When unpacking field \' | "NTLMSSP\x00 | b\'\\x9f\\x9e\\x00\\x00\\x01\\x14?\\x00W\\x00i\\x00n\\x00d\\x00o\\x00w\\x00s\\x00 \\x00l\\x00o\\x00g\\x00i\\x00n\\x00s\\x00 \\x00a\\x00r\\x00e\\x00 \\x00n\\x00o\\x00t\\x00
\\x00s\\x00u\\x00p\\x00p\\x00o\\x00r\\x00t\\x00e\\x00d\\x00 \\x00i\\x00n\\x00 \\x00t\\x00h\\x00i\\x00s\\x00 \\x00v\\x00e\\x00r\\x00s\\x00i\\x00o\\x00n\\x00 \\x00o\\x00f\\x00 \\x00S\\x00Q\\x00L\\x00
\\x00S\\x00e\\x00r\\x00v\\x00e\\x00r\\x00.\\x00\\x0b1\\x000\\x00.\\x001\\x007\\x009\\x00.\\x002\\x00.\\x001\\x001\\x00\\x00\\x00\\x00\\xfd\\x02\\x00\\x00\\x00\\x00\\x00\\x00\\x00\'[:8]\'')
...
Expected behavior
Connection established
Server returns TDS error message:
"Windows logins are not supported in this version of SQL Server."
NetExec attempts to parse response as NTLMSSP
Crash with:
Unpacked data doesn't match constant value 'NTLMSSP\x00'
Expected behavior:
Graceful handling of SQL Server error response
Clean failure indicating Windows authentication is not supported
No NTLM parsing attempt when server returns TDS error packet
Screenshots
If applicable, add screenshots to help explain your problem.
NetExec info
- OS: Kali Cloud
- Version of nxc: .5.0 - Yippie-Ki-Yay - b1e9d63 - 37
- Installed from: pipx
Additional context
impacket-mssqlclient handles this scenario correctly (fails login without crashing)
This appears to be a protocol state mismatch rather than a connectivity issue
Likely requires checking for TDS Error tokens before NTLM parsing