change hash-signature for 26610 (incompatible with 26600), remove debug print statements in attacks, add comments, add reference data

pull/3628/head
Your Name 1 year ago
parent 248c4afc09
commit 5208447e72

@ -335,7 +335,6 @@ KERNEL_FQ void m26610_comp (KERN_ATTR_TMPS_ESALT (pbkdf2_sha256_tmp_t, pbkdf2_sh
AES_GCM_Init (ukey, key_len, key, subKey, s_te0, s_te1, s_te2, s_te3, s_te4);
// iv
const u32 iv[4] = {
esalt_bufs[DIGESTS_OFFSET_HOST].iv_buf[0],
esalt_bufs[DIGESTS_OFFSET_HOST].iv_buf[1],
@ -349,33 +348,21 @@ KERNEL_FQ void m26610_comp (KERN_ATTR_TMPS_ESALT (pbkdf2_sha256_tmp_t, pbkdf2_sh
AES_GCM_Prepare_J0 (iv, iv_len, subKey, J0);
// ct
//u32 T[4] = { 0 };
//ct
u32 ct[4] = {
esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[0],
esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[1],
esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[2],
esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[3]
};
};
u32 pt[4] = { 0 };
//u32 S_len = 16;
//u32 aad_buf[4] = { 0 };
//u32 aad_len = 0;
//AES_GCM_GHASH_GLOBAL (subKey, aad_buf, aad_len, esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf, esalt_bufs[DIGESTS_OFFSET_HOST].ct_len, S);
//AES_GCM_GCTR (key, J0, S, S_len, T, s_te0, s_te1, s_te2, s_te3, s_te4);
// we try to decrypt the ciphertext
AES_GCM_inc32(J0); // the first ctr is used to compute the tag, only the second is used for decryption: https://en.wikipedia.org/wiki/Galois/Counter_Mode#/media/File:GCM-Galois_Counter_Mode_with_IV.svg
AES_GCM_GCTR (key, J0, ct, 16, pt, s_te0, s_te1, s_te2, s_te3, s_te4); // decrypt the ciphertext
if ((gid == 0) && (lid == 0)) printf ("pt[0]=%08x\n", pt[0]); // should be 5b7b2274 or [{"type"
// if ((gid == 0) && (lid == 0)) printf ("pt[0]=%08x\n", pt[0]); // should be 5b7b2274 or [{"type"
// cast plaintext buffer to byte such that we can do a byte per byte comparison
PRIVATE_AS const u32 *u32OutBufPtr = (PRIVATE_AS u32 *) pt;
@ -389,11 +376,12 @@ KERNEL_FQ void m26610_comp (KERN_ATTR_TMPS_ESALT (pbkdf2_sha256_tmp_t, pbkdf2_sh
for(int i=0;i<16;i++)
{
if(u8OutBufPtr[i] >=20 && u8OutBufPtr[i] <= 0x7e) {
if ((gid == 0) && (lid == 0)) printf("correct ASCII byte[%d]=0x%02x\n", i, u8OutBufPtr[i]);
//if ((gid == 0) && (lid == 0)) printf("correct ASCII byte[%d]=0x%02x\n", i, u8OutBufPtr[i]);
}
else {
if ((gid == 0) && (lid == 0)) printf("NOT correct! byte[%d]=0x%02x\n", i, u8OutBufPtr[i]);
//if ((gid == 0) && (lid == 0)) printf("NOT correct! byte[%d]=0x%02x\n", i, u8OutBufPtr[i]);
correct = false;
break;
}
}
@ -405,23 +393,17 @@ KERNEL_FQ void m26610_comp (KERN_ATTR_TMPS_ESALT (pbkdf2_sha256_tmp_t, pbkdf2_sh
esalt_bufs[DIGESTS_OFFSET_HOST].ct_buf[3],
};
if ((gid == 0) && (lid == 0)) printf ("ct[0]=%08x\n", ct[0]);
if ((gid == 0) && (lid == 0)) printf ("ct[1]=%08x\n", ct[1]);
if ((gid == 0) && (lid == 0)) printf ("ct[2]=%08x\n", ct[2]);
if ((gid == 0) && (lid == 0)) printf ("ct[3]=%08x\n", ct[3]);
if ((gid == 0) && (lid == 0)) printf("here0\n");
//if ((gid == 0) && (lid == 0)) printf ("ct[0]=%08x\n", ct[0]);
//if ((gid == 0) && (lid == 0)) printf ("ct[1]=%08x\n", ct[1]);
//if ((gid == 0) && (lid == 0)) printf ("ct[2]=%08x\n", ct[2]);
//if ((gid == 0) && (lid == 0)) printf ("ct[3]=%08x\n", ct[3]);
if (correct)
{
if ((gid == 0) && (lid == 0)) printf("here1\n");
int digest_pos = find_hash (digest, DIGESTS_CNT, &digests_buf[DIGESTS_OFFSET_HOST]);
if (digest_pos != -1)
{
if ((gid == 0) && (lid == 0)) printf("here2\n");
const u32 final_hash_pos = DIGESTS_OFFSET_HOST + digest_pos;
if (hc_atomic_inc (&hashes_shown[final_hash_pos]) == 0)

@ -22,6 +22,7 @@
- Added hash-mode: HMAC-RIPEMD160 (key = $salt)
- Added hash-mode: bcrypt(sha256($pass))
- Added hash-mode: md5(md5($salt).md5(md5($pass)))
- Added hash-mode: metamask (26610) with plaintext check instead of checking tag (26600). No longer needs all data in hash.
##
## Performance

@ -18,7 +18,8 @@ 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;
static const char *HASH_NAME = "MetaMask Wallet short data";
// 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
| OPTI_TYPE_SLOW_HASH_SIMD_LOOP;
@ -26,6 +27,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";
// 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; }
@ -237,15 +239,7 @@ int module_hash_decode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSE
digest[1] = (metamask->ct_buf[1]);
digest[2] = (metamask->ct_buf[2]);
digest[3] = (metamask->ct_buf[3]);
printf ("ct_buf[0]=%08x\n", metamask->ct_buf[0]);
printf ("ct_buf[1]=%08x\n", metamask->ct_buf[1]);
printf ("ct_buf[2]=%08x\n", metamask->ct_buf[2]);
printf ("ct_buf[3]=%08x\n", metamask->ct_buf[3]);
printf ("digest[0]=%08x\n", digest[0]);
printf ("digest[1]=%08x\n", digest[1]);
printf ("digest[2]=%08x\n", digest[2]);
printf ("digest[3]=%08x\n", digest[3]);
return (PARSER_OK);
}

@ -0,0 +1,41 @@
#!/usr/bin/env python3
from base64 import b64decode
from hashlib import pbkdf2_hmac
from Crypto.Cipher import AES
#TODO perhaps load the vault from tools/2hashcat_tests/metamask2hashcat.json similar as in tools/metamask2hashcat.py
vault = {"data":"R95fzGt4UQ0uwrcrVYnIi4UcSlWn9wlmer+//526ZDwYAp50K82F1u1oacYcdjjhuEvbZnWk/uBG00UkgLLlO3WbINljqmu2QWdDEwjTgo/qWR6MU9d/82rxNiONHQE8UrZ8SV+htVr6XIB0ze3aCV0E+fwI93EeP79ZeDxuOEhuHoiYT0bHWMv5nA48AdluG4DbOo7SrDAWBVCBsEdXsOfYsS3/TIh0a/iFCMX4uhxY2824JwcWp4H36SFWyBYMZCJ3/U4DYFbbjWZtGRthoJlIik5BJq4FLu3Y1jEgza0AWlAvu4MKTEqrYSpUIghfxf1a1f+kPvxsHNq0as0kRwCXu09DObbdsiggbmeoBkxMZiFq0d9ar/3Gon0r3hfc3c124Wlivzbzu1JcZ3wURhLSsUS7b5cfG86aXHJkxmQDA5urBz6lw3bsIvlEUB2ErkQy/zD+cPwCG1Rs/WKt7KNh45lppCUkHccbf+xlpdc8OfUwj01Xp7BdH8LMR7Vx1C4hZCvSdtURVl0VaAMxHDX0MjRkwmqS","iv":"h+BoIf2CQ5BEjaIOShFE7g==","salt":"jfGI3TXguhb8GPnKSXFrMzRk2NCEc131Gt5G3kZr5+s="}
password = "hashcat1"
salt = b64decode(vault["salt"])
key = pbkdf2_hmac("sha256", password.encode(), salt, 10_000)
iv = b64decode(vault["iv"])
payload = b64decode(vault["data"])
ciphertext = payload[:-16]
print(f"ciphertext.hex()={ciphertext.hex()[0:128]}")
tag = payload[-16:]
cipher = AES.new(key, AES.MODE_GCM, nonce=iv)
plaintext = cipher.decrypt(ciphertext)
print(plaintext.hex()[0:128])
print(str(plaintext[0:128]))
print()
try:
cipher.verify(tag)
print("The message is authentic:", plaintext.decode())
except ValueError:
print("Key incorrect or message corrupted")
print()
cipher = AES.new(key, AES.MODE_GCM, nonce=iv)
plaintext = cipher.decrypt(ciphertext[:32])
print("Partially encrypted message (32 bytes):", plaintext.decode())
cipher = AES.new(key, AES.MODE_GCM, nonce=iv)
plaintext = cipher.decrypt(ciphertext[:450])
print("Partially encrypted message (450 bytes):", plaintext.decode())

@ -0,0 +1 @@
{"data":"R95fzGt4UQ0uwrcrVYnIi4UcSlWn9wlmer+//526ZDwYAp50K82F1u1oacYcdjjhuEvbZnWk/uBG00UkgLLlO3WbINljqmu2QWdDEwjTgo/qWR6MU9d/82rxNiONHQE8UrZ8SV+htVr6XIB0ze3aCV0E+fwI93EeP79ZeDxuOEhuHoiYT0bHWMv5nA48AdluG4DbOo7SrDAWBVCBsEdXsOfYsS3/TIh0a/iFCMX4uhxY2824JwcWp4H36SFWyBYMZCJ3/U4DYFbbjWZtGRthoJlIik5BJq4FLu3Y1jEgza0AWlAvu4MKTEqrYSpUIghfxf1a1f+kPvxsHNq0as0kRwCXu09DObbdsiggbmeoBkxMZiFq0d9ar/3Gon0r3hfc3c124Wlivzbzu1JcZ3wURhLSsUS7b5cfG86aXHJkxmQDA5urBz6lw3bsIvlEUB2ErkQy/zD+cPwCG1Rs/WKt7KNh45lppCUkHccbf+xlpdc8OfUwj01Xp7BdH8LMR7Vx1C4hZCvSdtURVl0VaAMxHDX0MjRkwmqS","iv":"h+BoIf2CQ5BEjaIOShFE7g==","salt":"jfGI3TXguhb8GPnKSXFrMzRk2NCEc131Gt5G3kZr5+s="}

@ -11,8 +11,9 @@
import json
import argparse
import base64
def metamask_parser(file):
def metamask_parser(file, shortdata):
try:
f = open(file)
@ -23,7 +24,13 @@ def metamask_parser(file):
parser.print_help()
exit(1)
print('$metamask$' + j['salt'] + '$' + j['iv'] + '$' + j['data'])
if((len(j['data']) > 3000) or shortdata):
print("! Data too long, we limit it to 64 bytes, this hash can only be used with m26610!")
data_bin = base64.b64decode(j['data'])
j['data'] = base64.b64encode(data_bin[0:64]).decode("ascii")
print('$metamask-short$' + j['salt'] + '$' + j['iv'] + '$' + j['data'])
else:
print('$metamask$' + j['salt'] + '$' + j['iv'] + '$' + j['data'])
except ValueError as e:
parser.print_help()
exit(1)
@ -33,10 +40,12 @@ def metamask_parser(file):
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="metamask2hashcat.py extraction tool")
parser.add_argument('--vault', required=True, help='set metamask vault (json) file from path', type=str)
parser.add_argument('--shortdata', help='force short data, can only be used with m26610, ', action='store_true')
args = parser.parse_args()
if args.vault:
metamask_parser(args.vault)
metamask_parser(args.vault, args.shortdata)
else:
parser.print_help()
exit(1)

Loading…
Cancel
Save