Skip to content

Commit 7147aa2

Browse files
committed
parse TDS ERROR/INFO via impacket
1 parent b27b20f commit 7147aa2

1 file changed

Lines changed: 32 additions & 11 deletions

File tree

nxc/protocols/mssql.py

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,31 @@ def wrapper(self, *args, **kwargs):
7878
return func(self, *args, **kwargs)
7979
return wrapper
8080

81+
@staticmethod
82+
def decode_tds_info_error_msgtext(data, offset):
83+
remaining = len(data) - offset
84+
if remaining < 3 or data[offset] not in (TDS_ERROR_TOKEN, TDS_INFO_TOKEN):
85+
return None
86+
payload_len = int.from_bytes(data[offset + 1 : offset + 3], "little")
87+
if payload_len < 8 or remaining < 3 + payload_len:
88+
return None
89+
try:
90+
token = tds.TDS_INFO_ERROR(data[offset:])
91+
text = token["MsgText"].decode("utf-16le").strip()
92+
except Exception:
93+
return None
94+
return text or None
95+
96+
@staticmethod
97+
def login7_integrated_auth_error_message(packet_data, data_after_login_header):
98+
token_markers = (TDS_ERROR_TOKEN, TDS_INFO_TOKEN)
99+
for buf in filter(None, (packet_data, data_after_login_header)):
100+
for offset in (i for i in range(len(buf)) if buf[i] in token_markers):
101+
msg = mssql.decode_tds_info_error_msgtext(buf, offset)
102+
if msg:
103+
return msg
104+
return None
105+
81106
def check_if_admin(self):
82107
self.admin_privs = False
83108
try:
@@ -128,22 +153,18 @@ def enum_host_info(self):
128153
self.conn.tlsSocket = None
129154

130155
tdsx = self.conn.recvTDS()
131-
challenge = tdsx["Data"][3:]
132-
self.logger.debug(f"NTLM challenge: {challenge!s}")
156+
login_response = tdsx["Data"]
157+
# Impacket historically slices 3 bytes before treating payload as NTLMSSP (LOGIN7 response).
158+
challenge = login_response[3:]
159+
self.logger.debug(f"LOGIN7 response SSPI slice: {challenge!s}")
133160
except Exception as e:
134161
self.logger.info(f"Failed to receive NTLM challenge, reason: {e!s}")
135162
return False
136163
else:
137164
if not challenge.startswith(b"NTLMSSP\x00"):
138-
try:
139-
text = challenge.decode("utf-16le", errors="ignore")
140-
clean = "".join(c for c in text if c.isascii() and (c.isprintable() or c == " "))
141-
start = next((i for i, c in enumerate(clean) if c.isupper()), 0)
142-
end = clean.rfind(".")
143-
error_msg = clean[start:end + 1].strip() if 0 <= start < end else clean.strip()
144-
except Exception:
145-
error_msg = ""
146-
self.logger.fail(f"Server does not support Integrated Windows Authentication{f': {error_msg}' if error_msg else ''}")
165+
error_msg = self.login7_integrated_auth_error_message(login_response, challenge)
166+
detail = f": {error_msg}" if error_msg else ""
167+
self.logger.fail(f"Server does not support Integrated Windows Authentication{detail}")
147168
else:
148169
ntlm_info = parse_challenge(challenge)
149170
self.targetDomain = self.domain = ntlm_info["domain"]

0 commit comments

Comments
 (0)