Skip to content

Commit bb668ca

Browse files
authored
Merge pull request Pennyw0rth#857 from Pennyw0rth/neff-add-certipy-find
Add certipy module with 'find' implementation
2 parents 5c5f19b + 7de5c48 commit bb668ca

4 files changed

Lines changed: 279 additions & 51 deletions

File tree

nxc/logger.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ def __init__(self, extra=None, merge_extra=False):
101101
logging.getLogger("minidump").disabled = True
102102
logging.getLogger("lsassy").disabled = True
103103
logging.getLogger("dploot").disabled = True
104+
logging.getLogger("certipy").disabled = True
104105
logging.getLogger("aardwolf").disabled = True
105106
logging.getLogger("unicrypto").disabled = True
106107
logging.getLogger("asyncio").setLevel(logging.ERROR)

nxc/modules/certipy-find.py

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
#!/usr/bin/env python3
2+
import json
3+
from os import makedirs
4+
from certipy.commands.find import Find
5+
from certipy.lib.target import Target, DnsResolver
6+
from certipy.lib.formatting import pretty_print
7+
from datetime import datetime
8+
9+
from nxc.helpers.misc import CATEGORY
10+
from nxc.paths import NXC_PATH
11+
12+
13+
class NXCModule:
14+
"""Module made by: @NeffIsBack, @gatariee"""
15+
name = "certipy-find"
16+
description = "certipy find command with options to export the result to text/csv/json. Default: Show only vulnerable templates"
17+
supported_protocols = ["ldap"]
18+
category = CATEGORY.ENUMERATION
19+
20+
def __init__(self, context=None, module_options=None):
21+
self.context = context
22+
self.module_options = module_options
23+
24+
def options(self, context, module_options):
25+
"""
26+
VULN Show only vulnerable configurations (Default: True)
27+
ENABLED Show only enabled templates
28+
29+
Export options:
30+
TEXT Export results to a plain text file
31+
CSV Export results to a CSV file
32+
JSON Export results to a JSON file
33+
"""
34+
self.vuln = True
35+
self.enabled = False
36+
self.output_path = f"{NXC_PATH}/modules/certipy-find"
37+
self.json = False
38+
self.csv = False
39+
self.text = False
40+
41+
if "VULN" in module_options:
42+
self.vuln = module_options["VULN"].lower() in ["true", "1", "yes"]
43+
if "ENABLED" in module_options:
44+
self.enabled = module_options["ENABLED"].lower() in ["true", "1", "yes"]
45+
46+
# Export options
47+
if "JSON" in module_options:
48+
self.json = module_options["JSON"].lower() in ["true", "1", "yes"]
49+
if "CSV" in module_options:
50+
self.csv = module_options["CSV"].lower() in ["true", "1", "yes"]
51+
if "TEXT" in module_options:
52+
self.text = module_options["TEXT"].lower() in ["true", "1", "yes"]
53+
54+
def on_login(self, context, connection):
55+
resolv = DnsResolver.create(connection.args.dns_server if connection.args.dns_server else connection.host)
56+
target = Target(
57+
resolver=resolv,
58+
domain=connection.domain,
59+
username=connection.username,
60+
password=connection.password,
61+
lmhash=connection.lmhash,
62+
nthash=connection.nthash,
63+
target_ip=connection.host,
64+
ldap_port=connection.port,
65+
ldap_scheme="ldaps" if connection.port == 636 else "ldap",
66+
ldap_signing=connection.signing_required,
67+
ldap_channel_binding=connection.cbt_status in ["Always", "When Supported"],
68+
)
69+
70+
finder = Find(
71+
target=target,
72+
json=self.json,
73+
csv=self.csv,
74+
text=self.text,
75+
output_path=self.output_path,
76+
stdout=True,
77+
vulnerable=self.vuln,
78+
enabled=self.enabled,
79+
)
80+
81+
# Get templates and CAs
82+
templates = finder.get_certificate_templates()
83+
cas = finder.get_certificate_authorities()
84+
finder._link_cas_and_templates(cas, templates)
85+
86+
# Get OIDs
87+
oids = finder.get_issuance_policies()
88+
89+
# Process information
90+
finder._link_templates_and_policies(templates, oids)
91+
finder._process_ca_properties(cas)
92+
finder._process_template_properties(templates)
93+
94+
output = finder.get_output_for_text_and_json(templates, cas, oids)
95+
pretty_print(output, print_func=context.log.highlight)
96+
97+
# Save to disk if any export option specified
98+
if self.json or self.csv or self.text:
99+
makedirs(self.output_path, exist_ok=True)
100+
101+
filename = f"certipy_{connection.hostname}_{connection.host}_{datetime.now().strftime('%Y-%m-%d_%H%M%S')}".replace(":", "-")
102+
if self.json:
103+
with open(f"{self.output_path}/{filename}.json", "w") as f:
104+
json.dump(
105+
output,
106+
f,
107+
indent=2,
108+
default=str,
109+
)
110+
if self.csv:
111+
template_output = finder.get_template_output_for_csv(output)
112+
ca_output = finder.get_ca_output_for_csv(output)
113+
with open(f"{self.output_path}/{filename}-templates.csv", "w") as f:
114+
f.write(template_output)
115+
with open(f"{self.output_path}/{filename}-cas.csv", "w") as f:
116+
f.write(ca_output)
117+
if self.text:
118+
with open(f"{self.output_path}/{filename}.txt", "w") as f:
119+
pretty_print(output, print_func=lambda x: f.write(x + "\n"))

0 commit comments

Comments
 (0)