Added hash-mode: Kerberos 5, etype 18, DB

This commit is contained in:
Gabriele Gristina 2022-03-05 12:59:38 +01:00
parent 580afa985d
commit 0d282bbfb3
3 changed files with 871 additions and 0 deletions

424
OpenCL/m28900-pure.cl Normal file
View File

@ -0,0 +1,424 @@
/**
* Author......: See docs/credits.txt
* License.....: MIT
*/
#define NEW_SIMD_CODE
#ifdef KERNEL_STATIC
#include M2S(INCLUDE_PATH/inc_vendor.h)
#include M2S(INCLUDE_PATH/inc_types.h)
#include M2S(INCLUDE_PATH/inc_platform.cl)
#include M2S(INCLUDE_PATH/inc_common.cl)
#include M2S(INCLUDE_PATH/inc_simd.cl)
#include M2S(INCLUDE_PATH/inc_hash_sha1.cl)
#include M2S(INCLUDE_PATH/inc_cipher_aes.cl)
#endif
#define COMPARE_S M2S(INCLUDE_PATH/inc_comp_single.cl)
#define COMPARE_M M2S(INCLUDE_PATH/inc_comp_multi.cl)
typedef struct krb5db_18
{
u32 user[128];
u32 domain[128];
u32 account_info[512];
u32 account_info_len;
} krb5db_18_t;
typedef struct krb5db_18_tmp
{
u32 ipad[5];
u32 opad[5];
u32 dgst[16];
u32 out[16];
} krb5db_18_tmp_t;
DECLSPEC void aes256_encrypt_cbc (PRIVATE_AS const u32 *aes_ks, PRIVATE_AS u32 *aes_iv, PRIVATE_AS const u32 *in, PRIVATE_AS u32 *out, SHM_TYPE u32 *s_te0, SHM_TYPE u32 *s_te1, SHM_TYPE u32 *s_te2, SHM_TYPE u32 *s_te3, SHM_TYPE u32 *s_te4)
{
u32 data[4];
data[0] = hc_swap32_S (in[0]);
data[1] = hc_swap32_S (in[1]);
data[2] = hc_swap32_S (in[2]);
data[3] = hc_swap32_S (in[3]);
data[0] ^= aes_iv[0];
data[1] ^= aes_iv[1];
data[2] ^= aes_iv[2];
data[3] ^= aes_iv[3];
aes256_encrypt (aes_ks, data, out, s_te0, s_te1, s_te2, s_te3, s_te4);
aes_iv[0] = out[0];
aes_iv[1] = out[1];
aes_iv[2] = out[2];
aes_iv[3] = out[3];
out[0] = hc_swap32_S (out[0]);
out[1] = hc_swap32_S (out[1]);
out[2] = hc_swap32_S (out[2]);
out[3] = hc_swap32_S (out[3]);
}
DECLSPEC void aes256_decrypt_cbc (PRIVATE_AS const u32 *ks1, PRIVATE_AS const u32 *in, PRIVATE_AS u32 *out, PRIVATE_AS u32 *essiv, SHM_TYPE u32 *s_td0, SHM_TYPE u32 *s_td1, SHM_TYPE u32 *s_td2, SHM_TYPE u32 *s_td3, SHM_TYPE u32 *s_td4)
{
aes256_decrypt (ks1, in, out, s_td0, s_td1, s_td2, s_td3, s_td4);
out[0] ^= essiv[0];
out[1] ^= essiv[1];
out[2] ^= essiv[2];
out[3] ^= essiv[3];
essiv[0] = in[0];
essiv[1] = in[1];
essiv[2] = in[2];
essiv[3] = in[3];
}
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];
digest[1] = ipad[1];
digest[2] = ipad[2];
digest[3] = ipad[3];
digest[4] = ipad[4];
sha1_transform_vector (w0, w1, w2, w3, digest);
w0[0] = digest[0];
w0[1] = digest[1];
w0[2] = digest[2];
w0[3] = digest[3];
w1[0] = digest[4];
w1[1] = 0x80000000;
w1[2] = 0;
w1[3] = 0;
w2[0] = 0;
w2[1] = 0;
w2[2] = 0;
w2[3] = 0;
w3[0] = 0;
w3[1] = 0;
w3[2] = 0;
w3[3] = (64 + 20) * 8;
digest[0] = opad[0];
digest[1] = opad[1];
digest[2] = opad[2];
digest[3] = opad[3];
digest[4] = opad[4];
sha1_transform_vector (w0, w1, w2, w3, digest);
}
KERNEL_FQ void m28900_init (KERN_ATTR_TMPS_ESALT (krb5db_18_tmp_t, krb5db_18_t))
{
/**
* base
*/
const u64 gid = get_global_id (0);
if (gid >= GID_CNT) return;
/**
* main
*/
/* initialize hmac-sha1 for pbkdf2(password, account, 4096, account_len) */
sha1_hmac_ctx_t sha1_hmac_ctx;
sha1_hmac_init_global_swap (&sha1_hmac_ctx, pws[gid].i, pws[gid].pw_len);
tmps[gid].ipad[0] = sha1_hmac_ctx.ipad.h[0];
tmps[gid].ipad[1] = sha1_hmac_ctx.ipad.h[1];
tmps[gid].ipad[2] = sha1_hmac_ctx.ipad.h[2];
tmps[gid].ipad[3] = sha1_hmac_ctx.ipad.h[3];
tmps[gid].ipad[4] = sha1_hmac_ctx.ipad.h[4];
tmps[gid].opad[0] = sha1_hmac_ctx.opad.h[0];
tmps[gid].opad[1] = sha1_hmac_ctx.opad.h[1];
tmps[gid].opad[2] = sha1_hmac_ctx.opad.h[2];
tmps[gid].opad[3] = sha1_hmac_ctx.opad.h[3];
tmps[gid].opad[4] = sha1_hmac_ctx.opad.h[4];
sha1_hmac_update_global_swap (&sha1_hmac_ctx, esalt_bufs[DIGESTS_OFFSET_HOST].account_info, esalt_bufs[DIGESTS_OFFSET_HOST].account_info_len);
for (u32 i = 0, j = 1; i < 8; i += 5, j += 1)
{
sha1_hmac_ctx_t sha1_hmac_ctx2 = sha1_hmac_ctx;
u32 w0[4];
u32 w1[4];
u32 w2[4];
u32 w3[4];
w0[0] = j;
w0[1] = 0;
w0[2] = 0;
w0[3] = 0;
w1[0] = 0;
w1[1] = 0;
w1[2] = 0;
w1[3] = 0;
w2[0] = 0;
w2[1] = 0;
w2[2] = 0;
w2[3] = 0;
w3[0] = 0;
w3[1] = 0;
w3[2] = 0;
w3[3] = 0;
sha1_hmac_update_64 (&sha1_hmac_ctx2, w0, w1, w2, w3, 4);
sha1_hmac_final (&sha1_hmac_ctx2);
tmps[gid].dgst[i + 0] = sha1_hmac_ctx2.opad.h[0];
tmps[gid].dgst[i + 1] = sha1_hmac_ctx2.opad.h[1];
tmps[gid].dgst[i + 2] = sha1_hmac_ctx2.opad.h[2];
tmps[gid].dgst[i + 3] = sha1_hmac_ctx2.opad.h[3];
tmps[gid].dgst[i + 4] = sha1_hmac_ctx2.opad.h[4];
tmps[gid].out[i + 0] = tmps[gid].dgst[i + 0];
tmps[gid].out[i + 1] = tmps[gid].dgst[i + 1];
tmps[gid].out[i + 2] = tmps[gid].dgst[i + 2];
tmps[gid].out[i + 3] = tmps[gid].dgst[i + 3];
tmps[gid].out[i + 4] = tmps[gid].dgst[i + 4];
}
}
KERNEL_FQ void m28900_loop (KERN_ATTR_TMPS_ESALT (krb5db_18_tmp_t, krb5db_18_t))
{
/**
* base
*/
const u64 gid = get_global_id (0);
if ((gid * VECT_SIZE) >= GID_CNT) return;
u32x ipad[5];
u32x opad[5];
ipad[0] = packv (tmps, ipad, gid, 0);
ipad[1] = packv (tmps, ipad, gid, 1);
ipad[2] = packv (tmps, ipad, gid, 2);
ipad[3] = packv (tmps, ipad, gid, 3);
ipad[4] = packv (tmps, ipad, gid, 4);
opad[0] = packv (tmps, opad, gid, 0);
opad[1] = packv (tmps, opad, gid, 1);
opad[2] = packv (tmps, opad, gid, 2);
opad[3] = packv (tmps, opad, gid, 3);
opad[4] = packv (tmps, opad, gid, 4);
for (u32 i = 0; i < 8; i += 5)
{
u32x dgst[5];
u32x out[5];
dgst[0] = packv (tmps, dgst, gid, i + 0);
dgst[1] = packv (tmps, dgst, gid, i + 1);
dgst[2] = packv (tmps, dgst, gid, i + 2);
dgst[3] = packv (tmps, dgst, gid, i + 3);
dgst[4] = packv (tmps, dgst, gid, i + 4);
out[0] = packv (tmps, out, gid, i + 0);
out[1] = packv (tmps, out, gid, i + 1);
out[2] = packv (tmps, out, gid, i + 2);
out[3] = packv (tmps, out, gid, i + 3);
out[4] = packv (tmps, out, gid, i + 4);
for (u32 j = 0; j < LOOP_CNT; j++)
{
u32x w0[4];
u32x w1[4];
u32x w2[4];
u32x w3[4];
w0[0] = dgst[0];
w0[1] = dgst[1];
w0[2] = dgst[2];
w0[3] = dgst[3];
w1[0] = dgst[4];
w1[1] = 0x80000000;
w1[2] = 0;
w1[3] = 0;
w2[0] = 0;
w2[1] = 0;
w2[2] = 0;
w2[3] = 0;
w3[0] = 0;
w3[1] = 0;
w3[2] = 0;
w3[3] = (64 + 20) * 8;
hmac_sha1_run_V (w0, w1, w2, w3, ipad, opad, dgst);
out[0] ^= dgst[0];
out[1] ^= dgst[1];
out[2] ^= dgst[2];
out[3] ^= dgst[3];
out[4] ^= dgst[4];
}
unpackv (tmps, dgst, gid, i + 0, dgst[0]);
unpackv (tmps, dgst, gid, i + 1, dgst[1]);
unpackv (tmps, dgst, gid, i + 2, dgst[2]);
unpackv (tmps, dgst, gid, i + 3, dgst[3]);
unpackv (tmps, dgst, gid, i + 4, dgst[4]);
unpackv (tmps, out, gid, i + 0, out[0]);
unpackv (tmps, out, gid, i + 1, out[1]);
unpackv (tmps, out, gid, i + 2, out[2]);
unpackv (tmps, out, gid, i + 3, out[3]);
unpackv (tmps, out, gid, i + 4, out[4]);
}
}
KERNEL_FQ void m28900_comp (KERN_ATTR_TMPS_ESALT (krb5db_18_tmp_t, krb5db_18_t))
{
/**
* base
*/
const u64 gid = get_global_id (0);
const u64 lid = get_local_id (0);
const u64 lsz = get_local_size (0);
/**
* aes shared
*/
#ifdef REAL_SHM
LOCAL_VK u32 s_td0[256];
LOCAL_VK u32 s_td1[256];
LOCAL_VK u32 s_td2[256];
LOCAL_VK u32 s_td3[256];
LOCAL_VK u32 s_td4[256];
LOCAL_VK u32 s_te0[256];
LOCAL_VK u32 s_te1[256];
LOCAL_VK u32 s_te2[256];
LOCAL_VK u32 s_te3[256];
LOCAL_VK u32 s_te4[256];
for (u32 i = lid; i < 256; i += lsz)
{
s_td0[i] = td0[i];
s_td1[i] = td1[i];
s_td2[i] = td2[i];
s_td3[i] = td3[i];
s_td4[i] = td4[i];
s_te0[i] = te0[i];
s_te1[i] = te1[i];
s_te2[i] = te2[i];
s_te3[i] = te3[i];
s_te4[i] = te4[i];
}
SYNC_THREADS ();
#else
CONSTANT_AS u32a *s_td0 = td0;
CONSTANT_AS u32a *s_td1 = td1;
CONSTANT_AS u32a *s_td2 = td2;
CONSTANT_AS u32a *s_td3 = td3;
CONSTANT_AS u32a *s_td4 = td4;
CONSTANT_AS u32a *s_te0 = te0;
CONSTANT_AS u32a *s_te1 = te1;
CONSTANT_AS u32a *s_te2 = te2;
CONSTANT_AS u32a *s_te3 = te3;
CONSTANT_AS u32a *s_te4 = te4;
#endif
if (gid >= GID_CNT) return;
/*
at this point, the output ('seed') will be used to generate AES keys:
key_bytes = derive(seed, 'kerberos'.encode(), seedsize)
'key_bytes' will be the AES key used to generate 'ke' and 'ki'
'ke' will be the AES key to decrypt the ticket
'ki' will be the key to compute the final HMAC
*/
u32 nfolded[4];
// we can precompute _nfold('kerberos', 16)
nfolded[0] = 0x6b657262;
nfolded[1] = 0x65726f73;
nfolded[2] = 0x7b9b5b2b;
nfolded[3] = 0x93132b93;
// then aes_cbc encrypt this nfolded value with 'seed' as key along with a null IV
u32 aes_key[8];
aes_key[0] = hc_swap32_S (tmps[gid].out[0]);
aes_key[1] = hc_swap32_S (tmps[gid].out[1]);
aes_key[2] = hc_swap32_S (tmps[gid].out[2]);
aes_key[3] = hc_swap32_S (tmps[gid].out[3]);
aes_key[4] = hc_swap32_S (tmps[gid].out[4]);
aes_key[5] = hc_swap32_S (tmps[gid].out[5]);
aes_key[6] = hc_swap32_S (tmps[gid].out[6]);
aes_key[7] = hc_swap32_S (tmps[gid].out[7]);
u32 aes_iv[4];
aes_iv[0] = 0;
aes_iv[1] = 0;
aes_iv[2] = 0;
aes_iv[3] = 0;
u32 aes_ks[60];
aes256_set_encrypt_key (aes_ks, aes_key, s_te0, s_te1, s_te2, s_te3);
u32 key_bytes[8];
u32 out[4];
aes256_encrypt_cbc (aes_ks, aes_iv, nfolded, out, s_te0, s_te1, s_te2, s_te3, s_te4);
key_bytes[0] = out[0];
key_bytes[1] = out[1];
key_bytes[2] = out[2];
key_bytes[3] = out[3];
/*
aes_iv[0] = 0;
aes_iv[1] = 0;
aes_iv[2] = 0;
aes_iv[3] = 0;
aes256_encrypt_cbc (aes_ks, aes_iv, out, out, s_te0, s_te1, s_te2, s_te3, s_te4);
key_bytes[4] = out[0];
key_bytes[5] = out[1];
key_bytes[6] = out[2];
key_bytes[7] = out[3];
*/
const u32 r0 = key_bytes[0];
const u32 r1 = key_bytes[1];
const u32 r2 = key_bytes[2];
const u32 r3 = key_bytes[3];
#define il_pos 0
#ifdef KERNEL_STATIC
#include COMPARE_M
#endif
}

342
src/modules/module_28900.c Normal file
View File

@ -0,0 +1,342 @@
/**
* 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"
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_8;
static const u32 HASH_CATEGORY = HASH_CATEGORY_NETWORK_PROTOCOL;
static const char *HASH_NAME = "Kerberos 5, etype 18, DB";
static const u64 KERN_TYPE = 28900;
static const u32 OPTI_TYPE = OPTI_TYPE_ZERO_BYTE
| OPTI_TYPE_NOT_ITERATED
| OPTI_TYPE_SLOW_HASH_SIMD_LOOP;
static const u64 OPTS_TYPE = OPTS_TYPE_PT_GENERATE_LE;
static const u32 SALT_TYPE = SALT_TYPE_EMBEDDED;
static const char *ST_PASS = "password";
static const char *ST_HASH = "$krb5db$18$test$TEST.LOCAL$487addf1717899f2ee45c4b67e159d54adec46d086f339b88fd7deaa25d49a65";
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 krb5db_18
{
u32 user[128];
u32 domain[128];
u32 account_info[512];
u32 account_info_len;
} krb5db_18_t;
typedef struct krb5db_18_tmp
{
u32 ipad[5];
u32 opad[5];
u32 dgst[16];
u32 out[16];
} krb5db_18_tmp_t;
static const char *SIGNATURE_KRB5DB = "$krb5db$18$";
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)
{
// AMD Radeon Pro W5700X Compute Engine; 1.2 (Apr 22 2021 21:54:44); 11.3.1; 20E241
if ((device_param->opencl_platform_vendor_id == VENDOR_ID_APPLE) && (device_param->opencl_device_type & CL_DEVICE_TYPE_GPU))
{
if (device_param->is_metal == 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 (krb5db_18_tmp_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 (krb5db_18_t);
return esalt_size;
}
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;
krb5db_18_t *krb5db = (krb5db_18_t *) esalt_buf;
hc_token_t token;
token.signatures_cnt = 1;
token.signatures_buf[0] = SIGNATURE_KRB5DB;
token.len[0] = 11;
token.attr[0] = TOKEN_ATTR_FIXED_LENGTH
| TOKEN_ATTR_VERIFY_SIGNATURE;
/**
* $krb5db$18$user$realm$hash
* $krb5db$18$user$realm$*spn*$hash
*/
// assume no signature found
if (line_len < 11) return (PARSER_SALT_LENGTH);
char *spn_info_start = strchr ((const char *) line_buf + 11 + 1, '*');
int is_spn_provided = 0;
// assume $krb5db$17$user$realm$checksum$edata2
if (spn_info_start == NULL)
{
token.token_cnt = 4;
token.sep[1] = '$';
token.len_min[1] = 1;
token.len_max[1] = 512;
token.attr[1] = TOKEN_ATTR_VERIFY_LENGTH;
token.sep[2] = '$';
token.len_min[2] = 1;
token.len_max[2] = 512;
token.attr[2] = TOKEN_ATTR_VERIFY_LENGTH;
token.sep[3] = '$';
token.len_min[3] = 64;
token.len_max[3] = 64;
token.attr[3] = TOKEN_ATTR_VERIFY_LENGTH
| TOKEN_ATTR_VERIFY_HEX;
}
// assume $krb5db$18$user$realm$*spn*$hash
else
{
char *spn_info_stop = strchr ((const char *) spn_info_start + 1, '*');
if (spn_info_stop == NULL) return (PARSER_SEPARATOR_UNMATCHED);
spn_info_stop++; // we want the * $char included
spn_info_stop++; // we want the $ char included
const int spn_info_len = spn_info_stop - spn_info_start;
token.token_cnt = 5;
token.sep[1] = '$';
token.len_min[1] = 1;
token.len_max[1] = 512;
token.attr[1] = TOKEN_ATTR_VERIFY_LENGTH;
token.sep[2] = '$';
token.len_min[2] = 1;
token.len_max[2] = 512;
token.attr[2] = TOKEN_ATTR_VERIFY_LENGTH;
token.len[3] = spn_info_len;
token.attr[3] = TOKEN_ATTR_FIXED_LENGTH;
token.sep[4] = '$';
token.len_min[4] = 64;
token.len_max[4] = 64;
token.attr[4] = TOKEN_ATTR_VERIFY_LENGTH
| TOKEN_ATTR_VERIFY_HEX;
is_spn_provided = 1;
}
const int rc_tokenizer = input_tokenizer ((const u8 *) line_buf, line_len, &token);
if (rc_tokenizer != PARSER_OK) return (rc_tokenizer);
const u8 *user_pos;
const u8 *domain_pos;
const u8 *checksum_pos;
int user_len;
int domain_len;
int account_info_len;
user_pos = token.buf[1];
user_len = token.len[1];
memcpy (krb5db->user, user_pos, user_len);
domain_pos = token.buf[2];
domain_len = token.len[2];
memcpy (krb5db->domain, domain_pos, domain_len);
checksum_pos = token.buf[3 + is_spn_provided];
account_info_len = token.len[2] + token.len[1];
u8 *account_info_ptr = (u8 *) krb5db->account_info;
// domain must be uppercase
u8 domain[128];
memcpy (domain, domain_pos, domain_len);
uppercase (domain, domain_len);
memcpy (account_info_ptr, domain, domain_len);
memcpy (account_info_ptr + domain_len, user_pos, user_len);
krb5db->account_info_len = account_info_len;
// salt
salt->salt_buf[0] = krb5db->account_info[0];
salt->salt_buf[1] = krb5db->account_info[1];
salt->salt_buf[2] = krb5db->account_info[2];
salt->salt_buf[3] = krb5db->account_info[3];
salt->salt_len = 16;
salt->salt_iter = 4096 - 1;
// digest
digest[0] = byte_swap_32 (hex_to_u32 (checksum_pos + 0));
digest[1] = byte_swap_32 (hex_to_u32 (checksum_pos + 8));
digest[2] = byte_swap_32 (hex_to_u32 (checksum_pos + 16));
digest[3] = byte_swap_32 (hex_to_u32 (checksum_pos + 24));
digest[4] = byte_swap_32 (hex_to_u32 (checksum_pos + 32));
digest[5] = byte_swap_32 (hex_to_u32 (checksum_pos + 40));
digest[6] = byte_swap_32 (hex_to_u32 (checksum_pos + 48));
digest[7] = byte_swap_32 (hex_to_u32 (checksum_pos + 56));
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 u32 *digest = (const u32 *) digest_buf;
const krb5db_18_t *krb5db = (const krb5db_18_t *) esalt_buf;
const int line_len = snprintf (line_buf, line_size, "%s%s$%s$%08x%08x%08x%08x%08x%08x%08x%08x",
SIGNATURE_KRB5DB,
(char *) krb5db->user,
(char *) krb5db->domain,
digest[0],
digest[1],
digest[2],
digest[3],
digest[4],
digest[5],
digest[6],
digest[7]);
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_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_DEFAULT;
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;
}

View File

@ -0,0 +1,105 @@
#!/usr/bin/env perl
##
## Author......: See docs/credits.txt
## License.....: MIT
##
use strict;
use warnings;
use Digest::SHA qw (hmac_sha1);
use Crypt::Mode::CBC;
use Crypt::PBKDF2;
sub byte2hex
{
my $input = shift;
return unpack ("H*", $input);
}
sub hex2byte
{
my $input = shift;
return pack ("H*", $input);
}
sub pad
{
my $n = shift;
my $size = shift;
return (~$n + 1) & ($size - 1);
}
sub module_constraints { [[0, 256], [16, 16], [-1, -1], [-1, -1], [-1, -1]] }
sub module_generate_hash
{
my $word = shift;
my $salt = shift;
my $user = shift // "user";
my $realm = shift // "realm";
my $mysalt = uc $realm;
$mysalt = $mysalt . $user;
# first we generate the 'seed'
my $iter = 4096;
my $pbkdf2 = Crypt::PBKDF2->new
(
hash_class => 'HMACSHA1',
iterations => $iter,
output_len => 32
);
my $b_seed = $pbkdf2->PBKDF2 ($mysalt, $word);
# we can precompute this
my $b_kerberos_nfolded = hex2byte ('6b65726265726f737b9b5b2b93132b93');
my $b_iv = hex2byte ('0' x 32);
# 'key_bytes' will be the AES key used to generate 'ki' (for final hmac-sha1)
# and 'ke' (AES key to decrypt/encrypt the ticket)
my $cbc = Crypt::Mode::CBC->new ('AES', 0);
my $b_key_bytes = $cbc->encrypt ($b_kerberos_nfolded, $b_seed, $b_iv);
$b_key_bytes = $b_key_bytes . $cbc->encrypt ($b_key_bytes, $b_seed, $b_iv);
my $tmp_hash = sprintf ('$krb5db$18$%s$%s$%s', $user, $realm, unpack ("H*", $b_key_bytes));
return $tmp_hash;
}
sub module_verify_hash
{
my $line = shift;
my ($hash, $word) = split (':', $line);
return unless defined $hash;
return unless defined $word;
my @data = split ('\$', $hash);
return unless scalar @data == 5;
shift @data;
my $signature = shift @data;
my $algorithm = shift @data;
my $user = shift @data;
my $realm = shift @data;
return unless ($signature eq "krb5db");
return unless ($algorithm eq "18");
my $word_packed = pack_if_HEX_notation ($word);
my $new_hash = module_generate_hash ($word_packed, undef, $user, $realm);
return ($new_hash, $word);
}
1;