diff options
author | sahlberg <sahlberg@f5534014-38df-0310-8fa8-9805f1628bb7> | 2009-10-06 09:13:57 +0000 |
---|---|---|
committer | sahlberg <sahlberg@f5534014-38df-0310-8fa8-9805f1628bb7> | 2009-10-06 09:13:57 +0000 |
commit | 860bdf18ff750a28dccc1b31c6b199dd60889622 (patch) | |
tree | 71c2eccb11b13f45035c18e5b791f395d4d37c0e /epan/dissectors/packet-ntlmssp.c | |
parent | 0a8632d53f31b7ab0e677bb3e3f2898e6daa0093 (diff) |
From Matthieu Patou,
add code to decrypt ntlmv1 and v2 traffic
git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@30355 f5534014-38df-0310-8fa8-9805f1628bb7
Diffstat (limited to 'epan/dissectors/packet-ntlmssp.c')
-rw-r--r-- | epan/dissectors/packet-ntlmssp.c | 1389 |
1 files changed, 1162 insertions, 227 deletions
diff --git a/epan/dissectors/packet-ntlmssp.c b/epan/dissectors/packet-ntlmssp.c index e483b6d81c..1fdc0c6040 100644 --- a/epan/dissectors/packet-ntlmssp.c +++ b/epan/dissectors/packet-ntlmssp.c @@ -1,4 +1,6 @@ /* packet-ntlmssp.c + * Add-on for better NTLM v1/v2 handling + * Copyright 2009 Matthieu Patou <matthieu.patou@matws.net> * Routines for NTLM Secure Service Provider * Devin Heitmueller <dheitmueller@netilla.com> * Copyright 2003, Tim Potter <tpot@samba.org> @@ -27,7 +29,10 @@ #ifdef HAVE_CONFIG_H # include "config.h" #endif - +#ifdef DEBUG_NTLMSSP +#include <stdio.h> +#endif +#include <unistd.h> #include <string.h> #include <ctype.h> @@ -37,14 +42,18 @@ #include "packet-windows-common.h" #include "packet-smb-common.h" #include "packet-frame.h" +#include <epan/asn1.h> +#include "packet-kerberos.h" #include <epan/prefs.h> #include <epan/emem.h> #include <epan/tap.h> #include <epan/crypt/crypt-rc4.h> #include <epan/crypt/crypt-md4.h> +#include <epan/crypt/crypt-md5.h> #include <epan/crypt/crypt-des.h> #include "packet-dcerpc.h" #include "packet-gssapi.h" +#include <epan/crc32.h> #include "packet-ntlmssp.h" @@ -56,6 +65,10 @@ static int ntlmssp_tap = -1; #define NTLMSSP_CHALLENGE 2 #define NTLMSSP_AUTH 3 #define NTLMSSP_UNKNOWN 4 +#define CLIENT_SIGN_TEXT "session key to client-to-server signing key magic constant" +#define CLIENT_SEAL_TEXT "session key to client-to-server sealing key magic constant" +#define SERVER_SIGN_TEXT "session key to server-to-client signing key magic constant" +#define SERVER_SEAL_TEXT "session key to server-to-client sealing key magic constant" static const value_string ntlmssp_message_types[] = { { NTLMSSP_NEGOTIATE, "NTLMSSP_NEGOTIATE" }, @@ -65,6 +78,13 @@ static const value_string ntlmssp_message_types[] = { { 0, NULL } }; +typedef struct _md4_pass { + guint8 md4[16]; +} md4_pass; + +static unsigned char zeros[24] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; +static GHashTable* hash_packet = NULL; + /* * NTLMSSP negotiation flags * Taken from Samba @@ -108,7 +128,7 @@ static const value_string ntlmssp_message_types[] = { #define NTLMSSP_TARGET_TYPE_DOMAIN 0x00010000 #define NTLMSSP_TARGET_TYPE_SERVER 0x00020000 #define NTLMSSP_TARGET_TYPE_SHARE 0x00040000 -#define NTLMSSP_NEGOTIATE_NTLM2 0x00080000 +#define NTLMSSP_NEGOTIATE_EXTENDED_SECURITY 0x00080000 #define NTLMSSP_NEGOTIATE_IDENTIFY 0x00100000 #define NTLMSSP_NEGOTIATE_00200000 0x00200000 #define NTLMSSP_REQUEST_NON_NT_SESSION 0x00400000 @@ -167,7 +187,8 @@ static int hf_ntlmssp_negotiate_domain_strlen = -1; static int hf_ntlmssp_negotiate_domain_maxlen = -1; static int hf_ntlmssp_negotiate_domain_buffer = -1; static int hf_ntlmssp_negotiate_domain = -1; -static int hf_ntlmssp_ntlm_challenge = -1; +static int hf_ntlmssp_ntlm_server_challenge = -1; +static int hf_ntlmssp_ntlm_client_challenge = -1; static int hf_ntlmssp_reserved = -1; static int hf_ntlmssp_challenge_domain = -1; static int hf_ntlmssp_auth_username = -1; @@ -197,7 +218,8 @@ static int hf_ntlmssp_address_list_item_content = -1; static int hf_ntlmssp_verf = -1; static int hf_ntlmssp_verf_vers = -1; static int hf_ntlmssp_verf_body = -1; -static int hf_ntlmssp_verf_unknown1 = -1; +static int hf_ntlmssp_verf_randompad = -1; +static int hf_ntlmssp_verf_hmacmd5 = -1; static int hf_ntlmssp_verf_crc32 = -1; static int hf_ntlmssp_verf_sequence = -1; static int hf_ntlmssp_decrypted_payload = -1; @@ -211,6 +233,7 @@ static int hf_ntlmssp_ntlmv2_response_unknown = -1; static int hf_ntlmssp_ntlmv2_response_name = -1; static int hf_ntlmssp_ntlmv2_response_name_type = -1; static int hf_ntlmssp_ntlmv2_response_name_len = -1; +static int hf_ntlmssp_ntlmv2_response_restriction = -1; static int hf_ntlmssp_ntlmv2_response_client_time = -1; static gint ett_ntlmssp = -1; @@ -234,9 +257,14 @@ typedef struct _ntlmssp_blob { /* Used in the conversation function */ typedef struct _ntlmssp_info { guint32 flags; - rc4_state_struct rc4_state_peer1; - rc4_state_struct rc4_state_peer2; - guint32 peer1_dest_port; + int is_auth_ntlm_v2; + rc4_state_struct rc4_state_client; + rc4_state_struct rc4_state_server; + guint8 sign_key_client[16]; + guint8 sign_key_server[16]; + guint32 server_dest_port; + unsigned char server_challenge[8]; + unsigned char client_challenge[8]; int rc4_state_initialized; ntlmssp_blob ntlm_response; ntlmssp_blob lm_response; @@ -245,19 +273,79 @@ typedef struct _ntlmssp_info { /* If this struct exists in the payload_decrypt, then we have already decrypted it once */ typedef struct _ntlmssp_packet_info { - guint32 flags; guint8 *decrypted_payload; + guint8 payload_len; guint8 verifier[16]; gboolean payload_decrypted; gboolean verifier_decrypted; } ntlmssp_packet_info; - +#ifdef DEBUG_NTLMSSP +static void printnbyte(const guint8* tab,int nb,char* txt,char* txt2) +{ + int i=0; + fprintf(stderr,"%s ",txt); + for(i=0;i<nb;i++) + { + fprintf(stderr,"%02hhX ",*(tab+i)); + } + fprintf(stderr,"%s",txt2); +} +/* + static void printnchar(const guint8* tab,int nb,char* txt,char* txt2) +{ + int i=0; + fprintf(stderr,"%s ",txt); + for(i=0;i<nb;i++) + { + fprintf(stderr,"%c",*(tab+i)); + } + fprintf(stderr,"%s",txt2); +} +*/ +#else +static void printnbyte(const guint8* tab _U_,int nb _U_, char* txt _U_,char* txt2 _U_) +{ +} +#endif /* * GSlist of decrypted payloads. */ static GSList *decrypted_payloads; +int LEBE_Convert(int value) +{ + char a,b,c,d; + /* Get each byte */ + a=value&0x000000FF; + b=(value&0x0000FF00) >> 8; + c=(value&0x00FF0000) >> 16; + d=(value&0xFF000000) >> 24; + return (a << 24) | (b << 16) | (c << 8) | d; +} +/* + Perform a DES encryption with a 16 bit key and 8bit data item. + It's in fact 3 susbsequent call to crypt_des_ecb with a 7 bit key. + Missing bits for the key are replaced by 0; + Returns output in response, which is expected to be 24 bytes. +*/ +static int crypt_des_ecb_long(guint8 *response, + const guint8 *key, + const guint8 *data) +{ + guint8 pw21[21]; /* 21 bytes place for the needed key */ + + memset(pw21, 0, sizeof(pw21)); + memcpy(pw21, key, 16); + + memset(response, 0, 24); + /* crypt_des_ecb(data,key)*/ + crypt_des_ecb(response, data, pw21, 1); + crypt_des_ecb(response + 8, data, pw21 + 7, 1); + crypt_des_ecb(response + 16, data, pw21 + 14, 1); + + return 1; +} /* Generate a challenge response, given an eight byte challenge and either the NT or the Lan Manager password hash (16 bytes). @@ -281,31 +369,254 @@ static int ntlmssp_generate_challenge_response(guint8 *response, return 1; } -/* Create an NTLMSSP version 1 key. + +/* Ultra simple ainsi to unicode converter, will only work for ascii password ...*/ +static void str_to_unicode(const char *nt_password, char *nt_password_unicode) +{ + int password_len = 0; + int i; + + password_len = strlen(nt_password); + if(nt_password_unicode != NULL) + { + for(i=0;i<(password_len);i++) + { + nt_password_unicode[i*2]=nt_password[i]; + nt_password_unicode[i*2+1]=0; + } + } + nt_password_unicode[2*password_len]='\0'; +} + +/* This function generate the Key Exchange Key + * Depending on the flags this key will either be used to crypt the exported session key + * or will be used directly as exported session key. + * Exported session key is the key that will be used for sealing and signing communication*/ + +static void +get_keyexchange_key(unsigned char keyexchangekey[16],const unsigned char sessionbasekey[16],const unsigned char lm_challenge_response[24],int flags) +{ + guint8 basekey[16]; + guint8 zeros[24]; + + memset(keyexchangekey,0,16); + memset(basekey,0,16); + /* sessionbasekey is either derived from lm_password_hash or from nt_password_hash depending on the key type negotiated */ + memcpy(basekey,sessionbasekey,8); + memset(basekey,0xBD,8); + if(flags&NTLMSSP_NEGOTIATE_LM_KEY) + { + /*data,key*/ + crypt_des_ecb(keyexchangekey,lm_challenge_response,basekey,1); + crypt_des_ecb(keyexchangekey+8,lm_challenge_response,basekey+7,1); + } + else + { + if(flags&NTLMSSP_REQUEST_NON_NT_SESSION) + { + /*People from samba tends to use the same function in this case than in the previous one but with 0 data + * it's not clear that it produce the good result + * memcpy(keyexchangekey,lm_hash,8); + * Let's trust samba implementation it mights seem weird but they are more often rights than the spec ! + */ + memset(zeros,0,24); + crypt_des_ecb(keyexchangekey,zeros,basekey,3); + crypt_des_ecb(keyexchangekey+8,zeros,basekey+7,1); + } + else + { + /* it is stated page 65 of NTLM SSP spec that sessionbasekey should be encrypted with hmac_md5 using the concact of both challenge + * when it's NTLM v1 + extended security but it turns out to be wrong ! + */ + memcpy(keyexchangekey,sessionbasekey,16); + } + } +} +static guint32 +get_md4pass_list(md4_pass** p_pass_list,const char* nt_password) { + guint32 nb_pass = 0; + enc_key_t *ek; + unsigned char nt_password_hash[16]; + int password_len = 0; + char nt_password_unicode[256]; + md4_pass* pass_list; + int i = 0; + + for(ek=enc_key_list;ek;ek=ek->next){ + if( ek->keylength == 16 ) { + nb_pass++; + } + } + memset(nt_password_hash,0,16); + if (nt_password[0] != '\0' && ( strlen(nt_password) < 129 )) { + nb_pass++; + password_len = strlen(nt_password); + str_to_unicode(nt_password,nt_password_unicode); + crypt_md4(nt_password_hash,nt_password_unicode,password_len*2); + } + if( nb_pass == 0 ) { + /* Unable to calculate the session key without a password or if password is more than 128 char ......*/ + return 0; + } + i = 0; + *p_pass_list = ep_alloc(nb_pass*sizeof(md4_pass)); + pass_list=*p_pass_list; + + if( memcmp(nt_password_hash,zeros,16) != 0 ) { + memcpy(pass_list[i].md4,nt_password_hash,16); + i = 1; + } + for(ek=enc_key_list;ek;ek=ek->next){ + if( ek->keylength == 16 ) { + memcpy(pass_list[i].md4,ek->keyvalue,16); + i++; + } + } + return nb_pass; +} +/* Create an NTLMSSP version 2 + */ +static void +create_ntlmssp_v2_key(const char *nt_password, const guint8 *serverchallenge , const guint8 *clientchallenge , + guint8 *sessionkey ,const guint8 *encryptedsessionkey , int flags , ntlmssp_blob ntlm_response, ntlmssp_blob lm_response _U_, ntlmssp_header_t *ntlmssph ) { + char domain_name_unicode[256]; + char user_uppercase[256]; + char buf[512]; + /*guint8 md4[16];*/ + unsigned char nt_password_hash[16]; + unsigned char nt_proof[16]; + unsigned char ntowf[16]; + guint8 sessionbasekey[16]; + guint8 keyexchangekey[16]; + guint8 lm_challenge_response[24]; + guint32 i; + guint32 j; + rc4_state_struct rc4state; + guint32 user_len; + guint32 domain_len; + md4_pass *pass_list; + guint32 nb_pass = 0; + int found = 0; + + /* We are going to try password encrypted in keytab as well, it's an idean of Stefan Metzmacher <metze@samba.org> + * The idea is to be able to test all the key of domain in once and to be able to decode the NTLM dialogs */ + + memset(sessionkey, 0, 16); + nb_pass = get_md4pass_list(&pass_list,nt_password); + i=0; + memset(user_uppercase,0,256); + user_len = strlen(ntlmssph->acct_name); + if( user_len < 129 ) { + memset(buf,0,512); + str_to_unicode(ntlmssph->acct_name,buf); + for (j = 0; j < (2*user_len); j++) { + if( buf[j] != '\0' ) { + user_uppercase[j] = toupper(buf[j]); + } + } + } + else { + /* Unable to calculate the session not enought space in buffer, note this is unlikely to happen but ......*/ + return; + } + domain_len = strlen(ntlmssph->domain_name); + if( domain_len < 129 ) { + str_to_unicode(ntlmssph->domain_name,domain_name_unicode); + } + else { + /* Unable to calculate the session not enought space in buffer, note this is unlikely to happen but ......*/ + return; + } + while (i < nb_pass ) { + /*fprintf(stderr,"Turn %d, ",i);*/ + memcpy(nt_password_hash,pass_list[i].md4,16); + /*printnbyte(nt_password_hash,16,"Current NT password hash: ","\n");*/ + i++; + /* ntowf computation */ + memset(buf,0,512); + memcpy(buf,user_uppercase,user_len*2); + memcpy(buf+user_len*2,domain_name_unicode,domain_len*2); + md5_hmac(buf,domain_len*2+user_len*2,nt_password_hash,16,ntowf); + /* LM response */ + memset(buf,0,512); + memcpy(buf,serverchallenge,8); + memcpy(buf+8,clientchallenge,8); + md5_hmac(buf,16,ntowf,16,lm_challenge_response); + memcpy(lm_challenge_response+16,clientchallenge,8); + printnbyte(lm_challenge_response,24,"LM Response: ","\n"); + + /* NT proof = First 16 bytes of NT response */ + memset(buf,0,512); + memcpy(buf,serverchallenge,8); + memcpy(buf+8,ntlm_response.contents+16,ntlm_response.length-16); + md5_hmac(buf,ntlm_response.length-8,ntowf,16,nt_proof); + printnbyte(nt_proof,16,"NT proof: ","\n"); + if( !memcmp(nt_proof,ntlm_response.contents,16) ) { + found = 1; + break; + } + + } + if( found == 0 ) { + + return; + } + + md5_hmac(nt_proof,16,ntowf,16,sessionbasekey); + get_keyexchange_key(keyexchangekey,sessionbasekey,lm_challenge_response,flags); + /* now decrypt session key if needed and setup sessionkey for decrypting further communications */ + if (flags & NTLMSSP_NEGOTIATE_KEY_EXCH) + { + memcpy(sessionkey,encryptedsessionkey,16); + crypt_rc4_init(&rc4state,keyexchangekey,16); + crypt_rc4(&rc4state,sessionkey,16); + } + else + { + memcpy(sessionkey,keyexchangekey,16); + } + +} + /* Create an NTLMSSP version 1 key + * That is more complicated logic and methods and user challenge as well. * password points to the ANSI password to encrypt, challenge points to - * the 8 octet challenge string, key128 will do a 128 bit key if set to 1, - * otherwise it will do a 40 bit key. The result is stored in - * sspkey (expected to be 16 octets) + * the 8 octet challenge string */ static void -create_ntlmssp_v1_key(const char *nt_password, const guint8 *challenge, - int use_key_128, guint8 *sspkey) +create_ntlmssp_v1_key(const char *nt_password, const guint8 *serverchallenge, const guint8 *clientchallenge, + guint8 *sessionkey,const guint8 *encryptedsessionkey, int flags, const guint8 *ref_nt_challenge_response,const guint8 *ref_lm_challenge_response) { unsigned char lm_password_upper[16]; unsigned char lm_password_hash[16]; + unsigned char nt_password_hash[16]; + unsigned char challenges_hash[16]; + unsigned char challenges_hash_first8[8]; + unsigned char challenges[16]; + guint8 md4[16]; + guint8 nb_pass = 0; + guint8 sessionbasekey[16]; + guint8 keyexchangekey[16]; guint8 lm_challenge_response[24]; - guint8 rc4key[24]; - guint8 pw21[21]; /* Password hash padded to 21 bytes */ + guint8 nt_challenge_response[24]; + rc4_state_struct rc4state; + md5_state_t md5state; + char nt_password_unicode[256]; size_t password_len; unsigned int i; + int found = 0; + md4_pass *pass_list; unsigned char lmhash_key[] = {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25}; - + + memset(sessionkey, 0, 16); memset(lm_password_upper, 0, sizeof(lm_password_upper)); - + /* lm auth/lm session == (!NTLM_NEGOTIATE_NT_ONLY && NTLMSSP_NEGOTIATE_LM_KEY) || ! (EXTENDED_SECURITY) || ! NTLMSSP_NEGOTIATE_NTLM*/ /* Create a Lan Manager hash of the input password */ if (nt_password[0] != '\0') { password_len = strlen(nt_password); + /*Do not forget to free nt_password_nt*/ + str_to_unicode(nt_password,nt_password_unicode); + crypt_md4(nt_password_hash,nt_password_unicode,password_len*2); /* Truncate password if too long */ if (password_len > 16) password_len = 16; @@ -313,42 +624,181 @@ create_ntlmssp_v1_key(const char *nt_password, const guint8 *challenge, lm_password_upper[i] = toupper(nt_password[i]); } } + else + { + /* Unable to calculate the session key without a password ... and we will not use one for a keytab*/ + if( !(flags & NTLMSSP_NEGOTIATE_EXTENDED_SECURITY )) { + return; + } + } + if((flags & NTLMSSP_NEGOTIATE_LM_KEY && !(flags & NTLMSSP_NEGOTIATE_NT_ONLY)) || !(flags & NTLMSSP_NEGOTIATE_EXTENDED_SECURITY) || !(flags & NTLMSSP_NEGOTIATE_NTLM)) { + crypt_des_ecb(lm_password_hash, lmhash_key, lm_password_upper, 1); + crypt_des_ecb(lm_password_hash+8, lmhash_key, lm_password_upper+7, 1); + ntlmssp_generate_challenge_response(lm_challenge_response, + lm_password_hash, serverchallenge); + memcpy(sessionbasekey,lm_password_hash,16); + } + else { + + memset(lm_challenge_response,0,24); + if( flags & NTLMSSP_NEGOTIATE_EXTENDED_SECURITY ) { + nb_pass = get_md4pass_list(&pass_list,nt_password); + i=0; + while (i < nb_pass ) { + /*fprintf(stderr,"Turn %d, ",i);*/ + memcpy(nt_password_hash,pass_list[i].md4,16); + /*printnbyte(nt_password_hash,16,"Current NT password hash: ","\n");*/ + i++; + memcpy(lm_challenge_response,clientchallenge,8); + md5_init(&md5state); + md5_append(&md5state,serverchallenge,8); + md5_append(&md5state,clientchallenge,8); + md5_finish(&md5state,challenges_hash); + memcpy(challenges_hash_first8,challenges_hash,8); + crypt_des_ecb_long(nt_challenge_response,nt_password_hash,challenges_hash_first8); + if( !memcmp(ref_nt_challenge_response,nt_challenge_response,24) ) { + found = 1; + break; + } + } + } + else { + crypt_des_ecb_long(nt_challenge_response,nt_password_hash,serverchallenge); + if( flags & NTLMSSP_NEGOTIATE_NT_ONLY ) { + memcpy(lm_challenge_response,nt_challenge_response,24); + } + else { + crypt_des_ecb_long(lm_challenge_response,lm_password_hash,serverchallenge); + } + if( !memcmp(ref_nt_challenge_response,nt_challenge_response,24) && !memcmp(ref_lm_challenge_response,lm_challenge_response,24) ) { + found = 1; + } + } + /* So it's clearly not like this that's put into NTLMSSP doc but after some digging into samba code I'm quite confident + * that sessionbasekey should be based md4(nt_password_hash) only in the case of some NT auth + * Otherwise it should be lm_password_hash ...*/ + crypt_md4(md4,nt_password_hash,16); + if (flags & NTLMSSP_NEGOTIATE_EXTENDED_SECURITY) { + memcpy(challenges,serverchallenge,8); + memcpy(challenges+8,clientchallenge,8); + /*md5_hmac(text,text_len,key,key_len,digest);*/ + md5_hmac(challenges,16,md4,16,sessionbasekey); + } + else { + memcpy(sessionbasekey,md4,16); + } + } - crypt_des_ecb(lm_password_hash, lmhash_key, lm_password_upper, 1); - crypt_des_ecb(lm_password_hash+8, lmhash_key, lm_password_upper+7, 1); - - /* Generate the LanMan Challenge Response */ - ntlmssp_generate_challenge_response(lm_challenge_response, - lm_password_hash, challenge); - - /* Generate the NTLMSSP-v1 RC4 Key. - * The RC4 key is derived from the Lan Manager Hash. - * See lkcl "DCE/RPC over SMB" page 254 for the algorithm. - */ - memset(pw21, 0xBD, sizeof(pw21)); - memcpy(pw21, lm_password_hash, sizeof(lm_password_hash)); + if( found == 0 ) { + return; + } - /* Only the first eight bytes of challenge_response is used */ - crypt_des_ecb(rc4key, lm_challenge_response, pw21, 1); - crypt_des_ecb(rc4key + 8, lm_challenge_response, pw21 + 7, 1); - crypt_des_ecb(rc4key + 16, lm_challenge_response, pw21 + 14, 1); - /* Create the SSP Key */ - memset(sspkey, 0, sizeof(sspkey)); - if (use_key_128) { - /* Create 128 bit key */ - memcpy(sspkey, rc4key, 16); + get_keyexchange_key(keyexchangekey,sessionbasekey,lm_challenge_response,flags); + memset(sessionkey, 0, 16); + /*printnbyte(nt_challenge_response,24,"NT challenge response","\n"); + printnbyte(lm_challenge_response,24,"LM challenge response","\n");*/ + /* now decrypt session key if needed and setup sessionkey for decrypting further communications */ + if (flags & NTLMSSP_NEGOTIATE_KEY_EXCH) + { + memcpy(sessionkey,encryptedsessionkey,16); + crypt_rc4_init(&rc4state,keyexchangekey,16); + crypt_rc4(&rc4state,sessionkey,16); } - else { - /* Create 40 bit key */ - memcpy(sspkey, rc4key, 5); - sspkey[5]=0xe5; - sspkey[6]=0x38; - sspkey[7]=0xb0; + else + { + memcpy(sessionkey,keyexchangekey,16); } - return; +} +static void +get_siging_key(guint8 *sign_key_server,guint8* sign_key_client,const guint8 key[16], int keylen) +{ + md5_state_t md5state; + md5_state_t md5state2; + memset(sign_key_client,0,16); + memset(sign_key_server,0,16); + md5_init(&md5state); + md5_append(&md5state,key,keylen); + md5_append(&md5state,CLIENT_SIGN_TEXT,strlen(CLIENT_SIGN_TEXT)+1); + md5_finish(&md5state,sign_key_client); + md5_init(&md5state2); + md5_append(&md5state2,key,keylen); + md5_append(&md5state2,SERVER_SIGN_TEXT,strlen(SERVER_SIGN_TEXT)+1); + md5_finish(&md5state2,sign_key_server); + } +/* We return either a 128 or 64 bit key + */ +static void +get_sealing_rc4key(const guint8 exportedsessionkey[16] ,const int flags ,int *keylen ,guint8 *clientsealkey ,guint8 *serversealkey) +{ + md5_state_t md5state; + md5_state_t md5state2; + memset(clientsealkey,0,16); + memset(serversealkey,0,16); + memcpy(clientsealkey,exportedsessionkey,16); + if (flags & NTLMSSP_NEGOTIATE_EXTENDED_SECURITY) + { + if (flags & NTLMSSP_NEGOTIATE_128) + { + /* The exportedsessionkey has already the good length just update the length*/ + *keylen = 16; + } + else + { + if (flags & NTLMSSP_NEGOTIATE_56) + { + memset(clientsealkey+7,0,9); + *keylen = 7; + } + else + { + memset(clientsealkey+5,0,11); + *keylen = 5; + } + } + memcpy(serversealkey,clientsealkey,16); + md5_init(&md5state); + md5_append(&md5state,clientsealkey,*keylen); + md5_append(&md5state,CLIENT_SEAL_TEXT,strlen(CLIENT_SEAL_TEXT)+1); + md5_finish(&md5state,clientsealkey); + md5_init(&md5state2); + md5_append(&md5state2,serversealkey,*keylen); + md5_append(&md5state2,SERVER_SEAL_TEXT,strlen(SERVER_SEAL_TEXT)+1); + md5_finish(&md5state2,serversealkey); + } + else + { + if (flags & NTLMSSP_NEGOTIATE_128) + { + /* The exportedsessionkey has already the good length just update the length*/ + *keylen = 16; + } + else + { + *keylen = 8; + if (flags & NTLMSSP_NEGOTIATE_56) + { + memset(clientsealkey+7,0,9); + } + else + { + memset(clientsealkey+5,0,11); + clientsealkey[5]=0xe5; + clientsealkey[6]=0x38; + clientsealkey[7]=0xb0; + } + } + serversealkey = memcpy(serversealkey,clientsealkey,*keylen); + } +} +/* Create an NTLMSSP version 1 key. + * password points to the ANSI password to encrypt, challenge points to + * the 8 octet challenge string, key128 will do a 128 bit key if set to 1, + * otherwise it will do a 40 bit key. The result is stored in + * sspkey (expected to be 16 octets) + */ /* dissect a string - header area contains: two byte len two byte maxlen @@ -427,7 +877,6 @@ dissect_ntlmssp_blob (tvbuff_t *tvb, int offset, guint16 blob_length = tvb_get_letohs(tvb, offset); guint16 blob_maxlen = tvb_get_letohs(tvb, offset+2); guint32 blob_offset = tvb_get_letohl(tvb, offset+4); - if (0 == blob_length) { *end = (blob_offset > ((guint)offset)+8 ? blob_offset : ((guint)offset)+8); if (ntlmssp_tree) @@ -457,14 +906,27 @@ dissect_ntlmssp_blob (tvbuff_t *tvb, int offset, result->length = blob_length; memset(result->contents, 0, MAX_BLOB_SIZE); if (blob_length < MAX_BLOB_SIZE) + { tvb_memcpy(tvb, result->contents, blob_offset, blob_length); + if (blob_hf == hf_ntlmssp_auth_lmresponse && !(memcmp(tvb->real_data+blob_offset+8,"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",16))) + { + proto_tree_add_item (ntlmssp_tree, + hf_ntlmssp_ntlm_client_challenge, + tvb, blob_offset, 8, FALSE); + } + } } /* If we are dissecting the NTLM response and it is a NTLMv2 response call the appropriate dissector. */ if (blob_hf == hf_ntlmssp_auth_ntresponse && blob_length > 24) + { + proto_tree_add_item (ntlmssp_tree, + hf_ntlmssp_ntlm_client_challenge, + tvb, blob_offset+32, 8, FALSE); dissect_ntlmv2_response(tvb, tree, blob_offset, blob_length); + } return offset; } @@ -601,6 +1063,9 @@ dissect_ntlmssp_negotiate_flags (tvbuff_t *tvb, int offset, #define NTLM_NAME_DNS_HOST 0x0003 #define NTLM_NAME_DNS_DOMAIN 0x0004 #define NTLM_NAME_CLIENT_TIME 0x0007 +#define NTLM_NAME_RESTRICTION 0x0008 + + static const value_string ntlm_name_types[] = { { NTLM_NAME_END, "End of list" }, @@ -608,7 +1073,9 @@ static const value_string ntlm_name_types[] = { { NTLM_NAME_NB_DOMAIN, "NetBIOS domain name" }, { NTLM_NAME_DNS_HOST, "DNS host name" }, { NTLM_NAME_DNS_DOMAIN, "DNS domain name" }, + { NTLM_NAME_CLIENT_TIME, "Client Time" }, + { NTLM_NAME_RESTRICTION, "Encoding restriction" }, { 0, NULL } }; @@ -617,7 +1084,7 @@ dissect_ntlmv2_response(tvbuff_t *tvb, proto_tree *tree, int offset, int len) { proto_item *ntlmv2_item = NULL; proto_tree *ntlmv2_tree = NULL; - + const guint8 *restriction_bytes; /* Dissect NTLMv2 bits&pieces */ if (tree) { @@ -709,6 +1176,14 @@ dissect_ntlmv2_response(tvbuff_t *tvb, proto_tree *tree, int offset, int len) proto_item_append_text( name_item, "Client Time"); break; + case NTLM_NAME_RESTRICTION: + proto_item_append_text( + name_item, "%s", + val_to_str(name_type, ntlm_name_types, + "Unknown")); + restriction_bytes = tvb_get_ptr(tvb, offset,name_len); + proto_tree_add_bytes (name_tree,hf_ntlmssp_ntlmv2_response_restriction,tvb,offset,name_len,restriction_bytes); + break; case NTLM_NAME_NB_HOST: case NTLM_NAME_NB_DOMAIN: case NTLM_NAME_DNS_HOST: @@ -716,10 +1191,9 @@ dissect_ntlmv2_response(tvbuff_t *tvb, proto_tree *tree, int offset, int len) default: name = tvb_get_ephemeral_faked_unicode( tvb, offset, name_len / 2, TRUE); - proto_tree_add_text( name_tree, tvb, offset, name_len, - "Name: %s", name); + "Value: %s", name); proto_item_append_text( name_item, "%s, %s", val_to_str(name_type, ntlm_name_types, @@ -911,12 +1385,15 @@ dissect_ntlmssp_challenge (tvbuff_t *tvb, packet_info *pinfo, int offset, guint32 negotiate_flags; int item_start, item_end; int data_start, data_end; - ntlmssp_info *conv_ntlmssp_info; + guint8 clientkey[16]; /* NTLMSSP cipher key for client */ + guint8 serverkey[16]; /* NTLMSSP cipher key for server*/ + ntlmssp_info *conv_ntlmssp_info = NULL; conversation_t *conversation; gboolean unicode_strings = FALSE; guint8 challenge[8]; + guint8 tmp[8]; guint8 sspkey[16]; /* NTLMSSP cipher key */ - guint8 ssp_key_len; /* Either 8 or 16 (40 bit or 128) */ + int ssp_key_len; /* Either 8 or 16 (40 bit or 128) */ /* need to find unicode flag */ negotiate_flags = tvb_get_letohl (tvb, offset+8); @@ -940,7 +1417,7 @@ dissect_ntlmssp_challenge (tvbuff_t *tvb, packet_info *pinfo, int offset, /* NTLMSSP NT Lan Manager Challenge */ proto_tree_add_item (ntlmssp_tree, - hf_ntlmssp_ntlm_challenge, + hf_ntlmssp_ntlm_server_challenge, tvb, offset, 8, FALSE); /* @@ -954,29 +1431,36 @@ dissect_ntlmssp_challenge (tvbuff_t *tvb, packet_info *pinfo, int offset, conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); } - - if (!conversation_get_proto_data(conversation, proto_ntlmssp)) { + tvb_memcpy(tvb, tmp, offset, 8); + /* We can face more than one NTLM exchange over the same couple of IP and ports ...*/ + conv_ntlmssp_info = conversation_get_proto_data(conversation, proto_ntlmssp); + if (!conv_ntlmssp_info || memcmp(tmp,conv_ntlmssp_info->server_challenge,8) != 0) { conv_ntlmssp_info = se_alloc(sizeof(ntlmssp_info)); /* Insert the flags into the conversation */ conv_ntlmssp_info->flags = negotiate_flags; /* Insert the RC4 state information into the conversation */ tvb_memcpy(tvb, challenge, offset, 8); - + tvb_memcpy(tvb, conv_ntlmssp_info->server_challenge, offset, 8); + conv_ntlmssp_info->is_auth_ntlm_v2=0; /* Between the challenge and the user provided password, we can build the - NTLMSSP key and initialize the cipher */ - if (conv_ntlmssp_info->flags & NTLMSSP_NEGOTIATE_128) { - create_ntlmssp_v1_key(nt_password, challenge, 1, sspkey); - ssp_key_len = 16; - } - else { - create_ntlmssp_v1_key(nt_password, challenge, 0, sspkey); - ssp_key_len = 8; + NTLMSSP key and initialize the cipher if we are not in EXTENDED SECURITY + in this case we need the client challenge as well*/ + /* BTW this is true just if we are in LM Authentification if not the logic is a bit different. + * Right now it's not very clear what is LM Authentification it __seems__ to be when + * NEGOTIATE NT ONLY is not set and NEGOSIATE EXTENDED SECURITY is not set as well*/ + if (!(conv_ntlmssp_info->flags & NTLMSSP_NEGOTIATE_EXTENDED_SECURITY)) + { + conv_ntlmssp_info->rc4_state_initialized = 0; + create_ntlmssp_v1_key(nt_password, conv_ntlmssp_info->server_challenge,NULL, sspkey,NULL,conv_ntlmssp_info->flags,conv_ntlmssp_info->ntlm_response.contents,conv_ntlmssp_info->lm_response.contents); + if( memcmp(sspkey,zeros,16) != 0 ) { + get_sealing_rc4key(sspkey,conv_ntlmssp_info->flags,&ssp_key_len,clientkey,serverkey); + crypt_rc4_init(&conv_ntlmssp_info->rc4_state_client, sspkey, ssp_key_len); + crypt_rc4_init(&conv_ntlmssp_info->rc4_state_server, sspkey, ssp_key_len); + conv_ntlmssp_info->server_dest_port = pinfo->destport; + conv_ntlmssp_info->rc4_state_initialized = 1; + } + } - crypt_rc4_init(&conv_ntlmssp_info->rc4_state_peer1, sspkey, ssp_key_len); - crypt_rc4_init(&conv_ntlmssp_info->rc4_state_peer2, sspkey, ssp_key_len); - conv_ntlmssp_info->peer1_dest_port = pinfo->destport; - conv_ntlmssp_info->rc4_state_initialized = 1; - conversation_add_proto_data(conversation, proto_ntlmssp, conv_ntlmssp_info); } offset += 8; @@ -1023,15 +1507,27 @@ dissect_ntlmssp_auth (tvbuff_t *tvb, packet_info *pinfo, int offset, int item_start, item_end; int data_start, data_end = 0; guint32 negotiate_flags; + guint8 sspkey[16]; /* exported session key */ + guint8 clientkey[16]; /* NTLMSSP cipher key for client */ + guint8 serverkey[16]; /* NTLMSSP cipher key for server*/ + guint8 encryptedsessionkey[16]; + ntlmssp_blob sessionblob; gboolean unicode_strings = FALSE; - ntlmssp_info *conv_ntlmssp_info; + ntlmssp_info *conv_ntlmssp_info = NULL; conversation_t *conversation; - + int ssp_key_len; /* * Get flag info from the original negotiate message, if any. * This is because the flag information is sometimes missing from * the AUTHENTICATE message, so we can't figure out whether * strings are Unicode or not by looking at *our* flags. + * XXX it seems it's more from the CHALLENGE message, which is more clever in fact + * because the server can change some flags. + * But according to MS NTLMSSP doc it's not that simple. + * In case of Conection less mode AUTHENTICATE flags should be used because they + * reprensent the choice of the client after having been informed of options of the + * server in the CHALLENGE message. + * In Connection mode then the CHALLENGE flags should (must ?) be used */ conv_ntlmssp_info = p_get_proto_data(pinfo->fd, proto_ntlmssp); if (conv_ntlmssp_info == NULL) { @@ -1060,7 +1556,10 @@ dissect_ntlmssp_auth (tvbuff_t *tvb, packet_info *pinfo, int offset, /* * Sometimes the session key and flags are missing. - * Sometimes the session key is present but the flags are missing. + * Sometimes the session key is present but the flags are missing. + * XXX Who stay so ? Reading spec I would rather say the opposite: flags are + * always present, session information are always there as well but sometime + * session information could be null (in case of no session) * Sometimes they're both present. * * This does not correlate with any flags in the previous CHALLENGE @@ -1082,7 +1581,7 @@ dissect_ntlmssp_auth (tvbuff_t *tvb, packet_info *pinfo, int offset, conv_ntlmssp_info == NULL ? NULL : &conv_ntlmssp_info->lm_response); data_end = MAX(data_end, item_end); - + /* NTLM response */ item_start = tvb_get_letohl(tvb, offset+4); offset = dissect_ntlmssp_blob(tvb, offset, ntlmssp_tree, @@ -1090,8 +1589,22 @@ dissect_ntlmssp_auth (tvbuff_t *tvb, packet_info *pinfo, int offset, &item_end, conv_ntlmssp_info == NULL ? NULL : &conv_ntlmssp_info->ntlm_response); + if( conv_ntlmssp_info != NULL && conv_ntlmssp_info->ntlm_response.length > 24 ) { + memcpy(conv_ntlmssp_info->client_challenge,conv_ntlmssp_info->ntlm_response.contents+32,8); + } data_start = MIN(data_start, item_start); data_end = MAX(data_end, item_end); + if( conv_ntlmssp_info != NULL ) + { + if( conv_ntlmssp_info->ntlm_response.length > 24 ) + { + conv_ntlmssp_info->is_auth_ntlm_v2=1; + } + else + { + conv_ntlmssp_info->is_auth_ntlm_v2=0; + } + } /* domain name */ item_start = tvb_get_letohl(tvb, offset+4); @@ -1099,6 +1612,7 @@ dissect_ntlmssp_auth (tvbuff_t *tvb, packet_info *pinfo, int offset, unicode_strings, hf_ntlmssp_auth_domain, &item_start, &item_end, &(ntlmssph->domain_name)); + /*ntlmssph->domain_name_len=item_end-item_start;*/ data_start = MIN(data_start, item_start); data_end = MAX(data_end, item_end); @@ -1108,6 +1622,7 @@ dissect_ntlmssp_auth (tvbuff_t *tvb, packet_info *pinfo, int offset, unicode_strings, hf_ntlmssp_auth_username, &item_start, &item_end, &(ntlmssph->acct_name)); + /*ntlmssph->acct_name_len=item_end-item_start;*/ data_start = MIN(data_start, item_start); data_end = MAX(data_end, item_end); @@ -1123,32 +1638,329 @@ dissect_ntlmssp_auth (tvbuff_t *tvb, packet_info *pinfo, int offset, &item_start, &item_end, &(ntlmssph->host_name)); data_start = MIN(data_start, item_start); data_end = MAX(data_end, item_end); - + memset(sessionblob.contents, 0, MAX_BLOB_SIZE); + sessionblob.length = 0; if (offset < data_start) { /* Session Key */ offset = dissect_ntlmssp_blob(tvb, offset, ntlmssp_tree, hf_ntlmssp_auth_sesskey, - &item_end, NULL); + &item_end, &sessionblob); data_end = MAX(data_end, item_end); } + if( sessionblob.length != 0 ) { + memcpy(encryptedsessionkey,sessionblob.contents,sessionblob.length); + if (offset < data_start) { + /* NTLMSSP Negotiate Flags */ + negotiate_flags = tvb_get_letohl (tvb, offset); + offset = dissect_ntlmssp_negotiate_flags (tvb, offset, ntlmssp_tree, + negotiate_flags); + } + /* Try to attach to an existing conversation if not then it's useless to try to do so + * because we are missing important information (ie. server challenge) + */ + if (conv_ntlmssp_info) { + /* If we are in EXTENDED SECURITY then we can now initialize cipher */ + if ((conv_ntlmssp_info->flags & NTLMSSP_NEGOTIATE_EXTENDED_SECURITY)) + { + conv_ntlmssp_info->rc4_state_initialized = 0; + if( conv_ntlmssp_info->is_auth_ntlm_v2 ) { + create_ntlmssp_v2_key(nt_password, conv_ntlmssp_info->server_challenge,conv_ntlmssp_info->client_challenge, sspkey,encryptedsessionkey,conv_ntlmssp_info->flags,conv_ntlmssp_info->ntlm_response,conv_ntlmssp_info->lm_response,ntlmssph); + } + else + { + memcpy(conv_ntlmssp_info->client_challenge,conv_ntlmssp_info->lm_response.contents,8); + create_ntlmssp_v1_key(nt_password, conv_ntlmssp_info->server_challenge,conv_ntlmssp_info->client_challenge, sspkey,encryptedsessionkey,conv_ntlmssp_info->flags,conv_ntlmssp_info->ntlm_response.contents,conv_ntlmssp_info->lm_response.contents); + } + /* ssp is the exported session key */ + if( memcmp(sspkey,zeros,16) != 0) { + get_sealing_rc4key(sspkey,conv_ntlmssp_info->flags,&ssp_key_len,clientkey,serverkey); + get_siging_key((guint8*)&conv_ntlmssp_info->sign_key_server,(guint8*)&conv_ntlmssp_info->sign_key_client,sspkey,ssp_key_len); + crypt_rc4_init(&conv_ntlmssp_info->rc4_state_server, serverkey, ssp_key_len); + crypt_rc4_init(&conv_ntlmssp_info->rc4_state_client, clientkey, ssp_key_len); + conv_ntlmssp_info->server_dest_port = pinfo->destport; + conv_ntlmssp_info->rc4_state_initialized = 1; + } + } + } + } + return MAX(offset, data_end); +} +static guint8* +get_sign_key(packet_info *pinfo, int cryptpeer) +{ + conversation_t *conversation; + ntlmssp_info *conv_ntlmssp_info; - if (offset < data_start) { - /* NTLMSSP Negotiate Flags */ - negotiate_flags = tvb_get_letohl (tvb, offset); - offset = dissect_ntlmssp_negotiate_flags (tvb, offset, ntlmssp_tree, - negotiate_flags); + conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, + pinfo->ptype, pinfo->srcport, + pinfo->destport, 0); + if (conversation == NULL) { + /* We don't have a conversation. In this case, stop processing + because we do not have enough info to decrypt the payload */ + return NULL; } + else { + /* We have a conversation, check for encryption state */ + conv_ntlmssp_info = conversation_get_proto_data(conversation, + proto_ntlmssp); + if (conv_ntlmssp_info == NULL) { + /* No encryption state tied to the conversation. Therefore, we + cannot decrypt the payload */ + return NULL; + } + else { + /* We have the encryption state in the conversation. So return the + crypt state tied to the requested peer + */ + if (cryptpeer == 1) { + return (guint8*)&conv_ntlmssp_info->sign_key_client; + } else { + return (guint8*)&conv_ntlmssp_info->sign_key_server; + } + } + } +} +/* + * Get the encryption state tied to this conversation. cryptpeer indicates + * whether to retrieve the client key (1) or the server key (0) + */ +static rc4_state_struct * +get_encrypted_state(packet_info *pinfo, int cryptpeer) +{ + conversation_t *conversation; + ntlmssp_info *conv_ntlmssp_info; - return MAX(offset, data_end); + conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, + pinfo->ptype, pinfo->srcport, + pinfo->destport, 0); + if (conversation == NULL) { + /* We don't have a conversation. In this case, stop processing + because we do not have enough info to decrypt the payload */ + return NULL; + } + else { + /* We have a conversation, check for encryption state */ + conv_ntlmssp_info = conversation_get_proto_data(conversation, + proto_ntlmssp); + if (conv_ntlmssp_info == NULL) { + /* No encryption state tied to the conversation. Therefore, we + cannot decrypt the payload */ + return NULL; + } + else { + /* We have the encryption state in the conversation. So return the + crypt state tied to the requested peer + */ + if (cryptpeer == 1) { + return &conv_ntlmssp_info->rc4_state_client; + } else { + return &conv_ntlmssp_info->rc4_state_server; + } + } + } +} +void +decrypt_data_payload(tvbuff_t *tvb, int offset, guint32 encrypted_block_length, + packet_info *pinfo, proto_tree *tree _U_,gpointer key); +static void +decrypt_verifier(tvbuff_t *tvb, int offset, guint32 encrypted_block_length, + packet_info *pinfo, proto_tree *tree,gpointer key); +/* +tvbuff_t * +dissect_ntlmssp_encrypted_payload(tvbuff_t *data_tvb, + tvbuff_t *auth_tvb _U_, + int offset, + packet_info *pinfo, + dcerpc_auth_info *auth_info _U_)*/ + +int +dissect_ntlmssp_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree ) +{ + volatile int offset = 0; + proto_tree *volatile ntlmssp_tree = NULL; + proto_item *tf = NULL; + guint32 length; + guint32 encrypted_block_length; + guint8 key[16]; + /* the magic ntlm is the identifier of a NTLMSSP packet that's 00 00 00 01 + */ + guint32 ntlm_magic_size = 4; + guint32 ntlm_signature_size = 8; + guint32 ntlm_seq_size = 4; + length = tvb_length (tvb); + /* signature + seq + real payload */ + encrypted_block_length = length - ntlm_magic_size; + + if (encrypted_block_length < (ntlm_signature_size + ntlm_seq_size)) { + /* Don't know why this would happen, but if it does, don't even bother + attempting decryption/dissection */ + return offset + length; + } + + /* Setup a new tree for the NTLMSSP payload */ + if (tree) { + tf = proto_tree_add_item (tree, + hf_ntlmssp_verf, + tvb, offset, -1, FALSE); + + ntlmssp_tree = proto_item_add_subtree (tf, + ett_ntlmssp); + } + + /* + * Catch the ReportedBoundsError exception; the stuff we've been + * handed doesn't necessarily run to the end of the packet, it's + * an item inside a packet, so if it happens to be malformed (or + * we, or a dissector we call, has a bug), so that an exception + * is thrown, we want to report the error, but return and let + * our caller dissect the rest of the packet. + * + * If it gets a BoundsError, we can stop, as there's nothing more + * in the packet after our blob to see, so we just re-throw the + * exception. + */ + TRY { + /* Version number */ + proto_tree_add_item (ntlmssp_tree, hf_ntlmssp_verf_vers, + tvb, offset, 4, TRUE); + offset += 4; + + /* Encrypted body */ + proto_tree_add_item (ntlmssp_tree, hf_ntlmssp_verf_body, + tvb, offset, ntlm_signature_size + ntlm_seq_size, TRUE); + tvb_memcpy(tvb, key, offset, ntlm_signature_size + ntlm_seq_size); + /* Try to decrypt */ + decrypt_data_payload (tvb, offset+(ntlm_signature_size + ntlm_seq_size), encrypted_block_length-(ntlm_signature_size + ntlm_seq_size), pinfo, ntlmssp_tree,key); + decrypt_verifier (tvb, offset, ntlm_signature_size + ntlm_seq_size, pinfo, ntlmssp_tree,key); + /* let's try to hook ourselves here */ + + offset += 12; + } CATCH(BoundsError) { + RETHROW; + } CATCH(ReportedBoundsError) { + show_reported_bounds_error(tvb, pinfo, tree); + } ENDTRY; + + return offset; } +void +decrypt_data_payload(tvbuff_t *tvb, int offset, guint32 encrypted_block_length, + packet_info *pinfo, proto_tree *tree _U_,gpointer key) +{ + tvbuff_t *decr_tvb; /* Used to display decrypted buffer */ + guint8 *peer_block; + conversation_t *conversation; + rc4_state_struct *rc4_state; + rc4_state_struct *rc4_state_peer; + ntlmssp_info *conv_ntlmssp_info = NULL; + ntlmssp_packet_info *packet_ntlmssp_info = NULL; + ntlmssp_packet_info *stored_packet_ntlmssp_info = NULL; + /* Check to see if we already have state for this packet */ + packet_ntlmssp_info = p_get_proto_data(pinfo->fd, proto_ntlmssp); + if (packet_ntlmssp_info == NULL) { + /* We don't have any packet state, so create one */ + packet_ntlmssp_info = se_alloc(sizeof(ntlmssp_packet_info)); + memset(packet_ntlmssp_info, 0, sizeof(ntlmssp_packet_info)); + p_add_proto_data(pinfo->fd, proto_ntlmssp, packet_ntlmssp_info); + } + if (!packet_ntlmssp_info->payload_decrypted) { + /* Pull the challenge info from the conversation */ + conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, + pinfo->ptype, pinfo->srcport, + pinfo->destport, 0); + if (conversation == NULL) { + /* There is no conversation, thus no encryption state */ + return ; + } + + conv_ntlmssp_info = conversation_get_proto_data(conversation, + proto_ntlmssp); + if (conv_ntlmssp_info == NULL) { + /* There is no NTLMSSP state tied to the conversation */ + return ; + } + if (conv_ntlmssp_info->rc4_state_initialized != 1 ) { + /* The crypto sybsystem is not initialized. This means that either + the conversation did not include a challenge, or that we do not have the right password */ + return; + } + if( key != NULL ){ + stored_packet_ntlmssp_info = g_hash_table_lookup(hash_packet,key); + } + if( stored_packet_ntlmssp_info != NULL && stored_packet_ntlmssp_info->payload_decrypted == TRUE) + { + /* Mat TBD fprintf(stderr,"Found a already decrypted packet\n");*/ + memcpy(packet_ntlmssp_info,stored_packet_ntlmssp_info,sizeof(ntlmssp_packet_info)); + /* Mat TBD printnbyte(packet_ntlmssp_info->decrypted_payload,encrypted_block_length,"Data: ","\n");*/ + } + else + { + /* Get the pair of RC4 state structures. One is used for to decrypt the + payload. The other is used to re-encrypt the payload to represent + the peer */ + if (conv_ntlmssp_info->server_dest_port == pinfo->destport) { + /* client */ + rc4_state = get_encrypted_state(pinfo, 1); + rc4_state_peer = get_encrypted_state(pinfo, 0); + } else { + /* server */ + rc4_state = get_encrypted_state(pinfo, 0); + rc4_state_peer = get_encrypted_state(pinfo, 1); + } + + if (rc4_state == NULL ) { + /* There is no encryption state, so we cannot decrypt */ + return ; + } + + /* Store the decrypted contents in the packet state struct + (of course at this point, they aren't decrypted yet) */ + packet_ntlmssp_info->decrypted_payload = tvb_memdup(tvb, offset, + encrypted_block_length); + packet_ntlmssp_info->payload_len = encrypted_block_length; + decrypted_payloads = g_slist_prepend(decrypted_payloads, + packet_ntlmssp_info->decrypted_payload); + if( key != NULL ) { + g_hash_table_insert(hash_packet,key,packet_ntlmssp_info); + } + + /* Do the decryption of the payload */ + crypt_rc4(rc4_state, packet_ntlmssp_info->decrypted_payload, + encrypted_block_length); + /* decrypt the verifier */ + /*printnchar(packet_ntlmssp_info->decrypted_payload,encrypted_block_length,"data: ","\n");*/ + /* We setup a temporary buffer so we can re-encrypt the payload after + decryption. This is to update the opposite peer's RC4 state + it's usefull when we have only one key for both conversation + in case of KEY_EXCH we have independant key so this is not needed*/ + if( !(NTLMSSP_NEGOTIATE_KEY_EXCH & conv_ntlmssp_info->flags)) { + peer_block = g_malloc(encrypted_block_length); + memcpy(peer_block, packet_ntlmssp_info->decrypted_payload, + encrypted_block_length); + crypt_rc4(rc4_state_peer, peer_block, encrypted_block_length); + g_free(peer_block); + } + + packet_ntlmssp_info->payload_decrypted = TRUE; + } + } + + /* Show the decrypted buffer in a new window */ + decr_tvb = tvb_new_real_data(packet_ntlmssp_info->decrypted_payload, + encrypted_block_length, + encrypted_block_length); + + tvb_set_child_real_data_tvbuff(tvb, decr_tvb); + pinfo->gssapi_decrypted_tvb = decr_tvb; +} static void dissect_ntlmssp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { volatile int offset = 0; proto_tree *volatile ntlmssp_tree = NULL; proto_item *tf = NULL; - ntlmssp_header_t *ntlmssph; + ntlmssp_header_t *ntlmssph; ntlmssph=ep_alloc(sizeof(ntlmssp_header_t)); ntlmssph->type=0; @@ -1223,129 +2035,143 @@ dissect_ntlmssp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) show_reported_bounds_error(tvb, pinfo, tree); } ENDTRY; - tap_queue_packet(ntlmssp_tap, pinfo, ntlmssph); + /*tap_queue_packet(ntlmssp_tap, pinfo, ntlmssph);*/ } -/* - * Get the encryption state tied to this conversation. cryptpeer indicates - * whether to retrieve the data for peer1 or peer2. - */ -static rc4_state_struct * -get_encrypted_state(packet_info *pinfo, int cryptpeer) -{ - conversation_t *conversation; - ntlmssp_info *conv_ntlmssp_info; - conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, - pinfo->ptype, pinfo->srcport, - pinfo->destport, 0); - if (conversation == NULL) { - /* We don't have a conversation. In this case, stop processing - because we do not have enough info to decrypt the payload */ - return NULL; - } - else { - /* We have a conversation, check for encryption state */ - conv_ntlmssp_info = conversation_get_proto_data(conversation, - proto_ntlmssp); - if (conv_ntlmssp_info == NULL) { - /* No encryption state tied to the conversation. Therefore, we - cannot decrypt the payload */ - return NULL; - } - else { - /* We have the encryption state in the conversation. So return the - crypt state tied to the requested peer - */ - if (cryptpeer == 1) { - return &conv_ntlmssp_info->rc4_state_peer1; - } else { - return &conv_ntlmssp_info->rc4_state_peer2; - } - } - } -} /* * See page 45 of "DCE/RPC over SMB" by Luke Kenneth Casson Leighton. */ static void decrypt_verifier(tvbuff_t *tvb, int offset, guint32 encrypted_block_length, - packet_info *pinfo, proto_tree *tree) + packet_info *pinfo, proto_tree *tree,gpointer key) { proto_tree *decr_tree = NULL; proto_item *tf = NULL; conversation_t *conversation; + guint8* sign_key; rc4_state_struct *rc4_state; rc4_state_struct *rc4_state_peer; tvbuff_t *decr_tvb; /* Used to display decrypted buffer */ guint8 *peer_block; + guint8 *check_buf; + guint8 calculated_md5[16]; ntlmssp_info *conv_ntlmssp_info = NULL; ntlmssp_packet_info *packet_ntlmssp_info = NULL; int decrypted_offset = 0; + int sequence = 0; + ntlmssp_packet_info *stored_packet_ntlmssp_info = NULL; packet_ntlmssp_info = p_get_proto_data(pinfo->fd, proto_ntlmssp); if (packet_ntlmssp_info == NULL) { /* We don't have data for this packet */ return; } - if (!packet_ntlmssp_info->verifier_decrypted) { - conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, - pinfo->ptype, pinfo->srcport, - pinfo->destport, 0); - if (conversation == NULL) { - /* There is no conversation, thus no encryption state */ - return; - } - - conv_ntlmssp_info = conversation_get_proto_data(conversation, + conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, + pinfo->ptype, pinfo->srcport, + pinfo->destport, 0); + if (conversation == NULL) { + /* There is no conversation, thus no encryption state */ + return; + } + conv_ntlmssp_info = conversation_get_proto_data(conversation, proto_ntlmssp); - if (conv_ntlmssp_info == NULL) { - /* There is no NTLMSSP state tied to the conversation */ - return; - } - if (conv_ntlmssp_info->rc4_state_initialized != 1 ) { - /* The crypto sybsystem is not initialized. This means that either - the conversation did not include a challenge, or we are doing - something other than NTLMSSP v1 */ - return; - } - - if (conv_ntlmssp_info->peer1_dest_port == pinfo->destport) { - rc4_state = get_encrypted_state(pinfo, 1); - rc4_state_peer = get_encrypted_state(pinfo, 0); - } else { - rc4_state = get_encrypted_state(pinfo, 0); - rc4_state_peer = get_encrypted_state(pinfo, 1); - } + if (conv_ntlmssp_info == NULL) { + /* There is no NTLMSSP state tied to the conversation */ + return; + } - if (rc4_state == NULL || rc4_state_peer == NULL) { - /* There is no encryption state, so we cannot decrypt */ - return; + if( key != NULL ){ + stored_packet_ntlmssp_info = g_hash_table_lookup(hash_packet,key); + } + if( stored_packet_ntlmssp_info != NULL && stored_packet_ntlmssp_info->verifier_decrypted == TRUE) { + /* Mat TBD fprintf(stderr,"Found a already decrypted packet\n");*/ + /* In Theory it's aleady the case, and we should be more clever ... like just copying buffers ...*/ + packet_ntlmssp_info = stored_packet_ntlmssp_info; + } + else { + if (!packet_ntlmssp_info->verifier_decrypted) { + if (conv_ntlmssp_info->rc4_state_initialized != 1 ) { + /* The crypto sybsystem is not initialized. This means that either + the conversation did not include a challenge, or we are doing + something other than NTLMSSP v1 */ + return; + } + if (conv_ntlmssp_info->server_dest_port == pinfo->destport) { + /* client talk to server */ + rc4_state = get_encrypted_state(pinfo, 1); + sign_key = get_sign_key(pinfo,1); + rc4_state_peer = get_encrypted_state(pinfo, 0); + } else { + rc4_state = get_encrypted_state(pinfo, 0); + sign_key = get_sign_key(pinfo,0); + rc4_state_peer = get_encrypted_state(pinfo, 1); + } + + if (rc4_state == NULL || rc4_state_peer == NULL) { + /* There is no encryption state, so we cannot decrypt */ + return; + } + + /* Setup the buffer to decrypt to */ + tvb_memcpy(tvb, packet_ntlmssp_info->verifier, + offset, encrypted_block_length); + + /*if( !(NTLMSSP_NEGOTIATE_KEY_EXCH & packet_ntlmssp_info->flags)) {*/ + if( conv_ntlmssp_info->flags & NTLMSSP_NEGOTIATE_EXTENDED_SECURITY ) { + if( (NTLMSSP_NEGOTIATE_KEY_EXCH & conv_ntlmssp_info->flags)) { + /* The spec says that if we have have a key exchange then we have a the signature that is crypted + * otherwise it's just a hmac_md5(keysign,concat(message,sequence))[0..7] + */ + crypt_rc4(rc4_state, packet_ntlmssp_info->verifier, + 8); + } + /* + * Try to check the HMAC MD5 of the message against those calculated works great with LDAP payload but + * don't with DCE/RPC calls. + * Some analysis need to be done ... + */ + if( sign_key != NULL ) { + check_buf = g_malloc(packet_ntlmssp_info->payload_len+4); + tvb_memcpy(tvb, &sequence,offset+8,4); + memcpy(check_buf,&sequence,4); + memcpy(check_buf+4,packet_ntlmssp_info->decrypted_payload,packet_ntlmssp_info->payload_len); + md5_hmac(check_buf,(int)(packet_ntlmssp_info->payload_len+4),sign_key,16,calculated_md5); + /* + printnbyte(packet_ntlmssp_info->verifier,8,"HMAC from packet: ","\n"); + printnbyte(calculated_md5,8,"HMAC : ","\n"); + */ + g_free(check_buf); + } + } + else { + /* The packet has a PAD then a checksum then a sequence and they are encoded in this order so we can decrypt all at once */ + /* Do the actual decryption of the verifier */ + crypt_rc4(rc4_state, packet_ntlmssp_info->verifier, + encrypted_block_length); + } + + + + /* We setup a temporary buffer so we can re-encrypt the payload after + decryption. This is to update the opposite peer's RC4 state + This is not needed when we just have EXTENDED SECURITY because the signature is not crypted + and it's also not needed when we have key exchange because server and client have independant keys */ + if( !(NTLMSSP_NEGOTIATE_KEY_EXCH & conv_ntlmssp_info->flags) && !(NTLMSSP_NEGOTIATE_EXTENDED_SECURITY & conv_ntlmssp_info->flags)) { + peer_block = g_malloc(encrypted_block_length); + memcpy(peer_block, packet_ntlmssp_info->verifier, + encrypted_block_length); + crypt_rc4(rc4_state_peer, peer_block, encrypted_block_length); + g_free(peer_block); + } + + /* Mark the packet as decrypted so that subsequent attempts to dissect + the packet use the already decrypted payload instead of attempting + to decrypt again */ + packet_ntlmssp_info->verifier_decrypted = TRUE; } - - /* Setup the buffer to decrypt to */ - tvb_memcpy(tvb, packet_ntlmssp_info->verifier, - offset, encrypted_block_length); - - /* Do the actual decryption of the verifier */ - crypt_rc4(rc4_state, packet_ntlmssp_info->verifier, - encrypted_block_length); - - /* We setup a temporary buffer so we can re-encrypt the payload after - decryption. This is to update the opposite peer's RC4 state */ - peer_block = g_malloc(encrypted_block_length); - memcpy(peer_block, packet_ntlmssp_info->verifier, - encrypted_block_length); - crypt_rc4(rc4_state_peer, peer_block, encrypted_block_length); - g_free(peer_block); - - /* Mark the packet as decrypted so that subsequent attempts to dissect - the packet use the already decrypted payload instead of attempting - to decrypt again */ - packet_ntlmssp_info->verifier_decrypted = TRUE; } - /* Show the decrypted buffer in a new window */ decr_tvb = tvb_new_child_real_data(tvb, packet_ntlmssp_info->verifier, encrypted_block_length, @@ -1359,25 +2185,91 @@ decrypt_verifier(tvbuff_t *tvb, int offset, guint32 encrypted_block_length, encrypted_block_length, plurality(encrypted_block_length, "", "s")); decr_tree = proto_item_add_subtree (tf, ett_ntlmssp); + + if(( conv_ntlmssp_info->flags & NTLMSSP_NEGOTIATE_EXTENDED_SECURITY )) { + proto_tree_add_item (decr_tree, hf_ntlmssp_verf_hmacmd5, + decr_tvb, decrypted_offset, 8,TRUE); + decrypted_offset += 8; + + + + /* Incrementing sequence number of DCE conversation */ + proto_tree_add_item (decr_tree, hf_ntlmssp_verf_sequence, + decr_tvb, decrypted_offset, 4, TRUE); + decrypted_offset += 4; + } + else { - /* LKCL page 45 says this is a "reserved" field. I'm not sure if it's - garbage because it's some sort of nonce, or because there is a problem - with the verifier decryption routine. */ - proto_tree_add_item (decr_tree, hf_ntlmssp_verf_unknown1, - decr_tvb, decrypted_offset, 4, TRUE); - decrypted_offset += 4; - - /* CRC32 of the DCE fragment data */ - proto_tree_add_item (decr_tree, hf_ntlmssp_verf_crc32, - decr_tvb, decrypted_offset, 4, TRUE); - decrypted_offset += 4; - - /* Incrementing sequence number of DCE conversation */ - proto_tree_add_item (decr_tree, hf_ntlmssp_verf_sequence, - decr_tvb, decrypted_offset, 4, TRUE); - decrypted_offset += 4; + /* RANDOM PAD usually it's 0 */ + proto_tree_add_item (decr_tree, hf_ntlmssp_verf_randompad, + decr_tvb, decrypted_offset, 4, TRUE); + decrypted_offset += 4; + + /* CRC32 of the DCE fragment data */ + proto_tree_add_item (decr_tree, hf_ntlmssp_verf_crc32, + decr_tvb, decrypted_offset, 4, TRUE); + decrypted_offset += 4; + + /* Incrementing sequence number of DCE conversation */ + proto_tree_add_item (decr_tree, hf_ntlmssp_verf_sequence, + decr_tvb, decrypted_offset, 4, TRUE); + decrypted_offset += 4; + } } +/* Used when NTLMSSP is done over DCE/RPC because in this case verifier and real payload are not contigious*/ +static int +dissect_ntlmssp_payload_only(tvbuff_t *tvb, packet_info *pinfo, _U_ proto_tree *tree) +{ + volatile int offset = 0; + proto_tree *volatile ntlmssp_tree = NULL; + guint32 encrypted_block_length; + /* the magic ntlm is the identifier of a NTLMSSP packet that's 00 00 00 01 + */ + encrypted_block_length = tvb_length (tvb); + /* signature + seq + real payload */ + + /* Setup a new tree for the NTLMSSP payload */ + /* + if (tree) { + tf = proto_tree_add_item (tree, + hf_ntlmssp_verf, + tvb, offset, -1, FALSE); + + ntlmssp_tree = proto_item_add_subtree (tf, + ett_ntlmssp); + } + */ + /* + * Catch the ReportedBoundsError exception; the stuff we've been + * handed doesn't necessarily run to the end of the packet, it's + * an item inside a packet, so if it happens to be malformed (or + * we, or a dissector we call, has a bug), so that an exception + * is thrown, we want to report the error, but return and let + * our caller dissect the rest of the packet. + * + * If it gets a BoundsError, we can stop, as there's nothing more + * in the packet after our blob to see, so we just re-throw the + * exception. + */ + TRY { + /* Version number */ + + /* Try to decrypt */ + decrypt_data_payload (tvb, offset, encrypted_block_length, pinfo, ntlmssp_tree,NULL); + /* let's try to hook ourselves here */ + + } CATCH(BoundsError) { + RETHROW; + } CATCH(ReportedBoundsError) { + show_reported_bounds_error(tvb, pinfo, tree); + } ENDTRY; + + return offset; +} +/* Used when NTLMSSP is done over DCE/RPC because in this case verifier and real payload are not contigious + * But in fact this function could be merged with wrap_dissect_ntlmssp_verf because it's only used there + */ static int dissect_ntlmssp_verf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { @@ -1429,8 +2321,10 @@ dissect_ntlmssp_verf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) tvb, offset, encrypted_block_length, TRUE); /* Try to decrypt */ - decrypt_verifier (tvb, offset, encrypted_block_length, pinfo, ntlmssp_tree); + decrypt_verifier (tvb, offset, encrypted_block_length, pinfo, ntlmssp_tree,NULL); + /* let's try to hook ourselves here */ + offset += 12; offset += encrypted_block_length; } CATCH(BoundsError) { RETHROW; @@ -1442,13 +2336,27 @@ dissect_ntlmssp_verf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) } static tvbuff_t * +wrap_dissect_ntlmssp_payload_only(tvbuff_t *tvb,tvbuff_t *auth_tvb _U_, + int offset, packet_info *pinfo,dcerpc_auth_info *auth_info _U_) +{ + tvbuff_t *data_tvb; + + data_tvb = tvb_new_subset( + tvb, offset, tvb_length_remaining(tvb, offset), + tvb_length_remaining(tvb, offset)); + dissect_ntlmssp_payload_only(data_tvb, pinfo, NULL); + return pinfo->gssapi_decrypted_tvb; +} +/* +tvbuff_t * dissect_ntlmssp_encrypted_payload(tvbuff_t *data_tvb, tvbuff_t *auth_tvb _U_, int offset, packet_info *pinfo, dcerpc_auth_info *auth_info _U_) { - tvbuff_t *decr_tvb; /* Used to display decrypted buffer */ + / * gssapi_decrypted_tvb=NULL * / + tvbuff_t *decr_tvb; / * Used to display decrypted buffer * / guint8 *peer_block; conversation_t *conversation; guint32 encrypted_block_length; @@ -1456,39 +2364,38 @@ dissect_ntlmssp_encrypted_payload(tvbuff_t *data_tvb, rc4_state_struct *rc4_state_peer; ntlmssp_info *conv_ntlmssp_info = NULL; ntlmssp_packet_info *packet_ntlmssp_info = NULL; - encrypted_block_length = tvb_length_remaining (data_tvb, offset); - /* Check to see if we already have state for this packet */ + fprintf(stderr,"Called dissect_ntlmssp_encrypted_payload\n"); + / * Check to see if we already have state for this packet * / packet_ntlmssp_info = p_get_proto_data(pinfo->fd, proto_ntlmssp); if (packet_ntlmssp_info == NULL) { - /* We don't have any packet state, so create one */ + / * We don't have any packet state, so create one * / packet_ntlmssp_info = se_alloc(sizeof(ntlmssp_packet_info)); memset(packet_ntlmssp_info, 0, sizeof(ntlmssp_packet_info)); p_add_proto_data(pinfo->fd, proto_ntlmssp, packet_ntlmssp_info); } if (!packet_ntlmssp_info->payload_decrypted) { - /* Pull the challenge info from the conversation */ + / * Pull the challenge info from the conversation * / conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); if (conversation == NULL) { - /* There is no conversation, thus no encryption state */ + / * There is no conversation, thus no encryption state * / return NULL; - } + } conv_ntlmssp_info = conversation_get_proto_data(conversation, proto_ntlmssp); if (conv_ntlmssp_info == NULL) { - /* There is no NTLMSSP state tied to the conversation */ - return NULL; + / * There is no NTLMSSP state tied to the conversation * / + return NULL; } - - /* Get the pair of RC4 state structures. One is used for to decrypt the + / * Get the pair of RC4 state structures. One is used for to decrypt the payload. The other is used to re-encrypt the payload to represent - the peer */ - if (conv_ntlmssp_info->peer1_dest_port == pinfo->destport) { + the peer * / + if (conv_ntlmssp_info->server_dest_port == pinfo->destport) { rc4_state = get_encrypted_state(pinfo, 1); rc4_state_peer = get_encrypted_state(pinfo, 0); } else { @@ -1497,23 +2404,23 @@ dissect_ntlmssp_encrypted_payload(tvbuff_t *data_tvb, } if (rc4_state == NULL || rc4_state_peer == NULL) { - /* There is no encryption state, so we cannot decrypt */ + / * There is no encryption state, so we cannot decrypt * / return NULL; } - /* Store the decrypted contents in the packet state struct - (of course at this point, they aren't decrypted yet) */ + / * Store the decrypted contents in the packet state struct + (of course at this point, they aren't decrypted yet) * / packet_ntlmssp_info->decrypted_payload = tvb_memdup(data_tvb, offset, encrypted_block_length); decrypted_payloads = g_slist_prepend(decrypted_payloads, packet_ntlmssp_info->decrypted_payload); - /* Do the decryption of the payload */ + / * Do the decryption of the payload * / crypt_rc4(rc4_state, packet_ntlmssp_info->decrypted_payload, encrypted_block_length); - /* We setup a temporary buffer so we can re-encrypt the payload after - decryption. This is to update the opposite peer's RC4 state */ + / * We setup a temporary buffer so we can re-encrypt the payload after + decryption. This is to update the opposite peer's RC4 state * / peer_block = g_malloc(encrypted_block_length); memcpy(peer_block, packet_ntlmssp_info->decrypted_payload, encrypted_block_length); @@ -1523,7 +2430,7 @@ dissect_ntlmssp_encrypted_payload(tvbuff_t *data_tvb, packet_ntlmssp_info->payload_decrypted = TRUE; } - /* Show the decrypted buffer in a new window */ + / * Show the decrypted buffer in a new window * / decr_tvb = tvb_new_child_real_data(data_tvb, packet_ntlmssp_info->decrypted_payload, encrypted_block_length, encrypted_block_length); @@ -1532,13 +2439,28 @@ dissect_ntlmssp_encrypted_payload(tvbuff_t *data_tvb, return decr_tvb; } - +*/ static void free_payload(gpointer decrypted_payload, gpointer user_data _U_) { g_free(decrypted_payload); } +guint g_header_hash(gconstpointer pointer) { + guint32 crc = ~calculate_crc32c(pointer,16,CRC32C_PRELOAD); + /* Mat TBD fprintf(stderr,"Val: %u\n",crc);*/ + return crc; +} + +gboolean g_header_equal(gconstpointer pointer1, gconstpointer pointer2) { + if(!memcmp(pointer1,pointer2,16)) { + return TRUE; + } + else { + return FALSE; + } +} + static void ntlmssp_init_protocol(void) { @@ -1552,8 +2474,14 @@ ntlmssp_init_protocol(void) decrypted_payloads = NULL; } + if(hash_packet == NULL) { + hash_packet = g_hash_table_new(g_header_hash,g_header_equal); + } + } + + void proto_register_ntlmssp(void) { @@ -1606,7 +2534,7 @@ proto_register_ntlmssp(void) { &hf_ntlmssp_negotiate_flags_40000, { "Target Type Share", "ntlmssp.targettypeshare", FT_BOOLEAN, 32, TFS (&tfs_set_notset), NTLMSSP_TARGET_TYPE_SHARE, NULL, HFILL }}, { &hf_ntlmssp_negotiate_flags_80000, - { "Negotiate NTLM2 key", "ntlmssp.negotiatentlm2", FT_BOOLEAN, 32, TFS (&tfs_set_notset), NTLMSSP_NEGOTIATE_NTLM2, NULL, HFILL }}, + { "Negotiate Extended Security", "ntlmssp.negotiatentlm2", FT_BOOLEAN, 32, TFS (&tfs_set_notset), NTLMSSP_NEGOTIATE_EXTENDED_SECURITY, "", HFILL }}, { &hf_ntlmssp_negotiate_flags_100000, { "Negotiate Identify", "ntlmssp.negotiateidentify", FT_BOOLEAN, 32, TFS (&tfs_set_notset), NTLMSSP_NEGOTIATE_IDENTIFY, NULL, HFILL }}, { &hf_ntlmssp_negotiate_flags_200000, @@ -1647,8 +2575,10 @@ proto_register_ntlmssp(void) { "Calling workstation domain buffer", "ntlmssp.negotiate.domain.buffer", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }}, { &hf_ntlmssp_negotiate_domain, { "Calling workstation domain", "ntlmssp.negotiate.domain", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, - { &hf_ntlmssp_ntlm_challenge, - { "NTLM Challenge", "ntlmssp.ntlmchallenge", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, + { &hf_ntlmssp_ntlm_client_challenge, + { "NTLM Client Challenge", "ntlmssp.ntlmclientchallenge", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }}, + { &hf_ntlmssp_ntlm_server_challenge, + { "NTLM Server Challenge", "ntlmssp.ntlmserverchallenge", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }}, { &hf_ntlmssp_reserved, { "Reserved", "ntlmssp.reserved", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_ntlmssp_challenge_domain, @@ -1709,12 +2639,14 @@ proto_register_ntlmssp(void) { "Verifier Body", "ntlmssp.verf.body", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_ntlmssp_decrypted_payload, { "NTLM Decrypted Payload", "ntlmssp.decrypted_payload", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, - { &hf_ntlmssp_verf_unknown1, - { "Unknown 1", "ntlmssp.verf.unknown1", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }}, + { &hf_ntlmssp_verf_randompad, + { "Random Pad", "ntlmssp.verf.randompad", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }}, { &hf_ntlmssp_verf_crc32, { "Verifier CRC32", "ntlmssp.verf.crc32", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }}, + { &hf_ntlmssp_verf_hmacmd5, + { "HMAC MD5", "ntlmssp.verf.hmacmd5", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }}, { &hf_ntlmssp_verf_sequence, - { "Verifier Sequence Number", "ntlmssp.verf.sequence", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, + { "Sequence", "ntlmssp.verf.sequence", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }}, { &hf_ntlmssp_ntlmv2_response, { "NTLMv2 Response", "ntlmssp.ntlmv2response", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_ntlmssp_ntlmv2_response_hmac, @@ -1730,11 +2662,13 @@ proto_register_ntlmssp(void) { &hf_ntlmssp_ntlmv2_response_unknown, { "Unknown", "ntlmssp.ntlmv2response.unknown", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }}, { &hf_ntlmssp_ntlmv2_response_name, - { "Name", "ntlmssp.ntlmv2response.name", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, + { "Attribute", "ntlmssp.ntlmv2response.name", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }}, { &hf_ntlmssp_ntlmv2_response_name_type, - { "Name type", "ntlmssp.ntlmv2response.name.type", FT_UINT32, BASE_DEC, VALS(ntlm_name_types), 0x0, NULL, HFILL }}, + { "Attribute type", "ntlmssp.ntlmv2response.name.type", FT_UINT32, BASE_DEC, VALS(ntlm_name_types), 0x0, "", HFILL }}, { &hf_ntlmssp_ntlmv2_response_name_len, - { "Name len", "ntlmssp.ntlmv2response.name.len", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, + { "Value len", "ntlmssp.ntlmv2response.name.len", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }}, + { &hf_ntlmssp_ntlmv2_response_restriction, + { "Encoding restrictions", "ntlmssp.ntlmv2response.name.restrictions", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }}, { &hf_ntlmssp_ntlmv2_response_client_time, { "Client Time", "ntlmssp.ntlmv2response.client_time", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0, NULL, HFILL }} }; @@ -1769,6 +2703,8 @@ proto_register_ntlmssp(void) &nt_password); register_dissector("ntlmssp", dissect_ntlmssp, proto_ntlmssp); + new_register_dissector("ntlmssp_payload", dissect_ntlmssp_payload, proto_ntlmssp); + new_register_dissector("ntlmssp_data_only", dissect_ntlmssp_payload_only, proto_ntlmssp); new_register_dissector("ntlmssp_verf", dissect_ntlmssp_verf, proto_ntlmssp); } @@ -1794,7 +2730,6 @@ static int wrap_dissect_ntlmssp_verf(tvbuff_t *tvb, int offset, packet_info *pin auth_tvb = tvb_new_subset( tvb, offset, tvb_length_remaining(tvb, offset), tvb_length_remaining(tvb, offset)); - return dissect_ntlmssp_verf(auth_tvb, pinfo, tree); } @@ -1814,8 +2749,8 @@ static dcerpc_auth_subdissector_fns ntlmssp_seal_fns = { wrap_dissect_ntlmssp, /* AUTH3 */ wrap_dissect_ntlmssp_verf, /* Request verifier */ wrap_dissect_ntlmssp_verf, /* Response verifier */ - dissect_ntlmssp_encrypted_payload, /* Request data */ - dissect_ntlmssp_encrypted_payload /* Response data */ + wrap_dissect_ntlmssp_payload_only, /* Request data */ + wrap_dissect_ntlmssp_payload_only /* Response data */ }; void |