diff -rubN john-1.7.2/src/hmacmd5.c john-1.7.2-jmk-netlmv2/src/hmacmd5.c --- john-1.7.2/src/hmacmd5.c 1969-12-31 18:00:00.000000000 -0600 +++ john-1.7.2-jmk-netlmv2/src/hmacmd5.c 2008-03-20 16:17:44.000000000 -0500 @@ -0,0 +1,140 @@ +/* + Unix SMB/CIFS implementation. + HMAC MD5 code for use in NTLMv2 + Copyright (C) Luke Kenneth Casson Leighton 1996-2000 + Copyright (C) Andrew Tridgell 1992-2000 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* taken direct from rfc2104 implementation and modified for suitable use + * for ntlmv2. + */ + +#include + +#include "md5.h" +#include "hmacmd5.h" + +#define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x)) + +/*********************************************************************** + the rfc 2104 version of hmac_md5 initialisation. +***********************************************************************/ + +void hmac_md5_init_rfc2104(const unsigned char *key, int key_len, HMACMD5Context *ctx) +{ + int i; + unsigned char tk[16]; + + /* if key is longer than 64 bytes reset it to key=MD5(key) */ + if (key_len > 64) { + MD5_CTX tctx; + + MD5_Init(&tctx); + MD5_Update(&tctx, (void *)key, key_len); + MD5_Final(tk, &tctx); + + key = tk; + key_len = 16; + } + + /* start out by storing key in pads */ + ZERO_STRUCT(ctx->k_ipad); + ZERO_STRUCT(ctx->k_opad); + memcpy( ctx->k_ipad, key, key_len); + memcpy( ctx->k_opad, key, key_len); + + /* XOR key with ipad and opad values */ + for (i=0; i<64; i++) { + ctx->k_ipad[i] ^= 0x36; + ctx->k_opad[i] ^= 0x5c; + } + + MD5_Init(&ctx->ctx); + MD5_Update(&ctx->ctx, ctx->k_ipad, 64); +} + +/*********************************************************************** + the microsoft version of hmac_md5 initialisation. +***********************************************************************/ + +void hmac_md5_init_limK_to_64(const unsigned char* key, int key_len, + HMACMD5Context *ctx) +{ + int i; + + /* if key is longer than 64 bytes truncate it */ + if (key_len > 64) { + key_len = 64; + } + + /* start out by storing key in pads */ + ZERO_STRUCT(ctx->k_ipad); + ZERO_STRUCT(ctx->k_opad); + memcpy( ctx->k_ipad, key, key_len); + memcpy( ctx->k_opad, key, key_len); + + /* XOR key with ipad and opad values */ + for (i=0; i<64; i++) { + ctx->k_ipad[i] ^= 0x36; + ctx->k_opad[i] ^= 0x5c; + } + + MD5_Init(&ctx->ctx); + MD5_Update(&ctx->ctx, ctx->k_ipad, 64); +} + +/*********************************************************************** + update hmac_md5 "inner" buffer +***********************************************************************/ + +void hmac_md5_update(const unsigned char *text, int text_len, HMACMD5Context *ctx) +{ + MD5_Update(&ctx->ctx, (void *)text, text_len); /* then text of datagram */ +} + +/*********************************************************************** + finish off hmac_md5 "inner" buffer and generate outer one. +***********************************************************************/ +void hmac_md5_final(unsigned char *digest, HMACMD5Context *ctx) + +{ + MD5_CTX ctx_o; + + MD5_Final(digest, &ctx->ctx); + + MD5_Init(&ctx_o); + MD5_Update(&ctx_o, ctx->k_opad, 64); + MD5_Update(&ctx_o, digest, 16); + MD5_Final(digest, &ctx_o); +} + +/*********************************************************** + single function to calculate an HMAC MD5 digest from data. + use the microsoft hmacmd5 init method because the key is 16 bytes. +************************************************************/ + +void hmac_md5( unsigned char key[16], unsigned char *data, int data_len, unsigned char *digest) +{ + HMACMD5Context ctx; + hmac_md5_init_limK_to_64(key, 16, &ctx); + if (data_len != 0) + { + hmac_md5_update(data, data_len, &ctx); + } + hmac_md5_final(digest, &ctx); +} + diff -rubN john-1.7.2/src/hmacmd5.h john-1.7.2-jmk-netlmv2/src/hmacmd5.h --- john-1.7.2/src/hmacmd5.h 1969-12-31 18:00:00.000000000 -0600 +++ john-1.7.2-jmk-netlmv2/src/hmacmd5.h 2008-03-20 15:47:54.000000000 -0500 @@ -0,0 +1,30 @@ +/* + Unix SMB/CIFS implementation. + Interface header: Scheduler service + Copyright (C) Luke Kenneth Casson Leighton 1996-1999 + Copyright (C) Andrew Tridgell 1992-1999 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _HMAC_MD5_H + +typedef struct { + MD5_CTX ctx; + unsigned char k_ipad[65]; + unsigned char k_opad[65]; +} HMACMD5Context; + +#endif /* _HMAC_MD5_H */ diff -rubN john-1.7.2/src/john.c john-1.7.2-jmk-netlmv2/src/john.c --- john-1.7.2/src/john.c 2008-03-20 15:45:08.000000000 -0500 +++ john-1.7.2-jmk-netlmv2/src/john.c 2008-03-20 15:48:26.000000000 -0500 @@ -54,6 +54,7 @@ extern struct fmt_main fmt_DOMINOSEC; extern struct fmt_main fmt_NETLM; extern struct fmt_main fmt_NETNTLM; +extern struct fmt_main fmt_NETLMv2; extern struct fmt_main fmt_mssql; extern struct fmt_main fmt_mssql05; @@ -102,6 +103,7 @@ john_register_one(&fmt_DOMINOSEC); john_register_one(&fmt_NETLM); john_register_one(&fmt_NETNTLM); + john_register_one(&fmt_NETLMv2); john_register_one(&fmt_mssql); john_register_one(&fmt_mssql05); diff -rubN john-1.7.2/src/loader.c john-1.7.2-jmk-netlmv2/src/loader.c --- john-1.7.2/src/loader.c 2008-03-20 15:45:08.000000000 -0500 +++ john-1.7.2-jmk-netlmv2/src/loader.c 2008-03-20 15:50:43.000000000 -0500 @@ -230,6 +230,28 @@ if (source) sprintf(source, "%s:%s", uid, line); } + else if (options.format && (strncmp(options.format, "netlmv2", 7)==0)) { + char *srv_challenge = ldr_get_field(&line); + char *netlmv2 = ldr_get_field(&line); + char *cli_challenge = ldr_get_field(&line); + char *identity = NULL; + int i; + + identity = (char *) mem_alloc(strlen(*login) + strlen(uid) + 1); + memset(identity, 0, strlen(*login) + strlen(uid) + 1); + + sprintf(identity, *login, strlen(*login)); + sprintf(identity + strlen(*login), uid, strlen(uid)); + + /* Upper-Case Username and Domain */ + for(i=0; i= 'a') && (identity[i] <= 'z')) identity[i] ^= 0x20; + + tmp = (char *) mem_alloc(9 + strlen(identity) + 1 + strlen(srv_challenge) + 1 + strlen(netlmv2) + 1 + strlen(cli_challenge) + 1); + memset(tmp, 0, 9 + strlen(identity) + 1 + strlen(srv_challenge) + 1 + strlen(netlmv2) + 1 + strlen(cli_challenge) + 1); + sprintf(tmp, "$NETLMv2$%s$%s$%s$%s", identity, srv_challenge, netlmv2, cli_challenge); + *ciphertext = tmp; + } else if (options.format && ((strncmp(options.format, "netlm", 5)==0) || (strncmp(options.format, "netntlm", 7)==0))) { char *netlm = ldr_get_field(&line); diff -rubN john-1.7.2/src/Makefile john-1.7.2-jmk-netlmv2/src/Makefile --- john-1.7.2/src/Makefile 2008-03-20 15:45:08.000000000 -0500 +++ john-1.7.2-jmk-netlmv2/src/Makefile 2008-03-20 16:10:00.000000000 -0500 @@ -41,6 +41,7 @@ rawMD5go_fmt.o \ PO_fmt.o \ md5.o \ + hmacmd5.o \ IPB2_fmt.o \ rawSHA1_fmt.o \ saltSHA1_fmt.o \ @@ -50,6 +51,7 @@ mscash_fmt.o \ NETLM_fmt.o \ NETNTLM_fmt.o \ + NETLMv2_fmt.o \ mssql_fmt.o \ mssql05_fmt.o \ batch.o bench.o charset.o common.o compiler.o config.o cracker.o \ diff -rubN john-1.7.2/src/NETLMv2_fmt.c john-1.7.2-jmk-netlmv2/src/NETLMv2_fmt.c --- john-1.7.2/src/NETLMv2_fmt.c 1969-12-31 18:00:00.000000000 -0600 +++ john-1.7.2-jmk-netlmv2/src/NETLMv2_fmt.c 2008-03-20 15:47:47.000000000 -0500 @@ -0,0 +1,361 @@ +/* + * NETLMv2_fmt.c -- LMv2 Challenge/Response + * + * Written by JoMo-Kun in 2008 + * and placed in the public domain. + * + * This algorithm is designed for performing brute-force cracking of the LMv2 + * challenge/response sets exchanged during network-based authentication + * attempts [1]. The captured challenge/response set from these attempts + * should be stored using the following format: + * + * USERNAME::DOMAIN:SERVER CHALLENGE:LMv2 RESPONSE:CLIENT CHALLENGE + * + * For example: + * Administrator::WORKGROUP:1122334455667788:6759A5A7EFB25452911DE7DE8296A0D8:F503236B200A5B3A + * + * It should be noted that a LMv2 authentication response is not same as a LM + * password hash, which can be extracted using tools such as FgDump [2]. In + * fact, a NTLM hash and not a LM hash is used within the LMv2 algorithm. LMv2 + * challenge/response authentication typically takes place when the GPO + * "Network Security: LAN Manager authentication level" is configured to a setting + * that enforces the use of NTLMv2, such as "Send NTLMv2 response only\refuse + * LM & NTLM." + * + * LMv2 responses can be gathered via normal network capture or via tools which + * perform layer 2 attacks, such as Ettercap [3] and Cain [4]. The responses can + * also be harvested using a modified Samba service [5] in conjunction with + * some trickery to convince the user to connect to it. I leave what that + * trickery may actually be as an exercise for the reader (HINT: Karma, NMB + * broadcasts, IE, Outlook, social engineering, ...). + * + * [1] http://davenport.sourceforge.net/ntlm.html#theLmv2Response + * [2] http://www.foofus.net/fizzgig/fgdump/ + * [3] http://ettercap.sourceforge.net/ + * [4] http://www.oxid.it/cain.html + * [5] http://www.foofus.net/jmk/smbchallenge.html + * + */ + +#include +#include + +#include "misc.h" +#include "common.h" +#include "formats.h" + +#include "md5.h" +#include "hmacmd5.h" + +#ifndef uchar +#define uchar unsigned char +#endif + +#define FORMAT_LABEL "netlmv2" +#define FORMAT_NAME "LMv2 C/R MD4 DES" +#define ALGORITHM_NAME "netlmv2" +#define BENCHMARK_COMMENT "" +#define BENCHMARK_LENGTH 0 +#define PLAINTEXT_LENGTH 54 /* lmcons.h - PWLEN (256) ? 127 ? */ +#define USERNAME_LENGTH 20 /* lmcons.h - UNLEN (256) / LM20_UNLEN (20) */ +#define DOMAIN_LENGTH 15 /* lmcons.h - CNLEN / DNLEN */ +#define BINARY_SIZE 16 +#define CHALLENGE_LENGTH 32 +#define SALT_SIZE 16 + USERNAME_LENGTH + DOMAIN_LENGTH +#define CIPHERTEXT_LENGTH 32 +#define TOTAL_LENGTH 12 + USERNAME_LENGTH + DOMAIN_LENGTH + CHALLENGE_LENGTH + CIPHERTEXT_LENGTH +#define MIN_KEYS_PER_CRYPT 1 +#define MAX_KEYS_PER_CRYPT 1 + +static struct fmt_tests tests[] = { + {"$NETLMv2$ADMINISTRATORFOODOM$1122334455667788$6F64C5C1E35F68DD80388C0F00F34406$F0F3FF27037AA69F", "1337adminPASS"}, + {"$NETLMv2$USER1$1122334455667788$B1D163EA5881504F3963DC50FCDC26C1$EB4D9E8138149E20", "foobar"}, + {"$NETLMv2$ATEST$1122334455667788$83B59F1536D3321DBF1FAEC14ADB1675$A1E7281FE8C10E53", "SomeFancyP4$$w0rdHere"}, + {NULL} +}; + +uchar saved_plain[PLAINTEXT_LENGTH + 1]; +uchar challenge[SALT_SIZE + 1]; +uchar output[BINARY_SIZE + 1]; + +extern void E_md4hash(uchar *passwd, uchar *p16); +extern void hmac_md5_init_limK_to_64(const unsigned char*, int, HMACMD5Context*); +extern void hmac_md5_update(const unsigned char*, int, HMACMD5Context*); +extern void hmac_md5_final(unsigned char*, HMACMD5Context*); + +#if !defined(uint16) && !defined(HAVE_UINT16_FROM_RPC_RPC_H) +#if (SIZEOF_SHORT == 4) +#define uint16 __ERROR___CANNOT_DETERMINE_TYPE_FOR_INT16; +#else /* SIZEOF_SHORT != 4 */ +#define uint16 unsigned short +#endif /* SIZEOF_SHORT != 4 */ +#endif + +#if !defined(int16) && !defined(HAVE_INT16_FROM_RPC_RPC_H) +#if (SIZEOF_SHORT == 4) +#define int16 __ERROR___CANNOT_DETERMINE_TYPE_FOR_INT16; +#else /* SIZEOF_SHORT != 4 */ +#define int16 short +#endif /* SIZEOF_SHORT != 4 */ +#endif + +#include "byteorder.h" + +/* Routines for Windows NT MD4 Hash functions. */ +static int lmv2_wcslen(int16 *str) +{ + int len = 0; + while(*str++ != 0) + len++; + return len; +} + +/* + * Convert a string into an NT UNICODE string. + * Note that regardless of processor type + * this must be in intel (little-endian) + * format. + */ +int lmv2_mbstowcs(int16 *dst, uchar *src, int len) +{ + int i; + int16 val; + + for(i = 0; i < len; i++) { + val = *src; + SSVAL(dst,0,val); + dst++; + src++; + if(val == 0) + break; + } + return i; +} + +static int netlmv2_valid(char *ciphertext) +{ + char *pos, *pos2; + + if (ciphertext == NULL) return 0; + else if (strncmp(ciphertext, "$NETLMv2$", 9)!=0) return 0; + + pos = &ciphertext[9]; + + /* Validate Username and Domain Length */ + for (pos2 = pos; strncmp(pos2, "$", 1) != 0; pos2++) + if ( (*pos2 < 0x20) || (*pos2 > 0x7E) ) + return 0; + + if ( !(*pos2 && (pos2 - pos <= USERNAME_LENGTH + DOMAIN_LENGTH)) ) + return 0; + + /* Validate Server Challenge Length */ + pos2++; pos = pos2; + for (; strncmp(pos2, "$", 1) != 0; pos2++) + if (atoi16[ARCH_INDEX(*pos2)] == 0x7F) + return 0; + + if ( !(*pos2 && (pos2 - pos == CHALLENGE_LENGTH / 2)) ) + return 0; + + /* Validate LMv2 Response Length */ + pos2++; pos = pos2; + for (; strncmp(pos2, "$", 1) != 0; pos2++) + if (atoi16[ARCH_INDEX(*pos2)] == 0x7F) + return 0; + + if ( !(*pos2 && (pos2 - pos == CIPHERTEXT_LENGTH)) ) + return 0; + + /* Validate Client Challenge Length */ + pos2++; pos = pos2; + for (; atoi16[ARCH_INDEX(*pos2)] != 0x7F; pos2++); + if (pos2 - pos != CHALLENGE_LENGTH / 2) + return 0; + + return 1; +} + +static char *netlmv2_split(char *ciphertext, int index) +{ + static char out[TOTAL_LENGTH + 1]; + char *pos = NULL; + int identity_length = 0; + + /* Calculate identity length */ + for (pos = ciphertext + 9; strncmp(pos, "$", 1) != 0; pos++); + identity_length = pos - (ciphertext + 9); + + memset(out, 0, TOTAL_LENGTH + 1); + memcpy(&out, ciphertext, strlen(ciphertext)); + strlwr(&out[10 + identity_length]); /* Exclude: $NETLMv2$USERDOMAIN$ */ + + return out; +} + +static void *netlmv2_get_binary(char *ciphertext) +{ + static uchar binary[BINARY_SIZE]; + char *pos = NULL; + int i, identity_length; + + for (pos = ciphertext + 9; strncmp(pos, "$", 1) != 0; pos++); + identity_length = pos - (ciphertext + 9); + + ciphertext += 9 + identity_length + 1 + CHALLENGE_LENGTH / 2 + 1; + for (i=0; i