diff --git a/OpenCL/m31900-pure.cl b/OpenCL/m31900-pure.cl index 24ffb1232..fca9b423d 100644 --- a/OpenCL/m31900-pure.cl +++ b/OpenCL/m31900-pure.cl @@ -33,7 +33,7 @@ typedef struct pbkdf2_sha512_aes_cbc u32 salt_buf[64]; u32 iv_buf[4]; u32 iv_len; - u32 ct_buf[4]; + u32 ct_buf[8]; u32 ct_len; } pbkdf2_sha512_aes_cbc_t; @@ -413,16 +413,20 @@ KERNEL_FQ void m31900_comp (KERN_ATTR_TMPS_ESALT (pbkdf2_sha512_tmp_t, pbkdf2_sh // ct - u32 ct_buf[4]; + u32 ct_buf[8]; ct_buf[0] = esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[0]; ct_buf[1] = esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[1]; ct_buf[2] = esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[2]; ct_buf[3] = esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[3]; + ct_buf[4] = esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[4]; + ct_buf[5] = esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[5]; + ct_buf[6] = esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[6]; + ct_buf[7] = esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[7]; // decrypt first block - u32 pt_buf[4] = { 0 }; + u32 pt_buf[8] = { 0 }; AES256_decrypt (ks, ct_buf, pt_buf, s_td0, s_td1, s_td2, s_td3, s_td4); @@ -431,13 +435,29 @@ KERNEL_FQ void m31900_comp (KERN_ATTR_TMPS_ESALT (pbkdf2_sha512_tmp_t, pbkdf2_sh pt_buf[2] ^= iv_buf[2]; pt_buf[3] ^= iv_buf[3]; - const int correct = is_valid_printable_32 (pt_buf[0]) - + is_valid_printable_32 (pt_buf[1]) - + is_valid_printable_32 (pt_buf[2]) - + is_valid_printable_32 (pt_buf[3]); + const int correct_b1 = is_valid_printable_32 (pt_buf[0]) + + is_valid_printable_32 (pt_buf[1]) + + is_valid_printable_32 (pt_buf[2]) + + is_valid_printable_32 (pt_buf[3]); - if (correct != 4) return; + if (correct_b1 != 4) return; + // proceed with second block to further reduce false-positives + + AES256_decrypt (ks, ct_buf+4, pt_buf+4, s_td0, s_td1, s_td2, s_td3, s_td4); + + pt_buf[4] ^= ct_buf[0]; + pt_buf[5] ^= ct_buf[1]; + pt_buf[6] ^= ct_buf[2]; + pt_buf[7] ^= ct_buf[3]; + + const int correct_b2 = is_valid_printable_32 (pt_buf[4]) + + is_valid_printable_32 (pt_buf[5]) + + is_valid_printable_32 (pt_buf[6]) + + is_valid_printable_32 (pt_buf[7]); + + if (correct_b2 != 4) return; + const u32 r0 = ct_buf[0]; const u32 r1 = ct_buf[1]; const u32 r2 = ct_buf[2]; diff --git a/src/modules/module_31900.c b/src/modules/module_31900.c index 3f7002148..7ef9a8f07 100644 --- a/src/modules/module_31900.c +++ b/src/modules/module_31900.c @@ -26,7 +26,7 @@ static const u64 OPTS_TYPE = OPTS_TYPE_STOCK_MODULE | OPTS_TYPE_PT_GENERATE_LE; static const u32 SALT_TYPE = SALT_TYPE_EMBEDDED; static const char *ST_PASS = "hashcat1"; -static const char *ST_HASH = "$metamaskMobile$MjU1NTA5MTU2ODY5MjY4OQ==$3cccb51c401e54abc82987fd9310a8d3$WQhIECN0blOaV31RC3lKfQ=="; +static const char *ST_HASH = "$metamaskMobile$JV4j2dUDl7n+sujyqW3Wvg==$398f9b04c822d36bfcbdd1e68c82d1e8$auj3J2TwOZ4ev3UIGmNa7VXLh0Nmzr3rDbpXRRrONr4="; u32 module_attack_exec (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return ATTACK_EXEC; } u32 module_dgst_pos0 (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra) { return DGST_POS0; } @@ -58,7 +58,7 @@ typedef struct pbkdf2_sha512_aes_cbc u32 salt_buf[64]; u32 iv_buf[4]; u32 iv_len; - u32 ct_buf[4]; + u32 ct_buf[8]; u32 ct_len; } pbkdf2_sha512_aes_cbc_t; @@ -153,7 +153,7 @@ int module_hash_decode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSE | TOKEN_ATTR_VERIFY_HEX; token.sep[3] = '$'; - token.len[3] = 24; + token.len[3] = 44; token.attr[3] = TOKEN_ATTR_FIXED_LENGTH | TOKEN_ATTR_VERIFY_BASE64A; @@ -200,13 +200,13 @@ int module_hash_decode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSE const u8 *ct_pos = token.buf[3]; const int ct_len = token.len[3]; - u8 tmp_buf[24+1]; + u8 tmp_buf[44+1]; memset (tmp_buf, 0, sizeof (tmp_buf)); tmp_len = base64_decode (base64_to_int, ct_pos, ct_len, tmp_buf); - if (tmp_len != 16) return (PARSER_CT_LENGTH); + if (tmp_len != 32) return (PARSER_CT_LENGTH); memcpy ((u8 *) metamask->ct_buf, tmp_buf, tmp_len); @@ -214,6 +214,10 @@ int module_hash_decode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSE metamask->ct_buf[1] = byte_swap_32 (metamask->ct_buf[1]); metamask->ct_buf[2] = byte_swap_32 (metamask->ct_buf[2]); metamask->ct_buf[3] = byte_swap_32 (metamask->ct_buf[3]); + metamask->ct_buf[4] = byte_swap_32 (metamask->ct_buf[4]); + metamask->ct_buf[5] = byte_swap_32 (metamask->ct_buf[5]); + metamask->ct_buf[6] = byte_swap_32 (metamask->ct_buf[6]); + metamask->ct_buf[7] = byte_swap_32 (metamask->ct_buf[7]); metamask->ct_len = tmp_len / 4; @@ -229,13 +233,11 @@ int module_hash_decode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSE int module_hash_encode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const void *digest_buf, MAYBE_UNUSED const salt_t *salt, MAYBE_UNUSED const void *esalt_buf, MAYBE_UNUSED const void *hook_salt_buf, MAYBE_UNUSED const hashinfo_t *hash_info, char *line_buf, MAYBE_UNUSED const int line_size) { - const u32 *digest = (const u32 *) digest_buf; - - const pbkdf2_sha512_aes_cbc_t *metamask = (const pbkdf2_sha512_aes_cbc_t *) esalt_buf; + pbkdf2_sha512_aes_cbc_t *metamask = (pbkdf2_sha512_aes_cbc_t *) esalt_buf; // salt - const u8 *salt_buf = (const u8 *) salt->salt_buf; + u8 *salt_buf = (u8 *) salt->salt_buf; // iv @@ -250,14 +252,18 @@ int module_hash_encode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSE // ct - u32 tmp_buf[4]; + u32 tmp_buf[8]; - tmp_buf[0] = byte_swap_32 (digest[0]); - tmp_buf[1] = byte_swap_32 (digest[1]); - tmp_buf[2] = byte_swap_32 (digest[2]); - tmp_buf[3] = byte_swap_32 (digest[3]); + tmp_buf[0] = byte_swap_32 (metamask->ct_buf[0]); + tmp_buf[1] = byte_swap_32 (metamask->ct_buf[1]); + tmp_buf[2] = byte_swap_32 (metamask->ct_buf[2]); + tmp_buf[3] = byte_swap_32 (metamask->ct_buf[3]); + tmp_buf[4] = byte_swap_32 (metamask->ct_buf[4]); + tmp_buf[5] = byte_swap_32 (metamask->ct_buf[5]); + tmp_buf[6] = byte_swap_32 (metamask->ct_buf[6]); + tmp_buf[7] = byte_swap_32 (metamask->ct_buf[7]); - u8 ct_buf[24+1]; + u8 ct_buf[44+1]; memset (ct_buf, 0, sizeof (ct_buf)); diff --git a/tools/metamask2hashcat.py b/tools/metamask2hashcat.py index fe2f0e006..a2aa99774 100755 --- a/tools/metamask2hashcat.py +++ b/tools/metamask2hashcat.py @@ -2,8 +2,8 @@ # -*- coding: utf-8 -*- # Author: Gabriele 'matrix' Gristina -# Version: 2.0 -# Date: Thu 12 Aug 2021 06:44:14 PM CEST +# Version: 2.1 +# Date: Thu 28 Aug 2023 05:12:40 PM CEST # License: MIT # Extract metamask vault from browser and save to file, then you can use this tool @@ -66,10 +66,10 @@ def metamask_parser(file, shortdata): else: - # extract only first 16 bytes of ciphertext + # extract first 32 bytes of ciphertext for enhanced resistance to false-positives cipher_bin = base64.b64decode(j['cipher']) - j['cipher'] = base64.b64encode(cipher_bin[:16]).decode("ascii") + j['cipher'] = base64.b64encode(cipher_bin[:32]).decode("ascii") print('$metamaskMobile$' + j['salt'] + '$' + j['iv'] + '$' + j['cipher']) diff --git a/tools/test_modules/m31900.pm b/tools/test_modules/m31900.pm index c3dbf5c91..0dfec5a82 100644 --- a/tools/test_modules/m31900.pm +++ b/tools/test_modules/m31900.pm @@ -46,7 +46,7 @@ sub module_generate_hash my $pt = "[{\"type\":\"HD Key Tree\",\"data\":{\"mnemonic\":\"ocean hidden kidney famous rich season gloom husband spring convince attitude boy\",\"numberOfAccounts\":1,\"hdPath\":\"m/44'/60'/0'/0\"}}]"; - my $ct1 = substr ($cipher->encrypt ($pt), 0, 16); + my $ct1 = substr ($cipher->encrypt ($pt), 0, 32); my $hash = sprintf ('$metamaskMobile$%s$%s$%s', $salt_b64, $iv, encode_base64 ($ct1, "")); @@ -79,7 +79,7 @@ sub module_verify_hash return unless length $salt_b64 == 16; return unless length $iv_bin == 16; - return unless length $ct_bin == 16; + return unless length $ct_bin == 32; my $word_packed = pack_if_HEX_notation ($word);