aboutsummaryrefslogtreecommitdiffstats
path: root/epan
diff options
context:
space:
mode:
authorBill Meier <wmeier@newsguy.com>2012-08-16 17:03:07 +0000
committerBill Meier <wmeier@newsguy.com>2012-08-16 17:03:07 +0000
commitcf706ca547250734383228381f9e2ae4d6091840 (patch)
treefc26cc8b309be6e5e5707152c946ac34a4109edc /epan
parent832b999c2c9791dab610164d310d582bb6367fcf (diff)
From Stefan Metzmacher: Updates for the SMB2/3
This patches add some missing things for SMB2/3 and support for decryption of SMB3 traffic https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=7645 From me: Change an initializer from C99 to C89 style (since the Microsoft compiler doesn't support C99). svn path=/trunk/; revision=44542
Diffstat (limited to 'epan')
-rw-r--r--epan/dissectors/packet-nbns.c2
-rw-r--r--epan/dissectors/packet-ntlmssp.c22
-rw-r--r--epan/dissectors/packet-ntlmssp.h10
-rw-r--r--epan/dissectors/packet-smb2.c415
-rw-r--r--epan/dissectors/packet-smb2.h8
-rw-r--r--epan/dissectors/packet-windows-common.c1
6 files changed, 402 insertions, 56 deletions
diff --git a/epan/dissectors/packet-nbns.c b/epan/dissectors/packet-nbns.c
index bec18b4cc0..68a70b15bd 100644
--- a/epan/dissectors/packet-nbns.c
+++ b/epan/dissectors/packet-nbns.c
@@ -1691,8 +1691,6 @@ dissect_nbss(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
&& tvb_get_guint8(tvb,offset+6) == 'M'
&& tvb_get_guint8(tvb,offset+7) == 'B') {
is_cifs = TRUE;
- } else {
- is_cifs = FALSE;
}
/*
diff --git a/epan/dissectors/packet-ntlmssp.c b/epan/dissectors/packet-ntlmssp.c
index 5fb72c18ae..aca219bd58 100644
--- a/epan/dissectors/packet-ntlmssp.c
+++ b/epan/dissectors/packet-ntlmssp.c
@@ -57,19 +57,11 @@
static int ntlmssp_tap = -1;
-/* Message types */
-
-#define NTLMSSP_NEGOTIATE 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"
-#define NTLMSSP_KEY_LEN 16
-
static const value_string ntlmssp_message_types[] = {
{ NTLMSSP_NEGOTIATE, "NTLMSSP_NEGOTIATE" },
{ NTLMSSP_CHALLENGE, "NTLMSSP_CHALLENGE" },
@@ -631,6 +623,7 @@ create_ntlmssp_v2_key(const char *nt_password _U_, const guint8 *serverchallenge
memcpy(sessionkey,keyexchangekey,NTLMSSP_KEY_LEN);
}
+ memcpy(ntlmssph->session_key, sessionkey, NTLMSSP_KEY_LEN);
}
/* Create an NTLMSSP version 1 key
* That is more complicated logic and methods and user challenge as well.
@@ -640,7 +633,8 @@ create_ntlmssp_v2_key(const char *nt_password _U_, const guint8 *serverchallenge
static void
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)
+ const guint8 *ref_nt_challenge_response,const guint8 *ref_lm_challenge_response,
+ ntlmssp_header_t *ntlmssph)
{
unsigned char lm_password_upper[NTLMSSP_KEY_LEN];
unsigned char lm_password_hash[NTLMSSP_KEY_LEN];
@@ -767,6 +761,7 @@ create_ntlmssp_v1_key(const char *nt_password, const guint8 *serverchallenge, co
{
memcpy(sessionkey,keyexchangekey,NTLMSSP_KEY_LEN);
}
+ memcpy(ntlmssph->session_key, sessionkey, NTLMSSP_KEY_LEN);
}
static void
@@ -1483,7 +1478,6 @@ dissect_ntlmssp_challenge (tvbuff_t *tvb, packet_info *pinfo, int offset,
ntlmssp_info *conv_ntlmssp_info = NULL;
conversation_t *conversation;
gboolean unicode_strings = FALSE;
- guint8 challenge[8];
guint8 tmp[8];
guint8 sspkey[NTLMSSP_KEY_LEN]; /* NTLMSSP cipher key */
int ssp_key_len; /* Either 8 or 16 (40 bit or 128) */
@@ -1532,7 +1526,6 @@ dissect_ntlmssp_challenge (tvbuff_t *tvb, packet_info *pinfo, int offset,
/* 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
@@ -1544,7 +1537,7 @@ dissect_ntlmssp_challenge (tvbuff_t *tvb, packet_info *pinfo, int offset,
if (!(conv_ntlmssp_info->flags & NTLMSSP_NEGOTIATE_EXTENDED_SECURITY))
{
conv_ntlmssp_info->rc4_state_initialized = 0;
- create_ntlmssp_v1_key(gbl_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);
+ create_ntlmssp_v1_key(gbl_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,ntlmssph);
if( memcmp(sspkey,gbl_zeros,NTLMSSP_KEY_LEN) != 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);
@@ -1823,7 +1816,7 @@ dissect_ntlmssp_auth (tvbuff_t *tvb, packet_info *pinfo, int offset,
else
{
memcpy(conv_ntlmssp_info->client_challenge,conv_ntlmssp_info->lm_response.contents,8);
- create_ntlmssp_v1_key(gbl_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);
+ create_ntlmssp_v1_key(gbl_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,ntlmssph);
}
/* ssp is the exported session key */
if( memcmp(sspkey,gbl_zeros,NTLMSSP_KEY_LEN) != 0) {
@@ -2134,6 +2127,7 @@ dissect_ntlmssp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
ntlmssph->domain_name=NULL;
ntlmssph->acct_name=NULL;
ntlmssph->host_name=NULL;
+ memset(ntlmssph->session_key, 0, NTLMSSP_KEY_LEN);
/* Setup a new tree for the NTLMSSP payload */
if (tree) {
@@ -2207,7 +2201,7 @@ 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);
}
static gboolean
diff --git a/epan/dissectors/packet-ntlmssp.h b/epan/dissectors/packet-ntlmssp.h
index beef83c425..c93cbc0b8f 100644
--- a/epan/dissectors/packet-ntlmssp.h
+++ b/epan/dissectors/packet-ntlmssp.h
@@ -26,6 +26,15 @@
#ifndef __PACKET_NTLMSSP_H__
#define __PACKET_NTLMSSP_H__
+/* Message types */
+
+#define NTLMSSP_NEGOTIATE 1
+#define NTLMSSP_CHALLENGE 2
+#define NTLMSSP_AUTH 3
+#define NTLMSSP_UNKNOWN 4
+
+#define NTLMSSP_KEY_LEN 16
+
/* Dissect a ntlmv2 response */
int
@@ -38,6 +47,7 @@ typedef struct _ntlmssp_header_t {
const char *domain_name;
const char *acct_name;
const char *host_name;
+ guint8 session_key[NTLMSSP_KEY_LEN];
} ntlmssp_header_t;
#endif
diff --git a/epan/dissectors/packet-smb2.c b/epan/dissectors/packet-smb2.c
index 050fffa05f..ac37a2c60e 100644
--- a/epan/dissectors/packet-smb2.c
+++ b/epan/dissectors/packet-smb2.c
@@ -48,6 +48,12 @@
#include "packet-dcerpc-nt.h"
#include <string.h>
+#include <glib.h>
+/* Use libgcrypt for cipher libraries. */
+#ifdef HAVE_LIBGCRYPT
+#include <gcrypt.h>
+#endif /* HAVE_LIBGCRYPT */
+
static char smb_header_label[] = "SMB2 Header";
static char smb_transform_header_label[] = "SMB2 Transform Header";
@@ -69,6 +75,7 @@ static int hf_smb2_flags_async_cmd = -1;
static int hf_smb2_flags_dfs_op = -1;
static int hf_smb2_flags_chained = -1;
static int hf_smb2_flags_signature = -1;
+static int hf_smb2_flags_replay_operation = -1;
static int hf_smb2_chain_offset = -1;
static int hf_smb2_security_blob = -1;
static int hf_smb2_ioctl_in_data = -1;
@@ -266,6 +273,8 @@ static int hf_smb2_share_caching = -1;
static int hf_smb2_share_caps = -1;
static int hf_smb2_share_caps_dfs = -1;
static int hf_smb2_share_caps_continuous_availability = -1;
+static int hf_smb2_share_caps_scaleout = -1;
+static int hf_smb2_share_caps_cluster = -1;
static int hf_smb2_create_flags = -1;
static int hf_smb2_lock_count = -1;
static int hf_smb2_min_count = -1;
@@ -314,7 +323,6 @@ static int hf_smb2_transform_signature = -1;
static int hf_smb2_transform_nonce = -1;
static int hf_smb2_transform_msg_size = -1;
static int hf_smb2_transform_reserved = -1;
-static int hf_smb2_transform_sessionid = -1;
static int hf_smb2_encryption_aes128_ccm = -1;
static int hf_smb2_transform_enc_alg = -1;
static int hf_smb2_transform_encyrpted_data = -1;
@@ -598,6 +606,43 @@ smb2_sesid_info_hash(gconstpointer k)
return hash;
}
+static void smb2_key_derivation(const guint8 *KI _U_, guint32 KI_len _U_,
+ const guint8 *Label _U_, guint32 Label_len _U_,
+ const guint8 *Context _U_, guint32 Context_len _U_,
+ guint8 KO[16])
+{
+#ifdef HAVE_LIBGCRYPT
+ gcry_md_hd_t hd = NULL;
+ guint8 buf[4];
+ guint8 *digest = NULL;
+
+ /*
+ * a simplified version of
+ * "NIST Special Publication 800-108" section 5.1
+ * using hmac-sha256.
+ */
+ gcry_md_open(&hd, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
+ gcry_md_setkey(hd, KI, KI_len);
+
+ memset(buf, 0, sizeof(buf));
+ buf[3] = 1;
+ gcry_md_write(hd, buf, sizeof(buf));
+ gcry_md_write(hd, Label, Label_len);
+ gcry_md_write(hd, buf, 1);
+ gcry_md_write(hd, Context, Context_len);
+ buf[3] = 128;
+ gcry_md_write(hd, buf, sizeof(buf));
+
+ digest = gcry_md_read(hd, GCRY_MD_SHA256);
+
+ memcpy(KO, digest, 16);
+
+ gcry_md_close(hd);
+#else
+ memset(KO, 0, 16);
+#endif
+}
+
static int dissect_smb2_file_info_0f(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset, smb2_info_t *si);
@@ -860,6 +905,11 @@ static const true_false_string tfs_flags_signature = {
"This pdu is NOT signed"
};
+static const true_false_string tfs_flags_replay_operation = {
+ "This is a REPLAY OPEARATION",
+ "This is NOT a replay operation"
+};
+
static const true_false_string tfs_cap_dfs = {
"This host supports DFS",
"This host does NOT support DFS"
@@ -919,6 +969,8 @@ static const value_string smb2_ioctl_vals[] = {
{0x0011C017, "FSCTL_PIPE_TRANSCEIVE"},
{0x001401D4, "FSCTL_LMR_REQUEST_RESILIENCY"},
{0x001401FC, "FSCTL_QUERY_NETWORK_INTERFACE_INFO"},
+ {0x00140200, "FSCTL_VALIDATE_NEGOTIATE_INFO_224"},
+ {0x00140204, "FSCTL_VALIDATE_NEGOTIATE_INFO"},
{0x00144064, "FSCTL_GET_SHADOW_COPY_DATA"},
{0x000900C0, "FSCTL_CREATE_OR_GET_OBJECT_ID"},
{0x0009009C, "FSCTL_GET_OBJECT_ID"},
@@ -1080,9 +1132,26 @@ dissect_smb2_ioctl_function(tvbuff_t *tvb, packet_info *pinfo, proto_tree *paren
if (ioctlfunc)
*ioctlfunc=ioctl_function;
if(ioctl_function){
+ const gchar *unknown = "unknown";
+ const gchar *ioctl_name = val_to_str_const(ioctl_function,
+ smb2_ioctl_vals,
+ unknown);
+
+ /*
+ * val_to_str_const() doesn't work with a unknown == NULL
+ */
+ if (ioctl_name == unknown) {
+ ioctl_name = NULL;
+ }
+
+ if (check_col(pinfo->cinfo, COL_INFO) && ioctl_name != NULL) {
+ col_append_fstr(
+ pinfo->cinfo, COL_INFO, " %s", ioctl_name);
+ }
+
/* device */
proto_tree_add_item(tree, hf_smb2_ioctl_function_device, tvb, offset, 4, ENC_LITTLE_ENDIAN);
- if (check_col(pinfo->cinfo, COL_INFO)){
+ if (check_col(pinfo->cinfo, COL_INFO) && ioctl_name == NULL) {
col_append_fstr(
pinfo->cinfo, COL_INFO, " %s",
val_to_str((ioctl_function>>16)&0xffff, smb2_ioctl_device_vals,
@@ -1094,7 +1163,7 @@ dissect_smb2_ioctl_function(tvbuff_t *tvb, packet_info *pinfo, proto_tree *paren
/* function */
proto_tree_add_item(tree, hf_smb2_ioctl_function_function, tvb, offset, 4, ENC_LITTLE_ENDIAN);
- if (check_col(pinfo->cinfo, COL_INFO)){
+ if (check_col(pinfo->cinfo, COL_INFO) && ioctl_name == NULL) {
col_append_fstr(
pinfo->cinfo, COL_INFO, " Function:0x%04x",
(ioctl_function>>2)&0x0fff);
@@ -2111,8 +2180,10 @@ dissect_smb2_share_flags(proto_tree *tree, tvbuff_t *tvb, int offset)
return offset;
}
-#define SHARE_CAPS_DFS 0x00000008
-#define SHARE_CAPS_CONTINUOUS_AVAILABILITY 0x00000010
+#define SHARE_CAPS_DFS 0x00000008
+#define SHARE_CAPS_CONTINUOUS_AVAILABILITY 0x00000010
+#define SHARE_CAPS_SCALEOUT 0x00000020
+#define SHARE_CAPS_CLUSTER 0x00000040
static int
dissect_smb2_share_caps(proto_tree *tree, tvbuff_t *tvb, int offset)
@@ -2120,6 +2191,8 @@ dissect_smb2_share_caps(proto_tree *tree, tvbuff_t *tvb, int offset)
static const int *sc_fields[] = {
&hf_smb2_share_caps_dfs,
&hf_smb2_share_caps_continuous_availability,
+ &hf_smb2_share_caps_scaleout,
+ &hf_smb2_share_caps_cluster,
NULL
};
@@ -2200,13 +2273,32 @@ dissect_smb2_session_setup_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree
if(!pinfo->fd->flags.visited){
idx=0;
while((ntlmssph=fetch_tapped_data(ntlmssp_tap_id, idx++)) != NULL){
- if(ntlmssph && ntlmssph->type==3){
+ if(ntlmssph && ntlmssph->type==NTLMSSP_AUTH){
+ static const gint8 zeros[NTLMSSP_KEY_LEN];
smb2_sesid_info_t *sesid;
sesid=se_alloc(sizeof(smb2_sesid_info_t));
sesid->sesid=si->sesid;
sesid->acct_name=se_strdup(ntlmssph->acct_name);
sesid->domain_name=se_strdup(ntlmssph->domain_name);
sesid->host_name=se_strdup(ntlmssph->host_name);
+ if (memcmp(ntlmssph->session_key, zeros, NTLMSSP_KEY_LEN) != 0) {
+ smb2_key_derivation(ntlmssph->session_key,
+ NTLMSSP_KEY_LEN,
+ "SMB2AESCCM", 11,
+ "ServerIn ", 10,
+ sesid->server_decryption_key);
+ smb2_key_derivation(ntlmssph->session_key,
+ NTLMSSP_KEY_LEN,
+ "SMB2AESCCM", 11,
+ "ServerOut", 10,
+ sesid->client_decryption_key);
+ } else {
+ memset(sesid->server_decryption_key, 0,
+ sizeof(sesid->server_decryption_key));
+ memset(sesid->client_decryption_key, 0,
+ sizeof(sesid->client_decryption_key));
+ }
+ sesid->server_port = pinfo->destport;
sesid->auth_frame=pinfo->fd->num;
sesid->tids= g_hash_table_new(smb2_tid_info_hash, smb2_tid_info_equal);
g_hash_table_insert(si->conv->sesids, sesid, sesid);
@@ -4097,6 +4189,89 @@ dissect_smb2_FSCTL_QUERY_NETWORK_INTERFACE_INFO(tvbuff_t *tvb, packet_info *pinf
}
static void
+dissect_smb2_FSCTL_VALIDATE_NEGOTIATE_INFO_224(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset _U_, gboolean data_in)
+{
+ /*
+ * This is only used by Windows 8 beta
+ */
+ if(data_in){
+ /* capabilities */
+ offset = dissect_smb2_capabilities(tree, tvb, offset);
+
+ /* client guid */
+ proto_tree_add_item(tree, hf_smb2_client_guid, tvb, offset, 16, ENC_LITTLE_ENDIAN);
+ offset += 16;
+
+ /* security mode, skip second byte */
+ offset = dissect_smb2_secmode(tree, tvb, offset);
+ offset++;
+
+ /* dialect */
+ proto_tree_add_item(tree, hf_smb2_dialect, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+ offset += 2;
+ } else {
+ /* capabilities */
+ offset = dissect_smb2_capabilities(tree, tvb, offset);
+
+ /* server guid */
+ proto_tree_add_item(tree, hf_smb2_server_guid, tvb, offset, 16, ENC_LITTLE_ENDIAN);
+ offset += 16;
+
+ /* security mode, skip second byte */
+ offset = dissect_smb2_secmode(tree, tvb, offset);
+ offset++;
+
+ /* dialect */
+ proto_tree_add_item(tree, hf_smb2_dialect, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+ offset += 2;
+ }
+}
+
+static void
+dissect_smb2_FSCTL_VALIDATE_NEGOTIATE_INFO(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset _U_, gboolean data_in)
+{
+ if(data_in){
+ guint16 dc;
+
+ /* capabilities */
+ offset = dissect_smb2_capabilities(tree, tvb, offset);
+
+ /* client guid */
+ proto_tree_add_item(tree, hf_smb2_client_guid, tvb, offset, 16, ENC_LITTLE_ENDIAN);
+ offset += 16;
+
+ /* security mode, skip second byte */
+ offset = dissect_smb2_secmode(tree, tvb, offset);
+ offset++;
+
+ /* dialect count */
+ dc = tvb_get_letohs(tvb, offset);
+ proto_tree_add_item(tree, hf_smb2_dialect_count, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+ offset += 2;
+
+ for(;dc>0;dc--){
+ proto_tree_add_item(tree, hf_smb2_dialect, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+ offset += 2;
+ }
+ } else {
+ /* capabilities */
+ offset = dissect_smb2_capabilities(tree, tvb, offset);
+
+ /* server guid */
+ proto_tree_add_item(tree, hf_smb2_server_guid, tvb, offset, 16, ENC_LITTLE_ENDIAN);
+ offset += 16;
+
+ /* security mode, skip second byte */
+ offset = dissect_smb2_secmode(tree, tvb, offset);
+ offset++;
+
+ /* dialect */
+ proto_tree_add_item(tree, hf_smb2_dialect, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+ offset += 2;
+ }
+}
+
+static void
dissect_smb2_FSCTL_GET_SHADOW_COPY_DATA(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, gboolean data_in)
{
guint32 num_volumes;
@@ -4280,6 +4455,12 @@ dissect_smb2_ioctl_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, pro
case 0x001401FC: /* FSCTL_QUERY_NETWORK_INTERFACE_INFO */
dissect_smb2_FSCTL_QUERY_NETWORK_INTERFACE_INFO(tvb, pinfo, tree, 0, data_in);
break;
+ case 0x00140200: /* FSCTL_VALIDATE_NEGOTIATE_INFO_224 */
+ dissect_smb2_FSCTL_VALIDATE_NEGOTIATE_INFO_224(tvb, pinfo, tree, 0, data_in);
+ break;
+ case 0x00140204: /* FSCTL_VALIDATE_NEGOTIATE_INFO */
+ dissect_smb2_FSCTL_VALIDATE_NEGOTIATE_INFO(tvb, pinfo, tree, 0, data_in);
+ break;
case 0x00144064: /* FSCTL_GET_SHADOW_COPY_DATA */
dissect_smb2_FSCTL_GET_SHADOW_COPY_DATA(tvb, pinfo, tree, 0, data_in);
break;
@@ -5014,35 +5195,51 @@ typedef struct create_context_data_dissectors {
struct create_context_data_tag_dissectors {
const char *tag;
+ const char *val;
create_context_data_dissectors_t dissectors;
};
struct create_context_data_tag_dissectors create_context_dissectors_array[] = {
- { "ExtA", { dissect_smb2_ExtA_buffer_request, dissect_smb2_ExtA_buffer_response } },
- { "SecD", { dissect_smb2_SecD_buffer_request, dissect_smb2_SecD_buffer_response } },
- { "AlSi", { dissect_smb2_AlSi_buffer_request, dissect_smb2_AlSi_buffer_response } },
- { "MxAc", { dissect_smb2_MxAc_buffer_request, dissect_smb2_MxAc_buffer_response } },
- { "DHnQ", { dissect_smb2_DHnQ_buffer_request, dissect_smb2_DHnQ_buffer_response } },
- { "DHnC", { dissect_smb2_DHnC_buffer_request, dissect_smb2_DHnC_buffer_response } },
- { "DH2Q", { dissect_smb2_DH2Q_buffer_request, dissect_smb2_DH2Q_buffer_response } },
- { "DH2C", { dissect_smb2_DH2C_buffer_request, dissect_smb2_DH2C_buffer_response } },
- { "TWrp", { dissect_smb2_TWrp_buffer_request, dissect_smb2_TWrp_buffer_response } },
- { "QFid", { dissect_smb2_QFid_buffer_request, dissect_smb2_QFid_buffer_response } },
- { "RqLs", { dissect_smb2_RqLs_buffer_request, dissect_smb2_RqLs_buffer_response } },
- { "744D142E-46FA-0890-4AF7-A7EF6AA6BC45",
+ { "ExtA", "SMB2_CREATE_EA_BUFFER",
+ { dissect_smb2_ExtA_buffer_request, dissect_smb2_ExtA_buffer_response } },
+ { "SecD", "SMB2_CREATE_SD_BUFFER",
+ { dissect_smb2_SecD_buffer_request, dissect_smb2_SecD_buffer_response } },
+ { "AlSi", "SMB2_CREATE_ALLOCATION_SIZE",
+ { dissect_smb2_AlSi_buffer_request, dissect_smb2_AlSi_buffer_response } },
+ { "MxAc", "SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQUEST",
+ { dissect_smb2_MxAc_buffer_request, dissect_smb2_MxAc_buffer_response } },
+ { "DHnQ", "SMB2_CREATE_DURABLE_HANDLE_REQUEST",
+ { dissect_smb2_DHnQ_buffer_request, dissect_smb2_DHnQ_buffer_response } },
+ { "DHnC", "SMB2_CREATE_DURABLE_HANDLE_RECONNECT",
+ { dissect_smb2_DHnC_buffer_request, dissect_smb2_DHnC_buffer_response } },
+ { "DH2Q", "SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2",
+ { dissect_smb2_DH2Q_buffer_request, dissect_smb2_DH2Q_buffer_response } },
+ { "DH2C", "SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2",
+ { dissect_smb2_DH2C_buffer_request, dissect_smb2_DH2C_buffer_response } },
+ { "TWrp", "SMB2_CREATE_TIMEWARP_TOKEN",
+ { dissect_smb2_TWrp_buffer_request, dissect_smb2_TWrp_buffer_response } },
+ { "QFid", "SMB2_CREATE_QUERY_ON_DISK_ID",
+ { dissect_smb2_QFid_buffer_request, dissect_smb2_QFid_buffer_response } },
+ { "RqLs", "SMB2_CREATE_REQUEST_LEASE",
+ { dissect_smb2_RqLs_buffer_request, dissect_smb2_RqLs_buffer_response } },
+ { "744D142E-46FA-0890-4AF7-A7EF6AA6BC45", "SMB2_CREATE_APP_INSTANCE_ID",
{ dissect_smb2_APP_INSTANCE_buffer_request,
dissect_smb2_APP_INSTANCE_buffer_response } }
};
-static struct create_context_data_dissectors*
-get_create_context_data_dissectors(const char *tag)
+static struct create_context_data_tag_dissectors*
+get_create_context_data_tag_dissectors(const char *tag)
{
+ static struct create_context_data_tag_dissectors INVALID = {
+ NULL, "<invalid>", { NULL, NULL }
+ };
+
size_t i;
for (i=0; i<array_length(create_context_dissectors_array); i++) {
if (!strcmp(tag, create_context_dissectors_array[i].tag))
- return &create_context_dissectors_array[i].dissectors;
+ return &create_context_dissectors_array[i];
}
- return NULL;
+ return &INVALID;
}
static void
@@ -5059,6 +5256,7 @@ dissect_smb2_create_extra_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *pa
proto_item *sub_item=NULL;
proto_tree *sub_tree=NULL;
proto_item *parent_item=NULL;
+ struct create_context_data_tag_dissectors *tag_dissectors;
chain_offset=tvb_get_letohl(tvb, offset);
if (chain_offset) {
@@ -5084,11 +5282,13 @@ dissect_smb2_create_extra_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *pa
/* tag string */
tag = dissect_smb2_olb_string(pinfo, sub_tree, tvb, &tag_olb, OLB_TYPE_ASCII_STRING);
+ tag_dissectors = get_create_context_data_tag_dissectors(tag);
+
proto_item_append_text(parent_item, " %s", tag);
- proto_item_append_text(sub_item, ": %s", tag);
+ proto_item_append_text(sub_item, ": %s \"%s\"", tag_dissectors->val, tag);
/* data */
- dissectors = get_create_context_data_dissectors(tag);
+ dissectors = &tag_dissectors->dissectors;
if (dissectors)
dissector = (si->flags & SMB2_FLAGS_RESPONSE) ? dissectors->response : dissectors->request;
@@ -6059,13 +6259,28 @@ static smb2_function smb2_dissector[256] = {
#define ENC_ALG_aes128_ccm 0x0001
static int
-dissect_smb2_transform_header(packet_info *pinfo _U_, proto_tree *tree, tvbuff_t *tvb, int offset, smb2_transform_info_t *sti)
+dissect_smb2_transform_header(packet_info *pinfo _U_, proto_tree *tree,
+ tvbuff_t *tvb, int offset,
+ smb2_transform_info_t *sti,
+ tvbuff_t **enc_tvb, tvbuff_t **plain_tvb)
{
+ proto_item *sesid_item=NULL;
+ proto_tree *sesid_tree=NULL;
+ smb2_sesid_info_t sesid_key;
+ int sesid_offset;
+ guint8 *plain_data=NULL;
+#ifdef HAVE_LIBGCRYPT
+ guint8 *decryption_key=NULL;
+#endif
+ proto_item *item;
static const int *sf_fields[] = {
&hf_smb2_encryption_aes128_ccm,
NULL
};
+ *enc_tvb = NULL;
+ *plain_tvb = NULL;
+
/* signature */
proto_tree_add_item(tree, hf_smb2_transform_signature, tvb, offset, 16, ENC_LITTLE_ENDIAN);
offset += 16;
@@ -6090,10 +6305,103 @@ dissect_smb2_transform_header(packet_info *pinfo _U_, proto_tree *tree, tvbuff_t
offset += 2;
/* session ID */
- proto_tree_add_item(tree, hf_smb2_transform_sessionid, tvb, offset, 8, ENC_LITTLE_ENDIAN);
- tvb_memcpy(tvb, sti->session_id, offset, 8);
+ sesid_offset = offset;
+ sti->sesid=tvb_get_letoh64(tvb, offset);
+ sesid_item=proto_tree_add_item(tree, hf_smb2_sesid, tvb, offset, 8, ENC_LITTLE_ENDIAN);
+ if(tree){
+ sesid_tree=proto_item_add_subtree(sesid_item, ett_smb2_sesid_tree);
+ }
offset += 8;
+ /* now we need to first lookup the uid session */
+ sesid_key.sesid=sti->sesid;
+ sti->session=g_hash_table_lookup(sti->conv->sesids, &sesid_key);
+
+ if (sti->session != NULL && sti->session->auth_frame != (guint32)-1) {
+ item=proto_tree_add_string(sesid_tree, hf_smb2_acct_name, tvb, sesid_offset, 0, sti->session->acct_name);
+ PROTO_ITEM_SET_GENERATED(item);
+ proto_item_append_text(sesid_item, " Acct:%s", sti->session->acct_name);
+
+ item=proto_tree_add_string(sesid_tree, hf_smb2_domain_name, tvb, sesid_offset, 0, sti->session->domain_name);
+ PROTO_ITEM_SET_GENERATED(item);
+ proto_item_append_text(sesid_item, " Domain:%s", sti->session->domain_name);
+
+ item=proto_tree_add_string(sesid_tree, hf_smb2_host_name, tvb, sesid_offset, 0, sti->session->host_name);
+ PROTO_ITEM_SET_GENERATED(item);
+ proto_item_append_text(sesid_item, " Host:%s", sti->session->host_name);
+
+ item=proto_tree_add_uint(sesid_tree, hf_smb2_auth_frame, tvb, sesid_offset, 0, sti->session->auth_frame);
+ PROTO_ITEM_SET_GENERATED(item);
+ }
+
+#ifdef HAVE_LIBGCRYPT
+ if (sti->session != NULL && sti->alg == ENC_ALG_aes128_ccm) {
+ static const guint8 zeros[16];
+
+ if (pinfo->destport == sti->session->server_port) {
+ decryption_key = sti->session->server_decryption_key;
+ } else {
+ decryption_key = sti->session->client_decryption_key;
+ }
+
+ if (memcmp(decryption_key, zeros, 16) == 0) {
+ decryption_key = NULL;
+ }
+ }
+
+ if (decryption_key != NULL) {
+ gcry_cipher_hd_t cipher_hd = NULL;
+ guint8 A_1[16] = {
+ 3, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1
+ };
+
+ memcpy(&A_1[1], sti->nonce, 15 - 4);
+
+ plain_data = tvb_memdup(tvb, offset, sti->size);
+
+ /* Open the cipher. */
+ if (gcry_cipher_open(&cipher_hd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CTR, 0)) {
+ g_free(plain_data);
+ plain_data = NULL;
+ goto done_decryption;
+ }
+
+ /* Set the key and initial value. */
+ if (gcry_cipher_setkey(cipher_hd, decryption_key, 16)) {
+ gcry_cipher_close(cipher_hd);
+ g_free(plain_data);
+ plain_data = NULL;
+ goto done_decryption;
+ }
+ if (gcry_cipher_setctr(cipher_hd, A_1, 16)) {
+ gcry_cipher_close(cipher_hd);
+ g_free(plain_data);
+ plain_data = NULL;
+ goto done_decryption;
+ }
+
+ if (gcry_cipher_encrypt(cipher_hd, plain_data, sti->size, NULL, 0)) {
+ gcry_cipher_close(cipher_hd);
+ g_free(plain_data);
+ plain_data = NULL;
+ goto done_decryption;
+ }
+
+ /* Done with the cipher. */
+ gcry_cipher_close(cipher_hd);
+ }
+done_decryption:
+#endif
+ *enc_tvb = tvb_new_subset(tvb, offset, sti->size, sti->size);
+
+ if (plain_data != NULL) {
+ *plain_tvb = tvb_new_child_real_data(*enc_tvb, plain_data, sti->size, sti->size);
+ tvb_set_free_cb(*plain_tvb, g_free);
+ add_new_data_source(pinfo, *plain_tvb, "Decrypted SMB3");
+ }
+
+ offset += sti->size;
return offset;
}
@@ -6282,6 +6590,7 @@ dissect_smb2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, gboolea
conversation_add_proto_data(conversation, proto_smb2, si->conv);
}
+ sti->conv = si->conv;
col_set_str(pinfo->cinfo, COL_PROTOCOL, "SMB2");
if (check_col(pinfo->cinfo, COL_INFO)){
@@ -6306,11 +6615,12 @@ dissect_smb2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, gboolea
}
/* Decode the header */
- /* SMB2 marker */
- proto_tree_add_text(header_tree, tvb, offset, 4, "Server Component: SMB2");
- offset += 4;
if (!smb2_transform_header) {
+ /* SMB2 marker */
+ proto_tree_add_text(header_tree, tvb, offset, 4, "Server Component: SMB2");
+ offset += 4;
+
/* we need the flags before we know how to parse the credits field */
si->flags=tvb_get_letohl(tvb, offset+12);
@@ -6354,6 +6664,7 @@ dissect_smb2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, gboolea
"Flags: 0x%08x", si->flags);
flags_tree = proto_item_add_subtree(flags_item, ett_smb2_flags);
}
+ proto_tree_add_boolean(flags_tree, hf_smb2_flags_replay_operation, tvb, offset, 4, si->flags);
proto_tree_add_boolean(flags_tree, hf_smb2_flags_dfs_op, tvb, offset, 4, si->flags);
proto_tree_add_boolean(flags_tree, hf_smb2_flags_signature, tvb, offset, 4, si->flags);
proto_tree_add_boolean(flags_tree, hf_smb2_flags_chained, tvb, offset, 4, si->flags);
@@ -6482,13 +6793,30 @@ dissect_smb2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, gboolea
} else {
proto_item *enc_item=NULL;
proto_tree *enc_tree=NULL;
+ tvbuff_t *enc_tvb=NULL;
+ tvbuff_t *plain_tvb=NULL;
+
+ /* SMB2_TRANSFORM marker */
+ proto_tree_add_text(header_tree, tvb, offset, 4, "Server Component: SMB2_TRANSFORM");
+ offset += 4;
+
+ offset = dissect_smb2_transform_header(pinfo, header_tree, tvb, offset, sti,
+ &enc_tvb, &plain_tvb);
- offset = dissect_smb2_transform_header(pinfo, header_tree, tvb, offset, sti);
- enc_item = proto_tree_add_text(tree, tvb, offset, -1, "Encrypted SMB2 data");
+ enc_item = proto_tree_add_text(tree, enc_tvb, 0, sti->size, "Encrypted SMB3 data");
enc_tree = proto_item_add_subtree(enc_item, ett_smb2_encrypted);
- proto_tree_add_item(enc_tree, hf_smb2_transform_encyrpted_data, tvb, offset, sti->size, ENC_LITTLE_ENDIAN);
- col_append_fstr(pinfo->cinfo, COL_INFO, "Encrypted SMB 2.2");
- offset += sti->size;
+ if (plain_tvb != NULL) {
+ col_append_fstr(pinfo->cinfo, COL_INFO, "Decrypted SMB3");
+ dissect_smb2(plain_tvb, pinfo, enc_tree, FALSE);
+ } else {
+ col_append_fstr(pinfo->cinfo, COL_INFO, "Encrypted SMB3");
+ proto_tree_add_item(enc_tree, hf_smb2_transform_encyrpted_data,
+ enc_tvb, 0, sti->size, ENC_LITTLE_ENDIAN);
+ }
+
+ if (tvb_reported_length_remaining(tvb, offset) > 0) {
+ chain_offset = offset;
+ }
}
if (chain_offset > 0) {
@@ -6611,6 +6939,9 @@ proto_register_smb2(void)
{ &hf_smb2_flags_signature,
{ "Signing", "smb2.flags.signature", FT_BOOLEAN, 32,
TFS(&tfs_flags_signature), SMB2_FLAGS_SIGNATURE, "Whether the pdu is signed or not", HFILL }},
+ { &hf_smb2_flags_replay_operation,
+ { "Replay operation", "smb2.flags.replay", FT_BOOLEAN, 32,
+ TFS(&tfs_flags_replay_operation), SMB2_FLAGS_REPLAY_OPERATION, "Whether this is a replay operation", HFILL }},
{ &hf_smb2_tree,
{ "Tree", "smb2.tree", FT_STRING, BASE_NONE,
NULL, 0, "Name of the Tree/Share", HFILL }},
@@ -7375,6 +7706,16 @@ proto_register_smb2(void)
NULL, SHARE_CAPS_CONTINUOUS_AVAILABILITY,
"The specified share is continuously available", HFILL }},
+ { &hf_smb2_share_caps_scaleout,
+ { "SCALEOUT", "smb2.share_caps.scaleout", FT_BOOLEAN, 32,
+ NULL, SHARE_CAPS_SCALEOUT,
+ "The specified share is a scaleout share", HFILL }},
+
+ { &hf_smb2_share_caps_cluster,
+ { "CLUSTER", "smb2.share_caps.cluster", FT_BOOLEAN, 32,
+ NULL, SHARE_CAPS_CLUSTER,
+ "The specified share is a cluster share", HFILL }},
+
{ &hf_smb2_ioctl_flags,
{ "Flags", "smb2.ioctl.flags", FT_UINT32, BASE_HEX,
NULL, 0, NULL, HFILL }},
@@ -7554,10 +7895,6 @@ proto_register_smb2(void)
{ "Reserved", "smb2.header.transform.reserved", FT_BYTES, BASE_NONE,
NULL, 0, NULL, HFILL }},
- { &hf_smb2_transform_sessionid,
- { "Session ID", "smb2.header.transform.sessionid", FT_BYTES, BASE_NONE,
- NULL, 0, NULL, HFILL }},
-
{ &hf_smb2_transform_enc_alg,
{ "Encryption ALG", "smb2.header.transform.encryption_alg", FT_UINT16, BASE_HEX,
NULL, 0, NULL, HFILL }},
diff --git a/epan/dissectors/packet-smb2.h b/epan/dissectors/packet-smb2.h
index 10bb46727c..efed5c41bb 100644
--- a/epan/dissectors/packet-smb2.h
+++ b/epan/dissectors/packet-smb2.h
@@ -70,6 +70,9 @@ typedef struct _smb2_sesid_info_t {
char *acct_name;
char *domain_name;
char *host_name;
+ guint16 server_port;
+ guint8 client_decryption_key[16];
+ guint8 server_decryption_key[16];
GHashTable *tids;
} smb2_sesid_info_t;
@@ -92,6 +95,7 @@ typedef struct _smb2_conv_info_t {
#define SMB2_FLAGS_CHAINED 0x00000004
#define SMB2_FLAGS_SIGNATURE 0x00000008
#define SMB2_FLAGS_DFS_OP 0x10000000
+#define SMB2_FLAGS_REPLAY_OPERATION 0x20000000
typedef struct _smb2_info_t {
guint16 opcode;
guint32 ioctl_function;
@@ -113,7 +117,9 @@ typedef struct _smb2_transform_info_t {
guint8 nonce[16];
guint32 size;
guint16 alg;
- guint8 session_id[8];
+ guint64 sesid;
+ smb2_conv_info_t *conv;
+ smb2_sesid_info_t *session;
} smb2_transform_info_t;
diff --git a/epan/dissectors/packet-windows-common.c b/epan/dissectors/packet-windows-common.c
index 5dcc2a4981..e9a7918ca3 100644
--- a/epan/dissectors/packet-windows-common.c
+++ b/epan/dissectors/packet-windows-common.c
@@ -1000,6 +1000,7 @@ const value_string NT_errors[] = {
{ 0xC00002E7, "STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED" },
{ 0xC00002E8, "STATUS_MULTIPLE_FAULT_VIOLATION" },
{ 0xC0000300, "STATUS_NOT_SUPPORTED_ON_SBS" },
+ { 0xC000035C, "STATUS_NETWORK_SESSION_EXPIRED" },
{ 0xC0009898, "STATUS_WOW_ASSERTION" },
{ 0xC0020001, "RPC_NT_INVALID_STRING_BINDING" },
{ 0xC0020002, "RPC_NT_WRONG_KIND_OF_BINDING" },