diff options
author | Guy Harris <guy@alum.mit.edu> | 2001-12-05 08:20:30 +0000 |
---|---|---|
committer | Guy Harris <guy@alum.mit.edu> | 2001-12-05 08:20:30 +0000 |
commit | 6b253331f087fbecb5de5e4548fbbe644d19b7af (patch) | |
tree | 43a7a7e7ed39be14d47f53c6f515e1acd3d37a15 | |
parent | faacd2b71c6e1141c7fa88ca2164e56fb4a0daa7 (diff) |
Support for reassembly of DCERPC over SMB, from Ronnie Sahlberg.
svn path=/trunk/; revision=4335
-rw-r--r-- | packet-dcerpc.c | 4 | ||||
-rw-r--r-- | packet-smb-pipe.c | 73 | ||||
-rw-r--r-- | packet-smb.c | 195 | ||||
-rw-r--r-- | packet-tcp.c | 5 | ||||
-rw-r--r-- | smb.h | 15 |
5 files changed, 203 insertions, 89 deletions
diff --git a/packet-dcerpc.c b/packet-dcerpc.c index d64772ca29..5ede69e934 100644 --- a/packet-dcerpc.c +++ b/packet-dcerpc.c @@ -2,7 +2,7 @@ * Routines for DCERPC packet disassembly * Copyright 2001, Todd Sabin <tas@webspan.net> * - * $Id: packet-dcerpc.c,v 1.19 2001/11/27 22:37:19 guy Exp $ + * $Id: packet-dcerpc.c,v 1.20 2001/12/05 08:20:28 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -1582,5 +1582,5 @@ proto_reg_handoff_dcerpc (void) heur_dissector_add ("tcp", dissect_dcerpc_cn_bs, proto_dcerpc); heur_dissector_add ("netbios", dissect_dcerpc_cn_pk, proto_dcerpc); heur_dissector_add ("udp", dissect_dcerpc_dg, proto_dcerpc); - heur_dissector_add ("smb_transact", dissect_dcerpc_cn_pk, proto_dcerpc); + heur_dissector_add ("smb_transact", dissect_dcerpc_cn_bs, proto_dcerpc); } diff --git a/packet-smb-pipe.c b/packet-smb-pipe.c index cd7c6d1596..9c815ceba3 100644 --- a/packet-smb-pipe.c +++ b/packet-smb-pipe.c @@ -8,7 +8,7 @@ XXX Fixme : shouldnt show [malformed frame] for long packets * significant rewrite to tvbuffify the dissector, Ronnie Sahlberg and * Guy Harris 2001 * - * $Id: packet-smb-pipe.c,v 1.58 2001/11/28 11:33:54 guy Exp $ + * $Id: packet-smb-pipe.c,v 1.59 2001/12/05 08:20:28 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -55,6 +55,7 @@ XXX Fixme : shouldnt show [malformed frame] for long packets #include "packet-smb-pipe.h" #include "packet-smb-browse.h" #include "packet-dcerpc.h" +#include "reassemble.h" static int proto_smb_pipe = -1; static int hf_pipe_function = -1; @@ -72,6 +73,7 @@ static int hf_pipe_getinfo_pipe_name = -1; static int hf_pipe_write_raw_bytes_written = -1; static gint ett_smb_pipe = -1; +static gint ett_smb_pipe_fragments = -1; static int proto_smb_lanman = -1; static int hf_function_code = -1; @@ -2533,7 +2535,7 @@ static heur_dissector_list_t smb_transact_heur_subdissector_list; static gboolean dissect_pipe_msrpc(tvbuff_t *d_tvb, packet_info *pinfo, proto_tree *parent_tree, - guint16 fid) + proto_tree *tree, guint32 fid) { dcerpc_private_info dcerpc_priv; smb_info_t *smb_priv = (smb_info_t *)pinfo->private_data; @@ -2544,11 +2546,73 @@ dissect_pipe_msrpc(tvbuff_t *d_tvb, packet_info *pinfo, proto_tree *parent_tree, pinfo->private_data = &dcerpc_priv; + /* offer desegmentation service to DCERPC */ + pinfo->can_desegment=0; + pinfo->desegment_offset = 0; + pinfo->desegment_len = 0; + if(smb_dcerpc_reassembly){ + pinfo->can_desegment=2; + } + + /* see if this packet is already desegmented */ + if(smb_dcerpc_reassembly && pinfo->fd->flags.visited){ + fragment_data *fd_head; + tvbuff_t *new_tvb; + + fd_head=fragment_get(pinfo, pinfo->fd->num , + dcerpc_fragment_table); + if(fd_head && fd_head->flags&FD_DEFRAGMENTED){ + proto_tree *tr; + proto_item *it; + fragment_data *fd; + + new_tvb = tvb_new_real_data(fd_head->data, + fd_head->datalen, fd_head->datalen, + "DCERPC over SMB"); + tvb_set_child_real_data_tvbuff(d_tvb, new_tvb); + pinfo->fd->data_src=g_slist_append(pinfo->fd->data_src, + new_tvb); + pinfo->fragmented=FALSE; + + d_tvb=new_tvb; + + /* list what segments we have */ + it = proto_tree_add_text(tree, d_tvb, 0, 0, "Fragments"); + tr = proto_item_add_subtree(it, ett_smb_pipe_fragments); + for(fd=fd_head->next;fd;fd=fd->next){ + proto_tree_add_text(tr, d_tvb, 0, 0, "Frame:%d Data:%d-%d", + fd->frame, fd->offset, fd->offset+fd->len-1); + } + } + } + result = dissector_try_heuristic(smb_transact_heur_subdissector_list, d_tvb, pinfo, parent_tree); - pinfo->private_data = smb_priv; + /* check if dissector wanted us to desegment the data */ + if(smb_dcerpc_reassembly && !pinfo->fd->flags.visited && pinfo->desegment_len){ + fragment_add(d_tvb, 0, pinfo, pinfo->fd->num, + dcerpc_fragment_table, + 0, tvb_length(d_tvb), TRUE); + fragment_set_tot_len(pinfo, pinfo->fd->num, + dcerpc_fragment_table, + pinfo->desegment_len+tvb_length(d_tvb)); + /* since the other fragments are in normal ReadAndX and WriteAndX calls + we must make sure we can map FID values to this defragmentation + session */ + /* first remove any old mappings */ + if(g_hash_table_lookup(smb_priv->ct->dcerpc_fid_to_frame, (void *)fid)){ + g_hash_table_remove(smb_priv->ct->dcerpc_fid_to_frame, (void *)fid); + } + g_hash_table_insert(smb_priv->ct->dcerpc_fid_to_frame, (void *)fid, + (void *)pinfo->fd->num); + } + /* clear out the variables */ + pinfo->can_desegment=0; + pinfo->desegment_offset = 0; + pinfo->desegment_len = 0; + if (!result) call_dissector(data_handle, d_tvb, pinfo, parent_tree); @@ -2786,7 +2850,7 @@ dissect_pipe_smb(tvbuff_t *sp_tvb, tvbuff_t *s_tvb, tvbuff_t *pd_tvb, if (d_tvb == NULL) return FALSE; return dissect_pipe_msrpc(d_tvb, pinfo, tree, - fid); + pipe_tree, fid); } break; } @@ -2988,6 +3052,7 @@ proto_register_smb_pipe(void) }; static gint *ett[] = { &ett_smb_pipe, + &ett_smb_pipe_fragments, }; proto_smb_pipe = proto_register_protocol( diff --git a/packet-smb.c b/packet-smb.c index e9b3eb529e..adda0b19a9 100644 --- a/packet-smb.c +++ b/packet-smb.c @@ -2,7 +2,7 @@ * Routines for smb packet dissection * Copyright 1999, Richard Sharpe <rsharpe@ns.aus.com> * - * $Id: packet-smb.c,v 1.178 2001/12/05 00:49:31 guy Exp $ + * $Id: packet-smb.c,v 1.179 2001/12/05 08:20:28 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -666,18 +666,24 @@ static const gchar *get_unicode_or_ascii_string(tvbuff_t *tvb, /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - These are needed by the reassembly of SMB Transaction payload + These are needed by the reassembly of SMB Transaction payload and DCERPC over SMB XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ -/* Reassembly of SMB Transaction calls */ static gboolean smb_trans_reassembly = FALSE; +gboolean smb_dcerpc_reassembly = FALSE; static GHashTable *smb_trans_fragment_table = NULL; +GHashTable *dcerpc_fragment_table = NULL; static void smb_trans_reassembly_init(void) { fragment_table_init(&smb_trans_fragment_table); } +static void +smb_dcerpc_reassembly_init(void) +{ + fragment_table_init(&dcerpc_fragment_table); +} static fragment_data * @@ -802,10 +808,6 @@ static int smb_transact2_info_init_count = 200; static GMemChunk *smb_transact_info_chunk = NULL; static int smb_transact_info_init_count = 200; -typedef struct conv_tables { - GHashTable *unmatched; - GHashTable *matched; -} conv_tables_t; static GMemChunk *conv_tables_chunk = NULL; static int conv_tables_count = 10; @@ -4597,8 +4599,8 @@ static int dissect_read_andx_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree) { guint8 wc, cmd=0xff; - guint16 andxoffset=0, bc, datalen=0; - smb_info_t *si; + guint16 andxoffset=0, bc, datalen=0, dataoffset=0; + smb_info_t *si = (smb_info_t *)pinfo->private_data; WORD_COUNT; @@ -4621,7 +4623,6 @@ dissect_read_andx_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, offset += 2; /* If we have seen the request, then print which FID this refers to */ - si = (smb_info_t *)pinfo->private_data; /* first check if we have seen the request */ if(si->sip != NULL && si->sip->frame_req>0){ add_fid(tvb, pinfo, tree, 0, 0, (int)si->sip->extra_info); @@ -4645,7 +4646,8 @@ dissect_read_andx_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, offset += 2; /* data offset */ - proto_tree_add_item(tree, hf_smb_data_offset, tvb, offset, 2, TRUE); + dataoffset=tvb_get_letohs(tvb, offset); + proto_tree_add_uint(tree, hf_smb_data_offset, tvb, offset, 2, dataoffset); offset += 2; /* 10 reserved bytes */ @@ -4655,6 +4657,43 @@ dissect_read_andx_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, BYTE_COUNT; + /* is this part of DCERPC over SMB reassembly?*/ + if(smb_dcerpc_reassembly && !pinfo->fd->flags.visited && (bc<=tvb_length_remaining(tvb, offset)) ){ + guint32 frame; + frame=(guint32)g_hash_table_lookup(si->ct->dcerpc_fid_to_frame, + si->sip->extra_info); + if(frame){ + fragment_data *fd_head; + /* first fragment is always from a SMB Trans command and + offset 0 of the following read/write SMB commands start + BEYOND the first Trans SMB payload. Look for offset + in first read fragment */ + fd_head=fragment_get(pinfo, frame, dcerpc_fragment_table); + if(fd_head){ + /* skip to last fragment and add this data there*/ + while(fd_head->next){ + fd_head=fd_head->next; + } + /* if dataoffset was not specified in the SMB command + then we try to guess it as good as we can + */ + if(dataoffset==0){ + dataoffset=offset+bc-datalen; + } + fd_head=fragment_add(tvb, dataoffset, pinfo, + frame, dcerpc_fragment_table, + fd_head->offset+fd_head->len, + datalen, TRUE); + /* we completed reassembly, abort searching for more + fragments*/ + if(fd_head){ + g_hash_table_remove(si->ct->dcerpc_fid_to_frame, + si->sip->extra_info); + } + } + } + } + /* file data */ offset = dissect_file_data(tvb, pinfo, tree, offset, bc, datalen); bc = 0; @@ -12745,6 +12784,7 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree) guint8 errclass = 0; guint16 errcode = 0; guint16 uid, pid, tid; + conversation_t *conversation; top_tree=parent_tree; @@ -12798,6 +12838,29 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree) proto_tree_add_text(htree, tvb, offset, 4, "Server Component: SMB"); offset += 4; /* Skip the marker */ + /* find which conversation we are part of and get the tables for that + conversation*/ + conversation = find_conversation(&pinfo->src, &pinfo->dst, + pinfo->ptype, pinfo->srcport, pinfo->destport, 0); + if(conversation){ + si.ct=conversation_get_proto_data(conversation, proto_smb); + } else { + /* OK this is a new conversation, we must create it + and attach appropriate data (matched and unmatched + table for this conversation) + */ + conversation = conversation_new(&pinfo->src, &pinfo->dst, + pinfo->ptype, pinfo->srcport, pinfo->destport, 0); + si.ct = g_mem_chunk_alloc(conv_tables_chunk); + si.ct->matched= g_hash_table_new(smb_saved_info_hash_matched, + smb_saved_info_equal_matched); + si.ct->unmatched= g_hash_table_new(smb_saved_info_hash_matched, + smb_saved_info_equal_matched); + si.ct->dcerpc_fid_to_frame=g_hash_table_new( + smb_saved_info_hash_matched, + smb_saved_info_equal_matched); + conversation_add_proto_data(conversation, proto_smb, si.ct); + } if( (si.request) && (si.mid==0) @@ -12829,47 +12892,37 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree) requests smb_saved_info_t but we dont touch it or change anything in it. */ - conversation_t *conversation; - conv_tables_t *ct; si.unidir = TRUE; /*we dont expect an answer to this one*/ - - /* find which conversation we are part of and get the tables for that - conversation*/ - conversation = find_conversation(&pinfo->src, &pinfo->dst, - pinfo->ptype, pinfo->srcport, pinfo->destport, 0); - if(conversation){ - ct=conversation_get_proto_data(conversation, proto_smb); - if(!pinfo->fd->flags.visited){ - /* try to find which original call we match and if we - find it add us to the matched table. Dont touch - anything else since we dont want this one to mess - up the request/response matching. We still consider - the initial call the real request and this is only - some sort of continuation. - */ - /* we only check the unmatched table and assume that the - last seen MID matching ours is the right one. - This can fail but is better than nothing - */ - sip=g_hash_table_lookup(ct->unmatched, (void *)si.mid); - if(sip!=NULL){ - g_hash_table_insert(ct->matched, (void *)pinfo->fd->num, sip); - } - } else { - /* we have seen this packet before; check the - matching table - */ - sip=g_hash_table_lookup(ct->matched, (void *)pinfo->fd->num); - if(sip==NULL){ - /* - We didn't find it. - Too bad, unfortunately there is not really much we can - do now since this means that we never saw the initial - request. - */ - } + if(!pinfo->fd->flags.visited){ + /* try to find which original call we match and if we + find it add us to the matched table. Dont touch + anything else since we dont want this one to mess + up the request/response matching. We still consider + the initial call the real request and this is only + some sort of continuation. + */ + /* we only check the unmatched table and assume that the + last seen MID matching ours is the right one. + This can fail but is better than nothing + */ + sip=g_hash_table_lookup(si.ct->unmatched, (void *)si.mid); + if(sip!=NULL){ + g_hash_table_insert(si.ct->matched, (void *)pinfo->fd->num, sip); + } + } else { + /* we have seen this packet before; check the + matching table + */ + sip=g_hash_table_lookup(si.ct->matched, (void *)pinfo->fd->num); + if(sip==NULL){ + /* + We didn't find it. + Too bad, unfortunately there is not really much we can + do now since this means that we never saw the initial + request. + */ } } @@ -12902,38 +12955,13 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree) } } } else { /* normal bidirectional request or response */ - conversation_t *conversation; - conv_tables_t *ct; - si.unidir = FALSE; - /* first we try to find which conversation this packet is - part of - */ - conversation = find_conversation(&pinfo->src, &pinfo->dst, - pinfo->ptype, pinfo->srcport, pinfo->destport, 0); - if(conversation==NULL){ - /* OK this is a new conversation, we must create it - and attach appropriate data (matched and unmatched - table for this conversation) - */ - conversation = conversation_new(&pinfo->src, &pinfo->dst, - pinfo->ptype, pinfo->srcport, pinfo->destport, 0); - ct = g_mem_chunk_alloc(conv_tables_chunk); - ct->matched= g_hash_table_new(smb_saved_info_hash_matched, - smb_saved_info_equal_matched); - ct->unmatched= g_hash_table_new(smb_saved_info_hash_matched, - smb_saved_info_equal_matched); - conversation_add_proto_data(conversation, proto_smb, ct); - } else { - /* this is an old conversation, just get the tables */ - ct=conversation_get_proto_data(conversation, proto_smb); - } if(!pinfo->fd->flags.visited){ /* first see if we find an unmatched smb "equal" to the current one */ - sip=g_hash_table_lookup(ct->unmatched, (void *)si.mid); + sip=g_hash_table_lookup(si.ct->unmatched, (void *)si.mid); if(sip!=NULL){ if(si.request){ /* ok, we are processing an SMB @@ -12950,7 +12978,7 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree) request and concentrate on the present one instead. */ - g_hash_table_remove(ct->unmatched, (void *)si.mid); + g_hash_table_remove(si.ct->unmatched, (void *)si.mid); } else { /* we have found a response to some request we have seen earlier. What we do now depends on whether this is the first response @@ -12959,13 +12987,13 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree) if(sip->frame_res==0){ /* ok it is the first response we have seen to this packet */ sip->frame_res = pinfo->fd->num; - g_hash_table_insert(ct->matched, (void *)sip->frame_req, sip); - g_hash_table_insert(ct->matched, (void *)sip->frame_res, sip); + g_hash_table_insert(si.ct->matched, (void *)sip->frame_req, sip); + g_hash_table_insert(si.ct->matched, (void *)sip->frame_res, sip); } else { /* we have already seen another response to this one, but register it anyway so we see which request it matches */ - g_hash_table_insert(ct->matched, (void *)pinfo->fd->num, sip); + g_hash_table_insert(si.ct->matched, (void *)pinfo->fd->num, sip); } } } @@ -12974,7 +13002,7 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree) sip->frame_req = pinfo->fd->num; sip->frame_res = 0; sip->extra_info = NULL; - g_hash_table_insert(ct->unmatched, (void *)si.mid, sip); + g_hash_table_insert(si.ct->unmatched, (void *)si.mid, sip); } } else { /* we have seen this packet before; check the @@ -12985,7 +13013,7 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree) we've seen this packet before, we've already saved the information. */ - sip=g_hash_table_lookup(ct->matched, (void *)pinfo->fd->num); + sip=g_hash_table_lookup(si.ct->matched, (void *)pinfo->fd->num); } } @@ -14911,7 +14939,12 @@ proto_register_smb(void) "Reassemble SMB Transaction payload", "Whether the dissector should do reassembly the payload of SMB Transaction commands spanning multiple SMB PDUs", &smb_trans_reassembly); + prefs_register_bool_preference(smb_module, "smb.dcerpc.reassembly", + "Reassemble DCERPC over SMB", + "Whether the dissector should do reassembly of DCERPC over SMB commands", + &smb_dcerpc_reassembly); register_init_routine(smb_trans_reassembly_init); + register_init_routine(smb_dcerpc_reassembly_init); } void diff --git a/packet-tcp.c b/packet-tcp.c index 269ecf2b8b..566e69fcb7 100644 --- a/packet-tcp.c +++ b/packet-tcp.c @@ -1,7 +1,7 @@ /* packet-tcp.c * Routines for TCP packet disassembly * - * $Id: packet-tcp.c,v 1.120 2001/12/03 08:47:27 guy Exp $ + * $Id: packet-tcp.c,v 1.121 2001/12/05 08:20:30 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -539,6 +539,9 @@ desegment_tcp(tvbuff_t *tvb, packet_info *pinfo, int offset, */ call_dissector(data_handle,tvb_new_subset(tvb, deseg_offset,-1,tvb_reported_length_remaining(tvb,deseg_offset)), pinfo, tree); } + pinfo->can_desegment=0; + pinfo->desegment_offset = 0; + pinfo->desegment_len = 0; } @@ -2,7 +2,7 @@ * Defines for smb packet dissection * Copyright 1999, Richard Sharpe <rsharpe@ns.aus.com> * - * $Id: smb.h,v 1.28 2001/12/05 00:49:32 guy Exp $ + * $Id: smb.h,v 1.29 2001/12/05 08:20:30 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -242,6 +242,15 @@ typedef struct { #define TRANSACTION_PIPE 0 #define TRANSACTION_MAILSLOT 1 +/* this is the structure which is associated with each conversation */ +typedef struct conv_tables { + /* these two tables are used to match requests with responses */ + GHashTable *unmatched; + GHashTable *matched; + /* this tables is used by DCERPC over SMB reassembly*/ + GHashTable *dcerpc_fid_to_frame; +} conv_tables_t; + typedef struct smb_info { int cmd, mid; gboolean unicode; /* Are strings in this SMB Unicode? */ @@ -250,6 +259,7 @@ typedef struct smb_info { int info_level; int info_count; smb_saved_info_t *sip; /* smb_saved_info_t, if any, for this */ + conv_tables_t *ct; } smb_info_t; /* @@ -270,4 +280,7 @@ extern void add_fid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, extern int dissect_ipc_state(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset, gboolean setstate); +extern gboolean smb_dcerpc_reassembly; +extern GHashTable *dcerpc_fragment_table; + #endif |