84 lines
3.6 KiB
Python
84 lines
3.6 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
import json
|
|
|
|
from impacket.ldap import ldapasn1 as ldapasn1_impacket
|
|
from nxc.protocols.ldap.laps import LDAPConnect, LAPSv2Extract
|
|
|
|
class NXCModule:
|
|
"""
|
|
Module by technobro refactored by @mpgn (now compatible with LDAP protocol + filter by computer)
|
|
|
|
Initial module:
|
|
@T3KX: https://github.com/T3KX/Crackmapexec-LAPS
|
|
|
|
Credit: @mpgn_x64, @n00py1
|
|
"""
|
|
|
|
name = "laps"
|
|
description = "Retrieves the LAPS passwords"
|
|
supported_protocols = ["ldap"]
|
|
opsec_safe = True
|
|
multiple_hosts = False
|
|
|
|
def options(self, context, module_options):
|
|
"""
|
|
COMPUTER Computer name or wildcard ex: WIN-S10, WIN-* etc. Default: *
|
|
"""
|
|
|
|
self.computer = None
|
|
if "COMPUTER" in module_options:
|
|
self.computer = module_options["COMPUTER"]
|
|
|
|
def on_login(self, context, connection):
|
|
context.log.display("Getting LAPS Passwords")
|
|
if self.computer is not None:
|
|
searchFilter = "(&(objectCategory=computer)(|(msLAPS-EncryptedPassword=*)(ms-MCS-AdmPwd=*)(msLAPS-Password=*))(name=" + self.computer + "))"
|
|
else:
|
|
searchFilter = "(&(objectCategory=computer)(|(msLAPS-EncryptedPassword=*)(ms-MCS-AdmPwd=*)(msLAPS-Password=*)))"
|
|
attributes = [
|
|
"msLAPS-EncryptedPassword",
|
|
"msLAPS-Password",
|
|
"ms-MCS-AdmPwd",
|
|
"sAMAccountName",
|
|
]
|
|
results = connection.search(searchFilter, attributes, 0)
|
|
results = [r for r in results if isinstance(r, ldapasn1_impacket.SearchResultEntry)]
|
|
if len(results) != 0:
|
|
laps_computers = []
|
|
for computer in results:
|
|
msMCSAdmPwd = ""
|
|
sAMAccountName = ""
|
|
values = {str(attr["type"]).lower(): attr["vals"][0] for attr in computer["attributes"]}
|
|
if "mslaps-encryptedpassword" in values:
|
|
msMCSAdmPwd = values["mslaps-encryptedpassword"]
|
|
d = LAPSv2Extract(
|
|
bytes(msMCSAdmPwd),
|
|
connection.username if connection.username else "",
|
|
connection.password if connection.password else "",
|
|
connection.domain,
|
|
connection.nthash if connection.nthash else "",
|
|
connection.kerberos,
|
|
connection.kdcHost,
|
|
339)
|
|
try:
|
|
data = d.run()
|
|
except Exception as e:
|
|
self.logger.fail(str(e))
|
|
return
|
|
r = json.loads(data)
|
|
laps_computers.append((str(values["samaccountname"]), r["n"], str(r["p"])))
|
|
elif "mslaps-password" in values:
|
|
r = json.loads(str(values["mslaps-password"]))
|
|
laps_computers.append((str(values["samaccountname"]), r["n"], str(r["p"])))
|
|
elif "ms-mcs-admpwd" in values:
|
|
laps_computers.append((str(values["samaccountname"]), "", str(values["ms-mcs-admpwd"])))
|
|
else:
|
|
context.log.fail("No result found with attribute ms-MCS-AdmPwd or msLAPS-Password")
|
|
|
|
laps_computers = sorted(laps_computers, key=lambda x: x[0])
|
|
for sAMAccountName, user, password in laps_computers:
|
|
context.log.highlight("Computer:{} User:{:<15} Password:{}".format(sAMAccountName, user, password))
|
|
else:
|
|
context.log.fail("No result found with attribute ms-MCS-AdmPwd or msLAPS-Password !")
|