|
|
|
@ -18,7 +18,6 @@ static const u32 DGST_POS2 = 2;
|
|
|
|
|
static const u32 DGST_POS3 = 3;
|
|
|
|
|
static const u32 DGST_SIZE = DGST_SIZE_4_4;
|
|
|
|
|
static const u32 HASH_CATEGORY = HASH_CATEGORY_CRYPTOCURRENCY_WALLET;
|
|
|
|
|
// 22610 generates a decryption key based on a password-guess and uses that to AES-GCM decrypt the data decrypts
|
|
|
|
|
static const char *HASH_NAME = "MetaMask Wallet (short hash, plaintext check)";
|
|
|
|
|
static const u64 KERN_TYPE = 26610;
|
|
|
|
|
static const u32 OPTI_TYPE = OPTI_TYPE_ZERO_BYTE
|
|
|
|
@ -28,7 +27,6 @@ static const u64 OPTS_TYPE = OPTS_TYPE_STOCK_MODULE
|
|
|
|
|
| OPTS_TYPE_DEEP_COMP_KERNEL;
|
|
|
|
|
static const u32 SALT_TYPE = SALT_TYPE_EMBEDDED;
|
|
|
|
|
static const char *ST_PASS = "hashcat1";
|
|
|
|
|
// hash generated using with python3 tools/metamask2hashcat.py --vault tools/2hashcat_tests/metamask2hashcat.json --shortdata
|
|
|
|
|
static const char *ST_HASH = "$metamask-short$jfGI3TXguhb8GPnKSXFrMzRk2NCEc131Gt5G3kZr5+s=$h+BoIf2CQ5BEjaIOShFE7g==$R95fzGt4UQ0uwrcrVYnIi4UcSlWn9wlmer+//526ZDwYAp50K82F1u1oacYcdjjhuEvbZnWk/uBG00UkgLLlOw==";
|
|
|
|
|
|
|
|
|
|
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; }
|
|
|
|
@ -48,11 +46,11 @@ const char *module_st_pass (MAYBE_UNUSED const hashconfig_t *hashconfig,
|
|
|
|
|
|
|
|
|
|
typedef struct pbkdf2_sha256_tmp
|
|
|
|
|
{
|
|
|
|
|
u32 ipad[8];
|
|
|
|
|
u32 opad[8];
|
|
|
|
|
u32 ipad[8];
|
|
|
|
|
u32 opad[8];
|
|
|
|
|
|
|
|
|
|
u32 dgst[32];
|
|
|
|
|
u32 out[32];
|
|
|
|
|
u32 dgst[32];
|
|
|
|
|
u32 out[32];
|
|
|
|
|
|
|
|
|
|
} pbkdf2_sha256_tmp_t;
|
|
|
|
|
|
|
|
|
@ -61,7 +59,7 @@ typedef struct pbkdf2_sha256_aes_gcm
|
|
|
|
|
u32 salt_buf[64];
|
|
|
|
|
u32 iv_buf[4];
|
|
|
|
|
u32 iv_len;
|
|
|
|
|
u32 ct_buf[784]; // TODO this can be smaller and would speedup the attack, only 64 bytes of ciphertext are allowed
|
|
|
|
|
u32 ct_buf[16];
|
|
|
|
|
u32 ct_len;
|
|
|
|
|
|
|
|
|
|
} pbkdf2_sha256_aes_gcm_t;
|
|
|
|
@ -135,8 +133,6 @@ int module_hash_decode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSE
|
|
|
|
|
|
|
|
|
|
pbkdf2_sha256_aes_gcm_t *metamask = (pbkdf2_sha256_aes_gcm_t *) esalt_buf;
|
|
|
|
|
|
|
|
|
|
#define CT_MAX_LEN_BASE64 (((3136+16) * 8) / 6) + 3 // TODO this can be smaller and would speedup the attack, only 64 bytes of ciphertext are allowed
|
|
|
|
|
|
|
|
|
|
hc_token_t token;
|
|
|
|
|
|
|
|
|
|
memset (&token, 0, sizeof (hc_token_t));
|
|
|
|
@ -161,8 +157,8 @@ int module_hash_decode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSE
|
|
|
|
|
| TOKEN_ATTR_VERIFY_BASE64A;
|
|
|
|
|
|
|
|
|
|
token.sep[3] = '$';
|
|
|
|
|
token.len_min[3] = 32;
|
|
|
|
|
token.len_max[3] = 100; // TODO this can be smaller and would speedup the attack, only 64 bytes of ciphertext are allowed
|
|
|
|
|
token.len_min[3] = 88;
|
|
|
|
|
token.len_max[3] = 88;
|
|
|
|
|
token.attr[3] = TOKEN_ATTR_VERIFY_LENGTH
|
|
|
|
|
| TOKEN_ATTR_VERIFY_BASE64A;
|
|
|
|
|
|
|
|
|
@ -170,10 +166,6 @@ int module_hash_decode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSE
|
|
|
|
|
|
|
|
|
|
if (rc_tokenizer != PARSER_OK) return (rc_tokenizer);
|
|
|
|
|
|
|
|
|
|
u8 tmp_buf[CT_MAX_LEN_BASE64] = { 0 };
|
|
|
|
|
|
|
|
|
|
size_t tmp_len = 0;
|
|
|
|
|
|
|
|
|
|
// iter
|
|
|
|
|
|
|
|
|
|
salt->salt_iter = 10000 - 1;
|
|
|
|
@ -183,9 +175,11 @@ int module_hash_decode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSE
|
|
|
|
|
const u8 *salt_pos = token.buf[1];
|
|
|
|
|
const int salt_len = token.len[1];
|
|
|
|
|
|
|
|
|
|
u8 tmp_buf[88+1];
|
|
|
|
|
|
|
|
|
|
memset (tmp_buf, 0, sizeof (tmp_buf));
|
|
|
|
|
|
|
|
|
|
tmp_len = base64_decode (base64_to_int, salt_pos, salt_len, tmp_buf);
|
|
|
|
|
size_t tmp_len = base64_decode (base64_to_int, salt_pos, salt_len, tmp_buf);
|
|
|
|
|
|
|
|
|
|
if (tmp_len != 32) return (PARSER_SALT_LENGTH);
|
|
|
|
|
|
|
|
|
@ -231,20 +225,23 @@ int module_hash_decode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSE
|
|
|
|
|
|
|
|
|
|
tmp_len = base64_decode (base64_to_int, ct_pos, ct_len, tmp_buf);
|
|
|
|
|
|
|
|
|
|
if (tmp_len != 64) return (PARSER_CT_LENGTH);
|
|
|
|
|
|
|
|
|
|
memcpy ((u8 *) metamask->ct_buf, tmp_buf, tmp_len);
|
|
|
|
|
|
|
|
|
|
u32 j = tmp_len / 4;
|
|
|
|
|
|
|
|
|
|
if ((tmp_len % 4) > 0) j++;
|
|
|
|
|
|
|
|
|
|
for (u32 i = 0; i < j; i++) metamask->ct_buf[i] = byte_swap_32 (metamask->ct_buf[i]);
|
|
|
|
|
for (u32 i = 0; i < j; i++)
|
|
|
|
|
{
|
|
|
|
|
metamask->ct_buf[i] = byte_swap_32 (metamask->ct_buf[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
metamask->ct_len = tmp_len;
|
|
|
|
|
|
|
|
|
|
digest[0] = (metamask->ct_buf[0]);
|
|
|
|
|
digest[1] = (metamask->ct_buf[1]);
|
|
|
|
|
digest[2] = (metamask->ct_buf[2]);
|
|
|
|
|
digest[3] = (metamask->ct_buf[3]);
|
|
|
|
|
digest[0] = metamask->ct_buf[0];
|
|
|
|
|
digest[1] = metamask->ct_buf[1];
|
|
|
|
|
digest[2] = metamask->ct_buf[2];
|
|
|
|
|
digest[3] = metamask->ct_buf[3];
|
|
|
|
|
|
|
|
|
|
return (PARSER_OK);
|
|
|
|
|
}
|
|
|
|
@ -255,40 +252,42 @@ int module_hash_encode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSE
|
|
|
|
|
|
|
|
|
|
// salt
|
|
|
|
|
|
|
|
|
|
#define SALT_LEN_BASE64 ((32 * 8) / 6) + 3
|
|
|
|
|
#define IV_LEN_BASE64 ((16 * 8) / 6) + 3
|
|
|
|
|
#define CT_MAX_LEN_BASE64 (((3136+16) * 8) / 6) + 3 // TODO this can be much smaller now, probably 32 ?
|
|
|
|
|
u8 salt_buf[44+1];
|
|
|
|
|
|
|
|
|
|
u8 salt_buf[SALT_LEN_BASE64] = { 0 };
|
|
|
|
|
memset (salt_buf, 0, sizeof (salt_buf));
|
|
|
|
|
|
|
|
|
|
base64_encode (int_to_base64, (const u8 *) salt->salt_buf, (const int) salt->salt_len, salt_buf);
|
|
|
|
|
|
|
|
|
|
// iv
|
|
|
|
|
|
|
|
|
|
u32 tmp_iv_buf[4] = { 0 };
|
|
|
|
|
u32 tmp_iv_buf[4];
|
|
|
|
|
|
|
|
|
|
tmp_iv_buf[0] = byte_swap_32 (metamask->iv_buf[0]);
|
|
|
|
|
tmp_iv_buf[1] = byte_swap_32 (metamask->iv_buf[1]);
|
|
|
|
|
tmp_iv_buf[2] = byte_swap_32 (metamask->iv_buf[2]);
|
|
|
|
|
tmp_iv_buf[3] = byte_swap_32 (metamask->iv_buf[3]);
|
|
|
|
|
|
|
|
|
|
u8 iv_buf[IV_LEN_BASE64+1] = { 0 };
|
|
|
|
|
u8 iv_buf[24+1];
|
|
|
|
|
|
|
|
|
|
memset (iv_buf, 0, sizeof (iv_buf));
|
|
|
|
|
|
|
|
|
|
base64_encode (int_to_base64, (const u8 *) tmp_iv_buf, (const int) metamask->iv_len, iv_buf);
|
|
|
|
|
|
|
|
|
|
// ct
|
|
|
|
|
|
|
|
|
|
u32 ct_len = metamask->ct_len;
|
|
|
|
|
u32 tmp_buf[16];
|
|
|
|
|
|
|
|
|
|
u32 j = ct_len / 4;
|
|
|
|
|
memset (tmp_buf, 0, sizeof (tmp_buf));
|
|
|
|
|
|
|
|
|
|
if ((ct_len % 4) > 0) j++;
|
|
|
|
|
u32 ct_len = metamask->ct_len;
|
|
|
|
|
|
|
|
|
|
u32 tmp_buf[784] = { 0 }; // TODO this can be smaller and would speedup the attack, only 64 bytes of ciphertext are allowed
|
|
|
|
|
u32 j = ct_len / 4;
|
|
|
|
|
|
|
|
|
|
for (u32 i = 0; i < j; i++) tmp_buf[i] = byte_swap_32 (metamask->ct_buf[i]);
|
|
|
|
|
|
|
|
|
|
u8 ct_buf[CT_MAX_LEN_BASE64] = { 0 };
|
|
|
|
|
u8 ct_buf[88+1];
|
|
|
|
|
|
|
|
|
|
memset (ct_buf, 0, sizeof (ct_buf));
|
|
|
|
|
|
|
|
|
|
base64_encode (int_to_base64, (const u8 *) tmp_buf, (const int) metamask->ct_len, ct_buf);
|
|
|
|
|
|
|
|
|
|