]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #2821 in SNORT/snort3 from ~BJANDHYA/snort3:feature/dcerpc to...
authorLokesh Bevinamarad (lbevinam) <lbevinam@cisco.com>
Wed, 14 Apr 2021 15:07:29 +0000 (15:07 +0000)
committerLokesh Bevinamarad (lbevinam) <lbevinam@cisco.com>
Wed, 14 Apr 2021 15:07:29 +0000 (15:07 +0000)
Squashed commit of the following:

commit bddb8e4ce8aac8e8d78f3f62bf973228ac56994c
Author: Bhargava Jandhyala <bjandhya@cisco.com>
Date:   Wed Mar 31 12:21:44 2021 -0400

    dce_rpc: DCERPC Support over SMBv2

src/service_inspectors/dce_rpc/dce_co.cc
src/service_inspectors/dce_rpc/dce_smb1.cc
src/service_inspectors/dce_rpc/dce_smb1.h
src/service_inspectors/dce_rpc/dce_smb2.cc
src/service_inspectors/dce_rpc/dce_smb2.h
src/service_inspectors/dce_rpc/dce_smb2_file.cc
src/service_inspectors/dce_rpc/dce_smb2_tree.cc
src/service_inspectors/dce_rpc/dce_smb2_tree.h
src/service_inspectors/dce_rpc/dce_smb_common.cc
src/service_inspectors/dce_rpc/dce_smb_common.h
src/service_inspectors/dce_rpc/dce_smb_module.cc

index 106f787bb93c66a4190e4c2acac2610f02dbcea7..5cf0e1cf17be9f9d521bfea5bfe9abe3777be7a7 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "dce_expected_session.h"
 #include "dce_smb1.h"
+#include "dce_smb_common.h"
 #include "dce_smb_module.h"
 #include "dce_smb_utils.h"
 #include "dce_tcp.h"
@@ -230,6 +231,14 @@ void DCE2_CoInitTracker(DCE2_CoTracker* cot)
     cot->frag_tracker.expected_call_id = DCE2_SENTINEL;
     cot->frag_tracker.expected_opnum = DCE2_SENTINEL;
     cot->frag_tracker.expected_ctx_id = DCE2_SENTINEL;
+    cot->ctx_ids = nullptr;
+    cot->pending_ctx_ids = nullptr;
+    cot->frag_tracker.cli_stub_buf = nullptr;
+    cot->frag_tracker.srv_stub_buf = nullptr;
+    cot->cli_seg.buf = nullptr;
+    cot->cli_seg.frag_len = 0;
+    cot->srv_seg.buf = nullptr;
+    cot->srv_seg.frag_len = 0;
 }
 
 /********************************************************************
@@ -1350,8 +1359,7 @@ 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:
-        DCE2_SmbSetRdata((DCE2_SmbSsnData*)sd, wrdata,
-            (uint16_t)(rpkt->dsize - smb_hdr_len));
+        set_smb_reassembled_data(wrdata, (uint16_t)(rpkt->dsize - smb_hdr_len));
 
         if (rpkt_type == DCE2_RPKT_TYPE__SMB_CO_FRAG)
         {
@@ -2209,7 +2217,7 @@ static Packet* DCE2_CoGetSegRpkt(DCE2_SsnData* sd,
         if ( !rpkt )
             return nullptr;
 
-        DCE2_SmbSetRdata((DCE2_SmbSsnData*)sd, const_cast<uint8_t*>(rpkt->data),
+        set_smb_reassembled_data(const_cast<uint8_t*>(rpkt->data),
             (uint16_t)(rpkt->dsize - smb_hdr_len));
         break;
 
index f4396e3a35b8de495da68bfc0e3c1d4ea5c292fa..71b9a304c0278401497a5fbde0cd22e5531a0806 100644 (file)
@@ -24,6 +24,8 @@
 
 #include "dce_smb1.h"
 
+#include "dce_smb_utils.h"
+
 using namespace snort;
 
 //-------------------------------------------------------------------------
@@ -319,3 +321,8 @@ void Dce2Smb1SessionData::process()
     DCE2_Smb1Process(&ssd);
 }
 
+void Dce2Smb1SessionData::set_reassembled_data(uint8_t* nb_ptr,uint16_t co_len)
+{
+    DCE2_SmbSetRdata(&ssd, nb_ptr, co_len);
+}
+
index 716923e3856cd9a355ac6d16d6acbacad208a366..88bc18d92475c2bca8c2746ade0b5783a6b776fb 100644 (file)
@@ -277,6 +277,7 @@ public:
     { DCE2_SmbDataFree(&ssd); }
     void process() override;
     void handle_retransmit(FilePosition, FileVerdict) override { }
+    void set_reassembled_data(uint8_t*, uint16_t) override;
 
 private:
     DCE2_SmbSsnData ssd;
index 553f17122b0967aa67065b858a14363dcd1d943a..33262cb55134aa6209543589f884ab9b161a33a1 100644 (file)
@@ -398,7 +398,23 @@ void Dce2Smb2SessionData::process_command(const Smb2Hdr* smb_hdr,
         else
             dce2_smb_stats.v2_session_ignored++;
         break;
-
+    case SMB2_COM_IOCTL:
+        if (session)
+        {
+            if (SMB2_COMMAND_TYPE(IOCTL, REQUEST))
+            {
+                SMB2_HANDLE_HEADER_ERROR(IOCTL, REQUEST, ioctl_req)
+                session->process(command, SMB2_CMD_TYPE_REQUEST, smb_hdr, end);
+            }
+            else if ( SMB2_COMMAND_TYPE(IOCTL, RESPONSE))
+            {
+                SMB2_HANDLE_HEADER_ERROR(IOCTL, RESPONSE, ioctl_resp)
+                session->process(command, SMB2_CMD_TYPE_RESPONSE, smb_hdr, end);
+            }
+            else
+                SMB2_HANDLE_INVALID_STRUC_SIZE(ioctl)
+        }
+        break;
     default:
         dce2_smb_stats.v2_msgs_uninspected++;
         break;
@@ -468,9 +484,51 @@ void Dce2Smb2SessionData::process()
     {
         debug_logf(dce_smb_trace, p, "processing raw data for file id %" PRIu64 "\n",
             tcp_file_tracker->get_file_id());
-        
+
         if (!tcp_file_tracker->process_data(data_ptr, data_len))
             tcp_file_tracker->get_parent()->close_file(tcp_file_tracker->get_file_id());
     }
 }
 
+void Dce2Smb2SessionData::set_reassembled_data(uint8_t* nb_ptr, uint16_t co_len)
+{
+    NbssHdr* nb_hdr = (NbssHdr*)nb_ptr;
+    SmbNtHdr* smb_hdr = (SmbNtHdr*)((uint8_t*)nb_hdr + sizeof(NbssHdr));
+
+    uint32_t tid = (tcp_file_tracker) ? tcp_file_tracker->get_parent()->get_tree_id() : 0;
+    smb_hdr->smb_tid = alignedNtohl((const uint32_t*)&tid);
+
+    if (DetectionEngine::get_current_packet()->is_from_client())
+    {
+        Smb2WriteRequestHdr* write = (Smb2WriteRequestHdr*)((uint8_t*)smb_hdr + sizeof(SmbNtHdr));
+        uint32_t nb_len = sizeof(SmbNtHdr) + sizeof(Smb2WriteRequestHdr) + co_len;
+
+        if (nb_len > UINT16_MAX)
+            nb_len = UINT16_MAX;
+        write->structure_size = SMB2_WRITE_REQUEST_STRUC_SIZE;
+        nb_hdr->length = htons((uint16_t)nb_len);
+        if (tcp_file_tracker)
+        {
+            uint64_t fid = tcp_file_tracker->get_file_id();
+            write->fileId_persistent = alignedNtohq(&fid);
+            write->fileId_volatile = alignedNtohq(&fid);
+        }
+        else
+            write->fileId_persistent = write->fileId_volatile = 0;
+
+        write->length = alignedNtohs(&co_len);
+    }
+    else
+    {
+        Smb2ReadResponseHdr* read = (Smb2ReadResponseHdr*)((uint8_t*)smb_hdr + sizeof(SmbNtHdr));
+        uint32_t nb_len = sizeof(SmbNtHdr) + sizeof(Smb2ReadResponseHdr) + co_len;
+
+        if (nb_len > UINT16_MAX)
+            nb_len = UINT16_MAX;
+
+        nb_hdr->length = htons((uint16_t)nb_len);
+        read->structure_size = SMB2_READ_RESPONSE_STRUC_SIZE;
+        read->length = alignedNtohs(&co_len);
+    }
+}
+
index 498adf3ad27060ae39c69de836c6fec1e9468399..32c94093444689e41382085018fddde11e3e0642 100644 (file)
@@ -265,6 +265,9 @@ struct Smb2TreeConnectResponseHdr
 #define SMB2_LOGOFF_REQUEST_STRUC_SIZE 4
 #define SMB2_LOGOFF_RESPONSE_STRUC_SIZE 4
 
+#define SMB2_IOCTL_REQUEST_STRUC_SIZE 57
+#define SMB2_IOCTL_RESPONSE_STRUC_SIZE 49
+
 #define GET_CURRENT_PACKET snort::DetectionEngine::get_current_packet()
 
 class Dce2Smb2FileTracker;
@@ -419,6 +422,7 @@ public:
     void reset_matching_tcp_file_tracker(Dce2Smb2FileTracker*);
     void set_tcp_file_tracker(Dce2Smb2FileTracker* file_tracker)
     { tcp_file_tracker = file_tracker; }
+    void set_reassembled_data(uint8_t*, uint16_t) override;
 
 private:
     void process_command(const Smb2Hdr*, const uint8_t*);
index 9e18e32e8cf00b39c58fc8086ef24bce408ac306..106d94ceae75fbf87b5df6d65a94f15db0bbb4c5 100644 (file)
@@ -27,6 +27,7 @@
 #include "file_api/file_flows.h"
 #include "hash/hash_key_operations.h"
 
+#include "dce_co.h"
 #include "dce_smb2_session.h"
 #include "dce_smb2_tree.h"
 
@@ -100,6 +101,18 @@ bool Dce2Smb2FileTracker::process_data(const uint8_t* file_data,
     uint32_t data_size)
 {
     Dce2Smb2SessionData* current_flow = parent_tree->get_parent()->get_current_flow();
+
+    if (parent_tree->get_share_type() != SMB2_SHARE_TYPE_DISK)
+    {
+        if (data_size > UINT16_MAX)
+        {
+            data_size = UINT16_MAX;
+        }
+        DCE2_CoProcess(current_flow->get_dce2_session_data(), get_parent()->get_cotracker(),
+            file_data, data_size);
+        return true;
+    }
+
     int64_t file_detection_depth = current_flow->get_smb_file_depth();
     int64_t detection_size = 0;
 
@@ -153,8 +166,8 @@ bool Dce2Smb2FileTracker::process_data(const uint8_t* file_data,
 
 Dce2Smb2FileTracker::~Dce2Smb2FileTracker(void)
 {
-    debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "file tracker %" PRIu64
-        " file name hash %" PRIu64 " terminating\n", file_id, file_name_hash);
+    debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+        "file tracker %" PRIu64 " file name hash %" PRIu64 " terminating\n", file_id, file_name_hash);
 
     if (file_name)
         snort_free((void*)file_name);
index 76b3c95396fc19de453fd7e7d6edc0e3d3064ead..f16f41e98b33e6c890d11e596a520384dd56bbe4 100644 (file)
@@ -188,9 +188,12 @@ void Dce2Smb2TreeTracker::process_create_response(uint64_t message_id,
                 file_tracker = new Dce2Smb2FileTracker(file_id, this);
                 opened_files.insert(std::make_pair(file_id, file_tracker));
             }
-            file_tracker->set_info(create_request->get_file_name(),
-                create_request->get_file_name_size(), file_size, true);
-            create_request->reset_file_name();
+            if (share_type == SMB2_SHARE_TYPE_DISK)
+            {
+                file_tracker->set_info(create_request->get_file_name(),
+                    create_request->get_file_name_size(), file_size, true);
+                create_request->reset_file_name();
+            }
         }
         else
         {
@@ -241,8 +244,11 @@ void Dce2Smb2TreeTracker::process_create_request(uint64_t message_id,
         if (!file_tracker)
         {
             file_tracker = new Dce2Smb2FileTracker(file_id, this);
-            file_tracker->set_info(file_name, name_len, 0, true);
-            create_request->reset_file_name();
+            if (share_type == SMB2_SHARE_TYPE_DISK)
+            {
+                file_tracker->set_info(file_name, name_len, 0, true);
+                create_request->reset_file_name();
+            }
             opened_files.insert(std::make_pair(file_id, file_tracker));
         }
     }
@@ -345,6 +351,24 @@ void Dce2Smb2TreeTracker::process_write_request(uint64_t message_id,
     }
 }
 
+void Dce2Smb2TreeTracker::process_ioctl_command(uint8_t command_type, const Smb2Hdr* smb_header,
+    const uint8_t* end)
+{
+    const uint8_t* smb_data = (const uint8_t*)smb_header + SMB2_HEADER_LENGTH;
+    const uint8_t structure_size = (command_type == SMB2_CMD_TYPE_REQUEST) ?
+        SMB2_IOCTL_REQUEST_STRUC_SIZE : SMB2_IOCTL_RESPONSE_STRUC_SIZE;
+
+    const uint8_t* file_data = (const uint8_t*)smb_data + structure_size - 1;
+    int data_size = end - file_data;
+    Dce2Smb2SessionData* current_flow = parent_session->get_current_flow();
+    if (data_size > UINT16_MAX)
+    {
+        data_size = UINT16_MAX;
+    }
+
+    DCE2_CoProcess(current_flow->get_dce2_session_data(), co_tracker, file_data, data_size);
+}
+
 void Dce2Smb2TreeTracker::process(uint16_t command, uint8_t command_type,
     const Smb2Hdr* smb_header, const uint8_t* end)
 {
@@ -356,7 +380,7 @@ void Dce2Smb2TreeTracker::process(uint16_t command, uint8_t command_type,
             "%s_REQ: max req exceeded\n", smb2_command_string[command]);
         dce_alert(GID_DCE2, DCE2_SMB_MAX_REQS_EXCEEDED, (dce2CommonStats*)&dce2_smb_stats,
             *current_flow->get_dce2_session_data());
-        
+
         return;
     }
     uint64_t message_id = Smb2Mid(smb_header);
@@ -375,9 +399,8 @@ void Dce2Smb2TreeTracker::process(uint16_t command, uint8_t command_type,
             if (SMB2_SHARE_TYPE_DISK != share_type)
             {
                 debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "%s_REQ:"
-                    " ignored for ipc share\n", smb2_command_string[command]);
+                    "processed for ipc share\n", smb2_command_string[command]);
                 dce2_smb_stats.v2_crt_req_ipc++;
-                return;
             }
             process_create_request(message_id, smb_header, end);
         }
@@ -418,6 +441,17 @@ void Dce2Smb2TreeTracker::process(uint16_t command, uint8_t command_type,
         else if (SMB2_CMD_TYPE_REQUEST == command_type)
             process_write_request(message_id, smb_header, end);
         break;
+    case SMB2_COM_IOCTL:
+        if (SMB2_CMD_TYPE_ERROR_RESPONSE == command_type)
+        {
+            debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+                "%s_RESP: error\n", smb2_command_string[command]);
+        }
+        else if (SMB2_SHARE_TYPE_DISK != share_type)
+        {
+            process_ioctl_command(command_type, smb_header, end);
+        }
+        break;
     }
     if (SMB2_CMD_TYPE_RESPONSE == command_type or SMB2_CMD_TYPE_ERROR_RESPONSE == command_type)
         remove_request(message_id);
@@ -427,6 +461,13 @@ Dce2Smb2TreeTracker::~Dce2Smb2TreeTracker(void)
 {
     debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
         "tree tracker %" PRIu32 " terminating\n", tree_id);
+
+    if (co_tracker != nullptr)
+    {
+        DCE2_CoCleanTracker(co_tracker);
+        snort_free((void*)co_tracker);
+        co_tracker = nullptr;
+    }
     if (active_requests.size())
     {
         debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
index 84dfba4ee354ab348ad03d1219e65ed374610e04..67ff167c39d00c15ca18a082789238a2cbca0ab1 100644 (file)
@@ -24,6 +24,7 @@
 // This provides tree trackers for SMBv2.
 // Tree trackers are used to identify and track an opened share
 
+#include "dce_co.h"
 #include "dce_smb2.h"
 #include "dce_smb2_file.h"
 #include "dce_smb2_request.h"
@@ -45,6 +46,15 @@ public:
         debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
             "tree tracker %" PRIu32 " created\n", tree_id);
         memory::MemoryCap::update_allocations(sizeof(*this));
+        if (share_type != SMB2_SHARE_TYPE_DISK)
+        {
+            co_tracker = (DCE2_CoTracker*)snort_calloc(sizeof(DCE2_CoTracker));
+            DCE2_CoInitTracker(co_tracker);
+        }
+        else
+        {
+            co_tracker = nullptr;
+        }
     }
 
     ~Dce2Smb2TreeTracker();
@@ -55,6 +65,9 @@ public:
     Dce2Smb2RequestTracker* find_request(uint64_t);
     void process(uint16_t, uint8_t, const Smb2Hdr*, const uint8_t*);
     Dce2Smb2SessionTracker* get_parent() { return parent_session; }
+    DCE2_CoTracker* get_cotracker() { return co_tracker; }
+    uint32_t get_tree_id() { return tree_id; }
+    uint8_t get_share_type() { return share_type; }
 
 private:
     void process_set_info_request(const Smb2Hdr*);
@@ -66,11 +79,13 @@ private:
     void process_write_request(uint64_t, const Smb2Hdr*, const uint8_t*);
     uint64_t get_durable_file_id(const Smb2CreateRequestHdr*, const uint8_t*);
     bool remove_request(uint64_t);
+    void process_ioctl_command(uint8_t, const Smb2Hdr*, const uint8_t*);
     void store_request(uint64_t message_id, Dce2Smb2RequestTracker* request)
     { active_requests.insert(std::make_pair(message_id, request)); }
 
     uint32_t tree_id;
     uint8_t share_type;
+    DCE2_CoTracker* co_tracker; // Connection-oriented DCE/RPC tracker
     Dce2Smb2FileTrackerMap opened_files;
     Dce2Smb2RequestTrackerMap active_requests;
     Dce2Smb2SessionTracker* parent_session;
index 034fbdb5df19731363854154d419a9a4338ce327..52c49b6e4f8eb58788fa5a28b40607b7057a7f79 100644 (file)
@@ -99,8 +99,7 @@ Dce2SmbSessionData::Dce2SmbSessionData(const Packet* p,
 static inline DCE2_SmbVersion get_smb_version(const Packet* p)
 {
     // Only check reassembled SMB2 packet
-    if ( p->has_paf_payload() and
-        (p->dsize > sizeof(NbssHdr) + DCE2_SMB_ID_SIZE))
+    if ( p->has_paf_payload() and (p->dsize > sizeof(NbssHdr) + DCE2_SMB_ID_SIZE))
     {
         const SmbNtHdr* smb_hdr = (const SmbNtHdr*)(p->data + sizeof(NbssHdr));
         uint32_t smb_version_id = SmbId(smb_hdr);
@@ -196,3 +195,18 @@ char* get_smb_file_name(const uint8_t* data, uint32_t data_len, bool unicode,
     return fname;
 }
 
+void set_smb_reassembled_data(uint8_t* nb_ptr, uint16_t co_len)
+{
+    snort::Flow* flow = DetectionEngine::get_current_packet()->flow;
+    if (flow)
+    {
+        Dce2SmbFlowData* fd = (Dce2SmbFlowData*)flow->get_flow_data(
+            Dce2SmbFlowData::inspector_id);
+       if (fd)
+       {
+           Dce2SmbSessionData* smb_ssn_data = fd->get_smb_session_data();
+           smb_ssn_data->set_reassembled_data(nb_ptr, co_len);
+       }
+    }
+}
+
index 19c33384c4757647d5ac2f41b58ec595e5425096..63484d7be3d17024319c0f83ec5cf7dc83295359 100644 (file)
@@ -191,6 +191,11 @@ struct dce2SmbStats
     PegCount v2_cmpnd_req_lt_crossed;
     PegCount v2_tree_ignored;
     PegCount v2_session_ignored;
+    PegCount v2_ioctl;
+    PegCount v2_ioctl_err_resp;
+    PegCount v2_ioctl_inv_str_sz;
+    PegCount v2_ioctl_req_hdr_err;
+    PegCount v2_ioctl_resp_hdr_err;
     PegCount concurrent_sessions;
     PegCount max_concurrent_sessions;
 };
@@ -220,6 +225,7 @@ public:
 
     virtual void process() = 0;
     virtual void handle_retransmit(FilePosition, FileVerdict) = 0;
+    virtual void set_reassembled_data(uint8_t*, uint16_t) = 0;
 
     DCE2_SsnData* get_dce2_session_data()
     { return &sd; }
@@ -244,7 +250,7 @@ public:
     uint16_t get_smb_max_compound()
     {
         return sd.config ? ((dce2SmbProtoConf*)sd.config)->smb_max_compound :
-            SMB_DEFAULT_MAX_COMPOUND_REQ;
+               SMB_DEFAULT_MAX_COMPOUND_REQ;
     }
 
 protected:
@@ -285,6 +291,7 @@ DCE2_SsnData* get_dce2_session_data(snort::Flow*);
 snort::FileContext* get_smb_file_context(const snort::Packet*);
 snort::FileContext* get_smb_file_context(uint64_t, uint64_t, bool);
 char* get_smb_file_name(const uint8_t*, uint32_t, bool, uint16_t*);
+void set_smb_reassembled_data(uint8_t*, uint16_t);
 
 #endif
 
index b1fc1cbecaf15834f84427915895a5b3a584ae2b..33cc952ba362a5be67b140a227680de55720ef19 100644 (file)
@@ -178,6 +178,16 @@ static const PegInfo dce2_smb_pegs[] =
         "total number of packets ignored due to missing tree tracker" },
     { CountType::SUM, "v2_session_ignored",
         "total number of packets ignored due to missing session tracker" },
+    { CountType::SUM, "v2_ioctl",
+        "total number of ioctl calls" },
+    { CountType::SUM, "v2_ioctl_err_resp",
+        "total number of ioctl errors responses" },
+    { CountType::SUM, "v2_ioctl_inv_str_sz",
+        "total number of ioctl invalid structure size" },
+    { CountType::SUM, "v2_ioctl_req_hdr_err",
+        "total number of ioctl request header errors" },
+    { CountType::SUM, "v2_ioctl_resp_hdr_err",
+        "total number of ioctl response header errors" },
     { CountType::NOW, "concurrent_sessions", "total concurrent sessions" },
     { CountType::MAX, "max_concurrent_sessions", "maximum concurrent sessions" },
     { CountType::END, nullptr, nullptr }