Skip to content

Commit

Permalink
Public release
Browse files Browse the repository at this point in the history
  • Loading branch information
p0dalirius committed Mar 2, 2024
1 parent da4fa97 commit e02d46a
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 55 deletions.
4 changes: 4 additions & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# These are supported funding model platforms

github: p0dalirius
patreon: Podalirius
Binary file added .github/banner.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
75 changes: 22 additions & 53 deletions CrackedNTDStoXLSX.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# File name : ldapsearch.py
# File name : CrackedNTDStoXLSX.py
# Author : Podalirius (@podalirius_)
# Date created : 29 Jul 2021
# Date created : 01 March 2023


import argparse
from ldap3.protocol.formatters.formatters import format_sid
import ldap3
from sectools.windows.ldap import raw_ldap_query, init_ldap_session
from sectools.windows.crypto import nt_hash, parse_lm_nt_hashes
from sectools.windows.ldap import init_ldap_session
import os
import traceback
import sys
Expand Down Expand Up @@ -141,52 +141,11 @@ def query_all_naming_contexts(self, query, attributes=['*'], page_size=1000):
raise e
return results

def print_colored_result(self, dn, data):
def _parse_print(element, depth=0, maxdepth=15, prompt=[' | ', ' └─>']):
_pre = prompt[0] * (depth) + prompt[1]
if depth < maxdepth:
if type(element) == ldap3.utils.ciDict.CaseInsensitiveDict:
element = {key: value for key, value in element.items()}
if type(element) == dict:
for key in element.keys():
if type(element[key]) == dict:
_parse_print(element[key], depth=(depth + 1), maxdepth=maxdepth, prompt=prompt)
#
elif type(element[key]) == ldap3.utils.ciDict.CaseInsensitiveDict:
_ldap_ciDict = {key: value for key, value in element[key].items()}
_parse_print(_ldap_ciDict, depth=(depth + 1), maxdepth=maxdepth, prompt=prompt)
#
elif type(element[key]) == list:
if len(element[key]) == 0:
print(_pre + "\"\x1b[92m%s\x1b[0m\": []" % str(key))
elif len(element[key]) == 1:
print(_pre + "\"\x1b[92m%s\x1b[0m\": [\x1b[96m%s\x1b[0m]" % (str(key), element[key][0]))
else:
print(_pre + "\"\x1b[92m%s\x1b[0m\": %s" % (str(key), "["))
for _list_element in element[key]:
_parse_print(_list_element, depth=(depth + 1), maxdepth=maxdepth, prompt=prompt)
print(_pre + "%s" % "],")
#
elif type(element[key]) == str:
print(_pre + "\"\x1b[92m%s\x1b[0m\": \"\x1b[96m%s\x1b[0m\"," % (str(key), str(element[key])))
#
else:
print(prompt[0] * (depth) + prompt[1] + "\"\x1b[92m%s\x1b[0m\": \x1b[96m%s\x1b[0m," % (str(key), str(element[key])))
else:
print(prompt[0] * (depth) + prompt[1] + "\x1b[96m%s\x1b[0m" % str(element))
else:
# Max depth reached
pass
#
print("[>] %s" % dn)
_parse_print(data, prompt=[' ', ' '])



def parse_args():
default_attributes = ["accountExpires", "company", "department", "description", "displayName", "distinguishedName", "lastLogon", "lastLogonTimestamp", "memberOf", "whenChanged", "whenCreated"]

parser = argparse.ArgumentParser(add_help=True, description='CrackedNTDStoXLSX.py')
parser = argparse.ArgumentParser(add_help=True, description='A python tool to generate an Excel file linking the list of cracked accounts and their LDAP attributes.')
parser.add_argument('--use-ldaps', action='store_true', help='Use LDAPS instead of LDAP')
parser.add_argument("-debug", dest="debug", action="store_true", default=False, help="Debug mode")

Expand Down Expand Up @@ -219,6 +178,7 @@ def parse_args():


def export_xlsx(options, results):
# Prepare file path
basepath = os.path.dirname(options.xlsx)
filename = os.path.basename(options.xlsx)
if basepath not in [".", ""]:
Expand All @@ -228,6 +188,7 @@ def export_xlsx(options, results):
else:
path_to_file = filename

# Create Excel workbook
# https://xlsxwriter.readthedocs.io/workbook.html#Workbook
workbook_options = {
'constant_memory': True,
Expand All @@ -238,6 +199,7 @@ def export_xlsx(options, results):
workbook = xlsxwriter.Workbook(filename=path_to_file, options=workbook_options)
worksheet = workbook.add_worksheet()

# Prepare attributes
if '*' in options.attributes:
attributes = []
options.attributes.remove('*')
Expand All @@ -248,22 +210,24 @@ def export_xlsx(options, results):
else:
attributes = options.attributes

# Format colmun headers
header_format = workbook.add_format({'bold': 1})
header_format.set_pattern(1)
header_format.set_bg_color('green')

header_fields = ["domain", "username", "nthash", "password"]
# for h in header_fields:
# attributes = attributes.remove(h)
header_fields = header_fields + attributes
for k in range(len(header_fields)):
worksheet.set_column(k, k + 1, len(header_fields[k]) + 3)
worksheet.set_row(0, 40, header_format)
worksheet.write_row(0, 0, header_fields)
worksheet.set_row(row=0, height=40, cell_format=header_format)
worksheet.write_row(row=0, col=0, data=header_fields)

row_id = 1
for entry, ldapresults in results:
data = [entry["domain"], entry["username"], entry["nthash"], entry["password"]]
if len(ldapresults.keys()) != 1:
if len(ldapresults.keys()) == 0:
worksheet.write_row(row_id, 0, data)
worksheet.write_row(row=row_id, col=0, data=data)
else:
print("Error for entry:", entry)
print(list(ldapresults.keys()))
Expand All @@ -282,10 +246,15 @@ def export_xlsx(options, results):
data.append(str(value))
else:
data.append("")
worksheet.write_row(row_id, 0, data)
worksheet.write_row(row=row_id, col=0, data=data)
row_id += 1

worksheet.autofilter(0, 0, row_id, len(header_fields) - 1)
worksheet.autofilter(
first_row=0,
first_col=0,
last_row=row_id,
last_col=(len(header_fields)-1)
)
workbook.close()

print("[>] Written '%s'" % path_to_file)
Expand Down
39 changes: 37 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,35 @@
# CrackedNTDStoXLSX
![](./.github/banner.png)

<p align="center">
A python tool to generate an Excel file linking the list of cracked accounts and their LDAP attributes.
<br>
<img alt="GitHub release (latest by date)" src="https://img.shields.io/github/v/release/p0dalirius/CrackedNTDStoXLSX">
<a href="https://twitter.com/intent/follow?screen_name=podalirius_" title="Follow"><img src="https://img.shields.io/twitter/follow/podalirius_?label=Podalirius&style=social"></a>
<a href="https://www.youtube.com/c/Podalirius_?sub_confirmation=1" title="Subscribe"><img alt="YouTube Channel Subscribers" src="https://img.shields.io/youtube/channel/subscribers/UCF_x5O7CSfr82AfNVTKOv_A?style=social"></a>
<br>
</p>

## Features

- [x] Authentications:
- [x] Authenticate with password
- [x] Authenticate with LM:NT hashes (Pass the Hash)
- [x] Authenticate with kerberos ticket (Pass the Ticket)
- [x] Exportable to XLSX format with option `--xlsx`

## Demonstration

This tool takes the output of hashcat

```bash
./hashcat -m 1000 ./lab.local.ntds ./wordlists/rockyou.txt --username --show > cracked_ntds.txt
```

Then you can do:

```bash
./CrackedNTDStoXLSX.py -d 'LAB.local' -u 'user' -p 'P@ssw0rd' --dc-ip 10.0.0.101 -n cracked_ntds.txt -x cracked_users.xlsx
```

## Usage

Expand All @@ -7,7 +38,7 @@ $ ./CrackedNTDStoXLSX.py
usage: CrackedNTDStoXLSX.py [-h] [--use-ldaps] [-debug] [-a ATTRIBUTES] -x XLSX -n NTDS [--dc-ip ip address] [--kdcHost FQDN KDC] [-d DOMAIN] [-u USER]
[--no-pass | -p PASSWORD | -H [LMHASH:]NTHASH | --aes-key hex key] [-k]
CrackedNTDStoXLSX.py
A python tool to generate an Excel file linking the list of cracked accounts and their LDAP attributes.
options:
-h, --help show this help message and exit
Expand All @@ -34,3 +65,7 @@ authentication & connection:
-k, --kerberos Use Kerberos authentication. Grabs credentials from .ccache file (KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use the ones specified in the
command line
```

## Contributing

Pull requests are welcome. Feel free to open an issue if you want to add other features.

0 comments on commit e02d46a

Please sign in to comment.