diff --git a/examples/changepasswd.py b/examples/changepasswd.py index d18fcfdca..50cc2f004 100755 --- a/examples/changepasswd.py +++ b/examples/changepasswd.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # Impacket - Collection of Python classes for working with network protocols. # -# Copyright Fortra, LLC and its affiliated companies +# Copyright Fortra, LLC and its affiliated companies # # All rights reserved. # @@ -126,12 +126,14 @@ from impacket import version from impacket.dcerpc.v5 import transport, samr, epm -from impacket.krb5 import kpasswd +from impacket.krb5 import kerberosv5, kpasswd from impacket.ldap import ldap, ldapasn1 from impacket.examples import logger from impacket.examples.utils import parse_target +import OpenSSL + EMPTY_LM_HASH = "aad3b435b51404eeaad3b435b51404ee" @@ -287,12 +289,12 @@ def _changePassword( aesKey=self.aesKey, kdcHost=self.kdcHost, ) - except kpasswd.KPasswdError as e: + except (kerberosv5.KerberosError, kpasswd.KPasswdError) as e: logging.error(f"Password not changed: {e}") return False - else: - logging.info("Password was changed successfully.") - return True + + logging.info("Password was changed successfully.") + return True def _setPassword(self, targetUsername, targetDomain, newPassword, newPwdHashLM, newPwdHashNT): if not newPassword: @@ -312,10 +314,12 @@ def _setPassword(self, targetUsername, targetDomain, newPassword, newPwdHashLM, aesKey=self.aesKey, kdcHost=self.kdcHost, ) - except kpasswd.KPasswdError as e: + except (kerberosv5.KerberosError, kpasswd.KPasswdError) as e: logging.error(f"Password not changed for {targetDomain}\\{targetUsername}: {e}") - else: - logging.info(f"Password was set successfully for {targetDomain}\\{targetUsername}.") + return False + + logging.info(f"Password was set successfully for {targetDomain}\\{targetUsername}.") + return True class SamrPassword(PasswordHandler): @@ -414,6 +418,10 @@ def connect(self, retry_if_expired=False): ) logging.debug(str(e)) return False + elif "STATUS_ACCOUNT_DISABLED" in str(e): + logging.critical("The account is currently disabled.") + logging.debug(str(e)) + return False else: raise e @@ -442,6 +450,10 @@ def hSamrOpenUser(self, username): ) logging.debug(str(e)) return False + elif "STATUS_ACCESS_DENIED" in str(e): + logging.critical("Access denied") + logging.debug(str(e)) + return False else: raise e @@ -541,7 +553,7 @@ def _changePassword( targetUsername, oldPassword, "", oldPwdHashLM, oldPwdHashNT, newPwdHashLM, newPwdHashNT ) if res: - logging.warning("User will need to change their password on next logging because we are using hashes.") + logging.warning("User might need to change their password at next logon because we set hashes (unless password never expires is set).") return res def _setPassword(self, targetUsername, targetDomain, newPassword, newPwdHashLM, newPwdHashNT): @@ -569,7 +581,7 @@ def _changePassword( logging.warning( "MS-RPC transport requires new password in plaintext in default Active Directory configuration. Trying anyway." ) - super()._changePassword( + return super()._changePassword( targetUsername, targetDomain, oldPassword, newPassword, oldPwdHashLM, oldPwdHashNT, newPwdHashLM, newPwdHashNT ) @@ -577,7 +589,7 @@ def _setPassword(self, targetUsername, targetDomain, newPassword, newPwdHashLM, logging.warning( "MS-RPC transport does not allow password reset in default Active Directory configuration. Trying anyway." ) - super()._setPassword(targetUsername, targetDomain, newPassword, newPwdHashLM, newPwdHashNT) + return super()._setPassword(targetUsername, targetDomain, newPassword, newPwdHashLM, newPwdHashNT) class SmbPassword(SamrPassword): @@ -615,7 +627,7 @@ def connect(self, targetDomain): self.aesKey, kdcHost=self.kdcHost, ) - except ldap.LDAPSessionError as e: + except (ldap.LDAPSessionError, OpenSSL.SSL.SysCallError) as e: logging.error(f"Cannot connect to {ldapURI} as {self.domain}\\{self.username}: {e}") return False @@ -872,7 +884,12 @@ def parse_args(): elif options.no_pass: logging.info("Current password not given: will use KRB5CCNAME") else: - oldPassword = getpass("Current password: ") + try: + oldPassword = getpass("Current password: ") + except KeyboardInterrupt: + print() + logging.warning("Cancelled") + sys.exit(130) if options.newhashes is not None: newPassword = "" @@ -887,10 +904,15 @@ def parse_args(): newPwdHashLM = "" newPwdHashNT = "" if options.newpass is None: - newPassword = getpass("New password: ") - if newPassword != getpass("Retype new password: "): - logging.critical("Passwords do not match, try again.") - sys.exit(1) + try: + newPassword = getpass("New password: ") + if newPassword != getpass("Retype new password: "): + logging.critical("Passwords do not match, try again.") + sys.exit(1) + except KeyboardInterrupt: + print() + logging.warning("Cancelled") + sys.exit(130) else: newPassword = options.newpass @@ -949,7 +971,7 @@ def parse_args(): # Attempt the password change/reset if options.reset: - handler.setPassword(targetUsername, targetDomain, newPassword, newPwdHashLM, newPwdHashNT) + ret = handler.setPassword(targetUsername, targetDomain, newPassword, newPwdHashLM, newPwdHashNT) else: if (authDomain, authUsername) != (targetDomain, targetUsername): logging.warning( @@ -957,6 +979,11 @@ def parse_args(): "You may want to use '-reset' to *reset* the password of the target." ) - handler.changePassword( + ret = handler.changePassword( targetUsername, targetDomain, oldPassword, newPassword, oldPwdHashLM, oldPwdHashNT, newPwdHashLM, newPwdHashNT ) + + if ret: + sys.exit(0) + else: + sys.exit(1) diff --git a/examples/net.py b/examples/net.py index 2d8eb3de3..85500b602 100644 --- a/examples/net.py +++ b/examples/net.py @@ -24,6 +24,8 @@ # python net.py Administrator:password@targetMachine group -name "Domain Admins" # python net.py Administrator:password@targetMachine computer -name DC$ # python net.py Administrator:password@targetMachine group -name "Domain Admins" -join EvilUs3r +# python net.py Administrator:password@targetMachine user -enable EvilUs3r +# python net.py Administrator:password@targetMachine user -disable EvilUs3r # # Author: # Alex Romero (@NtAlexio2) @@ -215,11 +217,32 @@ def Remove(self, name): self._close_domain() def _hEnableAccount(self, user_handle): + user_account_control = samr.hSamrQueryInformationUser2(self._dce, user_handle, samr.USER_INFORMATION_CLASS.UserAllInformation)['Buffer']['All']['UserAccountControl'] buffer = samr.SAMPR_USER_INFO_BUFFER() buffer['tag'] = samr.USER_INFORMATION_CLASS.UserControlInformation - buffer['Control']['UserAccountControl'] = samr.USER_ALL_ADMINCOMMENT + buffer['Control']['UserAccountControl'] = user_account_control ^ samr.USER_ACCOUNT_DISABLED samr.hSamrSetInformationUser2(self._dce, user_handle, buffer) + def _hDisableAccount(self, user_handle): + user_account_control = samr.hSamrQueryInformationUser2(self._dce, user_handle, samr.USER_INFORMATION_CLASS.UserAllInformation)['Buffer']['All']['UserAccountControl'] + buffer = samr.SAMPR_USER_INFO_BUFFER() + buffer['tag'] = samr.USER_INFORMATION_CLASS.UserControlInformation + buffer['Control']['UserAccountControl'] = samr.USER_ACCOUNT_DISABLED | user_account_control + samr.hSamrSetInformationUser2(self._dce, user_handle, buffer) + + def SetUserAccountControl(self, name, action): + info = self.Query(name) + domain_handle = self._open_domain() + try: + user_handle = self._get_user_handle(domain_handle, name) + if action == 'enable': + self._hEnableAccount(user_handle) + else: + self._hDisableAccount(user_handle) + finally: + self._close_domain() + + class Computer(User): def __init__(self, smbConnection): @@ -358,6 +381,16 @@ def run(self, remoteName, remoteHost): actionObject.Remove(self.__options.remove) print("[+] {} account deleted succesfully!".format(self.__action)) + elif self.__is_option_present(self.__options, 'enable'): + print("[*] Enabling {} account '{}'".format(self.__action, self.__options.enable)) + actionObject.SetUserAccountControl(self.__options.enable, "enable") + print("[+] {} account enabled succesfully!".format(self.__action)) + + elif self.__is_option_present(self.__options, 'disable'): + print("[*] Disabling {} account '{}'".format(self.__action, self.__options.disable)) + actionObject.SetUserAccountControl(self.__options.disable, "disable") + print("[+] {} account disabled succesfully!".format(self.__action)) + elif self.__is_option_present(self.__options, 'join'): print("[*] Adding user account '{}' to group '{}'".format(self.__options.join,self.__options.name)) actionObject.Join(self.__options.name, self.__options.join) @@ -466,12 +499,16 @@ def __is_option_present(self, options, option): user_parser.add_argument('-create', action="store", metavar = "NAME", help='Add new user account to domain/computer.') user_parser.add_argument('-remove', action="store", metavar = "NAME", help='Remove existing user account from domain/computer.') user_parser.add_argument('-newPasswd', action="store", metavar = "PASSWORD", help='New password to set for creating account.') + user_parser.add_argument('-enable', action="store", metavar = "NAME", help='Enables account.') + user_parser.add_argument('-disable', action="store", metavar = "NAME", help='Disables account.') computer_parser = subparsers.add_parser('computer', help='Enumerate all computers in domain level') computer_parser.add_argument('-name', action="store", metavar = "NAME", help='Display single computer information.') computer_parser.add_argument('-create', action="store", metavar = "NAME", help='Add new computer account to domain.') computer_parser.add_argument('-remove', action="store", metavar = "NAME", help='Remove existing computer account from domain.') computer_parser.add_argument('-newPasswd', action="store", metavar = "PASSWORD", help='New password to set for creating account.') + computer_parser.add_argument('-enable', action="store", metavar = "NAME", help='Enables account.') + computer_parser.add_argument('-disable', action="store", metavar = "NAME", help='Disables account.') localgroup_parser = subparsers.add_parser('localgroup', help='Enumerate local groups (aliases) of local computer') localgroup_parser.add_argument('-name', action="store", metavar = "NAME", help='Operate on single specific domain group account.') diff --git a/impacket/dhcp.py b/impacket/dhcp.py index aeabb4013..dde0c3909 100644 --- a/impacket/dhcp.py +++ b/impacket/dhcp.py @@ -178,7 +178,7 @@ def unpackOptions(self, options): # size = self.calcUnpackSize(format, options[i+1:]) size = options[i+1] # print i, name, format, size - value = self.unpack(format, options[i+2:i+2+size]) + value = self.unpack(format, bytes(options[i+2:i+2+size])) answer.append((name, value)) i += 2+size diff --git a/impacket/examples/ntlmrelayx/clients/ldaprelayclient.py b/impacket/examples/ntlmrelayx/clients/ldaprelayclient.py index 9f69a71be..63536bae2 100644 --- a/impacket/examples/ntlmrelayx/clients/ldaprelayclient.py +++ b/impacket/examples/ntlmrelayx/clients/ldaprelayclient.py @@ -99,6 +99,7 @@ def sendNegotiate(self, negotiateMessage): if result['result'] == RESULT_SUCCESS: challenge = NTLMAuthChallenge() challenge.fromString(result['server_creds']) + self.sessionData['CHALLENGE_MESSAGE'] = challenge return challenge else: raise LDAPRelayClientException('Server did not offer NTLM authentication!') @@ -156,6 +157,13 @@ def create_authenticate_message(self): def parse_challenge_message(self, message): pass + def keepAlive(self): + # Basic LDAP query to keep the connection alive + self.session.search(search_base='', + search_filter='(objectClass=*)', + search_scope='BASE', + attributes=['namingContexts']) + class LDAPSRelayClient(LDAPRelayClient): PLUGIN_NAME = "LDAPS" MODIFY_ADD = MODIFY_ADD diff --git a/impacket/examples/ntlmrelayx/servers/socksplugins/ldap.py b/impacket/examples/ntlmrelayx/servers/socksplugins/ldap.py new file mode 100644 index 000000000..889fc951d --- /dev/null +++ b/impacket/examples/ntlmrelayx/servers/socksplugins/ldap.py @@ -0,0 +1,313 @@ +import select +from pyasn1.codec.ber import encoder, decoder +from pyasn1.error import SubstrateUnderrunError +from pyasn1.type import univ + +from impacket import LOG, ntlm +from impacket.examples.ntlmrelayx.servers.socksserver import SocksRelay +from impacket.ldap.ldap import LDAPSessionError +from impacket.ldap.ldapasn1 import KNOWN_NOTIFICATIONS, LDAPDN, NOTIFICATION_DISCONNECT, BindRequest, BindResponse, SearchRequest, SearchResultEntry, SearchResultDone, LDAPMessage, LDAPString, ResultCode, PartialAttributeList, PartialAttribute, AttributeValue, UnbindRequest, ExtendedRequest +from impacket.ntlm import NTLMSSP_NEGOTIATE_SIGN, NTLMSSP_NEGOTIATE_SEAL + +PLUGIN_CLASS = 'LDAPSocksRelay' + +class LDAPSocksRelay(SocksRelay): + PLUGIN_NAME = 'LDAP Socks Plugin' + PLUGIN_SCHEME = 'LDAP' + + MSG_SIZE = 4096 + + def __init__(self, targetHost, targetPort, socksSocket, activeRelays): + SocksRelay.__init__(self, targetHost, targetPort, socksSocket, activeRelays) + + @staticmethod + def getProtocolPort(): + return 389 + + def initConnection(self): + # No particular action required to initiate the connection + pass + + def skipAuthentication(self): + # Faking an NTLM authentication with the client + while True: + messages = self.recv_ldap_msg() + if messages is None: + LOG.warning('LDAP: Client did not send ldap messages or closed connection') + return False + LOG.debug(f'LDAP: Received {len(messages)} message(s)') + + for message in messages: + msg_component = message['protocolOp'].getComponent() + if msg_component.isSameTypeWith(BindRequest): + # BindRequest received + + if msg_component['authentication'] == univ.OctetString(''): + # First bind message without authentication + # Replying with a request for NTLM authentication + + LOG.debug('LDAP: Got empty bind request') + + bindresponse = BindResponse() + bindresponse['resultCode'] = ResultCode('success') + bindresponse['matchedDN'] = LDAPDN('NTLM') + bindresponse['diagnosticMessage'] = LDAPString('') + self.send_ldap_msg(bindresponse, message['messageID']) + + # Let's receive next messages + continue + + elif 'sicilyNegotiate' in msg_component['authentication']: + # Requested NTLM authentication + + LOG.debug('LDAP: Got NTLM bind request') + + # Load negotiate message + negotiateMessage = ntlm.NTLMAuthNegotiate() + negotiateMessage.fromString(msg_component['authentication']['sicilyNegotiate'].asOctets()) + + # Reuse the challenge message from the real authentication with the server + challengeMessage = self.sessionData['CHALLENGE_MESSAGE'] + # We still remove the annoying flags + challengeMessage['flags'] &= ~(NTLMSSP_NEGOTIATE_SIGN) + challengeMessage['flags'] &= ~(NTLMSSP_NEGOTIATE_SEAL) + + # Building the LDAP bind response message + bindresponse = BindResponse() + bindresponse['resultCode'] = ResultCode('success') + bindresponse['matchedDN'] = LDAPDN(challengeMessage.getData()) + bindresponse['diagnosticMessage'] = LDAPString('') + + # Sending the response + self.send_ldap_msg(bindresponse, message['messageID']) + + elif 'sicilyResponse' in msg_component['authentication']: + # Received an NTLM auth bind request + + # Parsing authentication method + chall_response = ntlm.NTLMAuthChallengeResponse() + chall_response.fromString(msg_component['authentication']['sicilyResponse'].asOctets()) + + username = chall_response['user_name'].decode('utf-16le') + domain = chall_response['domain_name'].decode('utf-16le') + self.username = f'{domain}/{username}' + + # Checking for the two formats the domain can have (taken from both HTTP and SMB socks plugins) + if f'{domain}/{username}'.upper() in self.activeRelays: + self.username = f'{domain}/{username}'.upper() + elif f'{domain.split(".", 1)[0]}/{username}'.upper() in self.activeRelays: + self.username = f'{domain.split(".", 1)[0]}/{username}'.upper() + else: + # Username not in active relays + LOG.error('LDAP: No session for %s@%s(%s) available' % ( + username, self.targetHost, self.targetPort)) + return False + + if self.activeRelays[self.username]['inUse'] is True: + LOG.error('LDAP: Connection for %s@%s(%s) is being used at the moment!' % ( + self.username, self.targetHost, self.targetPort)) + return False + else: + LOG.info('LDAP: Proxying client session for %s@%s(%s)' % ( + self.username, self.targetHost, self.targetPort)) + self.activeRelays[self.username]['inUse'] = True + self.session = self.activeRelays[self.username]['protocolClient'].session.socket + + # Building successful LDAP bind response + bindresponse = BindResponse() + bindresponse['resultCode'] = ResultCode('success') + bindresponse['matchedDN'] = LDAPDN('') + bindresponse['diagnosticMessage'] = LDAPString('') + + # Sending successful response + self.send_ldap_msg(bindresponse, message['messageID']) + + return True + else: + LOG.error('LDAP: Received an unknown LDAP binding request, cannot continue') + return False + + else: + msg_component = message['protocolOp'].getComponent() + if msg_component.isSameTypeWith(SearchRequest): + # Pre-auth search request + + if msg_component['attributes'][0] == LDAPString('supportedCapabilities'): + # supportedCapabilities + response = SearchResultEntry() + response['objectName'] = LDAPDN('') + response['attributes'] = PartialAttributeList() + + attribs = PartialAttribute() + attribs.setComponentByName('type', 'supportedCapabilities') + attribs.setComponentByName('vals', univ.SetOf(componentType=AttributeValue())) + # LDAP_CAP_ACTIVE_DIRECTORY_OID + attribs.getComponentByName('vals').setComponentByPosition(0, AttributeValue('1.2.840.113556.1.4.800')) + # LDAP_CAP_ACTIVE_DIRECTORY_V51_OID + attribs.getComponentByName('vals').setComponentByPosition(1, AttributeValue('1.2.840.113556.1.4.1670')) + # LDAP_CAP_ACTIVE_DIRECTORY_LDAP_INTEG_OID + attribs.getComponentByName('vals').setComponentByPosition(2, AttributeValue('1.2.840.113556.1.4.1791')) + # ISO assigned OIDs + attribs.getComponentByName('vals').setComponentByPosition(3, AttributeValue('1.2.840.113556.1.4.1935')) + attribs.getComponentByName('vals').setComponentByPosition(4, AttributeValue('1.2.840.113556.1.4.2080')) + attribs.getComponentByName('vals').setComponentByPosition(5, AttributeValue('1.2.840.113556.1.4.2237')) + + response['attributes'].append(attribs) + + elif msg_component['attributes'][0] == LDAPString('supportedSASLMechanisms'): + # supportedSASLMechanisms + response = SearchResultEntry() + response['objectName'] = LDAPDN('') + response['attributes'] = PartialAttributeList() + + attribs = PartialAttribute() + attribs.setComponentByName('type', 'supportedSASLMechanisms') + attribs.setComponentByName('vals', univ.SetOf(componentType=AttributeValue())) + # Force NTLMSSP to avoid parsing every type of authentication + attribs.getComponentByName('vals').setComponentByPosition(0, AttributeValue('NTLM')) + + response['attributes'].append(attribs) + else: + # Any other message triggers the closing of client connection + return False + + # Sending message + self.send_ldap_msg(response, message['messageID']) + # Sending searchResDone + result_done = SearchResultDone() + result_done['resultCode'] = ResultCode('success') + result_done['matchedDN'] = LDAPDN('') + result_done['diagnosticMessage'] = LDAPString('') + self.send_ldap_msg(result_done, message['messageID']) + + def recv_ldap_msg(self): + '''Receive LDAP messages during the SOCKS client LDAP authentication.''' + + data = b'' + done = False + while not done: + recvData = self.socksSocket.recv(self.MSG_SIZE) + if recvData == b'': + # Connection got closed + return None + if len(recvData) < self.MSG_SIZE: + done = True + data += recvData + + response = [] + while len(data) > 0: + try: + message, remaining = decoder.decode(data, asn1Spec=LDAPMessage()) + except SubstrateUnderrunError: + # We need more data + new_data = self.socksSocket.recv(self.MSG_SIZE) + if new_data == b'': + # Connection got closed + return None + remaining = data + new_data + else: + response.append(message) + data = remaining + + return response + + def send_ldap_msg(self, response, message_id, controls=None): + '''Send LDAP messages during the SOCKS client LDAP authentication.''' + + message = LDAPMessage() + message['messageID'] = message_id + message['protocolOp'].setComponentByType(response.getTagSet(), response) + if controls is not None: + message['controls'].setComponents(*controls) + + data = encoder.encode(message) + + return self.socksSocket.sendall(data) + + def wait_for_data(self, socket1, socket2): + return select.select([socket1, socket2], [], [])[0] + + def passthrough_sockets(self, client_sock, server_sock): + while True: + rready = self.wait_for_data(client_sock, server_sock) + + for sock in rready: + + if sock == client_sock: + # Data received from client + try: + read = client_sock.recv(self.MSG_SIZE) + except Exception: + read = '' + if not read: + return + + if not self.is_allowed_request(read): + # Stop client connection when unallowed requests are made + return + + if not self.is_forwardable_request(read): + # Do not forward unbind requests, otherwise we would loose the SOCKS + continue + + try: + server_sock.send(read) + except Exception: + raise BrokenPipeError('Broken pipe: LDAP server is gone') + + elif sock == server_sock: + # Data received from server + try: + read = server_sock.recv(self.MSG_SIZE) + except Exception: + read = '' + if not read: + raise BrokenPipeError('Broken pipe: LDAP server is gone') + + try: + client_sock.send(read) + except Exception: + return + + def tunnelConnection(self): + '''Charged of tunneling the rest of the connection.''' + + self.passthrough_sockets(self.socksSocket, self.session) + + # Free the relay so that it can be reused + self.activeRelays[self.username]['inUse'] = False + + LOG.debug('LDAP: Finished tunnelling') + + return True + + def is_forwardable_request(self, data): + try: + message, remaining = decoder.decode(data, asn1Spec=LDAPMessage()) + msg_component = message['protocolOp'].getComponent() + + # Search for unbind requests + if msg_component.isSameTypeWith(UnbindRequest): + LOG.warning('LDAP: Client tried to unbind LDAP connection, skipping message') + return False + except Exception: + # Is probably not an unbind LDAP message + pass + + return True + + def is_allowed_request(self, data): + try: + message, remaining = decoder.decode(data, asn1Spec=LDAPMessage()) + msg_component = message['protocolOp'].getComponent() + + # Search for START_TLS LDAP extendedReq OID + if msg_component.isSameTypeWith(ExtendedRequest) and msg_component['requestName'].asOctets() == b'1.3.6.1.4.1.1466.20037': + # 1.3.6.1.4.1.1466.20037 is LDAP_START_TLS_OID + LOG.warning('LDAP: Client tried to initiate Start TLS, closing connection') + return False + except Exception: + # Is probably not a ExtendedReq message + pass + + return True diff --git a/impacket/examples/ntlmrelayx/servers/socksplugins/ldaps.py b/impacket/examples/ntlmrelayx/servers/socksplugins/ldaps.py new file mode 100644 index 000000000..001b65adb --- /dev/null +++ b/impacket/examples/ntlmrelayx/servers/socksplugins/ldaps.py @@ -0,0 +1,47 @@ +import select +from impacket import LOG +from impacket.examples.ntlmrelayx.servers.socksplugins.ldap import LDAPSocksRelay +from impacket.examples.ntlmrelayx.utils.ssl import SSLServerMixin +from OpenSSL import SSL + +PLUGIN_CLASS = "LDAPSSocksRelay" + +class LDAPSSocksRelay(SSLServerMixin, LDAPSocksRelay): + PLUGIN_NAME = 'LDAPS Socks Plugin' + PLUGIN_SCHEME = 'LDAPS' + + def __init__(self, targetHost, targetPort, socksSocket, activeRelays): + LDAPSocksRelay.__init__(self, targetHost, targetPort, socksSocket, activeRelays) + + @staticmethod + def getProtocolPort(): + return 636 + + def skipAuthentication(self): + LOG.debug('Wrapping client connection in TLS/SSL') + self.wrapClientConnection() + + # Skip authentication using the same technique as LDAP + try: + if not LDAPSocksRelay.skipAuthentication(self): + # Shut down TLS connection + self.socksSocket.shutdown() + return False + except SSL.SysCallError: + LOG.warning('Cannot wrap client socket in TLS/SSL') + return False + + return True + + def wait_for_data(self, socket1, socket2): + rready = [] + + if socket1.pending(): + rready.append(socket1) + if socket2.pending(): + rready.append(socket2) + + if not rready: + rready, _, exc = select.select([socket1, socket2], [], []) + + return rready diff --git a/impacket/smb3structs.py b/impacket/smb3structs.py index efd1ec740..556e3e6f0 100644 --- a/impacket/smb3structs.py +++ b/impacket/smb3structs.py @@ -1496,6 +1496,12 @@ class FILE_ALL_INFORMATION(Structure): ('NameInformation',':',FILE_NAME_INFORMATION), ) +class FILE_ATTRIBUTE_TAG_INFORMATION(Structure): + structure = ( + ('FileAttributes','