mirror of
https://github.com/hashcat/hashcat.git
synced 2024-12-23 07:08:19 +00:00
Merge pull request #3208 from matrix/dpapimk_context_3
Added hash-modes: DPAPI masterkey file v1/v2 (context 3)
This commit is contained in:
commit
d1634eab84
@ -19,6 +19,17 @@
|
||||
#define COMPARE_S M2S(INCLUDE_PATH/inc_comp_single.cl)
|
||||
#define COMPARE_M M2S(INCLUDE_PATH/inc_comp_multi.cl)
|
||||
|
||||
typedef struct dpapimk_tmp_v1
|
||||
{
|
||||
u32 ipad[5];
|
||||
u32 opad[5];
|
||||
u32 dgst[10];
|
||||
u32 out[10];
|
||||
|
||||
u32 userKey[5];
|
||||
|
||||
} dpapimk_tmp_v1_t;
|
||||
|
||||
typedef struct dpapimk
|
||||
{
|
||||
u32 context;
|
||||
@ -39,17 +50,6 @@ typedef struct dpapimk
|
||||
|
||||
} dpapimk_t;
|
||||
|
||||
typedef struct dpapimk_tmp_v1
|
||||
{
|
||||
u32 ipad[5];
|
||||
u32 opad[5];
|
||||
u32 dgst[10];
|
||||
u32 out[10];
|
||||
|
||||
u32 userKey[5];
|
||||
|
||||
} dpapimk_tmp_v1_t;
|
||||
|
||||
DECLSPEC void hmac_sha1_run_V (PRIVATE_AS u32x *w0, PRIVATE_AS u32x *w1, PRIVATE_AS u32x *w2, PRIVATE_AS u32x *w3, PRIVATE_AS u32x *ipad, PRIVATE_AS u32x *opad, PRIVATE_AS u32x *digest)
|
||||
{
|
||||
digest[0] = ipad[0];
|
||||
|
1000
OpenCL/m15310-pure.cl
Normal file
1000
OpenCL/m15310-pure.cl
Normal file
File diff suppressed because it is too large
Load Diff
1189
OpenCL/m15910-pure.cl
Normal file
1189
OpenCL/m15910-pure.cl
Normal file
File diff suppressed because it is too large
Load Diff
@ -11,6 +11,8 @@
|
||||
- Added hash-mode: bcrypt(sha512($pass)) / bcryptsha512
|
||||
- Added hash-mode: Kerberos 5, etype 17, DB
|
||||
- Added hash-mode: Kerberos 5, etype 18, DB
|
||||
- Added hash-mode: DPAPI masterkey file v1 (context 3)
|
||||
- Added hash-mode: DPAPI masterkey file v2 (context 3)
|
||||
|
||||
##
|
||||
## Features
|
||||
|
@ -18,7 +18,7 @@ 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 v1";
|
||||
static const char *HASH_NAME = "DPAPI masterkey file v1 (context 1 and 2)";
|
||||
static const u64 KERN_TYPE = 15300;
|
||||
static const u32 OPTI_TYPE = OPTI_TYPE_ZERO_BYTE
|
||||
| OPTI_TYPE_SLOW_HASH_SIMD_LOOP;
|
||||
@ -224,6 +224,8 @@ int module_hash_decode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSE
|
||||
|
||||
dpapimk->context = hc_strtoul ((const char *) context_pos, NULL, 10);
|
||||
|
||||
if (dpapimk->context != 1 && dpapimk->context != 2) return (PARSER_SALT_LENGTH);
|
||||
|
||||
for (u32 i = 0; i < dpapimk->contents_len / 8; i++)
|
||||
{
|
||||
dpapimk->contents[i] = hex_to_u32 ((const u8 *) &contents_pos[i * 8]);
|
||||
|
480
src/modules/module_15310.c
Normal file
480
src/modules/module_15310.c
Normal file
@ -0,0 +1,480 @@
|
||||
/**
|
||||
* 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 v1 (context 3)";
|
||||
static const u64 KERN_TYPE = 15310;
|
||||
static const u32 OPTI_TYPE = OPTI_TYPE_ZERO_BYTE
|
||||
| OPTI_TYPE_SLOW_HASH_SIMD_LOOP
|
||||
| OPTI_TYPE_SLOW_HASH_SIMD_LOOP2;
|
||||
static const u64 OPTS_TYPE = OPTS_TYPE_PT_GENERATE_LE
|
||||
| OPTS_TYPE_INIT2
|
||||
| OPTS_TYPE_LOOP2;
|
||||
static const u32 SALT_TYPE = SALT_TYPE_EMBEDDED;
|
||||
static const char *ST_PASS = "hashcat";
|
||||
static const char *ST_HASH = "$DPAPImk$1*3*S-15-21-407415836-404165111-436049749-1915*des3*sha1*14825*3e86e7d8437c4d5582ff668a83632cb2*208*96ad763b59e67c9f5c3d925e42bbe28a1412b919d1dc4abf03b2bed4c5c244056c14931d94d441117529b7171dfd6ebbe6eecf5d958b65574c293778fbadb892351cc59d5c65d65d2fcda73f5b056548a4a5550106d03d0c39d3cca7e5cdc0d521f48ac9e51cecc5";
|
||||
|
||||
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; }
|
||||
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_v1
|
||||
{
|
||||
u32 ipad[5];
|
||||
u32 opad[5];
|
||||
u32 dgst[10];
|
||||
u32 out[10];
|
||||
|
||||
u32 userKey[5];
|
||||
|
||||
} dpapimk_tmp_v1_t;
|
||||
|
||||
static const char *SIGNATURE_DPAPIMK = "$DPAPImk$";
|
||||
|
||||
salt_t *module_benchmark_salt (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra)
|
||||
{
|
||||
salt_t *salt = (salt_t *) hcmalloc (sizeof (salt_t));
|
||||
|
||||
salt->salt_iter = 10000 - 1;
|
||||
salt->salt_iter2 = 13450 - 1;
|
||||
salt->salt_len = 16;
|
||||
|
||||
return salt;
|
||||
}
|
||||
|
||||
bool module_unstable_warning (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra, MAYBE_UNUSED const hc_device_param_t *device_param)
|
||||
{
|
||||
// amdgpu-pro-20.50-1234664-ubuntu-20.04 (legacy)
|
||||
// test_1619943729/test_report.log:! unhandled return code 255, cmdline : cat test_1619943729/15300_passwords.txt | ./hashcat --quiet --potfile-disable --runtime 400 --hwmon-disable -O -D 2 --backend-vector-width 1 -a 0 -m 15300 test_1619943729/15300_hashes.txt
|
||||
// test_1619955152/test_report.log:! unhandled return code 255, cmdline : cat test_1619955152/15300_passwords.txt | ./hashcat --quiet --potfile-disable --runtime 400 --hwmon-disable -D 2 --backend-vector-width 4 -a 0 -m 15300 test_1619955152/15300_hashes.txt
|
||||
if ((device_param->opencl_device_vendor_id == VENDOR_ID_AMD) && (device_param->has_vperm == false))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
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_v1_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 void *hook_salt_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;
|
||||
|
||||
memset (dpapimk, 0, sizeof (dpapimk_t));
|
||||
|
||||
hc_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);
|
||||
|
||||
if (dpapimk->context != 3) return (PARSER_SALT_LENGTH);
|
||||
|
||||
for (u32 i = 0; i < dpapimk->contents_len / 8; 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];
|
||||
}
|
||||
|
||||
dpapimk->SID_len = SID_len * 2;
|
||||
|
||||
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 = 10000 - 1;
|
||||
salt->salt_iter2 = 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 void *hook_salt_buf, MAYBE_UNUSED const hashinfo_t *hash_info, char *line_buf, MAYBE_UNUSED const int line_size)
|
||||
{
|
||||
const dpapimk_t *dpapimk = (const dpapimk_t *) esalt_buf;
|
||||
|
||||
u32 version = 1;
|
||||
u32 context = dpapimk->context;
|
||||
u32 rounds = salt->salt_iter2 + 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 = NULL;
|
||||
|
||||
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];
|
||||
|
||||
u32 u32_contents[36];
|
||||
u8 contents[288 + 1];
|
||||
|
||||
memset (u32_iv, 0, sizeof (u32_iv));
|
||||
memset (iv, 0, sizeof (iv));
|
||||
|
||||
memset (u32_contents, 0, sizeof (u32_contents));
|
||||
memset (contents, 0, sizeof (contents));
|
||||
|
||||
// convert back SID
|
||||
|
||||
SID_tmp = (u8 *) hcmalloc ((SID_len + 1) * sizeof (u8));
|
||||
|
||||
for (u32 i = 0; i < (SID_len / 4); 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;
|
||||
|
||||
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[208] = 0;
|
||||
|
||||
if (contents_len == 208)
|
||||
{
|
||||
memcpy (cipher_algorithm, "des3", strlen ("des3"));
|
||||
|
||||
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",
|
||||
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_benchmark_salt;
|
||||
module_ctx->module_build_plain_postprocess = MODULE_DEFAULT;
|
||||
module_ctx->module_deep_comp_kernel = MODULE_DEFAULT;
|
||||
module_ctx->module_deprecated_notice = 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_extra_tmp_size = MODULE_DEFAULT;
|
||||
module_ctx->module_extra_tuningdb_block = 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_decode_postprocess = MODULE_DEFAULT;
|
||||
module_ctx->module_hash_decode_potfile = 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_potfile = 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_hashes_count_min = MODULE_DEFAULT;
|
||||
module_ctx->module_hashes_count_max = MODULE_DEFAULT;
|
||||
module_ctx->module_hlfmt_disable = MODULE_DEFAULT;
|
||||
module_ctx->module_hook_extra_param_size = MODULE_DEFAULT;
|
||||
module_ctx->module_hook_extra_param_init = MODULE_DEFAULT;
|
||||
module_ctx->module_hook_extra_param_term = 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_jit_cache_disable = 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_kern_type_dynamic = MODULE_DEFAULT;
|
||||
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_custom_check = 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_unstable_warning;
|
||||
module_ctx->module_warmup_disable = MODULE_DEFAULT;
|
||||
}
|
@ -18,7 +18,7 @@ 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 char *HASH_NAME = "DPAPI masterkey file v2 (context 1 and 2)";
|
||||
static const u64 KERN_TYPE = 15900;
|
||||
static const u32 OPTI_TYPE = OPTI_TYPE_ZERO_BYTE
|
||||
| OPTI_TYPE_USES_BITS_64
|
||||
@ -212,6 +212,8 @@ int module_hash_decode (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSE
|
||||
|
||||
dpapimk->context = hc_strtoul ((const char *) context_pos, NULL, 10);
|
||||
|
||||
if (dpapimk->context != 1 && dpapimk->context != 2) return (PARSER_SALT_LENGTH);
|
||||
|
||||
for (u32 i = 0; i < dpapimk->contents_len / 8; i++)
|
||||
{
|
||||
dpapimk->contents[i] = hex_to_u32 ((const u8 *) &contents_pos[i * 8]);
|
||||
|
473
src/modules/module_15910.c
Normal file
473
src/modules/module_15910.c
Normal file
@ -0,0 +1,473 @@
|
||||
/**
|
||||
* 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 (context 3)";
|
||||
static const u64 KERN_TYPE = 15910;
|
||||
static const u32 OPTI_TYPE = OPTI_TYPE_ZERO_BYTE
|
||||
| OPTI_TYPE_USES_BITS_64
|
||||
| OPTI_TYPE_SLOW_HASH_SIMD_LOOP
|
||||
| OPTI_TYPE_SLOW_HASH_SIMD_LOOP2;
|
||||
static const u64 OPTS_TYPE = OPTS_TYPE_PT_GENERATE_LE
|
||||
| OPTS_TYPE_INIT2
|
||||
| OPTS_TYPE_LOOP2;
|
||||
static const u32 SALT_TYPE = SALT_TYPE_EMBEDDED;
|
||||
static const char *ST_PASS = "hashcat";
|
||||
static const char *ST_HASH = "$DPAPImk$2*3*S-15-21-464497560-472124119-475628788-1088*aes256*sha512*13450*685165fdb6d0627a15100215ec331ed8*288*7e1ea6f7ec3c2111f2a3903c73aefe66e524d8b241dc1482d0bd07cc1f3ccdadd8cebd4263b3b7c2496da48f40d2eb4890513e6624aeefbe6bbc6ea73f2f71fecf9cc5fef3891a2e697a4415ba7a069642069c142335d53cc750d42a4f4d2b0592956b4a0e57a5d5b1bfd27f0a8eac9d0d5fc5c5e5e23af18ce1a8eff442ed335e5db3bad6e89146f71aa9351e132fd9";
|
||||
|
||||
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; }
|
||||
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
|
||||
{
|
||||
u32 ipad[8];
|
||||
u32 opad[8];
|
||||
u32 dgst[32];
|
||||
u32 out[32];
|
||||
|
||||
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$";
|
||||
|
||||
salt_t *module_benchmark_salt (MAYBE_UNUSED const hashconfig_t *hashconfig, MAYBE_UNUSED const user_options_t *user_options, MAYBE_UNUSED const user_options_extra_t *user_options_extra)
|
||||
{
|
||||
salt_t *salt = (salt_t *) hcmalloc (sizeof (salt_t));
|
||||
|
||||
salt->salt_iter = 10000 - 1;
|
||||
salt->salt_iter2 = 13450 - 1;
|
||||
salt->salt_len = 16;
|
||||
|
||||
return salt;
|
||||
}
|
||||
|
||||
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 void *hook_salt_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;
|
||||
|
||||
memset (dpapimk, 0, sizeof (dpapimk_t));
|
||||
|
||||
hc_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);
|
||||
|
||||
if (dpapimk->context != 3) return (PARSER_SALT_LENGTH);
|
||||
|
||||
for (u32 i = 0; i < dpapimk->contents_len / 8; 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];
|
||||
}
|
||||
|
||||
dpapimk->SID_len = SID_len * 2;
|
||||
|
||||
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 = 10000 - 1;
|
||||
salt->salt_iter2 = 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 void *hook_salt_buf, MAYBE_UNUSED const hashinfo_t *hash_info, char *line_buf, MAYBE_UNUSED const int line_size)
|
||||
{
|
||||
const dpapimk_t *dpapimk = (const dpapimk_t *) esalt_buf;
|
||||
|
||||
u32 version = 2;
|
||||
u32 context = dpapimk->context;
|
||||
u32 rounds = salt->salt_iter2 + 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 = NULL;
|
||||
|
||||
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];
|
||||
|
||||
u32 u32_contents[36];
|
||||
u8 contents[288 + 1];
|
||||
|
||||
memset (u32_iv, 0, sizeof (u32_iv));
|
||||
memset (iv, 0, sizeof (iv));
|
||||
|
||||
memset (u32_contents, 0, sizeof (u32_contents));
|
||||
memset (contents, 0, sizeof (contents));
|
||||
|
||||
// convert back SID
|
||||
|
||||
SID_tmp = (u8 *) hcmalloc ((SID_len + 1) * sizeof (u8));
|
||||
|
||||
for (u32 i = 0; i < (SID_len / 4); 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;
|
||||
|
||||
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%u*%u*%s*%s*%s*%u*%s*%u*%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_benchmark_salt;
|
||||
module_ctx->module_build_plain_postprocess = MODULE_DEFAULT;
|
||||
module_ctx->module_deep_comp_kernel = MODULE_DEFAULT;
|
||||
module_ctx->module_deprecated_notice = 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_extra_tmp_size = MODULE_DEFAULT;
|
||||
module_ctx->module_extra_tuningdb_block = 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_decode_postprocess = MODULE_DEFAULT;
|
||||
module_ctx->module_hash_decode_potfile = 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_potfile = 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_hashes_count_min = MODULE_DEFAULT;
|
||||
module_ctx->module_hashes_count_max = MODULE_DEFAULT;
|
||||
module_ctx->module_hlfmt_disable = MODULE_DEFAULT;
|
||||
module_ctx->module_hook_extra_param_size = MODULE_DEFAULT;
|
||||
module_ctx->module_hook_extra_param_init = MODULE_DEFAULT;
|
||||
module_ctx->module_hook_extra_param_term = 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_jit_cache_disable = 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_kern_type_dynamic = MODULE_DEFAULT;
|
||||
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_custom_check = 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;
|
||||
}
|
@ -130,11 +130,11 @@ sub module_generate_hash
|
||||
|
||||
if ($context == 1)
|
||||
{
|
||||
$user_hash = sha1 (encode ("UTF-16LE", $word_buf));
|
||||
$user_hash = sha1 (encode ("UTF-16LE", $word_buf));
|
||||
}
|
||||
elsif ($context == 2)
|
||||
{
|
||||
$user_hash = md4 (encode ("UTF-16LE", $word_buf));
|
||||
$user_hash = md4 (encode ("UTF-16LE", $word_buf));
|
||||
}
|
||||
|
||||
$user_derivationKey = hmac_sha1 (encode ("UTF-16LE", $SID . "\x00"), $user_hash);
|
||||
@ -375,15 +375,15 @@ sub module_verify_hash
|
||||
|
||||
my $signature = $tmp_data[1];
|
||||
|
||||
next unless ($signature eq 'DPAPImk');
|
||||
return unless ($signature eq 'DPAPImk');
|
||||
|
||||
my @data = split ('\*', $tmp_data[2]);
|
||||
|
||||
next unless (scalar @data == 9);
|
||||
return unless (scalar @data == 9);
|
||||
|
||||
my $version = shift @data;
|
||||
|
||||
next unless ($version == 1 || $version == 2);
|
||||
return unless ($version == 1 || $version == 2);
|
||||
|
||||
my $context = shift @data;
|
||||
my $SID = shift @data;
|
||||
@ -394,7 +394,8 @@ sub module_verify_hash
|
||||
my $cipher_len = shift @data;
|
||||
my $cipher = shift @data;
|
||||
|
||||
next unless (length ($cipher) == $cipher_len);
|
||||
return unless ($context == 1 || $context == 2);
|
||||
return unless (length ($cipher) == $cipher_len);
|
||||
|
||||
if ($version == 1)
|
||||
{
|
||||
|
433
tools/test_modules/m15310.pm
Normal file
433
tools/test_modules/m15310.pm
Normal file
@ -0,0 +1,433 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
##
|
||||
## Author......: See docs/credits.txt
|
||||
## License.....: MIT
|
||||
##
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Digest::MD4 qw (md4);
|
||||
use Digest::SHA qw (sha1 hmac_sha1);
|
||||
use Crypt::PBKDF2;
|
||||
use Crypt::ECB;
|
||||
use Encode;
|
||||
|
||||
sub module_constraints { [[0, 256], [-1, -1], [-1, -1], [-1, -1], [-1, -1]] }
|
||||
|
||||
sub get_random_dpapimk_salt
|
||||
{
|
||||
my $version = shift;
|
||||
|
||||
my $salt_buf = "";
|
||||
|
||||
my $context = 3;
|
||||
|
||||
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 (1);
|
||||
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;
|
||||
|
||||
my $SIDenc = encode ("UTF-16LE", $SID);
|
||||
|
||||
my $NTLMhash = md4 (encode ("UTF-16LE", $word_buf));
|
||||
|
||||
my $hasher = Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA2', 256);
|
||||
|
||||
my $pbkdf2_1 = Crypt::PBKDF2->new (
|
||||
hasher => $hasher,
|
||||
iterations => 10000,
|
||||
output_len => 32
|
||||
);
|
||||
|
||||
my $pbkdf2_2 = Crypt::PBKDF2->new (
|
||||
hasher => $hasher,
|
||||
iterations => 1,
|
||||
output_len => 16
|
||||
);
|
||||
|
||||
$user_hash = $pbkdf2_1->PBKDF2 ($SIDenc, $NTLMhash);
|
||||
|
||||
$user_hash = $pbkdf2_2->PBKDF2 ($SIDenc, $user_hash);
|
||||
|
||||
$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 => "none",
|
||||
});
|
||||
|
||||
my $p2 = Crypt::ECB->new ({
|
||||
key => substr ($key, 8, 8),
|
||||
cipher => "DES",
|
||||
literal_key => 1,
|
||||
header => "none",
|
||||
keysize => 8,
|
||||
padding => "none",
|
||||
});
|
||||
|
||||
my $p3 = Crypt::ECB->new ({
|
||||
key => substr ($key, 16, 8),
|
||||
cipher => "DES",
|
||||
literal_key => 1,
|
||||
header => "none",
|
||||
keysize => 8,
|
||||
padding => "none",
|
||||
});
|
||||
|
||||
# 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 => "none",
|
||||
});
|
||||
|
||||
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 => "none",
|
||||
});
|
||||
|
||||
my $p2 = Crypt::ECB->new ({
|
||||
key => substr ($key, 8, 8),
|
||||
cipher => "DES",
|
||||
literal_key => 1,
|
||||
header => "none",
|
||||
keysize => 8,
|
||||
padding => "none",
|
||||
});
|
||||
|
||||
my $p3 = Crypt::ECB->new ({
|
||||
key => substr ($key, 16, 8),
|
||||
cipher => "DES",
|
||||
literal_key => 1,
|
||||
header => "none",
|
||||
keysize => 8,
|
||||
padding => "none",
|
||||
});
|
||||
|
||||
# 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 => "none",
|
||||
});
|
||||
|
||||
$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];
|
||||
|
||||
return unless ($signature eq 'DPAPImk');
|
||||
|
||||
my @data = split ('\*', $tmp_data[2]);
|
||||
|
||||
return unless (scalar @data == 9);
|
||||
|
||||
my $version = shift @data;
|
||||
|
||||
return 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;
|
||||
|
||||
return unless ($context == 3);
|
||||
return unless (length ($cipher) == $cipher_len);
|
||||
|
||||
if ($version == 1)
|
||||
{
|
||||
return unless ($cipher_len == 208);
|
||||
}
|
||||
elsif ($version == 2)
|
||||
{
|
||||
return 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;
|
@ -132,11 +132,11 @@ sub module_generate_hash
|
||||
|
||||
if ($context == 1)
|
||||
{
|
||||
$user_hash = sha1 (encode ("UTF-16LE", $word_buf));
|
||||
$user_hash = sha1 (encode ("UTF-16LE", $word_buf));
|
||||
}
|
||||
elsif ($context == 2)
|
||||
{
|
||||
$user_hash = md4 (encode ("UTF-16LE", $word_buf));
|
||||
$user_hash = md4 (encode ("UTF-16LE", $word_buf));
|
||||
}
|
||||
|
||||
$user_derivationKey = hmac_sha1 (encode ("UTF-16LE", $SID . "\x00"), $user_hash);
|
||||
@ -396,6 +396,7 @@ sub module_verify_hash
|
||||
my $cipher_len = shift @data;
|
||||
my $cipher = shift @data;
|
||||
|
||||
return unless ($context == 1 || $context == 2);
|
||||
return unless (length ($cipher) == $cipher_len);
|
||||
|
||||
if ($version == 1)
|
||||
|
434
tools/test_modules/m15910.pm
Normal file
434
tools/test_modules/m15910.pm
Normal file
@ -0,0 +1,434 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
##
|
||||
## Author......: See docs/credits.txt
|
||||
## License.....: MIT
|
||||
##
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Digest::MD4 qw (md4);
|
||||
use Digest::SHA qw (sha1 hmac_sha1 hmac_sha512);
|
||||
use Crypt::PBKDF2;
|
||||
use Crypt::CBC;
|
||||
use Crypt::ECB;
|
||||
use Encode;
|
||||
|
||||
sub module_constraints { [[0, 256], [-1, -1], [-1, -1], [-1, -1], [-1, -1]] }
|
||||
|
||||
sub get_random_dpapimk_salt
|
||||
{
|
||||
my $version = shift;
|
||||
|
||||
my $salt_buf = "";
|
||||
|
||||
my $context = 3;
|
||||
|
||||
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;
|
||||
|
||||
my $SIDenc = encode ("UTF-16LE", $SID);
|
||||
|
||||
my $NTLMhash = md4 (encode ("UTF-16LE", $word_buf));
|
||||
|
||||
my $hasher = Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA2', 256);
|
||||
|
||||
my $pbkdf2_1 = Crypt::PBKDF2->new (
|
||||
hasher => $hasher,
|
||||
iterations => 10000,
|
||||
output_len => 32
|
||||
);
|
||||
|
||||
my $pbkdf2_2 = Crypt::PBKDF2->new (
|
||||
hasher => $hasher,
|
||||
iterations => 1,
|
||||
output_len => 16
|
||||
);
|
||||
|
||||
$user_hash = $pbkdf2_1->PBKDF2 ($SIDenc, $NTLMhash);
|
||||
|
||||
$user_hash = $pbkdf2_2->PBKDF2 ($SIDenc, $user_hash);
|
||||
|
||||
$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 => "none",
|
||||
});
|
||||
|
||||
my $p2 = Crypt::ECB->new ({
|
||||
key => substr ($key, 8, 8),
|
||||
cipher => "DES",
|
||||
literal_key => 1,
|
||||
header => "none",
|
||||
keysize => 8,
|
||||
padding => "none",
|
||||
});
|
||||
|
||||
my $p3 = Crypt::ECB->new ({
|
||||
key => substr ($key, 16, 8),
|
||||
cipher => "DES",
|
||||
literal_key => 1,
|
||||
header => "none",
|
||||
keysize => 8,
|
||||
padding => "none",
|
||||
});
|
||||
|
||||
# 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 => "none",
|
||||
});
|
||||
|
||||
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 => "none",
|
||||
});
|
||||
|
||||
my $p2 = Crypt::ECB->new ({
|
||||
key => substr ($key, 8, 8),
|
||||
cipher => "DES",
|
||||
literal_key => 1,
|
||||
header => "none",
|
||||
keysize => 8,
|
||||
padding => "none",
|
||||
});
|
||||
|
||||
my $p3 = Crypt::ECB->new ({
|
||||
key => substr ($key, 16, 8),
|
||||
cipher => "DES",
|
||||
literal_key => 1,
|
||||
header => "none",
|
||||
keysize => 8,
|
||||
padding => "none",
|
||||
});
|
||||
|
||||
# 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 => "none",
|
||||
});
|
||||
|
||||
$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];
|
||||
|
||||
return unless ($signature eq 'DPAPImk');
|
||||
|
||||
my @data = split ('\*', $tmp_data[2]);
|
||||
|
||||
return unless (scalar @data == 9);
|
||||
|
||||
my $version = shift @data;
|
||||
|
||||
return 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;
|
||||
|
||||
return unless ($context == 3);
|
||||
return unless (length ($cipher) == $cipher_len);
|
||||
|
||||
if ($version == 1)
|
||||
{
|
||||
return unless ($cipher_len == 208);
|
||||
}
|
||||
elsif ($version == 2)
|
||||
{
|
||||
return 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