From b2709edea7451ceb4a7d2f2a02ba2c2a0d180c7c Mon Sep 17 00:00:00 2001 From: magnum Date: Mon, 9 Aug 2021 14:04:07 +0200 Subject: [PATCH] Office formats: Support Office 2007 documents using 256-bit keys. Before this, the CPU format bailed out with an error while the OpenCL format unfortunately just produced false negatives. Closes #4780 --- doc/NEWS | 5 ++++ run/opencl/office_kernel.cl | 39 +++++++++++++++++++----- src/office_fmt_plug.c | 57 +++++++++++++++++------------------- src/opencl_office_fmt_plug.c | 7 +++-- 4 files changed, 69 insertions(+), 39 deletions(-) diff --git a/doc/NEWS b/doc/NEWS index 9e12fe1874d..e004760e12f 100644 --- a/doc/NEWS +++ b/doc/NEWS @@ -214,6 +214,11 @@ Major changes from 1.9.0-jumbo-1 (May 2019) in this bleeding-edge version: - Add BestCrypt Volume Encryption V4 format. [Jean-Christophe Delaunay; 2021] +- Added missing code to the Office formats for cracking Office 2007 documents + with a 256-bit key (apparently very uncommon). The CPU format would bail + with a message (hence the issue reported) but unfortunately the OpenCL format + just produced false negatives until now. [magnum; 2021] + Major changes from 1.8.0-jumbo-1 (December 2014) to 1.9.0-jumbo-1 (May 2019): diff --git a/run/opencl/office_kernel.cl b/run/opencl/office_kernel.cl index db892046231..9595bd965a2 100644 --- a/run/opencl/office_kernel.cl +++ b/run/opencl/office_kernel.cl @@ -1,7 +1,7 @@ /* * Office 2007, 2010 and 2013 formats * - * Copyright 2012-2017, magnum + * Copyright 2012-2021, magnum * This software is hereby released to the general public under * the following terms: Redistribution and use in source and binary * forms, with or without modification, are permitted. @@ -122,6 +122,7 @@ void HashLoop0710(__global ms_office_state *state) __kernel void Final2007(__global ms_office_state *state, __global ms_office_out *out, + __constant ms_office_salt *salt, __constant ms_office_blob *blob) { uint i; @@ -130,6 +131,10 @@ void Final2007(__global ms_office_state *state, uchar c[20]; uint w[20/4]; } output; + union { + uchar c[40]; + uint w[40/4]; + } X3; uint gid = get_global_id(0); union { unsigned char c[16]; @@ -178,19 +183,39 @@ void Final2007(__global ms_office_state *state, W[i] = output.w[i] ^ 0x36363636; for (i = 5; i < 16; i++) W[i] = 0x36363636; - sha1_single(uint, W, output.w); + sha1_single(uint, W, X3.w); /* sha1_final (last block was 64 bytes) */ W[0] = 0x80000000; for (i = 1; i < 6; i++) W[i] = 0; W[15] = 64 << 3; - sha1_block_160Z(uint, W, output.w); + sha1_block_160Z(uint, W, X3.w); - /* Endian-swap to output (we only use 16 bytes) */ - for (i = 0; i < 4; i++) - output.w[i] = SWAP32(output.w[i]); + /* Endian-swap to output */ + for (i = 0; i < 5; i++) + X3.w[i] = SWAP32(X3.w[i]); /* This is X1 in MS-OFFCRYPTO */ + + if (salt->verifierHashSize < salt->keySize / 8) { + uint *X2 = &X3.w[5]; + + for (i = 0; i < 5; i++) + W[i] = output.w[i] ^ 0x5c5c5c5c; + for (i = 5; i < 16; i++) + W[i] = 0x5c5c5c5c; + sha1_single(uint, W, X2); + /* sha1_final (last block was 64 bytes) */ + W[0] = 0x80000000; + for (i = 1; i < 6; i++) + W[i] = 0; + W[15] = 64 << 3; + sha1_block_160Z(uint, W, X2); + + /* Endian-swap to output */ + for (i = 0; i < 5; i++) + X2[i] = SWAP32(X2[i]); + } - AES_set_decrypt_key(output.c, 128, &akey); + AES_set_decrypt_key(X3.c, salt->keySize, &akey); AES_ecb_decrypt(blob->encryptedVerifier, decryptedVerifier.c, 16, &akey); AES_ecb_decrypt(blob->encryptedVerifierHash, decryptedVerifierHash.c, 16, &akey); diff --git a/src/office_fmt_plug.c b/src/office_fmt_plug.c index 6bd9a1cbb63..ec32c6eb6ec 100644 --- a/src/office_fmt_plug.c +++ b/src/office_fmt_plug.c @@ -1,7 +1,7 @@ /* * Office 2007 cracker patch for JtR. This software is * Copyright (c) 2012 Dhiru Kholia . - * Copyright (c) 2012-2019 magnum + * Copyright (c) 2012-2021 magnum * and is hereby released to the general public under the following terms: * Redistribution and use in source and binary forms, with or without * modification, are permitted. @@ -83,6 +83,8 @@ static struct fmt_tests office_tests[] = { {"$office$*2007*20*128*16*fbd4cc5dab9b8e341778ddcde9eca740*46bef371486919d4bffe7280110f913d*b51af42e6696baa097a7109cebc3d0ff7cc8b1d8", "myhovercraftisfullofeels"}, /* 2007-Default_myhovercraftisfullofeels_.xltx */ {"$office$*2007*20*128*16*fbd4cc5dab9b8e341778ddcde9eca740*1addb6823689aca9ce400be8f9e55fc9*e06bf10aaf3a4049ffa49dd91cf9e7bbf88a1b3b", "myhovercraftisfullofeels"}, + /* Github issue #4780 (256-bit key length) */ + {"$office$*2007*20*256*16*3e94c22e93f35e14162402da444dec28*7057eb00b1e0e1cce5c85ba0727e9686*ff4f3a5a9e872c364e6d83f07af904ce518b53e6", "12Qwaszx"}, /* 2010-Default_myhovercraftisfullofeels_.docx */ {"$office$*2010*100000*128*16*213aefcafd9f9188e78c1936cbb05a44*d5fc7691292ab6daf7903b9a8f8c8441*46bfac7fb87cd43bd0ab54ebc21c120df5fab7e6f11375e79ee044e663641d5e", "myhovercraftisfullofeels"}, /* 2010-Default_myhovercraftisfullofeels_.dotx */ @@ -122,7 +124,7 @@ static UTF16 (*saved_key)[PLAINTEXT_LENGTH + 1]; static int *saved_len; static int *cracked; -static uint8_t (*encryptionKey)[20]; +static uint8_t (*encryptionKey)[40]; static uint8_t (*verifierKeys1)[64]; static uint8_t (*verifierKeys512)[128]; @@ -161,15 +163,16 @@ static void done(void) MEM_FREE(verifierKeys512); } -static uint8_t *DeriveKey(uint8_t *hashValue, uint8_t *X1) +static uint8_t *DeriveKey(uint8_t *hashValue, uint8_t *X3) { int i; uint8_t derivedKey[64]; SHA_CTX ctx; + int cbRequiredKeyLength = cur_salt->keySize / 8; + uint8_t *X1 = X3; + uint8_t *X2 = &X3[20]; - // This is step 4a in 2.3.4.7 of MS_OFFCRYPT version 1.0 - // and is required even though the notes say it should be - // used only when the encryption algorithm key > hash length. + // See 2.3.4.7 of MS-OFFCRYPTO for (i = 0; i < 64; i++) derivedKey[i] = (i < 20 ? 0x36 ^ hashValue[i] : 0x36); @@ -177,23 +180,20 @@ static uint8_t *DeriveKey(uint8_t *hashValue, uint8_t *X1) SHA1_Update(&ctx, derivedKey, 64); SHA1_Final(X1, &ctx); - if (cur_salt->verifierHashSize > cur_salt->keySize / 8) - return X1; + if (cur_salt->verifierHashSize < cbRequiredKeyLength) { + for (i = 0; i < 64; i++) + derivedKey[i] = (i < 20 ? 0x5C ^ hashValue[i] : 0x5C); - /* TODO: finish up this function */ - //for (i = 0; i < 64; i++) - // derivedKey[i] = (i < 30 ? 0x5C ^ hashValue[i] : 0x5C); - - fprintf(stderr, "\n\n*** ERROR: DeriveKey() entered Limbo.\n"); - fprintf(stderr, "Please report to john-dev mailing list.\n"); - error(); + SHA1_Init(&ctx); + SHA1_Update(&ctx, derivedKey, 64); + SHA1_Final(X2, &ctx); + } - return NULL; + return X3; } #ifdef SIMD_COEF_32 -static void GeneratePasswordHashUsingSHA1(int idx, - uint8_t final[SHA1_LOOP_CNT][20]) +static void GeneratePasswordHashUsingSHA1(int idx, uint8_t final[SHA1_LOOP_CNT][40]) { uint8_t hashBuf[20]; /* @@ -201,7 +201,7 @@ static void GeneratePasswordHashUsingSHA1(int idx, * hashBuf = SHA1Hash(salt, password); * create input buffer for SHA1 from salt and unicode version of password */ - uint8_t X1[20]; + uint8_t X3[40]; SHA_CTX ctx; uint8_t _IBuf[64*SHA1_LOOP_CNT + MEM_ALIGN_CACHE], *keys; uint32_t *keys32; @@ -270,12 +270,11 @@ static void GeneratePasswordHashUsingSHA1(int idx, /* Now convert back into a 'flat' value, which is a flat array. */ for (i = 0; i < SHA1_LOOP_CNT; i++) - memcpy(final[i], DeriveKey(&keys[20 * i], X1), cur_salt->keySize / 8); + memcpy(final[i], DeriveKey(&keys[20 * i], X3), cur_salt->keySize / 8); } #else // for non SIMD, SHA1_LOOP_CNT is 1 -static void GeneratePasswordHashUsingSHA1(int idx, - uint8_t final[SHA1_LOOP_CNT][20]) +static void GeneratePasswordHashUsingSHA1(int idx, uint8_t final[SHA1_LOOP_CNT][40]) { uint8_t hashBuf[20], *key; UTF16 *passwordBuf = saved_key[idx]; @@ -286,7 +285,7 @@ static void GeneratePasswordHashUsingSHA1(int idx, * create input buffer for SHA1 from salt and unicode version of password */ uint32_t inputBuf[(0x14 + 0x04 + 4) / sizeof(int)]; - uint8_t X1[20]; + uint8_t X3[40]; int i; SHA_CTX ctx; @@ -327,11 +326,10 @@ static void GeneratePasswordHashUsingSHA1(int idx, SHA1_Update(&ctx, &inputBuf[1], 0x14 + 0x04); SHA1_Final(hashBuf, &ctx); - key = DeriveKey(hashBuf, X1); + key = DeriveKey(hashBuf, X3); /* - * Should handle the case of longer key lengths as shown in 2.3.4.9 - * Grab the key length bytes of the final hash as the encrypytion key + * Grab the key length bytes of the final hash as the encryption key */ memcpy(final[0], key, cur_salt->keySize / 8); } @@ -477,8 +475,7 @@ static void GenerateAgileEncryptionKey(int idx, #endif #ifdef SIMD_COEF_64 -static void GenerateAgileEncryptionKey512(int idx, - uint8_t hashBuf[SHA512_LOOP_CNT][128]) +static void GenerateAgileEncryptionKey512(int idx, uint8_t hashBuf[SHA512_LOOP_CNT][128]) { uint8_t tmpBuf[64], *keys; uint32_t i, j, k; @@ -646,11 +643,11 @@ static int PasswordVerifier(ms_office_binary_blob *blob, uint8_t *key) SHA_CTX ctx; uint8_t checkHash[20]; - AES_set_decrypt_key(key, 128, &akey); + AES_set_decrypt_key(key, cur_salt->keySize, &akey); AES_ecb_encrypt(blob->encryptedVerifier, decryptedVerifier, &akey, AES_DECRYPT); - AES_set_decrypt_key(key, 128, &akey); + AES_set_decrypt_key(key, cur_salt->keySize, &akey); AES_ecb_encrypt(blob->encryptedVerifierHash, decryptedVerifierHash, &akey, AES_DECRYPT); diff --git a/src/opencl_office_fmt_plug.c b/src/opencl_office_fmt_plug.c index 5c303cfc0f2..1267fc210c0 100644 --- a/src/opencl_office_fmt_plug.c +++ b/src/opencl_office_fmt_plug.c @@ -2,7 +2,7 @@ * MS Office >= 2007 cracker for JtR. OpenCL support by magnum. * * This software is Copyright (c) 2012, Dhiru Kholia - * and Copyright (c) 2012-2017, magnum + * and Copyright (c) 2012-2021, magnum * and it is hereby released to the general public under the following terms: * Redistribution and use in source and binary forms, with or without * modification, are permitted. @@ -49,6 +49,8 @@ static struct fmt_tests tests[] = { {"$office$*2010*100000*128*16*213aefcafd9f9188e78c1936cbb05a44*d5fc7691292ab6daf7903b9a8f8c8441*46bfac7fb87cd43bd0ab54ebc21c120df5fab7e6f11375e79ee044e663641d5e", "myhovercraftisfullofeels"}, /* 2013-openwall.pptx */ {"$office$*2013*100000*256*16*9b12805dd6d56f46d07315153f3ecb9c*c5a4a167b51faa6629f6a4caf0b4baa8*87397e0659b2a6fff90291f8e6d6d0018b750b792fefed77001edbafba7769cd", "openwall"}, + /* Github issue #4780 (256-bit key length) */ + {"$office$*2007*20*256*16*3e94c22e93f35e14162402da444dec28*7057eb00b1e0e1cce5c85ba0727e9686*ff4f3a5a9e872c364e6d83f07af904ce518b53e6", "12Qwaszx"}, #if DEBUG /* 2007-Default_myhovercraftisfullofeels_.dotx */ {"$office$*2007*20*128*16*56ea65016fbb4eac14a6770b2dbe7e99*8cf82ce1b62f01fd3b2c7666a2313302*21443fe938177e648c482da72212a8848c2e9c80", "myhovercraftisfullofeels"}, @@ -205,7 +207,8 @@ static void create_clobj(size_t gws, struct fmt_main *self) HANDLE_CLERROR(clSetKernelArg(Final2007, 0, sizeof(cl_mem), (void*)&cl_state), "Error setting argument 0"); HANDLE_CLERROR(clSetKernelArg(Final2007, 1, sizeof(cl_mem), (void*)&cl_out), "Error setting argument 1"); - HANDLE_CLERROR(clSetKernelArg(Final2007, 2, sizeof(cl_mem), (void*)&cl_blob), "Error setting argument 2"); + HANDLE_CLERROR(clSetKernelArg(Final2007, 2, sizeof(cl_mem), (void*)&cl_salt), "Error setting argument 2"); + HANDLE_CLERROR(clSetKernelArg(Final2007, 3, sizeof(cl_mem), (void*)&cl_blob), "Error setting argument 3"); HANDLE_CLERROR(clSetKernelArg(Generate2010key, 0, sizeof(cl_mem), (void*)&cl_state), "Error setting argument 0"); HANDLE_CLERROR(clSetKernelArg(Generate2010key, 1, sizeof(cl_mem), (void*)&cl_out), "Error setting argument 1");