]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #549 in SNORT/snort3 from smb_reassembly to master
authorHui Cao (huica) <huica@cisco.com>
Wed, 6 Jul 2016 18:25:59 +0000 (14:25 -0400)
committerHui Cao (huica) <huica@cisco.com>
Wed, 6 Jul 2016 18:25:59 +0000 (14:25 -0400)
Squashed commit of the following:

commit e7dae9120e13a4d520376c24aa2ec1a1950b34dd
Author: mdagon <mdagon@cisco.com>
Date:   Fri Jul 1 03:04:07 2016 -0400

    Smb ressaembly

src/service_inspectors/dce_rpc/dce_co.cc
src/service_inspectors/dce_rpc/dce_common.cc
src/service_inspectors/dce_rpc/dce_smb.cc
src/service_inspectors/dce_rpc/dce_smb.h
src/service_inspectors/dce_rpc/dce_smb_commands.cc
src/service_inspectors/dce_rpc/dce_smb_transaction.cc
src/service_inspectors/dce_rpc/dce_smb_utils.cc
src/service_inspectors/dce_rpc/dce_smb_utils.h

index b06f29836f330052dd1e48d7192b61ce8333982c..8e1fc3612ceca5ee4e37da9dcf3e990ceb9cb2ac 100644 (file)
@@ -26,6 +26,7 @@
 #include "dce_smb_module.h"
 #include "dce_list.h"
 #include "dce_utils.h"
+#include "dce_smb_utils.h"
 #include "log/messages.h"
 #include "main/snort_debug.h"
 #include "utils/util.h"
@@ -217,7 +218,6 @@ static inline DCE2_CoSeg* DCE2_CoGetSegPtr(DCE2_SsnData* sd, DCE2_CoTracker* cot
  ********************************************************************/
 static DCE2_Ret DCE2_CoSetIface(DCE2_SsnData* sd, DCE2_CoTracker* cot, uint16_t ctx_id)
 {
-
     /* This should be set if we've gotten a Bind */
     if (cot->ctx_ids == nullptr)
         return DCE2_RET__ERROR;
@@ -1234,6 +1234,8 @@ static Packet* dce_co_reassemble(DCE2_SsnData* sd, DCE2_CoTracker* cot,
     dce2CommonStats* dce_common_stats = dce_get_proto_stats_ptr(sd);
     int co_hdr_len = DCE2_SsnFromClient(sd->wire_pkt) ? DCE2_MOCK_HDR_LEN__CO_CLI :
         DCE2_MOCK_HDR_LEN__CO_SRV;
+    int smb_hdr_len = DCE2_SsnFromClient(sd->wire_pkt) ? DCE2_MOCK_HDR_LEN__SMB_CLI :
+        DCE2_MOCK_HDR_LEN__SMB_SRV;
 
     if (sd->trans == DCE2_TRANS_TYPE__TCP)
     {
@@ -1255,8 +1257,30 @@ static Packet* dce_co_reassemble(DCE2_SsnData* sd, DCE2_CoTracker* cot,
     {
     case DCE2_RPKT_TYPE__SMB_CO_FRAG:
     case DCE2_RPKT_TYPE__SMB_CO_SEG:
-        // FIXIT-M add this when SMB is ported
-        return nullptr;
+        DCE2_SmbSetRdata((DCE2_SmbSsnData*)sd, (uint8_t*)rpkt->data,
+            (uint16_t)(rpkt->dsize - smb_hdr_len));
+
+        if (rpkt_type == DCE2_RPKT_TYPE__SMB_CO_FRAG)
+        {
+            DCE2_CoSetRdata(sd, cot, (uint8_t*)rpkt->data + smb_hdr_len,
+                (uint16_t)(rpkt->dsize - (smb_hdr_len + co_hdr_len)));
+
+            if (DCE2_SsnFromClient(sd->wire_pkt))
+                dce_common_stats->co_cli_frag_reassembled++;
+            else
+                dce_common_stats->co_srv_frag_reassembled++;
+        }
+        else
+        {
+            if (DCE2_SsnFromClient(sd->wire_pkt))
+                dce_common_stats->co_cli_seg_reassembled++;
+            else
+                dce_common_stats->co_srv_seg_reassembled++;
+        }
+
+        *co_hdr = (DceRpcCoHdr*)(rpkt->data + smb_hdr_len);
+        cot->stub_data = rpkt->data + smb_hdr_len + co_hdr_len;
+        return rpkt;
 
     case DCE2_RPKT_TYPE__TCP_CO_FRAG:
     case DCE2_RPKT_TYPE__TCP_CO_SEG:
@@ -1434,9 +1458,11 @@ static void DCE2_CoHandleFrag(DCE2_SsnData* sd, DCE2_CoTracker* cot,
     DCE2_Buffer* frag_buf = DCE2_CoGetFragBuf(sd, &cot->frag_tracker);
     uint16_t max_frag_data;
 
-    // FIXIT-M add SMB max_frag_data when SMB is ported
-
-    max_frag_data = DCE2_GetRpktMaxData(sd, DCE2_RPKT_TYPE__TCP_CO_FRAG);
+    /* Check for potential overflow */
+    if (sd->trans == DCE2_TRANS_TYPE__SMB)
+        max_frag_data = DCE2_GetRpktMaxData(sd, DCE2_RPKT_TYPE__SMB_CO_FRAG);
+    else
+        max_frag_data = DCE2_GetRpktMaxData(sd, DCE2_RPKT_TYPE__TCP_CO_FRAG);
 
     ret_val = dce_co_handle_frag(sd, cot,co_hdr, frag_ptr, frag_len,frag_buf,max_frag_data);
     if (ret_val == DCE2_RET__SUCCESS)
@@ -2099,7 +2125,8 @@ static Packet* DCE2_CoGetSegRpkt(DCE2_SsnData* sd,
     const uint8_t* data_ptr, uint32_t data_len)
 {
     Packet* rpkt = nullptr;
-    // FIXIT-M add smb_hdr_len when SMB is ported
+    int smb_hdr_len = DCE2_SsnFromClient(sd->wire_pkt) ? DCE2_MOCK_HDR_LEN__SMB_CLI :
+        DCE2_MOCK_HDR_LEN__SMB_SRV;
 
     if (sd->trans == DCE2_TRANS_TYPE__TCP)
     {
@@ -2113,7 +2140,15 @@ static Packet* DCE2_CoGetSegRpkt(DCE2_SsnData* sd,
     switch (sd->trans)
     {
     case DCE2_TRANS_TYPE__SMB:
-        // FIXIT-M add when SMB is ported
+        rpkt = DCE2_GetRpkt(sd->wire_pkt, DCE2_RPKT_TYPE__SMB_CO_SEG,
+            data_ptr, data_len);
+        if (rpkt == nullptr)
+        {
+            DebugMessage(DEBUG_DCE_COMMON, "Failed to create reassembly packet.\n");
+            return nullptr;
+        }
+        DCE2_SmbSetRdata((DCE2_SmbSsnData*)sd, (uint8_t*)rpkt->data,
+            (uint16_t)(rpkt->dsize - smb_hdr_len));
         break;
 
     case DCE2_TRANS_TYPE__TCP:
@@ -2149,7 +2184,8 @@ static void DCE2_CoSegDecode(DCE2_SsnData* sd, DCE2_CoTracker* cot, DCE2_CoSeg*
     const uint8_t* frag_ptr = nullptr;
     uint16_t frag_len = 0;
     dce2CommonStats* dce_common_stats = dce_get_proto_stats_ptr(sd);
-    // FIXIT-M add smb_hdr_len when SMB is ported
+    int smb_hdr_len = DCE2_SsnFromClient(sd->wire_pkt) ? DCE2_MOCK_HDR_LEN__SMB_CLI :
+        DCE2_MOCK_HDR_LEN__SMB_SRV;
 
     if (DCE2_SsnFromClient(sd->wire_pkt))
         dce_common_stats->co_cli_seg_reassembled++;
@@ -2173,7 +2209,8 @@ static void DCE2_CoSegDecode(DCE2_SsnData* sd, DCE2_CoTracker* cot, DCE2_CoSeg*
     switch (sd->trans)
     {
     case DCE2_TRANS_TYPE__SMB:
-        // FIXIT-M add when SMB is ported
+        frag_ptr = rpkt->data + smb_hdr_len;
+        frag_len = rpkt->dsize - smb_hdr_len;
         break;
 
     case DCE2_TRANS_TYPE__TCP:
@@ -2188,14 +2225,24 @@ static void DCE2_CoSegDecode(DCE2_SsnData* sd, DCE2_CoTracker* cot, DCE2_CoSeg*
         return;
     }
 
-    // FIXIT-L PORT_IF_NEEDED
-    //Push packet on stack and call detect
+    if (DCE2_PushPkt(rpkt,sd) != DCE2_RET__SUCCESS)
+    {
+        DebugMessage(DEBUG_DCE_COMMON, "Failed to push packet onto packet stack.\n");
+        return;
+    }
 
     /* All is good.  Decode the pdu */
     DCE2_CoDecode(sd, cot, frag_ptr, frag_len);
 
     DebugMessage(DEBUG_DCE_COMMON, "Reassembled CO segmented packet\n");
     DCE2_PrintPktData(rpkt->data, rpkt->dsize);
+
+    /* Call detect since this is a reassembled packet that the
+     * detection engine hasn't seen yet */
+    if (!co_reassembled)
+        DCE2_Detect(sd);
+
+    DCE2_PopPkt(sd);
 }
 
 static DCE2_Ret DCE2_HandleSegmentation(DCE2_Buffer* seg_buf, const uint8_t* data_ptr,
@@ -2296,71 +2343,89 @@ void DCE2_CoProcess(DCE2_SsnData* sd, DCE2_CoTracker* cot,
 {
     DCE2_CoSeg* seg = DCE2_CoGetSegPtr(sd, cot);
     dce2CommonStats* dce_common_stats = dce_get_proto_stats_ptr(sd);
+    uint32_t num_frags = 0;
 
     dce_common_stats->co_pdus++;
-
     co_reassembled = 0;
 
-    // FIXIT-L PORT_IF_NEEDED
-    //Loop to walk through multiple fragments in a packet
-
-    /* Fast track full fragments */
-    if (DCE2_BufferIsEmpty(seg->buf))
+    while (data_len > 0)
     {
-        const uint8_t* frag_ptr = data_ptr;
-        uint16_t frag_len;
+        num_frags++;
 
-        // FIXIT-L PORT_IF_NEEDED
-        //Not enough data left for a headerr
+        DebugFormat(DEBUG_DCE_COMMON, "DCE/RPC message number: %u\n", num_frags);
 
-        if (DCE2_CoHdrChecks(sd, cot, (DceRpcCoHdr*)data_ptr) != DCE2_RET__SUCCESS)
-            return;
+        /* Fast track full fragments */
+        if (DCE2_BufferIsEmpty(seg->buf))
+        {
+            const uint8_t* frag_ptr = data_ptr;
+            uint16_t frag_len;
 
-        frag_len = DceRpcCoFragLen((DceRpcCoHdr*)data_ptr);
+            // FIXIT-L PORT_IF_NEEDED
+            //Not enough data left for a headerr
 
-        /* Not enough data left for the pdu. */
-        if (data_len < frag_len)
-        {
-            DebugFormat(DEBUG_DCE_COMMON,
-                "Not enough data in packet for fragment length: %hu\n", frag_len);
+            if (DCE2_CoHdrChecks(sd, cot, (DceRpcCoHdr*)data_ptr) != DCE2_RET__SUCCESS)
+                return;
 
-            /* Set frag length so we don't have to check it again in seg code */
-            seg->frag_len = frag_len;
+            frag_len = DceRpcCoFragLen((DceRpcCoHdr*)data_ptr);
 
-            DCE2_CoHandleSegmentation(sd, seg, data_ptr, data_len, frag_len);
-            goto dce2_coprocess_exit;
-        }
+            /* Not enough data left for the pdu. */
+            if (data_len < frag_len)
+            {
+                DebugFormat(DEBUG_DCE_COMMON,
+                    "Not enough data in packet for fragment length: %hu\n", frag_len);
 
-        /* Got a full DCE/RPC pdu */
-        DCE2_CoDecode(sd, cot, frag_ptr, frag_len);
+                /* Set frag length so we don't have to check it again in seg code */
+                seg->frag_len = frag_len;
 
-        // FIXIT-L PORT_IF_NEEDED
-        //Detect first frag and reset frag count, DCE_MOVE
-    }
-    else  /* We've already buffered data */
-    {
-        DebugFormat(DEBUG_DCE_COMMON, "Segmentation buffer has %u bytes\n",
-            DCE2_BufferLength(seg->buf));
+                DCE2_CoHandleSegmentation(sd, seg, data_ptr, data_len, frag_len);
+                goto dce2_coprocess_exit;
+            }
 
-        // FIXIT-L PORT_IF_NEEDED
-        //Need more data to get header
+            DCE2_MOVE(data_ptr, data_len, frag_len);
 
-        /* Need more data for full pdu */
-        if (DCE2_BufferLength(seg->buf) < seg->frag_len)
-        {
-            DCE2_Ret status = DCE2_CoHandleSegmentation(sd, seg, data_ptr, data_len,
-                seg->frag_len);
+            /* Got a full DCE/RPC pdu */
+            DCE2_CoDecode(sd, cot, frag_ptr, frag_len);
 
-            /* Still not enough */
-            if (status != DCE2_RET__SUCCESS)
-                goto dce2_coprocess_exit;
+            /* If we're configured to do defragmentation only detect on first frag
+             * since we'll detect on reassembled */
+            if (!DCE2_GcDceDefrag((dce2CommonProtoConf*)sd->config) || ((num_frags == 1) &&
+                !co_reassembled))
+                DCE2_Detect(sd);
+
+            /* Reset if this is a last frag */
+            if (DceRpcCoLastFrag((DceRpcCoHdr*)frag_ptr))
+                num_frags = 0;
         }
+        else  /* We've already buffered data */
+        {
+            DebugFormat(DEBUG_DCE_COMMON, "Segmentation buffer has %u bytes\n",
+                DCE2_BufferLength(seg->buf));
 
-        // FIXIT-L PORT_IF_NEEDED
-        //Reset frag count, DCE_MOVE, data_used
+            // FIXIT-L PORT_IF_NEEDED
+            //Need more data to get header
 
-        /* Got the full DCE/RPC pdu. Need to create new packet before decoding */
-        DCE2_CoSegDecode(sd, cot, seg);
+            /* Need more data for full pdu */
+            if (DCE2_BufferLength(seg->buf) < seg->frag_len)
+            {
+                DCE2_Ret status = DCE2_CoHandleSegmentation(sd, seg, data_ptr, data_len,
+                    seg->frag_len);
+
+                /* Still not enough */
+                if (status != DCE2_RET__SUCCESS)
+                    goto dce2_coprocess_exit;
+            }
+
+            // FIXIT-L PORT_IF_NEEDED
+            // DCE_MOVE, data_used
+
+            /* Do this before calling DCE2_CoSegDecode since it will empty
+             * seg buffer */
+            if (DceRpcCoLastFrag((DceRpcCoHdr*)seg->buf->data))
+                num_frags = 0;
+
+            /* Got the full DCE/RPC pdu. Need to create new packet before decoding */
+            DCE2_CoSegDecode(sd, cot, seg);
+        }
     }
 
 dce2_coprocess_exit:
index 1c979aca5737b40cab507f0c5a7561bcc2af0d29..994d0e5685419ca6dfae3cd8d97a267d7880f847 100644 (file)
@@ -22,6 +22,7 @@
 #include "dce_tcp.h"
 #include "dce_smb.h"
 #include "dce_co.h"
+#include "dce_smb_utils.h"
 #include "framework/base_api.h"
 #include "framework/module.h"
 #include "flow/flow.h"
@@ -350,9 +351,20 @@ uint16_t DCE2_GetRpktMaxData(DCE2_SsnData* sd, DCE2_RpktType rtype)
     {
     case DCE2_RPKT_TYPE__SMB_SEG:
     case DCE2_RPKT_TYPE__SMB_TRANS:
+        break;
+
     case DCE2_RPKT_TYPE__SMB_CO_SEG:
+        if (DCE2_SsnFromClient(p))
+            overhead += DCE2_MOCK_HDR_LEN__SMB_CLI;
+        else
+            overhead += DCE2_MOCK_HDR_LEN__SMB_SRV;
+        break;
+
     case DCE2_RPKT_TYPE__SMB_CO_FRAG:
-        // FIXIT-M add support for these when SMB is ported
+        if (DCE2_SsnFromClient(p))
+            overhead += DCE2_MOCK_HDR_LEN__SMB_CLI + DCE2_MOCK_HDR_LEN__CO_CLI;
+        else
+            overhead += DCE2_MOCK_HDR_LEN__SMB_SRV + DCE2_MOCK_HDR_LEN__CO_SRV;
         break;
 
     case DCE2_RPKT_TYPE__TCP_CO_SEG:
@@ -371,37 +383,101 @@ uint16_t DCE2_GetRpktMaxData(DCE2_SsnData* sd, DCE2_RpktType rtype)
     return (DCE2_REASSEMBLY_BUF_SIZE - overhead);
 }
 
+static void dce2_fill_rpkt_info(Packet* rpkt, Packet* p)
+{
+    DceEndianness* endianness = (DceEndianness*)rpkt->endianness;
+    rpkt->reset();
+    rpkt->endianness = (Endianness*)endianness;
+    ((DceEndianness*)rpkt->endianness)->reset();
+    rpkt->pkth = p->pkth;
+    rpkt->ptrs = p->ptrs;
+    rpkt->flow = p->flow;
+    rpkt->proto_bits = p->proto_bits;
+    rpkt->packet_flags = p->packet_flags;
+    rpkt->packet_flags |= PKT_PSEUDO;
+    rpkt->user_policy_id = p->user_policy_id;
+}
+
 Packet* DCE2_GetRpkt(Packet* p,DCE2_RpktType rpkt_type,
     const uint8_t* data, uint32_t data_len)
 {
     Packet* rpkt = nullptr;
     uint16_t data_overhead = 0;
-    DceEndianness* endianness;
 
     switch (rpkt_type)
     {
     case DCE2_RPKT_TYPE__SMB_SEG:
+        rpkt = dce2_smb_rpkt[rpkt_type - DCE2_SMB_RPKT_TYPE_START];
+        dce2_fill_rpkt_info(rpkt, p);
+        rpkt->pseudo_type = PSEUDO_PKT_SMB_SEG;
+        break;
+
     case DCE2_RPKT_TYPE__SMB_TRANS:
+        rpkt = dce2_smb_rpkt[rpkt_type - DCE2_SMB_RPKT_TYPE_START];
+        dce2_fill_rpkt_info(rpkt, p);
+        rpkt->pseudo_type = PSEUDO_PKT_SMB_TRANS;
+        if (DCE2_SsnFromClient(p))
+        {
+            data_overhead = DCE2_MOCK_HDR_LEN__SMB_CLI;
+            memset((void*)rpkt->data, 0, data_overhead);
+            DCE2_SmbInitRdata((uint8_t*)rpkt->data, PKT_FROM_CLIENT);
+        }
+        else
+        {
+            data_overhead = DCE2_MOCK_HDR_LEN__SMB_SRV;
+            memset((void*)rpkt->data, 0, data_overhead);
+            DCE2_SmbInitRdata((uint8_t*)rpkt->data, PKT_FROM_SERVER);
+        }
+        break;
+
     case DCE2_RPKT_TYPE__SMB_CO_SEG:
+        rpkt = dce2_smb_rpkt[rpkt_type - DCE2_SMB_RPKT_TYPE_START];
+        dce2_fill_rpkt_info(rpkt, p);
+        rpkt->pseudo_type = PSEUDO_PKT_DCE_SEG;
+        if (DCE2_SsnFromClient(p))
+        {
+            data_overhead = DCE2_MOCK_HDR_LEN__SMB_CLI;
+            memset((void*)rpkt->data, 0, data_overhead);
+            DCE2_SmbInitRdata((uint8_t*)rpkt->data, PKT_FROM_CLIENT);
+        }
+        else
+        {
+            data_overhead = DCE2_MOCK_HDR_LEN__SMB_SRV;
+            memset((void*)rpkt->data, 0, data_overhead);
+            DCE2_SmbInitRdata((uint8_t*)rpkt->data, PKT_FROM_SERVER);
+        }
+        break;
+
     case DCE2_RPKT_TYPE__SMB_CO_FRAG:
+        rpkt = dce2_smb_rpkt[rpkt_type - DCE2_SMB_RPKT_TYPE_START];
+        dce2_fill_rpkt_info(rpkt, p);
+        rpkt->pseudo_type = PSEUDO_PKT_DCE_FRAG;
+        if (DCE2_SsnFromClient(p))
+        {
+            data_overhead = DCE2_MOCK_HDR_LEN__SMB_CLI + DCE2_MOCK_HDR_LEN__CO_CLI;
+            memset((void*)rpkt->data, 0, data_overhead);
+            DCE2_SmbInitRdata((uint8_t*)rpkt->data, PKT_FROM_CLIENT);
+            DCE2_CoInitRdata((uint8_t*)rpkt->data +
+                DCE2_MOCK_HDR_LEN__SMB_CLI, PKT_FROM_CLIENT);
+        }
+        else
+        {
+            data_overhead = DCE2_MOCK_HDR_LEN__SMB_SRV + DCE2_MOCK_HDR_LEN__CO_SRV;
+            memset((void*)rpkt->data, 0, data_overhead);
+            DCE2_SmbInitRdata((uint8_t*)rpkt->data, PKT_FROM_SERVER);
+            DCE2_CoInitRdata((uint8_t*)rpkt->data +
+                DCE2_MOCK_HDR_LEN__SMB_SRV, PKT_FROM_SERVER);
+        }
+        break;
+
     case DCE2_RPKT_TYPE__UDP_CL_FRAG:
-        // FIXIT-M add support when SMB, UDP are ported
+        // FIXIT-M add support when UDP is ported
         return nullptr;
 
     case DCE2_RPKT_TYPE__TCP_CO_SEG:
     case DCE2_RPKT_TYPE__TCP_CO_FRAG:
         rpkt = dce2_tcp_rpkt[rpkt_type - DCE2_TCP_RPKT_TYPE_START];
-        endianness = (DceEndianness*)rpkt->endianness;
-        rpkt->reset();
-        rpkt->endianness = (Endianness*)endianness;
-        ((DceEndianness*)rpkt->endianness)->reset();
-        rpkt->pkth = p->pkth;
-        rpkt->ptrs = p->ptrs;
-        rpkt->flow = p->flow;
-        rpkt->proto_bits = p->proto_bits;
-        rpkt->packet_flags = p->packet_flags;
-        rpkt->packet_flags |= PKT_PSEUDO;
-        rpkt->user_policy_id = p->user_policy_id;
+        dce2_fill_rpkt_info(rpkt, p);
         if (rpkt_type == DCE2_RPKT_TYPE__TCP_CO_FRAG)
         {
             rpkt->pseudo_type = PSEUDO_PKT_DCE_FRAG;
index f394342bee13a4ab85531d831c7e0443dc58688e..669216d527636bd9668317a08b15fcfc808c1366 100644 (file)
@@ -2890,6 +2890,7 @@ static void dce2_smb_thread_init()
         {
             Packet* p = (Packet*)snort_calloc(sizeof(Packet));
             p->data = (uint8_t*)snort_calloc(DCE2_REASSEMBLY_BUF_SIZE);
+            p->endianness = (Endianness*)new DceEndianness();
             p->dsize = DCE2_REASSEMBLY_BUF_SIZE;
             dce2_smb_rpkt[i] = p;
         }
@@ -2914,6 +2915,7 @@ static void dce2_smb_thread_term()
                 {
                     snort_free((void*)p->data);
                 }
+                delete p->endianness;
                 snort_free(p);
                 dce2_smb_rpkt[i] = nullptr;
             }
index 459f461b768422e601f1d943644b03a8121c8db1..d950e5317da858a57128a37db668fc85026750cd 100644 (file)
@@ -31,6 +31,7 @@
 #define DCE2_SMB_NAME "dce_smb"
 #define DCE2_SMB_HELP "dce over smb inspection"
 #define DCE2_SMB_RPKT_TYPE_MAX 4
+#define DCE2_SMB_RPKT_TYPE_START 1
 
 #define DCE2_SMB_BAD_NBSS_TYPE 2
 #define DCE2_SMB_BAD_TYPE 3
index 661bb41fddce4290eb982afaec72947e94366755..0cfb00b4f341c7bb5c46fadbefb25a25cdc30a38 100644 (file)
@@ -29,7 +29,6 @@
 #include "utils/util.h"
 #include "detection/detect.h"
 
-
 #define SERVICE_0     (0)                // IPC start
 #define SERVICE_1     (SERVICE_0+4)      // DISK start
 #define SERVICE_FS    (SERVICE_1+3)      // Failure
@@ -322,28 +321,25 @@ static DCE2_Ret DCE2_SmbWriteAndXRawRequest(DCE2_SmbSsnData* ssd, const SmbNtHdr
 
             if (ftracker->fp_writex_raw->remaining == 0)
             {
-                //FIXIT-M  - port Create reassembled packet
-/*
-                    const uint8_t *data_ptr = DCE2_BufferData(ftracker->fp_writex_raw->buf);
-                    uint32_t data_len = DCE2_BufferLength(ftracker->fp_writex_raw->buf);
-                    SFSnortPacket *rpkt = DCE2_SmbGetRpkt(ssd,
-                            &data_ptr, &data_len, DCE2_RPKT_TYPE__SMB_TRANS);
+                const uint8_t* data_ptr = DCE2_BufferData(ftracker->fp_writex_raw->buf);
+                uint32_t data_len = DCE2_BufferLength(ftracker->fp_writex_raw->buf);
+                Packet* rpkt = DCE2_SmbGetRpkt(ssd,
+                    &data_ptr, &data_len, DCE2_RPKT_TYPE__SMB_TRANS);
 
-                    if (rpkt == nullptr)
-                    {
-                        DCE2_BufferEmpty(ftracker->fp_writex_raw->buf);
-                        return DCE2_RET__ERROR;
-                    }
+                if (rpkt == nullptr)
+                {
+                    DCE2_BufferEmpty(ftracker->fp_writex_raw->buf);
+                    return DCE2_RET__ERROR;
+                }
 
-                    DebugMessage(DEBUG_DCE_SMB,
-                                "Reassembled WriteAndX raw mode request\n"));
-                    DCE2_DEBUG_CODE(DCE2_DEBUG__MAIN, DCE2_PrintPktData(rpkt->payload, rpkt->payload_size););
+                DebugMessage(DEBUG_DCE_SMB,
+                    "Reassembled WriteAndX raw mode request\n");
+                DCE2_PrintPktData(rpkt->data, rpkt->dsize);
 
-                    (void)DCE2_SmbProcessRequestData(ssd, fid, data_ptr, data_len, 0);
+                (void)DCE2_SmbProcessRequestData(ssd, fid, data_ptr, data_len, 0);
 
-                    DCE2_SmbReturnRpkt();
-                    DCE2_BufferEmpty(ftracker->fp_writex_raw->buf);
-*/
+                DCE2_SmbReturnRpkt(ssd);
+                DCE2_BufferEmpty(ftracker->fp_writex_raw->buf);
             }
         }
         else
index 4652dc1874ee579ac1739b9de2f38bbaf5e24f98..2ff58fd1b71aeb8de286fe3582dc44aa740bfc49 100644 (file)
@@ -936,24 +936,34 @@ static DCE2_Ret DCE2_SmbUpdateTransResponse(DCE2_SmbSsnData* ssd,
     {
         DCE2_MOVE(nb_ptr, nb_len, ((uint8_t*)smb_hdr + doff) - nb_ptr);
 
-        if ((dcnt != 0)
-            && (DCE2_SmbBufferTransactionData(ttracker, nb_ptr, dcnt, ddisp)
-            != DCE2_RET__SUCCESS))
+               if ((ttracker->dsent < ttracker->tdcnt)
+                || (ttracker->psent < ttracker->tpcnt)
+                || !DCE2_BufferIsEmpty(ttracker->dbuf))
         {
-            return DCE2_RET__ERROR;
-        }
+                       if ((dcnt != 0)
+                               && (DCE2_SmbBufferTransactionData(ttracker, nb_ptr, dcnt, ddisp)
+                                       != DCE2_RET__SUCCESS))
+                       {                        
+                               return DCE2_RET__ERROR;
+                       }
+               }
     }
 
     if (data_params & DCE2_SMB_TRANS__PARAMS)
     {
         DCE2_MOVE(nb_ptr, nb_len, ((uint8_t*)smb_hdr + poff) - nb_ptr);
-
-        if ((pcnt != 0)
-            && (DCE2_SmbBufferTransactionParameters(ttracker, nb_ptr, pcnt, pdisp)
-            != DCE2_RET__SUCCESS))
+               if ((ttracker->dsent < ttracker->tdcnt)
+                || (ttracker->psent < ttracker->tpcnt)
+                || !DCE2_BufferIsEmpty(ttracker->dbuf))
         {
-            return DCE2_RET__ERROR;
-        }
+                       if ((pcnt != 0)
+                               && (DCE2_SmbBufferTransactionParameters(ttracker, nb_ptr, pcnt, pdisp)
+                                       != DCE2_RET__SUCCESS))
+                       {
+                               return DCE2_RET__ERROR;
+                       }
+               }
     }
 
     if ((ttracker->dsent == ttracker->tdcnt)
@@ -1168,20 +1178,40 @@ DCE2_Ret DCE2_SmbTransaction(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
         switch (ttracker->subcom)
         {
         case TRANS_TRANSACT_NMPIPE:
-        case TRANS_READ_NMPIPE:
-        {
-            // FIXIT-M port reassembly case
+        case TRANS_READ_NMPIPE:      
+            if (!DCE2_BufferIsEmpty(ttracker->dbuf))
+            {
+                const uint8_t* data_ptr = DCE2_BufferData(ttracker->dbuf);
+                uint32_t data_len = DCE2_BufferLength(ttracker->dbuf);                 
+                Packet* rpkt = DCE2_SmbGetRpkt(ssd, &data_ptr,
+                                                                                          &data_len, DCE2_RPKT_TYPE__SMB_TRANS);
 
-            uint16_t dcnt = SmbTransactionRespDataCnt((SmbTransactionResp*)nb_ptr);
-            uint16_t doff = SmbTransactionRespDataOff((SmbTransactionResp*)nb_ptr);
+                if (rpkt == nullptr)
+                    return DCE2_RET__ERROR;
 
-            DCE2_MOVE(nb_ptr, nb_len, ((uint8_t*)smb_hdr + doff) - nb_ptr);
+                DebugMessage(DEBUG_DCE_SMB, "Reassembled Transaction response\n");
+                DCE2_PrintPktData(rpkt->data, rpkt->dsize);
 
-            if (DCE2_SmbProcessResponseData(ssd, nb_ptr, dcnt) != DCE2_RET__SUCCESS)
-                return DCE2_RET__ERROR;
+                status = DCE2_SmbProcessResponseData(ssd, data_ptr, data_len);
+
+                DCE2_SmbReturnRpkt(ssd);
+
+                if (status != DCE2_RET__SUCCESS)
+                    return status;
+            }
+            else
+            {
+                uint16_t dcnt = SmbTransactionRespDataCnt((SmbTransactionResp*)nb_ptr);
+                uint16_t doff = SmbTransactionRespDataOff((SmbTransactionResp*)nb_ptr);
+
+                DCE2_MOVE(nb_ptr, nb_len, ((uint8_t*)smb_hdr + doff) - nb_ptr);
+
+                if (DCE2_SmbProcessResponseData(ssd, nb_ptr, dcnt) != DCE2_RET__SUCCESS)
+                    return DCE2_RET__ERROR;
+            }
 
             break;
-        }
+        
         case TRANS_SET_NMPIPE_STATE:
             DebugFormat(DEBUG_DCE_SMB, "Setting pipe "
                 "to %s mode\n", ttracker->pipe_byte_mode ? "byte" : "message");
@@ -1617,23 +1647,20 @@ DCE2_Ret DCE2_SmbTransactionSecondary(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_
     case TRANS_TRANSACT_NMPIPE:
     case TRANS_WRITE_NMPIPE:
     {
-// FIXIT-M uncomment after porting packet reassembly code
-/*
-                const uint8_t *data_ptr = DCE2_BufferData(ttracker->dbuf);
-                uint32_t data_len = DCE2_BufferLength(ttracker->dbuf);
-                rpkt = DCE2_SmbGetRpkt(ssd, &data_ptr, &data_len, DCE2_RPKT_TYPE__SMB_TRANS);
+        const uint8_t* data_ptr = DCE2_BufferData(ttracker->dbuf);
+        uint32_t data_len = DCE2_BufferLength(ttracker->dbuf); 
+        Packet* rpkt = DCE2_SmbGetRpkt(ssd, &data_ptr, &data_len, DCE2_RPKT_TYPE__SMB_TRANS);
 
-                if (rpkt == nullptr)
-                    return DCE2_RET__ERROR;
+        if (rpkt == nullptr)
+            return DCE2_RET__ERROR;
 
-                DebugMessage(DEBUG_DCE_SMB, "Reassembled Transaction request\n"));
-                DCE2_DEBUG_CODE(DCE2_DEBUG__MAIN, DCE2_PrintPktData(rpkt->payload, rpkt->payload_size););
+        DebugMessage(DEBUG_DCE_SMB, "Reassembled Transaction request\n");
+        DCE2_PrintPktData(rpkt->data, rpkt->dsize);
 
-                status = DCE2_SmbTransactionReq(ssd, ttracker, data_ptr, data_len,
-                        DCE2_BufferData(ttracker->pbuf), DCE2_BufferLength(ttracker->pbuf));
+        status = DCE2_SmbTransactionReq(ssd, ttracker, data_ptr, data_len,
+            DCE2_BufferData(ttracker->pbuf), DCE2_BufferLength(ttracker->pbuf));
 
-                DCE2_SmbReturnRpkt();
-*/
+        DCE2_SmbReturnRpkt(ssd);
     }
     break;
 
@@ -1722,3 +1749,4 @@ DCE2_Ret DCE2_SmbNtTransactSecondary(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_h
 
     return DCE2_RET__SUCCESS;
 }
+
index 72ff8ea98bea243314e03108ab31858c59e2e3bb..94ff9aba111f738d522a94e41c7573e502f708ad 100644 (file)
@@ -1071,15 +1071,11 @@ DCE2_Ret DCE2_SmbProcessRequestData(DCE2_SmbSsnData* ssd,
 {
     DCE2_SmbFileTracker* ftracker = DCE2_SmbGetFileTracker(ssd, fid);
 
-    DebugFormat(DEBUG_DCE_SMB,
-        "Entering Processing request data with Fid: 0x%04X, ftracker ? %s ~~~~~~~~~~~~~~~~~\n",
-        fid,ftracker ? "TRUE" : "FALSE");
     if (ftracker == nullptr)
         return DCE2_RET__ERROR;
 
     DebugFormat(DEBUG_DCE_SMB,
-        "Processing request data with Fid: 0x%04X, is_ipc ? %s ~~~~~~~~~~~~~~~~~\n", ftracker->fid,
-        ftracker->is_ipc ? "TRUE" : "FALSE");
+        "Processing request data with Fid: 0x%04X ~~~~~~~~~~~~~~~~~\n", ftracker->fid);
 
     // Set this in case of chained commands or reassembled packet
     ssd->cur_rtracker->ftracker = ftracker;
@@ -1138,3 +1134,187 @@ DCE2_Ret DCE2_SmbProcessResponseData(DCE2_SmbSsnData* ssd,
     return DCE2_RET__SUCCESS;
 }
 
+static inline uint16_t SmbHtons(const uint16_t* ptr)
+{
+    return alignedNtohs(ptr);
+}
+
+/********************************************************************
+ * Function: DCE2_SmbInitRdata()
+ *
+ * Purpose:
+ *  Initializes the reassembled packet structure for an SMB
+ *  reassembled packet.  Uses WriteAndX and ReadAndX.
+ *  TODO Use command that was used when reassembly occurred.
+ *  One issue with this is that multiple different write/read
+ *  commands can be used to write/read the full DCE/RPC
+ *  request/response.
+ *
+ * Arguments:
+ *  uint8_t * - pointer to the start of the NetBIOS header where
+ *              data initialization should start.
+ *  int dir   - FLAG_FROM_CLIENT or FLAG_FROM_SERVER
+ *
+ * Returns: None
+ *
+ ********************************************************************/
+void DCE2_SmbInitRdata(uint8_t* nb_ptr, int dir)
+{
+    NbssHdr* nb_hdr = (NbssHdr*)nb_ptr;
+    SmbNtHdr* smb_hdr = (SmbNtHdr*)((uint8_t*)nb_hdr + sizeof(NbssHdr));
+
+    nb_hdr->type = NBSS_SESSION_TYPE__MESSAGE;
+    memcpy((void*)smb_hdr->smb_idf, (void*)"\xffSMB", sizeof(smb_hdr->smb_idf));
+
+    if (dir == PKT_FROM_CLIENT)
+    {
+        SmbWriteAndXReq* writex =
+            (SmbWriteAndXReq*)((uint8_t*)smb_hdr + sizeof(SmbNtHdr));
+        uint16_t offset = sizeof(SmbNtHdr) + sizeof(SmbWriteAndXReq);
+
+        smb_hdr->smb_com = SMB_COM_WRITE_ANDX;
+        smb_hdr->smb_flg = 0x00;
+
+        writex->smb_wct = 12;
+        writex->smb_com2 = SMB_COM_NO_ANDX_COMMAND;
+        writex->smb_doff = SmbHtons(&offset);
+    }
+    else
+    {
+        SmbReadAndXResp* readx =
+            (SmbReadAndXResp*)((uint8_t*)smb_hdr + sizeof(SmbNtHdr));
+        uint16_t offset = sizeof(SmbNtHdr) + sizeof(SmbReadAndXResp);
+
+        smb_hdr->smb_com = SMB_COM_READ_ANDX;
+        smb_hdr->smb_flg = 0x80;
+
+        readx->smb_wct = 12;
+        readx->smb_com2 = SMB_COM_NO_ANDX_COMMAND;
+        readx->smb_doff = SmbHtons(&offset);
+    }
+}
+
+/********************************************************************
+ * Function: DCE2_SmbSetRdata()
+ *
+ * Purpose:
+ *  When a reassembled packet is needed this function is called to
+ *  fill in appropriate fields to make the reassembled packet look
+ *  correct from an SMB standpoint.
+ *
+ * Arguments:
+ *  DCE2_SmbSsnData * - the session data structure.
+ *  uint8_t * - pointer to the start of the NetBIOS header where
+ *              data initialization should start.
+ *  uint16_t  - the length of the connection-oriented DCE/RPC data.
+ *
+ * Returns: None
+ *
+ ********************************************************************/
+void DCE2_SmbSetRdata(DCE2_SmbSsnData* ssd, uint8_t* nb_ptr, uint16_t co_len)
+{
+    NbssHdr* nb_hdr = (NbssHdr*)nb_ptr;
+    SmbNtHdr* smb_hdr = (SmbNtHdr*)((uint8_t*)nb_hdr + sizeof(NbssHdr));
+    uint16_t uid = (ssd->cur_rtracker == nullptr) ? 0 : ssd->cur_rtracker->uid;
+    uint16_t tid = (ssd->cur_rtracker == nullptr) ? 0 : ssd->cur_rtracker->tid;
+    DCE2_SmbFileTracker* ftracker = (ssd->cur_rtracker == nullptr) ? nullptr :
+        ssd->cur_rtracker->ftracker;
+
+    smb_hdr->smb_uid = SmbHtons((const uint16_t*)&uid);
+    smb_hdr->smb_tid = SmbHtons((const uint16_t*)&tid);
+
+    if (DCE2_SsnFromClient(ssd->sd.wire_pkt))
+    {
+        SmbWriteAndXReq* writex =
+            (SmbWriteAndXReq*)((uint8_t*)smb_hdr + sizeof(SmbNtHdr));
+        uint32_t nb_len = sizeof(SmbNtHdr) + sizeof(SmbWriteAndXReq) + co_len;
+
+        /* The data will get truncated anyway since we can only fit
+         * 64K in the reassembly buffer */
+        if (nb_len > UINT16_MAX)
+            nb_len = UINT16_MAX;
+
+        nb_hdr->length = htons((uint16_t)nb_len);
+
+        if ((ftracker != nullptr) && (ftracker->fid > 0))
+        {
+            uint16_t fid = (uint16_t)ftracker->fid;
+            writex->smb_fid = SmbHtons(&fid);
+        }
+        else
+        {
+            writex->smb_fid = 0;
+        }
+
+        writex->smb_countleft = SmbHtons(&co_len);
+        writex->smb_dsize = SmbHtons(&co_len);
+        writex->smb_bcc = SmbHtons(&co_len);
+    }
+    else
+    {
+        SmbReadAndXResp* readx =
+            (SmbReadAndXResp*)((uint8_t*)smb_hdr + sizeof(SmbNtHdr));
+        uint32_t nb_len = sizeof(SmbNtHdr) + sizeof(SmbReadAndXResp) + co_len;
+
+        /* The data will get truncated anyway since we can only fit
+         * 64K in the reassembly buffer */
+        if (nb_len > UINT16_MAX)
+            nb_len = UINT16_MAX;
+
+        nb_hdr->length = htons((uint16_t)nb_len);
+
+        readx->smb_remaining = SmbHtons(&co_len);
+        readx->smb_dsize = SmbHtons(&co_len);
+        readx->smb_bcc = SmbHtons(&co_len);
+    }
+}
+
+Packet* DCE2_SmbGetRpkt(DCE2_SmbSsnData* ssd,
+    const uint8_t** data, uint32_t* data_len, DCE2_RpktType rtype)
+{
+    if ((ssd == nullptr) || (data == nullptr) || (*data == nullptr)
+        || (data_len == nullptr) || (*data_len == 0))
+        return nullptr;
+
+    Packet* rpkt = DCE2_GetRpkt(ssd->sd.wire_pkt, rtype, *data, *data_len);
+
+    if (rpkt == nullptr)
+    {
+        DebugFormat(DEBUG_DCE_SMB,
+            "%s(%d) Failed to create reassembly packet.",
+            __FILE__, __LINE__);
+
+        return nullptr;
+    }
+
+    if (DCE2_PushPkt(rpkt, &ssd->sd) != DCE2_RET__SUCCESS)
+    {
+        DebugFormat(DEBUG_DCE_SMB,
+            "%s(%d) Failed to push packet onto packet stack.",
+            __FILE__, __LINE__);
+        return nullptr;
+    }
+
+    *data = rpkt->data;
+    *data_len = rpkt->dsize;
+
+    uint16_t header_len;
+    switch (rtype)
+    {
+    case DCE2_RPKT_TYPE__SMB_TRANS:
+        if (DCE2_SmbType(ssd) == SMB_TYPE__REQUEST)
+            header_len = DCE2_MOCK_HDR_LEN__SMB_CLI;
+        else
+            header_len = DCE2_MOCK_HDR_LEN__SMB_SRV;
+        DCE2_SmbSetRdata(ssd, (uint8_t*)rpkt->data,
+            (uint16_t)(rpkt->dsize - header_len));
+        DCE2_MOVE(*data, *data_len, header_len);
+        break;
+    case DCE2_RPKT_TYPE__SMB_SEG:
+    default:
+        break;
+    }
+
+    return rpkt;
+}
+
index 6af78a4fafeb9db83be31b5175d5353f7c6dcb18..369663591e9ae2e4f802b107936e5a81fb073467 100644 (file)
@@ -163,6 +163,10 @@ DCE2_Ret DCE2_SmbProcessRequestData(DCE2_SmbSsnData*, const uint16_t,
     const uint8_t*, uint32_t, uint64_t);
 DCE2_Ret DCE2_SmbProcessResponseData(DCE2_SmbSsnData*,
     const uint8_t*, uint32_t);
+void DCE2_SmbInitRdata(uint8_t*, int);
+void DCE2_SmbSetRdata(DCE2_SmbSsnData*, uint8_t*, uint16_t);
+Packet* DCE2_SmbGetRpkt(DCE2_SmbSsnData*, const uint8_t **,
+    uint32_t*, DCE2_RpktType);
 
 /********************************************************************
  * Inline functions
@@ -322,5 +326,10 @@ inline bool DCE2_SmbIsTransactionComplete(DCE2_SmbTransactionTracker* ttracker)
     return false;
 }
 
+inline void DCE2_SmbReturnRpkt(DCE2_SmbSsnData* ssd)
+{
+    DCE2_PopPkt(&ssd->sd);
+}
+
 #endif