Skip to content

Commit 8c37f34

Browse files
committed
Create dump-computers.py
ldap module
1 parent 78c08df commit 8c37f34

1 file changed

Lines changed: 87 additions & 0 deletions

File tree

nxc/modules/dump-computers.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
from nxc.logger import nxc_logger
2+
from impacket.ldap.ldap import LDAPSearchError
3+
from impacket.ldap.ldapasn1 import SearchResultEntry
4+
5+
class NXCModule:
6+
7+
name = "dump-computers"
8+
description = "Dumps all computers in the domain"
9+
supported_protocols = ["ldap"]
10+
opsec_safe = True
11+
multiple_hosts = False
12+
13+
def options(self, context, module_options):
14+
"""
15+
dump-computers: Specify dump-computers to call the module
16+
Usage:
17+
18+
>prints fqdn and version
19+
nxc ldap $DC-IP -u Username -p Password -M dump-computers
20+
21+
>prints only netbios name
22+
nxc ldap $DC-IP -u Username -p Password -M dump-computers -o NETBIOS=True
23+
24+
>prints fqdn and version, output to file
25+
nxc ldap $DC-IP -u Username -p Password -M dump-computers -o OUTPUT=<location>
26+
27+
>prints only netbios name, output to file
28+
nxc ldap $DC-IP -u Username -p Password -M dump-computers -o OUTPUT=<location> -o NETBIOS=True
29+
30+
"""
31+
self.output_file = None
32+
self.netbios_only = False
33+
34+
if "OUTPUT" in module_options:
35+
self.output_file = module_options["OUTPUT"]
36+
if "NETBIOS" in module_options and module_options["NETBIOS"].lower() == "true":
37+
self.netbios_only = True
38+
39+
def on_login(self, context, connection):
40+
search_filter = "(objectCategory=computer)"
41+
42+
try:
43+
context.log.debug(f"Search Filter={search_filter}")
44+
resp = connection.ldap_connection.search(searchFilter=search_filter, attributes=["dNSHostName", "operatingSystem"], sizeLimit=0)
45+
except LDAPSearchError as e:
46+
if e.getErrorString().find("sizeLimitExceeded") >= 0:
47+
context.log.debug("sizeLimitExceeded exception caught, giving up and processing the data received")
48+
resp = e.getAnswers()
49+
else:
50+
nxc_logger.debug(e)
51+
return False
52+
53+
answers = []
54+
context.log.debug(f"Total no. of records returned: {len(resp)}")
55+
for item in resp:
56+
if isinstance(item, SearchResultEntry) is not True:
57+
continue
58+
dns_host_name = ""
59+
operating_system = ""
60+
try:
61+
for attribute in item["attributes"]:
62+
if str(attribute["type"]) == "dNSHostName":
63+
dns_host_name = str(attribute["vals"][0])
64+
elif str(attribute["type"]) == "operatingSystem":
65+
operating_system = attribute["vals"][0]
66+
if dns_host_name:
67+
netbios_name = dns_host_name.split(".")[0]
68+
answer = netbios_name if self.netbios_only else f"{dns_host_name} ({operating_system})"
69+
answers.append(answer)
70+
except Exception as e:
71+
context.log.debug("Exception:", exc_info=True)
72+
context.log.debug(f"Skipping item, cannot process due to error {e}")
73+
74+
if len(answers) > 0:
75+
context.log.success("Found the following computers: ")
76+
for answer in answers:
77+
context.log.highlight(answer)
78+
79+
if self.output_file:
80+
try:
81+
with open(self.output_file, "w") as f:
82+
f.write("\n".join(answers) + "\n")
83+
context.log.success(f"Results saved to {self.output_file}")
84+
except Exception as e:
85+
context.log.error(f"Failed to write to file {self.output_file}: {e}")
86+
else:
87+
context.log.success("No computers found in the domain.")

0 commit comments

Comments
 (0)