@@ -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