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
dploot/action/cng.py ADDED
@@ -0,0 +1,129 @@
1
+ import argparse
2
+ import logging
3
+ import sys
4
+ from typing import Callable, Tuple
5
+
6
+ from dploot.action.masterkeys import add_masterkeys_argument_group, parse_masterkeys_options
7
+ from dploot.lib.smb import DPLootSMBConnection
8
+ from dploot.lib.target import Target, add_target_argument_group
9
+ from dploot.lib.utils import dump_looted_files_to_disk, handle_outputdir_option
10
+ from dploot.triage.cng import CngTriage
11
+ from dploot.triage.masterkeys import MasterkeysTriage, parse_masterkey_file
12
+
13
+
14
+ NAME = "cng"
15
+
16
+ class CngAction:
17
+ def __init__(self, options: argparse.Namespace) -> None:
18
+ self.options = options
19
+ self.target = Target.from_options(options)
20
+
21
+ self.conn = None
22
+ self._is_admin = None
23
+ self.outputdir = None
24
+ self.masterkeys = None
25
+ self.pvkbytes = None
26
+ self.passwords = None
27
+ self.nthashes = None
28
+
29
+ self.outputdir = handle_outputdir_option(directory=self.options.export_dir)
30
+
31
+ if self.options.mkfile is not None:
32
+ try:
33
+ self.masterkeys = parse_masterkey_file(self.options.mkfile)
34
+ except Exception as e:
35
+ logging.error(str(e))
36
+ sys.exit(1)
37
+
38
+ self.pvkbytes, self.passwords, self.nthashes = parse_masterkeys_options(
39
+ self.options, self.target
40
+ )
41
+
42
+ def connect(self) -> None:
43
+ self.conn = DPLootSMBConnection(self.target)
44
+ if self.conn.connect() is None:
45
+ logging.error("Could not connect to %s" % self.target.address)
46
+ sys.exit(1)
47
+
48
+ def run(self) -> None:
49
+ self.connect()
50
+ logging.info(
51
+ "Connected to {} as {}\\{} {}\n".format(
52
+ self.target.address,
53
+ self.target.domain,
54
+ self.target.username,
55
+ ("(admin)" if self.is_admin else ""),
56
+ )
57
+ )
58
+ if self.is_admin:
59
+ if self.masterkeys is None:
60
+
61
+ def masterkey_triage(masterkey):
62
+ masterkey.dump()
63
+
64
+ masterkeytriage = MasterkeysTriage(
65
+ target=self.target,
66
+ conn=self.conn,
67
+ pvkbytes=self.pvkbytes,
68
+ nthashes=self.nthashes,
69
+ passwords=self.passwords,
70
+ per_masterkey_callback=masterkey_triage
71
+ if not self.options.quiet
72
+ else None,
73
+ )
74
+ logging.info("Triage ALL USERS masterkeys\n")
75
+ self.masterkeys = masterkeytriage.triage_masterkeys()
76
+ print()
77
+ if self.outputdir is not None:
78
+ dump_looted_files_to_disk(self.outputdir, masterkeytriage.looted_files)
79
+
80
+ def cng_callback(cng):
81
+ if self.options.quiet:
82
+ cng.dump_quiet()
83
+ else:
84
+ cng.dump()
85
+
86
+ triage = CngTriage(
87
+ target=self.target,
88
+ conn=self.conn,
89
+ masterkeys=self.masterkeys,
90
+ per_cng_callback=cng_callback,
91
+ )
92
+ logging.info("Triage CNG files for ALL USERS\n")
93
+ triage.triage_cng()
94
+ if self.outputdir is not None:
95
+ dump_looted_files_to_disk(self.outputdir, triage.looted_files)
96
+ else:
97
+ logging.info("Not an admin, exiting...")
98
+
99
+ @property
100
+ def is_admin(self) -> bool:
101
+ if self._is_admin is not None:
102
+ return self._is_admin
103
+
104
+ self._is_admin = self.conn.is_admin()
105
+ return self._is_admin
106
+
107
+
108
+ def entry(options: argparse.Namespace) -> None:
109
+ a = CngAction(options)
110
+ a.run()
111
+
112
+
113
+ def add_subparser(subparsers: argparse._SubParsersAction) -> Tuple[str, Callable]:
114
+ subparser = subparsers.add_parser(
115
+ NAME, help="Dump users CNG files blob from local or remote target"
116
+ )
117
+
118
+ group = subparser.add_argument_group("cng options")
119
+
120
+ group.add_argument(
121
+ "-mkfile",
122
+ action="store",
123
+ help=("File containing {GUID}:SHA1 masterkeys mappings"),
124
+ )
125
+
126
+ add_masterkeys_argument_group(group)
127
+ add_target_argument_group(subparser)
128
+
129
+ return NAME, entry
@@ -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.credentials import CredentialsTriage
14
+ from dploot.triage.masterkeys import MasterkeysTriage, parse_masterkey_file
15
+
16
+ NAME = "credentials"
17
+
18
+
19
+ class CredentialsAction:
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 credential_callback(credential):
84
+ if self.options.quiet:
85
+ credential.dump_quiet()
86
+ else:
87
+ credential.dump()
88
+
89
+ triage = CredentialsTriage(
90
+ target=self.target,
91
+ conn=self.conn,
92
+ masterkeys=self.masterkeys,
93
+ per_credential_callback=credential_callback,
94
+ )
95
+ logging.info("Triage Credentials for ALL USERS\n")
96
+ triage.triage_credentials()
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 = CredentialsAction(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 Credential Manager blob from local or remote target"
119
+ )
120
+
121
+ group = subparser.add_argument_group("credentials 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
@@ -0,0 +1,136 @@
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.triage.certificates import CertificatesTriage
10
+ from dploot.triage.masterkeys import MasterkeysTriage, parse_masterkey_file
11
+
12
+
13
+ NAME = "machinecertificates"
14
+
15
+
16
+ class MachineCertificatesAction:
17
+ def __init__(self, options: argparse.Namespace) -> None:
18
+ self.options = options
19
+
20
+ self.target = Target.from_options(options)
21
+
22
+ self.conn = None
23
+ self._is_admin = None
24
+ self.masterkeys = None
25
+ self.outputdir = None
26
+
27
+ self.outputdir = handle_outputdir_option(directory=self.options.export_dir)
28
+
29
+ if self.options.mkfile is not None:
30
+ try:
31
+ self.masterkeys = parse_masterkey_file(self.options.mkfile)
32
+ except Exception as e:
33
+ logging.error(str(e))
34
+ sys.exit(1)
35
+
36
+ def connect(self) -> None:
37
+ self.conn = DPLootSMBConnection(self.target)
38
+ if self.conn.connect() is None:
39
+ logging.error("Could not connect to %s" % self.target.address)
40
+ sys.exit(1)
41
+
42
+ def run(self) -> None:
43
+ self.connect()
44
+ logging.info(
45
+ "Connected to {} as {}\\{} {}\n".format(
46
+ self.target.address,
47
+ self.target.domain,
48
+ self.target.username,
49
+ ("(admin)" if self.is_admin else ""),
50
+ )
51
+ )
52
+ if self.is_admin:
53
+ if self.masterkeys is None:
54
+
55
+ def masterkey_triage(masterkey):
56
+ masterkey.dump()
57
+
58
+ masterkeytriage = MasterkeysTriage(
59
+ target=self.target,
60
+ conn=self.conn,
61
+ per_masterkey_callback=masterkey_triage
62
+ if not self.options.quiet
63
+ else None,
64
+ )
65
+ logging.info("Triage SYSTEM masterkeys\n")
66
+ self.masterkeys = masterkeytriage.triage_system_masterkeys()
67
+ print()
68
+ if self.outputdir is not None:
69
+ dump_looted_files_to_disk(self.outputdir, masterkeytriage.looted_files)
70
+
71
+ def certificate_callback(certificate):
72
+ if not self.options.dump_all and not certificate.clientauth:
73
+ return
74
+ if not self.options.quiet:
75
+ certificate.dump()
76
+ filename = f"{certificate.username}_{certificate.filename[:16]}.pfx"
77
+ logging.critical("Writting certificate to %s" % filename)
78
+ with open(filename, "wb") as f:
79
+ f.write(certificate.pfx)
80
+
81
+ certificate_triage = CertificatesTriage(
82
+ target=self.target,
83
+ conn=self.conn,
84
+ masterkeys=self.masterkeys,
85
+ per_certificate_callback=certificate_callback,
86
+ )
87
+ logging.info("Triage SYSTEM Certificates\n")
88
+ certificate_triage.triage_system_certificates()
89
+ if self.outputdir is not None:
90
+ dump_looted_files_to_disk(self.outputdir, certificate_triage.looted_files)
91
+
92
+ else:
93
+ logging.info("Not an admin, exiting...")
94
+
95
+ @property
96
+ def is_admin(self) -> bool:
97
+ if self._is_admin is not None:
98
+ return self._is_admin
99
+
100
+ self._is_admin = self.conn.is_admin()
101
+ return self._is_admin
102
+
103
+
104
+ def entry(options: argparse.Namespace) -> None:
105
+ a = MachineCertificatesAction(options)
106
+ a.run()
107
+
108
+
109
+ def add_subparser(subparsers: argparse._SubParsersAction) -> Tuple[str, Callable]:
110
+ subparser = subparsers.add_parser(
111
+ NAME, help="Dump system certificates from local or remote target"
112
+ )
113
+
114
+ group = subparser.add_argument_group("machinecertificates options")
115
+
116
+ group.add_argument(
117
+ "-mkfile",
118
+ action="store",
119
+ help=("File containing {GUID}:SHA1 masterkeys mappings"),
120
+ )
121
+
122
+ group.add_argument(
123
+ "-outputfile",
124
+ action="store",
125
+ help=("Export keys to file"),
126
+ )
127
+
128
+ group.add_argument(
129
+ "-dump-all",
130
+ action="store_true",
131
+ help=("Dump also certificates not used for client authentication"),
132
+ )
133
+
134
+ add_target_argument_group(subparser)
135
+
136
+ return NAME, entry
@@ -0,0 +1,120 @@
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.triage.cng import CngTriage
10
+ from dploot.triage.masterkeys import MasterkeysTriage, parse_masterkey_file
11
+
12
+
13
+ NAME = "machinecng"
14
+
15
+
16
+ class MachineCngAction:
17
+ def __init__(self, options: argparse.Namespace) -> None:
18
+ self.options = options
19
+
20
+ self.target = Target.from_options(options)
21
+
22
+ self.conn = None
23
+ self._is_admin = None
24
+ self.masterkeys = None
25
+ self.outputdir = None
26
+
27
+ self.outputdir = handle_outputdir_option(directory=self.options.export_dir)
28
+
29
+ if self.options.mkfile is not None:
30
+ try:
31
+ self.masterkeys = parse_masterkey_file(self.options.mkfile)
32
+ except Exception as e:
33
+ logging.error(str(e))
34
+ sys.exit(1)
35
+
36
+ def connect(self) -> None:
37
+ self.conn = DPLootSMBConnection(self.target)
38
+ if self.conn.connect() is None:
39
+ logging.error("Could not connect to %s" % self.target.address)
40
+ sys.exit(1)
41
+
42
+ def run(self) -> None:
43
+ self.connect()
44
+ logging.info(
45
+ "Connected to {} as {}\\{} {}\n".format(
46
+ self.target.address,
47
+ self.target.domain,
48
+ self.target.username,
49
+ ("(admin)" if self.is_admin else ""),
50
+ )
51
+ )
52
+ if self.is_admin:
53
+ if self.masterkeys is None:
54
+
55
+ def masterkey_triage(masterkey):
56
+ masterkey.dump()
57
+
58
+ masterkeytriage = MasterkeysTriage(
59
+ target=self.target,
60
+ conn=self.conn,
61
+ per_masterkey_callback=masterkey_triage
62
+ if not self.options.quiet
63
+ else None,
64
+ )
65
+ logging.info("Triage SYSTEM masterkeys\n")
66
+ self.masterkeys = masterkeytriage.triage_system_masterkeys()
67
+ print()
68
+ if self.outputdir is not None:
69
+ dump_looted_files_to_disk(self.outputdir, masterkeytriage.looted_files)
70
+
71
+ def cng_callback(cng_file):
72
+ if self.options.quiet:
73
+ cng_file.dump_quiet()
74
+ else:
75
+ cng_file.dump()
76
+
77
+ triage = CngTriage(
78
+ target=self.target,
79
+ conn=self.conn,
80
+ masterkeys=self.masterkeys,
81
+ per_cng_callback=cng_callback,
82
+ )
83
+ logging.info("Triage SYSTEM CNG files\n")
84
+ triage.triage_system_cng()
85
+ if self.outputdir is not None:
86
+ dump_looted_files_to_disk(self.outputdir, triage.looted_files)
87
+
88
+ else:
89
+ logging.info("Not an admin, exiting...")
90
+
91
+ @property
92
+ def is_admin(self) -> bool:
93
+ if self._is_admin is not None:
94
+ return self._is_admin
95
+
96
+ self._is_admin = self.conn.is_admin()
97
+ return self._is_admin
98
+
99
+
100
+ def entry(options: argparse.Namespace) -> None:
101
+ a = MachineCngAction(options)
102
+ a.run()
103
+
104
+
105
+ def add_subparser(subparsers: argparse._SubParsersAction) -> Tuple[str, Callable]:
106
+ subparser = subparsers.add_parser(
107
+ NAME, help="Dump system CNG files from local or remote target"
108
+ )
109
+
110
+ group = subparser.add_argument_group("machinecng options")
111
+
112
+ group.add_argument(
113
+ "-mkfile",
114
+ action="store",
115
+ help=("File containing {GUID}:SHA1 masterkeys mappings"),
116
+ )
117
+
118
+ add_target_argument_group(subparser)
119
+
120
+ return NAME, entry
@@ -0,0 +1,120 @@
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.triage.credentials import CredentialsTriage
10
+ from dploot.triage.masterkeys import MasterkeysTriage, parse_masterkey_file
11
+
12
+
13
+ NAME = "machinecredentials"
14
+
15
+
16
+ class MachineCredentialsAction:
17
+ def __init__(self, options: argparse.Namespace) -> None:
18
+ self.options = options
19
+
20
+ self.target = Target.from_options(options)
21
+
22
+ self.conn = None
23
+ self._is_admin = None
24
+ self.masterkeys = None
25
+ self.outputdir = None
26
+
27
+ self.outputdir = handle_outputdir_option(directory=self.options.export_dir)
28
+
29
+ if self.options.mkfile is not None:
30
+ try:
31
+ self.masterkeys = parse_masterkey_file(self.options.mkfile)
32
+ except Exception as e:
33
+ logging.error(str(e))
34
+ sys.exit(1)
35
+
36
+ def connect(self) -> None:
37
+ self.conn = DPLootSMBConnection(self.target)
38
+ if self.conn.connect() is None:
39
+ logging.error("Could not connect to %s" % self.target.address)
40
+ sys.exit(1)
41
+
42
+ def run(self) -> None:
43
+ self.connect()
44
+ logging.info(
45
+ "Connected to {} as {}\\{} {}\n".format(
46
+ self.target.address,
47
+ self.target.domain,
48
+ self.target.username,
49
+ ("(admin)" if self.is_admin else ""),
50
+ )
51
+ )
52
+ if self.is_admin:
53
+ if self.masterkeys is None:
54
+
55
+ def masterkey_triage(masterkey):
56
+ masterkey.dump()
57
+
58
+ masterkeytriage = MasterkeysTriage(
59
+ target=self.target,
60
+ conn=self.conn,
61
+ per_masterkey_callback=masterkey_triage
62
+ if not self.options.quiet
63
+ else None,
64
+ )
65
+ logging.info("Triage SYSTEM masterkeys\n")
66
+ self.masterkeys = masterkeytriage.triage_system_masterkeys()
67
+ print()
68
+ if self.outputdir is not None:
69
+ dump_looted_files_to_disk(self.outputdir, masterkeytriage.looted_files)
70
+
71
+ def credential_callback(credential):
72
+ if self.options.quiet:
73
+ credential.dump_quiet()
74
+ else:
75
+ credential.dump()
76
+
77
+ cred_triage = CredentialsTriage(
78
+ target=self.target,
79
+ conn=self.conn,
80
+ masterkeys=self.masterkeys,
81
+ per_credential_callback=credential_callback,
82
+ )
83
+ logging.info("Triage SYSTEM Credentials\n")
84
+ cred_triage.triage_system_credentials()
85
+ if self.outputdir is not None:
86
+ dump_looted_files_to_disk(self.outputdir, cred_triage.looted_files)
87
+
88
+ else:
89
+ logging.info("Not an admin, exiting...")
90
+
91
+ @property
92
+ def is_admin(self) -> bool:
93
+ if self._is_admin is not None:
94
+ return self._is_admin
95
+
96
+ self._is_admin = self.conn.is_admin()
97
+ return self._is_admin
98
+
99
+
100
+ def entry(options: argparse.Namespace) -> None:
101
+ a = MachineCredentialsAction(options)
102
+ a.run()
103
+
104
+
105
+ def add_subparser(subparsers: argparse._SubParsersAction) -> Tuple[str, Callable]:
106
+ subparser = subparsers.add_parser(
107
+ NAME, help="Dump system credentials from local or remote target"
108
+ )
109
+
110
+ group = subparser.add_argument_group("machinecredentials options")
111
+
112
+ group.add_argument(
113
+ "-mkfile",
114
+ action="store",
115
+ help=("File containing {GUID}:SHA1 masterkeys mappings"),
116
+ )
117
+
118
+ add_target_argument_group(subparser)
119
+
120
+ return NAME, entry