Skip to content

Commit da9a820

Browse files
committed
Revert "v2.1"
This reverts commit 23edd20.
1 parent c740f6a commit da9a820

File tree

8 files changed

+19
-138
lines changed

8 files changed

+19
-138
lines changed

README.md

Lines changed: 13 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11

2-
3-
## about revealhashed-python v0.2.1
2+
## about revealhashed-python v0.1.4
43
revealhashed is a streamlined utility to correlate ntds usernames, nt hashes, and cracked passwords in one view while cutting out time-consuming manual tasks.
54

65
## dependencies
76
hashcat
87
impacket or python3-impacket
9-
neo4j
108

119
## how to install
1210
from pypi:
@@ -16,17 +14,17 @@ from github:
1614
`pipx install git+https://github.com/crosscutsaw/revealhashed-python`
1715

1816
from deb package:
19-
`wget https://github.com/crosscutsaw/revealhashed-python/releases/latest/download/revealhashed_0.2.1_all.deb; apt install ./revealhashed_0.2.1_all.deb`
17+
`wget https://github.com/crosscutsaw/revealhashed-python/releases/latest/download/revealhashed_0.1.4_all.deb; apt install ./revealhashed_0.1.4_all.deb`
2018

2119
from whl package:
22-
`wget https://github.com/crosscutsaw/revealhashed-python/releases/latest/download/revealhashed-0.2.1-py3-none-any.whl; pipx install revealhashed-0.2.1-py3-none-any.whl`
20+
`wget https://github.com/crosscutsaw/revealhashed-python/releases/latest/download/revealhashed-0.1.4-py3-none-any.whl; pipx install revealhashed-0.1.4-py3-none-any.whl`
2321

2422
## don't want to install?
2523
grab revealhashed binary from [here](https://github.com/crosscutsaw/revealhashed-python/releases/latest/download/revealhashed).
2624

2725
## how to use
2826
```
29-
revealhashed v0.2.1
27+
revealhashed v0.1.4
3028
3129
usage: revealhashed [-h] [-r] {dump,reveal} ...
3230
@@ -44,50 +42,26 @@ just execute `revealhashed -r` to remove contents of ~/.revealhashed
4442

4543
### revealhashed dump
4644
```
47-
revealhashed v0.2.1
48-
49-
usage: revealhashed dump [-h] [-debug] [-hashes HASHES] [-no-pass] [-k] [-aesKey AESKEY] [-dc-ip DC_IP] [-codec CODEC] -w WORDLIST WORDLIST2 [WORDLIST WORDLIST2 ...] [-e] [-nd] [-csv] [-bh] [--dburi DBURI] [--dbuser DBUSER] [--dbpassword DBPASSWORD] target
50-
51-
positional arguments:
52-
target Target for NTDS dumping (e.g. domain/user:pass@host)
45+
revealhashed v0.1.4
5346
54-
options:
55-
-h, --help show this help message and exit
56-
-debug
57-
-hashes HASHES
58-
-no-pass
59-
-k
60-
-aesKey AESKEY
61-
-dc-ip DC_IP
62-
-codec CODEC
63-
-w WORDLIST WORDLIST2 [WORDLIST WORDLIST2 ...], --wordlists WORDLIST WORDLIST2 [WORDLIST WORDLIST2 ...]
64-
Wordlists to use with hashcat
65-
-e, --enabled-only Only show enabled accounts
66-
-nd, --no-domain Don't display domain in usernames
67-
-csv Save output in CSV format
68-
-bh Mark cracked users as owned in BloodHound
69-
--dburi DBURI BloodHound Neo4j URI
70-
--dbuser DBUSER BloodHound Neo4j username
71-
--dbpassword DBPASSWORD
72-
BloodHound Neo4j password
47+
usage: revealhashed dump [-h] [-debug] [-hashes HASHES] [-no-pass] [-k] [-aesKey AESKEY] [-dc-ip DC_IP] [-codec CODEC] -w WORDLIST WORDLIST2 [WORDLIST WORDLIST2 ...] [-e] [-nd] [-csv] target
7348
```
7449

7550
this command executes [zblurx's ntdsutil.py](https://github.com/zblurx/ntdsutil.py) to dump ntds safely then does classic revealhashed operations.
7651

7752
-w (wordlist) switch is needed. one or more wordlists can be supplied.
78-
-e (enabled-only) switch is suggested. it's only shows enabled users.
53+
-e (enabled-only) switch is suggested. it's self explanatory; only shows enabled users.
7954
-nd (no-domain) switch hides domain names in usernames.
80-
-bh (bloodhound) switch marks cracked users as owned in bloodhound. if used, `--dburi`, `--dbuser` and `--dbpassword` are also needed to connect neo4j database. it supports both legacy and ce.
81-
-csv (csv) switch saves output to csv, together with txt.
55+
-csv (csv) switch is self explanatory; saves output to csv, together with txt.
8256

8357
for example:
84-
`revealhashed dump '<domain>/<username>:<password>'@<dc_ip> -w wordlist1.txt wordlist2.txt -e -nd -csv -bh --dburi bolt://localhost:7687 --dbuser neo4j --dbpassword 1234`
58+
`revealhashed dump '<domain>/<username>:<password>'@<dc_ip> -w wordlist1.txt wordlist2.txt -e -nd -csv`
8559

8660
### revealhashed reveal
8761
```
88-
revealhashed v0.2.1
62+
revealhashed v0.1.4
8963
90-
usage: revealhashed reveal [-h] [-ntds NTDS] [-nxc] [-w WORDLIST WORDLIST2 [WORDLIST WORDLIST2 ...]] [-e] [-nd] [-csv] [-bh] [--dburi DBURI] [--dbuser DBUSER] [--dbpassword DBPASSWORD]
64+
usage: revealhashed reveal [-h] [-ntds NTDS] [-nxc] [-w WORDLIST WORDLIST2 [WORDLIST WORDLIST2 ...]] [-e] [-nd] [-csv]
9165
9266
options:
9367
-h, --help show this help message and exit
@@ -98,11 +72,6 @@ options:
9872
-e, --enabled-only Only show enabled accounts
9973
-nd, --no-domain Don't display domain in usernames
10074
-csv Save output in CSV format
101-
-bh Mark cracked users as owned in BloodHound
102-
--dburi DBURI BloodHound Neo4j URI
103-
--dbuser DBUSER BloodHound Neo4j username
104-
--dbpassword DBPASSWORD
105-
BloodHound Neo4j password
10675
```
10776

10877
this command wants to get supplied with ntds file by user or netexec then does classic revealhashed operations.
@@ -111,10 +80,9 @@ this command wants to get supplied with ntds file by user or netexec then does c
11180

11281
-ntds or -nxc switch is needed. -ntds switch is for a file you own with hashes. -nxc switch is for scanning ~/.nxc/logs/ntds directory then selecting .ntds file.
11382
-w (wordlist) switch is needed. one or more wordlists can be supplied.
114-
-e (enabled-only) switch is suggested. it's only shows enabled users.
83+
-e (enabled-only) switch is suggested. it's self explanatory; only shows enabled users.
11584
-nd (no-domain) switch hides domain names in usernames.
116-
-bh (bloodhound) switch marks cracked users as owned in bloodhound. if used, `--dburi`, `--dbuser` and `--dbpassword` are also needed to connect neo4j database. it supports both legacy and ce.
117-
-csv (csv) switch saves output to csv, together with txt.
85+
-csv (csv) switch is self explanatory; saves output to csv, together with txt.
11886

11987
for example:
12088
`revealhashed reveal -ntds <ntds_file>.ntds -w wordlist1.txt -e -nd -csv`
@@ -128,5 +96,3 @@ for example:
12896
![](https://raw.githubusercontent.com/crosscutsaw/revealhashed-python/main/rp3.PNG)
12997

13098
![](https://raw.githubusercontent.com/crosscutsaw/revealhashed-python/main/rp4.PNG)
131-
132-
![](https://raw.githubusercontent.com/crosscutsaw/revealhashed-python/main/rp5.PNG)

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
[project]
22
name = "revealhashed"
3-
version = "0.2.1"
3+
version = "0.1.4"
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 = "emre@zurrak.com" }]
66
license = { text = "MIT" }
77
readme = "README.md"
88
requires-python = ">=3.7"
9-
dependencies = ["impacket","neo4j"]
9+
dependencies = ["impacket"]
1010

1111
[project.scripts]
1212
revealhashed = "revealhashed.__main__:main"

revealhashed/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "0.2.1"
1+
__version__ = "0.1.0"

revealhashed/core.py

Lines changed: 3 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,6 @@
2222
# ntds class
2323
from impacket.examples.secretsdump import NTDSHashes, LocalOperations
2424

25-
# neo4j
26-
from neo4j import Auth, GraphDatabase
27-
from neo4j.exceptions import ServiceUnavailable
28-
2925
# constants
3026
HOME = Path.home()
3127
TMP_DIR = HOME / ".revealhashed"
@@ -64,10 +60,6 @@ def parse_args():
6460
dump_parser.add_argument("-e", "--enabled-only", action="store_true", help="Only show enabled accounts")
6561
dump_parser.add_argument('-nd', '--no-domain', action='store_true', help="Don't display domain in usernames")
6662
dump_parser.add_argument('-csv', action='store_true', help="Save output in CSV format")
67-
dump_parser.add_argument('-bh', action='store_true', help="Mark cracked users as owned in BloodHound")
68-
dump_parser.add_argument('--dburi', help='BloodHound Neo4j URI')
69-
dump_parser.add_argument('--dbuser', help='BloodHound Neo4j username')
70-
dump_parser.add_argument('--dbpassword', help='BloodHound Neo4j password')
7163
# do not include -outputdir
7264

7365
# subparser: reveal
@@ -78,10 +70,7 @@ def parse_args():
7870
reveal_parser.add_argument("-e", "--enabled-only", action="store_true", help="Only show enabled accounts")
7971
reveal_parser.add_argument('-nd', '--no-domain', action='store_true', help="Don't display domain in usernames")
8072
reveal_parser.add_argument('-csv', action='store_true', help="Save output in CSV format")
81-
reveal_parser.add_argument('-bh', action='store_true', help="Mark cracked users as owned in BloodHound")
82-
reveal_parser.add_argument('--dburi', help='BloodHound Neo4j URI')
83-
reveal_parser.add_argument('--dbuser', help='BloodHound Neo4j username')
84-
reveal_parser.add_argument('--dbpassword', help='BloodHound Neo4j password')
73+
8574
return parser
8675

8776
def reset_tmp_dir():
@@ -98,76 +87,6 @@ def create_session_dir():
9887
session_path.mkdir(parents=True, exist_ok=True)
9988
return session_path
10089

101-
def mark_bloodhound_owned(txt_file_path, dburi, dbuser, dbpassword):
102-
try:
103-
driver = GraphDatabase.driver(dburi, auth=Auth(scheme="basic", principal=dbuser, credentials=dbpassword))
104-
driver.verify_connectivity()
105-
print(f"\n{BOLD_GREEN}[+]{RESET} Connected to BloodHound Neo4j database at {dburi} as {dbuser}\n")
106-
107-
# infer domain from first valid user line
108-
inferred_domain = None
109-
with open(txt_file_path) as f:
110-
for line in f:
111-
if "<no password>" in line:
112-
continue
113-
parts = line.strip().split()
114-
if not parts:
115-
continue
116-
user_field = parts[0]
117-
if "\\" in user_field:
118-
inferred_domain = user_field.split("\\", 1)[0].upper()
119-
break
120-
121-
with driver.session() as session:
122-
with open(txt_file_path) as f:
123-
for line in f:
124-
if "<no password>" in line:
125-
continue
126-
parts = line.strip().split()
127-
if not parts:
128-
continue
129-
130-
user_field = parts[0]
131-
if "\\" in user_field:
132-
domain, user = user_field.split("\\", 1)
133-
else:
134-
user = user_field
135-
domain = inferred_domain or ""
136-
137-
is_computer = user.endswith("$")
138-
if is_computer:
139-
user = user.rstrip("$")
140-
full_name = f"{user}.{domain}".upper()
141-
label = "Computer"
142-
else:
143-
full_name = f"{user}@{domain}".upper()
144-
label = "User"
145-
146-
# try marking as owned
147-
query = f"MATCH (c:{label} {{name:'{full_name}'}}) RETURN c.owned AS owned"
148-
result = session.run(query).data()
149-
150-
if not result:
151-
print(f"{BOLD_RED}[-]{RESET} Node {full_name} not found in BloodHound")
152-
continue
153-
154-
if result[0]["owned"] is True:
155-
print(f"{BOLD_GREEN}[+]{RESET} {full_name} already marked as owned")
156-
continue
157-
158-
update_query = f"MATCH (c:{label} {{name:'{full_name}'}}) SET c.owned=true RETURN c.name AS name"
159-
update_result = session.run(update_query).data()
160-
161-
if update_result:
162-
print(f"{BOLD_GREEN}[+]{RESET} Marked {full_name} as owned in BloodHound")
163-
else:
164-
print(f"{BOLD_RED}[-]{RESET} Failed to mark {full_name} as owned in BloodHound")
165-
166-
except ServiceUnavailable:
167-
print(f"{BOLD_RED}[-]{RESET} BloodHound DB unreachable at {dburi}")
168-
except Exception as e:
169-
print(f"{BOLD_RED}[-]{RESET} Error while marking BloodHound: {e}")
170-
17190
def extract_unique_hashes(ntds_path, output_path, full_output_path, write_full_output=True):
17291
print(f"{BOLD_GREEN}[+]{RESET} Extracting unique NT hashes from: {ntds_path}")
17392
seen_hashes = set()
@@ -280,7 +199,7 @@ def reveal_credentials(individual_ntds_path, cracked_hashes, session_dir, enable
280199
print(f"{BOLD_GREEN}[+]{RESET} Output saved to {output_file_csv}")
281200

282201
def main():
283-
print(f"\n{BOLD_BLUE}revealhashed v0.2.1{RESET}\n")
202+
print(f"\n{BOLD_BLUE}revealhashed v0.1.4{RESET}\n")
284203

285204
parser = parse_args()
286205
args = parser.parse_args()
@@ -370,8 +289,6 @@ def main():
370289
shutil.copy(HASHCAT_POT, session_dir)
371290
cracked = parse_potfile(HASHCAT_POT)
372291
reveal_credentials(ind_path, cracked, session_dir, enabled_only=args.enabled_only, no_domain=args.no_domain, to_csv=args.csv)
373-
if getattr(args, "bh", False):
374-
mark_bloodhound_owned(session_dir / "revealhashed.txt", args.dburi, args.dbuser, args.dbpassword)
375292

376293
elif args.command == "reveal":
377294
if args.nxc:
@@ -423,13 +340,11 @@ def main():
423340
shutil.copy(HASHCAT_POT, session_dir)
424341
cracked = parse_potfile(HASHCAT_POT)
425342
reveal_credentials(ind_path, cracked, session_dir, enabled_only=args.enabled_only, no_domain=args.no_domain, to_csv=args.csv)
426-
if getattr(args, "bh", False):
427-
mark_bloodhound_owned(session_dir / "revealhashed.txt", args.dburi, args.dbuser, args.dbpassword)
428343

429344
if __name__ == "__main__":
430345
main()
431346

432-
# revealhashed v0.2.1
347+
# revealhashed v0.1.4
433348
#
434349
# contact options
435350
# mail: https://blog.zurrak.com/contact.html

rp1.PNG

-90.3 KB
Loading

rp2.PNG

-4.74 KB
Loading

rp3.PNG

6.07 KB
Loading

rp5.PNG

-84.1 KB
Binary file not shown.

0 commit comments

Comments
 (0)