]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #268 in SNORT/snort3 from dce to master
authorRuss Combs (rucombs) <rucombs@cisco.com>
Wed, 17 Feb 2016 21:15:34 +0000 (16:15 -0500)
committerRuss Combs (rucombs) <rucombs@cisco.com>
Wed, 17 Feb 2016 21:15:34 +0000 (16:15 -0500)
Squashed commit of the following:

commit 69fbec7af0f882ff21c7e70efd25d6cf01170f12
Author: rrp <rrp@cisco.com>
Date:   Mon Feb 15 14:11:56 2016 -0500

    DCE - Add session creation/lookup and packet checks to TCP and SMB eval code.
    Tested with DCE over TCP and DCE over SMB traffic pcaps. Verified that the sessions get created/looked up correctly. Verified peg counters and profile stats for different processing sections

17 files changed:
src/main/snort_debug.h
src/service_inspectors/dce_rpc/CMakeLists.txt
src/service_inspectors/dce_rpc/Makefile.am
src/service_inspectors/dce_rpc/dce_co.cc [new file with mode: 0644]
src/service_inspectors/dce_rpc/dce_co.h
src/service_inspectors/dce_rpc/dce_common.cc
src/service_inspectors/dce_rpc/dce_common.h
src/service_inspectors/dce_rpc/dce_list.h
src/service_inspectors/dce_rpc/dce_smb.cc
src/service_inspectors/dce_rpc/dce_smb.h
src/service_inspectors/dce_rpc/dce_smb_module.cc
src/service_inspectors/dce_rpc/dce_smb_paf.cc
src/service_inspectors/dce_rpc/dce_tcp.cc
src/service_inspectors/dce_rpc/dce_tcp.h
src/service_inspectors/dce_rpc/dce_tcp_module.cc
src/service_inspectors/dce_rpc/dce_tcp_paf.cc
src/service_inspectors/dce_rpc/dce_utils.h

index 4365c7df228748cfdb2f123a5a0dbb72ef82757d..ba1f7f9e0d8965de9c737bc43a0b932315baac0d 100644 (file)
 #define DEBUG_LOGGER          0x0040000000000000LL
 #define DEBUG_DCE_TCP         0x0080000000000000LL
 #define DEBUG_DCE_SMB         0x0100000000000000LL
+#define DEBUG_DCE_COMMON      0x0200000000000000LL
 
 #ifdef PIGLET
-#define DEBUG_PIGLET          0x0200000000000000LL
+#define DEBUG_PIGLET          0x0400000000000000LL
 #endif
 
 
index d64aad13812438eeab828a806019403ee87cbc8c..5fee68f9b28461ff333aeac775e52140e1eb35cf 100644 (file)
@@ -1,5 +1,6 @@
 
 set( FILE_LIST
+   dce_co.cc
    dce_co.h 
    dce_common.cc 
    dce_common.h 
index 7db794e998cd17baab48b62f5f94958f040bad67..2126698b0ef71a217d7b2dfc8a33720bbe5ce3b7 100644 (file)
@@ -1,4 +1,5 @@
 file_list = \
+dce_co.cc \
 dce_co.h \
 dce_common.cc \
 dce_common.h \
diff --git a/src/service_inspectors/dce_rpc/dce_co.cc b/src/service_inspectors/dce_rpc/dce_co.cc
new file mode 100644 (file)
index 0000000..46bd5fd
--- /dev/null
@@ -0,0 +1,51 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2016-2016 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// dce_co.cc author Rashmi Pitre <rrp@cisco.com>
+// based on work by Todd Wease
+
+#include "dce_co.h"
+
+/********************************************************************
+ * Function: DCE2_CoInitTracker()
+ *
+ * Initializes fields in the connection-oriented tracker to
+ * sentinels.  Many decisions are made based on whether or not
+ * these fields have been set.
+ *
+ ********************************************************************/
+void DCE2_CoInitTracker(DCE2_CoTracker *cot)
+{
+    if (cot == NULL)
+        return;
+
+    cot->max_xmit_frag = DCE2_SENTINEL;
+    cot->data_byte_order = DCE2_SENTINEL;
+    cot->ctx_id = DCE2_SENTINEL;
+    cot->opnum = DCE2_SENTINEL;
+    cot->call_id = DCE2_SENTINEL;
+    cot->stub_data = NULL;
+    cot->got_bind = 0;
+
+    cot->frag_tracker.opnum = DCE2_SENTINEL;
+    cot->frag_tracker.ctx_id = DCE2_SENTINEL;
+    cot->frag_tracker.expected_call_id = DCE2_SENTINEL;
+    cot->frag_tracker.expected_opnum = DCE2_SENTINEL;
+    cot->frag_tracker.expected_ctx_id = DCE2_SENTINEL;
+}
+
index d6fa8ee899d3a8e4d217f417f6c7834d0a00658d..d97ce9d62ee0800a8a1f90fca9d1a0f91e176059 100644 (file)
@@ -23,6 +23,7 @@
 #define DCE_CO_H
 
 #include "dce_common.h"
+#include "dce_list.h"
 
 #define DCE2_CO_BAD_MAJOR_VERSION           27
 #define DCE2_CO_BAD_MINOR_VERSION           28
@@ -89,6 +90,56 @@ struct DceRpcCoHdr
 
 #pragma pack()
 
+struct DCE2_CoFragTracker
+{
+    DCE2_Buffer* cli_stub_buf;
+    DCE2_Buffer* srv_stub_buf;
+
+    int opnum;    /* Opnum that is ultimatley used for request */
+    int ctx_id;   /* Context id that is ultimatley used for request */
+
+    /* These are set on a first fragment received */
+    int expected_call_id;  /* Expected call id for fragments */
+    int expected_opnum;    /* Expected call id for fragments */
+    int expected_ctx_id;   /* Expected call id for fragments */
+};
+
+struct DCE2_CoSeg
+{
+    DCE2_Buffer* buf;
+
+    /* If there is enough data in segmentation buffer for header,
+     * this will be set to the frag length in the header */
+    uint16_t frag_len;
+};
+
+struct DCE2_CoTracker
+{
+    DCE2_List* ctx_ids;  /* splayed list so most recently used goes to front of list */
+    int got_bind;        /* got an accepted bind */
+
+    /* Queue of pending client bind or alter context request context items
+     * Since the actual context id number doesn't have to occur sequentially
+     * in the context list in the client packet, need to keep track to match
+     * up server response since server doesn't reply with actual context id
+     * numbers, but in the order they were in the client packet */
+    DCE2_Queue* pending_ctx_ids;
+
+    /* Keeps track of fragmentation buffer and frag specfic data */
+    DCE2_CoFragTracker frag_tracker;
+
+    int max_xmit_frag;    /* The maximum negotiated size of a client request */
+    int data_byte_order;  /* Depending on policy is from bind or request */
+    int ctx_id;           /* The current context id of the request */
+    int opnum;            /* The current opnum of the request */
+    int call_id;          /* The current call id of the request */
+    const uint8_t* stub_data;   /* Current pointer to stub data in the request */
+
+    /* For transport segmentation */
+    DCE2_CoSeg cli_seg;
+    DCE2_CoSeg srv_seg;
+};
+
 inline uint8_t DceRpcCoVersMaj(const DceRpcCoHdr* co)
 {
     return co->pversion.major;
@@ -114,5 +165,7 @@ inline uint16_t DceRpcCoFragLen(const DceRpcCoHdr* co)
     return DceRpcNtohs(&co->frag_length, DceRpcCoByteOrder(co));
 }
 
+void DCE2_CoInitTracker(DCE2_CoTracker*);
+
 #endif
 
index 09d237336f520c4439c93b8dc7e0566a75de19e6..9c96365d087f804b92cbc3439171cb07b685cd3f 100644 (file)
@@ -25,7 +25,7 @@
 #include "log/messages.h"
 #include "main/snort_debug.h"
 
-const char* dce2_get_policy_name(DCE2_POLICY policy)
+const char* dce2_get_policy_name(DCE2_Policy policy)
 {
     const char* policyStr = nullptr;
     switch (policy)
@@ -75,7 +75,7 @@ bool dce2_set_common_config(Value& v, dce2CommonProtoConf& common)
         common.max_frag_len = v.get_long();
 
     else if ( v.is("policy") )
-        common.policy = (DCE2_POLICY)v.get_long();
+        common.policy = (DCE2_Policy)v.get_long();
     else
         return false;
     return true;
@@ -92,21 +92,26 @@ void print_dce2_common_config(dce2CommonProtoConf& common)
         dce2_get_policy_name(common.policy));
 }
 
-bool dce2_paf_abort(Flow* flow)
+bool dce2_paf_abort(Flow* flow, DCE2_SsnData* sd)
 {
     if (flow->get_session_flags() & SSNFLAG_MIDSTREAM)
     {
-        DebugMessage(DEBUG_DCE_TCP,
+        DebugMessage(DEBUG_DCE_COMMON,
             "Aborting PAF because of midstream pickup.\n");
         return true;
     }
     else if (!(flow->get_session_flags() & SSNFLAG_ESTABLISHED))
     {
-        DebugMessage(DEBUG_DCE_TCP,
+        DebugMessage(DEBUG_DCE_COMMON,
             "Aborting PAF because of unestablished session.\n");
         return true;
     }
-    // FIXIT-M add the remaining checks
+
+    if ((sd != NULL) && DCE2_SsnNoInspect(sd))
+    {
+        DebugMessage(DEBUG_DCE_COMMON, "Aborting PAF because of session data check.\n");
+        return true;
+    }
 
     return false;
 }
index 637162ca2db0ce4550f3aee386e4afc1ebcac318..4250b656d3a9b638e933f1c6d8ec0a5d356a55cd 100644 (file)
 #include "main/snort_types.h"
 #include "framework/module.h"
 #include "framework/inspector.h"
+#include "protocols/packet.h"
 
 extern const InspectApi dce2_smb_api;
 extern const InspectApi dce2_tcp_api;
 
 #define GID_DCE2 145
 
-enum DCE2_POLICY
+enum DCE2_Policy
 {
     DCE2_POLICY__WIN2000 = 0,
     DCE2_POLICY__WINXP,
@@ -60,7 +61,7 @@ struct dce2CommonProtoConf
 {
     bool disable_defrag;
     uint16_t max_frag_len;
-    DCE2_POLICY policy;
+    DCE2_Policy policy;
 };
 
 #define DCE2_DEBUG__PAF_END_MSG    "=========================================================="
@@ -136,10 +137,19 @@ struct DCE2_Roptions
     const uint8_t* stub_data;  /* Set to NULL if not applicable */
 };
 
+enum DCE2_SsnFlag
+{
+    DCE2_SSN_FLAG__NONE               = 0x0000,
+    DCE2_SSN_FLAG__AUTODETECTED       = 0x0001,
+    DCE2_SSN_FLAG__NO_INSPECT         = 0x0002,
+    DCE2_SSN_FLAG__ALL                = 0xffff
+};
+
 struct DCE2_SsnData
 {
-    DCE2_POLICY server_policy;
-    DCE2_POLICY client_policy;
+    DCE2_TransType trans;
+    DCE2_Policy server_policy;
+    DCE2_Policy client_policy;
     int flags;
     const Packet* wire_pkt;
     uint64_t alert_mask;
@@ -186,9 +196,50 @@ inline uint16_t DceRpcNtohs(const uint16_t* ptr, const DceRpcBoFlag bo_flag)
     return ((value & 0xff00) >> 8) | ((value & 0x00ff) << 8);
 }
 
+inline void DCE2_ResetRopts(DCE2_Roptions* ropts)
+{
+    ropts->first_frag = DCE2_SENTINEL;
+    ropts->opnum = DCE2_SENTINEL;
+    ropts->hdr_byte_order = DCE2_SENTINEL;
+    ropts->data_byte_order = DCE2_SENTINEL;
+    ropts->stub_data = NULL;
+}
+
+inline void DCE2_SsnSetAutodetected(DCE2_SsnData* sd, Packet* p)
+{
+    sd->flags |= DCE2_SSN_FLAG__AUTODETECTED;
+    sd->autodetect_dir = p->packet_flags & (PKT_FROM_CLIENT | PKT_FROM_SERVER);
+}
+
+inline int DCE2_SsnAutodetectDir(DCE2_SsnData* sd)
+{
+    return sd->autodetect_dir;
+}
+
+inline int DCE2_SsnAutodetected(DCE2_SsnData* sd)
+{
+    return sd->flags & DCE2_SSN_FLAG__AUTODETECTED;
+}
+
+inline void DCE2_SsnClearAutodetected(DCE2_SsnData* sd)
+{
+    sd->flags &= ~DCE2_SSN_FLAG__AUTODETECTED;
+    sd->autodetect_dir = 0;
+}
+
+inline void DCE2_SsnSetNoInspect(DCE2_SsnData* sd)
+{
+    sd->flags |= DCE2_SSN_FLAG__NO_INSPECT;
+}
+
+inline int DCE2_SsnNoInspect(DCE2_SsnData* sd)
+{
+    return sd->flags & DCE2_SSN_FLAG__NO_INSPECT;
+}
+
 bool dce2_set_common_config(Value&, dce2CommonProtoConf&);
 void print_dce2_common_config(dce2CommonProtoConf&);
-bool dce2_paf_abort(Flow*);
+bool dce2_paf_abort(Flow*, DCE2_SsnData*);
 
 #endif
 
index 67fe9f7fb74e0a2579d5189468534a34b69a820f..18d6e679bc417a7be0ccd307c7d7d58b974c1252 100644 (file)
@@ -25,8 +25,8 @@
 *
 ****************************************************************************/
 
-#ifndef _DCE_LIST_H_
-#define _DCE_LIST_H_
+#ifndef DCE_LIST_H
+#define DCE_LIST_H
 
 #include "dce_utils.h"
 
@@ -82,6 +82,26 @@ struct DCE2_List
     struct DCE2_ListNode* prev;
 };
 
+struct DCE2_QueueNode
+{
+    void* data;
+    DCE2_QueueNode* prev;
+    DCE2_QueueNode* next;
+};
+
+typedef DCE2_ListDataFree DCE2_QueueDataFree;
+
+struct DCE2_Queue
+{
+    uint32_t num_nodes;
+    DCE2_QueueDataFree data_free;
+    DCE2_QueueNode* current;
+    DCE2_QueueNode* head;
+    DCE2_QueueNode* tail;
+    DCE2_QueueNode* next;
+    DCE2_QueueNode* prev;
+};
+
 /********************************************************************
  * Public function prototypes
  ********************************************************************/
@@ -120,4 +140,5 @@ inline bool DCE2_ListIsEmpty(DCE2_List* list)
     return false;
 }
 
-#endif   
+#endif
+
index 90fe7f53136c5e4c862c9fbc7bf90c89551ddc86..efb93186621929c3dde1b17c45ba7107304cefac 100644 (file)
 #include "dce_smb_module.h"
 #include "dce_list.h"
 #include "main/snort_debug.h"
+#include "file_api/file_service.h"
 
 THREAD_LOCAL dce2SmbStats dce2_smb_stats;
 
 THREAD_LOCAL ProfileStats dce2_smb_pstat_main;
 THREAD_LOCAL ProfileStats dce2_smb_pstat_session;
 THREAD_LOCAL ProfileStats dce2_smb_pstat_new_session;
-THREAD_LOCAL ProfileStats dce2_smb_pstat_session_state;
 THREAD_LOCAL ProfileStats dce2_smb_pstat_detect;
 THREAD_LOCAL ProfileStats dce2_smb_pstat_log;
 THREAD_LOCAL ProfileStats dce2_smb_pstat_co_seg;
@@ -47,6 +47,10 @@ THREAD_LOCAL ProfileStats dce2_smb_pstat_smb_file_api;
 THREAD_LOCAL ProfileStats dce2_smb_pstat_smb_fingerprint;
 THREAD_LOCAL ProfileStats dce2_smb_pstat_smb_negotiate;
 
+Dce2SmbFlowData::Dce2SmbFlowData() : FlowData(flow_id)
+{
+}
+
 unsigned Dce2SmbFlowData::flow_id = 0;
 
 DCE2_SmbSsnData* get_dce2_smb_session_data(Flow* flow)
@@ -57,6 +61,91 @@ DCE2_SmbSsnData* get_dce2_smb_session_data(Flow* flow)
     return fd ? &fd->dce2_smb_session : nullptr;
 }
 
+static DCE2_SmbSsnData* set_new_dce2_smb_session(Packet* p)
+{
+    Dce2SmbFlowData* fd = new Dce2SmbFlowData;
+
+    p->flow->set_application_data(fd);
+    return(&fd->dce2_smb_session);
+}
+
+static DCE2_SmbSsnData* dce2_create_new_smb_session(Packet* p, dce2SmbProtoConf config)
+{
+    DCE2_SmbSsnData* dce2_smb_sess = NULL;
+    Profile profile(dce2_smb_pstat_new_session);
+
+    if (DCE2_SmbAutodetect(p))
+    {
+        DebugMessage(DEBUG_DCE_SMB, "DCE over SMB packet detected\n");
+        DebugMessage(DEBUG_DCE_SMB, "Creating new session\n");
+
+        dce2_smb_sess = set_new_dce2_smb_session(p);
+        if ( dce2_smb_sess )
+        {
+            dce2_smb_sess->dialect_index = DCE2_SENTINEL;
+            dce2_smb_sess->max_outstanding_requests = 10;  // Until Negotiate/SessionSetupAndX
+            dce2_smb_sess->cli_data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER;
+            dce2_smb_sess->srv_data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER;
+            dce2_smb_sess->pdu_state = DCE2_SMB_PDU_STATE__COMMAND;
+            dce2_smb_sess->uid = DCE2_SENTINEL;
+            dce2_smb_sess->tid = DCE2_SENTINEL;
+            dce2_smb_sess->ftracker.fid = DCE2_SENTINEL;
+            dce2_smb_sess->rtracker.mid = DCE2_SENTINEL;
+            dce2_smb_sess->max_file_depth = FileService::get_max_file_depth();
+
+            DCE2_ResetRopts(&dce2_smb_sess->sd.ropts);
+
+            dce2_smb_stats.smb_sessions++;
+            DebugFormat(DEBUG_DCE_SMB,"Created (%p)\n", (void*)dce2_smb_sess);
+
+            dce2_smb_sess->sd.trans = DCE2_TRANS_TYPE__SMB;
+            dce2_smb_sess->sd.server_policy = config.common.policy;
+            dce2_smb_sess->sd.client_policy = DCE2_POLICY__WINXP;
+            dce2_smb_sess->sd.wire_pkt = p;
+
+            DCE2_SsnSetAutodetected(&dce2_smb_sess->sd, p);
+        }
+    }
+
+    return dce2_smb_sess;
+}
+
+DCE2_SmbSsnData* dce2_handle_smb_session(Packet* p, dce2SmbProtoConf& config)
+{
+    Profile profile(dce2_smb_pstat_session);
+
+    DCE2_SmbSsnData* dce2_smb_sess =  get_dce2_smb_session_data(p->flow);
+
+    if (dce2_smb_sess == nullptr)
+    {
+        dce2_smb_sess = dce2_create_new_smb_session(p, config);
+    }
+    else
+    {
+        DCE2_SsnData* sd = (DCE2_SsnData*)dce2_smb_sess;
+        sd->wire_pkt = p;
+
+        if (DCE2_SsnAutodetected(sd) && !(p->packet_flags & sd->autodetect_dir))
+        {
+            /* Try to autodetect in opposite direction */
+            if (!DCE2_SmbAutodetect(p))
+            {
+                DebugMessage(DEBUG_DCE_SMB, "Bad autodetect.\n");
+                DCE2_SsnNoInspect(sd);
+                dce2_smb_stats.sessions_aborted++;
+                dce2_smb_stats.bad_autodetects++;
+                return NULL;
+            }
+            DCE2_SsnClearAutodetected(sd);
+        }
+    }
+    DebugFormat(DEBUG_DCE_SMB, "Session pointer: %p\n", (void*)dce2_smb_sess);
+
+    // FIXIT-M add remaining session handling logic
+
+    return dce2_smb_sess;
+}
+
 //-------------------------------------------------------------------------
 // class stuff
 //-------------------------------------------------------------------------
@@ -98,17 +187,25 @@ void Dce2Smb::show(SnortConfig*)
 
 void Dce2Smb::eval(Packet* p)
 {
-    DCE2_SmbSsnData* dce2_sess = get_dce2_smb_session_data(p->flow);
+    DCE2_SmbSsnData* dce2_smb_sess;
+    Profile profile(dce2_smb_pstat_main);
+
+    assert(p->has_tcp_data());
+    assert(p->flow);
 
-    if (dce2_sess == nullptr)
+    if (p->flow->get_session_flags() & SSNFLAG_MIDSTREAM)
     {
-        /*Check if it is a DCE2 over SMB packet*/
+        DebugMessage(DEBUG_DCE_SMB,
+            "Midstream - not inspecting.\n");
+        return;
+    }
 
-        if (DCE2_SmbAutodetect(p))
-        {
-            DebugMessage(DEBUG_DCE_SMB, "DCE over SMB packet detected\n");
-        }
+    dce2_smb_sess = dce2_handle_smb_session(p, config);
+    if (!dce2_smb_sess)
+    {
+        return;
     }
+    dce2_smb_stats.smb_pkts++;
 }
 
 //-------------------------------------------------------------------------
@@ -125,6 +222,11 @@ static void mod_dtor(Module* m)
     delete m;
 }
 
+static void dce2_smb_init()
+{
+    Dce2SmbFlowData::init();
+}
+
 static Inspector* dce2_smb_ctor(Module* m)
 {
     Dce2SmbModule* mod = (Dce2SmbModule*)m;
@@ -156,7 +258,7 @@ const InspectApi dce2_smb_api =
     (uint16_t)PktType::PDU,
     nullptr,  // buffers
     "dce_smb",
-    nullptr,
+    dce2_smb_init,
     nullptr, // pterm
     nullptr, // tinit
     nullptr, // tterm
index e6fa7bd1dc78d61a3e820e3e19ffbc156e61c50d..996c218df1b0b84392d76d0e3188c504520a172c 100644 (file)
@@ -23,6 +23,7 @@
 #define DCE_SMB_H
 
 #include "dce_common.h"
+#include "dce_co.h"
 #include "protocols/packet.h"
 #include "profiler/profiler.h"
 #include "framework/counts.h"
@@ -183,7 +184,6 @@ extern THREAD_LOCAL dce2SmbStats dce2_smb_stats;
 extern THREAD_LOCAL ProfileStats dce2_smb_pstat_main;
 extern THREAD_LOCAL ProfileStats dce2_smb_pstat_session;
 extern THREAD_LOCAL ProfileStats dce2_smb_pstat_new_session;
-extern THREAD_LOCAL ProfileStats dce2_smb_pstat_session_state;
 extern THREAD_LOCAL ProfileStats dce2_smb_pstat_detect;
 extern THREAD_LOCAL ProfileStats dce2_smb_pstat_log;
 extern THREAD_LOCAL ProfileStats dce2_smb_pstat_co_seg;
@@ -221,7 +221,7 @@ struct NbssHdr
     uint8_t type;
     uint8_t flags;   /* Treat flags as the upper byte to length */
     uint16_t length;
-} ;
+};
 
 struct SmbNtHdr
 {
@@ -249,11 +249,200 @@ struct SmbNtHdr
 };
 
 #pragma pack()
+enum DCE2_SmbSsnState
+{
+    DCE2_SMB_SSN_STATE__START         = 0x00,
+    DCE2_SMB_SSN_STATE__NEGOTIATED    = 0x01,
+    DCE2_SMB_SSN_STATE__FP_CLIENT     = 0x02,  // Fingerprinted client
+    DCE2_SMB_SSN_STATE__FP_SERVER     = 0x04   // Fingerprinted server
+};
+
+enum DCE2_SmbDataState
+{
+    DCE2_SMB_DATA_STATE__NETBIOS_HEADER,
+    DCE2_SMB_DATA_STATE__SMB_HEADER,
+    DCE2_SMB_DATA_STATE__NETBIOS_PDU
+};
+
+enum DCE2_SmbPduState
+{
+    DCE2_SMB_PDU_STATE__COMMAND,
+    DCE2_SMB_PDU_STATE__RAW_DATA
+};
+
+enum DCE2_SmbFileDirection
+{
+    DCE2_SMB_FILE_DIRECTION__UNKNOWN = 0,
+    DCE2_SMB_FILE_DIRECTION__UPLOAD,
+    DCE2_SMB_FILE_DIRECTION__DOWNLOAD
+};
+
+struct DCE2_SmbWriteAndXRaw
+{
+    int remaining;  // A signed integer so it can be negative
+    DCE2_Buffer* buf;
+};
+
+struct DCE2_SmbFileChunk
+{
+    uint64_t offset;
+    uint32_t length;
+    uint8_t* data;
+};
+
+struct DCE2_SmbFileTracker
+{
+    int fid;   // A signed integer so it can be set to sentinel
+    uint16_t uid;
+    uint16_t tid;
+    bool is_ipc;
+    char* file_name;
+
+    union
+    {
+        struct
+        {
+            // If pipe has been set to byte mode via TRANS_SET_NMPIPE_STATE
+            bool byte_mode;
+
+            // For Windows 2000
+            bool used;
+
+            // For WriteAndX requests that use raw mode flag
+            // Windows only
+            DCE2_SmbWriteAndXRaw* writex_raw;
+
+            // Connection-oriented DCE/RPC tracker
+            DCE2_CoTracker* co_tracker;
+        } nmpipe;
+
+        struct
+        {
+            uint64_t file_size;
+            uint64_t file_offset;
+            uint64_t bytes_processed;
+            DCE2_List* file_chunks;
+            uint32_t bytes_queued;
+            DCE2_SmbFileDirection file_direction;
+            bool sequential_only;
+        } file;
+    } tracker;
+
+#define fp_byte_mode   tracker.nmpipe.byte_mode
+#define fp_used        tracker.nmpipe.used
+#define fp_writex_raw  tracker.nmpipe.writex_raw
+#define fp_co_tracker  tracker.nmpipe.co_tracker
+#define ff_file_size          tracker.file.file_size
+#define ff_file_offset        tracker.file.file_offset
+#define ff_bytes_processed    tracker.file.bytes_processed
+#define ff_file_direction     tracker.file.file_direction
+#define ff_file_chunks        tracker.file.file_chunks
+#define ff_bytes_queued       tracker.file.bytes_queued
+#define ff_sequential_only    tracker.file.sequential_only
+};
+
+struct DCE2_SmbTransactionTracker
+{
+    int smb_type;
+    uint8_t subcom;
+    bool one_way;
+    bool disconnect_tid;
+    bool pipe_byte_mode;
+    uint32_t tdcnt;
+    uint32_t dsent;
+    DCE2_Buffer* dbuf;
+    uint32_t tpcnt;
+    uint32_t psent;
+    DCE2_Buffer* pbuf;
+    // For Transaction2/Query File Information
+    uint16_t info_level;
+};
+
+struct DCE2_SmbRequestTracker
+{
+    int smb_com;
+
+    int mid;   // A signed integer so it can be set to sentinel
+    uint16_t uid;
+    uint16_t tid;
+    uint16_t pid;
+
+    // For WriteRaw
+    bool writeraw_writethrough;
+    uint32_t writeraw_remaining;
+
+    // For Transaction/Transaction2/NtTransact
+    DCE2_SmbTransactionTracker ttracker;
+
+    // Client can chain a write to an open.  Need to write data, but also
+    // need to associate tracker with fid returned from server
+    DCE2_Queue* ft_queue;
+
+    // This is a reference to an existing file tracker
+    DCE2_SmbFileTracker* ftracker;
+
+    // Used for requests to cache data that will ultimately end up in
+    // the file tracker upon response.
+    char* file_name;
+    uint64_t file_size;
+    uint64_t file_offset;
+    bool sequential_only;
+
+    // For TreeConnect to know whether it's to IPC
+    bool is_ipc;
+};
 
 struct DCE2_SmbSsnData
 {
     DCE2_SsnData sd;  // This member must be first
-    // FIXIT-M add all the remaining fields
+
+    DCE2_Policy policy;
+
+    int dialect_index;
+    int ssn_state_flags;
+
+    DCE2_SmbDataState cli_data_state;
+    DCE2_SmbDataState srv_data_state;
+
+    DCE2_SmbPduState pdu_state;
+
+    int uid;   // A signed integer so it can be set to sentinel
+    int tid;   // A signed integer so it can be set to sentinel
+    DCE2_List* uids;
+    DCE2_List* tids;
+
+    // For tracking files and named pipes
+    DCE2_SmbFileTracker ftracker;
+    DCE2_List* ftrackers;  // List of DCE2_SmbFileTracker
+
+    // For tracking requests / responses
+    DCE2_SmbRequestTracker rtracker;
+    //DCE2_Queue *rtrackers;
+    uint16_t max_outstanding_requests;
+    uint16_t outstanding_requests;
+
+    // The current pid/mid node for this request/response
+    DCE2_SmbRequestTracker* cur_rtracker;
+
+    // Used for TCP segmentation to get full PDU
+    DCE2_Buffer* cli_seg;
+    DCE2_Buffer* srv_seg;
+
+    // These are used for commands we don't need to process
+    uint32_t cli_ignore_bytes;
+    uint32_t srv_ignore_bytes;
+
+    // The file API supports one concurrent upload/download per session.
+    // This is a reference to a file tracker so shouldn't be freed.
+    DCE2_SmbFileTracker* fapi_ftracker;
+
+#ifdef ACTIVE_RESPONSE
+    DCE2_SmbFileTracker* fb_ftracker;
+    bool block_pdus;
+#endif
+
+    // Maximum file depth as returned from file API
+    int64_t max_file_depth;
 };
 
 inline uint32_t NbssLen(const NbssHdr* nb)
index be6c4c70efbd24e19397e11b925f63037194e2cf..4b002056dd9b0e84b9e4b5bf2fbdd4b9b1a97def 100644 (file)
@@ -218,86 +218,81 @@ ProfileStats* Dce2SmbModule::get_profile(
         return &dce2_smb_pstat_new_session;
 
     case 3:
-        name = "dce smb session_state";
-        parent = "dce smb session";
-        return &dce2_smb_pstat_session_state;
-
-    case 4:
         name = "dce smb detect";
         parent = "dce smb main";
         return &dce2_smb_pstat_detect;
 
-    case 5:
+    case 4:
         name = "dce smb log";
         parent = "dce smb main";
         return &dce2_smb_pstat_log;
 
-    case 6:
+    case 5:
         name = "dce smb connection-oriented segment";
         parent = "dce smb main";
         return &dce2_smb_pstat_co_seg;
 
-    case 7:
+    case 6:
         name = "dce smb connection-oriented fragment";
         parent = "dce smb main";
         return &dce2_smb_pstat_co_frag;
 
-    case 8:
+    case 7:
         name = "dce smb connection-oriented reassembly";
         parent = "dce smb main";
         return &dce2_smb_pstat_co_reass;
 
-    case 9:
+    case 8:
         name = "dce smb connection-oriented context";
         parent = "dce smb main";
         return &dce2_smb_pstat_co_ctx;
 
-    case 10:
+    case 9:
         name = "dce smb segment";
         parent = "dce smb main";
         return &dce2_smb_pstat_smb_seg;
 
-    case 11:
+    case 10:
         name = "dce smb request";
         parent = "dce smb main";
         return &dce2_smb_pstat_smb_req;
 
-    case 12:
+    case 11:
         name = "dce smb uid";
         parent = "dce smb main";
         return &dce2_smb_pstat_smb_uid;
 
-    case 13:
+    case 12:
         name = "dce smb tid";
         parent = "dce smb main";
         return &dce2_smb_pstat_smb_tid;
 
-    case 14:
+    case 13:
         name = "dce smb fid";
         parent = "dce smb main";
         return &dce2_smb_pstat_smb_fid;
 
-    case 15:
+    case 14:
         name = "dce smb file";
         parent = "dce smb main";
         return &dce2_smb_pstat_smb_file;
 
-    case 16:
+    case 15:
         name = "dce smb file detect";
         parent = "dce smb file";
         return &dce2_smb_pstat_smb_file_detect;
 
-    case 17:
+    case 16:
         name = "dce smb file api";
         parent = "dce smb file";
         return &dce2_smb_pstat_smb_file_api;
 
-    case 18:
+    case 17:
         name = "dce smb fingerprint";
         parent = "dce smb main";
         return &dce2_smb_pstat_smb_fingerprint;
 
-    case 19:
+    case 18:
         name = "dce smb negotiate";
         parent = "dce smb main";
         return &dce2_smb_pstat_smb_negotiate;
index 5246302db4cdf1b0c47d78875c1f7f9abc833d74..160f07224fd203896391830d568667e0b0957ac7 100644 (file)
@@ -86,6 +86,7 @@ StreamSplitter::Status dce2_smb_paf(DCE2_PafSmbData* ss, Flow* flow, const uint8
     StreamSplitter::Status ps = StreamSplitter::SEARCH;
     uint32_t nb_hdr;
     uint32_t nb_len;
+    DCE2_SmbSsnData* sd = get_dce2_smb_session_data(flow);
 
     DebugFormat(DEBUG_DCE_SMB, "%s\n", DCE2_DEBUG__PAF_START_MSG_SMB);
     DebugFormat(DEBUG_DCE_SMB, "SMB: %u bytes of data\n", len);
@@ -99,7 +100,7 @@ StreamSplitter::Status dce2_smb_paf(DCE2_PafSmbData* ss, Flow* flow, const uint8
     UNUSED(flags);
 #endif
 
-    if (dce2_paf_abort(flow))
+    if (dce2_paf_abort(flow, (DCE2_SsnData*)sd))
     {
         DebugFormat(DEBUG_DCE_SMB, "%s\n", DCE2_DEBUG__PAF_END_MSG);
         return StreamSplitter::ABORT;
index 77e6fe8302e5e5dd51bdfe7289df2fac7c4e1273..e0a371eeabadcd4af4c2680b590329c01d2099f3 100644 (file)
 #include "dce_tcp_module.h"
 #include "main/snort_debug.h"
 
+Dce2TcpFlowData::Dce2TcpFlowData() : FlowData(flow_id)
+{
+}
+
 THREAD_LOCAL dce2TcpStats dce2_tcp_stats;
 
 THREAD_LOCAL ProfileStats dce2_tcp_pstat_main;
 THREAD_LOCAL ProfileStats dce2_tcp_pstat_session;
 THREAD_LOCAL ProfileStats dce2_tcp_pstat_new_session;
-THREAD_LOCAL ProfileStats dce2_tcp_pstat_session_state;
 THREAD_LOCAL ProfileStats dce2_tcp_pstat_detect;
 THREAD_LOCAL ProfileStats dce2_tcp_pstat_log;
 THREAD_LOCAL ProfileStats dce2_tcp_pstat_co_seg;
@@ -47,6 +50,84 @@ DCE2_TcpSsnData* get_dce2_tcp_session_data(Flow* flow)
     return fd ? &fd->dce2_tcp_session : nullptr;
 }
 
+static DCE2_TcpSsnData* set_new_dce2_tcp_session(Packet* p)
+{
+    Dce2TcpFlowData* fd = new Dce2TcpFlowData;
+
+    p->flow->set_application_data(fd);
+    return(&fd->dce2_tcp_session);
+}
+
+static DCE2_TcpSsnData* dce2_create_new_tcp_session(Packet* p, dce2TcpProtoConf config)
+{
+    DCE2_TcpSsnData* dce2_tcp_sess = NULL;
+    Profile profile(dce2_tcp_pstat_new_session);
+
+    if (DCE2_TcpAutodetect(p))
+    {
+        DebugMessage(DEBUG_DCE_TCP, "DCE over TCP packet detected\n");
+        DebugMessage(DEBUG_DCE_TCP, "Creating new session\n");
+
+        dce2_tcp_sess = set_new_dce2_tcp_session(p);
+
+        if ( dce2_tcp_sess )
+        {
+            DCE2_CoInitTracker(&dce2_tcp_sess->co_tracker);
+            DCE2_ResetRopts(&dce2_tcp_sess->sd.ropts);
+
+            dce2_tcp_stats.tcp_sessions++;
+            DebugFormat(DEBUG_DCE_TCP,"Created (%p)\n", (void*)dce2_tcp_sess);
+
+            dce2_tcp_sess->sd.trans = DCE2_TRANS_TYPE__TCP;
+            dce2_tcp_sess->sd.server_policy = config.common.policy;
+            dce2_tcp_sess->sd.client_policy = DCE2_POLICY__WINXP;
+            dce2_tcp_sess->sd.wire_pkt = p;
+
+            DCE2_SsnSetAutodetected(&dce2_tcp_sess->sd, p);
+        }
+    }
+
+    return dce2_tcp_sess;
+}
+
+DCE2_TcpSsnData* dce2_handle_tcp_session(Packet* p, dce2TcpProtoConf& config)
+{
+    Profile profile(dce2_tcp_pstat_session);
+
+    DCE2_TcpSsnData* dce2_tcp_sess =  get_dce2_tcp_session_data(p->flow);
+
+    if (dce2_tcp_sess == nullptr)
+    {
+        dce2_tcp_sess = dce2_create_new_tcp_session(p, config);
+    }
+    else
+    {
+        DCE2_SsnData* sd = (DCE2_SsnData*)dce2_tcp_sess;
+        sd->wire_pkt = p;
+
+        if (DCE2_SsnAutodetected(sd) && !(p->packet_flags & sd->autodetect_dir))
+        {
+            /* Try to autodetect in opposite direction */
+            if (!DCE2_TcpAutodetect(p))
+            {
+                DebugMessage(DEBUG_DCE_TCP, "Bad autodetect.\n");
+                DCE2_SsnNoInspect(sd);
+                dce2_tcp_stats.sessions_aborted++;
+                dce2_tcp_stats.bad_autodetects++;
+                return NULL;
+            }
+
+            DCE2_SsnClearAutodetected(sd);
+        }
+    }
+
+    DebugFormat(DEBUG_DCE_TCP, "Session pointer: %p\n", (void*)dce2_tcp_sess);
+
+    // FIXIT-M add remaining session handling logic
+
+    return dce2_tcp_sess;
+}
+
 //-------------------------------------------------------------------------
 // class stuff
 //-------------------------------------------------------------------------
@@ -79,18 +160,25 @@ void Dce2Tcp::show(SnortConfig*)
 
 void Dce2Tcp::eval(Packet* p)
 {
-    DCE2_TcpSsnData* dce2_sess = get_dce2_tcp_session_data(p->flow);
+    DCE2_TcpSsnData* dce2_tcp_sess;
+    Profile profile(dce2_tcp_pstat_main);
+
+    assert(p->has_tcp_data());
+    assert(p->flow);
 
-    if (dce2_sess == nullptr)
+    if (p->flow->get_session_flags() & SSNFLAG_MIDSTREAM)
     {
-        /*Check if it is a DCE2 over TCP packet*/
-       
-        if (DCE2_TcpAutodetect(p))
-        {
-            DebugMessage(DEBUG_DCE_TCP, "DCE over TCP packet detected\n");
-        }
-        
+        DebugMessage(DEBUG_DCE_TCP,
+            "Midstream - not inspecting.\n");
+        return;
     }
+
+    dce2_tcp_sess = dce2_handle_tcp_session(p, config);
+    if (!dce2_tcp_sess)
+    {
+        return;
+    }
+    dce2_tcp_stats.tcp_pkts++;
 }
 
 //-------------------------------------------------------------------------
@@ -120,6 +208,11 @@ static void dce2_tcp_dtor(Inspector* p)
     delete p;
 }
 
+static void dce2_tcp_init()
+{
+    Dce2TcpFlowData::init();
+}
+
 const InspectApi dce2_tcp_api =
 {
     {
@@ -138,7 +231,7 @@ const InspectApi dce2_tcp_api =
     (uint16_t)PktType::PDU,
     nullptr,  // buffers
     "dce_tcp",
-    nullptr,
+    dce2_tcp_init,
     nullptr, // pterm
     nullptr, // tinit
     nullptr, // tterm
index 09e08c83e5e3108e05ab0b6e670a8e65fefc5ded..4f63d5a792f2a3a046ec597ae8955d8a5d897c99 100644 (file)
@@ -114,7 +114,7 @@ inline bool DCE2_TcpAutodetect(Packet* p)
 struct DCE2_TcpSsnData
 {
     DCE2_SsnData sd;  // This member must be first
-    // FIXIT-M add all the remaining fields
+    DCE2_CoTracker co_tracker;
 };
 
 class Dce2TcpFlowData : public FlowData
index 0bb1edc793b2e0eba7196576f73c704b99471047..ccf5ad9a4808d70e0df9507cc79c85d6107575be 100644 (file)
@@ -143,36 +143,31 @@ ProfileStats* Dce2TcpModule::get_profile(
         return &dce2_tcp_pstat_new_session;
 
     case 3:
-        name = "dce tcp session state";
-        parent = "dce tcp session";
-        return &dce2_tcp_pstat_session_state;
-
-    case 4:
         name = "dce tcp detect";
         parent = "dce tcp main";
         return &dce2_tcp_pstat_detect;
 
-    case 5:
+    case 4:
         name = "dce tcp log";
         parent = "dce_tcp_main";
         return &dce2_tcp_pstat_log;
 
-    case 6:
+    case 5:
         name = "dce tcp connection-oriented segment";
         parent = "dce tcp main";
         return &dce2_tcp_pstat_co_seg;
 
-    case 7:
+    case 6:
         name = "dce tcp connection-oriented fragment";
         parent = "dce tcp main";
         return &dce2_tcp_pstat_co_frag;
 
-    case 8:
+    case 7:
         name = "dce tcp connection-oriented reassembly";
         parent = "dce tcp main";
         return &dce2_tcp_pstat_co_reass;
 
-    case 9:
+    case 8:
         name = "dce tcp connection-oriented context";
         parent = "dce tcp main";
         return &dce2_tcp_pstat_co_ctx;
index e30cbac2368876d7451fda7ec398dd4ae3ba9f16..a279a529268662f33d97f03f18090a9e61823b7b 100644 (file)
@@ -56,7 +56,7 @@ static StreamSplitter::Status dce2_tcp_paf(DCE2_PafTcpData* ds, Flow* flow, cons
         DebugMessage(DEBUG_DCE_TCP, "Packet from Server\n");
 #endif
 
-    if (dce2_paf_abort(flow))
+    if (dce2_paf_abort(flow, (DCE2_SsnData*)sd))
     {
         DebugFormat(DEBUG_DCE_TCP, "%s\n", DCE2_DEBUG__PAF_END_MSG);
         return StreamSplitter::ABORT;
index afef4a02038c3e2c54e1ce3cc3f97ff719825202..e923f1ed4f02ce0fc4de874fd2a5e963f4842f8a 100644 (file)
@@ -17,8 +17,8 @@
 // 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 //--------------------------------------------------------------------------
 
-#ifndef _DCE_UTILS_H_
-#define _DCE_UTILS_H_
+#ifndef DCE_UTILS_H
+#define DCE_UTILS_H
 
 #include <string.h>
 #include <ctype.h>
@@ -50,6 +50,14 @@ enum DCE2_Ret
     DCE2_RET__DUPLICATE
 };
 
+enum DCE2_TransType
+{
+    DCE2_TRANS_TYPE__NONE = 0,
+    DCE2_TRANS_TYPE__SMB,
+    DCE2_TRANS_TYPE__TCP,
+    DCE2_TRANS_TYPE__MAX
+};
+
 enum DCE2_IntType
 {
     DCE2_INT_TYPE__INT8,
@@ -76,6 +84,15 @@ struct Uuid
     uint8_t node[6];
 };
 
+struct DCE2_Buffer
+{
+    uint8_t* data;
+    uint32_t len;
+    uint32_t size;
+    uint32_t min_add_size;
+    uint32_t offset;
+};
+
 /********************************************************************
  * Inline function prototypes
  ********************************************************************/