From: Sumit Kumar (sumikum7) Date: Fri, 27 Oct 2023 18:07:41 +0000 (+0000) Subject: Pull request #4061: Porting into 760(snort3) for SMB Multichannel Redesigning (First... X-Git-Tag: 3.1.74.0~8 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=eaa9764bd10a89ba01e1fd69ab5d9927a3876371;p=thirdparty%2Fsnort3.git Pull request #4061: Porting into 760(snort3) for SMB Multichannel Redesigning (First done in 741) Merge in SNORT/snort3 from ~SUMIKUM7/snort3:porting_760 to master Squashed commit of the following: commit 6fc8604a2a7448163b8226ffaf77799c2965f4c1 Author: Sumit Kumar Date: Fri Oct 13 15:45:05 2023 +0530 dce_rpc: Added SMB Redsigned Multichannel enabled code --- diff --git a/src/detection/CMakeLists.txt b/src/detection/CMakeLists.txt index 064c53e32..757c0260f 100644 --- a/src/detection/CMakeLists.txt +++ b/src/detection/CMakeLists.txt @@ -13,6 +13,7 @@ set (DETECTION_INCLUDES rules.h signature.h treenodes.h + pattern_match_data.h ) add_library (detection OBJECT @@ -38,7 +39,6 @@ add_library (detection OBJECT ips_context.cc ips_context_chain.cc ips_context_data.cc - pattern_match_data.h pcrm.cc pcrm.h regex_offload.cc diff --git a/src/detection/pattern_match_data.h b/src/detection/pattern_match_data.h index 5dc3e1068..5b08e7063 100644 --- a/src/detection/pattern_match_data.h +++ b/src/detection/pattern_match_data.h @@ -69,7 +69,7 @@ struct PatternMatchData NO_FP = 0x20, }; - uint16_t flags; // from above enum + uint16_t flags = 0; // from above enum uint16_t mpse_flags; // passed through to mpse uint16_t fp_offset; diff --git a/src/file_api/file_flows.cc b/src/file_api/file_flows.cc index 1d1d41fee..e76a591a5 100644 --- a/src/file_api/file_flows.cc +++ b/src/file_api/file_flows.cc @@ -206,7 +206,6 @@ uint64_t FileFlows::get_new_file_instance() FileFlows::~FileFlows() { - std::lock_guard guard(file_flow_context_mutex); FileCache* file_cache = FileService::get_file_cache(); assert(file_cache); uint64_t file_id = 0; @@ -496,10 +495,11 @@ bool FileFlows::file_process(Packet* p, const uint8_t* file_data, int data_size, bool FileFlows::set_file_name(const uint8_t* fname, uint32_t name_size, uint64_t file_id, uint64_t multi_file_processing_id, const uint8_t* url, uint32_t url_size) { - bool is_new_context = false; FileContext* context; - if (file_id) + if (file_id) { + bool is_new_context = false; context = get_file_context(file_id, false, is_new_context, multi_file_processing_id); + } else context = get_current_file_context(); if ( !context ) diff --git a/src/file_api/file_segment.cc b/src/file_api/file_segment.cc index 9af6556e2..c2cfe1c54 100644 --- a/src/file_api/file_segment.cc +++ b/src/file_api/file_segment.cc @@ -110,6 +110,7 @@ void FileSegments::add(const uint8_t* file_data, int64_t data_size, uint64_t off data_size = end -offset; file_data = file_data + offset - start; } + insert_segment(file_data, data_size, offset, find_left, &left); } // New segment should be at the start of link list else if (!left) @@ -119,29 +120,41 @@ void FileSegments::add(const uint8_t* file_data, int64_t data_size, uint64_t off /* Overlap, trim off extra data from end */ data_size = head->offset - offset; } + insert_segment(file_data, data_size, offset, find_left, &left); } else { //Left Overlap - if ( (left->offset + left->data->size() > start) ) + while(left and (left->offset + left->data->size() <= end)) { - offset = left->offset + left->data->size(); - data_size = end - offset; - file_data = file_data + offset - start; - } - //Right Overlap - if ( (left->next->offset < end) ) - { - data_size = left->next->offset - offset; - } + const uint8_t *cur_file_data = file_data; + if ( (left->offset + left->data->size() > start) ) + { + offset = left->offset + left->data->size(); + data_size = end - offset; + cur_file_data = cur_file_data + offset - start; + } + //Right Overlap + if ( left->next and (left->next->offset < end) ) + { + data_size = left->next->offset - offset; + } + + insert_segment(cur_file_data, data_size, offset, find_left, &left); + left = left->next; + } } +} +void FileSegments::insert_segment(const uint8_t* file_data, int64_t data_size, uint64_t offset, bool find_left, FileSegment** left) +{ // ignore overlap case if (data_size <= 0) { FILE_DEBUG(file_trace , DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, - GET_CURRENT_PACKET, "Complete overlap while adding segments\n"); + GET_CURRENT_PACKET, "Complete overlap while adding segments offset : %lu data_size : %lu\n", + offset, data_size); return; } @@ -150,22 +163,22 @@ void FileSegments::add(const uint8_t* file_data, int64_t data_size, uint64_t off new_segment->data = new std::string((const char*)file_data, data_size); FILE_DEBUG(file_trace , DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, - GET_CURRENT_PACKET, "Adding offset : %u data_size : %lu\n", new_segment->offset, + GET_CURRENT_PACKET, "Adding offset : %lu data_size : %lu\n", offset, data_size); - if (!find_left) - { - previous->next = new_segment; - - } - else if (!left) + if (!*left) { new_segment->next = head; head = new_segment; } + else if (!find_left) + { + (*left)->next = new_segment; + } else { - new_segment->next = left->next; - left->next = new_segment; + new_segment->next = (*left)->next; + (*left)->next = new_segment; + *left = (*left)->next; } } @@ -179,7 +192,7 @@ FilePosition FileSegments::get_file_position(uint64_t data_size, uint64_t file_s return SNORT_FILE_START; } - if (file_size <= data_size + current_offset) + if (file_size and (file_size <= data_size + current_offset)) return SNORT_FILE_END; return SNORT_FILE_MIDDLE; diff --git a/src/file_api/file_segment.h b/src/file_api/file_segment.h index 7badb4df1..0785bff9a 100644 --- a/src/file_api/file_segment.h +++ b/src/file_api/file_segment.h @@ -63,6 +63,7 @@ private: snort::FileContext* context = nullptr; void add(const uint8_t* file_data, int64_t data_size, uint64_t offset); + void insert_segment(const uint8_t* file_data, int64_t data_size, uint64_t offset, bool find_left, FileSegment** left); FilePosition get_file_position(uint64_t data_size, uint64_t file_size); int process_one(snort::Packet*, const uint8_t* file_data, int data_size, snort::FilePolicyBase*, FilePosition position=SNORT_FILE_POSITION_UNKNOWN); diff --git a/src/hash/lru_cache_local.h b/src/hash/lru_cache_local.h index 1f5492335..4cc87f1e2 100644 --- a/src/hash/lru_cache_local.h +++ b/src/hash/lru_cache_local.h @@ -35,7 +35,8 @@ { CountType::SUM, "cache_misses", module " cache did not find entry" }, \ { CountType::SUM, "cache_replaces", module " cache found entry and replaced its value" }, \ { CountType::SUM, "cache_max", module " cache's maximum byte usage"}, \ - { CountType::SUM, "cache_prunes", module " cache pruned entry to make space for new entry" } + { CountType::SUM, "cache_prunes", module " cache pruned entry to make space for new entry" }, \ + { CountType::SUM, "cache_removes", module " cache removed existing entry"} struct LruCacheLocalStats { @@ -45,6 +46,7 @@ struct LruCacheLocalStats PegCount cache_replaces; PegCount cache_max; PegCount cache_prunes; + PegCount cache_removes; }; template @@ -66,6 +68,10 @@ public: // else return false replacing the existing value if asked bool add(const Key&, const Value&, bool replace = false); + // If key does not exist, return false; + // else remove the entry associated with key + bool remove(const Key&); + // Copy all key-value pairs from the cache void get_all_values(std::vector>&); @@ -159,6 +165,21 @@ bool LruCacheLocal::add(const Key& key, const Value& value, bo return false; } +template +bool LruCacheLocal::remove(const Key& key) +{ + LruMapIter it = map.find(key); + if (it == map.end()) + { + return false; + } + list.erase(it->second); + map.erase(it); + current_size -= entry_size; + stats.cache_removes++; + return true; +} + template void LruCacheLocal::get_all_values(std::vector>& kv) { diff --git a/src/ips_options/CMakeLists.txt b/src/ips_options/CMakeLists.txt index d81ed4bb4..4ae54c65e 100644 --- a/src/ips_options/CMakeLists.txt +++ b/src/ips_options/CMakeLists.txt @@ -1,3 +1,6 @@ +set(IPS_INCLUDES + extract.h +) SET( PLUGIN_LIST ips_ack.cc @@ -45,8 +48,8 @@ SET( PLUGIN_LIST set (IPS_SOURCES + ${IPS_INCLUDES} extract.cc - extract.h ips_classtype.cc ips_content.cc ips_detection_filter.cc @@ -141,3 +144,7 @@ endif ( HAVE_HYPERSCAN ) endif (STATIC_IPS_OPTIONS) add_subdirectory(test) + +install(FILES ${IPS_INCLUDES} + DESTINATION "${INCLUDE_INSTALL_PATH}/ips_options/" +) diff --git a/src/protocols/packet.h b/src/protocols/packet.h index 245e9f5bc..38d3e2b5e 100644 --- a/src/protocols/packet.h +++ b/src/protocols/packet.h @@ -229,7 +229,7 @@ struct SO_PUBLIC Packet { return (proto_bits & PROTO_BIT__UDP) and data and dsize; } bool has_udp_quic_data() const - { return (pseudo_type == PSEUDO_PKT_UDP_QUIC) and data and dsize; } + { return (is_cooked() and pseudo_type == PSEUDO_PKT_UDP_QUIC) and data and dsize; } /* Get general, non-boolean information */ PktType type() const diff --git a/src/service_inspectors/dce_rpc/CMakeLists.txt b/src/service_inspectors/dce_rpc/CMakeLists.txt index 3f4ca4b09..a8b19ad04 100644 --- a/src/service_inspectors/dce_rpc/CMakeLists.txt +++ b/src/service_inspectors/dce_rpc/CMakeLists.txt @@ -6,6 +6,7 @@ set( FILE_LIST dce_common.h dce_context_data.cc dce_context_data.h + dce_db.h dce_expected_session.cc dce_expected_session.h dce_http_proxy.cc @@ -18,25 +19,18 @@ set( FILE_LIST dce_http_server_module.h dce_http_server_splitter.cc dce_http_server_splitter.h - dce_list.cc dce_list.h - dce_smb1.cc - dce_smb1.h + dce_list.cc + dce_smb.cc + dce_smb.h dce_smb2.cc dce_smb2.h - dce_smb2_file.cc - dce_smb2_file.h - dce_smb2_request.h - dce_smb2_session.cc - dce_smb2_session.h - dce_smb2_tree.cc - dce_smb2_tree.h + dce_smb2_commands.cc + dce_smb2_commands.h + dce_smb2_utils.cc + dce_smb2_utils.h dce_smb_commands.cc dce_smb_commands.h - dce_smb_common.cc - dce_smb_common.h - dce_smb_inspector.cc - dce_smb_inspector.h dce_smb_module.cc dce_smb_module.h dce_smb_paf.cc diff --git a/src/service_inspectors/dce_rpc/dce_co.cc b/src/service_inspectors/dce_rpc/dce_co.cc index a5810ea25..e3f39ef60 100644 --- a/src/service_inspectors/dce_rpc/dce_co.cc +++ b/src/service_inspectors/dce_rpc/dce_co.cc @@ -28,8 +28,7 @@ #include "utils/util.h" #include "dce_expected_session.h" -#include "dce_smb1.h" -#include "dce_smb_common.h" +#include "dce_smb.h" #include "dce_smb_module.h" #include "dce_smb_utils.h" #include "dce_tcp.h" @@ -40,11 +39,13 @@ static THREAD_LOCAL int co_reassembled = 0; /* [MS-RPCE] 2.2.5 - 64-Bit Network Data Representation */ static const Uuid uuid_ndr64 = { 0x71710533, 0xbeba, 0x4937, 0x83, 0x19, - { 0xb5, 0xdb, 0xef, 0x9c, 0xcc, 0x36 } }; + { 0xb5, 0xdb, 0xef, 0x9c, 0xcc, 0x36 } +}; /* Endpoint mapper UUID */ static const Uuid uuid_epm = { 0xe1af8308, 0x5d1f, 0x11c9, 0x91, 0xa4, - { 0x08, 0x00, 0x2b, 0x14, 0xa0, 0xfa } }; + { 0x08, 0x00, 0x2b, 0x14, 0xa0, 0xfa } +}; static inline dce2CommonStats* dce_get_proto_stats_ptr(const DCE2_SsnData* sd) { @@ -54,7 +55,9 @@ static inline dce2CommonStats* dce_get_proto_stats_ptr(const DCE2_SsnData* sd) } else { - return((dce2CommonStats*)&dce2_smb_stats); + /* Since dce2_smb_stats derives from LruCacheLocalStats, + force return the pointer to first peg of the derived class */ + return((dce2CommonStats*)&(dce2_smb_stats.events)); } // FIXIT-M add HTTP, UDP cases when these are ported } @@ -387,6 +390,7 @@ static inline DCE2_CoSeg* DCE2_CoGetSegPtr(DCE2_CoTracker* cot) Packet* p = DetectionEngine::get_current_packet(); if (p == nullptr) return nullptr; + if ( p->is_from_server() ) return &cot->srv_seg; @@ -818,7 +822,6 @@ static void dce_co_process_ctx_result(DCE2_SsnData*, DCE2_CoTracker* cot, const Uuid* transport) { DCE2_CoCtxIdNode* ctx_node, * existing_ctx_node; - /* Dequeue context item in pending queue - this will get put in the permanent * context id list or freed */ ctx_node = (DCE2_CoCtxIdNode*)DCE2_QueueDequeue(cot->pending_ctx_ids); @@ -1361,6 +1364,7 @@ static Packet* dce_co_reassemble(DCE2_SsnData* sd, DCE2_CoTracker* cot, Packet* p = DetectionEngine::get_current_packet(); if (p == nullptr) return nullptr; + bool from_client = p->is_from_client(); int co_hdr_len = from_client ? DCE2_MOCK_HDR_LEN__CO_CLI : DCE2_MOCK_HDR_LEN__CO_SRV; @@ -1378,7 +1382,8 @@ 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: - set_smb_reassembled_data(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) { @@ -1418,7 +1423,7 @@ static Packet* dce_co_reassemble(DCE2_SsnData* sd, DCE2_CoTracker* cot, if ( from_client ) dce_common_stats->co_cli_seg_reassembled++; else - dce_common_stats->co_srv_seg_reassembled++; + dce_common_stats->co_srv_frag_reassembled++; } *co_hdr = (const DceRpcCoHdr*)rpkt->data; @@ -2163,7 +2168,6 @@ static void DCE2_CoEarlyReassemble(DCE2_SsnData* sd, DCE2_CoTracker* cot) { DCE2_Buffer* frag_buf = DCE2_CoGetFragBuf(&cot->frag_tracker); Packet* p = DetectionEngine::get_current_packet(); - if ( (p == nullptr) || p->is_from_server() ) return; @@ -2234,16 +2238,16 @@ static Packet* DCE2_CoGetSegRpkt(DCE2_SsnData* sd, Packet* p = DetectionEngine::get_current_packet(); if (p == nullptr) return nullptr; + Packet* rpkt = nullptr; - int smb_hdr_len = p->is_from_client() ? DCE2_MOCK_HDR_LEN__SMB_CLI : - DCE2_MOCK_HDR_LEN__SMB_SRV; + int smb_hdr_len = p->is_from_client() ? DCE2_MOCK_HDR_LEN__SMB_CLI : DCE2_MOCK_HDR_LEN__SMB_SRV; switch (sd->trans) { case DCE2_TRANS_TYPE__SMB: rpkt = DCE2_GetRpkt(p, DCE2_RPKT_TYPE__SMB_CO_SEG, data_ptr, data_len); - if ( !rpkt || !rpkt->data ) + if ( !rpkt || !rpkt->data ) return nullptr; set_smb_reassembled_data(const_cast(rpkt->data), @@ -2293,7 +2297,6 @@ static void DCE2_CoSegDecode(DCE2_SsnData* sd, DCE2_CoTracker* cot, DCE2_CoSeg* dce_common_stats->co_srv_seg_reassembled++; } - Packet* rpkt = DCE2_CoGetSegRpkt(sd, DCE2_BufferData(seg->buf), DCE2_BufferLength(seg->buf)); // FIXIT-M don't toss data until success response to diff --git a/src/service_inspectors/dce_rpc/dce_co.h b/src/service_inspectors/dce_rpc/dce_co.h index bc8dea3d0..4f3e5b317 100644 --- a/src/service_inspectors/dce_rpc/dce_co.h +++ b/src/service_inspectors/dce_rpc/dce_co.h @@ -265,7 +265,8 @@ enum DCE2_CoCtxTransport DCE2_CO_CTX_TRANS_SYNTAX_NDR64 }; -enum DCE2_CoEpmOpnum { +enum DCE2_CoEpmOpnum +{ DCE2_CO_EPT_NONE = -1, DCE2_CO_EPT_INSERT = 0, DCE2_CO_EPT_DELETE, diff --git a/src/service_inspectors/dce_rpc/dce_common.cc b/src/service_inspectors/dce_rpc/dce_common.cc index e0ded056c..7682ddf01 100644 --- a/src/service_inspectors/dce_rpc/dce_common.cc +++ b/src/service_inspectors/dce_rpc/dce_common.cc @@ -32,8 +32,6 @@ #include "dce_context_data.h" #include "dce_http_proxy_module.h" #include "dce_http_server_module.h" -#include "dce_smb1.h" -#include "dce_smb_common.h" #include "dce_smb_utils.h" #include "dce_tcp.h" #include "dce_udp.h" diff --git a/src/service_inspectors/dce_rpc/dce_common.h b/src/service_inspectors/dce_rpc/dce_common.h index 7cc7eb89a..3f1ba8362 100644 --- a/src/service_inspectors/dce_rpc/dce_common.h +++ b/src/service_inspectors/dce_rpc/dce_common.h @@ -186,7 +186,7 @@ struct DCE2_Roptions int opnum; /* Set to sentinel if not applicable */ /* dce_stub_data */ - const uint8_t* stub_data; /* Set to null if not applicable */ + const uint8_t* stub_data; /* Set to null if not applicable */ }; enum DCE2_SsnFlag diff --git a/src/service_inspectors/dce_rpc/dce_context_data.cc b/src/service_inspectors/dce_rpc/dce_context_data.cc index 0539d2c55..3e9697fbe 100644 --- a/src/service_inspectors/dce_rpc/dce_context_data.cc +++ b/src/service_inspectors/dce_rpc/dce_context_data.cc @@ -41,35 +41,35 @@ void DceContextData::init(DCE2_TransType trans) unsigned DceContextData::get_ips_id(DCE2_TransType trans) { - switch(trans) + switch (trans) { - case DCE2_TRANS_TYPE__SMB: - return DceContextData::smb_ips_id; - case DCE2_TRANS_TYPE__TCP: - return DceContextData::tcp_ips_id; - case DCE2_TRANS_TYPE__UDP: - return DceContextData::udp_ips_id; - default: - break; + case DCE2_TRANS_TYPE__SMB: + return DceContextData::smb_ips_id; + case DCE2_TRANS_TYPE__TCP: + return DceContextData::tcp_ips_id; + case DCE2_TRANS_TYPE__UDP: + return DceContextData::udp_ips_id; + default: + break; } return 0; } void DceContextData::set_ips_id(DCE2_TransType trans, unsigned id) { - switch(trans) + switch (trans) { - case DCE2_TRANS_TYPE__SMB: - DceContextData::smb_ips_id = id; - break; - case DCE2_TRANS_TYPE__TCP: - DceContextData::tcp_ips_id = id; - break; - case DCE2_TRANS_TYPE__UDP: - DceContextData::udp_ips_id = id; - break; - default: - break; + case DCE2_TRANS_TYPE__SMB: + DceContextData::smb_ips_id = id; + break; + case DCE2_TRANS_TYPE__TCP: + DceContextData::tcp_ips_id = id; + break; + case DCE2_TRANS_TYPE__UDP: + DceContextData::udp_ips_id = id; + break; + default: + break; } return; } @@ -145,9 +145,8 @@ void DceContextData::clear_current_ropts(IpsContext* context, DCE2_TransType tra { dcd->clear(); } - - return; } + void DceContextData::clear_current_ropts(const Packet* p, DCE2_TransType trans) { IpsContext* context = p ? p->context : nullptr; diff --git a/src/service_inspectors/dce_rpc/dce_db.h b/src/service_inspectors/dce_rpc/dce_db.h new file mode 100644 index 000000000..47e5812eb --- /dev/null +++ b/src/service_inspectors/dce_rpc/dce_db.h @@ -0,0 +1,116 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2020-2023 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_db.h author Neha Sharma + +// This implementation provides interface that can be extended for map, list, etc. +// Currently only map has been implemented to handle multiple smb sessions +// in single tcp connection. This database will modify/change to handle +// single smb session spread across multiple tcp connections. + +#ifndef DCE_DB_H +#define DCE_DB_H + +#include +#include +#include "dce_utils.h" + +#include "main/snort_types.h" + +template +class DCE2_Db +{ +public: + + virtual bool Insert(const Key& key, Value data) = 0; + virtual Value Find(const Key& key) = 0; + virtual void Remove(const Key& key) = 0; + virtual int GetSize() = 0; + virtual std::vector< std::pair > get_all_entry() = 0; +}; + +template +class DCE2_DbMap : public DCE2_Db +{ +public: + + DCE2_DbMap(bool gc = true) : garbage_collection(gc) { } + + ~DCE2_DbMap() + { + auto it = Map.cbegin(); + while (it != Map.cend()) + { + if (garbage_collection) + delete it->second; + it = Map.erase(it); + } + } + + bool Insert(const Key& key, Value data) override; + Value Find(const Key& key) override; + void Remove(const Key& key) override; + int GetSize() override + { + return Map.size(); + } + + std::vector< std::pair > get_all_entry() override; + +private: + std::unordered_map Map; + bool garbage_collection = true; +}; + +template +bool DCE2_DbMap::Insert(const Key& key, Value data) +{ + return Map.insert(std::make_pair(key,data)).second; +} + +template +Value DCE2_DbMap::Find(const Key& key) +{ + auto elem = Map.find(key); + if (elem != Map.end()) + return elem->second; + return nullptr; +} + +template +void DCE2_DbMap::Remove(const Key& key) +{ + auto elem = Map.find(key); + if (elem != Map.end()) + { + if (garbage_collection) + delete elem->second; + + Map.erase(elem->first); + } +} + +template +std::vector< std::pair >DCE2_DbMap::get_all_entry() +{ + std::vector > vec; + std::copy(Map.begin(), Map.end(), std::back_inserter(vec)); + return vec; +} + +#endif + diff --git a/src/service_inspectors/dce_rpc/dce_expected_session.cc b/src/service_inspectors/dce_rpc/dce_expected_session.cc index 38f672ae0..c260b991b 100644 --- a/src/service_inspectors/dce_rpc/dce_expected_session.cc +++ b/src/service_inspectors/dce_rpc/dce_expected_session.cc @@ -56,7 +56,7 @@ void DceExpSsnManager::create_expected_session(const SfIp* ept_ip, } DceTcpExpSsnManager::DceTcpExpSsnManager(const dce2TcpProtoConf& config) : - DceExpSsnManager(IpProtocol::TCP, PktType::TCP), pc(config) {} + DceExpSsnManager(IpProtocol::TCP, PktType::TCP), pc(config) { } int DceTcpExpSsnManager::create_expected_session_impl(Packet* pkt, const snort::SfIp* src_ip, uint16_t src_port, @@ -84,3 +84,4 @@ int DceTcpExpSsnManager::create_expected_session_impl(Packet* pkt, return 0; } + diff --git a/src/service_inspectors/dce_rpc/dce_expected_session.h b/src/service_inspectors/dce_rpc/dce_expected_session.h index 26082c186..6bdb3202e 100644 --- a/src/service_inspectors/dce_rpc/dce_expected_session.h +++ b/src/service_inspectors/dce_rpc/dce_expected_session.h @@ -37,7 +37,7 @@ class DceExpSsnManager { public: DceExpSsnManager(IpProtocol p, PktType t) : - proto(p), type(t) {} + proto(p), type(t) { } virtual ~DceExpSsnManager() = default; @@ -70,9 +70,9 @@ class DceTcpExpSsnManager : public DceExpSsnManager { public: DceTcpExpSsnManager() = delete; - DceTcpExpSsnManager(const dce2TcpProtoConf&); + explicit DceTcpExpSsnManager(const dce2TcpProtoConf&); DceTcpExpSsnManager(const DceTcpExpSsnManager&) = delete; - DceTcpExpSsnManager& operator=(const DceTcpExpSsnManager&) =delete; + DceTcpExpSsnManager& operator=(const DceTcpExpSsnManager&) = delete; private: int create_expected_session_impl(snort::Packet*, @@ -84,3 +84,4 @@ private: }; #endif // DCE_EXPECTED_SESSION_H + diff --git a/src/service_inspectors/dce_rpc/dce_http_proxy_module.cc b/src/service_inspectors/dce_rpc/dce_http_proxy_module.cc index 75d13cbb7..aff67d328 100644 --- a/src/service_inspectors/dce_rpc/dce_http_proxy_module.cc +++ b/src/service_inspectors/dce_rpc/dce_http_proxy_module.cc @@ -31,7 +31,7 @@ static const PegInfo dce_http_proxy_pegs[] = { CountType::END, nullptr, nullptr } }; -DceHttpProxyModule::DceHttpProxyModule() : Module(DCE_HTTP_PROXY_NAME, DCE_HTTP_PROXY_HELP) +DceHttpProxyModule::DceHttpProxyModule() : Module(DCE_HTTP_PROXY_NAME, DCE_HTTP_PROXY_HELP) { } @@ -44,3 +44,4 @@ PegCount* DceHttpProxyModule::get_counts() const { return (PegCount*)&dce_http_proxy_stats; } + diff --git a/src/service_inspectors/dce_rpc/dce_http_proxy_splitter.cc b/src/service_inspectors/dce_rpc/dce_http_proxy_splitter.cc index 2e24b674e..86222d7cc 100644 --- a/src/service_inspectors/dce_rpc/dce_http_proxy_splitter.cc +++ b/src/service_inspectors/dce_rpc/dce_http_proxy_splitter.cc @@ -54,9 +54,9 @@ StreamSplitter::Status DceHttpProxySplitter::scan( StreamSplitter::Status status; if ( (flags & PKT_FROM_CLIENT) != 0 ) - status = match_request_head( data, len ); + status = match_request_head(data, len); else if ( (flags & PKT_FROM_SERVER) != 0 ) - status = match_response( data, len ); + status = match_response(data, len); else return StreamSplitter::ABORT; @@ -68,8 +68,7 @@ StreamSplitter::Status DceHttpProxySplitter::scan( } /* match_request_head() is only used by the c2s splitter instance. */ -StreamSplitter::Status - DceHttpProxySplitter::match_request_head(const uint8_t* data, uint32_t& len) +StreamSplitter::Status DceHttpProxySplitter::match_request_head(const uint8_t* data, uint32_t& len) { if ( match_index == (unsigned int)strlen(HTTP_PROXY_REQUEST) ) { @@ -80,7 +79,7 @@ StreamSplitter::Status len = (len > strlen(HTTP_PROXY_REQUEST)) ? strlen(HTTP_PROXY_REQUEST) : len; if ( ((len+match_index) > strlen(HTTP_PROXY_REQUEST)) || - memcmp( (const void*)data, (const void*)(&HTTP_PROXY_REQUEST[match_index]), len ) != 0 ) + memcmp( (const void*)data, (const void*)(&HTTP_PROXY_REQUEST[match_index]), len) != 0 ) return StreamSplitter::ABORT; else { @@ -101,19 +100,18 @@ StreamSplitter::Status DceHttpProxySplitter::match_response_head(const uint8_t* len = (len > strlen(HTTP_PROXY_RESPONSE)) ? strlen(HTTP_PROXY_RESPONSE) : len; - if ( memcmp( (const void*)data, (const void*)(&HTTP_PROXY_RESPONSE[match_index]), len ) != 0 ) + if ( memcmp( (const void*)data, (const void*)(&HTTP_PROXY_RESPONSE[match_index]), len) != 0 ) return StreamSplitter::ABORT; else { match_index += len; return match_index == (unsigned int)strlen(HTTP_PROXY_RESPONSE) ? - StreamSplitter::FLUSH : StreamSplitter::SEARCH; + StreamSplitter::FLUSH : StreamSplitter::SEARCH; } } /* match_request() is only used by the s2c splitter instance. */ -StreamSplitter::Status - DceHttpProxySplitter::match_response(const uint8_t* data, const uint32_t& len) +StreamSplitter::Status DceHttpProxySplitter::match_response(const uint8_t* data, const uint32_t& len) { uint32_t starting_index = 0; @@ -148,7 +146,7 @@ StreamSplitter::Status return StreamSplitter::SEARCH; } -DceHttpProxySplitter::DceHttpProxySplitter(bool c2s) : StreamSplitter(c2s) +DceHttpProxySplitter::DceHttpProxySplitter(bool c2s) : StreamSplitter(c2s) { cutover = false; match_index = 0; @@ -358,3 +356,4 @@ TEST_CASE("DceHttpProxySplitter-scan - bad_3_proxy_response", "[http_proxy_split } #endif + diff --git a/src/service_inspectors/dce_rpc/dce_http_server_module.cc b/src/service_inspectors/dce_rpc/dce_http_server_module.cc index 1117dcd71..97324a413 100644 --- a/src/service_inspectors/dce_rpc/dce_http_server_module.cc +++ b/src/service_inspectors/dce_rpc/dce_http_server_module.cc @@ -31,7 +31,7 @@ static const PegInfo dce_http_server_pegs[] = { CountType::END, nullptr, nullptr } }; -DceHttpServerModule::DceHttpServerModule() : Module(DCE_HTTP_SERVER_NAME, DCE_HTTP_SERVER_HELP) +DceHttpServerModule::DceHttpServerModule() : Module(DCE_HTTP_SERVER_NAME, DCE_HTTP_SERVER_HELP) { } @@ -44,3 +44,4 @@ PegCount* DceHttpServerModule::get_counts() const { return (PegCount*)&dce_http_server_stats; } + diff --git a/src/service_inspectors/dce_rpc/dce_http_server_splitter.cc b/src/service_inspectors/dce_rpc/dce_http_server_splitter.cc index afa589a5a..28736d712 100644 --- a/src/service_inspectors/dce_rpc/dce_http_server_splitter.cc +++ b/src/service_inspectors/dce_rpc/dce_http_server_splitter.cc @@ -55,17 +55,17 @@ StreamSplitter::Status DceHttpServerSplitter::match(const uint8_t* data, uint32_ len = (len > strlen(HTTP_SERVER_MARKER)) ? strlen(HTTP_SERVER_MARKER) : len; if ( ((len+match_index) > strlen(HTTP_SERVER_MARKER)) || - memcmp( (const void*)data, (const void*)(&HTTP_SERVER_MARKER[match_index]), len ) != 0 ) + memcmp( (const void*)data, (const void*)(&HTTP_SERVER_MARKER[match_index]), len) != 0 ) return StreamSplitter::ABORT; else { match_index += len; return match_index == (unsigned int)strlen(HTTP_SERVER_MARKER) ? - StreamSplitter::FLUSH : StreamSplitter::SEARCH; + StreamSplitter::FLUSH : StreamSplitter::SEARCH; } } -DceHttpServerSplitter::DceHttpServerSplitter(bool c2s) : StreamSplitter(c2s) +DceHttpServerSplitter::DceHttpServerSplitter(bool c2s) : StreamSplitter(c2s) { match_index = 0; cutover = false; @@ -180,3 +180,4 @@ TEST_CASE("DceHttpServerSplitter-scan - extra_server", "[http_server_splitter]") } #endif + diff --git a/src/service_inspectors/dce_rpc/dce_list.cc b/src/service_inspectors/dce_rpc/dce_list.cc index 854ad8b96..606d7c820 100644 --- a/src/service_inspectors/dce_rpc/dce_list.cc +++ b/src/service_inspectors/dce_rpc/dce_list.cc @@ -53,11 +53,11 @@ static void DCE2_ListInsertBefore(DCE2_List*, DCE2_ListNode*, DCE2_ListNode*); * for inserting, finding, etc. * DCE2_ListDataFree * An optional function to call to free data in the list. - * If null is passed in, the user will have to manually free + * If null is passed in, the user will have to manually free * the data. * DCE2_ListKeyFree * An optional function to call to free keys used in the list. - * If null is passed in, the user will have to manually free + * If null is passed in, the user will have to manually free * the keys. * int * Flags that affect processing of the list. @@ -66,7 +66,7 @@ static void DCE2_ListInsertBefore(DCE2_List*, DCE2_ListNode*, DCE2_ListNode*); * Returns: * DCE2_List * * Pointer to a valid list object. - * Null if an error occurs. + * null if an error occurs. * ********************************************************************/ DCE2_List* DCE2_ListNew(DCE2_ListType type, DCE2_ListKeyCompare kc, @@ -109,7 +109,6 @@ static void DCE2_ListInsertTail(DCE2_List* list, DCE2_ListNode* n) if ((list == nullptr) || (n == nullptr)) return; - if (list->tail == nullptr) { list->tail = list->head = n; @@ -221,7 +220,7 @@ static void DCE2_ListInsertBefore(DCE2_List* list, DCE2_ListNode* insert, DCE2_L * in the list and no duplicates are allowed. * DCE2_RET__SUCCESS if a new node with key and data is * successfully inserted into the list. - * DCE2_RET__ERROR if a null list object was passed in. + * DCE2_RET__ERROR if a null list object was passed in. * ********************************************************************/ DCE2_Ret DCE2_ListInsert(DCE2_List* list, void* key, void* data) @@ -309,7 +308,7 @@ DCE2_Ret DCE2_ListInsert(DCE2_List* list, void* key, void* data) * Returns: * void * * The data in the first node in the list. - * Null if the list object passed in is null, or there are + * null if the list object passed in is NULL, or there are * no items in the list. * ********************************************************************/ @@ -342,7 +341,7 @@ void* DCE2_ListFirst(DCE2_List* list) * Returns: * void * * The data in the next node in the list. - * Null if the list object passed in is null, or we are at + * null if the list object passed in is NULL, or we are at * the end of the list and there are no next nodes. * ********************************************************************/ @@ -372,7 +371,7 @@ void* DCE2_ListNext(DCE2_List* list) * * Removes all of the nodes in a list. Does not delete the list * object itself. Calls data free and key free functions for - * data and key if they are not null. + * data and key if they are not NULL. * * Arguments: * DCE2_List * @@ -446,7 +445,7 @@ void DCE2_ListDestroy(DCE2_List* list) * void * * If the key is found, the data associated with the node * is returned. - * Null is returned if the item cannot be found given the key. + * null is returned if the item cannot be found given the key. * ********************************************************************/ void* DCE2_ListFind(DCE2_List* list, void* key) @@ -579,7 +578,7 @@ DCE2_Ret DCE2_ListFindKey(DCE2_List* list, void* key) * Returns: * DCE2_Ret * DCE2_RET__ERROR if a node in the list with the specified - * key cannot be found or the list object passed in is null. + * key cannot be found or the list object passed in is NULL. * DCE2_RET__SUCCESS if the node is successfully removed from * the list. * @@ -688,7 +687,7 @@ void DCE2_ListRemoveCurrent(DCE2_List* list) * Arguments: * DCE2_QueueDataFree * An optional free function for the data inserted into - * the queue. If null is passed in, the user will be + * the queue. If null is passed in, the user will be * responsible for freeing data left in the queue. * * Returns: @@ -719,7 +718,7 @@ DCE2_Queue* DCE2_QueueNew(DCE2_QueueDataFree df) * * Returns: * DCE2_Ret - * DCE2_RET__ERROR if the queue object passed in is null. + * DCE2_RET__ERROR if the queue object passed in is NULL. * DCE2_RET__SUCCESS if the data is successfully added to * the queue. * @@ -766,8 +765,8 @@ DCE2_Ret DCE2_QueueEnqueue(DCE2_Queue* queue, void* data) * Returns: * void * * The data in the first node in the queue. - * Null if there are no items in the queue or the queue object - * passed in is null. + * null if there are no items in the queue or the queue object + * passed in is NULL. * ********************************************************************/ void* DCE2_QueueDequeue(DCE2_Queue* queue) @@ -808,7 +807,7 @@ void* DCE2_QueueDequeue(DCE2_Queue* queue) * * Removes all of the nodes in a queue. Does not delete the queue * object itself. Calls data free function for data if it is - * not null. + * not NULL. * * Arguments: * DCE2_Queue * @@ -876,7 +875,7 @@ void DCE2_QueueDestroy(DCE2_Queue* queue) * Returns: * void * * The data in the first node in the queue. - * Null if the queue object passed in is null, or there are + * null if the queue object passed in is NULL, or there are * no items in the queue. * ********************************************************************/ @@ -909,7 +908,7 @@ void* DCE2_QueueFirst(DCE2_Queue* queue) * Returns: * void * * The data in the next node in the queue. - * Null if the queue object passed in is null, or we are at + * null if the queue object passed in is NULL, or we are at * the end of the queue and there are no next nodes. * ********************************************************************/ @@ -994,7 +993,7 @@ void DCE2_QueueRemoveCurrent(DCE2_Queue* queue) * Returns: * void * * The data in the last node in the queue. - * Null if the queue object passed in is null, or there are + * null if the queue object passed in is NULL, or there are * no items in the queue. * ********************************************************************/ diff --git a/src/service_inspectors/dce_rpc/dce_smb1.cc b/src/service_inspectors/dce_rpc/dce_smb.cc similarity index 68% rename from src/service_inspectors/dce_rpc/dce_smb1.cc rename to src/service_inspectors/dce_rpc/dce_smb.cc index c6d72f394..d8cefaae9 100644 --- a/src/service_inspectors/dce_rpc/dce_smb1.cc +++ b/src/service_inspectors/dce_rpc/dce_smb.cc @@ -1,6 +1,5 @@ //-------------------------------------------------------------------------- // Copyright (C) 2020-2023 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 @@ -16,18 +15,32 @@ // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. //-------------------------------------------------------------------------- -// dce_smb1.cc author Bhargava Jandhyala +// dce_smb.cc author Rashmi Pitre #ifdef HAVE_CONFIG_H #include "config.h" #endif -#include "dce_smb1.h" +#include "dce_smb.h" + +#include "detection/detection_engine.h" +#include "file_api/file_service.h" +#include "managers/inspector_manager.h" +#include "protocols/packet.h" -#include "dce_smb_utils.h" +#include "dce_context_data.h" +#include "dce_smb_commands.h" +#include "dce_smb_module.h" +#include "dce_smb_paf.h" +#include "dce_smb_transaction.h" +#include "dce_smb2.h" +#include "dce_smb2_utils.h" using namespace snort; +THREAD_LOCAL dce2SmbStats dce2_smb_stats; +THREAD_LOCAL ProfileStats dce2_smb_pstat_main; + //------------------------------------------------------------------------- // debug stuff //------------------------------------------------------------------------- @@ -295,38 +308,215 @@ static const char* smb_com_strings[SMB_MAX_NUM_COMS] = const char* get_smb_com_string(uint8_t b) { return smb_com_strings[b]; } -Dce2Smb1SessionData::Dce2Smb1SessionData(const Packet* p, - const dce2SmbProtoConf* proto) : Dce2SmbSessionData(p, proto) +//------------------------------------------------------------------------- +// class stuff +//------------------------------------------------------------------------- + +class Dce2SmbInspector : public Inspector +{ +public: + explicit Dce2SmbInspector(const dce2SmbProtoConf&); + ~Dce2SmbInspector() override; + + void tinit() override; + void tterm() override; + + void show(const SnortConfig*) const override; + void eval(Packet*) override; + void clear(Packet*) override; + + StreamSplitter* get_splitter(bool c2s) override + { return new Dce2SmbSplitter(c2s); } + + bool can_carve_files() const override + { return true; } + +private: + dce2SmbProtoConf config; +}; + +Dce2SmbInspector::Dce2SmbInspector(const dce2SmbProtoConf& pc) : config(pc) { - ssd = { }; - ssd.max_outstanding_requests = 10; // Until Negotiate/SessionSetupAndX - ssd.cli_data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER; - ssd.srv_data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER; - ssd.pdu_state = DCE2_SMB_PDU_STATE__COMMAND; - ssd.uid = DCE2_SENTINEL; - ssd.tid = DCE2_SENTINEL; - ssd.ftracker.fid_v1 = DCE2_SENTINEL; - ssd.rtracker.mid = DCE2_SENTINEL; - ssd.dialect_index = dialect_index; - ssd.max_file_depth = max_file_depth; - ssd.sd = sd; - ssd.policy = policy; - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, p, "smb1 session created\n"); - dce2_smb_stats.total_smb1_sessions++; } -Dce2Smb1SessionData::~Dce2Smb1SessionData() +Dce2SmbInspector::~Dce2SmbInspector() { - DCE2_SmbDataFree(&ssd); + if (config.smb_invalid_shares) + { + DCE2_ListDestroy(config.smb_invalid_shares); + } +} + +void Dce2SmbInspector::show(const SnortConfig*) const +{ + print_dce2_smb_conf(config); +} + +void Dce2SmbInspector::eval(Packet* p) +{ + DCE2_SmbSsnData* dce2_smb_sess = nullptr; + DCE2_Smb2SsnData* dce2_smb2_sess = nullptr; + DCE2_SmbVersion smb_version = DCE2_SMB_VERSION_NULL; + Profile profile(dce2_smb_pstat_main); + + if (p == nullptr) + return; + + assert(p->has_tcp_data()); + assert(p->flow); + + reset_using_rpkt(); + + Dce2SmbFlowData* smb_flowdata = (Dce2SmbFlowData*)p->flow->get_flow_data(Dce2SmbFlowData::inspector_id); + if (smb_flowdata and smb_flowdata->dce2_smb_session_data) + { + smb_version = smb_flowdata->smb_version; + if (DCE2_SMB_VERSION_1 == smb_version) + dce2_smb_sess = (DCE2_SmbSsnData*)smb_flowdata->dce2_smb_session_data; + else + dce2_smb2_sess = (DCE2_Smb2SsnData*)smb_flowdata->dce2_smb_session_data; + } + else + { + smb_version = DCE2_Smb2Version(p); + + if (DCE2_SMB_VERSION_1 == smb_version) + { + //1st packet of flow in smb1 session, create smb1 session and flowdata + dce2_smb_sess = dce2_create_new_smb_session(p, &config); + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL + , p, "smb1 session created\n"); + } + else if (DCE2_SMB_VERSION_2 == smb_version) + { + //1st packet of flow in smb2 session, create smb2 session and flowdata + dce2_smb2_sess = dce2_create_new_smb2_session(p, &config); + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL + , p, "smb2 session created\n"); + } + else + { + //smb_version is DCE2_SMB_VERSION_NULL + //This means there is no flow data and this is not an SMB packet + //if it is a TCP packet for smb data, the flow must have been + //already identified with version. + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL + , p, "non-smb packet detected\n"); + return; + } + } + + // By this time we must know the smb version, have correct smb session data and created + // flowdata + p->packet_flags |= PKT_ALLOW_MULTIPLE_DETECT; + dce2_detected = 0; + p->endianness = new DceEndianness(); + + if (DCE2_SMB_VERSION_1 == smb_version) + { + DCE2_Smb1Process(dce2_smb_sess); + if (!dce2_detected) + DCE2_Detect(&dce2_smb_sess->sd); + } + else + { + DCE2_Smb2Process(dce2_smb2_sess); + if (!dce2_detected) + DCE2_Detect(&dce2_smb2_sess->sd); + } + + delete(p->endianness); + p->endianness = nullptr; } -void Dce2Smb1SessionData::process() +void Dce2SmbInspector::clear(Packet* p) { - DCE2_Smb1Process(&ssd); + DCE2_SsnData* sd = get_dce2_session_data(p->flow); + if ( sd ) + DCE2_ResetRopts(sd, p); } -void Dce2Smb1SessionData::set_reassembled_data(uint8_t* nb_ptr,uint16_t co_len) +void Dce2SmbInspector::tinit() { - DCE2_SmbSetRdata(&ssd, nb_ptr, co_len); + delete smb2_session_cache; + size_t smb_memcap = DCE2_ScSmbMemcap(&config); + DCE2_SmbSessionCacheInit(smb_memcap); } +void Dce2SmbInspector::tterm() +{ + delete smb2_session_cache; + smb2_session_cache = nullptr; +} + +//------------------------------------------------------------------------- +// api stuff +//------------------------------------------------------------------------- + +static Module* mod_ctor() +{ + return new Dce2SmbModule; +} + +static void mod_dtor(Module* m) +{ + delete m; +} + +static void dce2_smb_init() +{ + Dce2SmbFlowData::init(); + DCE2_SmbInitGlobals(); + DCE2_SmbInitDeletePdu(); + DceContextData::init(DCE2_TRANS_TYPE__SMB); +} + +static Inspector* dce2_smb_ctor(Module* m) +{ + Dce2SmbModule* mod = (Dce2SmbModule*)m; + dce2SmbProtoConf config; + mod->get_data(config); + return new Dce2SmbInspector(config); +} + +static void dce2_smb_dtor(Inspector* p) +{ + delete p; +} + +static const char* dce2_bufs[] = +{ + "dce_iface", + "dce_stub_data", + "file_data", + nullptr +}; + +const InspectApi dce2_smb_api = +{ + { + PT_INSPECTOR, + sizeof(InspectApi), + INSAPI_VERSION, + 0, + API_RESERVED, + API_OPTIONS, + DCE2_SMB_NAME, + DCE2_SMB_HELP, + mod_ctor, + mod_dtor + }, + IT_SERVICE, + PROTO_BIT__PDU, + dce2_bufs, + "netbios-ssn", + dce2_smb_init, + nullptr, // pterm + nullptr, // tinit + nullptr, // tterm + dce2_smb_ctor, + dce2_smb_dtor, + nullptr, // ssn + nullptr // reset +}; + diff --git a/src/service_inspectors/dce_rpc/dce_smb.h b/src/service_inspectors/dce_rpc/dce_smb.h new file mode 100644 index 000000000..9baf3cf15 --- /dev/null +++ b/src/service_inspectors/dce_rpc/dce_smb.h @@ -0,0 +1,532 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2016-2020 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_smb.h author Rashmi Pitre +// based on work by Todd Wease + +#ifndef DCE_SMB_H +#define DCE_SMB_H + +#include "dce_co.h" +#include "hash/lru_cache_local.h" +#include "protocols/packet.h" +#include "profiler/profiler_defs.h" +#include "smb_common.h" +#include "smb_message.h" + +#include "trace/trace_api.h" +#define SMB_DEBUG(module_name, module_id, log_level, p, ...) \ + trace_logf(log_level, module_name, module_id, p, __VA_ARGS__) + +#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 +#define DCE2_SMB_BAD_ID 4 +#define DCE2_SMB_BAD_WCT 5 +#define DCE2_SMB_BAD_BCC 6 +#define DCE2_SMB_BAD_FORM 7 +#define DCE2_SMB_BAD_OFF 8 +#define DCE2_SMB_TDCNT_ZE 9 +#define DCE2_SMB_NB_LT_SMBHDR 10 +#define DCE2_SMB_NB_LT_COM 11 +#define DCE2_SMB_NB_LT_BCC 12 +#define DCE2_SMB_NB_LT_DSIZE 13 +#define DCE2_SMB_TDCNT_LT_DSIZE 14 +#define DCE2_SMB_DSENT_GT_TDCNT 15 +#define DCE2_SMB_BCC_LT_DSIZE 16 +#define DCE2_SMB_INVALID_DSIZE 17 +#define DCE2_SMB_EXCESSIVE_TREE_CONNECTS 18 +#define DCE2_SMB_EXCESSIVE_READS 19 +#define DCE2_SMB_EXCESSIVE_CHAINING 20 +#define DCE2_SMB_MULT_CHAIN_SS 21 +#define DCE2_SMB_MULT_CHAIN_TC 22 +#define DCE2_SMB_CHAIN_SS_LOGOFF 23 +#define DCE2_SMB_CHAIN_TC_TDIS 24 +#define DCE2_SMB_CHAIN_OPEN_CLOSE 25 +#define DCE2_SMB_INVALID_SHARE 26 + +#define DCE2_SMB_V1 44 +#define DCE2_SMB_V2 45 +#define DCE2_SMB_INVALID_BINDING 46 +#define DCE2_SMB2_EXCESSIVE_COMPOUNDING 47 +#define DCE2_SMB_DCNT_ZERO 48 +#define DCE2_SMB_DCNT_MISMATCH 49 +#define DCE2_SMB_MAX_REQS_EXCEEDED 50 +#define DCE2_SMB_REQS_SAME_MID 51 +#define DCE2_SMB_DEPR_DIALECT_NEGOTIATED 52 +#define DCE2_SMB_DEPR_COMMAND_USED 53 +#define DCE2_SMB_UNUSUAL_COMMAND_USED 54 +#define DCE2_SMB_INVALID_SETUP_COUNT 55 +#define DCE2_SMB_MULTIPLE_NEGOTIATIONS 56 +#define DCE2_SMB_EVASIVE_FILE_ATTRS 57 +#define DCE2_SMB_INVALID_FILE_OFFSET 58 +#define DCE2_SMB_BAD_NEXT_COMMAND_OFFSET 59 + +#define DCE2_SMB_BAD_NBSS_TYPE_STR "SMB - bad NetBIOS session service session type" +#define DCE2_SMB_BAD_TYPE_STR "SMB - bad SMB message type" +#define DCE2_SMB_BAD_ID_STR "SMB - bad SMB Id (not \\xffSMB for SMB1 or not \\xfeSMB for SMB2)" +#define DCE2_SMB_BAD_WCT_STR "SMB - bad word count or structure size" +#define DCE2_SMB_BAD_BCC_STR "SMB - bad byte count" +#define DCE2_SMB_BAD_FORM_STR "SMB - bad format type" +#define DCE2_SMB_BAD_OFF_STR "SMB - bad offset" +#define DCE2_SMB_TDCNT_ZE_STR "SMB - zero total data count" +#define DCE2_SMB_NB_LT_SMBHDR_STR "SMB - NetBIOS data length less than SMB header length" +#define DCE2_SMB_NB_LT_COM_STR "SMB - remaining NetBIOS data length less than command length" +#define DCE2_SMB_NB_LT_BCC_STR "SMB - remaining NetBIOS data length less than command byte count" +#define DCE2_SMB_NB_LT_DSIZE_STR \ + "SMB - remaining NetBIOS data length less than command data size" +#define DCE2_SMB_TDCNT_LT_DSIZE_STR \ + "SMB - remaining total data count less than this command data size" +#define DCE2_SMB_DSENT_GT_TDCNT_STR \ + "SMB - total data sent (STDu64) greater than command total data expected" +#define DCE2_SMB_BCC_LT_DSIZE_STR "SMB - byte count less than command data size (STDu64)" +#define DCE2_SMB_INVALID_DSIZE_STR "SMB - invalid command data size for byte count" +#define DCE2_SMB_EXCESSIVE_TREE_CONNECTS_STR \ + "SMB - excessive tree connect requests with pending tree connect responses" +#define DCE2_SMB_EXCESSIVE_READS_STR "SMB - excessive read requests with pending read responses" +#define DCE2_SMB_EXCESSIVE_CHAINING_STR "SMB - excessive command chaining" +#define DCE2_SMB_MULT_CHAIN_SS_STR "SMB - multiple chained tree connect requests" +#define DCE2_SMB_MULT_CHAIN_TC_STR "SMB - multiple chained tree connect requests" +#define DCE2_SMB_CHAIN_SS_LOGOFF_STR "SMB - chained/compounded login followed by logoff" +#define DCE2_SMB_CHAIN_TC_TDIS_STR \ + "SMB - chained/compounded tree connect followed by tree disconnect" +#define DCE2_SMB_CHAIN_OPEN_CLOSE_STR \ + "SMB - chained/compounded open pipe followed by close pipe" +#define DCE2_SMB_INVALID_SHARE_STR "SMB - invalid share access" + +#define DCE2_SMB_V1_STR "SMB - invalid SMB version 1 seen" +#define DCE2_SMB_V2_STR "SMB - invalid SMB version 2 seen" +#define DCE2_SMB_INVALID_BINDING_STR "SMB - invalid user, tree connect, file binding" +#define DCE2_SMB2_EXCESSIVE_COMPOUNDING_STR "SMB - excessive command compounding" +#define DCE2_SMB_DCNT_ZERO_STR "SMB - zero data count" +#define DCE2_SMB_DCNT_MISMATCH_STR "SMB - data count mismatch in command and format" +#define DCE2_SMB_MAX_REQS_EXCEEDED_STR "SMB - maximum number of outstanding requests exceeded" +#define DCE2_SMB_REQS_SAME_MID_STR "SMB - outstanding requests with same MID" +#define DCE2_SMB_DEPR_DIALECT_NEGOTIATED_STR "SMB - deprecated dialect negotiated" +#define DCE2_SMB_DEPR_COMMAND_USED_STR "SMB - deprecated command used" +#define DCE2_SMB_UNUSUAL_COMMAND_USED_STR "SMB - unusual command used" +#define DCE2_SMB_INVALID_SETUP_COUNT_STR "SMB - invalid setup count for command" +#define DCE2_SMB_MULTIPLE_NEGOTIATIONS_STR \ + "SMB - client attempted multiple dialect negotiations on session" +#define DCE2_SMB_EVASIVE_FILE_ATTRS_STR \ + "SMB - client attempted to create or set a file's attributes to readonly/hidden/system" +#define DCE2_SMB_INVALID_FILE_OFFSET_STR \ + "SMB - file offset provided is greater than file size specified" +#define DCE2_SMB_BAD_NEXT_COMMAND_OFFSET_STR \ + "SMB - next command specified in SMB2 header is beyond payload boundary" + +struct dce2SmbStats : public LruCacheLocalStats +{ + PegCount events; + + PegCount co_pdus; + PegCount co_bind; + PegCount co_bind_ack; + PegCount co_alter_ctx; + PegCount co_alter_ctx_resp; + PegCount co_bind_nack; + PegCount co_request; + PegCount co_response; + PegCount co_cancel; + PegCount co_orphaned; + PegCount co_fault; + PegCount co_auth3; + PegCount co_shutdown; + PegCount co_reject; + PegCount co_ms_pdu; + PegCount co_other_req; + PegCount co_other_resp; + PegCount co_req_fragments; + PegCount co_resp_fragments; + PegCount co_cli_max_frag_size; + PegCount co_cli_min_frag_size; + PegCount co_cli_seg_reassembled; + PegCount co_cli_frag_reassembled; + PegCount co_srv_max_frag_size; + PegCount co_srv_min_frag_size; + PegCount co_srv_seg_reassembled; + PegCount co_srv_frag_reassembled; + + PegCount smb_sessions; + PegCount smb_pkts; + PegCount smb_ignored_bytes; + PegCount smb_cli_seg_reassembled; + PegCount smb_srv_seg_reassembled; + PegCount smb_max_outstanding_requests; + // FIXIT-M more peg count foo + /*uint64_t smb_com_stats[2][SMB_MAX_NUM_COMS]; + uint64_t smb_chained_stats[2][SMB_ANDX_COM__MAX][SMB_MAX_NUM_COMS]; + // The +1 is for codes beyond the range of the highest valid subcommand code + // Indicates a bogus subcommand + uint64_t smb_trans_subcom_stats[2][TRANS_SUBCOM_MAX+1]; + uint64_t smb_trans2_subcom_stats[2][TRANS2_SUBCOM_MAX+1]; + uint64_t smb_nt_transact_subcom_stats[2][NT_TRANSACT_SUBCOM_MAX+1]; + */ + PegCount smb_files_processed; + /* SMB2 stats */ + PegCount v2_setup; + PegCount v2_setup_err_resp; + PegCount v2_setup_inv_str_sz; + PegCount v2_setup_resp_hdr_err; + PegCount v2_tree_cnct; + PegCount v2_tree_cnct_err_resp; + PegCount v2_tree_cnct_ignored; + PegCount v2_tree_cnct_inv_str_sz; + PegCount v2_tree_cnct_resp_hdr_err; + PegCount v2_crt; + PegCount v2_crt_err_resp; + PegCount v2_crt_inv_file_data; + PegCount v2_crt_inv_str_sz; + PegCount v2_crt_resp_hdr_err; + PegCount v2_crt_req_hdr_err; + PegCount v2_crt_rtrkr_misng; + PegCount v2_crt_req_ipc; + PegCount v2_crt_tree_trkr_misng; + PegCount v2_wrt; + PegCount v2_wrt_err_resp; + PegCount v2_wrt_ignored; + PegCount v2_wrt_inv_str_sz; + PegCount v2_wrt_req_hdr_err; + PegCount v2_read; + PegCount v2_read_err_resp; + PegCount v2_read_ignored; + PegCount v2_read_inv_str_sz; + PegCount v2_read_rtrkr_misng; + PegCount v2_read_resp_hdr_err; + PegCount v2_read_req_hdr_err; + PegCount v2_setinfo; + PegCount v2_stinf_err_resp; + PegCount v2_stinf_ignored; + PegCount v2_stinf_inv_str_sz; + PegCount v2_stinf_req_ftrkr_misng; + PegCount v2_stinf_req_hdr_err; + PegCount v2_cls; + PegCount v2_cls_err_resp; + PegCount v2_cls_ignored; + PegCount v2_cls_inv_str_sz; + PegCount v2_cls_req_ftrkr_misng; + PegCount v2_cls_req_hdr_err; + PegCount v2_tree_discn; + PegCount v2_tree_discn_ignored; + PegCount v2_tree_discn_inv_str_sz; + PegCount v2_tree_discn_req_hdr_err; + PegCount v2_logoff; + PegCount v2_logoff_inv_str_sz; + PegCount v2_hdr_err; + PegCount v2_bad_next_cmd_offset; + PegCount v2_extra_file_data_err; + PegCount v2_inv_file_ctx_err; + PegCount v2_msgs_uninspected; + PegCount v2_cmpnd_req_lt_crossed; + PegCount concurrent_sessions; + PegCount max_concurrent_sessions; + PegCount total_smb1_sessions; + PegCount total_smb2_sessions; + PegCount total_encrypted_sessions; + PegCount total_mc_sessions; + PegCount v2_total_session_trackers; + PegCount v2_total_tree_trackers; + PegCount v2_total_file_trackers; + PegCount v2_updated_file_flows; + PegCount v2_ignored_file_processing; + PegCount v2_mc_file_transfers; + PegCount v2_ioctl; + PegCount v2_ioctl_err_resp; + PegCount v2_ioctl_inv_str_sz; + PegCount v2_ioctl_ignored; + PegCount total_sessions; // not used +}; + +extern THREAD_LOCAL dce2SmbStats dce2_smb_stats; +extern THREAD_LOCAL snort::ProfileStats dce2_smb_pstat_main; + +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 +}; + +enum SmbAndXCom +{ + SMB_ANDX_COM__NONE, + SMB_ANDX_COM__OPEN_ANDX, + SMB_ANDX_COM__READ_ANDX, + SMB_ANDX_COM__WRITE_ANDX, + SMB_ANDX_COM__TREE_CONNECT_ANDX, + SMB_ANDX_COM__SESSION_SETUP_ANDX, + SMB_ANDX_COM__LOGOFF_ANDX, + SMB_ANDX_COM__NT_CREATE_ANDX, + SMB_ANDX_COM__MAX +}; + +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; +}; + +enum DCE2_SmbVersion +{ + DCE2_SMB_VERSION_NULL, + DCE2_SMB_VERSION_1, + DCE2_SMB_VERSION_2 +}; + +struct DCE2_SmbFileTracker +{ + struct + { + int file_id; // A signed integer so it can be set to sentinel + uint16_t u_id; + uint16_t tree_id; + } file_key; + + bool is_ipc; + bool is_smb2; + char* file_name; + uint16_t file_name_size; + uint64_t file_name_hash; + + 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; + + DCE2_SmbPduState smb2_pdu_state; + +#define fid_v1 file_key.file_id +#define uid_v1 file_key.u_id +#define tid_v1 file_key.tree_id +#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 Smb2Request +{ + uint64_t message_id; /* identifies a message uniquely on connection */ + uint64_t offset; /* data offset */ + uint64_t file_id; /* file id */ + struct Smb2Request* next; + struct Smb2Request* previous; +}; + +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; + uint16_t file_name_size; + 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 + 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; + + DCE2_SmbFileTracker* fb_ftracker; + bool block_pdus; + + // Maximum file depth as returned from file API + int64_t max_file_depth; +}; + +struct DCE2_SmbFsm +{ + char input; + int next_state; + int fail_state; +}; + +class Dce2SmbFlowData : public snort::FlowData +{ +public: + Dce2SmbFlowData(); + ~Dce2SmbFlowData() override; + + static void init() + { inspector_id = snort::FlowData::create_flow_data_id(); } + + size_t size_of() override + { return sizeof(*this); } + +public: + static unsigned inspector_id; + DCE2_SmbVersion smb_version; + void* dce2_smb_session_data; +}; + +// Used for reassembled packets +#define DCE2_MOCK_HDR_LEN__SMB_CLI \ + ((unsigned)(sizeof(NbssHdr) + sizeof(SmbNtHdr) + sizeof(SmbWriteAndXReq))) +#define DCE2_MOCK_HDR_LEN__SMB_SRV \ + ((unsigned)(sizeof(NbssHdr) + sizeof(SmbNtHdr) + sizeof(SmbReadAndXResp))) + +DCE2_SsnData* get_dce2_session_data(snort::Flow*); + +const char* get_smb_com_string(uint8_t); +#endif + diff --git a/src/service_inspectors/dce_rpc/dce_smb1.h b/src/service_inspectors/dce_rpc/dce_smb1.h deleted file mode 100644 index 958b9c364..000000000 --- a/src/service_inspectors/dce_rpc/dce_smb1.h +++ /dev/null @@ -1,286 +0,0 @@ -//-------------------------------------------------------------------------- -// Copyright (C) 2020-2023 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_smb1.h author Bhargava Jandhyala - -#ifndef DCE_SMB1_H -#define DCE_SMB1_H - -// This provides smb session data and SMBv1 specific trackers - -#include "protocols/packet.h" -#include "profiler/profiler_defs.h" - -#include "dce_co.h" -#include "dce_smb_common.h" -#include "dce_smb_module.h" -#include "smb_message.h" - -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_SmbFileDirection -{ - DCE2_SMB_FILE_DIRECTION__UNKNOWN = 0, - DCE2_SMB_FILE_DIRECTION__UPLOAD, - DCE2_SMB_FILE_DIRECTION__DOWNLOAD -}; - -enum SmbAndXCom -{ - SMB_ANDX_COM__NONE, - SMB_ANDX_COM__OPEN_ANDX, - SMB_ANDX_COM__READ_ANDX, - SMB_ANDX_COM__WRITE_ANDX, - SMB_ANDX_COM__TREE_CONNECT_ANDX, - SMB_ANDX_COM__SESSION_SETUP_ANDX, - SMB_ANDX_COM__LOGOFF_ANDX, - SMB_ANDX_COM__NT_CREATE_ANDX, - SMB_ANDX_COM__MAX -}; - -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 -{ - struct - { - int file_id; // A signed integer so it can be set to sentinel - uint16_t u_id; - uint16_t tree_id; - } file_key; - - bool is_ipc; - bool is_smb2; - char* file_name; - uint16_t file_name_size; - uint64_t file_name_hash; - - 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 fid_v1 file_key.file_id -#define uid_v1 file_key.u_id -#define tid_v1 file_key.tree_id -#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 Smb2Request -{ - uint64_t message_id; /* identifies a message uniquely on connection */ - uint64_t offset; /* data offset */ - uint64_t file_id; /* file id */ - struct Smb2Request* next; - struct Smb2Request* previous; -}; - -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; - uint16_t file_name_size; - 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 - DCE2_Policy policy; - - int dialect_index; - int ssn_state_flags; - - DCE2_SmbDataState cli_data_state; - DCE2_SmbDataState srv_data_state; - - Dce2SmbPduState 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; - - DCE2_SmbFileTracker* fb_ftracker; - bool block_pdus; - - // Maximum file depth as returned from file API - int64_t max_file_depth; -}; - -struct DCE2_SmbFsm -{ - char input; - int next_state; - int fail_state; -}; - -// Used for reassembled packets -#define DCE2_MOCK_HDR_LEN__SMB_CLI \ - ((unsigned)(sizeof(NbssHdr) + sizeof(SmbNtHdr) + sizeof(SmbWriteAndXReq))) -#define DCE2_MOCK_HDR_LEN__SMB_SRV \ - ((unsigned)(sizeof(NbssHdr) + sizeof(SmbNtHdr) + sizeof(SmbReadAndXResp))) - -DCE2_SsnData* get_dce2_session_data(snort::Flow*); - -const char* get_smb_com_string(uint8_t); - -class Dce2Smb1SessionData : public Dce2SmbSessionData -{ -public: - Dce2Smb1SessionData() = delete; - Dce2Smb1SessionData(const snort::Packet*, const dce2SmbProtoConf* proto); - ~Dce2Smb1SessionData() override; - void process() override; - void handle_retransmit(FilePosition, FileVerdict) override { } - void set_reassembled_data(uint8_t*, uint16_t) override; - -private: - DCE2_SmbSsnData ssd; -}; - -#endif - diff --git a/src/service_inspectors/dce_rpc/dce_smb2.cc b/src/service_inspectors/dce_rpc/dce_smb2.cc index 53bf47e4c..e1f3bbdf2 100644 --- a/src/service_inspectors/dce_rpc/dce_smb2.cc +++ b/src/service_inspectors/dce_rpc/dce_smb2.cc @@ -24,22 +24,13 @@ #endif #include "dce_smb2.h" - +#include "dce_smb2_commands.h" #include "detection/detection_util.h" -#include "flow/flow_key.h" #include "stream/stream.h" -#include "dce_smb2_file.h" -#include "dce_smb2_session.h" -#include "dce_smb2_session_cache.h" -#include "dce_smb2_tree.h" - using namespace snort; -Dce2Smb2SessionCache smb2_session_cache(SMB_DEFAULT_MEMCAP); - -const char* smb2_command_string[SMB2_COM_MAX] = -{ +const char* smb2_command_string[SMB2_COM_MAX] = { "SMB2_COM_NEGOTIATE", "SMB2_COM_SESSION_SETUP", "SMB2_COM_LOGOFF", @@ -58,254 +49,268 @@ const char* smb2_command_string[SMB2_COM_MAX] = "SMB2_COM_CHANGE_NOTIFY", "SMB2_COM_QUERY_INFO", "SMB2_COM_SET_INFO", - "SMB2_COM_OPLOCK_BREAK" -}; + "SMB2_COM_OPLOCK_BREAK" }; -static inline uint64_t Smb2Sid(const Smb2Hdr* hdr) +DCE2_Smb2RequestTracker::DCE2_Smb2RequestTracker(uint64_t file_id_v, + uint64_t offset_v) : file_id(file_id_v), offset(offset_v) { - return alignedNtohq(&(hdr->session_id)); + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, + GET_CURRENT_PACKET, "Request tracker created with file_id = 0x%" PRIx64 " offset = %" PRIu64 "\n", file_id, + offset); } -static inline bool Smb2Error(const Smb2Hdr* hdr) +DCE2_Smb2RequestTracker::DCE2_Smb2RequestTracker(char* fname_v, + uint16_t fname_len_v) : fname(fname_v), fname_len(fname_len_v) { - return (SMB_NT_STATUS_SEVERITY__ERROR == (uint8_t)(hdr->status >> 30)); + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, + GET_CURRENT_PACKET, "Request tracker created\n"); } -uint32_t get_smb2_flow_key(const FlowKey* flow_key) +DCE2_Smb2RequestTracker::~DCE2_Smb2RequestTracker() { - Smb2FlowKey key; - - key.ip_l[0] = flow_key->ip_l[0]; - key.ip_l[1] = flow_key->ip_l[1]; - key.ip_l[2] = flow_key->ip_l[2]; - key.ip_l[3] = flow_key->ip_l[3]; - key.ip_h[0] = flow_key->ip_h[0]; - key.ip_h[1] = flow_key->ip_h[1]; - key.ip_h[2] = flow_key->ip_h[2]; - key.ip_h[3] = flow_key->ip_h[3]; - key.mplsLabel = flow_key->mplsLabel; - key.port_l = flow_key->port_l; - key.port_h = flow_key->port_h; - key.group_l = flow_key->group_l; - key.group_h = flow_key->group_h; - key.vlan_tag = flow_key->vlan_tag; - key.addressSpaceId = flow_key->addressSpaceId; - key.ip_protocol = flow_key->ip_protocol; - key.pkt_type = (uint8_t)flow_key->pkt_type; - key.version = flow_key->version; - key.padding = key.padding16 = 0; - - Smb2KeyHash hasher; - return hasher(key); + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, + nullptr, "Request tracker terminating\n"); + if (fname) + snort_free(fname); } -//Dce2Smb2SessionData member functions - -Dce2Smb2SessionData::Dce2Smb2SessionData(const Packet* p, - const dce2SmbProtoConf* proto) : Dce2SmbSessionData(p, proto) +DCE2_Smb2FileTracker::DCE2_Smb2FileTracker(uint64_t file_id_v, DCE2_Smb2TreeTracker* ttr_v, + DCE2_Smb2SessionTracker* str_v, Flow* flow_v) : file_id(file_id_v), ttr(ttr_v), + str(str_v), parent_flow(flow_v), ignore(false), upload(false), multi_channel_file(false) { - tcp_file_tracker = nullptr; - flow_key = get_smb2_flow_key(tcp_flow->key); - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, p, - "smb2 session created\n"); - dce2_smb_stats.total_smb2_sessions++; - vlan_id = p->get_flow_vlan_id(); + dce2_smb_stats.v2_total_file_trackers++; + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, + GET_CURRENT_PACKET, "File tracker 0x%" PRIx64 " created\n", file_id); + str->update_cache_size(sizeof(DCE2_Smb2FileTracker)); } -Dce2Smb2SessionData::~Dce2Smb2SessionData(void) +DCE2_Smb2FileTracker::~DCE2_Smb2FileTracker(void) { - for (auto it_session : connected_sessions) + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, + nullptr, "File tracker with file id: 0x%" PRIx64 " tracker terminating\n", file_id); + auto all_conn_trackers = str->conn_trackers.get_all_entry(); + for ( auto& h : all_conn_trackers ) { - it_session.second->detach_flow(flow_key); - it_session.second->set_file_context_cleaned(true); + if (h.second->ftracker_tcp) + { + if (h.second->ftracker_tcp == this) + { + h.second->ftracker_tcp = nullptr; + h.second->ftracker_local = nullptr; + } + } } - - if (get_tcp_file_tracker() && !(get_tcp_file_tracker()->get_flow_state_map().empty())) + if (multi_channel_file) + dce2_smb_stats.v2_mc_file_transfers++; + if (co_tracker != nullptr) { - get_tcp_file_tracker()->get_flow_state_map().erase(flow_key); + DCE2_CoCleanTracker(co_tracker); + snort_free((void*)co_tracker); } - if (tcp_file_tracker and tcp_file_tracker->get_flow_key() == flow_key ) - tcp_file_tracker->set_flow_key(0); - tcp_file_tracker = nullptr; + str->update_cache_size(-(int)sizeof(DCE2_Smb2FileTracker)); } -void Dce2Smb2SessionData::reset_matching_tcp_file_tracker( - Dce2Smb2FileTrackerPtr file_tracker) +DCE2_Smb2TreeTracker::DCE2_Smb2TreeTracker (uint32_t tid_v, uint8_t share_type_v) : + share_type(share_type_v), tid(tid_v) { - std::lock_guard guard(tcp_file_tracker_mutex); - if (tcp_file_tracker == file_tracker) - { - if (get_tcp_file_tracker() && !(get_tcp_file_tracker()->get_flow_state_map().empty())) - { - get_tcp_file_tracker()->get_flow_state_map().erase(flow_key); - tcp_file_tracker = nullptr; - } - else - return; - } + dce2_smb_stats.v2_total_tree_trackers++; + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, + GET_CURRENT_PACKET, "Tree tracker %" PRIu32 " created\n", tid); } -Smb2SessionKey Dce2Smb2SessionData::get_session_key(uint64_t session_id) +DCE2_Smb2TreeTracker::~DCE2_Smb2TreeTracker(void) { - Smb2SessionKey key; - Flow* flow = DetectionEngine::get_current_packet()->flow; - memcpy(key.cip, flow->client_ip.get_ip6_ptr(), 4*sizeof(uint32_t)); - memcpy(key.sip, flow->server_ip.get_ip6_ptr(), 4*sizeof(uint32_t)); - key.sid = session_id; - key.cgroup = flow->client_group; - key.sgroup = flow->server_group; - key.asid = flow->key->addressSpaceId; - return key; + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, + nullptr, "Tree tracker %" PRIu32 " terminating\n", tid); } -Dce2Smb2SessionTrackerPtr Dce2Smb2SessionData::find_session(uint64_t session_id) +DCE2_Smb2SessionTracker::DCE2_Smb2SessionTracker(uint64_t sid) : conn_trackers(false), session_id(sid), + encryption_flag(0) { - std::lock_guard guard(session_data_mutex); - auto it_session = connected_sessions.find(session_id); + update_cache_size((int)sizeof(DCE2_Smb2SessionTracker)); + dce2_smb_stats.v2_total_session_trackers++; + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, + GET_CURRENT_PACKET, "Session tracker 0x%" PRIx64 " created\n", session_id); +} - if (it_session != connected_sessions.end()) +DCE2_Smb2SessionTracker::~DCE2_Smb2SessionTracker(void) +{ + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, + nullptr, "Session tracker 0x%" PRIx64 " terminating\n", session_id); + removeSessionFromAllConnection(); + auto all_tree_trackers = tree_trackers.get_all_entry(); + for ( auto& h : all_tree_trackers ) { - Dce2Smb2SessionTrackerPtr session = it_session->second; - //we already have the session, but call find to update the LRU - smb2_session_cache.find_session(session->get_key()); - if (session->vlan_id != 0 and session->vlan_id != - (DetectionEngine::get_current_packet()->get_flow_vlan_id())) - return nullptr; - return session; + removeTtracker(h.first); } - else + update_cache_size(-(int)sizeof(DCE2_Smb2SessionTracker)); +} + +void DCE2_Smb2SessionTracker::removeSessionFromAllConnection() +{ + auto all_conn_trackers = conn_trackers.get_all_entry(); + auto all_tree_trackers = tree_trackers.get_all_entry(); + for ( auto& h : all_conn_trackers ) { - Dce2Smb2SessionTrackerPtr session = smb2_session_cache.find_session( - get_session_key(session_id)); - if (session and session->vlan_id != 0 and - session->vlan_id != (DetectionEngine::get_current_packet()->get_flow_vlan_id())) + if (h.second->ftracker_tcp) { - connected_sessions.insert(std::make_pair(session_id,session)); - return session; + for (auto& t : all_tree_trackers) + { + DCE2_Smb2FileTracker* ftr = t.second->findFtracker( + h.second->ftracker_tcp->file_id); + if (ftr and ftr == h.second->ftracker_tcp) + { + h.second->ftracker_tcp = nullptr; + h.second->ftracker_local = nullptr; + break; + } + } } - else - return nullptr; + DCE2_Smb2RemoveSidInSsd(h.second, session_id); } } -// Caller must ensure that the session is not already present in flow -Dce2Smb2SessionTrackerPtr Dce2Smb2SessionData::create_session(uint64_t session_id) +void DCE2_Smb2SessionTracker::update_cache_size(int size) { - Smb2SessionKey session_key = get_session_key(session_id); - Dce2Smb2SessionTrackerPtr session = smb2_session_cache.find_else_create_session(session_key, - this); - if (session) - { - connected_sessions.insert(std::make_pair(session_id, session)); - session->vlan_id = DetectionEngine::get_current_packet()->get_flow_vlan_id(); - } - return session; + DCE2_SmbSessionCacheUpdateSize(size); } -void Dce2Smb2SessionData::remove_session(uint64_t session_id) +DCE2_Smb2SsnData::DCE2_Smb2SsnData() { - session_data_mutex.lock(); - connected_sessions.erase(session_id); - session_data_mutex.unlock(); + Packet* p = DetectionEngine::get_current_packet(); + memset(&sd, 0, sizeof(DCE2_SsnData)); + memset(&policy, 0, sizeof(DCE2_Policy)); + dialect_index = 0; + ssn_state_flags = 0; + ftracker_tcp = nullptr; + smb_id = 0; + max_file_depth = FileService::get_max_file_depth(); + max_outstanding_requests = 10; // Until Negotiate + flow = p->flow; + SmbKeyHash hasher; + flow_key = hasher(*flow->key); } -void Dce2Smb2SessionData::process_command(const Smb2Hdr* smb_hdr, - const uint8_t* end) +DCE2_Smb2SsnData::~DCE2_Smb2SsnData() { - const uint8_t* smb_data = (const uint8_t*)smb_hdr + SMB2_HEADER_LENGTH; - uint16_t structure_size = alignedNtohs((const uint16_t*)smb_data); - uint16_t command = alignedNtohs(&(smb_hdr->command)); - uint64_t session_id = Smb2Sid(smb_hdr); - Dce2Smb2SessionTrackerPtr session; - -// Macro and shorthand to save some repetitive code -// Should only be used in this function -#define SMB2_COMMAND_TYPE(cmd, type) \ - (structure_size == SMB2_ ## cmd ## _ ## type ## _STRUC_SIZE) - -#define SMB2_GET_COMMAND_TYPE(cmd) \ - (SMB2_COMMAND_TYPE(ERROR,RESPONSE) and Smb2Error(smb_hdr)) ? \ - SMB2_CMD_TYPE_ERROR_RESPONSE : (SMB2_COMMAND_TYPE(cmd, REQUEST) ? \ - SMB2_CMD_TYPE_REQUEST : (SMB2_COMMAND_TYPE(cmd, RESPONSE) ? \ - SMB2_CMD_TYPE_RESPONSE : SMB2_CMD_TYPE_INVALID)) - -#define SMB2_HANDLE_HEADER_ERROR(cmd, type, counter) \ - { \ - if (smb_data + SMB2_ ## cmd ## _ ## type ## _STRUC_SIZE - 1 > end) \ - { \ - dce2_smb_stats.v2_ ## counter ## _hdr_err++; \ - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, \ - GET_CURRENT_PACKET, \ - "%s : smb data beyond end detected\n", \ - smb2_command_string[command]); \ - if (session) \ - { \ - session->set_do_not_delete(false); \ - session->set_prev_comand(SMB2_COM_MAX); \ - } \ - return; \ - } \ + for (auto it = session_trackers.cbegin(), next_it = it; it != session_trackers.cend(); it = next_it) + { + ++next_it; + auto sptr = it->second.lock(); + if (sptr) + { + if (flow_key) + sptr->removeConnectionTracker(flow_key); // remove tcp connection from session + // tracker + auto ttrs = sptr->tree_trackers.get_all_entry(); + for (const auto& titer: ttrs) + { + DCE2_Smb2TreeTracker* ttr = titer.second; + auto ftrs = ttr->file_trackers.get_all_entry(); + for (const auto& fiter: ftrs) + { + DCE2_Smb2FileTracker* ftr = fiter.second; + if (flow == ftr->parent_flow) + ftr->parent_flow = nullptr; + } + } + } } +} -#define SMB2_HANDLE_ERROR_RESPONSE(counter) \ - { \ - if (SMB2_COMMAND_TYPE(ERROR, RESPONSE) and Smb2Error(smb_hdr)) \ - { \ - dce2_smb_stats.v2_ ## counter ## _err_resp++; \ - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, GET_CURRENT_PACKET, \ - "%s_RESP: error\n", \ - smb2_command_string[command]); \ - if (session) \ - { \ - session->set_do_not_delete(false); \ - session->set_prev_comand(SMB2_COM_MAX); \ - } \ - return; \ - } \ - } +void DCE2_Smb2SsnData::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)); -#define SMB2_HANDLE_INVALID_STRUC_SIZE(counter) \ - { \ - dce2_smb_stats.v2_ ## counter ## _inv_str_sz++; \ - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL \ - , GET_CURRENT_PACKET, "%s: invalid struct size\n", \ - smb2_command_string[command]); \ - if (session) \ - { \ - session->set_do_not_delete(false); \ - session->set_prev_comand(SMB2_COM_MAX); \ - } \ - return; \ - } + uint32_t tid = (ftracker_tcp) ? ftracker_tcp->ttr->get_tid() : 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; - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, GET_CURRENT_PACKET, - "%s : flow %" PRIu32 " mid %" PRIu64 " sid %" PRIu64 " tid %" PRIu32 "\n", - (command < SMB2_COM_MAX ? smb2_command_string[command] : "unknown"), - flow_key, Smb2Mid(smb_hdr), session_id, Smb2Tid(smb_hdr)); - - // Handling case of two threads trying to do close same session at a time - session = smb2_session_cache.find(get_session_key(session_id)); - if (session and connected_sessions.size() < 9) - connected_sessions.insert(std::make_pair(session_id, session)); - if ((command == SMB2_COM_CLOSE or command == - SMB2_COM_TREE_DISCONNECT)and (session and session->get_prev_command() != SMB2_COM_MAX)) + 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 (ftracker_tcp) + { + uint64_t fid = ftracker_tcp->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 { - return; + 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); } +} - if (session) +static inline bool DCE2_Smb2FindSidTid(DCE2_Smb2SsnData* ssd, const uint64_t sid, + const uint32_t tid, const uint32_t mid, DCE2_Smb2SessionTracker** str, DCE2_Smb2TreeTracker** ttr, bool + lookup_cache = false) +{ + *str = DCE2_Smb2FindSidInSsd(ssd, sid).get(); + if (!*str) { - session->set_do_not_delete(true); - session->set_prev_comand(command); + if (lookup_cache) + *str = DCE2_Smb2FindElseCreateSid(ssd, sid, false); } + if (!*str) + return false; - // Try to find the session. - // The case when session is not available will be handled per command. + if (!tid) + *ttr = ssd->GetTreeTrackerFromMessage(mid); + else + *ttr = (*str)->findTtracker(tid); + + if (!*ttr) + return false; + + return true; +} + +// FIXIT-L port fileCache related code along with +// DCE2_Smb2Init, DCE2_Smb2Close and DCE2_Smb2UpdateStats + +static void DCE2_Smb2Inspect(DCE2_Smb2SsnData* ssd, const Smb2Hdr* smb_hdr, + const uint8_t* end) +{ + const uint8_t* smb_data = (const uint8_t*)smb_hdr + SMB2_HEADER_LENGTH; + uint16_t command = alignedNtohs(&(smb_hdr->command)); + int16_t structure_size = alignedNtohs((const uint16_t*)smb_data); + DCE2_Smb2SessionTracker* str = nullptr; + DCE2_Smb2TreeTracker* ttr = nullptr; + uint32_t tid = 0; + + uint64_t mid = Smb2Mid(smb_hdr); + uint64_t sid = Smb2Sid(smb_hdr); + /* Still process async commands*/ + if (!(alignedNtohl(&(smb_hdr->flags)) & SMB2_FLAGS_ASYNC_COMMAND)) + tid = Smb2Tid(smb_hdr); + + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, + DetectionEngine::get_current_packet(), + "%s : mid %" PRIu64 " sid 0x%" PRIx64 " tid %" PRIu32 "\n", + (command <= SMB2_COM_OPLOCK_BREAK ? smb2_command_string[command] : "unknown"), + mid, sid, tid); switch (command) { - //commands processed by flow case SMB2_COM_NEGOTIATE: - if (SMB2_COMMAND_TYPE(NEGOTIATE, RESPONSE)) + if (structure_size == SMB2_NEGOTIATE_RESPONSE_STRUC_SIZE) { const Smb2NegotiateResponseHdr* neg_resp_hdr = (const Smb2NegotiateResponseHdr*)smb_data; @@ -313,243 +318,159 @@ void Dce2Smb2SessionData::process_command(const Smb2Hdr* smb_hdr, { //total multichannel sessions dce2_smb_stats.total_mc_sessions++; - Packet* p = DetectionEngine::get_current_packet(); - Dce2SmbFlowData* fd = create_expected_smb_flow_data(p); - if (fd) - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_CRITICAL_LEVEL, - GET_CURRENT_PACKET, - "Requesting for expected smb flow\n"); - int result = Stream::set_snort_protocol_id_expected(p, PktType::TCP, - IpProtocol::TCP, p->ptrs.ip_api.get_dst(), 0,p->ptrs.ip_api.get_src(), - p->flow->server_port, snort_protocol_id_smb, fd, false, true); - - if (result < 0) - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_CRITICAL_LEVEL, - GET_CURRENT_PACKET, - "Failed to create expected smb flow\n"); - delete fd; - } - } - else - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_CRITICAL_LEVEL, - GET_CURRENT_PACKET, - "fd is null in negotiate , failed to create pinhole\n"); - } } } break; - case SMB2_COM_SESSION_SETUP: - dce2_smb_stats.v2_setup++; - SMB2_HANDLE_ERROR_RESPONSE(setup) - if (SMB2_COMMAND_TYPE(SETUP, RESPONSE)) + case SMB2_COM_CREATE: + if (!tid) { - SMB2_HANDLE_HEADER_ERROR(SETUP, RESPONSE, setup_resp) - if (!session) - create_session(session_id); + //Check request tracker for tid in Async case. + auto rtracker = ssd->findRtracker(mid); + if (rtracker) + tid = rtracker->get_tree_id(); } - else if (!SMB2_COMMAND_TYPE(SETUP, REQUEST)) - SMB2_HANDLE_INVALID_STRUC_SIZE(setup) - break; - - case SMB2_COM_LOGOFF: - dce2_smb_stats.v2_logoff++; - if (SMB2_COMMAND_TYPE(LOGOFF, REQUEST)) - smb2_session_cache.remove(get_session_key(session_id)); - else - SMB2_HANDLE_INVALID_STRUC_SIZE(logoff) - break; - //commands processed by session - case SMB2_COM_TREE_CONNECT: - dce2_smb_stats.v2_tree_cnct++; - SMB2_HANDLE_ERROR_RESPONSE(tree_cnct) - if (SMB2_COMMAND_TYPE(TREE_CONNECT, RESPONSE)) + dce2_smb_stats.v2_crt++; + DCE2_Smb2Create(ssd, smb_hdr, smb_data, end, mid, sid, tid); + break; + case SMB2_COM_READ: + if (!tid) { - SMB2_HANDLE_HEADER_ERROR(TREE_CONNECT, RESPONSE, tree_cnct_resp) - if (!session) - session = create_session(session_id); - if (!session) - return; - session->process(command, SMB2_CMD_TYPE_RESPONSE, smb_hdr, end, flow_key); + //Check request tracker for tid in Async case. + auto rtracker = ssd->findRtracker(mid); + if (rtracker) + tid = rtracker->get_tree_id(); + } + dce2_smb_stats.v2_read++; + if (!DCE2_Smb2FindSidTid(ssd, sid, tid, mid, &str, &ttr, true)) + { + dce2_smb_stats.v2_read_ignored++; + return; } - else if (!SMB2_COMMAND_TYPE(TREE_CONNECT,REQUEST)) - SMB2_HANDLE_INVALID_STRUC_SIZE(tree_cnct) - break; - - case SMB2_COM_TREE_DISCONNECT: - dce2_smb_stats.v2_tree_discn++; - if (session) + DCE2_Smb2Read(ssd, smb_hdr, smb_data, end, str, ttr, mid); + break; + case SMB2_COM_WRITE: + if (!tid) { - if (SMB2_COMMAND_TYPE(TREE_DISCONNECT, REQUEST)) - { - SMB2_HANDLE_HEADER_ERROR(TREE_DISCONNECT, REQUEST, tree_discn_req) - session->process(command, SMB2_CMD_TYPE_REQUEST, smb_hdr, end, flow_key); - } - else - { - SMB2_HANDLE_INVALID_STRUC_SIZE(tree_discn) - } + //Check request tracker for tid in Async case. + auto rtracker = ssd->findRtracker(mid); + if (rtracker) + tid = rtracker->get_tree_id(); } - else - dce2_smb_stats.v2_session_ignored++; + dce2_smb_stats.v2_wrt++; + if (!DCE2_Smb2FindSidTid(ssd, sid, tid, mid, &str, &ttr, true)) + { + dce2_smb_stats.v2_wrt_ignored++; + return; + } + + DCE2_Smb2Write(ssd, smb_hdr, smb_data, end, str, ttr, mid); break; - //commands processed by tree - case SMB2_COM_CREATE: - { - dce2_smb_stats.v2_crt++; - uint8_t command_type = SMB2_GET_COMMAND_TYPE(CREATE); - if (SMB2_CMD_TYPE_INVALID == command_type) - SMB2_HANDLE_INVALID_STRUC_SIZE(crt) - else if (SMB2_COMMAND_TYPE(CREATE, REQUEST)) - SMB2_HANDLE_HEADER_ERROR(CREATE, REQUEST, crt_req) - else if (SMB2_COMMAND_TYPE(CREATE, RESPONSE)) - SMB2_HANDLE_HEADER_ERROR(CREATE, RESPONSE, crt_resp) - - if (!session) - session = create_session(session_id); - if (!session) + case SMB2_COM_SET_INFO: + if (!tid) + { + //Check request tracker for tid in Async case. + auto rtracker = ssd->findRtracker(mid); + if (rtracker) + tid = rtracker->get_tree_id(); + } + dce2_smb_stats.v2_setinfo++; + if (!DCE2_Smb2FindSidTid(ssd, sid, tid, mid, &str, &ttr)) + { + dce2_smb_stats.v2_stinf_ignored++; return; - session->process(command, command_type, smb_hdr, end, flow_key); - } - break; + } + DCE2_Smb2SetInfo(ssd, smb_hdr, smb_data, end, ttr); + break; case SMB2_COM_CLOSE: + if (!tid) + { + //Check request tracker for tid in Async case. + auto rtracker = ssd->findRtracker(mid); + if (rtracker) + tid = rtracker->get_tree_id(); + } dce2_smb_stats.v2_cls++; - SMB2_HANDLE_ERROR_RESPONSE(cls) - if (session) + if (!DCE2_Smb2FindSidTid(ssd, sid, tid, mid, &str, &ttr)) { - if (SMB2_COMMAND_TYPE(CLOSE, REQUEST)) - { - SMB2_HANDLE_HEADER_ERROR(CLOSE, REQUEST, cls_req) - session->process(command, SMB2_CMD_TYPE_REQUEST, smb_hdr, end, flow_key); - } - else if (!SMB2_COMMAND_TYPE(CLOSE, RESPONSE)) - { - SMB2_HANDLE_INVALID_STRUC_SIZE(cls) - } + dce2_smb_stats.v2_cls_ignored++; + return; } - else - dce2_smb_stats.v2_session_ignored++; - break; - case SMB2_COM_SET_INFO: - dce2_smb_stats.v2_setinfo++; - SMB2_HANDLE_ERROR_RESPONSE(stinf) - if (session) + DCE2_Smb2CloseCmd(ssd, smb_hdr, smb_data, end, ttr, str, mid); + break; + case SMB2_COM_TREE_CONNECT: + dce2_smb_stats.v2_tree_cnct++; + // This will always return session tracker + str = DCE2_Smb2FindElseCreateSid(ssd, sid); + if (str) { - if (SMB2_COMMAND_TYPE(SET_INFO, REQUEST)) - { - SMB2_HANDLE_HEADER_ERROR(SET_INFO, REQUEST, stinf_req) - session->process(command, SMB2_CMD_TYPE_REQUEST, smb_hdr, end, flow_key); - } - else if (!SMB2_COMMAND_TYPE(SET_INFO, RESPONSE)) - { - SMB2_HANDLE_INVALID_STRUC_SIZE(stinf) - } + DCE2_Smb2TreeConnect(ssd, smb_hdr, smb_data, end, str, tid); } - else - dce2_smb_stats.v2_session_ignored++; break; - - case SMB2_COM_READ: - dce2_smb_stats.v2_read++; - if (session) + case SMB2_COM_TREE_DISCONNECT: + dce2_smb_stats.v2_tree_discn++; + if (!DCE2_Smb2FindSidTid(ssd, sid, tid, mid, &str, &ttr)) { - uint8_t command_type; - if (SMB2_COMMAND_TYPE(ERROR, RESPONSE) and Smb2Error(smb_hdr)) - command_type = SMB2_CMD_TYPE_ERROR_RESPONSE; - else if (SMB2_COMMAND_TYPE(READ, REQUEST)) - { - SMB2_HANDLE_HEADER_ERROR(READ, REQUEST, read_req) - command_type = SMB2_CMD_TYPE_REQUEST; - } - else if (SMB2_COMMAND_TYPE(READ, RESPONSE)) - { - SMB2_HANDLE_HEADER_ERROR(READ, RESPONSE, read_resp) - command_type = SMB2_CMD_TYPE_RESPONSE; - } - else - SMB2_HANDLE_INVALID_STRUC_SIZE(read) - session->process(command, command_type, smb_hdr, end, flow_key); + dce2_smb_stats.v2_tree_discn_ignored++; + return; } - else - dce2_smb_stats.v2_session_ignored++; + DCE2_Smb2TreeDisconnect(ssd, smb_data, end); break; - - case SMB2_COM_WRITE: - dce2_smb_stats.v2_wrt++; - if (session) + case SMB2_COM_SESSION_SETUP: + dce2_smb_stats.v2_setup++; + DCE2_Smb2Setup(ssd, smb_hdr, sid, smb_data, end); + break; + case SMB2_COM_LOGOFF: + dce2_smb_stats.v2_logoff++; + DCE2_Smb2Logoff(ssd, smb_data, sid); + break; + case SMB2_COM_IOCTL: + if (!tid) { - uint8_t command_type; - if (SMB2_COMMAND_TYPE(ERROR, RESPONSE) and Smb2Error(smb_hdr)) - command_type = SMB2_CMD_TYPE_ERROR_RESPONSE; - else if (SMB2_COMMAND_TYPE(WRITE, REQUEST)) - { - SMB2_HANDLE_HEADER_ERROR(WRITE, REQUEST, wrt_req) - command_type = SMB2_CMD_TYPE_REQUEST; - } - else if (SMB2_COMMAND_TYPE(WRITE, RESPONSE)) - { - SMB2_HANDLE_HEADER_ERROR(WRITE, RESPONSE, wrt_resp) - command_type = SMB2_CMD_TYPE_RESPONSE; - } - else - SMB2_HANDLE_INVALID_STRUC_SIZE(wrt) - session->process(command, command_type, smb_hdr, end, flow_key); + //Check request tracker for tid in Async case. + auto rtracker = ssd->findRtracker(mid); + if (rtracker) + tid = rtracker->get_tree_id(); + } + if (!DCE2_Smb2FindSidTid(ssd, sid, tid, mid, &str, &ttr)) + { + dce2_smb_stats.v2_ioctl_ignored++; + return; + } + else if (SMB2_SHARE_TYPE_DISK != ttr->get_share_type()) + { + dce2_smb_stats.v2_ioctl++; + DCE2_Smb2IoctlCommand(ssd, smb_hdr, smb_data, end, str, ttr, mid); } 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, flow_key); - } - 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, flow_key); - } - else - { - SMB2_HANDLE_INVALID_STRUC_SIZE(ioctl) - } + dce2_smb_stats.v2_ioctl_ignored++; + return; } break; default: dce2_smb_stats.v2_msgs_uninspected++; break; } - if (session) - { - session->set_prev_comand(SMB2_COM_MAX); - session->set_do_not_delete(false); - } } // This is the main entry point for SMB2 processing. -void Dce2Smb2SessionData::process() +void DCE2_Smb2Process(DCE2_Smb2SsnData* ssd) { Packet* p = DetectionEngine::get_current_packet(); const uint8_t* data_ptr = p->data; uint16_t data_len = p->dsize; - Dce2Smb2SessionTrackerPtr session = nullptr; - // Process the header if (p->is_pdu_start()) { // Check header length if (data_len < sizeof(NbssHdr) + SMB2_HEADER_LENGTH) { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_CRITICAL_LEVEL, - p, "Header error with data length %d\n",data_len); dce2_smb_stats.v2_hdr_err++; + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, p, + "Header error with data length %d\n",data_len); return; } const Smb2Hdr* smb_hdr = (const Smb2Hdr*)(data_ptr + sizeof(NbssHdr)); @@ -559,14 +480,12 @@ void Dce2Smb2SessionData::process() uint64_t sid = smb_trans_hdr->session_id; if (smb_proto_id == DCE2_SMB2_TRANS_ID) { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, p, "Encrypted header is received \n"); - session = find_session(sid); + DCE2_Smb2SessionTracker* session = DCE2_Smb2FindElseCreateSid(ssd, sid); if (session) { - bool flag = session->get_encryption_flag(); - if (!flag) - session->set_encryption_flag(true); + session->set_encryption_flag(true); } } uint32_t next_command_offset; @@ -581,18 +500,16 @@ void Dce2Smb2SessionData::process() // multiple requests up to the maximum size<88> that is supported by the transport." do { - process_command(smb_hdr, data_ptr + data_len); + DCE2_Smb2Inspect(ssd, smb_hdr, data_ptr + data_len); // In case of message compounding, find the offset of the next smb command next_command_offset = alignedNtohl(&(smb_hdr->next_command)); if (next_command_offset + (const uint8_t*)smb_hdr > (data_ptr + data_len)) { dce_alert(GID_DCE2, DCE2_SMB_BAD_NEXT_COMMAND_OFFSET, - (dce2CommonStats*)&dce2_smb_stats, sd); - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, - TRACE_ERROR_LEVEL, p, "bad next command offset\n"); + (dce2CommonStats*)&dce2_smb_stats, ssd->sd); + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + p, "bad next command offset\n"); dce2_smb_stats.v2_bad_next_cmd_offset++; - if (session) - session->set_do_not_delete(false); return; } if (next_command_offset) @@ -601,105 +518,46 @@ void Dce2Smb2SessionData::process() compound_request_index++; } - if (compound_request_index > get_smb_max_compound()) + if (compound_request_index > DCE2_ScSmbMaxCompound((dce2SmbProtoConf*)ssd->sd.config)) { dce2_smb_stats.v2_cmpnd_req_lt_crossed++; - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, - TRACE_INFO_LEVEL, p, "compound request limit" - " reached %" PRIu8 "\n",compound_request_index); - if (session) - session->set_do_not_delete(false); + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + p, "compound req limit reached %" PRIu8 "\n", + compound_request_index); return; } } while (next_command_offset and smb_hdr); } - else + else if ( ssd->ftracker_tcp and ssd->ftracker_local and (ssd->ftracker_local->smb2_pdu_state == + DCE2_SMB_PDU_STATE__RAW_DATA)) { - if ( tcp_file_tracker ) - { - session = smb2_session_cache.find(get_session_key(tcp_file_tracker->get_session_id())); - if (session) - session->set_do_not_delete(true); - else - return; - } - else + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, + p, "raw data file_name_hash %" PRIu64 " fid 0x%" PRIx64 " dir %s\n", + ssd->ftracker_tcp->file_name_hash, ssd->ftracker_tcp->file_id, + ssd->ftracker_tcp->upload ? "upload" : "download"); + + if (!DCE2_Smb2ProcessFileData(ssd, data_ptr, data_len)) return; - tcp_file_tracker_mutex.lock(); - if ( tcp_file_tracker and tcp_file_tracker.use_count() > - 1 and tcp_file_tracker->accepting_raw_data_from(flow_key)) - { - SMB_DEBUG(dce_smb_trace,DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, p, - "processing raw data for file id %" PRIu64 "\n", - tcp_file_tracker->get_file_id()); - tcp_file_tracker->process_data(flow_key, data_ptr, data_len, session); - tcp_file_tracker->stop_accepting_raw_data_from(flow_key); - } - else if (tcp_file_tracker and tcp_file_tracker.use_count() == 1) - { - if (get_tcp_file_tracker() && !(get_tcp_file_tracker()->get_flow_state_map().empty())) - { - get_tcp_file_tracker()->get_flow_state_map().erase(flow_key); - tcp_file_tracker = nullptr; - } - } - else - { - SMB_DEBUG(dce_smb_trace,DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, p, - "not processing raw data\n"); - } - tcp_file_tracker_mutex.unlock(); } - if (session) - session->set_do_not_delete(false); } -void Dce2Smb2SessionData::set_reassembled_data(uint8_t* nb_ptr, uint16_t co_len) +// Check whether the packet is smb2 +DCE2_SmbVersion DCE2_Smb2Version(const Packet* p) { - NbssHdr* nb_hdr = (NbssHdr*)nb_ptr; - SmbNtHdr* smb_hdr = (SmbNtHdr*)((uint8_t*)nb_hdr + sizeof(NbssHdr)); - - tcp_file_tracker_mutex.lock(); - uint32_t tid = (tcp_file_tracker) ? tcp_file_tracker->get_parent()->get_tree_id() : 0; - tcp_file_tracker_mutex.unlock(); - - smb_hdr->smb_tid = alignedNtohl((const uint32_t*)&tid); - - if (DetectionEngine::get_current_packet()->is_from_client()) + // Only check reassembled SMB2 packet + if ( p->has_paf_payload() and + (p->dsize > sizeof(NbssHdr) + DCE2_SMB_ID_SIZE) ) // DCE2_SMB_ID is u32 { - 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); - - tcp_file_tracker_mutex.lock(); - 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; - tcp_file_tracker_mutex.unlock(); + const Smb2Hdr* smb_hdr = (const Smb2Hdr*)(p->data + sizeof(NbssHdr)); + uint32_t smb_version_id = SmbId((const SmbNtHdr*)smb_hdr); - write->length = alignedNtohs(&co_len); + if (smb_version_id == DCE2_SMB_ID) + return DCE2_SMB_VERSION_1; + else if (smb_version_id == DCE2_SMB2_ID) + return DCE2_SMB_VERSION_2; } - 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); - } + return DCE2_SMB_VERSION_NULL; } diff --git a/src/service_inspectors/dce_rpc/dce_smb2.h b/src/service_inspectors/dce_rpc/dce_smb2.h index 26eb8cb83..91b931d9f 100644 --- a/src/service_inspectors/dce_rpc/dce_smb2.h +++ b/src/service_inspectors/dce_rpc/dce_smb2.h @@ -22,56 +22,14 @@ #ifndef DCE_SMB2_H #define DCE_SMB2_H -// This implements smb session data for SMBv2 -// Also provides SMBv2 related header structures - -#include - +#include "dce_db.h" +#include "dce_smb.h" +#include "hash/lru_cache_shared.h" +#include "flow/flow_key.h" #include "main/thread_config.h" #include "utils/util.h" -#include "dce_smb_common.h" - -/* SMB2 command codes */ -#define SMB2_COM_NEGOTIATE 0x00 -#define SMB2_COM_SESSION_SETUP 0x01 -#define SMB2_COM_LOGOFF 0x02 -#define SMB2_COM_TREE_CONNECT 0x03 -#define SMB2_COM_TREE_DISCONNECT 0x04 -#define SMB2_COM_CREATE 0x05 -#define SMB2_COM_CLOSE 0x06 -#define SMB2_COM_FLUSH 0x07 -#define SMB2_COM_READ 0x08 -#define SMB2_COM_WRITE 0x09 -#define SMB2_COM_LOCK 0x0A -#define SMB2_COM_IOCTL 0x0B -#define SMB2_COM_CANCEL 0x0C -#define SMB2_COM_ECHO 0x0D -#define SMB2_COM_QUERY_DIRECTORY 0x0E -#define SMB2_COM_CHANGE_NOTIFY 0x0F -#define SMB2_COM_QUERY_INFO 0x10 -#define SMB2_COM_SET_INFO 0x11 -#define SMB2_COM_OPLOCK_BREAK 0x12 -#define SMB2_COM_MAX 0x13 - -extern const char* smb2_command_string[SMB2_COM_MAX]; - -// file attribute for create response -#define SMB2_CREATE_RESPONSE_DIRECTORY 0x10 -#define SMB_AVG_FILES_PER_SESSION 5 - -#define SMB2_SHARE_TYPE_DISK 0x01 -#define SMB2_SHARE_TYPE_PIPE 0x02 -#define SMB2_SHARE_TYPE_PRINT 0x03 - -#define SMB2_CMD_TYPE_ERROR_RESPONSE 0 -#define SMB2_CMD_TYPE_REQUEST 1 -#define SMB2_CMD_TYPE_RESPONSE 2 -#define SMB2_CMD_TYPE_INVALID 3 - -#define FSCTL_PIPE_WAIT 0x00110018 -#define FSCTL_PIPE_TRANSCEIVE 0x0011C017 -#define FSCTL_PIPE_PEEK 0x0011400C +#define GET_CURRENT_PACKET snort::DetectionEngine::get_current_packet() struct Smb2Hdr { @@ -84,7 +42,24 @@ struct Smb2Hdr uint32_t flags; /* flags */ uint32_t next_command; /* used for compounded request */ uint64_t message_id; /* identifies a message uniquely on connection */ - uint64_t async_sync; /* used for async and sync differently */ + uint32_t process_id; /* Reserved */ + uint32_t tree_id; /* Tree id*/ + uint64_t session_id; /* identifies the established session for the command*/ + uint8_t signature[16]; /* signature of the message */ +}; + +struct Smb2ASyncHdr +{ + uint8_t smb_idf[4]; /* contains 0xFE,’SMB’ */ + uint16_t structure_size; /* This MUST be set to 64 */ + uint16_t credit_charge; /* # of credits that this request consumes */ + uint32_t status; /* depends */ + uint16_t command; /* command code */ + uint16_t credit; /* # of credits requesting/granted */ + uint32_t flags; /* flags */ + uint32_t next_command; /* used for compounded request */ + uint64_t message_id; /* identifies a message uniquely on connection */ + uint64_t async_id; /* handle operations asynchronously */ uint64_t session_id; /* identifies the established session for the command*/ uint8_t signature[16]; /* signature of the message */ }; @@ -106,6 +81,413 @@ struct Smb2SyncHdr uint8_t signature[16]; /* signature of the message */ }; +struct Smb2ErrorResponseHdr +{ + uint16_t structure_size; /* This MUST be set to 9 */ + uint16_t reserved; /* reserved */ + uint32_t byte_count; /* The number of bytes of error_data */ + uint8_t error_data[1]; /* If byte_count is 0, this MUST be 0*/ +}; + +class DCE2_Smb2TreeTracker; + +class DCE2_Smb2RequestTracker +{ +public: + + DCE2_Smb2RequestTracker() = delete; + DCE2_Smb2RequestTracker(const DCE2_Smb2RequestTracker& arg) = delete; + DCE2_Smb2RequestTracker& operator=(const DCE2_Smb2RequestTracker& arg) = delete; + + explicit DCE2_Smb2RequestTracker(uint64_t file_id_v, uint64_t offset_v = 0); + DCE2_Smb2RequestTracker(char* fname_v, uint16_t fname_len_v); + ~DCE2_Smb2RequestTracker(); + + uint64_t get_offset() + { + return offset; + } + + uint64_t get_file_id() + { + return file_id; + } + + void set_file_id(uint64_t fid) + { + file_id = fid; + } + + void set_tree_id(uint32_t l_tree_id) + { + tree_id = l_tree_id; + } + + uint32_t get_tree_id() + { + return tree_id; + } + + void set_session_id(uint32_t l_session_id) + { + session_id = l_session_id; + } + + uint32_t get_session_id() + { + return session_id; + } + + char* fname = nullptr; + uint16_t fname_len = 0; + uint64_t file_id = 0; + uint64_t offset = 0; + uint32_t tree_id = 0; + uint64_t session_id = 0; +}; + +struct DCE2_Smb2SsnData; +class DCE2_Smb2SessionTracker; + +class DCE2_Smb2FileTracker +{ +public: + + DCE2_Smb2FileTracker() = delete; + DCE2_Smb2FileTracker(const DCE2_Smb2FileTracker& arg) = delete; + DCE2_Smb2FileTracker& operator=(const DCE2_Smb2FileTracker& arg) = delete; + + DCE2_Smb2FileTracker(uint64_t file_id_v, DCE2_Smb2TreeTracker* ttr_v, + DCE2_Smb2SessionTracker* str_v, snort::Flow* flow_v); + ~DCE2_Smb2FileTracker(); + uint64_t max_offset = 0; + uint64_t file_id = 0; + uint64_t file_size = 0; + uint64_t file_name_hash = 0; + DCE2_Smb2TreeTracker* ttr = nullptr; + DCE2_Smb2SessionTracker* str = nullptr; + snort::Flow* parent_flow = nullptr; + DCE2_CoTracker* co_tracker = nullptr; + bool ignore : 1; + bool upload : 1; + bool multi_channel_file : 1; +}; + +class DCE2_Smb2LocalFileTracker +{ +public: + uint64_t file_offset = 0; + DCE2_SmbPduState smb2_pdu_state = DCE2_SMB_PDU_STATE__COMMAND; +}; +typedef DCE2_DbMap > DCE2_DbMapFtracker; +typedef DCE2_DbMap > DCE2_DbMapRtracker; +class DCE2_Smb2TreeTracker +{ +public: + + DCE2_Smb2TreeTracker() = delete; + DCE2_Smb2TreeTracker(const DCE2_Smb2TreeTracker& arg) = delete; + DCE2_Smb2TreeTracker& operator=(const DCE2_Smb2TreeTracker& arg) = delete; + + DCE2_Smb2TreeTracker (uint32_t tid_v, uint8_t share_type_v); + ~DCE2_Smb2TreeTracker(); + + // File Tracker + DCE2_Smb2FileTracker* findFtracker(uint64_t file_id) + { + return file_trackers.Find(file_id); + } + + bool insertFtracker(uint64_t file_id, DCE2_Smb2FileTracker* ftracker) + { + return file_trackers.Insert(file_id, ftracker); + } + + void removeFtracker(uint64_t file_id) + { + file_trackers.Remove(file_id); + } + + // common methods + uint8_t get_share_type() + { + return share_type; + } + + uint32_t get_tid() + { + return tid; + } + + uint8_t share_type = 0; + uint32_t tid = 0; + DCE2_DbMapFtracker file_trackers; +}; + +PADDING_GUARD_BEGIN + +struct Smb2SidHashKey +{ + uint32_t cip[4] = {}; + uint32_t sip[4] = {}; + uint32_t mplsLabel = 0; + int16_t cgroup = 0; + int16_t sgroup = 0; + uint32_t addressSpaceId = 0; + uint16_t vlan_tag = 0; + uint16_t padding = 0; + uint64_t sid = 0; + + bool operator==(const Smb2SidHashKey& other) const + { + return( cip[0] == other.cip[0] and + cip[1] == other.cip[1] and + cip[2] == other.cip[2] and + cip[3] == other.cip[3] and + sip[0] == other.sip[0] and + sip[1] == other.sip[1] and + sip[2] == other.sip[2] and + sip[3] == other.sip[3] and + mplsLabel == other.mplsLabel and + cgroup == other.cgroup and + sgroup == other.sgroup and + addressSpaceId == other.addressSpaceId and + vlan_tag == other.vlan_tag and + sid == other.sid); + } +}; +PADDING_GUARD_END + +//The below value is taken from Hash Key class static hash hardener +#define SMB_KEY_HASH_HARDENER 133824503 + +struct SmbKeyHash +{ + size_t operator()(const Smb2SidHashKey& key) const + { + return do_hash((const uint32_t*)&key); + } + + size_t operator()(const snort::FlowKey& key) const + { + return do_hash_flow_key((const uint32_t*)&key); + } + +private: + size_t do_hash(const uint32_t* d) const + { + uint32_t a, b, c; + a = b = c = SMB_KEY_HASH_HARDENER; + a += d[0]; b += d[1]; c += d[2]; mix(a, b, c); + a += d[3]; b += d[4]; c += d[5]; mix(a, b, c); + a += d[6]; b += d[7]; c += d[8]; mix(a, b, c); + a += d[9]; b += d[10]; c += d[11]; mix(a, b, c); + a += d[12]; b += d[13]; finalize(a, b, c); + return c; + } + + size_t do_hash_flow_key(const uint32_t* d) const + { + uint32_t a, b, c; + a = b = c = SMB_KEY_HASH_HARDENER; + + a += d[0]; // IPv6 lo[0] + b += d[1]; // IPv6 lo[1] + c += d[2]; // IPv6 lo[2] + + mix(a, b, c); + + a += d[3]; // IPv6 lo[3] + b += d[4]; // IPv6 hi[0] + c += d[5]; // IPv6 hi[1] + + mix(a, b, c); + + a += d[6]; // IPv6 hi[2] + b += d[7]; // IPv6 hi[3] + c += d[8]; // mpls label + + mix(a, b, c); + + a += d[9]; // addressSpaceId + b += d[10]; // port lo & port hi + c += d[11]; // group lo & group hi + + mix(a, b, c); + + a += d[12]; // vlan & pad + b += d[13]; // ip_proto, pkt_type, version, flags + + finalize(a, b, c); + + return c; + } +}; + +typedef DCE2_DbMap > DCE2_DbMapTtracker; +typedef DCE2_DbMap > DCE2_DbMapConntracker; +class DCE2_Smb2SessionTracker +{ +public: + + DCE2_Smb2SessionTracker() = delete; + DCE2_Smb2SessionTracker(uint64_t sid); + ~DCE2_Smb2SessionTracker(); + + void removeSessionFromAllConnection(); + void update_cache_size(int size); + + // tree tracker + bool insertTtracker(uint32_t tree_id, DCE2_Smb2TreeTracker* ttr) + { + update_cache_size(sizeof(DCE2_Smb2TreeTracker)); + return tree_trackers.Insert(tree_id, ttr); + } + + DCE2_Smb2TreeTracker* findTtracker(uint32_t tree_id) + { + return tree_trackers.Find(tree_id); + } + + void removeTtracker(uint32_t tree_id) + { + update_cache_size(-(int)sizeof(DCE2_Smb2TreeTracker)); + tree_trackers.Remove(tree_id); + } + + // ssd tracker + bool insertConnectionTracker(const uint32_t key, DCE2_Smb2SsnData* ssd) + { + return conn_trackers.Insert(key, ssd); + } + + DCE2_Smb2SsnData* findConnectionTracker(const uint32_t key) + { + return conn_trackers.Find(key); + } + + void removeConnectionTracker(const uint32_t key) + { + conn_trackers.Remove(key); + } + + int getConnTrackerSize() + { + return conn_trackers.GetSize(); + } + + void set_encryption_flag(bool flag) + { + if (flag) + encryption_flag++; + if (encryption_flag == 1) + dce2_smb_stats.total_encrypted_sessions++; + } + + bool get_encryption_flag() { return static_cast(encryption_flag); } + + DCE2_DbMapConntracker conn_trackers; + DCE2_DbMapTtracker tree_trackers; + uint64_t session_id = 0; + uint8_t encryption_flag = 0; +}; +struct DCE2_Smb2SsnData +{ + DCE2_SsnData sd; // This member must be first + uint8_t smb_id; + DCE2_Policy policy; + int dialect_index; + int ssn_state_flags; + int64_t max_file_depth; // Maximum file depth as returned from file API + int16_t max_outstanding_requests; // Maximum number of request that can stay pending + std::unordered_map, std::hash > session_trackers; + DCE2_Smb2FileTracker* ftracker_tcp; //To keep tab of current file being transferred over TCP + std::unique_ptr ftracker_local; + DCE2_DbMapRtracker req_trackers; + uint32_t flow_key; + snort::Flow* flow = nullptr; + DCE2_Smb2SsnData(); + ~DCE2_Smb2SsnData(); + void set_reassembled_data(uint8_t* nb_ptr, uint16_t co_len); + + std::shared_ptr find_session_tracker(uint64_t session_id) + { + auto session_iter = session_trackers.find(session_id); + if (session_iter != session_trackers.end()) + { + return session_iter->second.lock(); + } + return nullptr; + } + + void remove_session_tracker(uint64_t session_id) + { + session_trackers.erase(session_id); + } + + bool insert_session_tracker(uint64_t session_id, std::shared_ptr sptr) + { + return session_trackers.insert(std::make_pair(session_id, sptr)).second; + } + + // Request Tracker + DCE2_Smb2RequestTracker* findRtracker(uint64_t mid) + { + return req_trackers.Find(mid); + } + + bool insertRtracker(uint64_t message_id, DCE2_Smb2RequestTracker* rtracker) + { + return req_trackers.Insert(message_id, rtracker); + } + + void removeRtracker(uint64_t message_id) + { + req_trackers.Remove(message_id); + } + + int getTotalRequestsPending() + { + return req_trackers.GetSize(); + } + + DCE2_Smb2TreeTracker* GetTreeTrackerFromMessage(uint64_t mid) + { + DCE2_Smb2RequestTracker* request_tracker = findRtracker(mid); + if (request_tracker) + { + auto session_tracker = find_session_tracker(request_tracker->get_session_id()); + if (session_tracker) + { + return session_tracker->findTtracker(request_tracker->get_tree_id()); + } + } + return nullptr; + } +}; + +/* SMB2 command codes */ +#define SMB2_COM_NEGOTIATE 0x00 +#define SMB2_COM_SESSION_SETUP 0x01 +#define SMB2_COM_LOGOFF 0x02 +#define SMB2_COM_TREE_CONNECT 0x03 +#define SMB2_COM_TREE_DISCONNECT 0x04 +#define SMB2_COM_CREATE 0x05 +#define SMB2_COM_CLOSE 0x06 +#define SMB2_COM_FLUSH 0x07 +#define SMB2_COM_READ 0x08 +#define SMB2_COM_WRITE 0x09 +#define SMB2_COM_LOCK 0x0A +#define SMB2_COM_IOCTL 0x0B +#define SMB2_COM_CANCEL 0x0C +#define SMB2_COM_ECHO 0x0D +#define SMB2_COM_QUERY_DIRECTORY 0x0E +#define SMB2_COM_CHANGE_NOTIFY 0x0F +#define SMB2_COM_QUERY_INFO 0x10 +#define SMB2_COM_SET_INFO 0x11 +#define SMB2_COM_OPLOCK_BREAK 0x12 +#define SMB2_COM_MAX 0x13 + struct Smb2NegotiateResponseHdr { uint16_t structure_size; @@ -206,6 +588,9 @@ struct Smb2CreateRequestHdr uint32_t create_contexts_length; /* length of contexts */ }; +// file attribute for create response +#define SMB2_CREATE_RESPONSE_DIRECTORY 0x10 + struct Smb2CreateResponseHdr { uint16_t structure_size; /* This MUST be set to 89 */ @@ -226,16 +611,6 @@ struct Smb2CreateResponseHdr uint32_t create_contexts_length; /* */ }; -struct Smb2CreateContextHdr -{ - uint32_t next; /* next context header*/ - uint16_t name_offset; /* name offset */ - uint16_t name_length; /* name length */ - uint16_t reserved; /* reserved */ - uint16_t data_offset; /* data offset */ - uint32_t data_length; /* data length */ -}; - struct Smb2CloseRequestHdr { uint16_t structure_size; /* This MUST be set to 24 */ @@ -245,6 +620,10 @@ struct Smb2CloseRequestHdr uint64_t fileId_volatile; /* fileId that is volatile */ }; +#define SMB2_SHARE_TYPE_DISK 0x01 +#define SMB2_SHARE_TYPE_PIPE 0x02 +#define SMB2_SHARE_TYPE_PRINT 0x03 + struct Smb2TreeConnectResponseHdr { uint16_t structure_size; /* This MUST be set to 16 */ @@ -255,6 +634,42 @@ struct Smb2TreeConnectResponseHdr uint32_t maximal_access; /* maximal access for the user */ }; +struct Smb2TreeDisConnectHdr +{ + uint16_t structure_size; /* This MUST be set to 4 */ + uint16_t reserved; /* reserved */ +}; + +struct Smb2SetupRequestHdr +{ + uint16_t structure_size; /* This MUST be set to 25 (0x19) bytes */ + uint8_t flags; + uint8_t security_mode; + uint32_t capabilities; + uint32_t channel; + uint16_t secblob_ofs; + uint16_t secblob_size; + uint64_t previous_sessionid; +}; + +struct Smb2SetupResponseHdr +{ + uint16_t structure_size; /* This MUST be set to 9 (0x09) bytes */ + uint16_t session_flags; + uint16_t secblob_ofs; + uint16_t secblob_size; +}; + +struct Smb2CreateContextHdr +{ + uint32_t next; /* next context header*/ + uint16_t name_offset; /* name offset */ + uint16_t name_length; /* name length */ + uint16_t reserved; /* reserved */ + uint16_t data_offset; /* data offset */ + uint32_t data_length; /* data length */ +}; + struct Smb2IoctlRequestHdr { uint16_t structure_size; /* This MUST be set to 57 */ @@ -288,14 +703,14 @@ struct Smb2IoctlResponseHdr }; #define SMB2_HEADER_LENGTH 64 +#define SMB2_GLOBAL_CAP_MULTI_CHANNEL 0x08 #define SMB2_ERROR_RESPONSE_STRUC_SIZE 9 - -#define SMB2_NEGOTIATE_REQUEST_STRUC_SIZE 36 #define SMB2_NEGOTIATE_RESPONSE_STRUC_SIZE 65 #define SMB2_CREATE_REQUEST_STRUC_SIZE 57 #define SMB2_CREATE_RESPONSE_STRUC_SIZE 89 +#define SMB2_CREATE_REQUEST_DATA_OFFSET 120 #define SMB2_CLOSE_REQUEST_STRUC_SIZE 24 #define SMB2_CLOSE_RESPONSE_STRUC_SIZE 60 @@ -312,210 +727,35 @@ struct Smb2IoctlResponseHdr #define SMB2_TREE_CONNECT_REQUEST_STRUC_SIZE 9 #define SMB2_TREE_CONNECT_RESPONSE_STRUC_SIZE 16 #define SMB2_TREE_DISCONNECT_REQUEST_STRUC_SIZE 4 -#define SMB2_TREE_DISCONNECT_RESPONSE_STRUC_SIZE 4 + +#define SMB2_FILE_ALLOCATION_INFO 0x13 +#define SMB2_FILE_ENDOFFILE_INFO 0x14 #define SMB2_SETUP_REQUEST_STRUC_SIZE 25 #define SMB2_SETUP_RESPONSE_STRUC_SIZE 9 -#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 SMB2_FILE_ENDOFFILE_INFO 0x14 -#define SMB2_GLOBAL_CAP_MULTI_CHANNEL 0x08 - -#define GET_CURRENT_PACKET snort::DetectionEngine::get_current_packet() - -class Dce2Smb2FileTracker; -class Dce2Smb2SessionTracker; - -using Dce2Smb2SessionTrackerPtr = std::shared_ptr; -using Dce2Smb2SessionTrackerMap = - std::unordered_map >; - -using Dce2Smb2FileTrackerPtr = std::shared_ptr; -using Dce2Smb2FileTrackerMap = - std::unordered_map >; - -PADDING_GUARD_BEGIN -struct Smb2SessionKey -{ - uint32_t cip[4]; - uint32_t sip[4]; - uint64_t sid; - uint32_t asid; - int16_t cgroup; - int16_t sgroup; - - bool operator==(const Smb2SessionKey& other) const - { - return( sid == other.sid and - cip[0] == other.cip[0] and - cip[1] == other.cip[1] and - cip[2] == other.cip[2] and - cip[3] == other.cip[3] and - sip[0] == other.sip[0] and - sip[1] == other.sip[1] and - sip[2] == other.sip[2] and - sip[3] == other.sip[3] and - cgroup == other.cgroup and - sgroup == other.sgroup and - asid == other.asid ); - } -}; - -struct Smb2FlowKey -{ - uint32_t ip_l[4]; // Low IP - uint32_t ip_h[4]; // High IP - uint32_t mplsLabel; - uint32_t addressSpaceId; - uint16_t port_l; // Low Port - 0 if ICMP - uint16_t port_h; // High Port - 0 if ICMP - int16_t group_l; - int16_t group_h; - uint16_t vlan_tag; - uint16_t padding16; - uint8_t ip_protocol; - uint8_t pkt_type; - uint8_t version; - uint8_t padding; -}; - -struct Smb2MessageKey -{ - uint64_t mid; - uint32_t flow_key; - uint32_t padding; - - bool operator==(const Smb2MessageKey& other) const - { - return (mid == other.mid and - flow_key == other.flow_key); - } -}; -PADDING_GUARD_END - -//The below value is taken from Hash Key class static hash hardener -#define SMB_KEY_HASH_HARDENER 133824503 - -struct Smb2KeyHash -{ - size_t operator()(const Smb2FlowKey& key) const - { - return do_hash_flow_key((const uint32_t*)&key); - } - - size_t operator()(const Smb2SessionKey& key) const - { - return do_hash_session_key((const uint32_t*)&key); - } - - size_t operator()(const Smb2MessageKey& key) const - { - return do_hash_message_key((const uint32_t*)&key); - } - -private: - size_t do_hash_flow_key(const uint32_t* d) const - { - uint32_t a, b, c; - a = b = c = SMB_KEY_HASH_HARDENER; - a += d[0]; b += d[1]; c += d[2]; mix(a, b, c); - a += d[3]; b += d[4]; c += d[5]; mix(a, b, c); - a += d[6]; b += d[7]; c += d[8]; mix(a, b, c); - a += d[9]; b += d[10]; c += d[11]; mix(a, b, c); - a += d[12]; b += d[13]; finalize(a, b, c); - return c; - } - - size_t do_hash_session_key(const uint32_t* d) const - { - uint32_t a, b, c; - a = b = c = SMB_KEY_HASH_HARDENER; - a += d[0]; b += d[1]; c += d[2]; mix(a, b, c); - a += d[3]; b += d[4]; c += d[5]; mix(a, b, c); - a += d[6]; b += d[7]; c += d[8]; mix(a, b, c); - a += d[9]; b += d[10]; c += d[11]; finalize(a, b, c); - return c; - } - - size_t do_hash_message_key(const uint32_t* d) const - { - uint32_t a, b, c; - a = b = c = SMB_KEY_HASH_HARDENER; - a += d[0]; b += d[1]; c += d[2]; mix(a, b, c); - finalize(a, b, c); - return c; - } - - inline uint32_t rot(uint32_t x, unsigned k) const - { return (x << k) | (x >> (32 - k)); } - - inline void mix(uint32_t& a, uint32_t& b, uint32_t& c) const - { - a -= c; a ^= rot(c, 4); c += b; - b -= a; b ^= rot(a, 6); a += c; - c -= b; c ^= rot(b, 8); b += a; - a -= c; a ^= rot(c,16); c += b; - b -= a; b ^= rot(a,19); a += c; - c -= b; c ^= rot(b, 4); b += a; - } +#define SMB2_LOGOFF_REQUEST_STRUC_SIZE 4 - inline void finalize(uint32_t& a, uint32_t& b, uint32_t& c) const - { - c ^= b; c -= rot(b,14); - a ^= c; a -= rot(c,11); - b ^= a; b -= rot(a,25); - c ^= b; c -= rot(b,16); - a ^= c; a -= rot(c,4); - b ^= a; b -= rot(a,14); - c ^= b; c -= rot(b,24); - } -}; +#define SMB2_FLAGS_ASYNC_COMMAND 0x00000002 -uint32_t get_smb2_flow_key(const snort::FlowKey*); +#define SMB2_STATUS_PENDING 0x00000103 -class Dce2Smb2SessionData : public Dce2SmbSessionData -{ -public: - Dce2Smb2SessionData() = delete; - Dce2Smb2SessionData(const snort::Packet*, const dce2SmbProtoConf* proto); - ~Dce2Smb2SessionData() override; - void process() override; - void remove_session(uint64_t); - void handle_retransmit(FilePosition, FileVerdict) override { } - void reset_matching_tcp_file_tracker(Dce2Smb2FileTrackerPtr); - void set_reassembled_data(uint8_t*, uint16_t) override; - uint32_t get_flow_key() { return flow_key; } - void set_tcp_file_tracker(Dce2Smb2FileTrackerPtr file_tracker) - { - tcp_file_tracker = file_tracker; - } - - Dce2Smb2FileTrackerPtr get_tcp_file_tracker() - { - return tcp_file_tracker; - } +#define FSCTL_PIPE_WAIT 0x00110018 +#define FSCTL_PIPE_TRANSCEIVE 0x0011C017 +#define FSCTL_PIPE_PEEK 0x0011400C - Dce2Smb2SessionTrackerPtr find_session(uint64_t); - std::recursive_mutex session_data_mutex; - uint16_t vlan_id; +#define SMB2_CREATE_DURABLE_RECONNECT "DHnC" +#define SMB2_CREATE_DURABLE_RECONNECT_V2 "DH2C" -private: - void process_command(const Smb2Hdr*, const uint8_t*); - Smb2SessionKey get_session_key(uint64_t); - Dce2Smb2SessionTrackerPtr create_session(uint64_t); - Dce2Smb2FileTrackerPtr tcp_file_tracker; - uint32_t flow_key; - Dce2Smb2SessionTrackerMap connected_sessions; - std::mutex tcp_file_tracker_mutex; -}; +extern const char* smb2_command_string[SMB2_COM_MAX]; +/* Process smb2 message */ +void DCE2_Smb2Process(DCE2_Smb2SsnData* ssd); -using Dce2Smb2SessionDataMap = - std::unordered_map >; +/* Check smb version based on smb header */ +DCE2_SmbVersion DCE2_Smb2Version(const snort::Packet* p); #endif /* _DCE_SMB2_H_ */ diff --git a/src/service_inspectors/dce_rpc/dce_smb2_commands.cc b/src/service_inspectors/dce_rpc/dce_smb2_commands.cc new file mode 100644 index 000000000..43e2d5b8f --- /dev/null +++ b/src/service_inspectors/dce_rpc/dce_smb2_commands.cc @@ -0,0 +1,1204 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2016-2023 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_smb2_commands.cc author Bhargava Jandhyala +// based on work by Todd Wease + +// Smb commands processing + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "dce_smb2_commands.h" +#include "hash/hash_key_operations.h" +#include "log/messages.h" +#include "packet_io/active.h" +#include "protocols/packet.h" + +using namespace snort; +#define UNKNOWN_FILE_SIZE (~0) + +#define SMB2_CHECK_HDR_ERROR(smb_data, end, strcuture_size, counter, cmd) \ + { \ + if ((smb_data + (strcuture_size)) > end) \ + { \ + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, DetectionEngine::get_current_packet(), \ + "%s : smb truncated data detected\n", smb2_command_string[cmd]); \ + counter++; \ + return; \ + } \ + } + +inline FileFlows* DCE2_Smb2GetFileFlow(DCE2_Smb2FileTracker* ftracker) +{ + Packet* p = DetectionEngine::get_current_packet(); + if (p->flow != ftracker->parent_flow) + ftracker->multi_channel_file = true; + if (!ftracker->parent_flow) + { + //Parent flow is deleted, upgrade the current flow as parent flow + ftracker->parent_flow = p->flow; + dce2_smb_stats.v2_updated_file_flows++; + } + return FileFlows::get_file_flows(ftracker->parent_flow); +} + +inline FileFlows* DCE2_Smb2GetCurrentFileFlow() +{ + Packet* p = DetectionEngine::get_current_packet(); + return FileFlows::get_file_flows(p->flow); +} + +static inline FileContext* DCE2_Smb2GetFileContext(DCE2_Smb2SsnData*, DCE2_Smb2FileTracker* ftracker, bool + to_create = false) +{ + FileFlows* file_flows = DCE2_Smb2GetFileFlow(ftracker); + if ( !file_flows ) + { + dce2_smb_stats.v2_inv_file_ctx_err++; + return nullptr; + } + bool is_new_context = false; + if (ftracker->file_name_hash) + return file_flows->get_file_context(ftracker->file_name_hash, to_create, is_new_context, ftracker->file_id); + return file_flows->get_file_context(ftracker->file_id, to_create, is_new_context); +} + +inline void DCE2_Smb2UpdateMaxOffset(DCE2_Smb2FileTracker* ftracker, uint64_t offset) +{ + if (ftracker->max_offset < offset) + ftracker->max_offset = offset; +} + +bool DCE2_Smb2ProcessFileData(DCE2_Smb2SsnData* ssd, const uint8_t* file_data, + uint32_t data_size) +{ + if (ssd->ftracker_tcp->co_tracker) + { + DCE2_CoProcess(&ssd->sd, ssd->ftracker_tcp->co_tracker, + file_data, data_size); + return true; + } + int64_t file_detection_depth = DCE2_ScSmbFileDepth((dce2SmbProtoConf*)ssd->sd.config); + int64_t detection_size = 0; + + if (file_detection_depth == 0) + detection_size = data_size; + else if ( ssd->ftracker_local->file_offset < (uint64_t)file_detection_depth) + { + if ( file_detection_depth - ssd->ftracker_local->file_offset < data_size ) + detection_size = file_detection_depth - ssd->ftracker_local->file_offset; + else + detection_size = data_size; + } + + if (detection_size) + { + set_file_data(file_data, + (detection_size > UINT16_MAX) ? UINT16_MAX : (uint16_t)detection_size); + + DCE2_FileDetect(); + } + Packet* p = DetectionEngine::get_current_packet(); + FileDirection dir = ssd->ftracker_tcp->upload ? FILE_UPLOAD : FILE_DOWNLOAD; + + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, p, + "file_process fid 0x%" PRIx64 " data_size %" PRIu32 " offset %" + PRIu64 "\n", ssd->ftracker_tcp->file_id, data_size, + ssd->ftracker_local->file_offset); + + if (!ssd->ftracker_tcp->ignore) + { + // Do not process data beyond file size if file size is known. + if (ssd->ftracker_tcp->file_size) + { + if (ssd->ftracker_local->file_offset > ssd->ftracker_tcp->file_size) + { + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, + TRACE_ERROR_LEVEL, DetectionEngine::get_current_packet(), + "file_process: bad offset\n"); + return false; + } + else if (ssd->ftracker_local->file_offset + data_size > ssd->ftracker_tcp->file_size) + { + //Trim padded data + data_size = ssd->ftracker_tcp->file_size - ssd->ftracker_local->file_offset; + } + } + + FileFlows* file_flows = DCE2_Smb2GetFileFlow(ssd->ftracker_tcp); + if (!file_flows) + { + dce2_smb_stats.v2_extra_file_data_err++; + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + p, "No file flow \n"); + + DCE2_Smb2TreeTracker* ttr = ssd->ftracker_tcp->ttr; + ttr->removeFtracker(ssd->ftracker_tcp->file_id); + return false; + } + + // A hack to force to create a file flow for this connection + // Required for file type detection based on IPS rules. + if (ssd->flow != ssd->ftracker_tcp->parent_flow) + DCE2_Smb2GetCurrentFileFlow(); + + bool continue_processing = true; + if (ssd->ftracker_tcp->file_name_hash) + continue_processing = file_flows->file_process(p, ssd->ftracker_tcp->file_name_hash, file_data, data_size, + ssd->ftracker_local->file_offset, dir, ssd->ftracker_tcp->file_id); + else + continue_processing = file_flows->file_process(p, ssd->ftracker_tcp->file_id, file_data, data_size, + ssd->ftracker_local->file_offset, dir); + if (!continue_processing) + { + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, + p, "file_process completed\n"); + } + } + ssd->ftracker_local->file_offset += data_size; + return true; +} + +//------------------------------------------------------------------------- +// Process session setup response to find/create session tracker +//------------------------------------------------------------------------- +void DCE2_Smb2Setup(DCE2_Smb2SsnData* ssd, const Smb2Hdr* smb_hdr, const uint64_t sid, + const uint8_t* smb_data, const uint8_t* end) +{ + uint16_t structure_size = alignedNtohs((const uint16_t*)smb_data); + + if (structure_size == SMB2_ERROR_RESPONSE_STRUC_SIZE and Smb2Error(smb_hdr)) + { + if ((alignedNtohl(&(smb_hdr->flags)) & SMB2_FLAGS_ASYNC_COMMAND) && + (alignedNtohl(&(smb_hdr->status)) == SMB2_STATUS_PENDING)) + return; + + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, + DetectionEngine::get_current_packet(), "%s_RESP: error\n", + smb2_command_string[SMB2_COM_SESSION_SETUP]); + dce2_smb_stats.v2_setup_err_resp++; + } + else if (structure_size == SMB2_SETUP_RESPONSE_STRUC_SIZE) + { + SMB2_CHECK_HDR_ERROR( + smb_data, end, SMB2_SETUP_RESPONSE_STRUC_SIZE - 1, + dce2_smb_stats.v2_setup_resp_hdr_err, SMB2_COM_SESSION_SETUP) + DCE2_Smb2FindElseCreateSid(ssd, sid); + } + else if (structure_size != SMB2_SETUP_REQUEST_STRUC_SIZE) + { + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + DetectionEngine::get_current_packet(), "%s: invalid struct size\n", + smb2_command_string[SMB2_COM_SESSION_SETUP]); + dce2_smb_stats.v2_setup_inv_str_sz++; + } +} + +//------------------------------------------------------------------------- +// Process tree connect response to find/create tree tracker +//------------------------------------------------------------------------- +void DCE2_Smb2TreeConnect(DCE2_Smb2SsnData* ssd, const Smb2Hdr* smb_hdr, + const uint8_t* smb_data, const uint8_t* end, DCE2_Smb2SessionTracker* str, uint32_t tid) +{ + uint16_t structure_size = alignedNtohs((const uint16_t*)smb_data); + + if (structure_size == SMB2_ERROR_RESPONSE_STRUC_SIZE and Smb2Error(smb_hdr)) + { + if ((alignedNtohl(&(smb_hdr->flags)) & SMB2_FLAGS_ASYNC_COMMAND) && + (alignedNtohl(&(smb_hdr->status)) == SMB2_STATUS_PENDING)) + return; + + dce2_smb_stats.v2_tree_cnct_err_resp++; + } + else if (structure_size == SMB2_TREE_CONNECT_RESPONSE_STRUC_SIZE) + { + SMB2_CHECK_HDR_ERROR( + smb_data, end, SMB2_TREE_CONNECT_RESPONSE_STRUC_SIZE, + dce2_smb_stats.v2_tree_cnct_resp_hdr_err, SMB2_COM_TREE_CONNECT) + + if (!DCE2_Smb2InsertTid(ssd, tid, + ((const Smb2TreeConnectResponseHdr*)smb_data)->share_type, str)) + { + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, + DetectionEngine::get_current_packet(), "%s: ignored %d\n", + smb2_command_string[SMB2_COM_TREE_CONNECT], tid); + dce2_smb_stats.v2_tree_cnct_ignored++; + } + } + else if (structure_size != SMB2_TREE_CONNECT_REQUEST_STRUC_SIZE) + { + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + DetectionEngine::get_current_packet(), "%s: invalid struct size\n", + smb2_command_string[SMB2_COM_TREE_CONNECT]); + dce2_smb_stats.v2_tree_cnct_inv_str_sz++; + } +} + +//------------------------------------------------------------------------- +// Process tree disconnect request to cleanup tree tracker and its +// corresponding request trackers and file trackers +//------------------------------------------------------------------------- +void DCE2_Smb2TreeDisconnect(DCE2_Smb2SsnData*, const uint8_t* smb_data, + const uint8_t* end) +{ + if (SMB2_TREE_DISCONNECT_REQUEST_STRUC_SIZE == alignedNtohs((const uint16_t*)smb_data)) + { + SMB2_CHECK_HDR_ERROR( + smb_data, end, SMB2_TREE_DISCONNECT_REQUEST_STRUC_SIZE, + dce2_smb_stats.v2_tree_discn_req_hdr_err, SMB2_COM_TREE_DISCONNECT) + } + else + { + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + DetectionEngine::get_current_packet(), "%s: invalid struct size\n", + smb2_command_string[SMB2_COM_TREE_DISCONNECT]); + dce2_smb_stats.v2_tree_discn_inv_str_sz++; + } +} + +bool DCE2_IsSmb2DurableReconnect(const Smb2CreateRequestHdr* smb_create_hdr, const uint8_t* end, uint64_t& file_id) +{ + const uint8_t* data = (const uint8_t*)smb_create_hdr + alignedNtohl(&smb_create_hdr->create_contexts_offset) - + SMB2_HEADER_LENGTH; + uint32_t remaining = alignedNtohl(&smb_create_hdr->create_contexts_length); + + while (remaining > sizeof(Smb2CreateRequestHdr) && data < end) + { + const Smb2CreateContextHdr* context = (const Smb2CreateContextHdr*)data; + uint32_t next = alignedNtohl(&context->next); + uint16_t name_offset = alignedNtohs(&context->name_offset); + uint16_t name_length = alignedNtohs(&context->name_length); + uint16_t data_offset = alignedNtohs(&context->data_offset); + uint32_t data_length = alignedNtohl(&context->data_length); + + /* Check for general error condition */ + if ((next & 0x7) != 0 or + next > remaining or + name_offset != 16 or + name_length < 4 or + name_offset + name_length > remaining or + (data_offset & 0x7) != 0 or + (data_offset and (data_offset < name_offset + name_length)) or + (data_offset > remaining) or + (data_offset + data_length > remaining)) + { + return false; + } + + if ((strncmp((const char*)context+name_offset, SMB2_CREATE_DURABLE_RECONNECT_V2, name_length) == 0) or + (strncmp((const char*)context+name_offset, SMB2_CREATE_DURABLE_RECONNECT, name_length) == 0)) + { + file_id = alignedNtohq((const uint64_t*)(((const uint8_t*)context) + data_offset)); + return true; + } + + if (!next) + break; + + data += next; + remaining -= next; + } + return false; +} + +//------------------------------------------------------------------------- +// Process create request to get file name and save it in request tracker +//------------------------------------------------------------------------- +static void DCE2_Smb2CreateRequest(DCE2_Smb2SsnData* ssd, + const Smb2CreateRequestHdr* smb_create_hdr, const uint8_t* end, + DCE2_Smb2SessionTracker* str, DCE2_Smb2TreeTracker* ttr, uint64_t mid) +{ + uint16_t name_offset = alignedNtohs(&(smb_create_hdr->name_offset)); + + if (name_offset > SMB2_HEADER_LENGTH) + { + uint16_t name_len = 0; + + const uint8_t* file_data = (const uint8_t*)smb_create_hdr + smb_create_hdr->name_offset - + SMB2_HEADER_LENGTH; + if (file_data >= end) + { + dce2_smb_stats.v2_crt_inv_file_data++; + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + DetectionEngine::get_current_packet(), "%s_REQ: invalid " + "file data seen\n", smb2_command_string[SMB2_COM_CREATE]); + return; + } + + uint16_t size = alignedNtohs(&(smb_create_hdr->name_length)); + if (!size or (file_data + size > end)) + { + dce2_smb_stats.v2_crt_inv_file_data++; + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + DetectionEngine::get_current_packet(), + "%s_REQ: invalid file data seen with size %" PRIu16 "\n", + smb2_command_string[SMB2_COM_CREATE], size); + return; + } + + if (ssd->max_outstanding_requests > ssd->getTotalRequestsPending()) + { + char* file_name = DCE2_SmbGetFileName(file_data, size, true, &name_len); + auto rtracker = new DCE2_Smb2RequestTracker(file_name, name_len); + rtracker->set_session_id(str->session_id); + rtracker->set_tree_id(ttr->get_tid()); + ssd->insertRtracker(mid, rtracker); + uint64_t file_id = 0; + if (DCE2_IsSmb2DurableReconnect(smb_create_hdr, end, file_id)) + { + //Create a ftracker here to handle compound write case + auto ftracker = new DCE2_Smb2FileTracker(file_id, ttr, str, + DetectionEngine::get_current_packet()->flow); + if (file_name and name_len) + { + ftracker->file_name_hash = str_to_hash( + (const uint8_t*)file_name, name_len); + } + else + { + ftracker->ignore = true; + dce2_smb_stats.v2_ignored_file_processing++; + } + ttr->insertFtracker(file_id, ftracker); + if (SMB2_SHARE_TYPE_DISK == ttr->get_share_type()) + { + FileContext* file = DCE2_Smb2GetFileContext(ssd, ftracker, true); + if (file) + file->set_file_name(file_name, name_len); + else + { + //Ignore the file processing. + ftracker->ignore = true; + dce2_smb_stats.v2_ignored_file_processing++; + } + } + else + { + ftracker->co_tracker = (DCE2_CoTracker*)snort_calloc(sizeof(DCE2_CoTracker)); + DCE2_CoInitTracker(ftracker->co_tracker); + } + } + } + else + { + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + DetectionEngine::get_current_packet(), "%s_REQ: max req exceeded\n", + smb2_command_string[SMB2_COM_CREATE]); + dce_alert(GID_DCE2, DCE2_SMB_MAX_REQS_EXCEEDED, (dce2CommonStats*)&dce2_smb_stats, + ssd->sd); + } + } + else + { + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, + DetectionEngine::get_current_packet(), "%s_REQ: name_offset %" + PRIu16 "\n", smb2_command_string[SMB2_COM_CREATE], name_offset); + dce2_smb_stats.v2_crt_req_hdr_err++; + } +} + +//------------------------------------------------------------------------- +// Process create response to create file tracker with file id and file +// size. Request tracker is cleaned after updating file name in file tracker +//------------------------------------------------------------------------- +static void DCE2_Smb2CreateResponse(DCE2_Smb2SsnData* ssd, + const Smb2CreateResponseHdr* smb_create_hdr, DCE2_Smb2RequestTracker* rtracker, + DCE2_Smb2TreeTracker* ttr, DCE2_Smb2SessionTracker* str, uint64_t fileId_persistent) +{ + uint64_t file_size = 0; + + if (smb_create_hdr->end_of_file) + { + file_size = alignedNtohq((const uint64_t*)(&(smb_create_hdr->end_of_file))); + } + + DCE2_Smb2FileTracker* ftracker = ttr->findFtracker(fileId_persistent); + if (!ftracker) + { + ftracker = new DCE2_Smb2FileTracker(fileId_persistent, ttr, str, DetectionEngine::get_current_packet()->flow); + ttr->insertFtracker(fileId_persistent, ftracker); + } + + ftracker->file_size = file_size; + if (SMB2_SHARE_TYPE_DISK == ttr->get_share_type()) + { + if (rtracker->fname and rtracker->fname_len) + { + if (!ftracker->file_name_hash) + ftracker->file_name_hash = str_to_hash( + (const uint8_t*)rtracker->fname, rtracker->fname_len); + + FileContext* file = DCE2_Smb2GetFileContext(ssd, ftracker, true); + + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, + DetectionEngine::get_current_packet(), "%s_RESP: file size %" + PRIu64 " fid 0x%" PRIx64 " file_name_hash %" PRIu64 " file context %s\n", + smb2_command_string[SMB2_COM_CREATE], file_size, + fileId_persistent, ftracker->file_name_hash, (file ? "found" : "not found")); + + if (file) + { + if (file->verdict == FILE_VERDICT_UNKNOWN) + { + file->set_file_size(!file_size ? UNKNOWN_FILE_SIZE : file_size); + file->set_file_name(rtracker->fname, rtracker->fname_len); + } + } + else + { + // could not create file context, hence this file transfer + // cant be inspected + ftracker->ignore = true; + dce2_smb_stats.v2_ignored_file_processing++; + } + } + else + { + ftracker->ignore = true; // file can not be inspected as file name is not present + dce2_smb_stats.v2_ignored_file_processing++; + } + } + else + { + ftracker->co_tracker = (DCE2_CoTracker*)snort_calloc(sizeof(DCE2_CoTracker)); + DCE2_CoInitTracker(ftracker->co_tracker); + } +} + +//------------------------------------------------------------------------- +// Process create request to handle mid stream sessions by adding tree +// tracker if not already present. Process create response for only disk +// share type. +//------------------------------------------------------------------------- +void DCE2_Smb2Create(DCE2_Smb2SsnData* ssd, const Smb2Hdr* smb_hdr, + const uint8_t* smb_data, const uint8_t* end, uint64_t mid, uint64_t sid, uint32_t tid) +{ + DCE2_Smb2SessionTracker* str = DCE2_Smb2FindElseCreateSid(ssd, sid); + DCE2_Smb2TreeTracker* ttr = nullptr; + if (tid) + ttr = str->findTtracker(tid); + uint16_t structure_size = alignedNtohs((const uint16_t*)smb_data); + + if (structure_size == SMB2_ERROR_RESPONSE_STRUC_SIZE and Smb2Error(smb_hdr)) + { + if ((alignedNtohl(&(smb_hdr->flags)) & SMB2_FLAGS_ASYNC_COMMAND) && + (alignedNtohl(&(smb_hdr->status)) == SMB2_STATUS_PENDING)) + return; + + ssd->removeRtracker(mid); + + dce2_smb_stats.v2_crt_err_resp++; + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + DetectionEngine::get_current_packet(), "%s_RESP: error\n", + smb2_command_string[SMB2_COM_CREATE]); + } + // Using structure size to decide whether it is response or request + else if (structure_size == SMB2_CREATE_REQUEST_STRUC_SIZE) + { + SMB2_CHECK_HDR_ERROR( + smb_data, end, SMB2_CREATE_REQUEST_STRUC_SIZE - 1, + dce2_smb_stats.v2_crt_req_hdr_err, SMB2_COM_CREATE) + + if (!ttr) + { + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, + DetectionEngine::get_current_packet(), + "%s_REQ: mid stream session detected\n", + smb2_command_string[SMB2_COM_CREATE]); + ttr = DCE2_Smb2InsertTid(ssd, tid, SMB2_SHARE_TYPE_DISK, str); + if (!ttr) + { + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + DetectionEngine::get_current_packet(), + "%s_REQ: insert tree tracker failed\n", + smb2_command_string[SMB2_COM_CREATE]); + return; + } + } + else if (SMB2_SHARE_TYPE_DISK != ttr->get_share_type()) + { + dce2_smb_stats.v2_crt_req_ipc++; + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + "%s_REQ: processed for ipc share\n", + smb2_command_string[SMB2_COM_CREATE]); + } + DCE2_Smb2CreateRequest(ssd, (const Smb2CreateRequestHdr*)smb_data, end, str, ttr, mid); + } + else if (structure_size == SMB2_CREATE_RESPONSE_STRUC_SIZE) + { + SMB2_CHECK_HDR_ERROR( + smb_data, end, SMB2_CREATE_RESPONSE_STRUC_SIZE - 1, + dce2_smb_stats.v2_crt_resp_hdr_err, SMB2_COM_CREATE) + if (!ttr) + { + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + DetectionEngine::get_current_packet(), + "%s_RESP: tree tracker missing\n", + smb2_command_string[SMB2_COM_CREATE]); + dce2_smb_stats.v2_crt_tree_trkr_misng++; + return; + } + + DCE2_Smb2RequestTracker* rtr = ssd->findRtracker(mid); + if (!rtr) + { + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + DetectionEngine::get_current_packet(), + "%s_RESP: req tracker missing\n", + smb2_command_string[SMB2_COM_CREATE]); + dce2_smb_stats.v2_crt_rtrkr_misng++; + return; + } + + uint64_t fileId_persistent = alignedNtohq((const uint64_t*)( + &(((const Smb2CreateResponseHdr*)smb_data)->fileId_persistent))); + + if (((const Smb2CreateResponseHdr*)smb_data)->file_attributes & + SMB2_CREATE_RESPONSE_DIRECTORY) + { + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + DetectionEngine::get_current_packet(), + "%s_RESP: not processing for directory\n", + smb2_command_string[SMB2_COM_CREATE]); + ssd->removeRtracker(mid); + return; + } + + DCE2_Smb2CreateResponse(ssd, (const Smb2CreateResponseHdr*)smb_data, rtr, ttr, + str, fileId_persistent); + ssd->removeRtracker(mid); + } + else + { + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + DetectionEngine::get_current_packet(), "%s: invalid struct size\n", + smb2_command_string[SMB2_COM_CREATE]); + dce2_smb_stats.v2_crt_inv_str_sz++; + } +} + +//------------------------------------------------------------------------- +// Process close command request to do file processing for an upload or +// download request with unknown size. +//------------------------------------------------------------------------- +void DCE2_Smb2CloseCmd(DCE2_Smb2SsnData* ssd, const Smb2Hdr* smb_hdr, + const uint8_t* smb_data, const uint8_t* end, DCE2_Smb2TreeTracker* ttr, + DCE2_Smb2SessionTracker* str, uint64_t mid) +{ + uint16_t structure_size = alignedNtohs((const uint16_t*)smb_data); + + if (structure_size == SMB2_ERROR_RESPONSE_STRUC_SIZE and Smb2Error(smb_hdr)) + { + if ((alignedNtohl(&(smb_hdr->flags)) & SMB2_FLAGS_ASYNC_COMMAND) && + (alignedNtohl(&(smb_hdr->status)) == SMB2_STATUS_PENDING)) + return; + + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + DetectionEngine::get_current_packet(), "%s_RESP: error\n", + smb2_command_string[SMB2_COM_CLOSE]); + dce2_smb_stats.v2_cls_err_resp++; + } + // Using structure size to decide whether it is response or request + else if (structure_size == SMB2_CLOSE_REQUEST_STRUC_SIZE) + { + SMB2_CHECK_HDR_ERROR( + smb_data, end, SMB2_CLOSE_REQUEST_STRUC_SIZE, + dce2_smb_stats.v2_cls_req_hdr_err, SMB2_COM_CLOSE) + + uint64_t fileId_persistent = alignedNtohq(&(((const + Smb2CloseRequestHdr*)smb_data)->fileId_persistent)); + DCE2_Smb2FileTracker* ftracker = ttr->findFtracker(fileId_persistent); + if (!ftracker) + { + dce2_smb_stats.v2_cls_req_ftrkr_misng++; + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + DetectionEngine::get_current_packet(), "%s_REQ: ftracker missing 0x%" + PRIx64 "\n", smb2_command_string[SMB2_COM_CLOSE], fileId_persistent); + return; + } + + if (ssd->max_outstanding_requests > ssd->getTotalRequestsPending()) + { + auto rtracker = new DCE2_Smb2RequestTracker(fileId_persistent); + rtracker->set_session_id(str->session_id); + rtracker->set_tree_id(ttr->get_tid()); + ssd->insertRtracker(mid, rtracker); + } + + if (SMB2_SHARE_TYPE_DISK == ttr->get_share_type() and !ftracker->ignore + and !ftracker->file_size and ftracker->max_offset) + { + ftracker->file_size = ftracker->max_offset; + FileContext* file = DCE2_Smb2GetFileContext(ssd, ftracker); + if (file) + { + file->set_file_size(ftracker->file_size); + } + + ssd->ftracker_tcp = ftracker; + ssd->ftracker_local = std::unique_ptr(new DCE2_Smb2LocalFileTracker()); + ssd->ftracker_local->file_offset = ftracker->max_offset; + // In case of upload/download of file with UNKNOWN size, we will not be able to + // detect malicious file during write request or read response. Once the close + // command request comes, we will go for file inspection and block an subsequent + // upload/download request for this file even with unknown size + DCE2_Smb2ProcessFileData(ssd, nullptr, 0); + } + } + else if (structure_size == SMB2_CLOSE_RESPONSE_STRUC_SIZE) + { + DCE2_Smb2RequestTracker* rtr = ssd->findRtracker(mid); + if (!rtr) + { + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + DetectionEngine::get_current_packet(), + "%s_RESP: req tracker missing\n", + smb2_command_string[SMB2_COM_CLOSE]); + return; + } + auto fileId_persistent = rtr->get_file_id(); + ttr->removeFtracker(fileId_persistent); + ssd->removeRtracker(mid); + } + else + { + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + DetectionEngine::get_current_packet(), "%s: invalid struct size\n", + smb2_command_string[SMB2_COM_CLOSE]); + dce2_smb_stats.v2_cls_inv_str_sz++; + DCE2_Smb2RequestTracker* rtr = ssd->findRtracker(mid); + if (rtr) + { + auto fileId_persistent = rtr->get_file_id(); + ttr->removeFtracker(fileId_persistent); + ssd->removeRtracker(mid); + } + } +} + +//------------------------------------------------------------------------- +// Process set info request to update file size +//------------------------------------------------------------------------- +void DCE2_Smb2SetInfo(DCE2_Smb2SsnData* ssd, const Smb2Hdr* smb_hdr, + const uint8_t* smb_data, const uint8_t* end, DCE2_Smb2TreeTracker* ttr) +{ + uint16_t structure_size = alignedNtohs((const uint16_t*)smb_data); + + // Using structure size to decide whether it is response or request + if (structure_size == SMB2_ERROR_RESPONSE_STRUC_SIZE and Smb2Error(smb_hdr)) + { + if ((alignedNtohl(&(smb_hdr->flags)) & SMB2_FLAGS_ASYNC_COMMAND) && + (alignedNtohl(&(smb_hdr->status)) == SMB2_STATUS_PENDING)) + return; + + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + DetectionEngine::get_current_packet(), "%s: error resp\n", + smb2_command_string[SMB2_COM_SET_INFO]); + dce2_smb_stats.v2_stinf_err_resp++; + } + else if (structure_size == SMB2_SET_INFO_REQUEST_STRUC_SIZE) + { + SMB2_CHECK_HDR_ERROR( + smb_data, end, SMB2_SET_INFO_REQUEST_STRUC_SIZE, + dce2_smb_stats.v2_stinf_req_hdr_err, SMB2_COM_SET_INFO) + + const Smb2SetInfoRequestHdr* smb_set_info_hdr = (const Smb2SetInfoRequestHdr*)smb_data; + const uint8_t* file_data = (const uint8_t*)smb_set_info_hdr + + SMB2_SET_INFO_REQUEST_STRUC_SIZE - 1; + + if (smb_set_info_hdr->file_info_class == SMB2_FILE_ENDOFFILE_INFO or + smb_set_info_hdr->file_info_class == SMB2_FILE_ALLOCATION_INFO) + { + uint64_t file_size = alignedNtohq((const uint64_t*)file_data); + uint64_t fileId_persistent = alignedNtohq(&(smb_set_info_hdr->fileId_persistent)); + DCE2_Smb2FileTracker* ftracker = ttr->findFtracker(fileId_persistent); + if (ftracker and !ftracker->ignore) + { + if (smb_set_info_hdr->file_info_class == SMB2_FILE_ALLOCATION_INFO) + { + if(ftracker->file_size < file_size) + { + //Then possible ZIP upload in which case we dont know the actual size of the file + ftracker->file_size = 0; + } + } + else + ftracker->file_size = file_size; + + FileContext* file = DCE2_Smb2GetFileContext(ssd, ftracker); + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, + DetectionEngine::get_current_packet(), + "%s_REQ: set file size %" PRIu64 " fid 0x%" PRIx64 " file context %s\n", + smb2_command_string[SMB2_COM_SET_INFO], file_size, fileId_persistent, + file ? "found" : "not found"); + if (file) + { + file->set_file_size(ftracker->file_size); + } + } + else + { + dce2_smb_stats.v2_stinf_req_ftrkr_misng++; + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + DetectionEngine::get_current_packet(), + "%s_REQ: ftracker missing\n", + smb2_command_string[SMB2_COM_SET_INFO]); + } + } + else + { + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + DetectionEngine::get_current_packet(), "%s_REQ: header error\n", + smb2_command_string[SMB2_COM_SET_INFO]); + + dce2_smb_stats.v2_stinf_req_hdr_err++; + } + } + else if (structure_size != SMB2_SET_INFO_RESPONSE_STRUC_SIZE) + { + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + DetectionEngine::get_current_packet(), "%s: invalid struct size\n", + smb2_command_string[SMB2_COM_SET_INFO]); + dce2_smb_stats.v2_stinf_inv_str_sz++; + } +} + +//------------------------------------------------------------------------- +// Process read request to create read request trackers to get file offset +//------------------------------------------------------------------------- +static void DCE2_Smb2ReadRequest(DCE2_Smb2SsnData* ssd, + const Smb2ReadRequestHdr* smb_read_hdr, const uint8_t*, DCE2_Smb2SessionTracker* str, + DCE2_Smb2TreeTracker* ttr, uint64_t message_id) +{ + uint64_t offset = alignedNtohq((const uint64_t*)(&(smb_read_hdr->offset))); + uint64_t fileId_persistent = alignedNtohq((const + uint64_t*)(&(smb_read_hdr->fileId_persistent))); + + if (ssd->max_outstanding_requests > ssd->getTotalRequestsPending()) + { + DCE2_Smb2RequestTracker* readtracker = ssd->findRtracker(message_id); + if (!readtracker) + readtracker = new DCE2_Smb2RequestTracker(fileId_persistent, offset); + readtracker->set_session_id(str->session_id); + readtracker->set_tree_id(ttr->get_tid()); + readtracker->set_file_id(fileId_persistent); + ssd->insertRtracker(message_id, readtracker); + } + else + { + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_CRITICAL_LEVEL, + DetectionEngine::get_current_packet(), "%s_REQ: max req exceeded\n", + smb2_command_string[SMB2_COM_READ]); + dce_alert(GID_DCE2, DCE2_SMB_MAX_REQS_EXCEEDED, (dce2CommonStats*)&dce2_smb_stats, + ssd->sd); + return; + } + + DCE2_Smb2FileTracker* ftracker = ttr->findFtracker(fileId_persistent); + if (!ftracker and ttr->get_share_type() == SMB2_SHARE_TYPE_DISK) + { + //At times read is sent after the close, in case of malware block + // Create a file tracker here + ftracker = new DCE2_Smb2FileTracker(fileId_persistent, ttr, str, DetectionEngine::get_current_packet()->flow); + ttr->insertFtracker(fileId_persistent, ftracker); + } + if (!ftracker) + { + dce2_smb_stats.v2_read_rtrkr_misng++; + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_CRITICAL_LEVEL, + DetectionEngine::get_current_packet(), "%s_REQ: ftracker missing 0x%" + PRIx64 "\n", smb2_command_string[SMB2_COM_READ], fileId_persistent); + return; + } + + if (ftracker->file_size and (offset > ftracker->file_size)) + { + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_CRITICAL_LEVEL, + DetectionEngine::get_current_packet(), + "%s_REQ: invalid file offset\n", smb2_command_string[SMB2_COM_READ]); + dce_alert(GID_DCE2, DCE2_SMB_INVALID_FILE_OFFSET, (dce2CommonStats*)&dce2_smb_stats, + ssd->sd); + } +} + +//------------------------------------------------------------------------- +// Process read response to send file data for inspection. read request +// trackers is cleaned after updating file offset in file tracker +//------------------------------------------------------------------------- +static void DCE2_Smb2ReadResponse(DCE2_Smb2SsnData* ssd, const Smb2Hdr* smb_hdr, + const Smb2ReadResponseHdr* smb_read_hdr, const uint8_t* end, DCE2_Smb2TreeTracker* ttr, + uint64_t message_id) +{ + const uint8_t* file_data = (const uint8_t*)smb_read_hdr + SMB2_READ_RESPONSE_STRUC_SIZE - 1; + int data_size = end - file_data; + uint16_t data_offset; + DCE2_Smb2RequestTracker* request = ssd->findRtracker(message_id); + + if (!request) + { + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_CRITICAL_LEVEL, + DetectionEngine::get_current_packet(), + "%s_RESP: request tracker missing\n", smb2_command_string[SMB2_COM_READ]); + dce2_smb_stats.v2_read_rtrkr_misng++; + return; + } + data_offset = alignedNtohs((const uint16_t*)(&(smb_read_hdr->data_offset))); + if (data_offset + (const uint8_t*)smb_hdr > end) + { + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_CRITICAL_LEVEL, + DetectionEngine::get_current_packet(), "%s_RESP: bad offset\n", + smb2_command_string[SMB2_COM_READ]); + dce_alert(GID_DCE2, DCE2_SMB_BAD_OFF, (dce2CommonStats*)&dce2_smb_stats, ssd->sd); + } + + DCE2_Smb2FileTracker* ftracker = ttr->findFtracker(request->get_file_id()); + if ( ftracker and !ftracker->ignore ) + { + ftracker->upload = false; + ssd->ftracker_local = std::unique_ptr(new DCE2_Smb2LocalFileTracker()); + ssd->ftracker_local->file_offset = request->get_offset(); + ssd->ftracker_tcp = ftracker; + if (!ssd->ftracker_local->file_offset and SMB2_SHARE_TYPE_DISK == ttr->get_share_type()) + { + FileContext* file = DCE2_Smb2GetFileContext(ssd, ftracker, true); + if (file) + file->set_file_size(!ftracker->file_size ? UNKNOWN_FILE_SIZE : ftracker->file_size); + } + if (!DCE2_Smb2ProcessFileData(ssd, file_data, data_size)) + { + ssd->removeRtracker(message_id); + return; + } + + uint32_t total_data_length = alignedNtohl((const uint32_t*)&(smb_read_hdr->length)); + DCE2_Smb2UpdateMaxOffset(ftracker, request->get_offset() + total_data_length); + if (total_data_length > (uint32_t)data_size) + { + ssd->ftracker_local->smb2_pdu_state = DCE2_SMB_PDU_STATE__RAW_DATA; + } + } + ssd->removeRtracker(message_id); +} + +//------------------------------------------------------------------------- +// Process read message +//------------------------------------------------------------------------- +void DCE2_Smb2Read(DCE2_Smb2SsnData* ssd, const Smb2Hdr* smb_hdr, + const uint8_t* smb_data, const uint8_t* end, DCE2_Smb2SessionTracker* str, + DCE2_Smb2TreeTracker* ttr, uint64_t mid) +{ + uint16_t structure_size = alignedNtohs((const uint16_t*)smb_data); + + if (structure_size == SMB2_ERROR_RESPONSE_STRUC_SIZE and Smb2Error(smb_hdr)) + { + if ((alignedNtohl(&(smb_hdr->flags)) & SMB2_FLAGS_ASYNC_COMMAND) && + (alignedNtohl(&(smb_hdr->status)) == SMB2_STATUS_PENDING)) + return; + + DCE2_Smb2RequestTracker* rtr = ssd->findRtracker(mid); + if (rtr and rtr->get_file_id()) + { + DCE2_Smb2FileTracker* ftracker = ttr->findFtracker(rtr->get_file_id()); + if (ftracker) + { + ttr->removeFtracker(rtr->get_file_id()); + } + } + ssd->removeRtracker(mid); + dce2_smb_stats.v2_read_err_resp++; + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + DetectionEngine::get_current_packet(), "%s_RESP: error\n", + smb2_command_string[SMB2_COM_WRITE]); + } + // Using structure size to decide whether it is response or request + else if (structure_size == SMB2_READ_REQUEST_STRUC_SIZE) + { + SMB2_CHECK_HDR_ERROR( + smb_data, end, SMB2_READ_REQUEST_STRUC_SIZE - 1, + dce2_smb_stats.v2_read_req_hdr_err, SMB2_COM_READ) + DCE2_Smb2ReadRequest(ssd, (const Smb2ReadRequestHdr*)smb_data, end, str, ttr, mid); + } + else if (structure_size == SMB2_READ_RESPONSE_STRUC_SIZE) + { + SMB2_CHECK_HDR_ERROR( + smb_data, end, SMB2_READ_RESPONSE_STRUC_SIZE - 1, + dce2_smb_stats.v2_read_resp_hdr_err, SMB2_COM_READ) + + DCE2_Smb2ReadResponse(ssd, smb_hdr, (const Smb2ReadResponseHdr*)smb_data, end, ttr, mid); + } + else + { + dce2_smb_stats.v2_read_inv_str_sz++; + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + DetectionEngine::get_current_packet(),"%s: invalid struct size\n", + smb2_command_string[SMB2_COM_WRITE]); + } +} + +//------------------------------------------------------------------------- +// Process write request to create write trackers (to enforce credits limit) +// and to send file data for inspection. +//------------------------------------------------------------------------- +static void DCE2_Smb2WriteRequest(DCE2_Smb2SsnData* ssd, const Smb2Hdr* smb_hdr, + const Smb2WriteRequestHdr* smb_write_hdr, const uint8_t* end, DCE2_Smb2SessionTracker* str, + DCE2_Smb2TreeTracker* ttr, uint64_t mid) +{ + const uint8_t* file_data = (const uint8_t*)smb_write_hdr + SMB2_WRITE_REQUEST_STRUC_SIZE - 1; + int data_size = end - file_data; + uint64_t fileId_persistent, offset; + uint16_t data_offset; + + fileId_persistent = alignedNtohq((const uint64_t*)(&(smb_write_hdr->fileId_persistent))); + + if (ssd->max_outstanding_requests > ssd->getTotalRequestsPending()) + { + DCE2_Smb2RequestTracker* writetracker = ssd->findRtracker(mid); + if (!writetracker) + writetracker = new DCE2_Smb2RequestTracker(fileId_persistent); + writetracker->set_session_id(str->session_id); + writetracker->set_tree_id(ttr->get_tid()); + writetracker->set_file_id(fileId_persistent); + ssd->insertRtracker(mid, writetracker); + } + else + { + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_CRITICAL_LEVEL, + DetectionEngine::get_current_packet(), "%s_REQ: max req exceeded\n", + smb2_command_string[SMB2_COM_WRITE]); + dce_alert(GID_DCE2, DCE2_SMB_MAX_REQS_EXCEEDED, (dce2CommonStats*)&dce2_smb_stats, + ssd->sd); + return; + } + + data_offset = alignedNtohs((const uint16_t*)(&(smb_write_hdr->data_offset))); + if (data_offset + (const uint8_t*)smb_hdr > end) + { + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_CRITICAL_LEVEL, + DetectionEngine::get_current_packet(), "%s_REQ: bad offset\n", + smb2_command_string[SMB2_COM_WRITE]); + dce_alert(GID_DCE2, DCE2_SMB_BAD_OFF, (dce2CommonStats*)&dce2_smb_stats, ssd->sd); + } + + offset = alignedNtohq((const uint64_t*)(&(smb_write_hdr->offset))); + DCE2_Smb2FileTracker* ftracker = ttr->findFtracker(fileId_persistent); + + if (!ftracker and ttr->get_share_type() == SMB2_SHARE_TYPE_DISK) + { + ftracker = new DCE2_Smb2FileTracker(fileId_persistent, ttr, str, DetectionEngine::get_current_packet()->flow); + ttr->insertFtracker(fileId_persistent, ftracker); + } + if (!ftracker) + { + dce2_smb_stats.v2_read_rtrkr_misng++; + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + DetectionEngine::get_current_packet(), + "%s_REQ: ftracker missing 0x%" PRIx64 "\n", + smb2_command_string[SMB2_COM_WRITE], fileId_persistent); + return; + } + + if (!ftracker->ignore) // file tracker can not be nullptr here + { + if (ftracker->file_size and (offset > ftracker->file_size)) + { + dce_alert(GID_DCE2, DCE2_SMB_INVALID_FILE_OFFSET, (dce2CommonStats*)&dce2_smb_stats, + ssd->sd); + } + + ftracker->upload = true; + ssd->ftracker_local = std::unique_ptr(new DCE2_Smb2LocalFileTracker()); + ssd->ftracker_local->file_offset = offset; + ssd->ftracker_tcp = ftracker; + if (!ssd->ftracker_local->file_offset and SMB2_SHARE_TYPE_DISK == ttr->get_share_type()) + { + FileContext* file = DCE2_Smb2GetFileContext(ssd, ftracker, true); + if (file) + file->set_file_size(!ftracker->file_size ? UNKNOWN_FILE_SIZE : ftracker->file_size); + } + if (!DCE2_Smb2ProcessFileData(ssd, file_data, data_size)) + return; + + uint32_t total_data_length = alignedNtohl((const uint32_t*)&(smb_write_hdr->length)); + DCE2_Smb2UpdateMaxOffset(ftracker, offset + total_data_length); + if (total_data_length > (uint32_t)data_size) + { + ssd->ftracker_local->smb2_pdu_state = DCE2_SMB_PDU_STATE__RAW_DATA; + } + } +} + +//------------------------------------------------------------------------- +// Process write message +//------------------------------------------------------------------------- +void DCE2_Smb2Write(DCE2_Smb2SsnData* ssd, const Smb2Hdr* smb_hdr, + const uint8_t* smb_data, const uint8_t* end, DCE2_Smb2SessionTracker* str, + DCE2_Smb2TreeTracker* ttr, uint64_t mid) +{ + uint16_t structure_size = alignedNtohs((const uint16_t*)smb_data); + + if (structure_size == SMB2_ERROR_RESPONSE_STRUC_SIZE and Smb2Error(smb_hdr)) + { + if ((alignedNtohl(&(smb_hdr->flags)) & SMB2_FLAGS_ASYNC_COMMAND) && + (alignedNtohl(&(smb_hdr->status)) == SMB2_STATUS_PENDING)) + return; + + DCE2_Smb2RequestTracker* wtr = ssd->findRtracker(mid); + if (wtr and wtr->get_file_id()) + { + DCE2_Smb2FileTracker* ftracker = ttr->findFtracker(wtr->get_file_id()); + if (ftracker) + { + ttr->removeFtracker(wtr->get_file_id()); + } + } + ssd->removeRtracker(mid); + dce2_smb_stats.v2_wrt_err_resp++; + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + DetectionEngine::get_current_packet(), "%s_RESP: error\n", + smb2_command_string[SMB2_COM_WRITE]); + } + // Using structure size to decide whether it is response or request + else if (structure_size == SMB2_WRITE_REQUEST_STRUC_SIZE) + { + SMB2_CHECK_HDR_ERROR( + smb_data, end, SMB2_WRITE_REQUEST_STRUC_SIZE - 1, + dce2_smb_stats.v2_wrt_req_hdr_err, SMB2_COM_WRITE) + DCE2_Smb2WriteRequest(ssd, smb_hdr, (const Smb2WriteRequestHdr*)smb_data, end, str, ttr, + mid); + } + else if (structure_size == SMB2_WRITE_RESPONSE_STRUC_SIZE) + { + ssd->removeRtracker(mid); + } + else + { + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + DetectionEngine::get_current_packet(), "%s: invalid struct size\n", + smb2_command_string[SMB2_COM_WRITE]); + dce2_smb_stats.v2_wrt_inv_str_sz++; + } +} + +//------------------------------------------------------------------------- +// Process logoff to cleanup session tracker and their corresponding tree +// trackers and their corresponding file trackers +//------------------------------------------------------------------------- +void DCE2_Smb2Logoff(DCE2_Smb2SsnData* ssd, const uint8_t* smb_data, + const uint64_t sid) +{ + if (alignedNtohs((const uint16_t*)smb_data) == SMB2_LOGOFF_REQUEST_STRUC_SIZE) + { + auto str = DCE2_Smb2FindSidInSsd(ssd, sid); + if (str) + { + auto session_key = get_key(sid); + DCE2_SmbSessionCacheRemove(session_key); + } + } + else + { + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + DetectionEngine::get_current_packet(), "%s: invalid struct size\n", + smb2_command_string[SMB2_COM_LOGOFF]); + dce2_smb_stats.v2_logoff_inv_str_sz++; + } +} + +void DCE2_Smb2IoctlCommand(DCE2_Smb2SsnData* ssd, const Smb2Hdr* smb_hdr, + const uint8_t* smb_data, const uint8_t* end, DCE2_Smb2SessionTracker* str, + DCE2_Smb2TreeTracker* ttr, uint64_t mid) +{ + uint16_t structure_size = alignedNtohs((const uint16_t*)smb_data); + const uint8_t* file_data = (const uint8_t*)smb_data + structure_size - 1; + int data_size = end - file_data; + uint64_t fileId_persistent = 0; + Packet* p = DetectionEngine::get_current_packet(); + if (data_size > UINT16_MAX) + { + data_size = UINT16_MAX; + } + if (structure_size == SMB2_ERROR_RESPONSE_STRUC_SIZE and Smb2Error(smb_hdr)) + { + if ((alignedNtohl(&(smb_hdr->flags)) & SMB2_FLAGS_ASYNC_COMMAND) && + (alignedNtohl(&(smb_hdr->status)) == SMB2_STATUS_PENDING)) + return; + + dce2_smb_stats.v2_ioctl_err_resp++; + ssd->removeRtracker(mid); + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + p, "%s_RESP: error\n", + smb2_command_string[SMB2_COM_IOCTL]); + } + // Using structure size to decide whether it is response or request + else if (structure_size == SMB2_IOCTL_REQUEST_STRUC_SIZE) + { + const Smb2IoctlRequestHdr* ioctl_request = (const Smb2IoctlRequestHdr*)smb_data; + if ((ioctl_request->ctl_code != FSCTL_PIPE_PEEK) and (ioctl_request->ctl_code != + FSCTL_PIPE_WAIT) and (ioctl_request->ctl_code != FSCTL_PIPE_TRANSCEIVE)) + { + return; + } + fileId_persistent = ioctl_request->fileId_persistent; + if (ssd->max_outstanding_requests > ssd->getTotalRequestsPending()) + { + DCE2_Smb2RequestTracker* readtracker = ssd->findRtracker(mid); + if (!readtracker) + readtracker = new DCE2_Smb2RequestTracker(fileId_persistent, 0); + readtracker->set_session_id(str->session_id); + readtracker->set_tree_id(ttr->get_tid()); + readtracker->set_file_id(fileId_persistent); + ssd->insertRtracker(mid, readtracker); + } + else + { + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_CRITICAL_LEVEL, + DetectionEngine::get_current_packet(), "%s_REQ: max req exceeded\n", + smb2_command_string[SMB2_COM_READ]); + dce_alert(GID_DCE2, DCE2_SMB_MAX_REQS_EXCEEDED, (dce2CommonStats*)&dce2_smb_stats, + ssd->sd); + return; + } + } + else if (structure_size == SMB2_IOCTL_RESPONSE_STRUC_SIZE) + { + const Smb2IoctlResponseHdr* ioctl_response = (const Smb2IoctlResponseHdr*)smb_data; + if ((ioctl_response->ctl_code != FSCTL_PIPE_PEEK) and (ioctl_response->ctl_code != + FSCTL_PIPE_WAIT) and (ioctl_response->ctl_code != FSCTL_PIPE_TRANSCEIVE)) + { + return; + } + fileId_persistent = ioctl_response->fileId_persistent; + ssd->removeRtracker(mid); + } + else + { + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + p, "%s: invalid struct size\n", + smb2_command_string[SMB2_COM_IOCTL]); + dce2_smb_stats.v2_ioctl_inv_str_sz++; + return; + } + DCE2_Smb2FileTracker* ftracker = ttr->findFtracker(fileId_persistent); + if (ftracker and ftracker->co_tracker) + { + DCE2_CoProcess(&ssd->sd, ftracker->co_tracker, file_data, data_size); + } +} + diff --git a/src/service_inspectors/dce_rpc/dce_smb2_commands.h b/src/service_inspectors/dce_rpc/dce_smb2_commands.h new file mode 100644 index 000000000..1c054a62d --- /dev/null +++ b/src/service_inspectors/dce_rpc/dce_smb2_commands.h @@ -0,0 +1,74 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2016-2023 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_smb2_commands.h author Bhargava Jandhyala +// based on work by Todd Wease + +#ifndef DCE_SMB2_COMMANDS_H +#define DCE_SMB2_COMMANDS_H + +#include "dce_smb_module.h" +#include "dce_smb_utils.h" +#include "dce_smb2_utils.h" +#include "detection/detection_util.h" +#include "file_api/file_flows.h" +#include "file_api/file_service.h" + +void DCE2_Smb2Setup(DCE2_Smb2SsnData*, const Smb2Hdr*, + const uint64_t sid, const uint8_t* smb_data, const uint8_t* end); + +void DCE2_Smb2TreeConnect(DCE2_Smb2SsnData*, const Smb2Hdr*, + const uint8_t* smb_data, const uint8_t* end, DCE2_Smb2SessionTracker* str, uint32_t tid); + +void DCE2_Smb2TreeDisconnect(DCE2_Smb2SsnData*, const uint8_t* smb_data, + const uint8_t* end); + +void DCE2_Smb2Create(DCE2_Smb2SsnData*, const Smb2Hdr*, + const uint8_t* smb_data, const uint8_t* end, uint64_t mid, uint64_t sid, uint32_t tid); + +void DCE2_Smb2Read(DCE2_Smb2SsnData*, const Smb2Hdr*, + const uint8_t* smb_data, const uint8_t* end, DCE2_Smb2SessionTracker* str, + DCE2_Smb2TreeTracker* ttr, uint64_t mid); + +void DCE2_Smb2Write(DCE2_Smb2SsnData*, const Smb2Hdr*, + const uint8_t* smb_data, const uint8_t* end, DCE2_Smb2SessionTracker* str, + DCE2_Smb2TreeTracker* ttr, uint64_t mid); + +void DCE2_Smb2SetInfo(DCE2_Smb2SsnData*, const Smb2Hdr*, + const uint8_t* smb_data, const uint8_t* end, DCE2_Smb2TreeTracker* ttr); + +bool DCE2_Smb2ProcessFileData(DCE2_Smb2SsnData*, const uint8_t* file_data, + uint32_t data_size); + +void DCE2_Smb2CloseCmd(DCE2_Smb2SsnData*, const Smb2Hdr*, + const uint8_t* smb_data, const uint8_t* end, DCE2_Smb2TreeTracker* ttr, + DCE2_Smb2SessionTracker* str, uint64_t mid); + +void DCE2_Smb2Logoff(DCE2_Smb2SsnData*, const uint8_t* smb_data, + const uint64_t sid); + +DCE2_Smb2TreeTracker*find_tree_for_message(DCE2_Smb2SsnData*, const uint64_t); + +bool DCE2_IsSmb2DurableReconnect(const Smb2CreateRequestHdr* smb_create_hdr, const uint8_t* end, uint64_t& file_id); + +void DCE2_Smb2IoctlCommand(DCE2_Smb2SsnData* ssd, const Smb2Hdr* smb_hdr, + const uint8_t* smb_data, const uint8_t* end, + DCE2_Smb2SessionTracker* str, DCE2_Smb2TreeTracker* ttr, uint64_t mid); + +#endif + diff --git a/src/service_inspectors/dce_rpc/dce_smb2_file.cc b/src/service_inspectors/dce_rpc/dce_smb2_file.cc deleted file mode 100644 index cd50843d3..000000000 --- a/src/service_inspectors/dce_rpc/dce_smb2_file.cc +++ /dev/null @@ -1,376 +0,0 @@ -//-------------------------------------------------------------------------- -// Copyright (C) 2020-2023 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_smb2_file.cc author Dipta Pandit - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "dce_smb2_file.h" - -#include "file_api/file_flows.h" -#include "hash/hash_key_operations.h" - -#include "dce_co.h" -#include "dce_smb2.h" -#include "dce_smb2_session.h" -#include "dce_smb2_tree.h" -#include "dce_smb2_session_cache.h" -#include "flow/flow.h" -#include -#include "time/packet_time.h" - -#include -using namespace snort; - -#define UNKNOWN_FILE_SIZE (~0) - -void Dce2Smb2FileTracker::accept_raw_data_from(Dce2Smb2SessionData* flow, uint64_t offset, - Dce2Smb2FileTrackerPtr file_tracker) -{ - if (flow) - { - std::lock_guard guard(flow->session_data_mutex); - uint32_t current_flow_key = flow->get_flow_key(); - std::lock_guard guard1(flow_state_mutex); - tcp_flow_state& current_flow_state = flow_state[current_flow_key]; - if ( (current_flow_state.pdu_state == DCE2_SMB_PDU_STATE__RAW_DATA)and - (current_flow_state.file_offset == current_flow_state.max_offset)) - { - current_flow_state.file_offset = offset; - } - - current_flow_state.pdu_state = DCE2_SMB_PDU_STATE__RAW_DATA; - flow->set_tcp_file_tracker(file_tracker); - } -} - -void Dce2Smb2FileTracker::stop_accepting_raw_data_from(uint32_t current_flow_key) -{ - std::lock_guard guard(flow_state_mutex); - tcp_flow_state& current_flow_state = flow_state[current_flow_key]; - if (current_flow_state.file_offset == current_flow_state.max_offset) - current_flow_state.pdu_state = DCE2_SMB_PDU_STATE__COMMAND; -} - -inline void Dce2Smb2FileTracker::file_detect() -{ - DetectionEngine::detect(DetectionEngine::get_current_packet()); - dce2_detected = 1; -} - -std::pair Dce2Smb2FileTracker::update_processing_flow( - Dce2Smb2SessionData* current_flow,Dce2Smb2SessionTrackerPtr session_tracker) -{ - bool switched = false; - Dce2Smb2SessionData* processing_flow = nullptr; - std::lock_guard guard1(session_tracker->attached_flows_mutex); - auto it_flow = session_tracker->attached_flows.find(file_flow_key); - if (it_flow != session_tracker->attached_flows.end()) - processing_flow = (it_flow != session_tracker->attached_flows.end()) ? it_flow->second : - nullptr; - if (processing_flow) - { - if (session_tracker->vlan_id != processing_flow->vlan_id) - processing_flow = nullptr; - else - { - processing_flow->session_data_mutex.lock(); - if (processing_flow->get_tcp_flow()->session_state & STREAM_STATE_CLOSED or - processing_flow->get_tcp_flow()->session_state & STREAM_STATE_RELEASING) - { - processing_flow->session_data_mutex.unlock(); - return std::make_pair(switched, nullptr); - } - } - } - if (!processing_flow) - { - switched = true; - if (current_flow) - processing_flow = current_flow; - else - { - Flow* flow = DetectionEngine::get_current_packet()->flow; - Dce2SmbFlowData* current_flow_data = (Dce2SmbFlowData*)(flow->get_flow_data( - Dce2SmbFlowData::inspector_id)); - if (current_flow_data) - processing_flow = (Dce2Smb2SessionData*)current_flow_data->get_smb_session_data(); - } - if (processing_flow) - { - file_flow_key = processing_flow->get_flow_key(); - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, GET_CURRENT_PACKET, - "updating the processing flow key to %u\n", file_flow_key); - } - } - if (processing_flow and processing_flow->get_tcp_flow()) - processing_flow->get_tcp_flow()->last_data_seen = packet_time(); - - if (processing_flow and processing_flow->get_tcp_flow()) - { - processing_flow->get_tcp_flow()->last_data_seen = packet_time(); - } - if (processing_flow) - processing_flow->session_data_mutex.unlock(); - return std::make_pair(switched, processing_flow); -} - -void Dce2Smb2FileTracker::set_info(char* file_name_v, uint16_t name_len_v, uint64_t size_v) -{ - if (file_name_v and name_len_v and !file_name) - { - file_name = (char*)snort_alloc(name_len_v + 1); - memcpy(file_name, file_name_v, name_len_v); - file_name_len = name_len_v; - file_name_hash = str_to_hash((uint8_t*)file_name, file_name_len); - } - file_size = size_v; - Packet* p = DetectionEngine::get_current_packet(); - Flow* flow = p->flow; - { - std::lock_guard guard(process_file_mutex); - FileContext* file = get_smb_file_context(flow, file_name_hash, file_id, true); - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, GET_CURRENT_PACKET, - "set file info: file size %" - PRIu64 " fid %" PRIu64 " file_name_hash %" PRIu64 " file context " - "%sfound\n", size_v, file_id, file_name_hash, (file ? "" : "not ")); - if (file) - { - ignore = false; - if (file->verdict == FILE_VERDICT_UNKNOWN) - { - if ((file_name_v and name_len_v)) - file->set_file_name(file_name, file_name_len); - file->set_file_size(size_v ? size_v : UNKNOWN_FILE_SIZE); - } - } - } -} - -bool Dce2Smb2FileTracker::close(const uint32_t current_flow_key) -{ - flow_state_mutex.lock(); - uint64_t file_offset = flow_state[current_flow_key].file_offset; - flow_state_mutex.unlock(); - if (!ignore and !file_size and file_offset) - { - file_size = file_offset; - std::lock_guard guard1( - get_parent()->get_parent()->attached_flows_mutex); - Dce2Smb2SessionData* current_flow; - Packet* p = DetectionEngine::get_current_packet(); - Flow* flow = p->flow; - Dce2SmbFlowData* current_flow_data = (Dce2SmbFlowData*)(flow->get_flow_data( - Dce2SmbFlowData::inspector_id)); - if (!current_flow_data) - return false; - current_flow = (Dce2Smb2SessionData*)current_flow_data->get_smb_session_data(); - Dce2Smb2SessionTracker* sess = parent_tree->get_parent(); - Dce2Smb2SessionTrackerPtr ses_ptr = smb2_session_cache.find_id(sess->get_key()); - Dce2Smb2SessionData* processing_flow = update_processing_flow(current_flow, - ses_ptr).second; - if (!processing_flow) - return false; - flow = processing_flow->get_tcp_flow(); - { - std::lock_guard guard(process_file_mutex); - FileContext* file = get_smb_file_context(flow, file_name_hash, file_id, false); - if (file) - file->set_file_size(file_size); - } - return (!process_data(current_flow_key, nullptr, 0, ses_ptr)); - } - return true; -} - -bool Dce2Smb2FileTracker::process_data(const uint32_t current_flow_key, const uint8_t* file_data, - uint32_t data_size, const uint64_t offset, uint64_t max_offset) -{ - flow_state_mutex.lock(); - tcp_flow_state& current_flow_state = flow_state[current_flow_key]; - current_flow_state.file_offset = offset; - current_flow_state.max_offset = offset + max_offset; - flow_state_mutex.unlock(); - Dce2Smb2SessionTrackerPtr ses_ptr = nullptr; - Dce2Smb2SessionTracker* sess = parent_tree->get_parent(); - if (!sess) - return false; - ses_ptr = smb2_session_cache.find_id(sess->get_key()); - if (ses_ptr.use_count() < 2) - return false; - if (parent_tree->get_share_type() != SMB2_SHARE_TYPE_DISK) - { - Dce2Smb2SessionData* current_flow = nullptr; - if (ses_ptr.use_count() < 2) - return false; - Packet* p = DetectionEngine::get_current_packet(); - Flow* flow = p->flow; - Dce2SmbFlowData* current_flow_data = (Dce2SmbFlowData*)(flow->get_flow_data( - Dce2SmbFlowData::inspector_id)); - if (!current_flow_data) - return false; - current_flow = (Dce2Smb2SessionData*)current_flow_data->get_smb_session_data(); - if (!current_flow) - return false; - if (data_size > UINT16_MAX) - { - data_size = UINT16_MAX; - } - current_flow->session_data_mutex.lock(); - if (current_flow->get_tcp_flow()) - current_flow->get_tcp_flow()->last_data_seen = packet_time(); - sess->co_tracker_mutex.lock(); - if (parent_tree->get_cotracker()) - { - DCE2_CoProcess(current_flow->get_dce2_session_data(), parent_tree->get_cotracker(), - file_data, data_size); - } - sess->co_tracker_mutex.unlock(); - current_flow->session_data_mutex.unlock(); - return true; - } - return process_data(current_flow_key, file_data, data_size, ses_ptr); -} - -bool Dce2Smb2FileTracker::process_data(const uint32_t current_flow_key, const uint8_t* file_data, - uint32_t data_size,Dce2Smb2SessionTrackerPtr session_tracker) -{ - if (!session_tracker or session_tracker.use_count() < 2) - return false; - std::lock_guard guard1(session_tracker->attached_flows_mutex); - Dce2Smb2SessionData* current_flow; - Packet* p = DetectionEngine::get_current_packet(); - Flow* flow = p->flow; - Dce2SmbFlowData* current_flow_data = (Dce2SmbFlowData*)(flow->get_flow_data( - Dce2SmbFlowData::inspector_id)); - if (!current_flow_data) - return false; - current_flow = (Dce2Smb2SessionData*)current_flow_data->get_smb_session_data(); - int64_t file_detection_depth = current_flow->get_smb_file_depth(); - int64_t detection_size = 0; - - flow_state_mutex.lock(); - uint64_t file_offset = flow_state[current_flow_key].file_offset; - flow_state_mutex.unlock(); - - if (file_detection_depth == 0) - detection_size = data_size; - else if ( file_offset < (uint64_t)file_detection_depth) - { - if ( file_detection_depth - file_offset < data_size ) - detection_size = file_detection_depth - file_offset; - else - detection_size = data_size; - } - - if (detection_size) - { - set_file_data(file_data, (detection_size > UINT16_MAX) ? - UINT16_MAX : (uint16_t)detection_size); - file_detect(); - } - - if (ignore) - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, p, - "file name not set , ignored\n"); - return true; - } - - if (file_size and file_offset > file_size) - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, p, - "file_process: bad offset\n"); - dce_alert(GID_DCE2, DCE2_SMB_INVALID_FILE_OFFSET, (dce2CommonStats*) - &dce2_smb_stats, *(current_flow->get_dce2_session_data())); - } - - if (session_tracker.use_count() < 2) - return false; - auto updated_flow = update_processing_flow(current_flow, session_tracker); - Dce2Smb2SessionData* processing_flow = updated_flow.second; - if (!processing_flow) - return false; - if ( !processing_flow->get_tcp_flow()) - return false; - processing_flow->session_data_mutex.lock(); - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, p, - "file_process fid %" PRIu64 " data_size %" PRIu32 " offset %" PRIu64 "\n", file_id, - data_size, file_offset); - { - if (processing_flow->get_tcp_flow()->session_state & STREAM_STATE_CLOSED or - processing_flow->get_tcp_flow()->session_state & STREAM_STATE_RELEASING) - { - processing_flow->session_data_mutex.unlock(); - return true; - } - FileFlows* file_flows = FileFlows::get_file_flows(processing_flow->get_tcp_flow()); - - if (!file_flows) - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_CRITICAL_LEVEL, p, - "file_flows not found\n"); - processing_flow->session_data_mutex.unlock(); - return true; - } - - { - std::lock_guard guard(file_flows->file_flow_context_mutex); - - if (updated_flow.first) - { - // update the new file context in case of flow switch - bool is_new_context = false; - FileContext* file = file_flows->get_file_context(file_name_hash, true, is_new_context, file_id); - file->set_file_name(file_name, file_name_len); - file->set_file_size(file_size.load() ? file_size.load() : UNKNOWN_FILE_SIZE); - } - FileFlows::get_file_flows(p->flow); - bool continue_processing = file_flows->file_process(p, file_name_hash, file_data, - data_size, - file_offset, direction, file_id); - - if (!continue_processing) - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, p, - "file_process completed\n"); - processing_flow->session_data_mutex.unlock(); - return false; - } - } - } - - file_offset += data_size; - flow_state_mutex.lock(); - flow_state[current_flow_key].file_offset = file_offset; - flow_state_mutex.unlock(); - processing_flow->session_data_mutex.unlock(); - return true; -} - -Dce2Smb2FileTracker::~Dce2Smb2FileTracker(void) -{ - if (file_name) - snort_free((void*)file_name); - - file_name = nullptr; - parent_tree.reset(); -} - diff --git a/src/service_inspectors/dce_rpc/dce_smb2_file.h b/src/service_inspectors/dce_rpc/dce_smb2_file.h deleted file mode 100644 index 8159110b8..000000000 --- a/src/service_inspectors/dce_rpc/dce_smb2_file.h +++ /dev/null @@ -1,116 +0,0 @@ -//-------------------------------------------------------------------------- -// Copyright (C) 2020-2023 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_smb2_file.h author Dipta Pandit - -#ifndef DCE_SMB2_FILE_H -#define DCE_SMB2_FILE_H - -// This provides file tracker for SMBv2 - -#include "dce_smb2.h" -#include - -class Dce2Smb2TreeTracker; -using Dce2Smb2TreeTrackerPtr = std::shared_ptr; - -typedef struct _tcp_flow_state -{ - Dce2SmbPduState pdu_state; - uint64_t file_offset; - uint64_t max_offset; -} tcp_flow_state; - -class Dce2Smb2FileTracker -{ -public: - - Dce2Smb2FileTracker() = delete; - Dce2Smb2FileTracker(const Dce2Smb2FileTracker& arg) = delete; - Dce2Smb2FileTracker& operator=(const Dce2Smb2FileTracker& arg) = delete; - - Dce2Smb2FileTracker(uint64_t file_idv, const uint32_t flow_key, Dce2Smb2TreeTrackerPtr p_tree, - uint64_t sid) : - ignore(true), file_name_len(0), file_flow_key(flow_key), - file_id(file_idv), file_size(0), file_name_hash(0), file_name(nullptr), - direction(FILE_DOWNLOAD), parent_tree(p_tree), session_id(sid) - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, GET_CURRENT_PACKET, - "file tracker %" PRIu64 " created\n", file_id); - } - - ~Dce2Smb2FileTracker(); - bool process_data(const uint32_t, const uint8_t*, uint32_t, const uint64_t, uint64_t); - bool process_data(const uint32_t, const uint8_t*, uint32_t, Dce2Smb2SessionTrackerPtr); - bool close(const uint32_t); - void set_info(char*, uint16_t, uint64_t); - void accept_raw_data_from(Dce2Smb2SessionData*, uint64_t, Dce2Smb2FileTrackerPtr); - bool accepting_raw_data_from(uint32_t current_flow_key) - { - std::lock_guard guard(flow_state_mutex); - return (flow_state[current_flow_key].pdu_state == DCE2_SMB_PDU_STATE__RAW_DATA); - } - - void stop_accepting_raw_data_from(uint32_t); - - void set_direction(FileDirection dir) { direction = dir; } - Dce2Smb2TreeTrackerPtr get_parent() { return parent_tree; } - void set_parent(Dce2Smb2TreeTrackerPtr pt) { parent_tree = pt; } - uint64_t get_file_id() { return file_id; } - uint64_t get_file_name_hash() { return file_name_hash; } - uint64_t get_session_id() { return session_id; } - std::unordered_map > get_flow_state_map() - { - return flow_state; - } - - uint32_t get_flow_key() - { - return file_flow_key; - } - - void set_flow_key(uint32_t key) - { - file_flow_key = key; - } - -private: - void file_detect(); - std::pair update_processing_flow(Dce2Smb2SessionData* = nullptr, - Dce2Smb2SessionTrackerPtr session_tracker = nullptr); - bool ignore; - uint16_t file_name_len; - uint32_t file_flow_key; - uint64_t file_id; - std::atomic file_size; - uint64_t file_name_hash; - char* file_name; - FileDirection direction; - Dce2Smb2TreeTrackerPtr parent_tree; - std::unordered_map > flow_state; - uint64_t session_id; - std::mutex process_file_mutex; - std::mutex flow_state_mutex; -}; - -using Dce2Smb2FileTrackerPtr = std::shared_ptr; -using Dce2Smb2FileTrackerMap = - std::unordered_map >; - -#endif - diff --git a/src/service_inspectors/dce_rpc/dce_smb2_request.h b/src/service_inspectors/dce_rpc/dce_smb2_request.h deleted file mode 100644 index 1454baa40..000000000 --- a/src/service_inspectors/dce_rpc/dce_smb2_request.h +++ /dev/null @@ -1,74 +0,0 @@ -//-------------------------------------------------------------------------- -// Copyright (C) 2020-2023 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_smb2_request.h author Bhargava Jandhyala - -#ifndef DCE_SMB2_REQUEST_H -#define DCE_SMB2_REQUEST_H - -// This provides request trackers for SMBv2. -// Request trackers are used to track CREATE, READ and WRITE requests - -#include "dce_smb2.h" - -class Dce2Smb2RequestTracker -{ -public: - - Dce2Smb2RequestTracker() = delete; - Dce2Smb2RequestTracker(const Dce2Smb2RequestTracker& arg) = delete; - Dce2Smb2RequestTracker& operator=(const Dce2Smb2RequestTracker& arg) = delete; - - Dce2Smb2RequestTracker(uint64_t file_id_v, uint64_t offset_v = 0) - : fname(nullptr), fname_len(0), file_id(file_id_v), offset(offset_v) - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, GET_CURRENT_PACKET, - "request tracker created\n"); - } - - Dce2Smb2RequestTracker(char* fname_v, uint16_t fname_len_v) - : fname(fname_v), fname_len(fname_len_v), file_id(0), offset(0) - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, GET_CURRENT_PACKET, - "request tracker created\n"); - } - - ~Dce2Smb2RequestTracker() - { - if (fname) - snort_free(fname); - } - - uint64_t get_offset() { return offset; } - uint64_t get_file_id() { return file_id; } - char* get_file_name() { return fname; } - uint16_t get_file_name_size() { return fname_len; } - -private: - char* fname; - uint16_t fname_len; - uint64_t file_id; - uint64_t offset; -}; - -using Dce2Smb2RequestTrackerPtr = std::shared_ptr; -using Dce2Smb2RequestTrackerMap = - std::unordered_map; - -#endif - diff --git a/src/service_inspectors/dce_rpc/dce_smb2_session.cc b/src/service_inspectors/dce_rpc/dce_smb2_session.cc deleted file mode 100644 index 5bd0dd872..000000000 --- a/src/service_inspectors/dce_rpc/dce_smb2_session.cc +++ /dev/null @@ -1,253 +0,0 @@ -//-------------------------------------------------------------------------- -// Copyright (C) 2020-2023 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_smb2_session.cc author Dipta Pandit - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "dce_smb2_session.h" - -#include "dce_smb2_session_cache.h" - -#include "file_api/file_flows.h" - -#include - -uint32_t Smb2Tid(const Smb2Hdr* hdr) -{ - return snort::alignedNtohl(&(((const Smb2SyncHdr*)hdr)->tree_id)); -} - -Dce2Smb2SessionData* Dce2Smb2SessionTracker::get_flow(uint32_t flow_key) -{ - std::lock_guard guard(attached_flows_mutex); - auto it_flow = attached_flows.find(flow_key); - return (it_flow != attached_flows.end()) ? it_flow->second : nullptr; -} - -Dce2Smb2TreeTrackerPtr Dce2Smb2SessionTracker::find_tree_for_message( - const uint64_t message_id, const uint32_t flow_key) -{ - std::lock_guard guard(connected_trees_mutex); - for (auto it_tree : connected_trees) - { - Dce2Smb2RequestTrackerPtr request = it_tree.second->find_request(message_id, flow_key); - if (request) - return it_tree.second; - } - return nullptr; -} - -Dce2Smb2TreeTrackerPtr Dce2Smb2SessionTracker::find_tree_for_tree_id( - const uint32_t tree_id) -{ - std::lock_guard guard(connected_trees_mutex); - auto it_tree = connected_trees.find(tree_id); - if (it_tree != connected_trees.end()) - return it_tree->second; - return nullptr; -} - -uint32_t Dce2Smb2SessionTracker::fill_map(const uint64_t msg_id, const uint8_t command_type, const - uint32_t current_flow_key) -{ - std::lock_guard guard(mid_mutex); - auto it = mid_map.find(current_flow_key); - msgid_state* mid_ptr; - if (it == mid_map.end()) - { - mid_ptr = new msgid_state; - mid_map.insert(std::make_pair(current_flow_key, mid_ptr)); - } - else - mid_ptr = it->second; - if (command_type == SMB2_CMD_TYPE_REQUEST) - { - if (msg_id > mid_ptr->max_req_msg_id) - { - const int size = msg_id-(mid_ptr->max_req_msg_id)-1; - std::vector v(size); - std::iota(v.begin(), v.end(), mid_ptr->max_req_msg_id+1); - mid_ptr->missing_req_msg_ids.insert(v.begin (), v.end ()); - mid_ptr->max_req_msg_id = msg_id; - } - else - { - if (mid_ptr->missing_req_msg_ids.find(msg_id) == mid_ptr->missing_req_msg_ids.end()) - { - return 1; - } - else - { - mid_ptr->missing_req_msg_ids.erase(msg_id); - } - } - } - if (command_type == SMB2_CMD_TYPE_RESPONSE) - { - if (msg_id > mid_ptr->max_resp_msg_id) - { - const int size = msg_id-(mid_ptr->max_resp_msg_id)-1; - std::vector v(size); - std::iota(v.begin(), v.end(), mid_ptr->max_resp_msg_id+1); - mid_ptr->missing_resp_msg_ids.insert(v.begin (), v.end ()); - mid_ptr->max_resp_msg_id = msg_id; - } - else - { - if (mid_ptr->missing_resp_msg_ids.find(msg_id) == mid_ptr->missing_resp_msg_ids.end()) - { - return 1; - } - else - { - mid_ptr->missing_resp_msg_ids.erase(msg_id); - } - } - } - return 0; -} - -void Dce2Smb2SessionTracker::process(const uint16_t command, uint8_t command_type, - const Smb2Hdr* smb_header, const uint8_t* end, const uint32_t current_flow_key) -{ - Dce2Smb2TreeTrackerPtr tree; - uint32_t tree_id = Smb2Tid(smb_header); - - if (tree_id) - { - connected_trees_mutex.lock(); - auto it_tree = connected_trees.find(tree_id); - if (it_tree != connected_trees.end()) - tree = it_tree->second; - connected_trees_mutex.unlock(); - } - else - { - //async response case - tree = find_tree_for_message(Smb2Mid(smb_header), current_flow_key); - } - - if (fill_map(Smb2Mid(smb_header), command_type, current_flow_key)) - { - dce2_smb_stats.ignore_dup_sessions++; - return; - } - - switch (command) - { - case SMB2_COM_TREE_CONNECT: - { - uint8_t share_type = ((const Smb2TreeConnectResponseHdr*) - ((const uint8_t*)smb_header + SMB2_HEADER_LENGTH))->share_type; - connect_tree(tree_id, share_type); - } - break; - case SMB2_COM_TREE_DISCONNECT: - { - if (!tree) - dce2_smb_stats.v2_tree_discn_ignored++; - } - break; - - //for all other cases, tree tracker should handle the command - case SMB2_COM_CREATE: - if (!tree and SMB2_CMD_TYPE_REQUEST == command_type) - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, - TRACE_INFO_LEVEL, GET_CURRENT_PACKET, - "%s_REQ: mid-stream session detected\n", - smb2_command_string[command]); - tree = connect_tree(tree_id); - if (!tree) - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, - TRACE_INFO_LEVEL, GET_CURRENT_PACKET, - "%s_REQ: insert tree tracker failed\n", - smb2_command_string[command]); - } - } - // fallthrough - default: - if (tree) - tree->process(command, command_type, smb_header, end, current_flow_key); - else - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, - TRACE_ERROR_LEVEL, GET_CURRENT_PACKET, - "%s: tree tracker missing\n", smb2_command_string[command]); - dce2_smb_stats.v2_tree_ignored++; - } - break; - } -} - -Dce2Smb2TreeTrackerPtr Dce2Smb2SessionTracker::connect_tree(const uint32_t tree_id, - const uint8_t share_type) -{ - Dce2Smb2TreeTrackerPtr tree; - connected_trees_mutex.lock(); - auto it_tree = connected_trees.find(tree_id); - if (it_tree != connected_trees.end()) - tree = it_tree->second; - connected_trees_mutex.unlock(); - if (!tree) - { - tree = std::make_shared(tree_id, this, share_type); - connected_trees_mutex.lock(); - connected_trees.insert(std::make_pair(tree_id, tree)); - connected_trees_mutex.unlock(); - increase_size(sizeof(Dce2Smb2TreeTracker)); - } - return tree; -} - -void Dce2Smb2SessionTracker::increase_size(const size_t size) -{ - smb2_session_cache.increase_size(size); -} - -void Dce2Smb2SessionTracker::decrease_size(const size_t size) -{ - smb2_session_cache.decrease_size(size); -} - -// Session Tracker is created and destroyed only from session cache -Dce2Smb2SessionTracker::~Dce2Smb2SessionTracker(void) -{ - if (!(fcfs_mutex.try_lock())) - return; - - if (do_not_delete ) - { - // Dont prune the session in LRU Cache - smb2_session_cache.find_id(get_key()); - fcfs_mutex.unlock(); - return; - } - disconnect_tree(); - free_map(); - - do_not_delete = false; - fcfs_mutex.unlock(); - std::lock_guard guard(attached_flows_mutex); - attached_flows.clear(); -} - diff --git a/src/service_inspectors/dce_rpc/dce_smb2_session.h b/src/service_inspectors/dce_rpc/dce_smb2_session.h deleted file mode 100644 index f8bc618cf..000000000 --- a/src/service_inspectors/dce_rpc/dce_smb2_session.h +++ /dev/null @@ -1,175 +0,0 @@ -//-------------------------------------------------------------------------- -// Copyright (C) 2020-2023 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_smb2_session.h author Dipta Pandit - -#ifndef DCE_SMB2_SESSION_H -#define DCE_SMB2_SESSION_H - -// This provides session tracker for SMBv2 - -#include "dce_smb2.h" -#include "dce_smb2_tree.h" - -uint32_t Smb2Tid(const Smb2Hdr* hdr); - -typedef struct _msgid_state -{ - uint64_t max_req_msg_id = 0; - uint64_t max_resp_msg_id = 0; - std::unordered_set missing_req_msg_ids; - std::unordered_set missing_resp_msg_ids; -} msgid_state; - -class Dce2Smb2SessionTracker -{ -public: - Dce2Smb2SessionTracker(const Smb2SessionKey& key) - { - session_id = key.sid; - session_key = key; - reload_prune = false; - do_not_delete = false; - file_context_cleaned = false; - command_prev = SMB2_COM_MAX; - encryption_flag = false; - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, GET_CURRENT_PACKET, - "session tracker %" PRIu64 "created\n", session_id); - } - - ~Dce2Smb2SessionTracker(); - Dce2Smb2TreeTrackerPtr connect_tree(const uint32_t, - uint8_t=SMB2_SHARE_TYPE_DISK); - - void disconnect_tree() - { - std::lock_guard guard(connected_trees_mutex); - auto it_tree = connected_trees.begin(); - while (it_tree != connected_trees.end()) - { - auto next_it_tree = std::next(it_tree); - it_tree->second->close_all_files(); - connected_trees.erase(it_tree->second->get_tree_id()); - decrease_size(sizeof(Dce2Smb2TreeTracker)); - it_tree = next_it_tree; - } - } - - void attach_flow(uint32_t flow_key, Dce2Smb2SessionData* ssd) - { - std::lock_guard guard(attached_flows_mutex); - if (attached_flows.find(flow_key) == attached_flows.end()) - { - attached_flows.insert(std::make_pair(flow_key, ssd)); - } - } - - bool detach_flow(uint32_t flow_key) - { - std::lock_guard guard(attached_flows_mutex); - if (attached_flows.size()<2) - attached_flows.clear(); - else - { - attached_flows.erase(flow_key); - attached_flows[flow_key] = nullptr; - } - free_one_flow_map(flow_key); - return (0 == attached_flows.size()); - } - - void free_one_flow_map(uint32_t flow_key) - { - std::lock_guard guard(mid_mutex); - auto it = mid_map.find(flow_key); - if (it != mid_map.end()) - { - delete it->second; - mid_map.erase(it); - } - } - - void free_map() - { - std::lock_guard guard(mid_mutex); - std::vector mid_ptrs; - auto it_map = mid_map.begin(); - while (it_map != mid_map.end()) - { - mid_ptrs.push_back(it_map->second); - it_map = mid_map.erase(it_map); - } - for (msgid_state* it_msg_id : mid_ptrs) - { - delete it_msg_id; - } - } - - Smb2SessionKey get_key() { return session_key; } - Dce2Smb2SessionData* get_flow(uint32_t); - void process(const uint16_t, uint8_t, const Smb2Hdr*, const uint8_t*, const uint32_t); - void increase_size(const size_t size); - void decrease_size(const size_t size); - void set_reload_prune(bool flag) { reload_prune = flag; } - uint64_t get_session_id() { return session_id; } - void set_do_not_delete(bool flag) { do_not_delete = flag; } - bool get_do_not_delete() { return do_not_delete; } - void set_file_context_cleaned(bool flag) { file_context_cleaned = flag; } - bool get_file_context_cleaned() { return file_context_cleaned; } - void set_prev_comand(uint16_t cmd) { command_prev = cmd; } - uint16_t get_prev_command() { return command_prev; } - std::mutex co_tracker_mutex; - void set_encryption_flag(bool flag) - { - encryption_flag = flag; - if (flag) - dce2_smb_stats.total_encrypted_sessions++; - } - - bool get_encryption_flag() { return encryption_flag; } - Dce2Smb2TreeTrackerPtr find_tree_for_tree_id(const uint32_t); - uint32_t fill_map(const uint64_t msg_id, const uint8_t command_type, const uint32_t - current_flow_key); - std::recursive_mutex attached_flows_mutex; - uint16_t vlan_id = 0; - Dce2Smb2SessionDataMap attached_flows; - -private: - // do_not_delete is to make sure when we are in processing we should not delete the context - // which is being processed - bool do_not_delete; - bool file_context_cleaned; - Dce2Smb2TreeTrackerPtr find_tree_for_message(const uint64_t, const uint32_t); - uint64_t session_id; - //to keep the tab of previous command - uint16_t command_prev; - Smb2SessionKey session_key; - Dce2Smb2TreeTrackerMap connected_trees; - std::atomic reload_prune; - std::atomic encryption_flag; - std::mutex connected_trees_mutex; - - // fcfs_mutex is to make sure the mutex is taken at first come first basis if code - // is being hit by two different paths - std::mutex fcfs_mutex; - std::mutex mid_mutex; - std::unordered_map > mid_map; -}; - -#endif - diff --git a/src/service_inspectors/dce_rpc/dce_smb2_session_cache.h b/src/service_inspectors/dce_rpc/dce_smb2_session_cache.h deleted file mode 100644 index 771382645..000000000 --- a/src/service_inspectors/dce_rpc/dce_smb2_session_cache.h +++ /dev/null @@ -1,145 +0,0 @@ -//-------------------------------------------------------------------------- -// Copyright (C) 2020-2023 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_smb2_session_cache.h author Bhargava Jandhyala - -#ifndef DCE_SMB2_SESSION_CACHE_H -#define DCE_SMB2_SESSION_CACHE_H - -// This provides a wrapper over LRU cache shared for SMBv2 Session trackers - -#include "hash/lru_cache_shared.h" - -#include "dce_smb2_session.h" -#define SMB_AVG_FILES_PER_SESSION 5 - -template, -typename Purgatory = std::vector > > -class Dce2Smb2SharedCache : public LruCacheShared -{ -public: - Dce2Smb2SharedCache() = delete; - Dce2Smb2SharedCache(const Dce2Smb2SharedCache& arg) = delete; - Dce2Smb2SharedCache& operator=(const Dce2Smb2SharedCache& arg) = delete; - Dce2Smb2SharedCache(const size_t initial_size) : - LruCacheShared(initial_size) { } - - using Data = std::shared_ptr; - - Data find_id(const Key& key) - { - Data session = this->find(key); - return session; - } - - Data find_session(const Key& key) - { - Data session = this->find(key); - return session; - } - - Data find_else_create_session(const Key& key, Dce2Smb2SessionData* ssd) - { - Data new_session = Data(new Value(key)); - Data session = this->find_else_insert(key, new_session, nullptr,false); - if (new_session == session) - { - session->attach_flow(ssd->get_flow_key(), ssd); - return session; - } - return nullptr; - } - - size_t mem_size() override - { - return current_size; - } - - void increase_size(size_t size) - { - current_size += size; - } - - void decrease_size(size_t size) - { - assert(current_size >= size); - current_size -= size; - } - - // Since decrease_size() does not account for associated objects in smb2_session_cache, - // we will over-prune when we reach the new_size here, as more space will be freed up - // when actual objects are destroyed. We might need to do gradual pruning like how - // host cache does. For now over pruning is ok. - void reload_prune(size_t new_size) - { - Purgatory data; - std::lock_guard cache_lock(cache_mutex); - max_size = new_size; - while (current_size > max_size && !list.empty()) - { - LruListIter list_iter = --list.end(); - data.emplace_back(list_iter->second); // increase reference count - // This instructs the session_tracker to take a lock before detaching - // from ssd, when it is getting destroyed. - if (!list_iter->second->get_do_not_delete()) - { - list_iter->second->set_reload_prune(true); - decrease_size(list_iter->second.get()); - map.erase(list_iter->first); - list.erase(list_iter); - ++stats.reload_prunes; - } - else - { - // Move entry to front of LruList - list.splice(list.begin(), list, list_iter); - } - } - } - -private: - using LruBase = LruCacheShared; - using LruBase::cache_mutex; - using LruBase::current_size; - using LruBase::list; - using LruBase::map; - using LruBase::max_size; - using LruBase::stats; - using LruListIter = typename LruBase::LruListIter; - void increase_size(Value* value_ptr=nullptr) override - { - if (value_ptr) current_size += sizeof(*value_ptr); - } - - void decrease_size(Value* value_ptr=nullptr) override - { - if (value_ptr) - { - assert(current_size >= sizeof(*value_ptr) ); - current_size -= sizeof(*value_ptr); - } - } -}; - -using Dce2Smb2SessionCache = - Dce2Smb2SharedCache; - -extern Dce2Smb2SessionCache smb2_session_cache; - -#endif - diff --git a/src/service_inspectors/dce_rpc/dce_smb2_tree.cc b/src/service_inspectors/dce_rpc/dce_smb2_tree.cc deleted file mode 100644 index 78847027f..000000000 --- a/src/service_inspectors/dce_rpc/dce_smb2_tree.cc +++ /dev/null @@ -1,647 +0,0 @@ -//-------------------------------------------------------------------------- -// Copyright (C) 2020-2023 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_smb2_tree.cc author Dipta Pandit - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "dce_smb2_tree.h" - -#include "dce_smb2_session.h" -#include - -using namespace snort; - -#define SMB2_CREATE_DURABLE_RECONNECT "DHnC" -#define SMB2_CREATE_DURABLE_RECONNECT_V2 "DH2C" - -uint64_t Smb2Mid(const Smb2Hdr* hdr) -{ - return alignedNtohq(&(hdr->message_id)); -} - -Dce2Smb2FileTrackerPtr Dce2Smb2TreeTracker::open_file(const uint64_t file_id, - const uint32_t current_flow_key) -{ - Dce2Smb2TreeTrackerPtr tree_ptr = parent_session->find_tree_for_tree_id(tree_id); - if (!tree_ptr) - return nullptr; - std::shared_ptr ftracker = std::make_shared ( - file_id, current_flow_key, tree_ptr, this->get_parent()->get_session_id()); - tree_tracker_mutex.lock(); - opened_files.insert(std::make_pair(file_id, ftracker)); - tree_tracker_mutex.unlock(); - parent_session->increase_size(sizeof(Dce2Smb2FileTracker)); - return ftracker; -} - -Dce2Smb2FileTrackerPtr Dce2Smb2TreeTracker::find_file(uint64_t file_id) -{ - std::lock_guard guard(tree_tracker_mutex); - auto it_file = opened_files.find(file_id); - if (it_file != opened_files.end()) - return it_file->second; - return nullptr; -} - -void Dce2Smb2TreeTracker::close_file(uint64_t file_id, bool destroy) -{ - tree_tracker_mutex.lock(); - auto it_file = opened_files.find(file_id); - if (it_file != opened_files.end()) - { - Dce2Smb2FileTrackerPtr file = it_file->second; - it_file->second->get_parent().reset(); - if (opened_files.erase(file_id) and destroy) - { - parent_session->decrease_size(sizeof(Dce2Smb2FileTracker)); - tree_tracker_mutex.unlock(); - return; - } - } - tree_tracker_mutex.unlock(); -} - -void Dce2Smb2TreeTracker::close_all_files() -{ - tree_tracker_mutex.lock(); - auto it_file = opened_files.begin(); - while (it_file != opened_files.end()) - { - it_file = opened_files.erase(it_file); - } - tree_tracker_mutex.unlock(); -} - -Dce2Smb2RequestTrackerPtr Dce2Smb2TreeTracker::find_request(const uint64_t message_id, - const uint32_t current_flow_key) -{ - Smb2MessageKey message_key = { message_id, current_flow_key, 0 }; - std::lock_guard guard(tree_tracker_mutex); - auto request_it = active_requests.find(message_key); - return (request_it == active_requests.end()) ? nullptr : request_it->second; -} - -bool Dce2Smb2TreeTracker::remove_request(const uint64_t message_id, - const uint32_t current_flow_key) -{ - Smb2MessageKey message_key = { message_id, current_flow_key, 0 }; - std::lock_guard guard(tree_tracker_mutex); - auto request_it = active_requests.find(message_key); - if (request_it != active_requests.end()) - { - return active_requests.erase(message_key); - } - return false; -} - -void Dce2Smb2TreeTracker::process_set_info_request(const Smb2Hdr* smb_header) -{ - const uint8_t* smb_data = (const uint8_t*)smb_header + SMB2_HEADER_LENGTH; - const Smb2SetInfoRequestHdr* set_info_hdr = (const Smb2SetInfoRequestHdr*)smb_data; - - if (set_info_hdr->file_info_class == SMB2_FILE_ENDOFFILE_INFO) - { - uint64_t file_size = alignedNtohq((const uint64_t*)((const uint8_t*) - set_info_hdr + SMB2_SET_INFO_REQUEST_STRUC_SIZE - 1)); - uint64_t file_id = alignedNtohq(&(set_info_hdr->fileId_persistent)); - - do_not_delete_tree = true; - Dce2Smb2FileTrackerPtr file_tracker = find_file(file_id); - if (file_tracker) - file_tracker->set_info(nullptr, 0, file_size); - else - { - dce2_smb_stats.v2_stinf_req_ftrkr_misng++; - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, - GET_CURRENT_PACKET, "%s_REQ: ftracker missing\n", - smb2_command_string[SMB2_COM_SET_INFO]); - } - do_not_delete_tree = false; - } - else - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, - GET_CURRENT_PACKET, "%s_REQ: header error\n", - smb2_command_string[SMB2_COM_SET_INFO]); - dce2_smb_stats.v2_stinf_req_hdr_err++; - } -} - -void Dce2Smb2TreeTracker::process_close_request(const Smb2Hdr* smb_header, - const uint32_t current_flow_key) -{ - const uint8_t* smb_data = (const uint8_t*)smb_header + SMB2_HEADER_LENGTH; - uint64_t file_id = alignedNtohq(&(((const Smb2CloseRequestHdr*) - smb_data) - ->fileId_persistent)); - - do_not_delete_tree = true; - Dce2Smb2FileTrackerPtr file_tracker = find_file(file_id); - if (!file_tracker) - { - dce2_smb_stats.v2_cls_req_ftrkr_misng++; - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, - GET_CURRENT_PACKET, "%s_REQ: ftracker missing %" PRIu64 "\n", - smb2_command_string[SMB2_COM_CLOSE], file_id); - do_not_delete_tree = false; - return; - } - if (file_tracker->close(current_flow_key)) - close_file(file_id, true); - - do_not_delete_tree = false; - - if (share_type != SMB2_SHARE_TYPE_DISK) - { - parent_session->co_tracker_mutex.lock(); - DCE2_CoCleanTracker(co_tracker); - parent_session->co_tracker_mutex.unlock(); - - } -} - -uint64_t Dce2Smb2TreeTracker::get_durable_file_id( - const Smb2CreateRequestHdr* smb_create_hdr, const uint8_t* end) -{ - const uint8_t* data = (const uint8_t*)smb_create_hdr + - alignedNtohl(&smb_create_hdr->create_contexts_offset) - SMB2_HEADER_LENGTH; - uint32_t remaining = alignedNtohl(&smb_create_hdr->create_contexts_length); - - while (remaining > sizeof(Smb2CreateContextHdr) and data < end) - { - const Smb2CreateContextHdr* context = (const Smb2CreateContextHdr*)data; - uint32_t next = alignedNtohl(&context->next); - uint16_t name_offset = alignedNtohs(&context->name_offset); - uint16_t name_length = alignedNtohs(&context->name_length); - uint16_t data_offset = alignedNtohs(&context->data_offset); - uint32_t data_length = alignedNtohl(&context->data_length); - - /* Check for general error condition */ - if (((next & 0x7) != 0)or (next > remaining) or (name_offset != 16) or - (name_length != 4) or (name_offset + name_length > remaining) or - ((data_offset & 0x7) != 0) or - (data_offset and (data_offset < name_offset + name_length)) or - (data_offset > remaining) or (data_offset + data_length > remaining)) - { - return 0; - } - - if ((strncmp((const char*)context+name_offset, - SMB2_CREATE_DURABLE_RECONNECT_V2, name_length) == 0)or - (strncmp((const char*)context+name_offset, - SMB2_CREATE_DURABLE_RECONNECT, name_length) == 0)) - { - return alignedNtohq((const uint64_t*)(((const uint8_t*)context) + - data_offset)); - } - - if (!next) - break; - - data += next; - remaining -= next; - } - return 0; -} - -void Dce2Smb2TreeTracker::process_create_response(const uint64_t message_id, - const uint32_t current_flow_key, const Smb2Hdr* smb_header) -{ - const uint8_t* smb_data = (const uint8_t*)smb_header + SMB2_HEADER_LENGTH; - const Smb2CreateResponseHdr* create_res_hdr = (const Smb2CreateResponseHdr*)smb_data; - uint64_t file_size = 0; - uint64_t file_id = alignedNtohq((const uint64_t*)(&(create_res_hdr->fileId_persistent))); - if (create_res_hdr->end_of_file) - file_size = alignedNtohq((const uint64_t*)(&(create_res_hdr->end_of_file))); - if (create_res_hdr->file_attributes & SMB2_CREATE_RESPONSE_DIRECTORY) - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, - GET_CURRENT_PACKET, "%s_RESP: not processing for directory\n", - smb2_command_string[SMB2_COM_CREATE]); - close_file(file_id, true); - } - else - { - do_not_delete_tree = true; - Dce2Smb2RequestTrackerPtr create_request = find_request(message_id, current_flow_key); - if (create_request) - { - Dce2Smb2FileTrackerPtr file_tracker = find_file(file_id); - if (!file_tracker) - file_tracker = open_file(file_id, current_flow_key); - - if (share_type == SMB2_SHARE_TYPE_DISK) - { - file_tracker->set_info(create_request->get_file_name(), - create_request->get_file_name_size(), file_size); - } - } - else - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, - GET_CURRENT_PACKET, "%s_RESP: req tracker missing\n", - smb2_command_string[SMB2_COM_CREATE]); - dce2_smb_stats.v2_crt_rtrkr_misng++; - } - do_not_delete_tree = false; - } -} - -void Dce2Smb2TreeTracker::process_create_request(const uint64_t message_id, - const uint32_t current_flow_key, const Smb2Hdr* smb_header, const uint8_t* end) -{ - const uint8_t* smb_data = (const uint8_t*)smb_header + SMB2_HEADER_LENGTH; - const Smb2CreateRequestHdr* create_req_hdr = (const Smb2CreateRequestHdr*)smb_data; - if (alignedNtohs(&(create_req_hdr->name_offset)) <= SMB2_HEADER_LENGTH) - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, - GET_CURRENT_PACKET, "%s_REQ: name_offset %" PRIu16 "\n", - smb2_command_string[SMB2_COM_CREATE], create_req_hdr->name_offset); - dce2_smb_stats.v2_crt_req_hdr_err++; - return; - } - const uint8_t* file_name_offset = (const uint8_t*)smb_header + - create_req_hdr->name_offset; - uint16_t file_name_size = alignedNtohs(&(create_req_hdr->name_length)); - if (!file_name_size or (file_name_offset >= end) or - (file_name_offset + file_name_size > end)) - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, GET_CURRENT_PACKET, - "%s_REQ: invalid file name data seen with size %" PRIu16 "\n", - smb2_command_string[SMB2_COM_CREATE], file_name_size); - dce2_smb_stats.v2_crt_inv_file_data++; - return; - } - - uint16_t name_len = 0; - char* file_name = get_smb_file_name(file_name_offset, file_name_size, true, &name_len); - //keep a request tracker with the available info - Dce2Smb2RequestTrackerPtr create_request = std::make_shared(file_name, - name_len); - if (!store_request(message_id, current_flow_key, create_request)) - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_CRITICAL_LEVEL, - GET_CURRENT_PACKET, "SMB2_COM_CREATE_REQ: store failed\n"); - } - //check if file_id is available form a durable reconnect request. - //if present we can create a file tracker right now. - //mostly this is the case for compound request. - uint64_t file_id = get_durable_file_id(create_req_hdr, end); - if (file_id) - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, - GET_CURRENT_PACKET, "requested file_id %lu\n", file_id); - do_not_delete_tree = true; - Dce2Smb2FileTrackerPtr file_tracker = find_file(file_id); - if (!file_tracker) - { - file_tracker = open_file(file_id, current_flow_key); - if (share_type == SMB2_SHARE_TYPE_DISK) - { - file_tracker->set_info(file_name, name_len, 0); - } - } - do_not_delete_tree = false; - } -} - -void Dce2Smb2TreeTracker::process_read_response(const uint64_t message_id, - const uint32_t current_flow_key, const Smb2Hdr* smb_header, const uint8_t* end) -{ - const uint8_t* smb_data = (const uint8_t*)smb_header + SMB2_HEADER_LENGTH; - const Smb2ReadResponseHdr* read_resp_hdr = (const Smb2ReadResponseHdr*)smb_data; - - uint16_t data_offset = alignedNtohs((const uint16_t*)(&(read_resp_hdr->data_offset))); - Packet* p = DetectionEngine::get_current_packet(); - Flow* flow = p->flow; - Dce2SmbFlowData* current_flow_data = (Dce2SmbFlowData*)(flow->get_flow_data( - Dce2SmbFlowData::inspector_id)); - if (!current_flow_data) - return; - Dce2Smb2SessionData* current_flow = - (Dce2Smb2SessionData*)current_flow_data->get_smb_session_data(); - if (data_offset + (const uint8_t*)smb_header > end) - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, - GET_CURRENT_PACKET, "SMB2_COM_READ_RESP: bad offset\n"); - dce_alert(GID_DCE2, DCE2_SMB_BAD_OFF, (dce2CommonStats*)&dce2_smb_stats, - *current_flow->get_dce2_session_data()); - } - - do_not_delete_tree = true; - - Dce2Smb2RequestTrackerPtr read_request = find_request(message_id, current_flow_key); - if (!read_request) - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, - GET_CURRENT_PACKET, "SMB2_COM_READ_RESP: request tracker missing\n"); - dce2_smb_stats.v2_read_rtrkr_misng++; - do_not_delete_tree = false; - return; - } - - Dce2Smb2FileTrackerPtr file_tracker = find_file(read_request->get_file_id()); - if (file_tracker) - { - const uint8_t* file_data = (const uint8_t*)read_resp_hdr + - SMB2_READ_RESPONSE_STRUC_SIZE - 1; - // we may not have enough data in some case, use best effort to process file for whatever - // data we have till now. - int data_size = (read_resp_hdr->length > (end - file_data)) ? - (end - file_data) : read_resp_hdr->length; - if (file_tracker->process_data(current_flow_key, file_data, data_size, - read_request->get_offset(), read_resp_hdr->length)) - { - if ((uint32_t)data_size < alignedNtohl((const uint32_t*)&(read_resp_hdr->length))) - { - file_tracker->accept_raw_data_from(current_flow, 0, file_tracker); - } - } - } - else - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, - GET_CURRENT_PACKET, "SMB2_COM_READ_RESP: file tracker missing\n"); - } - do_not_delete_tree = false; -} - -void Dce2Smb2TreeTracker::process_read_request(const uint64_t message_id, - const uint32_t current_flow_key, const Smb2Hdr* smb_header) -{ - const uint8_t* smb_data = (const uint8_t*)smb_header + SMB2_HEADER_LENGTH; - const Smb2ReadRequestHdr* read_req_hdr = (const Smb2ReadRequestHdr*)smb_data; - uint64_t file_id = alignedNtohq((const uint64_t*)(&(read_req_hdr->fileId_persistent))); - uint64_t offset = alignedNtohq((const uint64_t*)(&(read_req_hdr->offset))); - Dce2Smb2RequestTrackerPtr read_request = std::make_shared(file_id, - offset); - if (!store_request(message_id, current_flow_key, read_request)) - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_CRITICAL_LEVEL, - GET_CURRENT_PACKET, "SMB2_COM_READ_REQ: store failed\n"); - } - do_not_delete_tree = true; - Dce2Smb2FileTrackerPtr file_tracker = find_file(file_id); - Packet* p = DetectionEngine::get_current_packet(); - Flow* flow = p->flow; - Dce2SmbFlowData* current_flow_data = (Dce2SmbFlowData*)(flow->get_flow_data( - Dce2SmbFlowData::inspector_id)); - if (!current_flow_data) - return; - Dce2Smb2SessionData* current_flow = - (Dce2Smb2SessionData*)current_flow_data->get_smb_session_data(); - if (file_tracker) - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, - GET_CURRENT_PACKET, "SMB2_COM_READ_REQ: start accepting Raw Data\n"); - file_tracker->accept_raw_data_from(current_flow,offset, file_tracker); - } - else - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, - GET_CURRENT_PACKET, "SMB2_COM_READ_REQ: file tracker missing\n"); - } - do_not_delete_tree = false; -} - -void Dce2Smb2TreeTracker::process_write_request(const uint64_t message_id, - const uint32_t current_flow_key, const Smb2Hdr* smb_header, const uint8_t* end) -{ - const uint8_t* smb_data = (const uint8_t*)smb_header + SMB2_HEADER_LENGTH; - const Smb2WriteRequestHdr* write_req_hdr = (const Smb2WriteRequestHdr*)smb_data; - uint64_t file_id = alignedNtohq((const uint64_t*)(&(write_req_hdr->fileId_persistent))); - Packet* p = DetectionEngine::get_current_packet(); - Flow* flow = p->flow; - Dce2SmbFlowData* current_flow_data = (Dce2SmbFlowData*)(flow->get_flow_data( - Dce2SmbFlowData::inspector_id)); - if (!current_flow_data) - return; - Dce2Smb2SessionData* current_flow = - (Dce2Smb2SessionData*)current_flow_data->get_smb_session_data(); - if ((alignedNtohs((const uint16_t*)(&(write_req_hdr->data_offset))) + - (const uint8_t*)smb_header > end)) - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, - GET_CURRENT_PACKET, "SMB2_COM_WRITE_REQ: bad offset\n"); - dce_alert(GID_DCE2, DCE2_SMB_BAD_OFF, (dce2CommonStats*)&dce2_smb_stats, - *current_flow->get_dce2_session_data()); - } - //track this request to clean up opened file in case of error response - Dce2Smb2RequestTrackerPtr write_request = std::make_shared(file_id); - if (!store_request(message_id, current_flow_key, write_request)) - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, - GET_CURRENT_PACKET, "SMB2_COM_WRITE_REQ: store failed\n"); - } - const uint8_t* file_data = (const uint8_t*)write_req_hdr + SMB2_WRITE_REQUEST_STRUC_SIZE - 1; - do_not_delete_tree = true; - Dce2Smb2FileTrackerPtr file_tracker = find_file(file_id); - if (file_tracker) - { - file_tracker->set_direction(FILE_UPLOAD); - // we may not have enough data in some case, use best effort to process file for whatever - // data we have till now. - int data_size = (write_req_hdr->length > (end - file_data)) ? - (end - file_data) : write_req_hdr->length; - uint64_t offset = alignedNtohq((const uint64_t*)(&(write_req_hdr->offset))); - if (file_tracker->process_data(current_flow_key, file_data, data_size, offset, - write_req_hdr->length)) - { - if ((uint32_t)data_size < alignedNtohl((const uint32_t*)&(write_req_hdr->length))) - { - file_tracker->accept_raw_data_from(current_flow, 0, file_tracker); - } - } - } - else - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, - GET_CURRENT_PACKET,"SMB2_COM_WRITE_REQ: file tracker missing\n"); - } - do_not_delete_tree = false; -} - -void Dce2Smb2TreeTracker::process_ioctl_command(const 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; - if (SMB2_CMD_TYPE_REQUEST == command_type) - { - const Smb2IoctlRequestHdr* ioctl_req = (const Smb2IoctlRequestHdr*)smb_data; - if ((ioctl_req->ctl_code != FSCTL_PIPE_PEEK)and (ioctl_req->ctl_code != - FSCTL_PIPE_WAIT) and (ioctl_req->ctl_code != FSCTL_PIPE_TRANSCEIVE)) - { - return; - } - } - - if (SMB2_CMD_TYPE_RESPONSE == command_type) - { - const Smb2IoctlResponseHdr* ioctl_response = (const Smb2IoctlResponseHdr*)smb_data; - if ((ioctl_response->ctl_code != FSCTL_PIPE_PEEK)and (ioctl_response->ctl_code != - FSCTL_PIPE_WAIT) and (ioctl_response->ctl_code != FSCTL_PIPE_TRANSCEIVE)) - { - return; - } - } - const uint8_t* file_data = (const uint8_t*)smb_data + structure_size - 1; - int data_size = end - file_data; - Packet* p = DetectionEngine::get_current_packet(); - if (data_size > UINT16_MAX) - { - data_size = UINT16_MAX; - } - parent_session->co_tracker_mutex.lock(); - if (co_tracker) - { - DCE2_CoProcess(get_dce2_session_data(p->flow), co_tracker, file_data, data_size); - } - parent_session->co_tracker_mutex.unlock(); -} - -void Dce2Smb2TreeTracker::process(uint16_t command, uint8_t command_type, - const Smb2Hdr* smb_header, const uint8_t* end, const uint32_t current_flow_key) -{ - tree_tracker_mutex.lock(); - size_t pending_requests = active_requests.size(); - tree_tracker_mutex.unlock(); - Packet* p = DetectionEngine::get_current_packet(); - Flow* flow = p->flow; - Dce2SmbFlowData* current_flow_data = (Dce2SmbFlowData*)(flow->get_flow_data( - Dce2SmbFlowData::inspector_id)); - if (!current_flow_data) - return; - Dce2Smb2SessionData* current_flow = - (Dce2Smb2SessionData*)current_flow_data->get_smb_session_data(); - if (SMB2_CMD_TYPE_REQUEST == command_type and current_flow and - pending_requests >= current_flow->get_max_outstanding_requests()) - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, - GET_CURRENT_PACKET, "%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); - - switch (command) - { - case SMB2_COM_CREATE: - if (SMB2_CMD_TYPE_ERROR_RESPONSE == command_type) - { - dce2_smb_stats.v2_crt_err_resp++; - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, - GET_CURRENT_PACKET, "%s_RESP: error\n", smb2_command_string[command]); - } - else if (SMB2_CMD_TYPE_REQUEST == command_type) - { - if (SMB2_SHARE_TYPE_DISK != share_type) - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, - GET_CURRENT_PACKET, "%s_REQ: processed for ipc share\n", - smb2_command_string[command]); - dce2_smb_stats.v2_crt_req_ipc++; - } - process_create_request(message_id, current_flow_key, smb_header, end); - } - else if (SMB2_CMD_TYPE_RESPONSE == command_type) - process_create_response(message_id, current_flow_key, smb_header); - break; - case SMB2_COM_CLOSE: - process_close_request(smb_header, current_flow_key); - break; - case SMB2_COM_SET_INFO: - process_set_info_request(smb_header); - break; - case SMB2_COM_READ: - if (SMB2_CMD_TYPE_ERROR_RESPONSE == command_type) - { - dce2_smb_stats.v2_read_err_resp++; - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, - GET_CURRENT_PACKET, "%s_RESP: error\n", smb2_command_string[command]); - do_not_delete_tree = true; - Dce2Smb2RequestTrackerPtr request = find_request(message_id, current_flow_key); - if (request) - close_file(request->get_file_id(), true); - do_not_delete_tree = false; - } - else if (SMB2_CMD_TYPE_REQUEST == command_type) - process_read_request(message_id, current_flow_key, smb_header); - else if (SMB2_CMD_TYPE_RESPONSE == command_type) - process_read_response(message_id, current_flow_key, smb_header, end); - break; - case SMB2_COM_WRITE: - if (SMB2_CMD_TYPE_ERROR_RESPONSE == command_type) - { - dce2_smb_stats.v2_wrt_err_resp++; - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, - GET_CURRENT_PACKET, "%s_RESP: error\n", smb2_command_string[command]); - do_not_delete_tree = true; - Dce2Smb2RequestTrackerPtr request = find_request(message_id, current_flow_key); - if (request) - close_file(request->get_file_id(), true); - do_not_delete_tree = false; - } - else if (SMB2_CMD_TYPE_REQUEST == command_type) - process_write_request(message_id, current_flow_key, smb_header, end); - break; - case SMB2_COM_IOCTL: - if (SMB2_CMD_TYPE_ERROR_RESPONSE == command_type) - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, - 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, current_flow_key); -} - -Dce2Smb2TreeTracker::~Dce2Smb2TreeTracker(void) -{ - if (do_not_delete_tree == true) - return; - - if (co_tracker != nullptr) - { - DCE2_CoCleanTracker(co_tracker); - snort_free((void*)co_tracker); - co_tracker = nullptr; - } - - tree_tracker_mutex.lock(); - - for (auto it_file : opened_files) - { - it_file.second->get_parent().reset(); - parent_session->decrease_size(sizeof(Dce2Smb2FileTracker)); - } - - tree_tracker_mutex.unlock(); -} - diff --git a/src/service_inspectors/dce_rpc/dce_smb2_tree.h b/src/service_inspectors/dce_rpc/dce_smb2_tree.h deleted file mode 100644 index 315254c24..000000000 --- a/src/service_inspectors/dce_rpc/dce_smb2_tree.h +++ /dev/null @@ -1,109 +0,0 @@ -//-------------------------------------------------------------------------- -// Copyright (C) 2020-2023 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_smb2_tree.h author Dipta Pandit - -#ifndef DCE_SMB2_TREE_H -#define DCE_SMB2_TREE_H - -// 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" - -using Dce2Smb2RequestTrackerPtr = std::shared_ptr; - -uint64_t Smb2Mid(const Smb2Hdr* hdr); - -class Dce2Smb2SessionTracker; - -class Dce2Smb2TreeTracker -{ -public: - Dce2Smb2TreeTracker() = delete; - Dce2Smb2TreeTracker(const Dce2Smb2TreeTracker&) = delete; - Dce2Smb2TreeTracker& operator=(const Dce2Smb2TreeTracker&) = delete; - - Dce2Smb2TreeTracker(uint32_t tree_id_v, Dce2Smb2SessionTracker* p_session, uint8_t sharetype) - : tree_id(tree_id_v), share_type(sharetype), parent_session(p_session) - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, - GET_CURRENT_PACKET, "tree tracker %" PRIu32 " created\n", tree_id); - 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(); - - Dce2Smb2FileTrackerPtr open_file(const uint64_t, const uint32_t); - void close_file(uint64_t, bool); - void close_all_files(); - Dce2Smb2FileTrackerPtr find_file(uint64_t); - Dce2Smb2RequestTrackerPtr find_request(const uint64_t, const uint32_t); - void process(uint16_t, uint8_t, const Smb2Hdr*, const uint8_t*, const uint32_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; } - std::atomic do_not_delete_tree { false }; - void set_parent(Dce2Smb2SessionTracker* session_tracker) { parent_session = session_tracker; } - -private: - void process_set_info_request(const Smb2Hdr*); - void process_close_request(const Smb2Hdr*, const uint32_t); - void process_create_response(const uint64_t, const uint32_t, const Smb2Hdr*); - void process_create_request(const uint64_t, const uint32_t, const Smb2Hdr*, const uint8_t*); - void process_read_response(const uint64_t, const uint32_t, const Smb2Hdr*, const uint8_t*); - void process_read_request(const uint64_t, const uint32_t, const Smb2Hdr*); - void process_write_request(const uint64_t, const uint32_t, const Smb2Hdr*, const uint8_t*); - uint64_t get_durable_file_id(const Smb2CreateRequestHdr*, const uint8_t*); - bool remove_request(const uint64_t, const uint32_t); - void process_ioctl_command(const uint8_t, const Smb2Hdr*, const uint8_t*); - bool store_request(const uint64_t message_id, const uint32_t current_flow_key, - Dce2Smb2RequestTrackerPtr request) - { - Smb2MessageKey message_key = { message_id, current_flow_key, 0 }; - std::lock_guard guard(tree_tracker_mutex); - return active_requests.insert(std::make_pair(message_key, request)).second; - } - - 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; - std::mutex tree_tracker_mutex; -}; - -using Dce2Smb2TreeTrackerPtr = std::shared_ptr; -using Dce2Smb2TreeTrackerMap = - std::unordered_map >; - -#endif - diff --git a/src/service_inspectors/dce_rpc/dce_smb2_utils.cc b/src/service_inspectors/dce_rpc/dce_smb2_utils.cc new file mode 100644 index 000000000..67511335b --- /dev/null +++ b/src/service_inspectors/dce_rpc/dce_smb2_utils.cc @@ -0,0 +1,99 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2023 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. +//-------------------------------------------------------------------------- + +// SMB2 utils processing +// dce_smb2_utils.cc author Bhargava Jandhyala + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "dce_smb_module.h" +#include "dce_smb_utils.h" +#include "dce_smb2_utils.h" +#include "detection/detection_util.h" +#include "flow/flow_key.h" + +using namespace snort; + +size_t session_cache_size; +THREAD_LOCAL SmbSessionCache* smb2_session_cache; + +Smb2SidHashKey get_key(uint64_t sid) +{ + Smb2SidHashKey key = { }; + Flow* flow = DetectionEngine::get_current_packet()->flow; + if (flow) + { + memcpy(key.cip, flow->client_ip.get_ip6_ptr(), 4 * sizeof(uint32_t)); + memcpy(key.sip, flow->server_ip.get_ip6_ptr(), 4 * sizeof(uint32_t)); + key.sid = sid; + key.cgroup = flow->client_group; + key.sgroup = flow->server_group; + key.vlan_tag = flow->key->vlan_tag; + key.mplsLabel = flow->key->mplsLabel; + key.addressSpaceId = flow->key->addressSpaceId; + key.padding = 0; + } + return key; +} + +DCE2_Smb2SessionTracker* DCE2_Smb2FindElseCreateSid(DCE2_Smb2SsnData* ssd, const + uint64_t sid, bool force_cache_update) +{ + // Local MAP search + auto stracker = DCE2_Smb2FindSidInSsd(ssd, sid); + if (!stracker) + { + // Global Hash Search + stracker = DCE2_SmbSessionCacheFindElseCreate(sid); + DCE2_Smb2InsertSidInSsd(ssd, sid, stracker); + } + else if (force_cache_update) + { + //find on cache to force update LRU. + auto key = get_key(sid); + smb2_session_cache->find(key); + } + return stracker.get(); +} + +DCE2_Smb2TreeTracker* DCE2_Smb2InsertTid(DCE2_Smb2SsnData* ssd, const uint32_t tid, uint8_t + share_type, + DCE2_Smb2SessionTracker* str) +{ + if (share_type == SMB2_SHARE_TYPE_DISK and + ssd->max_file_depth == -1 and DCE2_ScSmbFileDepth((dce2SmbProtoConf*)ssd->sd.config) == -1) + { + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, + DetectionEngine::get_current_packet(), + "Not inserting TID (%u) because it's not IPC and not " + " inspecting normal file data.\n", tid); + return nullptr; + } + + DCE2_Smb2TreeTracker* ttracker = str->findTtracker(tid); + if (!ttracker) + { + ttracker = new DCE2_Smb2TreeTracker(tid, share_type); + str->insertTtracker(tid, ttracker); + } + + return ttracker; +} + diff --git a/src/service_inspectors/dce_rpc/dce_smb2_utils.h b/src/service_inspectors/dce_rpc/dce_smb2_utils.h new file mode 100644 index 000000000..1cda4503e --- /dev/null +++ b/src/service_inspectors/dce_rpc/dce_smb2_utils.h @@ -0,0 +1,153 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2016-2023 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_smb2_utils.h author Bhargava Jandhyala +// based on work by Todd Wease + +#ifndef DCE_SMB2_UTILS_H +#define DCE_SMB2_UTILS_H + +#include "dce_smb.h" +#include "dce_smb2.h" +#include "file_api/file_flows.h" + +Smb2SidHashKey get_key(uint64_t sid); + +template +class LruCacheLocalSmbMultiChannel : public LruCacheLocal +{ +public: + using LruLocal = LruCacheLocal; + using LruLocal::current_size; + using LruLocal::max_size; + using LruLocal::list; + using LruLocal::map; + using LruLocal::stats; + using LruMapIter = typename LruLocal::LruMapIter; + + LruCacheLocalSmbMultiChannel(const size_t sz, struct LruCacheLocalStats& st) : LruLocal(sz, st) { } + + void update(int size) + { + if ( size < 0 ) + assert(current_size >= (size_t)-size); + current_size += size; + if ( size > 0) + { + // Checking 1+ size prevents crash if max_size is too low to hold even a single entry + if ( current_size > max_size and list.size() > 1 ) + LruLocal::prune(); + if ( stats.cache_max < current_size ) + stats.cache_max = current_size; + } + } + + Value find(Key& key) + { + LruMapIter it = map.find(key); + if (it == map.end()) + return nullptr; + //Move entry to front of LruList + list.splice(list.begin(), list, it->second); + return list.begin()->second; + } +}; + +typedef LruCacheLocalSmbMultiChannel, + SmbKeyHash> SmbSessionCache; + +extern THREAD_LOCAL SmbSessionCache* smb2_session_cache; + +// SMB2 Session cache manipulation functions +inline void DCE2_SmbSessionCacheInit(const size_t cache_size) +{ + smb2_session_cache = new SmbSessionCache(cache_size, dce2_smb_stats); +} + +inline void DCE2_SmbSessionCacheUpdateSize(int size) +{ + smb2_session_cache->update(size); +} + +inline std::shared_ptr DCE2_SmbSessionCacheFindElseCreate(uint64_t sid) +{ + bool is_new = false; + auto& session_ptr = smb2_session_cache->find_else_create(get_key(sid), &is_new); + if (is_new) + { + session_ptr.reset(new DCE2_Smb2SessionTracker(sid)); + } + return session_ptr; +} + +inline bool DCE2_SmbSessionCacheRemove(Smb2SidHashKey& key) +{ + return smb2_session_cache->remove(key); +} + +// SMB2 functions for fetching sid, tid, request type and so on. +inline uint64_t Smb2Sid(const Smb2Hdr* hdr) +{ + return snort::alignedNtohq(&(((const Smb2SyncHdr*)hdr)->session_id)); +} + +inline uint32_t Smb2Tid(const Smb2Hdr* hdr) +{ + return snort::alignedNtohl(&(((const Smb2SyncHdr*)hdr)->tree_id)); +} + +inline uint64_t Smb2Mid(const Smb2Hdr* hdr) +{ + return snort::alignedNtohq(&(((const Smb2SyncHdr*)hdr)->message_id)); +} + +inline bool Smb2Error(const Smb2Hdr* hdr) +{ + return (hdr->status != SMB_NT_STATUS__SUCCESS); +} + +inline std::shared_ptr DCE2_Smb2FindSidInSsd(DCE2_Smb2SsnData* ssd, const + uint64_t sid) +{ + return ssd->find_session_tracker(sid); +} + +inline void DCE2_Smb2InsertSidInSsd(DCE2_Smb2SsnData* ssd, const uint64_t sid, + std::shared_ptr stracker) +{ + // add ssd in session tracker's tcp trackers database + if (ssd->flow_key) + { + stracker->insertConnectionTracker(ssd->flow_key, ssd); + } + ssd->insert_session_tracker(sid, stracker); +} + +inline void DCE2_Smb2RemoveSidInSsd(DCE2_Smb2SsnData* ssd, const uint64_t sid) +{ + ssd->remove_session_tracker(sid); +} + +DCE2_Smb2TreeTracker* DCE2_Smb2InsertTid(DCE2_Smb2SsnData*, const uint32_t tid, uint8_t share_type, + DCE2_Smb2SessionTracker*); + +DCE2_Smb2SessionTracker* DCE2_Smb2FindElseCreateSid(DCE2_Smb2SsnData*, const uint64_t sid, bool + force_cache_update = true); + +#endif + diff --git a/src/service_inspectors/dce_rpc/dce_smb_commands.cc b/src/service_inspectors/dce_rpc/dce_smb_commands.cc index 2092a063d..01f9c39c2 100644 --- a/src/service_inspectors/dce_rpc/dce_smb_commands.cc +++ b/src/service_inspectors/dce_rpc/dce_smb_commands.cc @@ -1,6 +1,5 @@ //-------------------------------------------------------------------------- // Copyright (C) 2016-2023 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 @@ -567,7 +566,7 @@ DCE2_Ret DCE2_SmbOpen(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr, dce2_move(nb_ptr, nb_len, 1); ssd->cur_rtracker->file_name = - get_smb_file_name(nb_ptr, nb_len, SmbUnicode(smb_hdr), + DCE2_SmbGetFileName(nb_ptr, nb_len, SmbUnicode(smb_hdr), &ssd->cur_rtracker->file_name_size); } @@ -625,7 +624,7 @@ DCE2_Ret DCE2_SmbCreate(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr, dce2_move(nb_ptr, nb_len, 1); ssd->cur_rtracker->file_name = - get_smb_file_name(nb_ptr, nb_len, SmbUnicode(smb_hdr), + DCE2_SmbGetFileName(nb_ptr, nb_len, SmbUnicode(smb_hdr), &ssd->cur_rtracker->file_name_size); } @@ -856,7 +855,7 @@ DCE2_Ret DCE2_SmbCreateNew(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr, dce2_move(nb_ptr, nb_len, 1); ssd->cur_rtracker->file_name = - get_smb_file_name(nb_ptr, nb_len, SmbUnicode(smb_hdr), + DCE2_SmbGetFileName(nb_ptr, nb_len, SmbUnicode(smb_hdr), &ssd->cur_rtracker->file_name_size); } @@ -1069,7 +1068,7 @@ DCE2_Ret DCE2_SmbOpenAndX(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr, if (ssd->cur_rtracker->file_name == nullptr) { ssd->cur_rtracker->file_name = - get_smb_file_name(nb_ptr, nb_len, unicode, &ssd->cur_rtracker->file_name_size); + DCE2_SmbGetFileName(nb_ptr, nb_len, unicode, &ssd->cur_rtracker->file_name_size); } } @@ -1491,13 +1490,13 @@ DCE2_Ret DCE2_SmbSessionSetupAndX(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr, uint8_t r2 = 0; // Release version second digit // Get Major version - for (i = 0; (i < nb_len) && (*nb_ptr != '\0'); i += increment) + for (i = 0; (i < nb_len); i += increment) { if (isdigit((int)nb_ptr[i])) break; } - if ((i == nb_len) || (*nb_ptr == '\0')) + if (i == nb_len) { return DCE2_RET__SUCCESS; } @@ -1930,7 +1929,7 @@ DCE2_Ret DCE2_SmbNtCreateAndX(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr, if (ssd->cur_rtracker->file_name == nullptr) { ssd->cur_rtracker->file_name = - get_smb_file_name(nb_ptr, file_name_length, unicode, + DCE2_SmbGetFileName(nb_ptr, file_name_length, unicode, &ssd->cur_rtracker->file_name_size); } @@ -2167,3 +2166,4 @@ DCE2_Ret DCE2_SmbWriteAndClose(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr, return DCE2_RET__SUCCESS; } + diff --git a/src/service_inspectors/dce_rpc/dce_smb_commands.h b/src/service_inspectors/dce_rpc/dce_smb_commands.h index 74a77ec22..429dd84f4 100644 --- a/src/service_inspectors/dce_rpc/dce_smb_commands.h +++ b/src/service_inspectors/dce_rpc/dce_smb_commands.h @@ -24,6 +24,8 @@ #include "dce_smb_utils.h" +#define SMB2_GLOBAL_CAP_MULTI_CHANNEL 0x08 + DCE2_Ret DCE2_SmbOpen(DCE2_SmbSsnData*, const SmbNtHdr*, const DCE2_SmbComInfo*, const uint8_t*, uint32_t); DCE2_Ret DCE2_SmbCreate(DCE2_SmbSsnData*, const SmbNtHdr*, diff --git a/src/service_inspectors/dce_rpc/dce_smb_common.cc b/src/service_inspectors/dce_rpc/dce_smb_common.cc deleted file mode 100644 index 5b0156779..000000000 --- a/src/service_inspectors/dce_rpc/dce_smb_common.cc +++ /dev/null @@ -1,245 +0,0 @@ -//-------------------------------------------------------------------------- -// Copyright (C) 2020-2023 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_smb_common.cc author Dipta Pandit - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "dce_smb_common.h" - -#include "file_api/file_flows.h" -#include "file_api/file_service.h" - -#include "dce_smb1.h" -#include "dce_smb2.h" - -using namespace snort; - -THREAD_LOCAL dce2SmbStats dce2_smb_stats; -THREAD_LOCAL ProfileStats dce2_smb_pstat_main; - -//Dce2SmbFlowData members - -unsigned Dce2SmbFlowData::inspector_id = 0; - -Dce2SmbFlowData::Dce2SmbFlowData(Dce2SmbSessionData* ssd_v) : FlowData(inspector_id) -{ - dce2_smb_stats.concurrent_sessions++; - if (dce2_smb_stats.max_concurrent_sessions < dce2_smb_stats.concurrent_sessions) - dce2_smb_stats.max_concurrent_sessions = dce2_smb_stats.concurrent_sessions; - ssd = ssd_v; -} - -Dce2SmbSessionData* Dce2SmbFlowData::upgrade(const Packet* p) -{ - dce2SmbProtoConf* config = - (dce2SmbProtoConf*)ssd->get_dce2_session_data()->config; - delete ssd; - ssd = new Dce2Smb2SessionData(p, config); - return ssd; -} - -void Dce2SmbFlowData::handle_retransmit(Packet* p) -{ - FilePosition position = get_file_position(p); - if (!(SNORT_FILE_FULL == position or SNORT_FILE_END == position)) - return; - FileContext* context = get_smb_file_context(p); - FileVerdict verdict = context ? context->verdict : FILE_VERDICT_UNKNOWN; - ssd->handle_retransmit(position, verdict); -} - -Dce2SmbFlowData::~Dce2SmbFlowData() -{ - if (ssd) - delete ssd; - assert(dce2_smb_stats.concurrent_sessions > 0); - dce2_smb_stats.concurrent_sessions--; -} - -//Dce2SmbSessionData members - -Dce2SmbSessionData::Dce2SmbSessionData(const Packet* p, - const dce2SmbProtoConf* config) -{ - sd = { }; - policy = { }; - tcp_flow = p->flow; - DCE2_ResetRopts(&sd, p); - sd.trans = DCE2_TRANS_TYPE__SMB; - sd.server_policy = config->common.policy; - sd.client_policy = DCE2_POLICY__WINXP; - sd.config = (void*)config; - dialect_index = DCE2_SENTINEL; - max_file_depth = FileService::get_max_file_depth(); - dce2_smb_stats.smb_sessions++; -} - -//Helper functions - -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)) - { - const SmbNtHdr* smb_hdr = (const SmbNtHdr*)(p->data + sizeof(NbssHdr)); - uint32_t smb_version_id = SmbId(smb_hdr); - - if (smb_version_id == DCE2_SMB_ID) - return DCE2_SMB_VERSION_1; - else if (smb_version_id == DCE2_SMB2_ID) - return DCE2_SMB_VERSION_2; - } - - return DCE2_SMB_VERSION_NULL; -} - -Dce2SmbFlowData* create_expected_smb_flow_data(const Packet* p) -{ - DCE2_SmbVersion smb_version = get_smb_version(p); - if (DCE2_SMB_VERSION_2 == smb_version) - { - return new Dce2SmbFlowData(); - } - return nullptr; -} - -Dce2SmbSessionData* create_smb_session_data(Dce2SmbFlowData* flow_data, const Packet* p, - dce2SmbProtoConf* config) -{ - DCE2_SmbVersion smb_version = get_smb_version(p); - if (DCE2_SMB_VERSION_2 != smb_version) - return nullptr; - Dce2SmbSessionData* ssd = (Dce2SmbSessionData*)new Dce2Smb2SessionData(p, config); - flow_data->update_smb_session_data(ssd); - return ssd; -} - -Dce2SmbSessionData* create_new_smb_session(const Packet* p, - dce2SmbProtoConf* config) -{ - DCE2_SmbVersion smb_version = get_smb_version(p); - - if (DCE2_SMB_VERSION_NULL == smb_version) - return nullptr; - - Dce2SmbSessionData* ssd = (DCE2_SMB_VERSION_1 == smb_version) ? - (Dce2SmbSessionData*)new Dce2Smb1SessionData(p, config) : - (Dce2SmbSessionData*)new Dce2Smb2SessionData(p, config); - - Dce2SmbFlowData* flow_data = new Dce2SmbFlowData(ssd); - p->flow->set_flow_data(flow_data); - - return ssd; -} - -DCE2_SsnData* get_dce2_session_data(snort::Flow* flow) -{ - Dce2SmbFlowData* fd = (Dce2SmbFlowData*)flow->get_flow_data(Dce2SmbFlowData::inspector_id); - return fd ? fd->get_smb_session_data() ? fd->get_smb_session_data()->get_dce2_session_data() : - nullptr : nullptr; -} - -inline FileContext* get_smb_file_context(const Packet* p) -{ - FileFlows* file_flows = FileFlows::get_file_flows(p->flow); - if (file_flows) - { - std::lock_guard guard(file_flows->file_flow_context_mutex); - return file_flows->get_current_file_context(); - } - else - return nullptr; -} - -FileContext* get_smb_file_context(Flow* flow, uint64_t file_id, - uint64_t multi_file_processing_id, bool to_create) -{ - if (!flow) - { - dce2_smb_stats.v2_inv_file_ctx_err++; - return nullptr; - } - FileFlows* file_flows = FileFlows::get_file_flows(flow); - - if ( !file_flows ) - { - dce2_smb_stats.v2_inv_file_ctx_err++; - return nullptr; - } - - bool is_new_context = false; - std::lock_guard guard(file_flows->file_flow_context_mutex); - return file_flows->get_file_context(file_id, to_create, is_new_context, multi_file_processing_id); -} - -char* get_smb_file_name(const uint8_t* data, uint32_t data_len, bool unicode, - uint16_t* file_name_len) -{ - const uint8_t inc = unicode ? 2 : 1; - if (data_len < inc) - return nullptr; - - const uint32_t max_len = unicode ? data_len - 1 : data_len; - // Move forward. Don't know if the end of data is actually - // the end of the string. - uint32_t i; - for (i = 0; i < max_len; i += inc) - { - uint16_t uchar = unicode ? extract_16bits(data + i) : data[i]; - if (uchar == 0) - break; - } - - char* fname = nullptr; - const uint32_t real_len = i; - - if (unicode) - { - fname = (char*)snort_calloc(real_len + UTF_16_LE_BOM_LEN + 2); - memcpy(fname, UTF_16_LE_BOM, UTF_16_LE_BOM_LEN);//Prepend with BOM - memcpy(fname + UTF_16_LE_BOM_LEN, data, real_len); - *file_name_len = real_len + UTF_16_LE_BOM_LEN; - } - else - { - fname = (char*)snort_alloc(real_len + 1); - memcpy(fname, data, real_len); - fname[real_len] = 0; - *file_name_len = real_len; - } - 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); - } - } -} - diff --git a/src/service_inspectors/dce_rpc/dce_smb_common.h b/src/service_inspectors/dce_rpc/dce_smb_common.h deleted file mode 100644 index b03adf89d..000000000 --- a/src/service_inspectors/dce_rpc/dce_smb_common.h +++ /dev/null @@ -1,320 +0,0 @@ -//-------------------------------------------------------------------------- -// Copyright (C) 2020-2023 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_smb_common.h author Dipta Pandit - -#ifndef DCE_SMB_COMMON_H -#define DCE_SMB_COMMON_H - -// This provides SMB flow data and base class for SMB session data -// Also provides common functions used by both versions - -#include "file_api/file_api.h" -#include "protocols/packet.h" -#include "profiler/profiler_defs.h" -#include "trace/trace_api.h" - -#include "dce_common.h" -#include "dce_smb_module.h" -#include "smb_common.h" - -#define DCE2_SMB_NAME "dce_smb" -#define DCE2_SMB_HELP "dce over smb inspection" - -#define SMB_DEBUG(module_name, module_id, log_level, p, ...) \ - trace_logf(log_level, module_name , module_id, p, __VA_ARGS__) - -#define DCE2_SMB_ID 0xff534d42 /* \xffSMB */ -#define DCE2_SMB2_ID 0xfe534d42 /* \xfeSMB */ -#define DCE2_SMB_ID_SIZE 4 - -#define SMB_DEFAULT_MAX_CREDIT 8192 -#define SMB_DEFAULT_MEMCAP 8388608 -#define SMB_DEFAULT_MAX_COMPOUND_REQ 3 - -#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 -#define DCE2_SMB_BAD_ID 4 -#define DCE2_SMB_BAD_WCT 5 -#define DCE2_SMB_BAD_BCC 6 -#define DCE2_SMB_BAD_FORM 7 -#define DCE2_SMB_BAD_OFF 8 -#define DCE2_SMB_TDCNT_ZE 9 -#define DCE2_SMB_NB_LT_SMBHDR 10 -#define DCE2_SMB_NB_LT_COM 11 -#define DCE2_SMB_NB_LT_BCC 12 -#define DCE2_SMB_NB_LT_DSIZE 13 -#define DCE2_SMB_TDCNT_LT_DSIZE 14 -#define DCE2_SMB_DSENT_GT_TDCNT 15 -#define DCE2_SMB_BCC_LT_DSIZE 16 -#define DCE2_SMB_INVALID_DSIZE 17 -#define DCE2_SMB_EXCESSIVE_TREE_CONNECTS 18 -#define DCE2_SMB_EXCESSIVE_READS 19 -#define DCE2_SMB_EXCESSIVE_CHAINING 20 -#define DCE2_SMB_MULT_CHAIN_SS 21 -#define DCE2_SMB_MULT_CHAIN_TC 22 -#define DCE2_SMB_CHAIN_SS_LOGOFF 23 -#define DCE2_SMB_CHAIN_TC_TDIS 24 -#define DCE2_SMB_CHAIN_OPEN_CLOSE 25 -#define DCE2_SMB_INVALID_SHARE 26 - -#define DCE2_SMB_V1 44 -#define DCE2_SMB_V2 45 -#define DCE2_SMB_INVALID_BINDING 46 -#define DCE2_SMB2_EXCESSIVE_COMPOUNDING 47 -#define DCE2_SMB_DCNT_ZERO 48 -#define DCE2_SMB_DCNT_MISMATCH 49 -#define DCE2_SMB_MAX_REQS_EXCEEDED 50 -#define DCE2_SMB_REQS_SAME_MID 51 -#define DCE2_SMB_DEPR_DIALECT_NEGOTIATED 52 -#define DCE2_SMB_DEPR_COMMAND_USED 53 -#define DCE2_SMB_UNUSUAL_COMMAND_USED 54 -#define DCE2_SMB_INVALID_SETUP_COUNT 55 -#define DCE2_SMB_MULTIPLE_NEGOTIATIONS 56 -#define DCE2_SMB_EVASIVE_FILE_ATTRS 57 -#define DCE2_SMB_INVALID_FILE_OFFSET 58 -#define DCE2_SMB_BAD_NEXT_COMMAND_OFFSET 59 - -struct dce2SmbStats -{ - PegCount events; - - PegCount co_pdus; - PegCount co_bind; - PegCount co_bind_ack; - PegCount co_alter_ctx; - PegCount co_alter_ctx_resp; - PegCount co_bind_nack; - PegCount co_request; - PegCount co_response; - PegCount co_cancel; - PegCount co_orphaned; - PegCount co_fault; - PegCount co_auth3; - PegCount co_shutdown; - PegCount co_reject; - PegCount co_ms_pdu; - PegCount co_other_req; - PegCount co_other_resp; - PegCount co_req_fragments; - PegCount co_resp_fragments; - PegCount co_cli_max_frag_size; - PegCount co_cli_min_frag_size; - PegCount co_cli_seg_reassembled; - PegCount co_cli_frag_reassembled; - PegCount co_srv_max_frag_size; - PegCount co_srv_min_frag_size; - PegCount co_srv_seg_reassembled; - PegCount co_srv_frag_reassembled; - - PegCount smb_sessions; - PegCount smb_pkts; - PegCount smb_ignored_bytes; - PegCount smb_cli_seg_reassembled; - PegCount smb_srv_seg_reassembled; - PegCount smb_max_outstanding_requests; - // FIXIT-M more peg count foo - /*uint64_t smb_com_stats[2][SMB_MAX_NUM_COMS]; - uint64_t smb_chained_stats[2][SMB_ANDX_COM__MAX][SMB_MAX_NUM_COMS]; - // The +1 is for codes beyond the range of the highest valid subcommand code - // Indicates a bogus subcommand - uint64_t smb_trans_subcom_stats[2][TRANS_SUBCOM_MAX+1]; - uint64_t smb_trans2_subcom_stats[2][TRANS2_SUBCOM_MAX+1]; - uint64_t smb_nt_transact_subcom_stats[2][NT_TRANSACT_SUBCOM_MAX+1]; - */ - PegCount smb_files_processed; - /* SMB2 stats */ - PegCount v2_setup; - PegCount v2_setup_err_resp; - PegCount v2_setup_inv_str_sz; - PegCount v2_setup_resp_hdr_err; - PegCount v2_tree_cnct; - PegCount v2_tree_cnct_err_resp; - PegCount v2_tree_cnct_ignored; - PegCount v2_tree_cnct_inv_str_sz; - PegCount v2_tree_cnct_resp_hdr_err; - PegCount v2_crt; - PegCount v2_crt_err_resp; - PegCount v2_crt_inv_file_data; - PegCount v2_crt_inv_str_sz; - PegCount v2_crt_resp_hdr_err; - PegCount v2_crt_req_hdr_err; - PegCount v2_crt_rtrkr_misng; - PegCount v2_crt_req_ipc; - PegCount v2_crt_tree_trkr_misng; - PegCount v2_wrt; - PegCount v2_wrt_err_resp; - PegCount v2_wrt_inv_str_sz; - PegCount v2_wrt_req_hdr_err; - PegCount v2_wrt_resp_hdr_err; - PegCount v2_read; - PegCount v2_read_err_resp; - PegCount v2_read_inv_str_sz; - PegCount v2_read_rtrkr_misng; - PegCount v2_read_resp_hdr_err; - PegCount v2_read_req_hdr_err; - PegCount v2_setinfo; - PegCount v2_stinf_err_resp; - PegCount v2_stinf_inv_str_sz; - PegCount v2_stinf_req_ftrkr_misng; - PegCount v2_stinf_req_hdr_err; - PegCount v2_cls; - PegCount v2_cls_err_resp; - PegCount v2_cls_inv_str_sz; - PegCount v2_cls_req_ftrkr_misng; - PegCount v2_cls_req_hdr_err; - PegCount v2_tree_discn; - PegCount v2_tree_discn_ignored; - PegCount v2_tree_discn_inv_str_sz; - PegCount v2_tree_discn_req_hdr_err; - PegCount v2_logoff; - PegCount v2_logoff_inv_str_sz; - PegCount v2_hdr_err; - PegCount v2_bad_next_cmd_offset; - PegCount v2_inv_file_ctx_err; - PegCount v2_msgs_uninspected; - 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; - PegCount total_smb1_sessions; - PegCount total_smb2_sessions; - PegCount total_encrypted_sessions; - PegCount total_mc_sessions; - PegCount ignore_dup_sessions; -}; - -enum DCE2_SmbVersion -{ - DCE2_SMB_VERSION_NULL, - DCE2_SMB_VERSION_1, - DCE2_SMB_VERSION_2 -}; - -enum Dce2SmbPduState -{ - DCE2_SMB_PDU_STATE__COMMAND, - DCE2_SMB_PDU_STATE__RAW_DATA -}; - -extern THREAD_LOCAL dce2SmbStats dce2_smb_stats; -extern THREAD_LOCAL snort::ProfileStats dce2_smb_pstat_main; -extern bool smb_module_is_up; -extern SnortProtocolId snort_protocol_id_smb; - -class Dce2SmbSessionData -{ -public: - Dce2SmbSessionData() = delete; - Dce2SmbSessionData(const snort::Packet*, const dce2SmbProtoConf*); - virtual ~Dce2SmbSessionData() { } - - 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; } - - snort::Flow* get_tcp_flow() - { return tcp_flow; } - - int64_t get_max_file_depth() - { return max_file_depth; } - - uint16_t get_max_outstanding_requests() - { - return sd.config ? ((dce2SmbProtoConf*)sd.config)->smb_max_credit : - SMB_DEFAULT_MAX_CREDIT; - } - - int64_t get_smb_file_depth() - { - return ((dce2SmbProtoConf*)sd.config)->smb_file_depth; - } - - uint16_t get_smb_max_compound() - { - return sd.config ? ((dce2SmbProtoConf*)sd.config)->smb_max_compound : - SMB_DEFAULT_MAX_COMPOUND_REQ; - } - -protected: - DCE2_SsnData sd; - DCE2_Policy policy; - int64_t max_file_depth; - int dialect_index; - snort::Flow* tcp_flow; -}; - -class Dce2SmbFlowData : public snort::FlowData -{ -public: - Dce2SmbFlowData(Dce2SmbSessionData*); - Dce2SmbFlowData() : snort::FlowData(inspector_id) - { - dce2_smb_stats.concurrent_sessions++; - if (dce2_smb_stats.max_concurrent_sessions < dce2_smb_stats.concurrent_sessions) - dce2_smb_stats.max_concurrent_sessions = dce2_smb_stats.concurrent_sessions; - ssd = nullptr; - } - - ~Dce2SmbFlowData() override; - - static void init() - { inspector_id = snort::FlowData::create_flow_data_id(); } - - Dce2SmbSessionData* get_smb_session_data() - { return ssd; } - - Dce2SmbSessionData* upgrade(const snort::Packet*); - void update_smb_session_data(Dce2SmbSessionData* ssd_v) - { - if (ssd) delete ssd; - ssd = ssd_v; - } - void handle_retransmit(snort::Packet*) override; - -public: - static unsigned inspector_id; - -private: - Dce2SmbSessionData* ssd; -}; - -Dce2SmbFlowData* create_expected_smb_flow_data(const snort::Packet*); -Dce2SmbSessionData* create_new_smb_session(const snort::Packet*, dce2SmbProtoConf*); -Dce2SmbSessionData* create_smb_session_data(Dce2SmbFlowData*, const snort::Packet*, - dce2SmbProtoConf*); -DCE2_SsnData* get_dce2_session_data(snort::Flow*); -snort::FileContext* get_smb_file_context(const snort::Packet*); -snort::FileContext* get_smb_file_context(snort::Flow*, 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 - diff --git a/src/service_inspectors/dce_rpc/dce_smb_inspector.cc b/src/service_inspectors/dce_rpc/dce_smb_inspector.cc deleted file mode 100644 index 69474cf40..000000000 --- a/src/service_inspectors/dce_rpc/dce_smb_inspector.cc +++ /dev/null @@ -1,192 +0,0 @@ -//-------------------------------------------------------------------------- -// Copyright (C) 2020-2023 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_smb_inspector.h author Dipta Pandit - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include "dce_smb_inspector.h" - -#include "dce_smb_common.h" -#include "dce_smb_module.h" -#include "dce_smb_utils.h" -#include "dce_smb2_session_cache.h" -#include "main/thread_config.h" - -#define DCE_SMB_PROTOCOL_ID "netbios-ssn" - -using namespace snort; - -bool smb_module_is_up = false; -SnortProtocolId snort_protocol_id_smb = UNKNOWN_PROTOCOL_ID; - -Dce2Smb::Dce2Smb(const dce2SmbProtoConf& pc) : - config(pc) { } - -Dce2Smb::~Dce2Smb() -{ - if (config.smb_invalid_shares) - { - DCE2_ListDestroy(config.smb_invalid_shares); - } -} - -bool Dce2Smb::configure(SnortConfig* sc) -{ - snort_protocol_id_smb = sc->proto_ref->add(DCE_SMB_PROTOCOL_ID); - return true; -} - -void Dce2Smb::show(const SnortConfig*) const -{ - print_dce2_smb_conf(config); -} - -void Dce2Smb::eval(Packet* p) -{ - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, - p, "smb packet detected with dsize as %u\n", p->dsize); - - Profile profile(dce2_smb_pstat_main); - - assert(p->has_tcp_data() || p->has_udp_quic_data()); - assert(p->flow); - - reset_using_rpkt(); - - Dce2SmbFlowData* smb_flowdata = - (Dce2SmbFlowData*)p->flow->get_flow_data(Dce2SmbFlowData::inspector_id); - - Dce2SmbSessionData* smb_session_data; - if (smb_flowdata) - { - smb_session_data = smb_flowdata->get_smb_session_data(); - // if flow data present but session data is not, it is an expected session - // try to update the session data, will only do for SMBv2. Ideally it should - // be done in handle_expected, but we dont have access to the config there. - if (!smb_session_data) - smb_session_data = create_smb_session_data(smb_flowdata, p, &config); - } - else - smb_session_data = create_new_smb_session(p, &config); - - if (smb_session_data) - { - dce2_detected = 0; - p->packet_flags |= PKT_ALLOW_MULTIPLE_DETECT; - p->endianness = new DceEndianness(); - - smb_session_data->process(); - //smb_session_data may not be valid anymore in case of upgrade - //but flow will always have updated session - if (!dce2_detected) - DCE2_Detect(get_dce2_session_data(p->flow)); - delete(p->endianness); - p->endianness = nullptr; - } - else - { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, - p, "non-smb packet detected with dsize as %u\n", p->dsize); - } -} - -void Dce2Smb::clear(Packet* p) -{ - DCE2_SsnData* sd = get_dce2_session_data(p->flow); - if (sd) - DCE2_ResetRopts(sd, p); -} - -//------------------------------------------------------------------------- -// api stuff -//------------------------------------------------------------------------- - -static Module* mod_ctor() -{ - return new Dce2SmbModule; -} - -static void mod_dtor(Module* m) -{ - delete m; -} - -static void dce2_smb_init() -{ - Dce2SmbFlowData::init(); - DCE2_SmbInitGlobals(); - DCE2_SmbInitDeletePdu(); - DceContextData::init(DCE2_TRANS_TYPE__SMB); -} - -static Inspector* dce2_smb_ctor(Module* m) -{ - Dce2SmbModule* mod = (Dce2SmbModule*)m; - dce2SmbProtoConf config; - mod->get_data(config); - size_t max_smb_mem = DCE2_ScSmbMemcap(&config); - uint16_t num_threads = ThreadConfig::get_instance_max(); - smb_module_is_up = true; - smb2_session_cache.reload_prune(max_smb_mem*num_threads); - return new Dce2Smb(config); -} - -static void dce2_smb_dtor(Inspector* p) -{ - smb_module_is_up = false; - delete p; -} - -static const char* dce2_bufs[] = -{ - "dce_iface", - "dce_stub_data", - "file_data", - nullptr -}; - -const InspectApi dce2_smb_api = -{ - { - PT_INSPECTOR, - sizeof(InspectApi), - INSAPI_VERSION, - 0, - API_RESERVED, - API_OPTIONS, - DCE2_SMB_NAME, - DCE2_SMB_HELP, - mod_ctor, - mod_dtor - }, - IT_SERVICE, - PROTO_BIT__PDU, - dce2_bufs, - DCE_SMB_PROTOCOL_ID, - dce2_smb_init, - nullptr, - nullptr, // tinit - nullptr, // tterm - dce2_smb_ctor, - dce2_smb_dtor, - nullptr, // ssn - nullptr // reset -}; - diff --git a/src/service_inspectors/dce_rpc/dce_smb_inspector.h b/src/service_inspectors/dce_rpc/dce_smb_inspector.h deleted file mode 100644 index df9d83147..000000000 --- a/src/service_inspectors/dce_rpc/dce_smb_inspector.h +++ /dev/null @@ -1,51 +0,0 @@ -//-------------------------------------------------------------------------- -// Copyright (C) 2020-2023 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_smb_inspector.h author Dipta Pandit - -#ifndef DCE_SMB_INSPECTOR_H -#define DCE_SMB_INSPECTOR_H - -#include "managers/inspector_manager.h" - -#include "dce_smb_module.h" -#include "dce_smb_paf.h" - -class Dce2Smb : public snort::Inspector -{ -public: - Dce2Smb(const dce2SmbProtoConf&); - ~Dce2Smb() override; - - bool configure(snort::SnortConfig*) override; - void show(const snort::SnortConfig*) const override; - void eval(snort::Packet*) override; - void clear(snort::Packet*) override; - - snort::StreamSplitter* get_splitter(bool c2s) override - { return new Dce2SmbSplitter(c2s); } - - bool can_carve_files() const override - { return true; } - -private: - dce2SmbProtoConf config; -}; - -#endif - diff --git a/src/service_inspectors/dce_rpc/dce_smb_module.cc b/src/service_inspectors/dce_rpc/dce_smb_module.cc index 2183f6af6..d21dacf29 100644 --- a/src/service_inspectors/dce_rpc/dce_smb_module.cc +++ b/src/service_inspectors/dce_rpc/dce_smb_module.cc @@ -29,7 +29,7 @@ #include "trace/trace.h" #include "utils/util.h" -#include "dce_smb_common.h" +#include "dce_smb.h" using namespace snort; using namespace std; @@ -38,13 +38,14 @@ THREAD_LOCAL const Trace* dce_smb_trace = nullptr; static const PegInfo dce2_smb_pegs[] = { + LRU_CACHE_LOCAL_PEGS("smbv2"), { CountType::SUM, "events", "total events" }, { CountType::SUM, "pdus", "total connection-oriented PDUs" }, { CountType::SUM, "binds", "total connection-oriented binds" }, { CountType::SUM, "bind_acks", "total connection-oriented binds acks" }, { CountType::SUM, "alter_contexts", "total connection-oriented alter contexts" }, { CountType::SUM, "alter_context_responses", - "total connection-oriented alter context responses" }, + "total connection-oriented alter context responses" }, { CountType::SUM, "bind_naks", "total connection-oriented bind naks" }, { CountType::SUM, "requests", "total connection-oriented requests" }, { CountType::SUM, "responses", "total connection-oriented responses" }, @@ -55,27 +56,27 @@ static const PegInfo dce2_smb_pegs[] = { CountType::SUM, "shutdowns", "total connection-oriented shutdowns" }, { CountType::SUM, "rejects", "total connection-oriented rejects" }, { CountType::SUM, "ms_rpc_http_pdus", - "total connection-oriented MS requests to send RPC over HTTP" }, + "total connection-oriented MS requests to send RPC over HTTP" }, { CountType::SUM, "other_requests", "total connection-oriented other requests" }, { CountType::SUM, "other_responses", "total connection-oriented other responses" }, { CountType::SUM, "request_fragments", "total connection-oriented request fragments" }, { CountType::SUM, "response_fragments", "total connection-oriented response fragments" }, { CountType::SUM, "client_max_fragment_size", - "connection-oriented client maximum fragment size" }, + "connection-oriented client maximum fragment size" }, { CountType::SUM, "client_min_fragment_size", - "connection-oriented client minimum fragment size" }, + "connection-oriented client minimum fragment size" }, { CountType::SUM, "client_segs_reassembled", - "total connection-oriented client segments reassembled" }, + "total connection-oriented client segments reassembled" }, { CountType::SUM, "client_frags_reassembled", - "total connection-oriented client fragments reassembled" }, + "total connection-oriented client fragments reassembled" }, { CountType::SUM, "server_max_fragment_size", - "connection-oriented server maximum fragment size" }, + "connection-oriented server maximum fragment size" }, { CountType::SUM, "server_min_fragment_size", - "connection-oriented server minimum fragment size" }, + "connection-oriented server minimum fragment size" }, { CountType::SUM, "server_segs_reassembled", - "total connection-oriented server segments reassembled" }, + "total connection-oriented server segments reassembled" }, { CountType::SUM, "server_frags_reassembled", - "total connection-oriented server fragments reassembled" }, + "total connection-oriented server fragments reassembled" }, { CountType::SUM, "sessions", "total smb sessions" }, { CountType::SUM, "packets", "total smb packets" }, { CountType::SUM, "ignored_bytes", "total ignored bytes" }, @@ -84,117 +85,115 @@ static const PegInfo dce2_smb_pegs[] = { CountType::MAX, "max_outstanding_requests", "maximum outstanding requests" }, { CountType::SUM, "files_processed", "total smb files processed" }, { CountType::SUM, "v2_setup", "total number of SMBv2 setup packets seen" }, - { CountType::SUM, "v2_setup_err_resp", - "total number of SMBv2 setup error response packets seen" }, + { CountType::SUM, "v2_setup_err_resp", "total number of SMBv2 setup error response packets seen" }, { CountType::SUM, "v2_setup_inv_str_sz", - "total number of SMBv2 setup packets seen with invalid structure size" }, + "total number of SMBv2 setup packets seen with invalid structure size" }, { CountType::SUM, "v2_setup_resp_hdr_err", - "total number of SMBv2 setup response packets ignored due to corrupted header" }, + "total number of SMBv2 setup response packets ignored due to corrupted header" }, { CountType::SUM, "v2_tree_cnct", "total number of SMBv2 tree connect packets seen" }, { CountType::SUM, "v2_tree_cnct_err_resp", - "total number of SMBv2 tree connect error response packets seen" }, + "total number of SMBv2 tree connect error response packets seen" }, { CountType::SUM, "v2_tree_cnct_ignored", - "total number of SMBv2 setup response packets ignored due to failure in creating tree tracker" }, + "total number of SMBv2 setup response packets ignored due to failure in creating tree tracker" }, { CountType::SUM, "v2_tree_cnct_inv_str_sz", - "total number of SMBv2 tree connect packets seen with invalid structure size" }, + "total number of SMBv2 tree connect packets seen with invalid structure size" }, { CountType::SUM, "v2_tree_cnct_resp_hdr_err", - "total number of SMBv2 tree connect response packets ignored due to corrupted header" }, + "total number of SMBv2 tree connect response packets ignored due to corrupted header" }, { CountType::SUM, "v2_crt", "total number of SMBv2 create packets seen" }, - { CountType::SUM, "v2_crt_err_resp", - "total number of SMBv2 create error response packets seen" }, + { CountType::SUM, "v2_crt_err_resp", "total number of SMBv2 create error response packets seen" }, { CountType::SUM, "v2_crt_inv_file_data", - "total number of SMBv2 create request packets ignored due to error in getting file name" }, + "total number of SMBv2 create request packets ignored due to error in getting file name" }, { CountType::SUM, "v2_crt_inv_str_sz", - "total number of SMBv2 create packets seen with invalid structure size" }, + "total number of SMBv2 create packets seen with invalid structure size" }, { CountType::SUM, "v2_crt_resp_hdr_err", - "total number of SMBv2 create response packets ignored due to corrupted header" }, + "total number of SMBv2 create response packets ignored due to corrupted header" }, { CountType::SUM, "v2_crt_req_hdr_err", - "total number of SMBv2 create request packets ignored due to corrupted header" }, + "total number of SMBv2 create request packets ignored due to corrupted header" }, { CountType::SUM, "v2_crt_rtrkr_misng", - "total number of SMBv2 create response packets ignored due to missing create request tracker" }, + "total number of SMBv2 create response packets ignored due to missing create request tracker" }, { CountType::SUM, "v2_crt_req_ipc", - "total number of SMBv2 create request packets ignored as share type is IPC" }, + "total number of SMBv2 create request packets ignored as share type is IPC" }, { CountType::SUM, "v2_crt_tree_trkr_misng", - "total number of SMBv2 create response packets ignored due to missing tree tracker" }, + "total number of SMBv2 create response packets ignored due to missing tree tracker" }, { CountType::SUM, "v2_wrt", "total number of SMBv2 write packets seen" }, - { CountType::SUM, "v2_wrt_err_resp", - "total number of SMBv2 write error response packets seen" }, + { CountType::SUM, "v2_wrt_err_resp", "total number of SMBv2 write error response packets seen" }, + { CountType::SUM, "v2_wrt_ignored", + "total number of SMBv2 write packets ignored due to missing trackers or invalid share type" }, { CountType::SUM, "v2_wrt_inv_str_sz", - "total number of SMBv2 write packets seen with invalid structure size" }, + "total number of SMBv2 write packets seen with invalid structure size" }, { CountType::SUM, "v2_wrt_req_hdr_err", - "total number of SMBv2 write request packets ignored due to corrupted header" }, - { CountType::SUM, "v2_wrt_resp_hdr_err", - "total number of SMBv2 write response packets ignored due to corrupted header" }, + "total number of SMBv2 write request packets ignored due to corrupted header" }, { CountType::SUM, "v2_read", "total number of SMBv2 read packets seen" }, - { CountType::SUM, "v2_read_err_resp", - "total number of SMBv2 read error response packets seen" }, + { CountType::SUM, "v2_read_err_resp", "total number of SMBv2 read error response packets seen" }, + { CountType::SUM, "v2_read_ignored", + "total number of SMBv2 write packets ignored due to missing trackers or invalid share type" }, { CountType::SUM, "v2_read_inv_str_sz", - "total number of SMBv2 read packets seen with invalid structure size" }, + "total number of SMBv2 read packets seen with invalid structure size" }, { CountType::SUM, "v2_read_rtrkr_misng", - "total number of SMBv2 read response packets ignored due to missing read request tracker" }, + "total number of SMBv2 read response packets ignored due to missing read request tracker" }, { CountType::SUM, "v2_read_resp_hdr_err", - "total number of SMBv2 read response packets ignored due to corrupted header" }, + "total number of SMBv2 read response packets ignored due to corrupted header" }, { CountType::SUM, "v2_read_req_hdr_err", - "total number of SMBv2 read request packets ignored due to corrupted header" }, + "total number of SMBv2 read request packets ignored due to corrupted header" }, { CountType::SUM, "v2_setinfo", "total number of SMBv2 set info packets seen" }, - { CountType::SUM, "v2_stinf_err_resp", - "total number of SMBv2 set info error response packets seen" }, + { CountType::SUM, "v2_stinf_err_resp", "total number of SMBv2 set info error response packets seen" }, + { CountType::SUM, "v2_stinf_ignored", + "total number of SMBv2 set info packets ignored due to missing trackers or invalid share type" }, { CountType::SUM, "v2_stinf_inv_str_sz", - "total number of SMBv2 set info packets seen with invalid structure size" }, + "total number of SMBv2 set info packets seen with invalid structure size" }, { CountType::SUM, "v2_stinf_req_ftrkr_misng", - "total number of SMBv2 set info request packets ignored due to missing file tracker" }, + "total number of SMBv2 set info request packets ignored due to missing file tracker" }, { CountType::SUM, "v2_stinf_req_hdr_err", - "total number of SMBv2 set info request packets ignored due to corrupted header" }, + "total number of SMBv2 set info request packets ignored due to corrupted header" }, { CountType::SUM, "v2_cls", "total number of SMBv2 close packets seen" }, - { CountType::SUM, "v2_cls_err_resp", - "total number of SMBv2 close error response packets seen" }, + { CountType::SUM, "v2_cls_err_resp", "total number of SMBv2 close error response packets seen" }, + { CountType::SUM, "v2_cls_ignored", + "total number of SMBv2 close packets ignored due to missing trackers or invalid share type" }, { CountType::SUM, "v2_cls_inv_str_sz", - "total number of SMBv2 close packets seen with invalid structure size" }, + "total number of SMBv2 close packets seen with invalid structure size" }, { CountType::SUM, "v2_cls_req_ftrkr_misng", - "total number of SMBv2 close request packets ignored due to missing file tracker" }, + "total number of SMBv2 close request packets ignored due to missing file tracker" }, { CountType::SUM, "v2_cls_req_hdr_err", - "total number of SMBv2 close request packets ignored due to corrupted header" }, + "total number of SMBv2 close request packets ignored due to corrupted header" }, { CountType::SUM, "v2_tree_discn", - "total number of SMBv2 tree disconnect packets seen" }, + "total number of SMBv2 tree disconnect packets seen" }, { CountType::SUM, "v2_tree_discn_ignored", - "total number of SMBv2 tree disconnect packets ignored due to missing trackers or invalid share type" }, + "total number of SMBv2 tree disconnect packets ignored due to missing trackers or invalid share type" }, { CountType::SUM, "v2_tree_discn_inv_str_sz", - "total number of SMBv2 tree disconnect packets seen with invalid structure size" }, + "total number of SMBv2 tree disconnect packets seen with invalid structure size" }, { CountType::SUM, "v2_tree_discn_req_hdr_err", - "total number of SMBv2 tree disconnect request packets ignored due to corrupted header" }, + "total number of SMBv2 tree disconnect request packets ignored due to corrupted header" }, { CountType::SUM, "v2_logoff", "total number of SMBv2 logoff" }, { CountType::SUM, "v2_logoff_inv_str_sz", - "total number of SMBv2 logoff packets seen with invalid structure size" }, + "total number of SMBv2 logoff packets seen with invalid structure size" }, { CountType::SUM, "v2_hdr_err", "total number of SMBv2 packets seen with corrupted hdr" }, { CountType::SUM, "v2_bad_next_cmd_offset", - "total number of SMBv2 packets seen with invalid next command offset" }, + "total number of SMBv2 packets seen with invalid next command offset" }, + { CountType::SUM, "v2_extra_file_data_err", + "total number of SMBv2 packets seen with where file data beyond file size is observed" }, { CountType::SUM, "v2_inv_file_ctx_err", - "total number of times null file context are seen resulting in not being able to set file size" }, + "total number of times null file context are seen resulting in not being able to set file size" }, { CountType::SUM, "v2_msgs_uninspected", - "total number of SMBv2 packets seen where command is not being inspected" }, + "total number of SMBv2 packets seen where command is not being inspected" }, { CountType::SUM, "v2_cmpnd_req_lt_crossed", - "total number of SMBv2 packets seen where compound requests exceed the smb_max_compound limit" }, - { CountType::SUM, "v2_tree_ignored", - "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" }, + "total number of SMBv2 packets seen where compound requests exceed the smb_max_compound limit" }, { CountType::NOW, "concurrent_sessions", "total concurrent sessions" }, { CountType::MAX, "max_concurrent_sessions", "maximum concurrent sessions" }, { CountType::SUM, "total_smb1_sessions", "total smb1 sessions" }, { CountType::SUM, "total_smb2_sessions", "total smb2 sessions" }, { CountType::SUM, "total_encrypted_sessions", "total encrypted sessions" }, { CountType::SUM, "total_mc_sessions", "total multichannel sessions" }, - { CountType::SUM, "ignore_dup_sessions", "total smb req/resp dropped because of dup msg id" }, + { CountType::SUM, "v2_total_session_trackers", "total number of session trackers" }, + { CountType::SUM, "v2_total_tree_trackers", "total number of tree trackers" }, + { CountType::SUM, "v2_total_file_trackers", "total number of file trackers" }, + { CountType::SUM, "v2_updated_file_flows", "total number of updated file flows due to parent flow cleanup" }, + { CountType::SUM, "v2_ignored_file_processing", "total number of file processing ignored" }, + { CountType::SUM, "v2_mc_file_transfers", "total multichannel files transferred" }, + { 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_ignored", "total number of SMBv2 IOCTL packets ignored due to missing trackers or invalid share type" }, + { CountType::SUM, "total_sessions", "total smb sessions" },/* not used */ { CountType::END, nullptr, nullptr } }; @@ -248,7 +247,7 @@ static const Parameter s_params[] = "Maximum number of outstanding request" }, { "memcap", Parameter::PT_INT, "512:maxSZ", "8388608", - "Memory utilization limit on smb" }, + "Memory utilization limit on SMBv2 cache" }, { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } }; @@ -322,7 +321,7 @@ static std::string get_shares(DCE2_List* shares) return cmds; } -Dce2SmbModule::Dce2SmbModule() : Module(DCE2_SMB_NAME, DCE2_SMB_HELP, s_params) +Dce2SmbModule::Dce2SmbModule() : Module(DCE2_SMB_NAME, DCE2_SMB_HELP, s_params) { memset(&config, 0, sizeof(config)); } @@ -534,7 +533,7 @@ bool Dce2SmbModule::set(const char*, Value& v, SnortConfig*) void Dce2SmbModule::get_data(dce2SmbProtoConf& dce2_smb_config) { - dce2_smb_config = config; // includes pointer copy so set to null + dce2_smb_config = config; // includes pointer copy so set to NULL config.smb_invalid_shares = nullptr; } diff --git a/src/service_inspectors/dce_rpc/dce_smb_module.h b/src/service_inspectors/dce_rpc/dce_smb_module.h index be10a0c3f..905d9674d 100644 --- a/src/service_inspectors/dce_rpc/dce_smb_module.h +++ b/src/service_inspectors/dce_rpc/dce_smb_module.h @@ -21,9 +21,8 @@ #ifndef DCE_SMB_MODULE_H #define DCE_SMB_MODULE_H -#include "framework/module.h" - #include "dce_common.h" +#include "framework/module.h" #include "dce_list.h" namespace snort @@ -37,59 +36,6 @@ extern THREAD_LOCAL const snort::Trace* dce_smb_trace; #define DCE2_VALID_SMB_VERSION_FLAG_V1 1 #define DCE2_VALID_SMB_VERSION_FLAG_V2 2 -#define DCE2_SMB_BAD_NBSS_TYPE_STR "SMB - bad NetBIOS session service session type" -#define DCE2_SMB_BAD_TYPE_STR "SMB - bad SMB message type" -#define DCE2_SMB_BAD_ID_STR "SMB - bad SMB Id (not \\xffSMB for SMB1 or not \\xfeSMB for SMB2)" -#define DCE2_SMB_BAD_WCT_STR "SMB - bad word count or structure size" -#define DCE2_SMB_BAD_BCC_STR "SMB - bad byte count" -#define DCE2_SMB_BAD_FORM_STR "SMB - bad format type" -#define DCE2_SMB_BAD_OFF_STR "SMB - bad offset" -#define DCE2_SMB_TDCNT_ZE_STR "SMB - zero total data count" -#define DCE2_SMB_NB_LT_SMBHDR_STR "SMB - NetBIOS data length less than SMB header length" -#define DCE2_SMB_NB_LT_COM_STR "SMB - remaining NetBIOS data length less than command length" -#define DCE2_SMB_NB_LT_BCC_STR "SMB - remaining NetBIOS data length less than command byte count" -#define DCE2_SMB_NB_LT_DSIZE_STR \ - "SMB - remaining NetBIOS data length less than command data size" -#define DCE2_SMB_TDCNT_LT_DSIZE_STR \ - "SMB - remaining total data count less than this command data size" -#define DCE2_SMB_DSENT_GT_TDCNT_STR \ - "SMB - total data sent (STDu64) greater than command total data expected" -#define DCE2_SMB_BCC_LT_DSIZE_STR "SMB - byte count less than command data size (STDu64)" -#define DCE2_SMB_INVALID_DSIZE_STR "SMB - invalid command data size for byte count" -#define DCE2_SMB_EXCESSIVE_TREE_CONNECTS_STR \ - "SMB - excessive tree connect requests with pending tree connect responses" -#define DCE2_SMB_EXCESSIVE_READS_STR "SMB - excessive read requests with pending read responses" -#define DCE2_SMB_EXCESSIVE_CHAINING_STR "SMB - excessive command chaining" -#define DCE2_SMB_MULT_CHAIN_SS_STR "SMB - Multiple chained login requests" -#define DCE2_SMB_MULT_CHAIN_TC_STR "SMB - Multiple chained tree connect requests" -#define DCE2_SMB_CHAIN_SS_LOGOFF_STR "SMB - chained/compounded login followed by logoff" -#define DCE2_SMB_CHAIN_TC_TDIS_STR \ - "SMB - chained/compounded tree connect followed by tree disconnect" -#define DCE2_SMB_CHAIN_OPEN_CLOSE_STR \ - "SMB - chained/compounded open pipe followed by close pipe" -#define DCE2_SMB_INVALID_SHARE_STR "SMB - invalid share access" - -#define DCE2_SMB_V1_STR "SMB - invalid SMB version 1 seen" -#define DCE2_SMB_V2_STR "SMB - invalid SMB version 2 seen" -#define DCE2_SMB_INVALID_BINDING_STR "SMB - invalid user, tree connect, file binding" -#define DCE2_SMB2_EXCESSIVE_COMPOUNDING_STR "SMB - excessive command compounding" -#define DCE2_SMB_DCNT_ZERO_STR "SMB - zero data count" -#define DCE2_SMB_DCNT_MISMATCH_STR "SMB - data count mismatch in command and format" -#define DCE2_SMB_MAX_REQS_EXCEEDED_STR "SMB - maximum number of outstanding requests exceeded" -#define DCE2_SMB_REQS_SAME_MID_STR "SMB - outstanding requests with same MID" -#define DCE2_SMB_DEPR_DIALECT_NEGOTIATED_STR "SMB - deprecated dialect negotiated" -#define DCE2_SMB_DEPR_COMMAND_USED_STR "SMB - deprecated command used" -#define DCE2_SMB_UNUSUAL_COMMAND_USED_STR "SMB - unusual command used" -#define DCE2_SMB_INVALID_SETUP_COUNT_STR "SMB - invalid setup count for command" -#define DCE2_SMB_MULTIPLE_NEGOTIATIONS_STR \ - "SMB - client attempted multiple dialect negotiations on session" -#define DCE2_SMB_EVASIVE_FILE_ATTRS_STR \ - "SMB - client attempted to create or set a file's attributes to readonly/hidden/system" -#define DCE2_SMB_INVALID_FILE_OFFSET_STR \ - "SMB - file offset provided is greater than file size specified" -#define DCE2_SMB_BAD_NEXT_COMMAND_OFFSET_STR \ - "SMB - next command specified in SMB2 header is beyond payload boundary" - enum dce2SmbFingerprintPolicy { DCE2_SMB_FINGERPRINT_POLICY_NONE = 0, diff --git a/src/service_inspectors/dce_rpc/dce_smb_paf.cc b/src/service_inspectors/dce_rpc/dce_smb_paf.cc index 3c31a2159..977ee4b15 100644 --- a/src/service_inspectors/dce_rpc/dce_smb_paf.cc +++ b/src/service_inspectors/dce_rpc/dce_smb_paf.cc @@ -23,9 +23,11 @@ #include "config.h" #endif +#include "dce_smb_module.h" #include "dce_smb_paf.h" - -#include "dce_smb_common.h" +#include "dce_smb.h" +#include "trace/trace_api.h" +#include "utils/util.h" namespace { @@ -45,8 +47,8 @@ using namespace snort; * junk states, header type must be Session Message. * *********************************************************************/ -static inline bool DCE2_PafSmbIsValidNetbiosHdr(uint32_t nb_hdr, bool junk, - const SmbNtHdr* nt_hdr, uint32_t* nb_len) +static inline bool DCE2_PafSmbIsValidNetbiosHdr(uint32_t nb_hdr, bool junk, const SmbNtHdr* nt_hdr, + uint32_t* nb_len) { uint8_t type = (uint8_t)(nb_hdr >> 24); uint8_t bit = (uint8_t)((nb_hdr & 0x00ff0000) >> 16); @@ -106,8 +108,8 @@ static inline bool DCE2_PafSmbIsValidNetbiosHdr(uint32_t nb_hdr, bool junk, * state 7 until this is the case. * *********************************************************************/ -static StreamSplitter::Status dce2_smb_paf(DCE2_PafSmbData* ss, Flow* flow, - const uint8_t* data, uint32_t len, uint32_t, uint32_t* fp) +static StreamSplitter::Status dce2_smb_paf(DCE2_PafSmbData* ss, Flow* flow, const uint8_t* data, + uint32_t len, uint32_t, uint32_t* fp) { uint32_t n = 0; StreamSplitter::Status ps = StreamSplitter::SEARCH; @@ -179,7 +181,7 @@ static StreamSplitter::Status dce2_smb_paf(DCE2_PafSmbData* ss, Flow* flow, return ps; } -Dce2SmbSplitter::Dce2SmbSplitter(bool c2s) : StreamSplitter(c2s) +Dce2SmbSplitter::Dce2SmbSplitter(bool c2s) : StreamSplitter(c2s) { state.paf_state = DCE2_PAF_SMB_STATES__0; state.nb_hdr = 0; @@ -190,9 +192,9 @@ StreamSplitter::Status Dce2SmbSplitter::scan( uint32_t flags, uint32_t* fp) { DCE2_PafSmbData* pfdata = &state; - StreamSplitter::Status ps = dce2_smb_paf(pfdata, pkt->flow, data, len, flags, fp); + StreamSplitter::Status ps = dce2_smb_paf(pfdata, pkt->flow, data, len, flags, fp); SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, pkt, - "Dce2SmbSplitter scan with length %u and status %d\n", len, ps); + "Dce2SmbSplitter scan with length %u, status %d and fp %u\n", len, ps, *fp); return ps; } diff --git a/src/service_inspectors/dce_rpc/dce_smb_paf.h b/src/service_inspectors/dce_rpc/dce_smb_paf.h index bd6844e29..455fbd1c4 100644 --- a/src/service_inspectors/dce_rpc/dce_smb_paf.h +++ b/src/service_inspectors/dce_rpc/dce_smb_paf.h @@ -48,7 +48,7 @@ struct DCE2_PafSmbData class Dce2SmbSplitter : public snort::StreamSplitter { public: - Dce2SmbSplitter(bool c2s); + explicit Dce2SmbSplitter(bool c2s); Status scan(snort::Packet*, const uint8_t* data, uint32_t len, uint32_t flags, uint32_t* fp) override; diff --git a/src/service_inspectors/dce_rpc/dce_smb_transaction.cc b/src/service_inspectors/dce_rpc/dce_smb_transaction.cc index 2349b30f6..2aba031ff 100644 --- a/src/service_inspectors/dce_rpc/dce_smb_transaction.cc +++ b/src/service_inspectors/dce_rpc/dce_smb_transaction.cc @@ -290,7 +290,7 @@ static DCE2_Ret DCE2_SmbNtTransactCreateReq(DCE2_SmbSsnData* ssd, dce2_move(param_ptr, param_len, pad); ssd->cur_rtracker->file_name = - get_smb_file_name(param_ptr, file_name_length, unicode, &ssd->cur_rtracker->file_name_size); + DCE2_SmbGetFileName(param_ptr, file_name_length, unicode, &ssd->cur_rtracker->file_name_size); return DCE2_RET__SUCCESS; } @@ -528,8 +528,7 @@ static DCE2_Ret DCE2_SmbUpdateTransRequest(DCE2_SmbSsnData* ssd, if (DCE2_SsnIsWindowsPolicy(&ssd->sd) && ssd->cur_rtracker->ftracker->fp_byte_mode) { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, - DetectionEngine::get_current_packet(), + debug_log(dce_smb_trace, DetectionEngine::get_current_packet(), "Pipe is in byte mode - TRANS_TRANSACT_NMPIPE won't work\n"); return DCE2_RET__ERROR; } @@ -554,14 +553,14 @@ static DCE2_Ret DCE2_SmbUpdateTransRequest(DCE2_SmbSsnData* ssd, // Not implemented according to MS-CIFS case TRANS_RAW_READ_NMPIPE: - // Can only write 2 null bytes and subsequent writes return pipe disconnected + // Can only write 2 NULL bytes and subsequent writes return pipe disconnected case TRANS_RAW_WRITE_NMPIPE: // Can at most do a DCE/RPC bind case TRANS_CALL_NMPIPE: dce_alert(GID_DCE2, DCE2_SMB_DEPR_COMMAND_USED, (dce2CommonStats*)&dce2_smb_stats, ssd->sd); - // fallthrough + // fallthrough // Aren't looking at these or the three above case TRANS_QUERY_NMPIPE_STATE: @@ -588,10 +587,9 @@ static DCE2_Ret DCE2_SmbUpdateTransRequest(DCE2_SmbSsnData* ssd, // And Samba uses the ByteCount to validate if (DCE2_SsnIsSambaPolicy(&ssd->sd) && (DCE2_SmbTransactionGetName(nb_ptr, nb_len, - byte_count, SmbUnicode(smb_hdr)) != DCE2_RET__SUCCESS)) + byte_count, SmbUnicode(smb_hdr)) != DCE2_RET__SUCCESS)) { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, - DetectionEngine::get_current_packet(), + debug_log(dce_smb_trace, DetectionEngine::get_current_packet(), "Failed to validate pipe name for Samba.\n"); return DCE2_RET__ERROR; } @@ -720,7 +718,7 @@ static DCE2_Ret DCE2_SmbUpdateTransRequest(DCE2_SmbSsnData* ssd, // If all of the data and parameters weren't sent, buffer what was sent if (((dcnt != tdcnt) || (pcnt != tpcnt)) && (dcnt != 0) && (DCE2_SmbBufferTransactionData(ttracker, - nb_ptr, dcnt, 0) != DCE2_RET__SUCCESS)) + nb_ptr, dcnt, 0) != DCE2_RET__SUCCESS)) { return DCE2_RET__ERROR; } @@ -737,7 +735,7 @@ static DCE2_Ret DCE2_SmbUpdateTransRequest(DCE2_SmbSsnData* ssd, // If all of the data and parameters weren't sent, buffer what was sent if (((pcnt != tpcnt) || (dcnt != tdcnt)) && (pcnt != 0) && (DCE2_SmbBufferTransactionParameters(ttracker, - nb_ptr, pcnt, 0) != DCE2_RET__SUCCESS)) + nb_ptr, pcnt, 0) != DCE2_RET__SUCCESS)) { return DCE2_RET__ERROR; } @@ -960,7 +958,7 @@ static DCE2_Ret DCE2_SmbTrans2Open2Req(DCE2_SmbSsnData* ssd, dce2_move(param_ptr, param_len, sizeof(SmbTrans2Open2ReqParams)); ssd->cur_rtracker->file_name = - get_smb_file_name(param_ptr, param_len, unicode, &ssd->cur_rtracker->file_name_size); + DCE2_SmbGetFileName(param_ptr, param_len, unicode, &ssd->cur_rtracker->file_name_size); return DCE2_RET__SUCCESS; } @@ -1075,8 +1073,8 @@ DCE2_Ret DCE2_SmbTransaction(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr, if (DCE2_ComInfoIsRequest(com_info) && !DCE2_SmbIsTransactionComplete(ttracker)) { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, - DetectionEngine::get_current_packet(), "Got new transaction request " + debug_log(dce_smb_trace, DetectionEngine::get_current_packet(), + "Got new transaction request " "that matches an in progress transaction - not inspecting.\n"); return DCE2_RET__ERROR; } @@ -1085,8 +1083,7 @@ DCE2_Ret DCE2_SmbTransaction(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr, if (DCE2_ComInfoIsRequest(com_info) && (DCE2_ComInfoWordCount(com_info) != 16)) { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, - DetectionEngine::get_current_packet(), + debug_log(dce_smb_trace, DetectionEngine::get_current_packet(), "\\PIPE\\LANMAN request - not inspecting\n"); return DCE2_RET__IGNORE; } @@ -1199,9 +1196,9 @@ DCE2_Ret DCE2_SmbTransaction2(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr, if (DCE2_ComInfoIsRequest(com_info) && !DCE2_SmbIsTransactionComplete(ttracker)) { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, - DetectionEngine::get_current_packet(), "Got new transaction request " - "that matches an in progress transaction - not inspecting.\n"); + debug_log(dce_smb_trace, DetectionEngine::get_current_packet(), + "Got new transaction request " + "that matches an in progress transaction - not inspecting.\n"); return DCE2_RET__ERROR; } @@ -1294,9 +1291,9 @@ DCE2_Ret DCE2_SmbTransaction2(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr, if (!DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid) && (SmbFileAttrsDirectory(SmbTrans2Open2RespFileAttrs( - (const SmbTrans2Open2RespParams*)ptr)) + (const SmbTrans2Open2RespParams*)ptr)) || !SmbResourceTypeDisk(SmbTrans2Open2RespResourceType( - (const SmbTrans2Open2RespParams*)ptr)))) + (const SmbTrans2Open2RespParams*)ptr)))) { return DCE2_RET__SUCCESS; } @@ -1458,8 +1455,8 @@ DCE2_Ret DCE2_SmbNtTransact(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr, if (DCE2_ComInfoIsRequest(com_info) && !DCE2_SmbIsTransactionComplete(ttracker)) { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, - DetectionEngine::get_current_packet(), "Got new transaction request " + debug_log(dce_smb_trace, DetectionEngine::get_current_packet(), + "Got new transaction request " "that matches an in progress transaction - not inspecting.\n"); return DCE2_RET__ERROR; } diff --git a/src/service_inspectors/dce_rpc/dce_smb_transaction_utils.cc b/src/service_inspectors/dce_rpc/dce_smb_transaction_utils.cc index a22e996a6..f92fefcf3 100644 --- a/src/service_inspectors/dce_rpc/dce_smb_transaction_utils.cc +++ b/src/service_inspectors/dce_rpc/dce_smb_transaction_utils.cc @@ -402,3 +402,4 @@ DCE2_Ret DCE2_SmbBufferTransactionParameters(DCE2_SmbTransactionTracker* ttracke return DCE2_RET__SUCCESS; } + diff --git a/src/service_inspectors/dce_rpc/dce_smb_transaction_utils.h b/src/service_inspectors/dce_rpc/dce_smb_transaction_utils.h index dd39cb489..a81319d18 100644 --- a/src/service_inspectors/dce_rpc/dce_smb_transaction_utils.h +++ b/src/service_inspectors/dce_rpc/dce_smb_transaction_utils.h @@ -22,7 +22,7 @@ #ifndef DCE_SMB_TRANSACTION_UTILS_H #define DCE_SMB_TRANSACTION_UTILS_H -#include "dce_smb1.h" +#include "dce_smb.h" DCE2_Ret DCE2_SmbTransactionGetName(const uint8_t* nb_ptr, uint32_t nb_len, uint16_t bcc, bool unicode); diff --git a/src/service_inspectors/dce_rpc/dce_smb_utils.cc b/src/service_inspectors/dce_rpc/dce_smb_utils.cc index f92ab9ebe..b2c3f7cf2 100644 --- a/src/service_inspectors/dce_rpc/dce_smb_utils.cc +++ b/src/service_inspectors/dce_rpc/dce_smb_utils.cc @@ -94,6 +94,47 @@ bool DCE2_SmbIsTidIPC(DCE2_SmbSsnData* ssd, const uint16_t tid) return false; } +// Extract file name from data. Supports ASCII and UTF-16LE. +// Returns byte stream (ASCII or UTF-16LE with BOM) +char* DCE2_SmbGetFileName(const uint8_t* data, uint32_t data_len, bool unicode, + uint16_t* file_name_len) +{ + const uint8_t inc = unicode ? 2 : 1; + if (data_len < inc) + return nullptr; + + const uint32_t max_len = unicode ? data_len - 1 : data_len; + // Move forward. Don't know if the end of data is actually + // the end of the string. + uint32_t i; + for (i = 0; i < max_len; i += inc) + { + uint16_t uchar = unicode ? extract_16bits(data + i) : data[i]; + if (uchar == 0) + break; + } + + char* fname = nullptr; + const uint32_t real_len = i; + + if (unicode) + { + fname = (char*)snort_calloc(real_len + UTF_16_LE_BOM_LEN + 2); + memcpy(fname, UTF_16_LE_BOM, UTF_16_LE_BOM_LEN);//Prepend with BOM + memcpy(fname + UTF_16_LE_BOM_LEN, data, real_len); + *file_name_len = real_len + UTF_16_LE_BOM_LEN; + } + else + { + fname = (char*)snort_alloc(real_len + 1); + memcpy(fname, data, real_len); + fname[real_len] = 0; + *file_name_len = real_len; + } + + return fname; +} + int DCE2_SmbUidTidFidCompare(const void* a, const void* b) { int x = (int)(uintptr_t)a; @@ -137,7 +178,7 @@ void DCE2_SmbInsertUid(DCE2_SmbSsnData* ssd, const uint16_t uid) } } - DCE2_ListInsert(ssd->uids, (void*)(uintptr_t)uid, (void*)(uintptr_t)uid); + (void)DCE2_ListInsert(ssd->uids, (void*)(uintptr_t)uid, (void*)(uintptr_t)uid); } } @@ -439,7 +480,7 @@ DCE2_SmbFileTracker* DCE2_SmbFindFileTracker(DCE2_SmbSsnData* ssd, break; } - // fallthrough + // fallthrough case DCE2_POLICY__WIN2003: case DCE2_POLICY__WINXP: @@ -663,7 +704,7 @@ void DCE2_SmbRemoveFileTrackerFromRequestTrackers(DCE2_SmbSsnData* ssd, if (ftracker == nullptr) return; - // null out file trackers of any outstanding requests + // NULL out file trackers of any outstanding requests // that reference this file tracker if (ssd->rtracker.ftracker == ftracker) ssd->rtracker.ftracker = nullptr; @@ -794,8 +835,8 @@ void DCE2_SmbInsertTid(DCE2_SmbSsnData* ssd, if ( !is_ipc and ssd->max_file_depth == -1 and DCE2_ScSmbFileDepth((dce2SmbProtoConf*)ssd->sd.config) == -1 ) { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, - DetectionEngine::get_current_packet(), "Not inserting TID (%hu) " + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, + DetectionEngine::get_current_packet(), "Not inserting TID (%hu) " "because it's not IPC and not inspecting normal file data.\n", tid); return; } @@ -822,7 +863,7 @@ void DCE2_SmbInsertTid(DCE2_SmbSsnData* ssd, } } - DCE2_ListInsert(ssd->tids, (void*)(uintptr_t)tid, (void*)(uintptr_t)insert_tid); + (void)DCE2_ListInsert(ssd->tids, (void*)(uintptr_t)tid, (void*)(uintptr_t)insert_tid); } } @@ -951,8 +992,7 @@ DCE2_Ret DCE2_SmbProcessRequestData(DCE2_SmbSsnData* ssd, if (data_len > UINT16_MAX) data_len = UINT16_MAX; - if (ftracker->fp_co_tracker) - DCE2_CoProcess(&ssd->sd, ftracker->fp_co_tracker, data_ptr, (uint16_t)data_len); + DCE2_CoProcess(&ssd->sd, ftracker->fp_co_tracker, data_ptr, (uint16_t)data_len); if (!ftracker->fp_used) ftracker->fp_used = true; @@ -1303,9 +1343,7 @@ static FileContext* DCE2_get_main_file_context() { FileFlows* file_flows = FileFlows::get_file_flows(DetectionEngine::get_current_packet()->flow); if (file_flows) - { return file_flows->get_current_file_context(); - } else return nullptr; } @@ -1423,9 +1461,7 @@ static void DCE2_SmbFinishFileAPI(DCE2_SmbSsnData* ssd) FileFlows* file_flows = FileFlows::get_file_flows(p->flow); if (!file_flows) - { return; - } bool upload = (ftracker->ff_file_direction == DCE2_SMB_FILE_DIRECTION__UPLOAD); if (get_file_processed_size(p->flow) != 0) @@ -1435,11 +1471,8 @@ static void DCE2_SmbFinishFileAPI(DCE2_SmbSsnData* ssd) if ((ftracker->ff_file_size == 0) && (ftracker->ff_bytes_processed != 0)) { - file_flows->file_flow_context_mutex.lock(); - bool resault = file_flows->file_process(p, nullptr, 0, SNORT_FILE_END, upload, - ftracker->file_name_hash); - file_flows->file_flow_context_mutex.unlock(); - if (resault) + if (file_flows->file_process(p, nullptr, 0, SNORT_FILE_END, upload, + ftracker->file_name_hash)) { if (upload) { @@ -1511,13 +1544,12 @@ static DCE2_Ret DCE2_SmbFileAPIProcess(DCE2_SmbSsnData* ssd, if (!file_flows) return DCE2_RET__ERROR; - std::lock_guard guard(file_flows->file_flow_context_mutex); if (!file_flows->file_process(p, data_ptr, (int)data_len, position, upload, ftracker->file_name_hash)) { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, - p, "File API returned FAILURE for (0x%02X) %s\n", - ftracker->fid_v1, upload ? "UPLOAD" : "DOWNLOAD"); + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_ERROR_LEVEL, + p, "File API returned FAILURE for (0x%02X) %s\n", + ftracker->fid_v1, upload ? "UPLOAD" : "DOWNLOAD"); // Failure. Abort tracking this file under file API return DCE2_RET__ERROR; @@ -1657,7 +1689,7 @@ static DCE2_Ret DCE2_SmbHandleOutOfOrderFileData(DCE2_SmbSsnData* ssd, DCE2_Ret ret; if ((ret = DCE2_ListInsert(ftracker->ff_file_chunks, - (void*)file_chunk, (void*)file_chunk)) != DCE2_RET__SUCCESS) + (void*)file_chunk, (void*)file_chunk)) != DCE2_RET__SUCCESS) { snort_free((void*)file_chunk->data); snort_free((void*)file_chunk); @@ -1769,10 +1801,10 @@ void DCE2_SmbProcessFileData(DCE2_SmbSsnData* ssd, } else if (ftracker->ff_file_offset < ftracker->ff_bytes_processed) { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, - DetectionEngine::get_current_packet(), "File offset %" PRIu64 " is less than bytes processed %" - PRIu64 " - aborting.\n", ftracker->ff_file_offset, - ftracker->ff_bytes_processed); + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, + DetectionEngine::get_current_packet(), "File offset %" PRIu64 " is less than bytes processed %" + PRIu64 " - aborting.\n", ftracker->ff_file_offset, + ftracker->ff_bytes_processed); DCE2_SmbAbortFileAPI(ssd); DCE2_SmbSetNewFileAPIFileTracker(ssd); diff --git a/src/service_inspectors/dce_rpc/dce_smb_utils.h b/src/service_inspectors/dce_rpc/dce_smb_utils.h index 0a2fdb432..a86ccb73e 100644 --- a/src/service_inspectors/dce_rpc/dce_smb_utils.h +++ b/src/service_inspectors/dce_rpc/dce_smb_utils.h @@ -22,7 +22,7 @@ #ifndef DCE_SMB_UTILS_H #define DCE_SMB_UTILS_H -#include "dce_smb1.h" +#include "dce_smb.h" #include "file_api/file_flows.h" /******************************************************************** @@ -125,6 +125,7 @@ inline bool DCE2_ComInfoCanProcessCommand(const DCE2_SmbComInfo* com_info) * Function prototypes ********************************************************************/ bool DCE2_SmbIsTidIPC(DCE2_SmbSsnData*, const uint16_t); +char* DCE2_SmbGetFileName(const uint8_t* data, uint32_t data_len, bool unicode, uint16_t* file_name_len); int DCE2_SmbUidTidFidCompare(const void*, const void*); DCE2_Ret DCE2_SmbFindUid(DCE2_SmbSsnData*, const uint16_t); void DCE2_SmbInsertUid(DCE2_SmbSsnData*, const uint16_t); @@ -177,7 +178,6 @@ void DCE2_SmbProcessFileData(DCE2_SmbSsnData* ssd, uint32_t data_len, bool upload); void DCE2_FileDetect(); FileVerdict DCE2_get_file_verdict(); -void DCE2_SmbInitGlobals(); void DCE2_SmbInitDeletePdu(); void DCE2_Update_Ftracker_from_ReqTracker(DCE2_SmbFileTracker*, DCE2_SmbRequestTracker*); diff --git a/src/service_inspectors/dce_rpc/dce_tcp.cc b/src/service_inspectors/dce_rpc/dce_tcp.cc index 3b6f58a7b..8dd658ee1 100644 --- a/src/service_inspectors/dce_rpc/dce_tcp.cc +++ b/src/service_inspectors/dce_rpc/dce_tcp.cc @@ -34,10 +34,10 @@ using namespace snort; -Dce2TcpFlowData::Dce2TcpFlowData() : FlowData(inspector_id) +Dce2TcpFlowData::Dce2TcpFlowData() : FlowData(inspector_id) { dce2_tcp_stats.concurrent_sessions++; - if(dce2_tcp_stats.max_concurrent_sessions < dce2_tcp_stats.concurrent_sessions) + if (dce2_tcp_stats.max_concurrent_sessions < dce2_tcp_stats.concurrent_sessions) dce2_tcp_stats.max_concurrent_sessions = dce2_tcp_stats.concurrent_sessions; } @@ -113,7 +113,7 @@ static DCE2_TcpSsnData* dce2_handle_tcp_session(Packet* p, dce2TcpProtoConf* con // class stuff //------------------------------------------------------------------------- Dce2Tcp::Dce2Tcp(const dce2TcpProtoConf& pc) : - config(pc), esm(config) {} + config(pc), esm(config) { } bool Dce2Tcp::configure(snort::SnortConfig* sc) { @@ -167,7 +167,6 @@ void Dce2Tcp::clear(Packet* p) { DCE2_ResetRopts(&dce2_tcp_sess->sd, p); } - } //------------------------------------------------------------------------- diff --git a/src/service_inspectors/dce_rpc/dce_tcp.h b/src/service_inspectors/dce_rpc/dce_tcp.h index 44d86b918..7723a2924 100644 --- a/src/service_inspectors/dce_rpc/dce_tcp.h +++ b/src/service_inspectors/dce_rpc/dce_tcp.h @@ -128,14 +128,14 @@ public: public: static unsigned inspector_id; - DCE2_TcpSsnData dce2_tcp_session; - DCE2_TcpFlowState state; + DCE2_TcpSsnData dce2_tcp_session = {}; + DCE2_TcpFlowState state = DCE2_TCP_FLOW__COMMON; }; class Dce2Tcp : public snort::Inspector { public: - Dce2Tcp(const dce2TcpProtoConf&); + explicit Dce2Tcp(const dce2TcpProtoConf&); bool configure(snort::SnortConfig*) override; void show(const snort::SnortConfig*) const override; diff --git a/src/service_inspectors/dce_rpc/dce_tcp_module.cc b/src/service_inspectors/dce_rpc/dce_tcp_module.cc index 1e8d1fd41..335ff0fcc 100644 --- a/src/service_inspectors/dce_rpc/dce_tcp_module.cc +++ b/src/service_inspectors/dce_rpc/dce_tcp_module.cc @@ -79,7 +79,7 @@ static const PegInfo dce2_tcp_pegs[] = { CountType::SUM, "bind_acks", "total connection-oriented binds acks" }, { CountType::SUM, "alter_contexts", "total connection-oriented alter contexts" }, { CountType::SUM, "alter_context_responses", - "total connection-oriented alter context responses" }, + "total connection-oriented alter context responses" }, { CountType::SUM, "bind_naks", "total connection-oriented bind naks" }, { CountType::SUM, "requests", "total connection-oriented requests" }, { CountType::SUM, "responses", "total connection-oriented responses" }, @@ -90,27 +90,27 @@ static const PegInfo dce2_tcp_pegs[] = { CountType::SUM, "shutdowns", "total connection-oriented shutdowns" }, { CountType::SUM, "rejects", "total connection-oriented rejects" }, { CountType::SUM, "ms_rpc_http_pdus", - "total connection-oriented MS requests to send RPC over HTTP" }, + "total connection-oriented MS requests to send RPC over HTTP" }, { CountType::SUM, "other_requests", "total connection-oriented other requests" }, { CountType::SUM, "other_responses", "total connection-oriented other responses" }, { CountType::SUM, "request_fragments", "total connection-oriented request fragments" }, { CountType::SUM, "response_fragments", "total connection-oriented response fragments" }, { CountType::SUM, "client_max_fragment_size", - "connection-oriented client maximum fragment size" }, + "connection-oriented client maximum fragment size" }, { CountType::SUM, "client_min_fragment_size", - "connection-oriented client minimum fragment size" }, + "connection-oriented client minimum fragment size" }, { CountType::SUM, "client_segs_reassembled", - "total connection-oriented client segments reassembled" }, + "total connection-oriented client segments reassembled" }, { CountType::SUM, "client_frags_reassembled", - "total connection-oriented client fragments reassembled" }, + "total connection-oriented client fragments reassembled" }, { CountType::SUM, "server_max_fragment_size", - "connection-oriented server maximum fragment size" }, + "connection-oriented server maximum fragment size" }, { CountType::SUM, "server_min_fragment_size", - "connection-oriented server minimum fragment size" }, + "connection-oriented server minimum fragment size" }, { CountType::SUM, "server_segs_reassembled", - "total connection-oriented server segments reassembled" }, + "total connection-oriented server segments reassembled" }, { CountType::SUM, "server_frags_reassembled", - "total connection-oriented server fragments reassembled" }, + "total connection-oriented server fragments reassembled" }, { CountType::SUM, "tcp_sessions", "total tcp sessions" }, { CountType::SUM, "tcp_expected_sessions", "total tcp dynamic endpoint expected sessions" }, { CountType::SUM, "tcp_expected_realized", "total tcp dynamic endpoint expected realized sessions" }, @@ -120,7 +120,7 @@ static const PegInfo dce2_tcp_pegs[] = { CountType::END, nullptr, nullptr } }; -Dce2TcpModule::Dce2TcpModule() : Module(DCE2_TCP_NAME, DCE2_TCP_HELP, s_params) +Dce2TcpModule::Dce2TcpModule() : Module(DCE2_TCP_NAME, DCE2_TCP_HELP, s_params) { } diff --git a/src/service_inspectors/dce_rpc/dce_tcp_module.h b/src/service_inspectors/dce_rpc/dce_tcp_module.h index 74021805a..dee0440e4 100644 --- a/src/service_inspectors/dce_rpc/dce_tcp_module.h +++ b/src/service_inspectors/dce_rpc/dce_tcp_module.h @@ -31,7 +31,7 @@ struct SnortConfig; struct dce2TcpProtoConf { - dce2CoProtoConf common; + dce2CoProtoConf common = {}; }; class Dce2TcpModule : public snort::Module diff --git a/src/service_inspectors/dce_rpc/dce_tcp_paf.cc b/src/service_inspectors/dce_rpc/dce_tcp_paf.cc index 1c3384d77..aaecd9dba 100644 --- a/src/service_inspectors/dce_rpc/dce_tcp_paf.cc +++ b/src/service_inspectors/dce_rpc/dce_tcp_paf.cc @@ -30,7 +30,7 @@ using namespace snort; -Dce2TcpSplitter::Dce2TcpSplitter(bool c2s) : StreamSplitter(c2s) +Dce2TcpSplitter::Dce2TcpSplitter(bool c2s) : StreamSplitter(c2s) { state.paf_state = DCE2_PAF_TCP_STATES__0; state.byte_order = DCERPC_BO_FLAG__NONE; @@ -53,12 +53,12 @@ StreamSplitter::Status Dce2TcpSplitter::scan( { DCE2_TcpSsnData* sd = get_dce2_tcp_session_data(pkt->flow); - if (dce2_paf_abort((DCE2_SsnData*) sd)) + if (dce2_paf_abort((DCE2_SsnData*)sd)) return StreamSplitter::ABORT; uint32_t n = 0; uint32_t new_fp = 0; - int start_state = (uint8_t) state.paf_state; + int start_state = (uint8_t)state.paf_state; int num_requests = 0; while (n < len) @@ -108,7 +108,8 @@ StreamSplitter::Status Dce2TcpSplitter::scan( if (state.frag_len < sizeof(DceRpcCoHdr)) { if (sd) - dce_alert(GID_DCE2, DCE2_CO_FRAG_LEN_LT_HDR, (dce2CommonStats*)&dce2_tcp_stats, *(DCE2_SsnData*)sd); + dce_alert(GID_DCE2, DCE2_CO_FRAG_LEN_LT_HDR, (dce2CommonStats*)&dce2_tcp_stats, + *(DCE2_SsnData*)sd); return StreamSplitter::ABORT; } @@ -117,7 +118,7 @@ StreamSplitter::Status Dce2TcpSplitter::scan( state.autodetected = true; /* Increment n here so we can continue */ - n += state.frag_len - (uint8_t) state.paf_state; + n += state.frag_len - (uint8_t)state.paf_state; num_requests++; /* Might have multiple PDUs in one segment. If the last PDU is partial, * flush just before it */ @@ -142,3 +143,4 @@ StreamSplitter::Status Dce2TcpSplitter::scan( return StreamSplitter::SEARCH; } + diff --git a/src/service_inspectors/dce_rpc/dce_tcp_paf.h b/src/service_inspectors/dce_rpc/dce_tcp_paf.h index a1c470f75..82ab251fc 100644 --- a/src/service_inspectors/dce_rpc/dce_tcp_paf.h +++ b/src/service_inspectors/dce_rpc/dce_tcp_paf.h @@ -51,7 +51,7 @@ struct DCE2_PafTcpData class Dce2TcpSplitter : public snort::StreamSplitter { public: - Dce2TcpSplitter(bool c2s); + explicit Dce2TcpSplitter(bool c2s); Status scan(snort::Packet*, const uint8_t* data, uint32_t len, uint32_t flags, uint32_t* fp) override; diff --git a/src/service_inspectors/dce_rpc/dce_udp.cc b/src/service_inspectors/dce_rpc/dce_udp.cc index e6315389f..a3b606319 100644 --- a/src/service_inspectors/dce_rpc/dce_udp.cc +++ b/src/service_inspectors/dce_rpc/dce_udp.cc @@ -50,10 +50,10 @@ static void DCE2_ClCleanTracker(DCE2_ClTracker* clt) //------------------------------------------------------------------------- // class stuff //------------------------------------------------------------------------- -Dce2UdpFlowData::Dce2UdpFlowData() : FlowData(inspector_id) +Dce2UdpFlowData::Dce2UdpFlowData() : FlowData(inspector_id) { dce2_udp_stats.concurrent_sessions++; - if(dce2_udp_stats.max_concurrent_sessions < dce2_udp_stats.concurrent_sessions) + if (dce2_udp_stats.max_concurrent_sessions < dce2_udp_stats.concurrent_sessions) dce2_udp_stats.max_concurrent_sessions = dce2_udp_stats.concurrent_sessions; } @@ -108,7 +108,7 @@ static DCE2_UdpSsnData* dce2_handle_udp_session(Packet* p, dce2UdpProtoConf* con class Dce2Udp : public Inspector { public: - Dce2Udp(const dce2UdpProtoConf&); + explicit Dce2Udp(const dce2UdpProtoConf&); void show(const SnortConfig*) const override; void eval(Packet*) override; void clear(Packet*) override; @@ -117,9 +117,8 @@ private: dce2UdpProtoConf config; }; -Dce2Udp::Dce2Udp(const dce2UdpProtoConf& pc) +Dce2Udp::Dce2Udp(const dce2UdpProtoConf& pc) : config(pc) { - config = pc; } void Dce2Udp::show(const SnortConfig*) const @@ -163,7 +162,6 @@ void Dce2Udp::clear(Packet* p) { DCE2_ResetRopts(&dce2_udp_sess->sd, p); } - } //------------------------------------------------------------------------- diff --git a/src/service_inspectors/dce_rpc/dce_udp.h b/src/service_inspectors/dce_rpc/dce_udp.h index eca90f7d1..c491afa7e 100644 --- a/src/service_inspectors/dce_rpc/dce_udp.h +++ b/src/service_inspectors/dce_rpc/dce_udp.h @@ -196,7 +196,7 @@ public: { inspector_id = snort::FlowData::create_flow_data_id(); } static unsigned inspector_id; - DCE2_UdpSsnData dce2_udp_session; + DCE2_UdpSsnData dce2_udp_session = {}; }; DCE2_UdpSsnData* get_dce2_udp_session_data(snort::Flow*); diff --git a/src/service_inspectors/dce_rpc/dce_udp_module.cc b/src/service_inspectors/dce_rpc/dce_udp_module.cc index b3c17c39a..c4990cf54 100644 --- a/src/service_inspectors/dce_rpc/dce_udp_module.cc +++ b/src/service_inspectors/dce_rpc/dce_udp_module.cc @@ -85,7 +85,7 @@ static const PegInfo dce2_udp_pegs[] = { CountType::END, nullptr, nullptr } }; -Dce2UdpModule::Dce2UdpModule() : Module(DCE2_UDP_NAME, DCE2_UDP_HELP, s_params) +Dce2UdpModule::Dce2UdpModule() : Module(DCE2_UDP_NAME, DCE2_UDP_HELP, s_params), config {} { } void Dce2UdpModule::set_trace(const Trace* trace) const diff --git a/src/service_inspectors/dce_rpc/dce_udp_module.h b/src/service_inspectors/dce_rpc/dce_udp_module.h index 170f485e4..3c53050b8 100644 --- a/src/service_inspectors/dce_rpc/dce_udp_module.h +++ b/src/service_inspectors/dce_rpc/dce_udp_module.h @@ -44,7 +44,7 @@ extern THREAD_LOCAL const snort::Trace* dce_udp_trace; struct dce2UdpProtoConf { - dce2CommonProtoConf common; + dce2CommonProtoConf common = {}; }; class Dce2UdpModule : public snort::Module diff --git a/src/service_inspectors/dce_rpc/dce_udp_processing.cc b/src/service_inspectors/dce_rpc/dce_udp_processing.cc index 3c6643a1a..735421bec 100644 --- a/src/service_inspectors/dce_rpc/dce_udp_processing.cc +++ b/src/service_inspectors/dce_rpc/dce_udp_processing.cc @@ -1,6 +1,5 @@ //-------------------------------------------------------------------------- // Copyright (C) 2014-2023 Cisco and/or its affiliates. All rights reserved. -// Copyright (C) 2008-2013 Sourcefire, Inc. // // 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 @@ -538,10 +537,10 @@ static int DCE2_ClFragCompare(const void* a, const void* b) static void DCE2_ClFragReassemble( DCE2_SsnData* sd, DCE2_ClActTracker* at, const DceRpcClHdr* cl_hdr) { - uint8_t dce2_cl_rbuf[IP_MAXPACKET]; + auto dce2_cl_rbuf = std::make_unique(IP_MAXPACKET); DCE2_ClFragTracker* ft = &at->frag_tracker; - const uint8_t* rdata = dce2_cl_rbuf; - uint16_t rlen = sizeof(dce2_cl_rbuf); + const uint8_t* rdata = dce2_cl_rbuf.get(); + uint16_t rlen = IP_MAXPACKET; DCE2_ClFragNode* fnode; uint32_t stub_len = 0; @@ -558,7 +557,7 @@ static void DCE2_ClFragReassemble( } Packet* rpkt = DCE2_GetRpkt(DetectionEngine::get_current_packet(), - DCE2_RPKT_TYPE__UDP_CL_FRAG, dce2_cl_rbuf, stub_len); + DCE2_RPKT_TYPE__UDP_CL_FRAG, dce2_cl_rbuf.get(), stub_len); if ( !rpkt ) return; diff --git a/src/service_inspectors/dce_rpc/dce_utils.cc b/src/service_inspectors/dce_rpc/dce_utils.cc index cfd7bfc8e..ffa787c27 100644 --- a/src/service_inspectors/dce_rpc/dce_utils.cc +++ b/src/service_inspectors/dce_rpc/dce_utils.cc @@ -182,7 +182,6 @@ const char* DCE2_UuidToStr( return uuid_buf; } - DCE2_Buffer* DCE2_BufferNew(uint32_t initial_size, uint32_t min_add_size) { DCE2_Buffer* buf = (DCE2_Buffer*)snort_calloc(sizeof(DCE2_Buffer)); diff --git a/src/service_inspectors/dce_rpc/dce_utils.h b/src/service_inspectors/dce_rpc/dce_utils.h index 64c3de039..c3ce017ab 100644 --- a/src/service_inspectors/dce_rpc/dce_utils.h +++ b/src/service_inspectors/dce_rpc/dce_utils.h @@ -1,6 +1,5 @@ -//-------------------------------------------------------------------------- +//-------------------------------------------------------------------------/ // Copyright (C) 2014-2023 Cisco and/or its affiliates. All rights reserved. -// Copyright (C) 2008-2013 Sourcefire, Inc. // // 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 @@ -136,11 +135,10 @@ void DCE2_BufferDestroy(DCE2_Buffer* buf); #define DCE2_UUID_BUF_SIZE 50 const char* DCE2_UuidToStr( - const Uuid*, DceRpcBoFlag, char (&buf)[DCE2_UUID_BUF_SIZE]); + const Uuid*, DceRpcBoFlag, char (& buf)[DCE2_UUID_BUF_SIZE]); // Determines if the character passed in is a character that // the inspector considers a to be a space character. - inline bool DCE2_IsSpaceChar(const char c) { if (isspace((int)c)) @@ -151,7 +149,6 @@ inline bool DCE2_IsSpaceChar(const char c) // Determines if the character passed in is a character that // the inspector considers a to be an end of configuration // character. - inline bool DCE2_IsConfigEndChar(const char c) { if (c == DCE2_CFG_TOK__END) @@ -161,7 +158,6 @@ inline bool DCE2_IsConfigEndChar(const char c) // Prunes whitespace surrounding string. // String must be 0 terminated. - inline char* DCE2_PruneWhiteSpace(char* str) { char* end; @@ -186,7 +182,6 @@ inline char* DCE2_PruneWhiteSpace(char* str) // Checks if string is null, empty or just spaces. // String must be 0 terminated. - inline bool DCE2_IsEmptyStr(char* str) { char* end; @@ -386,3 +381,4 @@ inline void dce2_move(const uint8_t*& data_ptr, int64_t& data_len, int amount) } #endif + diff --git a/src/service_inspectors/dce_rpc/dev_notes.txt b/src/service_inspectors/dce_rpc/dev_notes.txt index 6942429e4..da0d1d8ce 100644 --- a/src/service_inspectors/dce_rpc/dev_notes.txt +++ b/src/service_inspectors/dce_rpc/dev_notes.txt @@ -2,7 +2,7 @@ This directory contains all the files related to DCE-RPC protocol processing. DCE is supported over TCP/IP, UDP, SMB and HTTP v1 Proxy and Server. -The DCE-RPC preprocessor is split into four inspectors - one for each +The DCE-RPC inspector is split into four inspectors - one for each transport. This includes the configuration as well as the inspector modules. @@ -25,18 +25,13 @@ inspectors. These inspectors only serve to locate the 'tunnel' setup content. If/when the setup content is located, the session is transferred to the DCE TCP inspector. -The SMB inspector supports version 1 and version 2 of the protocol. -It processes relevant messages and inspects file transferred over this transport. +The SMB inspector supports version 1 and version 2 of the protocol. +It processes relevant messages and inspects file transferred over this transport. For SMBv2, it supports TCP as transport and it also supports multiple File transfer -on single SMB2 connection. -The SMB inspector implements base class for smb flow data, -which all versions now inherits and implements. SMBv1 and SMBv2 code is completely -segregated, maintaining common code in separate file to reduce redundancy. -The common functionality used by both versions are in dce_smb_common files. -SMBv2 specific trackers are in there own file now. +on single SMB2 connection or multiple SMB2 connection from the same source IP. The inspector eval function checks for the presence of SMB flow data in the flow, if not present, it creates an SMB flow data according to detected version, otherwise calls the respective process function. The process functions processes the commands according to respective versions and when -file transfer is detected, it calls file_flow process(). \ No newline at end of file +file transfer is detected, it calls file_flow process(). diff --git a/src/service_inspectors/dce_rpc/ips_dce_iface.cc b/src/service_inspectors/dce_rpc/ips_dce_iface.cc index a681a4137..cf891dc83 100644 --- a/src/service_inspectors/dce_rpc/ips_dce_iface.cc +++ b/src/service_inspectors/dce_rpc/ips_dce_iface.cc @@ -231,8 +231,8 @@ public: private: const RangeCheck version; - const bool any_frag; - const Uuid uuid; + const bool any_frag = false; + const Uuid uuid = {}; PatternMatchData pmd; PatternMatchData alt_pmd; }; @@ -249,7 +249,7 @@ Dce2IfaceOption::~Dce2IfaceOption() } } -static char* make_pattern_buffer( const Uuid &uuid, DceRpcBoFlag type ) +static char* make_pattern_buffer(const Uuid& uuid, DceRpcBoFlag type) { int index = 0; char* pattern_buf = (char*)snort_alloc(sizeof(Uuid)); @@ -314,9 +314,9 @@ PatternMatchData* Dce2IfaceOption::get_pattern(SnortProtocolId snort_protocol_id } else if (snort_protocol_id == SNORT_PROTO_UDP) { - pmd.pattern_buf = make_pattern_buffer( uuid, DCERPC_BO_FLAG__LITTLE_ENDIAN ); + pmd.pattern_buf = make_pattern_buffer(uuid, DCERPC_BO_FLAG__LITTLE_ENDIAN); pmd.pattern_size = sizeof(Uuid); - alt_pmd.pattern_buf = make_pattern_buffer( uuid, DCERPC_BO_FLAG__BIG_ENDIAN ); + alt_pmd.pattern_buf = make_pattern_buffer(uuid, DCERPC_BO_FLAG__BIG_ENDIAN); alt_pmd.pattern_size = sizeof(Uuid); return &pmd; @@ -454,7 +454,7 @@ static const Parameter s_params[] = class Dce2IfaceModule : public Module { public: - Dce2IfaceModule() : Module(s_name, s_help, s_params) { } + Dce2IfaceModule() : Module(s_name, s_help, s_params) { } bool begin(const char*, int, SnortConfig*) override; bool set(const char*, Value&, SnortConfig*) override; diff --git a/src/service_inspectors/dce_rpc/ips_dce_opnum.cc b/src/service_inspectors/dce_rpc/ips_dce_opnum.cc index 31c264ac6..5a7b318c3 100644 --- a/src/service_inspectors/dce_rpc/ips_dce_opnum.cc +++ b/src/service_inspectors/dce_rpc/ips_dce_opnum.cc @@ -342,8 +342,8 @@ static DCE2_Ret DCE2_OpnumParse(char* args, DCE2_Opnum* opnum) class Dce2OpnumOption : public IpsOption { public: - Dce2OpnumOption(const DCE2_Opnum& src_opnum) : IpsOption(s_name) - { opnum = src_opnum; } + explicit Dce2OpnumOption(const DCE2_Opnum& src_opnum) : IpsOption(s_name), opnum(src_opnum) + { } uint32_t hash() const override; bool operator==(const IpsOption&) const override; EvalStatus eval(Cursor&, Packet*) override; @@ -462,7 +462,7 @@ static const Parameter s_params[] = class Dce2OpnumModule : public Module { public: - Dce2OpnumModule() : Module(s_name, s_help, s_params) + Dce2OpnumModule() : Module(s_name, s_help, s_params) { memset(&opnum, 0, sizeof(opnum)); } bool begin(const char*, int, SnortConfig*) override; @@ -489,7 +489,8 @@ bool Dce2OpnumModule::begin(const char*, int, SnortConfig*) bool Dce2OpnumModule::set(const char*, Value& v, SnortConfig*) { - assert(v.is("~")); + if ( !v.is("~") ) + return false; std::string tok = v.get_unquoted_string(); char* s = snort_strdup(tok.c_str()); DCE2_Ret status = DCE2_OpnumParse(s, &opnum); diff --git a/src/service_inspectors/dce_rpc/ips_dce_stub_data.cc b/src/service_inspectors/dce_rpc/ips_dce_stub_data.cc index eba1dcba9..2c0269de2 100644 --- a/src/service_inspectors/dce_rpc/ips_dce_stub_data.cc +++ b/src/service_inspectors/dce_rpc/ips_dce_stub_data.cc @@ -46,7 +46,7 @@ static THREAD_LOCAL ProfileStats dce2_stub_data_perf_stats; class Dce2StubDataOption : public IpsOption { public: - Dce2StubDataOption() : IpsOption(s_name) { } + Dce2StubDataOption() : IpsOption(s_name) { } uint32_t hash() const override; bool operator==(const IpsOption&) const override; @@ -109,7 +109,7 @@ IpsOption::EvalStatus Dce2StubDataOption::eval(Cursor& c, Packet* p) class Dce2StubDataModule : public Module { public: - Dce2StubDataModule() : Module(s_name, s_help) { } + Dce2StubDataModule() : Module(s_name, s_help) { } ProfileStats* get_profile() const override; Usage get_usage() const override diff --git a/src/service_inspectors/dce_rpc/smb_common.h b/src/service_inspectors/dce_rpc/smb_common.h index 1975b8184..3331160a3 100644 --- a/src/service_inspectors/dce_rpc/smb_common.h +++ b/src/service_inspectors/dce_rpc/smb_common.h @@ -397,7 +397,7 @@ inline uint32_t NbssLen(const NbssHdr* nb) } // NbssLen2 should be used by SMB2/SMB3 -inline uint32_t NbssLen2(const NbssHdr *nb) +inline uint32_t NbssLen2(const NbssHdr* nb) { // The Length is 3 bytes. [MS-SMB2] 2.1 Transport // The left operand of '<<' is a garbage value diff --git a/src/service_inspectors/dce_rpc/smb_message.cc b/src/service_inspectors/dce_rpc/smb_message.cc index 419677881..e2b273adf 100644 --- a/src/service_inspectors/dce_rpc/smb_message.cc +++ b/src/service_inspectors/dce_rpc/smb_message.cc @@ -24,12 +24,15 @@ #include "smb_message.h" +#include "dce_smb.h" #include "dce_smb_commands.h" #include "dce_smb_module.h" #include "dce_smb_paf.h" #include "dce_smb_transaction.h" +#include "dce_smb2_utils.h" #include "detection/detect.h" #include "file_api/file_service.h" +#include "memory/memory_cap.h" #include "packet_io/active.h" #include "protocols/packet.h" #include "trace/trace_api.h" @@ -803,9 +806,9 @@ static void DCE2_SmbProcessCommand(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr com_info.cmd_size = 0; com_info.byte_count = 0; DCE2_SmbCheckCommand(ssd, smb_hdr, smb_com, nb_ptr, nb_len, com_info); - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, - DetectionEngine::get_current_packet(), - "Processing command: %s (0x%02X)\n", get_smb_com_string(smb_com), smb_com); + SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, + DetectionEngine::get_current_packet(), + "Processing command: %s (0x%02X)\n", get_smb_com_string(smb_com), smb_com); // Note that even if the command shouldn't be processed, some of // the command functions need to know and do cleanup or some other @@ -830,8 +833,8 @@ static void DCE2_SmbProcessCommand(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr break; SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_DEBUG_LEVEL, - DetectionEngine::get_current_packet(), - "Chained SMB command: %s\n", get_smb_com_string(smb_com2)); + DetectionEngine::get_current_packet(), + "Chained SMB command: %s\n", get_smb_com_string(smb_com2)); num_chained++; if (DCE2_ScSmbMaxChain((dce2SmbProtoConf*)ssd->sd.config) && @@ -1012,7 +1015,7 @@ static void DCE2_SmbProcessCommand(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr * Function: DCE2_SmbInspect() * * Purpose: - * Determines whether the SMB command is something the inspector + * Determines whether the SMB command is something the preprocessor * needs to inspect. * This function returns a DCE2_SmbRequestTracker which tracks command * requests / responses. @@ -1294,6 +1297,71 @@ void DCE2_SmbDataFree(DCE2_SmbSsnData* ssd) } } +Dce2SmbFlowData::Dce2SmbFlowData() : FlowData(inspector_id) +{ + dce2_smb_stats.concurrent_sessions++; + if (dce2_smb_stats.max_concurrent_sessions < dce2_smb_stats.concurrent_sessions) + dce2_smb_stats.max_concurrent_sessions = dce2_smb_stats.concurrent_sessions; + smb_version = DCE2_SMB_VERSION_NULL; + dce2_smb_session_data = nullptr; +} + +Dce2SmbFlowData::~Dce2SmbFlowData() +{ + if (DCE2_SMB_VERSION_1 == smb_version) + { + DCE2_SmbDataFree((DCE2_SmbSsnData*)dce2_smb_session_data); + delete (DCE2_SmbSsnData*)dce2_smb_session_data; + } + else + { + delete (DCE2_Smb2SsnData*)dce2_smb_session_data; + } + assert(dce2_smb_stats.concurrent_sessions > 0); + dce2_smb_stats.concurrent_sessions--; +} + +unsigned Dce2SmbFlowData::inspector_id = 0; + +static inline DCE2_SmbSsnData* set_new_dce2_smb_session(Packet* p) +{ + Dce2SmbFlowData* fd = new Dce2SmbFlowData; + fd->smb_version = DCE2_SMB_VERSION_1; + fd->dce2_smb_session_data = new DCE2_SmbSsnData(); + p->flow->set_flow_data(fd); + return (DCE2_SmbSsnData*)(fd->dce2_smb_session_data); +} + +DCE2_SmbSsnData* dce2_create_new_smb_session(Packet* p, dce2SmbProtoConf* config) +{ + DCE2_SmbSsnData* 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_v1 = 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, p); + + dce2_smb_stats.smb_sessions++; + dce2_smb_stats.total_smb1_sessions++; + + 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.config = (void*)config; + } + + return dce2_smb_sess; +} + /******************************************************************** * Function: DCE2_NbssHdrChecks() * @@ -1554,15 +1622,15 @@ void DCE2_Smb1Process(DCE2_SmbSsnData* ssd) if (!DCE2_GcIsLegacyMode((dce2SmbProtoConf*)ssd->sd.config)) { // Upgrade connection to SMBv2 - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, - p, "upgrading to smb2 session\n"); + debug_log(dce_smb_trace, p, "upgrading to smb2 session\n"); + dce2SmbProtoConf* config = (dce2SmbProtoConf*)ssd->sd.config; Dce2SmbFlowData* fd = (Dce2SmbFlowData*)p->flow->get_flow_data( Dce2SmbFlowData::inspector_id); - if (fd) - { - Dce2SmbSessionData* dce2_smb2_sess = fd->upgrade(p); - dce2_smb2_sess->process(); - } + p->flow->free_flow_data(fd); + DCE2_Smb2SsnData* dce2_smb2_sess = dce2_create_new_smb2_session(p, config); + DCE2_Smb2Process(dce2_smb2_sess); + if (!dce2_detected) + DCE2_Detect(&dce2_smb2_sess->sd); } else ssd->sd.flags |= DCE2_SSN_FLAG__SMB2; @@ -1573,8 +1641,7 @@ void DCE2_Smb1Process(DCE2_SmbSsnData* ssd) rtracker = DCE2_SmbInspect(ssd, smb_hdr); if (rtracker == nullptr) { - SMB_DEBUG(dce_smb_trace, DEFAULT_TRACE_OPTION_ID, TRACE_INFO_LEVEL, - p, "Not inspecting SMB packet.\n"); + debug_log(dce_smb_trace, p, "Not inspecting SMB packet.\n"); if (DCE2_BufferIsEmpty(*seg_buf)) { @@ -2489,3 +2556,63 @@ void DCE2_SmbInitGlobals() } } +/* smb2 Functions */ + +static inline DCE2_Smb2SsnData* set_new_dce2_smb2_session(Packet* p) +{ + Dce2SmbFlowData* fd = new Dce2SmbFlowData; + fd->smb_version = DCE2_SMB_VERSION_2; + fd->dce2_smb_session_data = new DCE2_Smb2SsnData(); + + p->flow->set_flow_data(fd); + return((DCE2_Smb2SsnData*)fd->dce2_smb_session_data); +} + +DCE2_Smb2SsnData* dce2_create_new_smb2_session(Packet* p, dce2SmbProtoConf* config) +{ + DCE2_Smb2SsnData* dce2_smb2_sess = set_new_dce2_smb2_session(p); + if ( dce2_smb2_sess ) + { + dce2_smb2_sess->sd.flags |= DCE2_SSN_FLAG__SMB2; + dce2_smb2_sess->dialect_index = DCE2_SENTINEL; + + DCE2_ResetRopts(&dce2_smb2_sess->sd, p); + + dce2_smb_stats.smb_sessions++; + dce2_smb_stats.total_smb2_sessions++; + + dce2_smb2_sess->sd.trans = DCE2_TRANS_TYPE__SMB; + dce2_smb2_sess->sd.server_policy = config->common.policy; + dce2_smb2_sess->sd.client_policy = DCE2_POLICY__WINXP; + dce2_smb2_sess->sd.config = (void*)config; + dce2_smb2_sess->max_outstanding_requests = DCE2_ScSmbMaxCredit(config); + } + + return dce2_smb2_sess; +} + +DCE2_SsnData* get_dce2_session_data(snort::Flow* flow) +{ + Dce2SmbFlowData* fd = (Dce2SmbFlowData*)flow->get_flow_data(Dce2SmbFlowData::inspector_id); + if (fd and fd->dce2_smb_session_data) + return (fd->smb_version == DCE2_SMB_VERSION_1) ? + (DCE2_SsnData*)(&((DCE2_SmbSsnData*)fd->dce2_smb_session_data)->sd) : + (DCE2_SsnData*)(&((DCE2_Smb2SsnData*)fd->dce2_smb_session_data)->sd); + else + return nullptr; +} + +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 and fd->dce2_smb_session_data) + return (fd->smb_version == DCE2_SMB_VERSION_1) ? + DCE2_SmbSetRdata((DCE2_SmbSsnData*)fd->dce2_smb_session_data, nb_ptr, co_len): + (((DCE2_Smb2SsnData*)fd->dce2_smb_session_data)->set_reassembled_data(nb_ptr, co_len)); + } +} + diff --git a/src/service_inspectors/dce_rpc/smb_message.h b/src/service_inspectors/dce_rpc/smb_message.h index 3b786b6a8..2f6e9f9bd 100644 --- a/src/service_inspectors/dce_rpc/smb_message.h +++ b/src/service_inspectors/dce_rpc/smb_message.h @@ -152,7 +152,7 @@ inline uint16_t SmbCloseReqFid(const SmbCloseReq* req) ********************************************************************/ struct SmbDeleteReq /* smb_wct = 1 */ { - uint8_t smb_wct; + uint8_t smb_wct; uint16_t smb_search_attrs; uint16_t smb_bcc; }; @@ -489,7 +489,7 @@ inline uint64_t SmbReadAndXReqOffset(const SmbReadAndXExtReq* req) return (uint64_t)snort::alignedNtohl(&req->smb_offset); return (uint64_t)snort::alignedNtohl(&req->smb_off_high) << 32 - | (uint64_t)snort::alignedNtohl(&req->smb_offset); + | (uint64_t)snort::alignedNtohl(&req->smb_offset); } inline uint16_t SmbReadAndXRespDataOff(const SmbReadAndXResp* req) @@ -500,7 +500,7 @@ inline uint16_t SmbReadAndXRespDataOff(const SmbReadAndXResp* req) inline uint32_t SmbReadAndXRespDataCnt(const SmbReadAndXResp* resp) { return (uint32_t)snort::alignedNtohs(&resp->smb_dsize_high) << 16 - | (uint32_t)snort::alignedNtohs(&resp->smb_dsize); + | (uint32_t)snort::alignedNtohs(&resp->smb_dsize); } /******************************************************************** @@ -583,13 +583,13 @@ inline uint64_t SmbWriteAndXReqOffset(const SmbWriteAndXExtReq* req) return (uint64_t)snort::alignedNtohl(&req->smb_offset); return (uint64_t)snort::alignedNtohl(&req->smb_off_high) << 32 - | (uint64_t)snort::alignedNtohl(&req->smb_offset); + | (uint64_t)snort::alignedNtohl(&req->smb_offset); } inline uint32_t SmbWriteAndXReqDataCnt(const SmbWriteAndXReq* req) { return (uint32_t)snort::alignedNtohs(&req->smb_dsize_high) << 16 - | (uint32_t)snort::alignedNtohs(&req->smb_dsize); + | (uint32_t)snort::alignedNtohs(&req->smb_dsize); } inline uint16_t SmbWriteAndXReqWriteMode(const SmbWriteAndXReq* req) @@ -2033,7 +2033,7 @@ inline uint64_t SmbReadRawReqOffset(const SmbReadRawExtReq* req) return (uint64_t)snort::alignedNtohl(&req->smb_offset); return (uint64_t)snort::alignedNtohl(&req->smb_off_high) << 32 - | (uint64_t)snort::alignedNtohl(&req->smb_offset); + | (uint64_t)snort::alignedNtohl(&req->smb_offset); } /******************************************************************** @@ -2112,7 +2112,7 @@ inline uint64_t SmbWriteRawReqOffset(const SmbWriteRawExtReq* req) return (uint64_t)snort::alignedNtohl(&req->smb_offset); return (uint64_t)snort::alignedNtohl(&req->smb_off_high) << 32 | - (uint64_t)snort::alignedNtohl(&req->smb_offset); + (uint64_t)snort::alignedNtohl(&req->smb_offset); } inline uint16_t SmbWriteRawInterimRespRemaining(const SmbWriteRawInterimResp* resp) @@ -2190,8 +2190,12 @@ inline uint16_t SmbWriteAndCloseRespCount(const SmbWriteAndCloseResp* resp) #pragma pack() +void DCE2_SmbInitGlobals(); void DCE2_Smb1Process(struct DCE2_SmbSsnData*); +struct DCE2_SmbSsnData* dce2_create_new_smb_session(snort::Packet*, struct dce2SmbProtoConf*); +struct DCE2_Smb2SsnData* dce2_create_new_smb2_session(snort::Packet*, struct dce2SmbProtoConf*); void DCE2_SmbDataFree(DCE2_SmbSsnData*); +void set_smb_reassembled_data(uint8_t* nb_ptr, uint16_t co_len); #endif