mirror of
https://github.com/hashcat/hashcat.git
synced 2025-01-08 23:01:14 +00:00
Add module and unit test for hash-mode 15000
This commit is contained in:
parent
fc90bfc00c
commit
c67287e754
@ -643,17 +643,6 @@ typedef struct keepass_tmp
|
||||
|
||||
} keepass_tmp_t;
|
||||
|
||||
typedef struct dpapimk_tmp_v2
|
||||
{
|
||||
u64 ipad64[8];
|
||||
u64 opad64[8];
|
||||
u64 dgst64[16];
|
||||
u64 out64[16];
|
||||
|
||||
u32 userKey[8];
|
||||
|
||||
} dpapimk_tmp_v2_t;
|
||||
|
||||
typedef struct apple_secure_notes_tmp
|
||||
{
|
||||
u32 ipad[8];
|
||||
@ -664,7 +653,6 @@ typedef struct apple_secure_notes_tmp
|
||||
|
||||
} apple_secure_notes_tmp_t;
|
||||
|
||||
|
||||
typedef struct struct_psafe2_hdr
|
||||
{
|
||||
u32 random[2];
|
||||
@ -927,7 +915,6 @@ typedef enum kern_type
|
||||
KERN_TYPE_JKS_SHA1 = 15500,
|
||||
KERN_TYPE_ETHEREUM_PBKDF2 = 15600,
|
||||
KERN_TYPE_ETHEREUM_SCRYPT = 15700,
|
||||
KERN_TYPE_DPAPIMK_V2 = 15900,
|
||||
KERN_TYPE_TRIPCODE = 16000,
|
||||
KERN_TYPE_TACACS_PLUS = 16100,
|
||||
KERN_TYPE_APPLE_SECURE_NOTES = 16200,
|
||||
@ -1010,7 +997,6 @@ typedef enum rounds_count
|
||||
ROUNDS_ITUNES102_BACKUP = 10000,
|
||||
ROUNDS_ATLASSIAN = 10000,
|
||||
ROUNDS_NETBSD_SHA1CRYPT = 20000,
|
||||
ROUNDS_DPAPIMK_V2 = 8000 - 1, // from 4000 to 24000 (possibly more)
|
||||
ROUNDS_ETHEREUM_PBKDF2 = 262144 - 1,
|
||||
ROUNDS_APPLE_SECURE_NOTES = 20000,
|
||||
ROUNDS_ETHEREUM_PRESALE = 2000 - 1,
|
||||
|
@ -105,7 +105,6 @@
|
||||
" 11500 | CRC32 | Checksums",
|
||||
" 1100 | Domain Cached Credentials (DCC), MS Cache | Operating Systems",
|
||||
" 2100 | Domain Cached Credentials 2 (DCC2), MS Cache 2 | Operating Systems",
|
||||
" 15900 | DPAPI masterkey file v2 | Operating Systems",
|
||||
" 12800 | MS-AzureSync PBKDF2-HMAC-SHA256 | Operating Systems",
|
||||
" 12400 | BSDi Crypt, Extended DES | Operating Systems",
|
||||
" 7400 | sha256crypt $5$, SHA256 (Unix) | Operating Systems",
|
||||
@ -448,7 +447,6 @@ static const char *ST_HASH_15400 = "$chacha20$*0400000000000003*35*0200000000000
|
||||
static const char *ST_HASH_15500 = "$jksprivk$*338BD2FBEBA7B3EF198A4CBFC6E18AFF1E229367*5225850113575146134463704406336350011656*D5253EB151EB92DC73E542D8C0A4D7A848A5B0C0E370E625E6547D4E6F23416FC85A27BC295731B8021CDFBD003551C66C434FFBC87DACAD1FDF39022320034A2F86E779F2B1B3325428A666518FA89507AD63E15FD9C57B9E36EF5B642A2F448A9A3F09B79AD93D65F46B8692CD07539FD140146F8F219DC262971AF019E18EDC16C3C240569E1673F4D98BC818CCF28298D5A7BFF038A663DD10FE5E48643C3217C237D342164E2D41EF15075431FBD5B34800E5AE7EB80FAA5AE9982A55F35379AA7B31217E7F1C5F1964A15024A305AE4B3981FE1C80C163BC38ECA5581F11867E5C34C5D124D0367B3737E5E5BB14D2CAB26A698C8DAAB755C82BA6B823BCAECDD4A89C831651ACE5A6029FD0D3515C5D1D53AD8B9062CE8C445373862035CBBF60D490CA2E4975EE6E0358EC32E871FAB15347E3032E21F30F543BAAB01D779BA833CA0B8C7591B42C7C59A8FDD46D7DECEC0E91ADBF331177605E7830ABED62FAD7D5D806D8EFD01C38765940B7F97168FC72C39BF4C98F944FFC310CA8F4EB1D0F960F352CC5E2BB23A1EB221072A5471EDA2CE81C04595B8D37088CFB5C14F6A4A881AD12125DEFBB8154EB4C130AB7FD9933FD36DF1A6A26B51AB169866788678FCED988C8E017CA84354F487A5508210181AFB8B3AD0753E3E28BE674DFBD4E4FBDFD1E30D592F4EA3A77A2F0F5CF9A175DBC590EF5D42971A39918F12B92DCD8BFD56BE9A3459856B5587603C7B53062663A4C8894BBC9894FB1663BF30F32D907664328138B7A50EAC7F8E3183D74562A5C90FE1889AC4C5FE43EBEB8974563B6682F92591ECA4FA0DA72236C3851DA102DB6BA0CC07BFD32F7E962AB0EDCF4A8DEA6525174F5BB5C021E2A9A3F7F761E9CA90B6E27FB7E55CD91DA184FAC5E534E8AD25314C56CE5796506A0CA70881782F9C5147D87705065D68BD67D2B0344205BA6445D562273690004CA5A303274FB283A75F49BA968D7947943AA98F2AF9CB8253B425B86225E7395A331AC4CB1B1700C64D4F458D5D642C54148AE6DA41D9E26657D331B157D76042C2CF3057B83997C23D8BF68FB3C7337CAFB8B324AD0DF7A80B554B4D7F9AD6ED527E7932F1741A573C152A41610F6517E3F4A3BC6B66685871A7CE3795C559BD47CDB8E34CB2C1DFE980518D79E2078C258C54F312EB38609F640E7DC013E0F2A16A25BB5971882B4308D27930CA99FEC231AE927B62215A1B56098C362B7F20593953B29428681875070E84BF5B60BEA3948127151634123DA77C814AAD54CE10905763C8C19BC191C0C40458C809402E1957C4C05C4EAE27576B2D30593F7FDCC9A248DB5DB23CF2FA22A92C016090F611690BF0AB5B8B2866ED25F345EFE85DF3311C9E91C37CEE709CF16E7CB09D01BECD2961D094C02D42EC85BF47FAB1B67A13B9A1741C15F7156D57A71BFFABB03B71E69707913A5C136B3D69CE3F71ABFE376F0A21D723FFA2E60AC180689D3E8AF4348C9F555CD897387327FC8BA2B9C51A7298547E556A11A60441EF5331A1BFB847A3D23DD9F7C50E636A2C6309BC82E1A8852F5A8569B6D93*14*78D6A2424484CF5149932B7EA8BF*test";
|
||||
static const char *ST_HASH_15600 = "$ethereum$p*1024*38353131353831333338313138363430*a8b4dfe92687dbc0afeb5dae7863f18964241e96b264f09959903c8c924583fc*0a9252861d1e235994ce33dbca91c98231764d8ecb4950015a8ae20d6415b986";
|
||||
//static const char *ST_HASH_15700 = "$ethereum$s*262144*8*1*3134313837333434333838303231333633373433323633373534333136363537*73da7f80ec3bd4f2a128c3a815cfb4d576ecb1a9b47024c902e62ea926f7795b*910e0f8dc1f7ba41959e1089bb769f3e919109591913cc33ba03953d7a905efd";
|
||||
static const char *ST_HASH_15900 = "$DPAPImk$2*1*S-15-21-439882973-489230393-482956683-1522*aes256*sha512*12900*79f7ca399f2626e21aad108c3922af7c*288*c47bc8a985ca6aa708b01c97b004bff20cc52379dc2635b4acf59ce17970a2cb47ace98c7e8de977f265243c5c03d0a97e4b954b494d9e38d9158d0c1e729d16a28ba69e2e7c6c3bc0e3afc9c9b6306b83372ccb35d89b98925728fd36315b8ee95b4d4eccdcb31564769f9a4b9ee10828184e16d4af336675d5e31d987dd87233d34fbbb98880c5e1f64cbb9b043ad8";
|
||||
static const char *ST_HASH_16000 = "pfaRCwDe0U";
|
||||
static const char *ST_HASH_16100 = "$tacacs-plus$0$5fde8e68$4e13e8fb33df$c006";
|
||||
static const char *ST_HASH_16200 = "$ASN$*1*20000*80771171105233481004850004085037*d04b17af7f6b184346aad3efefe8bec0987ee73418291a41";
|
||||
@ -610,7 +608,6 @@ static const char *HT_15400 = "ChaCha20";
|
||||
static const char *HT_15500 = "JKS Java Key Store Private Keys (SHA1)";
|
||||
static const char *HT_15600 = "Ethereum Wallet, PBKDF2-HMAC-SHA256";
|
||||
static const char *HT_15700 = "Ethereum Wallet, SCRYPT";
|
||||
static const char *HT_15900 = "DPAPI masterkey file v2";
|
||||
static const char *HT_16000 = "Tripcode";
|
||||
static const char *HT_16100 = "TACACS+";
|
||||
static const char *HT_16200 = "Apple Secure Notes";
|
||||
@ -15873,8 +15870,6 @@ void hashconfig_benchmark_defaults (hashcat_ctx_t *hashcat_ctx, salt_t *salt, vo
|
||||
break;
|
||||
case 15700: salt->salt_iter = 1;
|
||||
break;
|
||||
case 15900: salt->salt_iter = ROUNDS_DPAPIMK_V2;
|
||||
break;
|
||||
case 16200: salt->salt_iter = ROUNDS_APPLE_SECURE_NOTES - 1;
|
||||
break;
|
||||
case 16300: salt->salt_iter = ROUNDS_ETHEREUM_PRESALE;
|
||||
@ -18346,91 +18341,6 @@ int ascii_digest (hashcat_ctx_t *hashcat_ctx, char *out_buf, const int out_size,
|
||||
digest_buf[7]
|
||||
);
|
||||
}
|
||||
else if (hash_mode == 15900)
|
||||
{
|
||||
dpapimk_t *dpapimks = (dpapimk_t *) esalts_buf;
|
||||
|
||||
dpapimk_t *dpapimk = &dpapimks[digest_cur];
|
||||
|
||||
u32 version = 2;
|
||||
u32 context = dpapimk->context;
|
||||
u32 rounds = salt.salt_iter + 1;
|
||||
u32 contents_len = dpapimk->contents_len;
|
||||
u32 SID_len = dpapimk->SID_len;
|
||||
u32 iv_len = 32;
|
||||
|
||||
u8 cipher_algorithm[8] = { 0 };
|
||||
u8 hash_algorithm[8] = { 0 };
|
||||
u8 SID[512] = { 0 };
|
||||
u8* SID_tmp;
|
||||
|
||||
u32 *ptr_SID = (u32 *) dpapimk->SID;
|
||||
u32 *ptr_iv = (u32 *) dpapimk->iv;
|
||||
u32 *ptr_contents = (u32 *) dpapimk->contents;
|
||||
|
||||
u32 u32_iv[4];
|
||||
u8 iv[32 + 1];
|
||||
|
||||
// convert back SID
|
||||
|
||||
SID_tmp = (u8 *) hcmalloc ((SID_len + 1) * sizeof(u8));
|
||||
|
||||
for (u32 i = 0; i < (SID_len / 4) + 1; i++)
|
||||
{
|
||||
u8 hex[8] = { 0 };
|
||||
u32_to_hex (byte_swap_32 (ptr_SID[i]), hex);
|
||||
|
||||
for (u32 j = 0, k = 0; j < 8; j += 2, k++)
|
||||
{
|
||||
SID_tmp[i * 4 + k] = hex_to_u8 (&hex[j]);
|
||||
}
|
||||
}
|
||||
// overwrite trailing 0x80
|
||||
SID_tmp[SID_len] = 0;
|
||||
|
||||
for (u32 i = 0, j = 0 ; j < SID_len ; i++, j += 2)
|
||||
{
|
||||
SID[i] = SID_tmp[j];
|
||||
}
|
||||
|
||||
hcfree(SID_tmp);
|
||||
|
||||
for (u32 i = 0; i < iv_len / 8; i++)
|
||||
{
|
||||
u32_iv[i] = byte_swap_32 (ptr_iv[i]);
|
||||
u32_to_hex (u32_iv[i], iv + i * 8);
|
||||
}
|
||||
iv[32] = 0;
|
||||
|
||||
u32 u32_contents[36];
|
||||
u8 contents[288 + 1];
|
||||
|
||||
for (u32 i = 0; i < contents_len / 8; i++)
|
||||
{
|
||||
u32_contents[i] = byte_swap_32 (ptr_contents[i]);
|
||||
u32_to_hex (u32_contents[i], contents + i * 8);
|
||||
}
|
||||
|
||||
contents[288] = 0;
|
||||
|
||||
if (contents_len == 288)
|
||||
{
|
||||
memcpy(cipher_algorithm, "aes256", strlen("aes256"));
|
||||
memcpy(hash_algorithm, "sha512", strlen("sha512"));
|
||||
}
|
||||
|
||||
snprintf (out_buf, out_size, "%s%d*%d*%s*%s*%s*%d*%s*%d*%s",
|
||||
SIGNATURE_DPAPIMK,
|
||||
version,
|
||||
context,
|
||||
SID,
|
||||
cipher_algorithm,
|
||||
hash_algorithm,
|
||||
rounds,
|
||||
iv,
|
||||
contents_len,
|
||||
contents);
|
||||
}
|
||||
else if (hash_mode == 16000)
|
||||
{
|
||||
memset (tmp_buf, 0, sizeof (tmp_buf));
|
||||
@ -23018,25 +22928,6 @@ int hashconfig_init (hashcat_ctx_t *hashcat_ctx)
|
||||
hashconfig->st_pass = ST_PASS_HASHCAT_PLAIN;
|
||||
break;
|
||||
|
||||
case 15900: hashconfig->hash_type = HASH_TYPE_DPAPIMK;
|
||||
hashconfig->salt_type = SALT_TYPE_EMBEDDED;
|
||||
hashconfig->attack_exec = ATTACK_EXEC_OUTSIDE_KERNEL;
|
||||
hashconfig->opts_type = OPTS_TYPE_PT_GENERATE_LE
|
||||
| OPTS_TYPE_PREFERED_THREAD;
|
||||
hashconfig->kern_type = KERN_TYPE_DPAPIMK_V2;
|
||||
hashconfig->dgst_size = DGST_SIZE_4_4;
|
||||
hashconfig->parse_func = dpapimk_parse_hash;
|
||||
hashconfig->opti_type = OPTI_TYPE_ZERO_BYTE
|
||||
| OPTI_TYPE_USES_BITS_64
|
||||
| OPTI_TYPE_SLOW_HASH_SIMD_LOOP;
|
||||
hashconfig->dgst_pos0 = 0;
|
||||
hashconfig->dgst_pos1 = 1;
|
||||
hashconfig->dgst_pos2 = 2;
|
||||
hashconfig->dgst_pos3 = 3;
|
||||
hashconfig->st_hash = ST_HASH_15900;
|
||||
hashconfig->st_pass = ST_PASS_HASHCAT_PLAIN;
|
||||
break;
|
||||
|
||||
case 16000: hashconfig->hash_type = HASH_TYPE_DESCRYPT;
|
||||
hashconfig->salt_type = SALT_TYPE_NONE;
|
||||
hashconfig->attack_exec = ATTACK_EXEC_INSIDE_KERNEL;
|
||||
@ -23419,7 +23310,6 @@ int hashconfig_init (hashcat_ctx_t *hashcat_ctx)
|
||||
case 15500: hashconfig->esalt_size = sizeof (jks_sha1_t); break;
|
||||
case 15600: hashconfig->esalt_size = sizeof (ethereum_pbkdf2_t); break;
|
||||
case 15700: hashconfig->esalt_size = sizeof (ethereum_scrypt_t); break;
|
||||
case 15900: hashconfig->esalt_size = sizeof (dpapimk_t); break;
|
||||
case 16100: hashconfig->esalt_size = sizeof (tacacs_plus_t); break;
|
||||
case 16200: hashconfig->esalt_size = sizeof (apple_secure_notes_t); break;
|
||||
case 16300: hashconfig->esalt_size = sizeof (ethereum_presale_t); break;
|
||||
@ -23522,7 +23412,6 @@ int hashconfig_init (hashcat_ctx_t *hashcat_ctx)
|
||||
case 15100: hashconfig->tmp_size = sizeof (pbkdf1_sha1_tmp_t); break;
|
||||
case 15200: hashconfig->tmp_size = sizeof (mywallet_tmp_t); break;
|
||||
case 15600: hashconfig->tmp_size = sizeof (pbkdf2_sha256_tmp_t); break;
|
||||
case 15900: hashconfig->tmp_size = sizeof (dpapimk_tmp_v2_t); break;
|
||||
case 16200: hashconfig->tmp_size = sizeof (apple_secure_notes_tmp_t); break;
|
||||
case 16300: hashconfig->tmp_size = sizeof (pbkdf2_sha256_tmp_t); break;
|
||||
case 16700: hashconfig->tmp_size = sizeof (apple_secure_notes_tmp_t); break;
|
||||
@ -23716,7 +23605,6 @@ u32 default_pw_max (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED co
|
||||
case 15400: pw_max = 32; break; // Underlaying ChaCha20 fixed
|
||||
case 15600: pw_max = PW_MAX; break;
|
||||
case 15700: pw_max = PW_MAX; break;
|
||||
case 15900: pw_max = PW_MAX; break;
|
||||
case 16000: pw_max = 8; break; // Underlaying DES max
|
||||
case 16900: pw_max = PW_MAX; break;
|
||||
}
|
||||
|
@ -22,9 +22,11 @@ static const char *HASH_NAME = "DPAPI masterkey file v1";
|
||||
static const u32 HASH_TYPE = HASH_TYPE_GENERIC;
|
||||
static const u64 KERN_TYPE = 15300;
|
||||
static const u32 OPTI_TYPE = OPTI_TYPE_ZERO_BYTE
|
||||
| OPTI_TYPE_USES_BITS_64
|
||||
| OPTI_TYPE_SLOW_HASH_SIMD_LOOP;
|
||||
static const u64 OPTS_TYPE = OPTS_TYPE_STATE_BUFFER_LE
|
||||
| OPTS_TYPE_PT_GENERATE_LE;
|
||||
| OPTS_TYPE_PT_GENERATE_LE
|
||||
| OPTS_TYPE_PREFERED_THREAD;
|
||||
static const u32 SALT_TYPE = SALT_TYPE_EMBEDDED;
|
||||
static const char *ST_PASS = "hashcat";
|
||||
static const char *ST_HASH = "$DPAPImk$1*1*S-15-21-466364039-425773974-453930460-1925*des3*sha1*24000*b038489dee5ad04e3e3cab4d957258b5*208*cb9b5b7d96a0d2a00305ca403d3fd9c47c561e35b4b2cf3aebfd1d3199a6481d56972be7ebd6c291b199e6f1c2ffaee91978706737e9b1209e6c7d3aa3d8c3c3e38ad1ccfa39400d62c2415961c17fd0bd6b0f7bbd49cc1de1a394e64b7237f56244238da8d37d78";
|
||||
@ -294,13 +296,15 @@ int module_hash_encode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSE
|
||||
u8 cipher_algorithm[8] = { 0 };
|
||||
u8 hash_algorithm[8] = { 0 };
|
||||
u8 SID[512] = { 0 };
|
||||
|
||||
u8* SID_tmp;
|
||||
|
||||
u32 *ptr_SID = (u32 *) dpapimk->SID;
|
||||
u32 *ptr_iv = (u32 *) dpapimk->iv;
|
||||
u32 *ptr_contents = (u32 *) dpapimk->contents;
|
||||
u32 *ptr_SID = (u32 *) dpapimk->SID;
|
||||
u32 *ptr_iv = (u32 *) dpapimk->iv;
|
||||
u32 *ptr_contents = (u32 *) dpapimk->contents;
|
||||
|
||||
u32 u32_iv[4];
|
||||
|
||||
u8 iv[32 + 1];
|
||||
|
||||
// convert back SID
|
||||
@ -310,6 +314,7 @@ int module_hash_encode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSE
|
||||
for (u32 i = 0; i < (SID_len / 4) + 1; i++)
|
||||
{
|
||||
u8 hex[8] = { 0 };
|
||||
|
||||
u32_to_hex (byte_swap_32 (ptr_SID[i]), hex);
|
||||
|
||||
for (u32 j = 0, k = 0; j < 8; j += 2, k++)
|
||||
@ -317,6 +322,7 @@ int module_hash_encode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSE
|
||||
SID_tmp[i * 4 + k] = hex_to_u8 (&hex[j]);
|
||||
}
|
||||
}
|
||||
|
||||
// overwrite trailing 0x80
|
||||
SID_tmp[SID_len] = 0;
|
||||
|
||||
@ -330,17 +336,21 @@ int module_hash_encode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSE
|
||||
for (u32 i = 0; i < iv_len / 8; i++)
|
||||
{
|
||||
u32_iv[i] = byte_swap_32 (ptr_iv[i]);
|
||||
|
||||
u32_to_hex (u32_iv[i], iv + i * 8);
|
||||
}
|
||||
|
||||
iv[32] = 0;
|
||||
|
||||
u32 u32_contents[36];
|
||||
u8 contents[288 + 1];
|
||||
|
||||
u8 contents[288 + 1];
|
||||
|
||||
for (u32 i = 0; i < contents_len / 8; i++)
|
||||
{
|
||||
u32_contents[i] = byte_swap_32 (ptr_contents[i]);
|
||||
u32_to_hex (u32_contents[i], contents + i * 8);
|
||||
|
||||
u32_to_hex (u32_contents[i], contents + i * 8);
|
||||
}
|
||||
|
||||
contents[208] = 0;
|
||||
@ -348,7 +358,8 @@ int module_hash_encode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSE
|
||||
if (contents_len == 208)
|
||||
{
|
||||
memcpy (cipher_algorithm, "des3", strlen("des3"));
|
||||
memcpy (hash_algorithm, "sha1", strlen("sha1"));
|
||||
|
||||
memcpy (hash_algorithm, "sha1", strlen("sha1"));
|
||||
}
|
||||
|
||||
const int line_len = snprintf (line_buf, line_size, "%s%u*%u*%s*%s*%s*%u*%s*%u*%s",
|
||||
|
442
src/modules/module_15900.c
Normal file
442
src/modules/module_15900.c
Normal file
@ -0,0 +1,442 @@
|
||||
/**
|
||||
* Author......: See docs/credits.txt
|
||||
* License.....: MIT
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "types.h"
|
||||
#include "modules.h"
|
||||
#include "bitops.h"
|
||||
#include "convert.h"
|
||||
#include "shared.h"
|
||||
#include "memory.h"
|
||||
|
||||
static const u32 ATTACK_EXEC = ATTACK_EXEC_OUTSIDE_KERNEL;
|
||||
static const u32 DGST_POS0 = 0;
|
||||
static const u32 DGST_POS1 = 1;
|
||||
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_OS;
|
||||
static const char *HASH_NAME = "DPAPI masterkey file v2";
|
||||
static const u32 HASH_TYPE = HASH_TYPE_GENERIC;
|
||||
static const u64 KERN_TYPE = 15900;
|
||||
static const u32 OPTI_TYPE = OPTI_TYPE_ZERO_BYTE
|
||||
| OPTI_TYPE_SLOW_HASH_SIMD_LOOP;
|
||||
static const u64 OPTS_TYPE = OPTS_TYPE_STATE_BUFFER_LE
|
||||
| OPTS_TYPE_PT_GENERATE_LE;
|
||||
static const u32 SALT_TYPE = SALT_TYPE_EMBEDDED;
|
||||
static const char *ST_PASS = "hashcat";
|
||||
static const char *ST_HASH = "$DPAPImk$2*1*S-15-21-439882973-489230393-482956683-1522*aes256*sha512*12900*79f7ca399f2626e21aad108c3922af7c*288*c47bc8a985ca6aa708b01c97b004bff20cc52379dc2635b4acf59ce17970a2cb47ace98c7e8de977f265243c5c03d0a97e4b954b494d9e38d9158d0c1e729d16a28ba69e2e7c6c3bc0e3afc9c9b6306b83372ccb35d89b98925728fd36315b8ee95b4d4eccdcb31564769f9a4b9ee10828184e16d4af336675d5e31d987dd87233d34fbbb98880c5e1f64cbb9b043ad8";
|
||||
|
||||
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; }
|
||||
u32 module_dgst_pos1 (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_POS1; }
|
||||
u32 module_dgst_pos2 (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_POS2; }
|
||||
u32 module_dgst_pos3 (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_POS3; }
|
||||
u32 module_dgst_size (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_SIZE; }
|
||||
u32 module_hash_category (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 HASH_CATEGORY; }
|
||||
const char *module_hash_name (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 HASH_NAME; }
|
||||
u32 module_hash_type (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 HASH_TYPE; }
|
||||
u64 module_kern_type (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 KERN_TYPE; }
|
||||
u32 module_opti_type (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 OPTI_TYPE; }
|
||||
u64 module_opts_type (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 OPTS_TYPE; }
|
||||
u32 module_salt_type (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 SALT_TYPE; }
|
||||
const char *module_st_hash (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 ST_HASH; }
|
||||
const char *module_st_pass (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 ST_PASS; }
|
||||
|
||||
typedef struct dpapimk
|
||||
{
|
||||
u32 context;
|
||||
|
||||
u32 SID[32];
|
||||
u32 SID_len;
|
||||
u32 SID_offset;
|
||||
|
||||
/* here only for possible
|
||||
forward compatibiliy
|
||||
*/
|
||||
// u8 cipher_algo[16];
|
||||
// u8 hash_algo[16];
|
||||
|
||||
u32 iv[4];
|
||||
u32 contents_len;
|
||||
u32 contents[128];
|
||||
|
||||
} dpapimk_t;
|
||||
|
||||
typedef struct dpapimk_tmp_v2
|
||||
{
|
||||
u64 ipad64[8];
|
||||
u64 opad64[8];
|
||||
u64 dgst64[16];
|
||||
u64 out64[16];
|
||||
|
||||
u32 userKey[8];
|
||||
|
||||
} dpapimk_tmp_v2_t;
|
||||
|
||||
static const char *SIGNATURE_DPAPIMK = "$DPAPImk$";
|
||||
|
||||
u64 module_tmp_size (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra)
|
||||
{
|
||||
const u64 tmp_size = (const u64) sizeof (dpapimk_tmp_v2_t);
|
||||
|
||||
return tmp_size;
|
||||
}
|
||||
|
||||
u64 module_esalt_size (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra)
|
||||
{
|
||||
const u64 esalt_size = (const u64) sizeof (dpapimk_t);
|
||||
|
||||
return esalt_size;
|
||||
}
|
||||
|
||||
u32 module_pw_max (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra)
|
||||
{
|
||||
const u32 pw_max = PW_MAX;
|
||||
|
||||
return pw_max;
|
||||
}
|
||||
|
||||
int module_hash_decode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED void *digest_buf, MAYBE_UNUSED salt_t *salt, MAYBE_UNUSED void *esalt_buf, MAYBE_UNUSED hashinfo_t *hash_info, const char *line_buf, MAYBE_UNUSED const int line_len)
|
||||
{
|
||||
u32 *digest = (u32 *) digest_buf;
|
||||
|
||||
dpapimk_t *dpapimk = (dpapimk_t *) esalt_buf;
|
||||
|
||||
token_t token;
|
||||
|
||||
token.token_cnt = 10;
|
||||
|
||||
token.signatures_cnt = 1;
|
||||
token.signatures_buf[0] = SIGNATURE_DPAPIMK;
|
||||
|
||||
// signature
|
||||
token.len[0] = 9;
|
||||
token.attr[0] = TOKEN_ATTR_FIXED_LENGTH
|
||||
| TOKEN_ATTR_VERIFY_SIGNATURE;
|
||||
|
||||
// version
|
||||
token.len_min[1] = 1;
|
||||
token.len_max[1] = 1;
|
||||
token.sep[1] = '*';
|
||||
token.attr[1] = TOKEN_ATTR_VERIFY_LENGTH
|
||||
| TOKEN_ATTR_VERIFY_DIGIT;
|
||||
|
||||
// context
|
||||
token.len_min[2] = 1;
|
||||
token.len_max[2] = 1;
|
||||
token.sep[2] = '*';
|
||||
token.attr[2] = TOKEN_ATTR_VERIFY_LENGTH
|
||||
| TOKEN_ATTR_VERIFY_DIGIT;
|
||||
|
||||
// sid
|
||||
token.len_min[3] = 10;
|
||||
token.len_max[3] = 60;
|
||||
token.sep[3] = '*';
|
||||
token.attr[3] = TOKEN_ATTR_VERIFY_LENGTH;
|
||||
|
||||
// cipher
|
||||
token.len_min[4] = 4;
|
||||
token.len_max[4] = 6;
|
||||
token.sep[4] = '*';
|
||||
token.attr[4] = TOKEN_ATTR_VERIFY_LENGTH;
|
||||
|
||||
// hash
|
||||
token.len_min[5] = 4;
|
||||
token.len_max[5] = 6;
|
||||
token.sep[5] = '*';
|
||||
token.attr[5] = TOKEN_ATTR_VERIFY_LENGTH;
|
||||
|
||||
// iterations
|
||||
token.len_min[6] = 1;
|
||||
token.len_max[6] = 6;
|
||||
token.sep[6] = '*';
|
||||
token.attr[6] = TOKEN_ATTR_VERIFY_LENGTH
|
||||
| TOKEN_ATTR_VERIFY_DIGIT;
|
||||
|
||||
// iv
|
||||
token.len_min[7] = 32;
|
||||
token.len_max[7] = 32;
|
||||
token.sep[7] = '*';
|
||||
token.attr[7] = TOKEN_ATTR_VERIFY_LENGTH
|
||||
| TOKEN_ATTR_VERIFY_HEX;
|
||||
|
||||
// content len
|
||||
token.len_min[8] = 1;
|
||||
token.len_max[8] = 6;
|
||||
token.sep[8] = '*';
|
||||
token.attr[8] = TOKEN_ATTR_VERIFY_LENGTH
|
||||
| TOKEN_ATTR_VERIFY_DIGIT;
|
||||
|
||||
// content
|
||||
token.len_min[9] = 0;
|
||||
token.len_max[9] = 1024;
|
||||
token.attr[9] = TOKEN_ATTR_VERIFY_LENGTH
|
||||
| TOKEN_ATTR_VERIFY_HEX;
|
||||
|
||||
const int rc_tokenizer = input_tokenizer ((const u8 *) line_buf, line_len, &token);
|
||||
|
||||
if (rc_tokenizer != PARSER_OK) return (rc_tokenizer);
|
||||
|
||||
const u8 *version_pos = token.buf[1];
|
||||
const u8 *context_pos = token.buf[2];
|
||||
const u8 *SID_pos = token.buf[3];
|
||||
const u8 *rounds_pos = token.buf[6];
|
||||
const u8 *iv_pos = token.buf[7];
|
||||
const u8 *contents_len_pos = token.buf[8];
|
||||
const u8 *contents_pos = token.buf[9];
|
||||
|
||||
/**
|
||||
* content verification
|
||||
*/
|
||||
|
||||
const int version = hc_strtoul ((const char *) version_pos, NULL, 10);
|
||||
const int contents_len = hc_strtoul ((const char *) contents_len_pos, NULL, 10);
|
||||
|
||||
if (version == 1)
|
||||
{
|
||||
if (contents_len != 208) return (PARSER_SALT_LENGTH);
|
||||
}
|
||||
else if (version == 2)
|
||||
{
|
||||
if (contents_len != 288) return (PARSER_SALT_LENGTH);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (PARSER_SALT_VALUE);
|
||||
}
|
||||
|
||||
if (contents_len != token.len[9]) return (PARSER_SALT_LENGTH);
|
||||
|
||||
dpapimk->contents_len = contents_len;
|
||||
|
||||
dpapimk->context = hc_strtoul ((const char *) context_pos, NULL, 10);
|
||||
|
||||
// division by 4 should be fine because contents_len is either 208 or 288
|
||||
|
||||
for (u32 i = 0; i < dpapimk->contents_len / 4; i++)
|
||||
{
|
||||
dpapimk->contents[i] = hex_to_u32 ((const u8 *) &contents_pos[i * 8]);
|
||||
|
||||
dpapimk->contents[i] = byte_swap_32 (dpapimk->contents[i]);
|
||||
}
|
||||
|
||||
// SID
|
||||
|
||||
const int SID_len = token.len[3];
|
||||
|
||||
u8 SID_utf16le[128] = { 0 };
|
||||
|
||||
for (int i = 0; i < SID_len; i++)
|
||||
{
|
||||
SID_utf16le[i * 2] = SID_pos[i];
|
||||
}
|
||||
|
||||
/* Specific to DPAPI: needs trailing '\0' while computing hash */
|
||||
|
||||
dpapimk->SID_len = (SID_len + 1) * 2;
|
||||
|
||||
SID_utf16le[dpapimk->SID_len] = 0x80;
|
||||
|
||||
memcpy ((u8 *) dpapimk->SID, SID_utf16le, sizeof (SID_utf16le));
|
||||
|
||||
for (u32 i = 0; i < 32; i++)
|
||||
{
|
||||
dpapimk->SID[i] = byte_swap_32 (dpapimk->SID[i]);
|
||||
}
|
||||
|
||||
// iv
|
||||
|
||||
dpapimk->iv[0] = hex_to_u32 ((const u8 *) &iv_pos[ 0]);
|
||||
dpapimk->iv[1] = hex_to_u32 ((const u8 *) &iv_pos[ 8]);
|
||||
dpapimk->iv[2] = hex_to_u32 ((const u8 *) &iv_pos[16]);
|
||||
dpapimk->iv[3] = hex_to_u32 ((const u8 *) &iv_pos[24]);
|
||||
|
||||
dpapimk->iv[0] = byte_swap_32 (dpapimk->iv[0]);
|
||||
dpapimk->iv[1] = byte_swap_32 (dpapimk->iv[1]);
|
||||
dpapimk->iv[2] = byte_swap_32 (dpapimk->iv[2]);
|
||||
dpapimk->iv[3] = byte_swap_32 (dpapimk->iv[3]);
|
||||
|
||||
digest[0] = dpapimk->iv[0];
|
||||
digest[1] = dpapimk->iv[1];
|
||||
digest[2] = dpapimk->iv[2];
|
||||
digest[3] = dpapimk->iv[3];
|
||||
|
||||
salt->salt_buf[0] = dpapimk->iv[0];
|
||||
salt->salt_buf[1] = dpapimk->iv[1];
|
||||
salt->salt_buf[2] = dpapimk->iv[2];
|
||||
salt->salt_buf[3] = dpapimk->iv[3];
|
||||
|
||||
salt->salt_len = 16;
|
||||
|
||||
// iter
|
||||
|
||||
salt->salt_iter = hc_strtoul ((const char *) rounds_pos, NULL, 10) - 1;
|
||||
|
||||
return (PARSER_OK);
|
||||
}
|
||||
|
||||
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 hashinfo_t *hash_info, char *line_buf, MAYBE_UNUSED const int line_size)
|
||||
{
|
||||
const u32 *digest = (const u32 *) digest_buf;
|
||||
|
||||
const dpapimk_t *dpapimk = (const dpapimk_t *) esalt_buf;
|
||||
|
||||
u32 version = 2;
|
||||
u32 context = dpapimk->context;
|
||||
u32 rounds = salt->salt_iter + 1;
|
||||
u32 contents_len = dpapimk->contents_len;
|
||||
u32 SID_len = dpapimk->SID_len;
|
||||
u32 iv_len = 32;
|
||||
|
||||
u8 cipher_algorithm[8] = { 0 };
|
||||
u8 hash_algorithm[8] = { 0 };
|
||||
u8 SID[512] = { 0 };
|
||||
u8* SID_tmp;
|
||||
|
||||
u32 *ptr_SID = (u32 *) dpapimk->SID;
|
||||
u32 *ptr_iv = (u32 *) dpapimk->iv;
|
||||
u32 *ptr_contents = (u32 *) dpapimk->contents;
|
||||
|
||||
u32 u32_iv[4];
|
||||
u8 iv[32 + 1];
|
||||
|
||||
// convert back SID
|
||||
|
||||
SID_tmp = (u8 *) hcmalloc ((SID_len + 1) * sizeof(u8));
|
||||
|
||||
for (u32 i = 0; i < (SID_len / 4) + 1; i++)
|
||||
{
|
||||
u8 hex[8] = { 0 };
|
||||
|
||||
u32_to_hex (byte_swap_32 (ptr_SID[i]), hex);
|
||||
|
||||
for (u32 j = 0, k = 0; j < 8; j += 2, k++)
|
||||
{
|
||||
SID_tmp[i * 4 + k] = hex_to_u8 (&hex[j]);
|
||||
}
|
||||
}
|
||||
|
||||
// overwrite trailing 0x80
|
||||
SID_tmp[SID_len] = 0;
|
||||
|
||||
for (u32 i = 0, j = 0 ; j < SID_len ; i++, j += 2)
|
||||
{
|
||||
SID[i] = SID_tmp[j];
|
||||
}
|
||||
|
||||
hcfree (SID_tmp);
|
||||
|
||||
for (u32 i = 0; i < iv_len / 8; i++)
|
||||
{
|
||||
u32_iv[i] = byte_swap_32 (ptr_iv[i]);
|
||||
|
||||
u32_to_hex (u32_iv[i], iv + i * 8);
|
||||
}
|
||||
|
||||
iv[32] = 0;
|
||||
|
||||
u32 u32_contents[36];
|
||||
|
||||
u8 contents[288 + 1];
|
||||
|
||||
for (u32 i = 0; i < contents_len / 8; i++)
|
||||
{
|
||||
u32_contents[i] = byte_swap_32 (ptr_contents[i]);
|
||||
|
||||
u32_to_hex (u32_contents[i], contents + i * 8);
|
||||
}
|
||||
|
||||
contents[288] = 0;
|
||||
|
||||
if (contents_len == 288)
|
||||
{
|
||||
memcpy (cipher_algorithm, "aes256", strlen ("aes256"));
|
||||
|
||||
memcpy (hash_algorithm, "sha512", strlen ("sha512"));
|
||||
}
|
||||
|
||||
const int line_len = snprintf (line_buf, line_size, "%s%d*%d*%s*%s*%s*%d*%s*%d*%s",
|
||||
SIGNATURE_DPAPIMK,
|
||||
version,
|
||||
context,
|
||||
SID,
|
||||
cipher_algorithm,
|
||||
hash_algorithm,
|
||||
rounds,
|
||||
iv,
|
||||
contents_len,
|
||||
contents);
|
||||
|
||||
return line_len;
|
||||
}
|
||||
|
||||
void module_init (module_ctx_t *module_ctx)
|
||||
{
|
||||
module_ctx->module_context_size = MODULE_CONTEXT_SIZE_CURRENT;
|
||||
module_ctx->module_interface_version = MODULE_INTERFACE_VERSION_CURRENT;
|
||||
|
||||
module_ctx->module_attack_exec = module_attack_exec;
|
||||
module_ctx->module_benchmark_esalt = MODULE_DEFAULT;
|
||||
module_ctx->module_benchmark_hook_salt = MODULE_DEFAULT;
|
||||
module_ctx->module_benchmark_mask = MODULE_DEFAULT;
|
||||
module_ctx->module_benchmark_salt = MODULE_DEFAULT;
|
||||
module_ctx->module_build_plain_postprocess = MODULE_DEFAULT;
|
||||
module_ctx->module_deep_comp_kernel = MODULE_DEFAULT;
|
||||
module_ctx->module_dgst_pos0 = module_dgst_pos0;
|
||||
module_ctx->module_dgst_pos1 = module_dgst_pos1;
|
||||
module_ctx->module_dgst_pos2 = module_dgst_pos2;
|
||||
module_ctx->module_dgst_pos3 = module_dgst_pos3;
|
||||
module_ctx->module_dgst_size = module_dgst_size;
|
||||
module_ctx->module_dictstat_disable = MODULE_DEFAULT;
|
||||
module_ctx->module_esalt_size = module_esalt_size;
|
||||
module_ctx->module_extra_buffer_size = MODULE_DEFAULT;
|
||||
module_ctx->module_forced_outfile_format = MODULE_DEFAULT;
|
||||
module_ctx->module_hash_binary_count = MODULE_DEFAULT;
|
||||
module_ctx->module_hash_binary_parse = MODULE_DEFAULT;
|
||||
module_ctx->module_hash_binary_save = MODULE_DEFAULT;
|
||||
module_ctx->module_hash_binary_verify = MODULE_DEFAULT;
|
||||
module_ctx->module_hash_decode_outfile = MODULE_DEFAULT;
|
||||
module_ctx->module_hash_decode_zero_hash = MODULE_DEFAULT;
|
||||
module_ctx->module_hash_decode = module_hash_decode;
|
||||
module_ctx->module_hash_encode_status = MODULE_DEFAULT;
|
||||
module_ctx->module_hash_encode = module_hash_encode;
|
||||
module_ctx->module_hash_init_selftest = MODULE_DEFAULT;
|
||||
module_ctx->module_hash_mode = MODULE_DEFAULT;
|
||||
module_ctx->module_hash_category = module_hash_category;
|
||||
module_ctx->module_hash_name = module_hash_name;
|
||||
module_ctx->module_hash_type = module_hash_type;
|
||||
module_ctx->module_hlfmt_disable = MODULE_DEFAULT;
|
||||
module_ctx->module_hook12 = MODULE_DEFAULT;
|
||||
module_ctx->module_hook23 = MODULE_DEFAULT;
|
||||
module_ctx->module_hook_salt_size = MODULE_DEFAULT;
|
||||
module_ctx->module_hook_size = MODULE_DEFAULT;
|
||||
module_ctx->module_jit_build_options = MODULE_DEFAULT;
|
||||
module_ctx->module_kernel_accel_max = MODULE_DEFAULT;
|
||||
module_ctx->module_kernel_accel_min = MODULE_DEFAULT;
|
||||
module_ctx->module_kernel_loops_max = MODULE_DEFAULT;
|
||||
module_ctx->module_kernel_loops_min = MODULE_DEFAULT;
|
||||
module_ctx->module_kernel_threads_max = MODULE_DEFAULT;
|
||||
module_ctx->module_kernel_threads_min = MODULE_DEFAULT;
|
||||
module_ctx->module_kern_type = module_kern_type;
|
||||
module_ctx->module_opti_type = module_opti_type;
|
||||
module_ctx->module_opts_type = module_opts_type;
|
||||
module_ctx->module_outfile_check_disable = MODULE_DEFAULT;
|
||||
module_ctx->module_outfile_check_nocomp = MODULE_DEFAULT;
|
||||
module_ctx->module_potfile_disable = MODULE_DEFAULT;
|
||||
module_ctx->module_potfile_keep_all_hashes = MODULE_DEFAULT;
|
||||
module_ctx->module_pwdump_column = MODULE_DEFAULT;
|
||||
module_ctx->module_pw_max = module_pw_max;
|
||||
module_ctx->module_pw_min = MODULE_DEFAULT;
|
||||
module_ctx->module_salt_max = MODULE_DEFAULT;
|
||||
module_ctx->module_salt_min = MODULE_DEFAULT;
|
||||
module_ctx->module_salt_type = module_salt_type;
|
||||
module_ctx->module_separator = MODULE_DEFAULT;
|
||||
module_ctx->module_st_hash = module_st_hash;
|
||||
module_ctx->module_st_pass = module_st_pass;
|
||||
module_ctx->module_tmp_size = module_tmp_size;
|
||||
module_ctx->module_unstable_warning = MODULE_DEFAULT;
|
||||
module_ctx->module_warmup_disable = MODULE_DEFAULT;
|
||||
}
|
@ -8,10 +8,10 @@
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Encode;
|
||||
use Crypt::ECB qw (encrypt);
|
||||
use Digest::MD4 qw (md4);
|
||||
use Digest::SHA qw (sha1 hmac_sha1);
|
||||
use Crypt::ECB qw (encrypt);
|
||||
use Encode;
|
||||
|
||||
sub module_constraints { [[0, 255], [-1, -1], [0, 27], [-1, -1], [-1, -1]] }
|
||||
|
||||
|
412
tools/test_modules/m15900.pm
Normal file
412
tools/test_modules/m15900.pm
Normal file
@ -0,0 +1,412 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
##
|
||||
## Author......: See docs/credits.txt
|
||||
## License.....: MIT
|
||||
##
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Crypt::CBC;
|
||||
use Crypt::ECB qw (encrypt);
|
||||
use Digest::MD4 qw (md4);
|
||||
use Digest::SHA qw (sha1 hmac_sha1 hmac_sha512);
|
||||
use Encode;
|
||||
|
||||
sub module_constraints { [[0, 255], [-1, -1], [0, 27], [-1, -1], [-1, -1]] }
|
||||
|
||||
sub get_random_dpapimk_salt
|
||||
{
|
||||
my $version = shift;
|
||||
|
||||
my $salt_buf = "";
|
||||
|
||||
my $context = random_number (1, 2);
|
||||
|
||||
my $cipher_algo = "";
|
||||
|
||||
my $hash_algo = "";
|
||||
|
||||
my $iterations;
|
||||
|
||||
my $SID = sprintf ('S-15-21-%d-%d-%d-%d',
|
||||
random_number (400000000,490000000),
|
||||
random_number (400000000,490000000),
|
||||
random_number (400000000,490000000),
|
||||
random_number (1000,1999));
|
||||
|
||||
my $cipher_len = 0;
|
||||
|
||||
if ($version == 1)
|
||||
{
|
||||
$iterations = random_number (4000, 24000);
|
||||
|
||||
$cipher_algo = "des3";
|
||||
|
||||
$hash_algo = "sha1";
|
||||
|
||||
$cipher_len = 208;
|
||||
}
|
||||
elsif ($version == 2)
|
||||
{
|
||||
$iterations = random_number (8000, 17000);
|
||||
|
||||
$cipher_algo = "aes256";
|
||||
|
||||
$hash_algo = "sha512";
|
||||
|
||||
$cipher_len = 288;
|
||||
}
|
||||
|
||||
my $iv = random_bytes (16);
|
||||
$iv = unpack ("H*", $iv);
|
||||
|
||||
$salt_buf = $version . '*' .
|
||||
$context . '*' .
|
||||
$SID . '*' .
|
||||
$cipher_algo . '*' .
|
||||
$hash_algo . '*' .
|
||||
$iterations . '*' .
|
||||
$iv . '*' .
|
||||
$cipher_len . '*';
|
||||
|
||||
return $salt_buf;
|
||||
}
|
||||
|
||||
#Thanks to Jochen Hoenicke <hoenicke@gmail.com>
|
||||
# (one of the authors of Palm Keyring)
|
||||
# for these next two subs.
|
||||
sub dpapi_pbkdf2
|
||||
{
|
||||
my ($password, $salt, $iter, $keylen, $prf) = @_;
|
||||
my ($k, $t, $u, $ui, $i);
|
||||
$t = "";
|
||||
for ($k = 1; length ($t) < $keylen; $k++)
|
||||
{
|
||||
$u = $ui = &$prf ($salt.pack ('N', $k), $password);
|
||||
for ($i = 1; $i < $iter; $i++)
|
||||
{
|
||||
# modification to fit Microsoft
|
||||
# weird pbkdf2 implementation...
|
||||
$ui = &$prf ($u, $password);
|
||||
$u ^= $ui;
|
||||
}
|
||||
$t .= $u;
|
||||
}
|
||||
return substr ($t, 0, $keylen);
|
||||
}
|
||||
|
||||
sub module_generate_hash
|
||||
{
|
||||
my $word_buf = shift;
|
||||
my $salt_buf = shift;
|
||||
my $dpapimk_salt = shift // get_random_dpapimk_salt (2);
|
||||
my $cipher = shift;
|
||||
|
||||
my @salt_arr = split ('\*', $dpapimk_salt);
|
||||
|
||||
my $version = $salt_arr[0];
|
||||
my $context = $salt_arr[1];
|
||||
my $SID = $salt_arr[2];
|
||||
my $cipher_algorithm = $salt_arr[3];
|
||||
my $hash_algorithm = $salt_arr[4];
|
||||
my $iterations = $salt_arr[5];
|
||||
my $salt = pack ("H*", $salt_arr[6]);
|
||||
my $cipher_len = $salt_arr[7];
|
||||
|
||||
# intermediate values
|
||||
|
||||
my $user_hash;
|
||||
my $user_derivationKey;
|
||||
my $encKey;
|
||||
my $expected_hmac;
|
||||
my $cleartext;
|
||||
|
||||
if ($context == 1)
|
||||
{
|
||||
$user_hash = sha1 (encode ("UTF-16LE", $word_buf));
|
||||
}
|
||||
elsif ($context == 2)
|
||||
{
|
||||
$user_hash = md4 (encode ("UTF-16LE", $word_buf));
|
||||
}
|
||||
|
||||
$user_derivationKey = hmac_sha1 (encode ("UTF-16LE", $SID . "\x00"), $user_hash);
|
||||
|
||||
my $hmacSalt = random_bytes (16);
|
||||
my $last_key = random_bytes (64);
|
||||
|
||||
if ($version == 1)
|
||||
{
|
||||
$encKey = hmac_sha1 ($hmacSalt, $user_derivationKey);
|
||||
$expected_hmac = hmac_sha1 ($last_key, $encKey);
|
||||
|
||||
# need padding because keyLen is 24 and hashLen 20
|
||||
$expected_hmac = $expected_hmac . random_bytes (4);
|
||||
}
|
||||
elsif ($version == 2)
|
||||
{
|
||||
$encKey = hmac_sha512 ($hmacSalt, $user_derivationKey);
|
||||
$expected_hmac = hmac_sha512 ($last_key, $encKey);
|
||||
}
|
||||
|
||||
$cleartext = $hmacSalt . $expected_hmac . $last_key;
|
||||
|
||||
my $derived_key;
|
||||
my $key;
|
||||
my $iv;
|
||||
|
||||
my $pbkdf2;
|
||||
|
||||
if ($version == 1)
|
||||
{
|
||||
$derived_key = dpapi_pbkdf2 ($user_derivationKey, $salt, $iterations, 32, \&hmac_sha1);
|
||||
}
|
||||
elsif ($version == 2)
|
||||
{
|
||||
$derived_key = dpapi_pbkdf2 ($user_derivationKey, $salt, $iterations, 48, \&hmac_sha512);
|
||||
}
|
||||
|
||||
if (defined $cipher)
|
||||
{
|
||||
$cipher = pack ("H*", $cipher);
|
||||
|
||||
my $computed_hmac = "";
|
||||
|
||||
if ($version == 1)
|
||||
{
|
||||
$key = substr ($derived_key, 0, 24);
|
||||
$iv = substr ($derived_key, 24, 8);
|
||||
|
||||
my $p1 = Crypt::ECB->new ({
|
||||
key => substr ($key, 0, 8),
|
||||
cipher => "DES",
|
||||
literal_key => 1,
|
||||
header => "none",
|
||||
keysize => 8,
|
||||
padding => "null",
|
||||
});
|
||||
|
||||
my $p2 = Crypt::ECB->new ({
|
||||
key => substr ($key, 8, 8),
|
||||
cipher => "DES",
|
||||
literal_key => 1,
|
||||
header => "none",
|
||||
keysize => 8,
|
||||
padding => "null",
|
||||
});
|
||||
|
||||
my $p3 = Crypt::ECB->new ({
|
||||
key => substr ($key, 16, 8),
|
||||
cipher => "DES",
|
||||
literal_key => 1,
|
||||
header => "none",
|
||||
keysize => 8,
|
||||
padding => "null",
|
||||
});
|
||||
|
||||
# let's compute a 3DES-EDE-CBC decryption
|
||||
|
||||
my $out1;
|
||||
my $out2;
|
||||
my $out3;
|
||||
my $expected_cleartext = "";
|
||||
|
||||
# size of cipherlen is 104 bytes
|
||||
for (my $k = 0; $k < 13; $k++)
|
||||
{
|
||||
$out1 = $p3->decrypt (substr ($cipher, $k * 8, 8));
|
||||
$out2 = $p2->encrypt ($out1);
|
||||
$out3 = $p1->decrypt ($out2);
|
||||
|
||||
$expected_cleartext .= substr ($out3, 0, 8) ^ $iv;
|
||||
|
||||
$iv = substr ($cipher, $k * 8, 8);
|
||||
}
|
||||
|
||||
$last_key = substr ($expected_cleartext, length ($expected_cleartext) - 64, 64);
|
||||
$hmacSalt = substr ($expected_cleartext, 0, 16);
|
||||
$expected_hmac = substr ($expected_cleartext, 16, 20);
|
||||
|
||||
$encKey = hmac_sha1 ($hmacSalt, $user_derivationKey);
|
||||
$computed_hmac = hmac_sha1 ($last_key, $encKey);
|
||||
|
||||
$cleartext = $expected_cleartext;
|
||||
|
||||
if (unpack ("H*", $expected_hmac) ne unpack ("H*", $computed_hmac))
|
||||
{
|
||||
$cleartext = "0" x 104;
|
||||
}
|
||||
}
|
||||
elsif ($version == 2)
|
||||
{
|
||||
$key = substr ($derived_key, 0, 32);
|
||||
$iv = substr ($derived_key, 32, 16);
|
||||
|
||||
my $aes = Crypt::CBC->new ({
|
||||
key => $key,
|
||||
cipher => "Crypt::Rijndael",
|
||||
iv => $iv,
|
||||
literal_key => 1,
|
||||
header => "none",
|
||||
keysize => 32,
|
||||
padding => "null",
|
||||
});
|
||||
|
||||
my $expected_cleartext = $aes->decrypt ($cipher);
|
||||
|
||||
$last_key = substr ($expected_cleartext, length ($expected_cleartext) - 64, 64);
|
||||
$hmacSalt = substr ($expected_cleartext, 0, 16);
|
||||
$expected_hmac = substr ($expected_cleartext, 16, 64);
|
||||
|
||||
$encKey = hmac_sha512 ($hmacSalt, $user_derivationKey);
|
||||
$computed_hmac = hmac_sha512 ($last_key, $encKey);
|
||||
|
||||
$cleartext = $expected_cleartext;
|
||||
|
||||
if (unpack ("H*", $expected_hmac) ne unpack ("H*", $computed_hmac))
|
||||
{
|
||||
$cleartext = "0" x 144;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($version == 1)
|
||||
{
|
||||
$key = substr ($derived_key, 0, 24);
|
||||
$iv = substr ($derived_key, 24, 8);
|
||||
|
||||
my $p1 = Crypt::ECB->new ({
|
||||
key => substr ($key, 0, 8),
|
||||
cipher => "DES",
|
||||
literal_key => 1,
|
||||
header => "none",
|
||||
keysize => 8,
|
||||
padding => "null",
|
||||
});
|
||||
|
||||
my $p2 = Crypt::ECB->new ({
|
||||
key => substr ($key, 8, 8),
|
||||
cipher => "DES",
|
||||
literal_key => 1,
|
||||
header => "none",
|
||||
keysize => 8,
|
||||
padding => "null",
|
||||
});
|
||||
|
||||
my $p3 = Crypt::ECB->new ({
|
||||
key => substr ($key, 16, 8),
|
||||
cipher => "DES",
|
||||
literal_key => 1,
|
||||
header => "none",
|
||||
keysize => 8,
|
||||
padding => "null",
|
||||
});
|
||||
|
||||
# let's compute a 3DES-EDE-CBC encryption
|
||||
|
||||
# compute first block
|
||||
my $out1 = $p1->encrypt (substr ($cleartext, 0, 8) ^ $iv);
|
||||
my $out2 = $p2->decrypt ($out1);
|
||||
my $out3 = $p3->encrypt ($out2);
|
||||
|
||||
$cipher = substr ($out3, 0, 8);
|
||||
|
||||
# size of cipherlen is 104 bytes
|
||||
for (my $k = 1; $k < 13; $k++)
|
||||
{
|
||||
$iv = $out3;
|
||||
|
||||
$out1 = $p1->encrypt (substr ($cleartext, $k * 8, 8) ^ $iv);
|
||||
$out2 = $p2->decrypt ($out1);
|
||||
$out3 = $p3->encrypt ($out2);
|
||||
|
||||
$cipher .= substr ($out3, 0, 8);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$key = substr ($derived_key, 0, 32);
|
||||
$iv = substr ($derived_key, 32, 16);
|
||||
|
||||
my $aes = Crypt::CBC->new ({
|
||||
key => $key,
|
||||
cipher => "Crypt::Rijndael",
|
||||
iv => $iv,
|
||||
literal_key => 1,
|
||||
header => "none",
|
||||
keysize => 32,
|
||||
padding => "null",
|
||||
});
|
||||
|
||||
$cipher = $aes->encrypt ($cleartext);
|
||||
}
|
||||
|
||||
my $tmp_hash = sprintf ('$DPAPImk$%d*%d*%s*%s*%s*%d*%s*%d*%s',
|
||||
$version,
|
||||
$context,
|
||||
$SID,
|
||||
$cipher_algorithm,
|
||||
$hash_algorithm,
|
||||
$iterations,
|
||||
unpack ("H*", $salt),
|
||||
$cipher_len,
|
||||
unpack ("H*", $cipher));
|
||||
|
||||
return $tmp_hash;
|
||||
}
|
||||
|
||||
sub module_verify_hash
|
||||
{
|
||||
my $line = shift;
|
||||
|
||||
my ($hash, $word) = split (':', $line);
|
||||
|
||||
return unless defined $hash;
|
||||
return unless defined $word;
|
||||
|
||||
my @tmp_data = split ('\$', $hash);
|
||||
|
||||
my $signature = $tmp_data[1];
|
||||
|
||||
next unless ($signature eq 'DPAPImk');
|
||||
|
||||
my @data = split ('\*', $tmp_data[2]);
|
||||
|
||||
next unless (scalar @data == 9);
|
||||
|
||||
my $version = shift @data;
|
||||
|
||||
next unless ($version == 1 || $version == 2);
|
||||
|
||||
my $context = shift @data;
|
||||
my $SID = shift @data;
|
||||
my $cipher_algorithm = shift @data;
|
||||
my $hash_algorithm = shift @data;
|
||||
my $iteration = shift @data;
|
||||
my $iv = shift @data;
|
||||
my $cipher_len = shift @data;
|
||||
my $cipher = shift @data;
|
||||
|
||||
next unless (length ($cipher) == $cipher_len);
|
||||
|
||||
if ($version == 1)
|
||||
{
|
||||
next unless ($cipher_len == 208);
|
||||
}
|
||||
elsif ($version == 2)
|
||||
{
|
||||
next unless ($cipher_len == 288);
|
||||
}
|
||||
|
||||
my $dpapimk_salt = substr ($hash, length ('$DPAPImk$'));
|
||||
|
||||
my $word_packed = pack_if_HEX_notation ($word);
|
||||
|
||||
my $new_hash = module_generate_hash ($word_packed, undef, $dpapimk_salt, $cipher);
|
||||
|
||||
return ($new_hash, $word);
|
||||
}
|
||||
|
||||
1;
|
Loading…
Reference in New Issue
Block a user