├── LICENSE ├── README.md └── scan.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Preempt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # New! Exploit Scan for CVE-2020-1472 (ZeroLogon) 2 | 3 | Scan DCs in your network to detect *actual* exploitation of CVE-2020-1472 4 | 5 | Examples: 6 | ``` 7 | python scan.py -vuln CVE-2020-1472 -target-file targets.txt 8 | python scan.py -vuln CVE-2020-1472 -target 9 | ``` 10 | 11 | Tool works by trying an empty password for DCs every minute. Since exploitation must set password to an empty one, unless reverted very quickly this will detect exploitation attempts if running during exploitation. 12 | 13 | # NTLM scanner 14 | 15 | Checks for various NTLM vulnerabilities over SMB. 16 | The script will establish a connection to the target host(s) and send 17 | an invalid NTLM authentication. If this is accepted, the host is vulnerable to 18 | the applied NTLM vulnerability and you can execute the relevant NTLM attack. 19 | More details in: 20 | - https://www.preempt.com/blog/how-to-easily-bypass-epa-to-compromise-any-web-server-that-supports-windows-integrated-authentication/ 21 | - https://www.preempt.com/blog/your-session-key-is-my-session-key-how-to-retrieve-the-session-key-for-any-authentication/ 22 | - https://www.preempt.com/blog/drop-the-mic-cve-2019-1040/ 23 | - https://www.preempt.com/blog/drop-the-mic-2-active-directory-open-to-more-ntlm-attacks/ 24 | 25 | Note most scans do not generate failed login attempts as the login information itself is valid. CVE-2019-1338 does generate 26 | a failed authentication and might cause an account lockout. 27 | 28 | Software is based on the following: 29 | - CVE-2019-1040 scanner (https://github.com/fox-it/cve-2019-1040-scanner) by Dirk-jan Mollema (@_dirkjan) 30 | - Impacket (https://github.com/SecureAuthCorp/impacket) by SecureAuth Corporation (https://www.secureauth.com/) 31 | 32 | # Usage 33 | The script requires a recent impacket version. Should work with both python 2 and 3 (Python 3 requires you to use impacket from git). 34 | 35 | ``` 36 | [*] NTLM vulnerabilities scanner by @YaronZi / Preempt - Based on impacket by SecureAuth 37 | usage: scan.py [-h] [-target TARGET] [-target-file file] 38 | [-port [destination port]] [-vuln [scanned vulnerability]] 39 | [-hashes LMHASH:NTHASH] 40 | 41 | NTLM scanner - Connects over SMB and attempts to authenticate with invalid 42 | NTLM packets. If accepted, target is vulnerable to the scanned vulnerability 43 | 44 | optional arguments: 45 | -h, --help show this help message and exit 46 | -target TARGET [[domain/]username[:password]@] 47 | 48 | connection: 49 | -target-file file Use the targets in the specified file instead of the 50 | one on the command line (you must still specify 51 | something as target name) 52 | -port [destination port] 53 | Destination port to connect to SMB Server 54 | -vuln [scanned vulnerability] 55 | The vulnerability to scan SMB Server on [CVE-2019-1019 56 | |CVE-2019-1040|CVE-2019-1166|CVE-2019-1338|CVE-2020-14 57 | 72] 58 | 59 | authentication: 60 | -hashes LMHASH:NTHASH 61 | NTLM hashes, format is LMHASH:NTHASH 62 | ``` 63 | -------------------------------------------------------------------------------- /scan.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #################### 3 | # 4 | # Copyright (c) 2020 Yaron Zinar / Preempt (@YaronZi) 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy 7 | # of this software and associated documentation files (the "Software"), to deal 8 | # in the Software without restriction, including without limitation the rights 9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | # copies of the Software, and to permit persons to whom the Software is 11 | # furnished to do so, subject to the following conditions: 12 | # 13 | # The above copyright notice and this permission notice shall be included in all 14 | # copies or substantial portions of the Software. 15 | # 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | # SOFTWARE. 23 | # 24 | # Checks for several NTLM vulnerabilities (CVE-2019-1019, CVE-2019-1040, 25 | # CVE-2019-1166, CVE-2019-1338) over SMB. The script will establish a connection 26 | # to the target host(s) and send an invalid NTLM authentication. 27 | # If this is accepted, the host is vulnerable to the scanned vulnerability and you can 28 | # execute the the relevant attack. 29 | # 30 | # See: 31 | # https://www.preempt.com/blog/drop-the-mic-cve-2019-1040/ 32 | # https://www.preempt.com/blog/drop-the-mic-2-active-directory-open-to-more-ntlm-attacks/ 33 | # for more info. 34 | # 35 | # Authors: 36 | # Yaron Zinar (@YaronZi) 37 | # 38 | # Software is based on the following: 39 | # - CVE-2019-1040 scanner (https://github.com/fox-it/cve-2019-1040-scanner) by Dirk-jan Mollema (@_dirkjan) 40 | # - Impacket (https://github.com/SecureAuthCorp/impacket) by SecureAuth Corporation (https://www.secureauth.com/) 41 | # 42 | #################### 43 | import sys 44 | import logging 45 | import argparse 46 | import codecs 47 | import calendar 48 | import struct 49 | import time 50 | import datetime 51 | import random 52 | from impacket import version 53 | from impacket.krb5.asn1 import seq_set, seq_set_iter, EncryptedData, KERB_PA_PAC_REQUEST, PA_ENC_TS_ENC, AS_REQ 54 | from impacket.krb5.kerberosv5 import sendReceive 55 | from impacket.examples.logger import ImpacketFormatter 56 | from impacket.smbconnection import SMBConnection, SessionError 57 | from impacket.krb5.types import Principal, KerberosTime 58 | from pyasn1.codec.der import encoder, decoder 59 | from impacket.krb5 import constants 60 | from impacket.smb3structs import * 61 | from impacket.krb5.crypto import Key, _enctype_table 62 | from impacket import ntlm 63 | from impacket.ntlm import AV_PAIRS, NTLMSSP_AV_EOL, NTLMSSP_AV_TIME, NTLMSSP_AV_FLAGS, NTOWFv2, NTLMSSP_AV_TARGET_NAME, NTLMSSP_AV_HOSTNAME,USE_NTLMv2, hmac_md5 64 | from pyasn1.type.univ import noValue 65 | 66 | def verify_kerberos_password(user, password, domain, kdc_host=None, request_pac=True, host_names=None, source_ip=None): 67 | host_names = host_names or [] 68 | clientName = Principal(user, type=constants.PrincipalNameType.NT_PRINCIPAL.value) 69 | 70 | domain = domain.upper() 71 | serverName = Principal("krbtgt/%s" % domain, type=constants.PrincipalNameType.NT_PRINCIPAL.value) 72 | 73 | pacRequest = KERB_PA_PAC_REQUEST() 74 | pacRequest["include-pac"] = request_pac 75 | encodedPacRequest = encoder.encode(pacRequest) 76 | 77 | enctype = constants.EncryptionTypes.rc4_hmac.value 78 | encryptionTypesData = None # RC4 doesn"t have salt 79 | cipher = _enctype_table[enctype] 80 | 81 | salt = encryptionTypesData[enctype] if encryptionTypesData else '' 82 | key = cipher.string_to_key(password, salt, None) 83 | 84 | # Let"s build the timestamp 85 | timeStamp = PA_ENC_TS_ENC() 86 | 87 | now = datetime.datetime.utcnow() 88 | timeStamp["patimestamp"] = KerberosTime.to_asn1(now) 89 | timeStamp["pausec"] = now.microsecond 90 | 91 | encodedTimeStamp = encoder.encode(timeStamp) 92 | 93 | # Key Usage 1 94 | # AS-REQ PA-ENC-TIMESTAMP padata timestamp, encrypted with the 95 | # client key (Section 5.2.7.2) 96 | encriptedTimeStamp = cipher.encrypt(key, 1, encodedTimeStamp, None) 97 | 98 | encryptedData = EncryptedData() 99 | encryptedData["etype"] = cipher.enctype 100 | encryptedData["cipher"] = encriptedTimeStamp 101 | encodedEncryptedData = encoder.encode(encryptedData) 102 | 103 | # Now prepare the new AS_REQ again with the PADATA 104 | # ToDo: cannot we reuse the previous one? 105 | asReq = AS_REQ() 106 | 107 | asReq['pvno'] = 5 108 | asReq['msg-type'] = int(constants.ApplicationTagNumbers.AS_REQ.value) 109 | 110 | asReq['padata'] = noValue 111 | asReq['padata'][0] = noValue 112 | asReq['padata'][0]['padata-type'] = int(constants.PreAuthenticationDataTypes.PA_ENC_TIMESTAMP.value) 113 | asReq['padata'][0]['padata-value'] = encodedEncryptedData 114 | 115 | asReq['padata'][1] = noValue 116 | asReq['padata'][1]['padata-type'] = int(constants.PreAuthenticationDataTypes.PA_PAC_REQUEST.value) 117 | asReq['padata'][1]['padata-value'] = encodedPacRequest 118 | 119 | reqBody = seq_set(asReq, 'req-body') 120 | 121 | opts = list() 122 | opts.append(constants.KDCOptions.forwardable.value) 123 | opts.append(constants.KDCOptions.renewable.value) 124 | opts.append(constants.KDCOptions.proxiable.value) 125 | reqBody["kdc-options"] = constants.encodeFlags(opts) 126 | 127 | seq_set(reqBody, "sname", serverName.components_to_asn1) 128 | seq_set(reqBody, "cname", clientName.components_to_asn1) 129 | 130 | reqBody["realm"] = domain 131 | 132 | now = datetime.datetime.utcnow() + datetime.timedelta(days=1) 133 | reqBody["till"] = KerberosTime.to_asn1(now) 134 | reqBody["rtime"] = KerberosTime.to_asn1(now) 135 | reqBody["nonce"] = random.getrandbits(31) 136 | 137 | seq_set_iter(reqBody, "etype", ((int(cipher.enctype),))) 138 | 139 | try: 140 | tgt = sendReceive(encoder.encode(asReq), domain, kdc_host) 141 | except Exception, e: 142 | if str(e).find('KDC_ERR_PREAUTH_FAILED') >= 0: 143 | return False 144 | raise 145 | 146 | return True 147 | 148 | 149 | class mod_AV_PAIRS: 150 | def __init__(self, data = None): 151 | self.fields = {} 152 | if data is not None: 153 | self.fromString(data) 154 | 155 | def __setitem__(self,key,value): 156 | self.fields[key] = value 157 | 158 | def __getitem__(self, key): 159 | if key in self.fields: 160 | return self.fields[key] 161 | return None 162 | 163 | def __delitem__(self, key): 164 | del self.fields[key] 165 | 166 | def __len__(self): 167 | return len(self.getData()) 168 | 169 | def __str__(self): 170 | return len(self.getData()) 171 | 172 | def fromString(self, data): 173 | tInfo = data 174 | fType = 0xff 175 | while fType is not NTLMSSP_AV_EOL: 176 | fType = struct.unpack('