Skip to content

Commit 38821f7

Browse files
committed
v0.1.2
1 parent 97e3a7b commit 38821f7

File tree

7 files changed

+94
-21
lines changed

7 files changed

+94
-21
lines changed

README.md

+17-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
## about revealhashed-python v0.1.1
1+
2+
## about revealhashed-python v0.1.2
23
revealhashed is a streamlined utility to correlate ntds usernames, nt hashes, and cracked passwords in one view while cutting out time-consuming manual tasks.
34

45
## how to install
@@ -8,9 +9,13 @@ from pypi:
89
from github:
910
`pipx install git+https://github.com/crosscutsaw/revealhashed-python`
1011

12+
## don't want to install?
13+
14+
grab revealhashed binary from [releases](https://github.com/crosscutsaw/revealhashed-python/releases/latest) section.
15+
1116
## how to use
1217
```
13-
revealhashed v0.1
18+
revealhashed v0.1.2
1419
1520
usage: revealhashed [-h] [-r] {dump,reveal} ...
1621
@@ -27,23 +32,28 @@ options:
2732
just execute `revealhashed -r` to remove contents of ~/.revealhashed
2833

2934
### revealhashed dump
30-
this command executes [zblurx's ntdsutil.py](https://github.com/zblurx/ntdsutil.py) then does classic revealhashed operations.
35+
this command executes [zblurx's ntdsutil.py](https://github.com/zblurx/ntdsutil.py) to dump ntds safely then does classic revealhashed operations.
3136

3237
-w (wordlist) switch is needed. one or more wordlists can be supplied.
3338
-e (enabled-only) switch is not needed but suggested. it's self explanatory; only shows enabled users.
3439

35-
for example: `revealhashed dump 'troupe.local/emreda:Aa123456'@192.168.2.11 -w wordlist1.txt wordlist2.txt -e`
40+
for example:
41+
`revealhashed dump 'troupe.local/emreda:Aa123456'@192.168.2.11 -w wordlist1.txt wordlist2.txt -e`
3642

3743
### revealhashed reveal
38-
this command wants to get supplied with ntds file by user then does classic revealhashed operations.
44+
this command wants to get supplied with ntds file by user then does classic revealhashed operations.
45+
_ntds file should contain usernames and hashes. it should be not ntds.dit. example ntds dump can be obtained from repo_
3946

40-
-ntds switch is needed.
47+
-ntds or -nxc switch is needed. -ntds switch is for a file you own with hashes. -nxc switch is for scanning ~/.nxc/logs/ntds then selecting .ntds file.
4148
-w (wordlist) switch is needed. one or more wordlists can be supplied.
4249
-e (enabled-only) switch is not needed but suggested. it's self explanatory; only shows enabled users.
4350

44-
for example: `revealhashed reveal -ntds TROUPEDC_192.168.2.11_2025-05-12_123035.ntds -w wordlist1.txt -e`
51+
for example:
52+
`revealhashed reveal -ntds TROUPEDC_192.168.2.11_2025-05-12_123035.ntds -w wordlist1.txt -e`
4553

4654
## example outputs
4755
![](https://raw.githubusercontent.com/crosscutsaw/revealhashed-python/main/rp1.PNG)
4856

4957
![](https://raw.githubusercontent.com/crosscutsaw/revealhashed-python/main/rp2.PNG)
58+
59+
![](https://raw.githubusercontent.com/crosscutsaw/revealhashed-python/main/rp3.PNG)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
Administrator:500:aad3b435b51404eeaad3b435b51404ee:2c1c756a7e80cb00b03ac7db8802c947::: (status=Enabled)
2+
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0::: (status=Disabled)
3+
krbtgt:502:aad3b435b51404eeaad3b435b51404ee:ee292567175d1131bd099acfd0251d5f::: (status=Disabled)
4+
DefaultAccount:503:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0::: (status=Disabled)
5+
emretest:1601:aad3b435b51404eeaad3b435b51404ee:47bf8039a8506cd67c524a03ff84ba4e::: (status=Enabled)
6+
troupe.local\abuzer.komurcu:1626:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0::: (status=Disabled)
7+
troupe.local\erdal.komurcu:1627:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0::: (status=Disabled)
8+
troupe.local\ersoy.ulubey:1628:aad3b435b51404eeaad3b435b51404ee:3c7408268811f6310eca314943a94564::: (status=Disabled)
9+
troupe.local\hakantasiyan:1629:aad3b435b51404eeaad3b435b51404ee:7b357db710907a0ab26b51be1da0b4a9::: (status=Enabled)
10+
troupe.local\azerbulbul:1630:aad3b435b51404eeaad3b435b51404ee:7b357db710907a0ab26b51be1da0b4a9::: (status=Disabled)
11+
troupe.local\devrancaglar:1631:aad3b435b51404eeaad3b435b51404ee:bc89cfa104790d312e2542eea4207aee::: (status=Disabled)
12+
troupe.local\muslumgurses:1632:aad3b435b51404eeaad3b435b51404ee:7b357db710907a0ab26b51be1da0b4a9::: (status=Disabled)
13+
troupe.local\selahattinozdemir:1633:aad3b435b51404eeaad3b435b51404ee:a9090a292c94f91aba40e4f47790bac3::: (status=Enabled)
14+
troupe.local\1_nopassword:1634:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0::: (status=Enabled)
15+
troupe.local\2_nopassword_disable:1635:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0::: (status=Disabled)
16+
troupe.local\3_password_disabled:1636:aad3b435b51404eeaad3b435b51404ee:2ef7256e0f88f6653220c88801bdcbb5::: (status=Disabled)
17+
troupe.local\longnametestA1B2C3D4:1637:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0::: (status=Disabled)
18+
gpptest:1638:aad3b435b51404eeaad3b435b51404ee:7c53cfa5ea7d0f9b3b968aa0fb51a3f5::: (status=Enabled)
19+
troupe.local\emreda:1644:aad3b435b51404eeaad3b435b51404ee:47bf8039a8506cd67c524a03ff84ba4e::: (status=Enabled)
20+
emreea:1647:aad3b435b51404eeaad3b435b51404ee:1674049edd3d39cead200b0fee90982a::: (status=Enabled)
21+
bbtest:1650:aad3b435b51404eeaad3b435b51404ee:67587a19e4c2b479f1fa85b95b544229::: (status=Enabled)
22+
cctest:1651:aad3b435b51404eeaad3b435b51404ee:a2af76c474f274222bec25b340f857a8::: (status=Enabled)
23+
dummy:1652:aad3b435b51404eeaad3b435b51404ee:ef8d80b784540a0ec71a1fc853985619::: (status=Enabled)
24+
TROUPEDC$:1000:aad3b435b51404eeaad3b435b51404ee:4791603d21ff3acdf373120bfc8ef66c::: (status=Enabled)
25+
EMRE-SBKCVF1D1N$:1640:aad3b435b51404eeaad3b435b51404ee:0e3c52a413f0b1338ca1634c86fe9d0a::: (status=Enabled)
26+
TESTULAN$:1642:aad3b435b51404eeaad3b435b51404ee:f216e2977b48aa936316e1ac06748894::: (status=Enabled)
27+
PENTEST$:1643:aad3b435b51404eeaad3b435b51404ee:4391854c7e1e24e278c91f26a6e7d03c::: (status=Enabled)
28+
PENTEST3$:1649:aad3b435b51404eeaad3b435b51404ee:9cae71d6709eaa45d6ec77c22d9d035a::: (status=Enabled)

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "revealhashed"
3-
version = "0.1.1"
3+
version = "0.1.2"
44
description = "Dump or analyze existing NTDS data, crack NT hashes with hashcat and match them to their corresponding user accounts."
55
authors = [{ name = "aslan emre aslan", email = "[email protected]" }]
66
license = "MIT"

revealhashed/core.py

+48-13
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,9 @@ def parse_args():
5151

5252
# subparser: reveal
5353
reveal_parser = subparsers.add_parser("reveal", help="Use your own NTDS dump then reveal credentials with it")
54-
reveal_parser.add_argument("-ntds", help="Path to .ntds file", required=True)
55-
reveal_parser.add_argument("-w", "--wordlists", nargs="+", metavar="WORDLIST WORDLIST2", help="Wordlists to use with hashcat", required=True)
54+
reveal_parser.add_argument("-ntds", help="Path to .ntds file")
55+
reveal_parser.add_argument("-nxc", action="store_true", help="Scan $HOME/.nxc/logs/ntds for .ntds files")
56+
reveal_parser.add_argument("-w", "--wordlists", nargs="+", metavar="WORDLIST WORDLIST2", help="Wordlists to use with hashcat", required=False)
5657
reveal_parser.add_argument("-e", "--enabled-only", action="store_true", help="Only show enabled accounts")
5758

5859
return parser
@@ -100,10 +101,10 @@ def extract_unique_hashes(ntds_path, output_path, full_output_path, write_full_o
100101
raise
101102

102103
def run_hashcat(hashes_file, wordlists):
103-
start = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
104+
start = datetime.now().strftime("%H:%M:%S %d-%m-%Y")
104105
print(f"{BOLD_GREEN}[+]{RESET} Starting hashcat session at {start}")
105106
subprocess.run(["hashcat", "-m1000", str(hashes_file), *wordlists, "--quiet"])
106-
end = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
107+
end = datetime.now().strftime("%H:%M:%S %d-%m-%Y")
107108
print(f"{BOLD_GREEN}[+]{RESET} Ended hashcat session at {end}")
108109

109110
def parse_potfile(potfile_path):
@@ -168,7 +169,7 @@ def reveal_credentials(individual_ntds_path, cracked_hashes, session_dir, enable
168169
print(f"\n{BOLD_GREEN}[+]{RESET} Output saved to {output_file}")
169170

170171
def main():
171-
print(f"\n{BOLD_BLUE}revealhashed v0.1{RESET}\n")
172+
print(f"\n{BOLD_BLUE}revealhashed v0.1.2{RESET}\n")
172173

173174
parser = parse_args()
174175
args = parser.parse_args()
@@ -188,16 +189,17 @@ def main():
188189
ntdsutil_dir = session_dir / "ntdsutil"
189190
ntdsutil_dir.mkdir(parents=True, exist_ok=True)
190191
args.outputdir = str(ntdsutil_dir)
191-
192-
print(f"{BOLD_GREEN}[+]{RESET} Starting NTDS dump with ntdsutil")
192+
193+
start = datetime.now().strftime("%H:%M:%S %d-%m-%Y")
194+
print(f"{BOLD_GREEN}[+]{RESET} Starting NTDS dump with ntdsutil at {start}")
193195

194196
try:
195197
ntdsutil.run_ntdsutil(args)
196198
except Exception as e:
197199
print(f"{BOLD_RED}[!]{RESET} NTDS dump failed: {e}")
198200
return
199-
200-
print(f"{BOLD_GREEN}[+]{RESET} NTDS successfully dumped!")
201+
end = datetime.now().strftime("%H:%M:%S %d-%m-%Y")
202+
print(f"{BOLD_GREEN}[+]{RESET} NTDS successfully dumped at {end}")
201203

202204
# run secretsdump in the same session folder
203205
system_path = ntdsutil_dir / "SYSTEM"
@@ -247,11 +249,37 @@ def main():
247249
reveal_credentials(ind_path, cracked, session_dir, enabled_only=args.enabled_only)
248250

249251
elif args.command == "reveal":
250-
if not args.ntds:
251-
print(f"{BOLD_RED}[!]{RESET} Please provide an NTDS file with -ntds")
252-
return
252+
if args.nxc:
253+
nxc_dir = Path.home() / ".nxc" / "logs" / "ntds"
254+
ntds_files = sorted(nxc_dir.glob("*.ntds"))
255+
256+
if not ntds_files:
257+
print(f"{BOLD_RED}[!]{RESET} No .ntds files found in {nxc_dir}")
258+
sys.exit(1)
259+
260+
print(f"{BOLD_GREEN}[+]{RESET} Found {len(ntds_files)} .ntds files in {nxc_dir}")
261+
for idx, f in enumerate(ntds_files):
262+
print(f"[{idx}] {f.name}")
263+
264+
while True:
265+
try:
266+
selection = int(input("\nSelect file by index: "))
267+
print()
268+
if 0 <= selection < len(ntds_files):
269+
ntds_path = ntds_files[selection]
270+
args.ntds = str(ntds_path)
271+
break
272+
else:
273+
print(f"\n{BOLD_RED}[!]{RESET} Invalid selection. Try again.")
274+
except ValueError:
275+
print(f"\n{BOLD_RED}[!]{RESET} Please enter a valid number.")
276+
else:
277+
if not args.ntds:
278+
print(f"{BOLD_RED}[!]{RESET} Please specify either -ntds or -nxc")
279+
sys.exit(1)
280+
ntds_path = Path(args.ntds)
253281
if not args.wordlists:
254-
print(f"{BOLD_RED}[!]{RESET} No wordlists provided. Use -w to specify at least one wordlist.")
282+
print(f"\n{BOLD_RED}[!]{RESET} No wordlists provided. Use -w to specify at least one wordlist.")
255283
return
256284

257285
TMP_DIR.mkdir(parents=True, exist_ok=True)
@@ -273,3 +301,10 @@ def main():
273301

274302
if __name__ == "__main__":
275303
main()
304+
305+
# revealhashed v0.1.2
306+
#
307+
# contact options
308+
# mail: https://blog.zurrak.com/contact.html
309+
# twitter: https://twitter.com/tasiyanci
310+
# linkedin: https://linkedin.com/in/aslanemreaslan

rp1.PNG

8.69 KB
Loading

rp2.PNG

8.32 KB
Loading

rp3.PNG

61.5 KB
Loading

0 commit comments

Comments
 (0)