NetExec/nxc/modules/group_members.py

102 lines
4.1 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from impacket.ldap import ldapasn1 as ldapasn1_impacket
class NXCModule:
"""
Module by CyberCelt: @Cyb3rC3lt
Initial module:
https://github.com/Cyb3rC3lt/CrackMapExec-Modules
"""
name = "group-mem"
description = "Retrieves all the members within a Group"
supported_protocols = ["ldap"]
opsec_safe = True
multiple_hosts = False
primaryGroupID = ""
answers = []
def options(self, context, module_options):
"""
group-mem: Specify group-mem to call the module
GROUP: Specify the GROUP option to query for that group's members
Usage: nxc ldap $DC-IP -u Username -p Password -M group-mem -o GROUP="domain admins"
nxc ldap $DC-IP -u Username -p Password -M group-mem -o GROUP="domain controllers"
"""
self.GROUP = ""
if "GROUP" in module_options:
self.GROUP = module_options["GROUP"]
else:
context.log.error("GROUP option is required!")
exit(1)
def on_login(self, context, connection):
# First look up the SID of the group passed in
search_filter = "(&(objectCategory=group)(cn=" + self.GROUP + "))"
attribute = "objectSid"
search_result = do_search(self, context, connection, search_filter, attribute)
# If no SID for the Group is returned exit the program
if search_result is None:
context.log.success('Unable to find any members of the "' + self.GROUP + '" group')
return True
# Convert the binary SID to a primaryGroupID string to be used further
sid_string = connection.sid_to_str(search_result).split("-")
self.primaryGroupID = sid_string[-1]
# Look up the groups DN
search_filter = "(&(objectCategory=group)(cn=" + self.GROUP + "))"
attribute = "distinguishedName"
distinguished_name = (do_search(self, context, connection, search_filter, attribute)).decode("utf-8")
# Carry out the search
search_filter = "(|(memberOf=" + distinguished_name + ")(primaryGroupID=" + self.primaryGroupID + "))"
attribute = "sAMAccountName"
search_result = do_search(self, context, connection, search_filter, attribute)
if len(self.answers) > 0:
context.log.success("Found the following members of the " + self.GROUP + " group:")
for answer in self.answers:
context.log.highlight(f"{answer[0]}")
# Carry out an LDAP search for the Group with the supplied Group name
def do_search(self, context, connection, searchFilter, attributeName):
try:
context.log.debug(f"Search Filter={searchFilter}")
resp = connection.ldapConnection.search(
searchFilter=searchFilter,
attributes=[attributeName],
sizeLimit=0
)
context.log.debug(f"Total number of records returned {len(resp)}")
for item in resp:
if isinstance(item, ldapasn1_impacket.SearchResultEntry) is not True:
continue
attribute_value = ""
try:
for attribute in item["attributes"]:
if str(attribute["type"]) == attributeName:
if attributeName == "objectSid":
attribute_value = bytes(attribute["vals"][0])
return attribute_value
elif attributeName == "distinguishedName":
attribute_value = bytes(attribute["vals"][0])
return attribute_value
else:
attribute_value = str(attribute["vals"][0])
if attribute_value is not None:
self.answers.append([attribute_value])
except Exception as e:
context.log.debug("Exception:", exc_info=True)
context.log.debug(f"Skipping item, cannot process due to error {e}")
pass
except Exception as e:
context.log.debug(f"Exception: {e}")
return False