dploot 3.2.0__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dploot/__init__.py +0 -0
- dploot/action/__init__.py +0 -0
- dploot/action/backupkey.py +102 -0
- dploot/action/blob.py +167 -0
- dploot/action/browser.py +192 -0
- dploot/action/certificates.py +146 -0
- dploot/action/cng.py +129 -0
- dploot/action/credentials.py +132 -0
- dploot/action/machinecertificates.py +136 -0
- dploot/action/machinecng.py +120 -0
- dploot/action/machinecredentials.py +120 -0
- dploot/action/machinemasterkeys.py +117 -0
- dploot/action/machinetriage.py +158 -0
- dploot/action/machinevaults.py +127 -0
- dploot/action/masterkeys.py +200 -0
- dploot/action/mobaxterm.py +138 -0
- dploot/action/rdg.py +132 -0
- dploot/action/sccm.py +125 -0
- dploot/action/triage.py +187 -0
- dploot/action/vaults.py +132 -0
- dploot/action/wam.py +133 -0
- dploot/action/wifi.py +137 -0
- dploot/entry.py +98 -0
- dploot/lib/__init__.py +0 -0
- dploot/lib/consts.py +30 -0
- dploot/lib/crypto.py +415 -0
- dploot/lib/dpapi.py +302 -0
- dploot/lib/masterkey.py +75 -0
- dploot/lib/smb.py +517 -0
- dploot/lib/target.py +219 -0
- dploot/lib/utils.py +99 -0
- dploot/lib/wmi.py +61 -0
- dploot/triage/__init__.py +30 -0
- dploot/triage/backupkey.py +81 -0
- dploot/triage/browser.py +441 -0
- dploot/triage/certificates.py +444 -0
- dploot/triage/cng.py +165 -0
- dploot/triage/credentials.py +163 -0
- dploot/triage/masterkeys.py +279 -0
- dploot/triage/mobaxterm.py +653 -0
- dploot/triage/rdg.py +249 -0
- dploot/triage/sccm.py +302 -0
- dploot/triage/vaults.py +307 -0
- dploot/triage/wam.py +251 -0
- dploot/triage/wifi.py +424 -0
- dploot-3.2.0.dist-info/METADATA +865 -0
- dploot-3.2.0.dist-info/RECORD +50 -0
- dploot-3.2.0.dist-info/WHEEL +4 -0
- dploot-3.2.0.dist-info/entry_points.txt +3 -0
- dploot-3.2.0.dist-info/licenses/LICENSE +21 -0
dploot/action/vaults.py
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import logging
|
|
3
|
+
import sys
|
|
4
|
+
from typing import Callable, Tuple
|
|
5
|
+
from dploot.action.masterkeys import (
|
|
6
|
+
add_masterkeys_argument_group,
|
|
7
|
+
parse_masterkeys_options,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
from dploot.lib.smb import DPLootSMBConnection
|
|
11
|
+
from dploot.lib.target import Target, add_target_argument_group
|
|
12
|
+
from dploot.lib.utils import dump_looted_files_to_disk, handle_outputdir_option
|
|
13
|
+
from dploot.triage.masterkeys import MasterkeysTriage, parse_masterkey_file
|
|
14
|
+
from dploot.triage.vaults import VaultsTriage
|
|
15
|
+
|
|
16
|
+
NAME = "vaults"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class VaultsAction:
|
|
20
|
+
def __init__(self, options: argparse.Namespace) -> None:
|
|
21
|
+
self.options = options
|
|
22
|
+
self.target = Target.from_options(options)
|
|
23
|
+
|
|
24
|
+
self.conn = None
|
|
25
|
+
self._is_admin = None
|
|
26
|
+
self.outputdir = None
|
|
27
|
+
self.masterkeys = None
|
|
28
|
+
self.pvkbytes = None
|
|
29
|
+
self.passwords = None
|
|
30
|
+
self.nthashes = None
|
|
31
|
+
|
|
32
|
+
self.outputdir = handle_outputdir_option(directory=self.options.export_dir)
|
|
33
|
+
|
|
34
|
+
if self.options.mkfile is not None:
|
|
35
|
+
try:
|
|
36
|
+
self.masterkeys = parse_masterkey_file(self.options.mkfile)
|
|
37
|
+
except Exception as e:
|
|
38
|
+
logging.error(str(e))
|
|
39
|
+
sys.exit(1)
|
|
40
|
+
|
|
41
|
+
self.pvkbytes, self.passwords, self.nthashes = parse_masterkeys_options(
|
|
42
|
+
self.options, self.target
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
def connect(self) -> None:
|
|
46
|
+
self.conn = DPLootSMBConnection(self.target)
|
|
47
|
+
if self.conn.connect() is None:
|
|
48
|
+
logging.error("Could not connect to %s" % self.target.address)
|
|
49
|
+
sys.exit(1)
|
|
50
|
+
|
|
51
|
+
def run(self) -> None:
|
|
52
|
+
self.connect()
|
|
53
|
+
logging.info(
|
|
54
|
+
"Connected to {} as {}\\{} {}\n".format(
|
|
55
|
+
self.target.address,
|
|
56
|
+
self.target.domain,
|
|
57
|
+
self.target.username,
|
|
58
|
+
("(admin)" if self.is_admin else ""),
|
|
59
|
+
)
|
|
60
|
+
)
|
|
61
|
+
if self.is_admin:
|
|
62
|
+
if self.masterkeys is None:
|
|
63
|
+
|
|
64
|
+
def masterkey_triage(masterkey):
|
|
65
|
+
masterkey.dump()
|
|
66
|
+
|
|
67
|
+
masterkeytriage = MasterkeysTriage(
|
|
68
|
+
target=self.target,
|
|
69
|
+
conn=self.conn,
|
|
70
|
+
pvkbytes=self.pvkbytes,
|
|
71
|
+
nthashes=self.nthashes,
|
|
72
|
+
passwords=self.passwords,
|
|
73
|
+
per_masterkey_callback=masterkey_triage
|
|
74
|
+
if not self.options.quiet
|
|
75
|
+
else None,
|
|
76
|
+
)
|
|
77
|
+
logging.info("Triage ALL USERS masterkeys\n")
|
|
78
|
+
self.masterkeys = masterkeytriage.triage_masterkeys()
|
|
79
|
+
print()
|
|
80
|
+
if self.outputdir is not None:
|
|
81
|
+
dump_looted_files_to_disk(self.outputdir, masterkeytriage.looted_files)
|
|
82
|
+
|
|
83
|
+
def secret_callback(vault):
|
|
84
|
+
if self.options.quiet:
|
|
85
|
+
vault.dump_quiet()
|
|
86
|
+
else:
|
|
87
|
+
vault.dump()
|
|
88
|
+
|
|
89
|
+
triage = VaultsTriage(
|
|
90
|
+
target=self.target,
|
|
91
|
+
conn=self.conn,
|
|
92
|
+
masterkeys=self.masterkeys,
|
|
93
|
+
per_vault_callback=secret_callback,
|
|
94
|
+
)
|
|
95
|
+
logging.info("Triage Vaults for ALL USERS\n")
|
|
96
|
+
triage.triage_vaults()
|
|
97
|
+
if self.outputdir is not None:
|
|
98
|
+
dump_looted_files_to_disk(self.outputdir, triage.looted_files)
|
|
99
|
+
else:
|
|
100
|
+
logging.info("Not an admin, exiting...")
|
|
101
|
+
|
|
102
|
+
@property
|
|
103
|
+
def is_admin(self) -> bool:
|
|
104
|
+
if self._is_admin is not None:
|
|
105
|
+
return self._is_admin
|
|
106
|
+
|
|
107
|
+
self._is_admin = self.conn.is_admin()
|
|
108
|
+
return self._is_admin
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def entry(options: argparse.Namespace) -> None:
|
|
112
|
+
a = VaultsAction(options)
|
|
113
|
+
a.run()
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def add_subparser(subparsers: argparse._SubParsersAction) -> Tuple[str, Callable]:
|
|
117
|
+
subparser = subparsers.add_parser(
|
|
118
|
+
NAME, help="Dump users Vaults blob from local or remote target"
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
group = subparser.add_argument_group("vaults options")
|
|
122
|
+
|
|
123
|
+
group.add_argument(
|
|
124
|
+
"-mkfile",
|
|
125
|
+
action="store",
|
|
126
|
+
help=("File containing {GUID}:SHA1 masterkeys mappings"),
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
add_masterkeys_argument_group(group)
|
|
130
|
+
add_target_argument_group(subparser)
|
|
131
|
+
|
|
132
|
+
return NAME, entry
|
dploot/action/wam.py
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import logging
|
|
3
|
+
import sys
|
|
4
|
+
from typing import Callable, Tuple
|
|
5
|
+
from dploot.action.masterkeys import (
|
|
6
|
+
add_masterkeys_argument_group,
|
|
7
|
+
parse_masterkeys_options,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
from dploot.lib.smb import DPLootSMBConnection
|
|
11
|
+
from dploot.lib.target import Target, add_target_argument_group
|
|
12
|
+
from dploot.lib.utils import dump_looted_files_to_disk, handle_outputdir_option
|
|
13
|
+
from dploot.triage.masterkeys import MasterkeysTriage, parse_masterkey_file
|
|
14
|
+
from dploot.triage.wam import WamTriage
|
|
15
|
+
|
|
16
|
+
NAME = "wam"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class WamAction:
|
|
20
|
+
def __init__(self, options: argparse.Namespace) -> None:
|
|
21
|
+
self.options = options
|
|
22
|
+
self.target = Target.from_options(options)
|
|
23
|
+
|
|
24
|
+
self.conn = None
|
|
25
|
+
self._is_admin = None
|
|
26
|
+
self.outputdir = None
|
|
27
|
+
self.masterkeys = None
|
|
28
|
+
self.pvkbytes = None
|
|
29
|
+
self.passwords = None
|
|
30
|
+
self.nthashes = None
|
|
31
|
+
|
|
32
|
+
self.outputdir = handle_outputdir_option(directory=self.options.export_dir)
|
|
33
|
+
|
|
34
|
+
if self.options.mkfile is not None:
|
|
35
|
+
try:
|
|
36
|
+
self.masterkeys = parse_masterkey_file(self.options.mkfile)
|
|
37
|
+
except Exception as e:
|
|
38
|
+
logging.error(str(e))
|
|
39
|
+
sys.exit(1)
|
|
40
|
+
|
|
41
|
+
self.pvkbytes, self.passwords, self.nthashes = parse_masterkeys_options(
|
|
42
|
+
self.options, self.target
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
def connect(self) -> None:
|
|
46
|
+
self.conn = DPLootSMBConnection(self.target)
|
|
47
|
+
if self.conn.connect() is None:
|
|
48
|
+
logging.error("Could not connect to %s" % self.target.address)
|
|
49
|
+
sys.exit(1)
|
|
50
|
+
|
|
51
|
+
def run(self) -> None:
|
|
52
|
+
self.connect()
|
|
53
|
+
logging.info(
|
|
54
|
+
"Connected to {} as {}\\{} {}\n".format(
|
|
55
|
+
self.target.address,
|
|
56
|
+
self.target.domain,
|
|
57
|
+
self.target.username,
|
|
58
|
+
("(admin)" if self.is_admin else ""),
|
|
59
|
+
)
|
|
60
|
+
)
|
|
61
|
+
if self.is_admin:
|
|
62
|
+
if self.masterkeys is None:
|
|
63
|
+
|
|
64
|
+
def masterkey_triage(masterkey):
|
|
65
|
+
masterkey.dump()
|
|
66
|
+
|
|
67
|
+
masterkeytriage = MasterkeysTriage(
|
|
68
|
+
target=self.target,
|
|
69
|
+
conn=self.conn,
|
|
70
|
+
pvkbytes=self.pvkbytes,
|
|
71
|
+
nthashes=self.nthashes,
|
|
72
|
+
passwords=self.passwords,
|
|
73
|
+
per_masterkey_callback=masterkey_triage
|
|
74
|
+
if not self.options.quiet
|
|
75
|
+
else None,
|
|
76
|
+
)
|
|
77
|
+
logging.info("Triage ALL USERS masterkeys\n")
|
|
78
|
+
self.masterkeys = masterkeytriage.triage_masterkeys()
|
|
79
|
+
print()
|
|
80
|
+
if self.outputdir is not None:
|
|
81
|
+
dump_looted_files_to_disk(self.outputdir, masterkeytriage.looted_files)
|
|
82
|
+
|
|
83
|
+
def token_callback(token):
|
|
84
|
+
if self.options.quiet:
|
|
85
|
+
token.dump_quiet()
|
|
86
|
+
else:
|
|
87
|
+
token.dump()
|
|
88
|
+
|
|
89
|
+
triage = WamTriage(
|
|
90
|
+
target=self.target,
|
|
91
|
+
conn=self.conn,
|
|
92
|
+
masterkeys=self.masterkeys,
|
|
93
|
+
per_token_callback=token_callback,
|
|
94
|
+
)
|
|
95
|
+
logging.info("Triage Office Token Broker Cache for ALL USERS\n")
|
|
96
|
+
triage.triage_wam()
|
|
97
|
+
if self.outputdir is not None:
|
|
98
|
+
dump_looted_files_to_disk(self.outputdir, triage.looted_files)
|
|
99
|
+
else:
|
|
100
|
+
logging.info("Not an admin, exiting...")
|
|
101
|
+
|
|
102
|
+
@property
|
|
103
|
+
def is_admin(self) -> bool:
|
|
104
|
+
if self._is_admin is not None:
|
|
105
|
+
return self._is_admin
|
|
106
|
+
|
|
107
|
+
self._is_admin = self.conn.is_admin()
|
|
108
|
+
return self._is_admin
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def entry(options: argparse.Namespace) -> None:
|
|
112
|
+
a = WamAction(options)
|
|
113
|
+
a.run()
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def add_subparser(subparsers: argparse._SubParsersAction) -> Tuple[str, Callable]:
|
|
117
|
+
subparser = subparsers.add_parser(
|
|
118
|
+
NAME,
|
|
119
|
+
help="Dump users cached azure tokens from local or remote target",
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
group = subparser.add_argument_group("wam options")
|
|
123
|
+
|
|
124
|
+
group.add_argument(
|
|
125
|
+
"-mkfile",
|
|
126
|
+
action="store",
|
|
127
|
+
help=("File containing {GUID}:SHA1 masterkeys mappings"),
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
add_masterkeys_argument_group(group)
|
|
131
|
+
add_target_argument_group(subparser)
|
|
132
|
+
|
|
133
|
+
return NAME, entry
|
dploot/action/wifi.py
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import logging
|
|
3
|
+
import sys
|
|
4
|
+
from typing import Callable, Tuple
|
|
5
|
+
|
|
6
|
+
from dploot.lib.smb import DPLootSMBConnection
|
|
7
|
+
from dploot.lib.target import Target, add_target_argument_group
|
|
8
|
+
from dploot.lib.utils import dump_looted_files_to_disk, handle_outputdir_option
|
|
9
|
+
from dploot.action.masterkeys import parse_masterkeys_options
|
|
10
|
+
from dploot.triage.masterkeys import MasterkeysTriage, parse_masterkey_file
|
|
11
|
+
from dploot.triage.wifi import WifiTriage
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
NAME = "wifi"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class WifiAction:
|
|
18
|
+
def __init__(self, options: argparse.Namespace) -> None:
|
|
19
|
+
self.options = options
|
|
20
|
+
|
|
21
|
+
self.target = Target.from_options(options)
|
|
22
|
+
|
|
23
|
+
self.conn = None
|
|
24
|
+
self._is_admin = None
|
|
25
|
+
self.masterkeys = None
|
|
26
|
+
self.outputdir = None
|
|
27
|
+
|
|
28
|
+
self.outputdir = handle_outputdir_option(directory=self.options.export_dir)
|
|
29
|
+
|
|
30
|
+
self.pvkbytes, self.passwords, self.nthashes = parse_masterkeys_options(
|
|
31
|
+
self.options, self.target
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
if self.options.mkfile is not None:
|
|
35
|
+
try:
|
|
36
|
+
self.masterkeys = parse_masterkey_file(self.options.mkfile)
|
|
37
|
+
except Exception as e:
|
|
38
|
+
logging.error(str(e))
|
|
39
|
+
sys.exit(1)
|
|
40
|
+
|
|
41
|
+
def connect(self) -> None:
|
|
42
|
+
self.conn = DPLootSMBConnection(self.target)
|
|
43
|
+
if self.conn.connect() is None:
|
|
44
|
+
logging.error("Could not connect to %s" % self.target.address)
|
|
45
|
+
sys.exit(1)
|
|
46
|
+
|
|
47
|
+
def run(self) -> None:
|
|
48
|
+
self.connect()
|
|
49
|
+
logging.info(
|
|
50
|
+
"Connected to {} as {}\\{} {}\n".format(
|
|
51
|
+
self.target.address,
|
|
52
|
+
self.target.domain,
|
|
53
|
+
self.target.username,
|
|
54
|
+
("(admin)" if self.is_admin else ""),
|
|
55
|
+
)
|
|
56
|
+
)
|
|
57
|
+
if self.is_admin:
|
|
58
|
+
if self.masterkeys is None:
|
|
59
|
+
|
|
60
|
+
def masterkey_triage(masterkey):
|
|
61
|
+
masterkey.dump()
|
|
62
|
+
|
|
63
|
+
masterkeytriage = MasterkeysTriage(
|
|
64
|
+
target=self.target,
|
|
65
|
+
conn=self.conn,
|
|
66
|
+
pvkbytes=self.pvkbytes,
|
|
67
|
+
nthashes=self.nthashes,
|
|
68
|
+
passwords=self.passwords,
|
|
69
|
+
per_masterkey_callback=masterkey_triage
|
|
70
|
+
if not self.options.quiet
|
|
71
|
+
else None,
|
|
72
|
+
)
|
|
73
|
+
logging.info("Triage SYSTEM masterkeys\n")
|
|
74
|
+
self.masterkeys = masterkeytriage.triage_system_masterkeys()
|
|
75
|
+
# we need user masterkeys, too.
|
|
76
|
+
logging.info("Triage ALL USERS masterkeys\n")
|
|
77
|
+
self.masterkeys.extend(masterkeytriage.triage_masterkeys())
|
|
78
|
+
print()
|
|
79
|
+
if self.outputdir is not None:
|
|
80
|
+
dump_looted_files_to_disk(self.outputdir, masterkeytriage.looted_files)
|
|
81
|
+
|
|
82
|
+
def profile_callback(profile):
|
|
83
|
+
if self.options.quiet:
|
|
84
|
+
profile.dump_quiet()
|
|
85
|
+
else:
|
|
86
|
+
profile.dump()
|
|
87
|
+
|
|
88
|
+
wifi_triage = WifiTriage(
|
|
89
|
+
target=self.target,
|
|
90
|
+
conn=self.conn,
|
|
91
|
+
masterkeys=self.masterkeys,
|
|
92
|
+
per_profile_callback=profile_callback,
|
|
93
|
+
)
|
|
94
|
+
logging.info("Triage ALL WIFI profiles\n")
|
|
95
|
+
wifi_triage.triage_wifi()
|
|
96
|
+
if self.outputdir is not None:
|
|
97
|
+
dump_looted_files_to_disk(self.outputdir, wifi_triage.looted_files)
|
|
98
|
+
|
|
99
|
+
else:
|
|
100
|
+
logging.info("Not an admin, exiting...")
|
|
101
|
+
|
|
102
|
+
@property
|
|
103
|
+
def is_admin(self) -> bool:
|
|
104
|
+
if self._is_admin is not None:
|
|
105
|
+
return self._is_admin
|
|
106
|
+
|
|
107
|
+
self._is_admin = self.conn.is_admin()
|
|
108
|
+
return self._is_admin
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def entry(options: argparse.Namespace) -> None:
|
|
112
|
+
a = WifiAction(options)
|
|
113
|
+
a.run()
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def add_subparser(subparsers: argparse._SubParsersAction) -> Tuple[str, Callable]:
|
|
117
|
+
subparser = subparsers.add_parser(
|
|
118
|
+
NAME, help="Dump wifi profiles from local or remote target"
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
group = subparser.add_argument_group("wifi options")
|
|
122
|
+
|
|
123
|
+
group.add_argument(
|
|
124
|
+
"-mkfile",
|
|
125
|
+
action="store",
|
|
126
|
+
help=("File containing {GUID}:SHA1 masterkeys mappings"),
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
group.add_argument(
|
|
130
|
+
"-outputfile",
|
|
131
|
+
action="store",
|
|
132
|
+
help=("Export keys to file"),
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
add_target_argument_group(subparser)
|
|
136
|
+
|
|
137
|
+
return NAME, entry
|
dploot/entry.py
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import importlib.metadata
|
|
3
|
+
import logging
|
|
4
|
+
import sys
|
|
5
|
+
import traceback
|
|
6
|
+
|
|
7
|
+
from impacket.examples import logger
|
|
8
|
+
|
|
9
|
+
from dploot.action import (
|
|
10
|
+
backupkey,
|
|
11
|
+
blob,
|
|
12
|
+
browser,
|
|
13
|
+
certificates,
|
|
14
|
+
cng,
|
|
15
|
+
credentials,
|
|
16
|
+
machinecertificates,
|
|
17
|
+
machinecng,
|
|
18
|
+
machinecredentials,
|
|
19
|
+
machinemasterkeys,
|
|
20
|
+
machinetriage,
|
|
21
|
+
machinevaults,
|
|
22
|
+
masterkeys,
|
|
23
|
+
mobaxterm,
|
|
24
|
+
rdg,
|
|
25
|
+
sccm,
|
|
26
|
+
triage,
|
|
27
|
+
vaults,
|
|
28
|
+
wam,
|
|
29
|
+
wifi,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
ENTRY_PARSERS = [
|
|
33
|
+
backupkey,
|
|
34
|
+
blob,
|
|
35
|
+
browser,
|
|
36
|
+
certificates,
|
|
37
|
+
cng,
|
|
38
|
+
credentials,
|
|
39
|
+
machinecertificates,
|
|
40
|
+
machinecng,
|
|
41
|
+
machinecredentials,
|
|
42
|
+
machinemasterkeys,
|
|
43
|
+
machinetriage,
|
|
44
|
+
machinevaults,
|
|
45
|
+
masterkeys,
|
|
46
|
+
mobaxterm,
|
|
47
|
+
rdg,
|
|
48
|
+
sccm,
|
|
49
|
+
triage,
|
|
50
|
+
vaults,
|
|
51
|
+
wam,
|
|
52
|
+
wifi,
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def main() -> None:
|
|
57
|
+
logger.init()
|
|
58
|
+
version = importlib.metadata.version("dploot")
|
|
59
|
+
print(f"dploot (https://github.com/zblurx/dploot) v{version} by @_zblurx")
|
|
60
|
+
parser = argparse.ArgumentParser(
|
|
61
|
+
description="DPAPI looting locally remotely in Python",
|
|
62
|
+
add_help=True,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
subparsers = parser.add_subparsers(help="Action", dest="action", required=True)
|
|
66
|
+
|
|
67
|
+
actions = {}
|
|
68
|
+
|
|
69
|
+
for entry_parser in ENTRY_PARSERS:
|
|
70
|
+
action, entry = entry_parser.add_subparser(subparsers)
|
|
71
|
+
actions[action] = entry
|
|
72
|
+
|
|
73
|
+
if len(sys.argv) == 1:
|
|
74
|
+
parser.print_help()
|
|
75
|
+
sys.exit(1)
|
|
76
|
+
|
|
77
|
+
options = parser.parse_args()
|
|
78
|
+
|
|
79
|
+
if options.debug is True:
|
|
80
|
+
logging.getLogger().setLevel(logging.DEBUG)
|
|
81
|
+
elif options.quiet is True:
|
|
82
|
+
logging.getLogger().setLevel(logging.CRITICAL)
|
|
83
|
+
else:
|
|
84
|
+
logging.getLogger().setLevel(logging.INFO)
|
|
85
|
+
|
|
86
|
+
logging.debug(f"{options=}")
|
|
87
|
+
try:
|
|
88
|
+
actions[options.action](options)
|
|
89
|
+
except Exception as e:
|
|
90
|
+
logging.error("Got error: %s" % e)
|
|
91
|
+
if options.debug:
|
|
92
|
+
traceback.print_exc()
|
|
93
|
+
else:
|
|
94
|
+
logging.error("Use -debug to print a stacktrace")
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
if __name__ == "__main__":
|
|
98
|
+
main()
|
dploot/lib/__init__.py
ADDED
|
File without changes
|
dploot/lib/consts.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Define some dploot consts.
|
|
2
|
+
|
|
3
|
+
FALSE_POSITIVES = [
|
|
4
|
+
".",
|
|
5
|
+
"..",
|
|
6
|
+
"desktop.ini",
|
|
7
|
+
"Public",
|
|
8
|
+
"Default",
|
|
9
|
+
"Default User",
|
|
10
|
+
"All Users",
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
# simple class to check for false positives, case insensitive
|
|
14
|
+
class FalsePositives(list):
|
|
15
|
+
def __init__(self,
|
|
16
|
+
false_positives: list[str] = None
|
|
17
|
+
) -> None:
|
|
18
|
+
if false_positives is None:
|
|
19
|
+
false_positives = FALSE_POSITIVES
|
|
20
|
+
|
|
21
|
+
super().__init__(map (lambda x: x.lower(), false_positives))
|
|
22
|
+
|
|
23
|
+
def __contains__(self, name):
|
|
24
|
+
return super().__contains__(str(name).lower())
|
|
25
|
+
|
|
26
|
+
def __setitem__(self, key, value):
|
|
27
|
+
return super().__setitem__(key,str(value).lower())
|
|
28
|
+
|
|
29
|
+
def append(self, element):
|
|
30
|
+
return super().append(str(element).lower())
|