aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-ntlmssp.c
diff options
context:
space:
mode:
authorsahlberg <sahlberg@f5534014-38df-0310-8fa8-9805f1628bb7>2009-10-06 09:13:57 +0000
committersahlberg <sahlberg@f5534014-38df-0310-8fa8-9805f1628bb7>2009-10-06 09:13:57 +0000
commit860bdf18ff750a28dccc1b31c6b199dd60889622 (patch)
tree71c2eccb11b13f45035c18e5b791f395d4d37c0e /epan/dissectors/packet-ntlmssp.c
parent0a8632d53f31b7ab0e677bb3e3f2898e6daa0093 (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.c1389
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