rules.h
signature.h
treenodes.h
+ pattern_match_data.h
)
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
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;
FileFlows::~FileFlows()
{
- std::lock_guard<std::mutex> guard(file_flow_context_mutex);
FileCache* file_cache = FileService::get_file_cache();
assert(file_cache);
uint64_t file_id = 0;
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 )
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)
/* 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;
}
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;
}
}
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;
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);
{ 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
{
PegCount cache_replaces;
PegCount cache_max;
PegCount cache_prunes;
+ PegCount cache_removes;
};
template<typename Key, typename Value, typename Hash>
// 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<std::pair<Key, Value>>&);
return false;
}
+template<typename Key, typename Value, typename Hash>
+bool LruCacheLocal<Key, Value, Hash>::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<typename Key, typename Value, typename Hash>
void LruCacheLocal<Key, Value, Hash>::get_all_values(std::vector<std::pair<Key, Value>>& kv)
{
+set(IPS_INCLUDES
+ extract.h
+)
SET( PLUGIN_LIST
ips_ack.cc
set (IPS_SOURCES
+ ${IPS_INCLUDES}
extract.cc
- extract.h
ips_classtype.cc
ips_content.cc
ips_detection_filter.cc
endif (STATIC_IPS_OPTIONS)
add_subdirectory(test)
+
+install(FILES ${IPS_INCLUDES}
+ DESTINATION "${INCLUDE_INSTALL_PATH}/ips_options/"
+)
{ 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
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
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
#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"
/* [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)
{
}
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
}
Packet* p = DetectionEngine::get_current_packet();
if (p == nullptr)
return nullptr;
+
if ( p->is_from_server() )
return &cot->srv_seg;
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);
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;
{
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)
{
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;
{
DCE2_Buffer* frag_buf = DCE2_CoGetFragBuf(&cot->frag_tracker);
Packet* p = DetectionEngine::get_current_packet();
-
if ( (p == nullptr) || p->is_from_server() )
return;
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<uint8_t*>(rpkt->data),
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
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,
#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"
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
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;
}
{
dcd->clear();
}
-
- return;
}
+
void DceContextData::clear_current_ropts(const Packet* p, DCE2_TransType trans)
{
IpsContext* context = p ? p->context : nullptr;
--- /dev/null
+//--------------------------------------------------------------------------
+// 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 <nehash4@cisco.com>
+
+// 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 <unordered_map>
+#include <vector>
+#include "dce_utils.h"
+
+#include "main/snort_types.h"
+
+template<typename Key, typename Value, typename Hash>
+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<Key, Value> > get_all_entry() = 0;
+};
+
+template<typename Key, typename Value, typename Hash>
+class DCE2_DbMap : public DCE2_Db<Key, Value, Hash>
+{
+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<Key, Value> > get_all_entry() override;
+
+private:
+ std::unordered_map<Key, Value, Hash> Map;
+ bool garbage_collection = true;
+};
+
+template<typename Key, typename Value, typename Hash>
+bool DCE2_DbMap<Key, Value, Hash>::Insert(const Key& key, Value data)
+{
+ return Map.insert(std::make_pair(key,data)).second;
+}
+
+template<typename Key, typename Value, typename Hash>
+Value DCE2_DbMap<Key, Value, Hash>::Find(const Key& key)
+{
+ auto elem = Map.find(key);
+ if (elem != Map.end())
+ return elem->second;
+ return nullptr;
+}
+
+template<typename Key, typename Value, typename Hash>
+void DCE2_DbMap<Key, Value, Hash>::Remove(const Key& key)
+{
+ auto elem = Map.find(key);
+ if (elem != Map.end())
+ {
+ if (garbage_collection)
+ delete elem->second;
+
+ Map.erase(elem->first);
+ }
+}
+
+template<typename Key, typename Value, typename Hash>
+std::vector< std::pair<Key, Value> >DCE2_DbMap<Key, Value, Hash>::get_all_entry()
+{
+ std::vector<std::pair<Key, Value> > vec;
+ std::copy(Map.begin(), Map.end(), std::back_inserter(vec));
+ return vec;
+}
+
+#endif
+
}
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,
return 0;
}
+
{
public:
DceExpSsnManager(IpProtocol p, PktType t) :
- proto(p), type(t) {}
+ proto(p), type(t) { }
virtual ~DceExpSsnManager() = default;
{
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*,
};
#endif // DCE_EXPECTED_SESSION_H
+
{ 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)
{
}
{
return (PegCount*)&dce_http_proxy_stats;
}
+
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;
}
/* 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) )
{
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
{
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;
return StreamSplitter::SEARCH;
}
-DceHttpProxySplitter::DceHttpProxySplitter(bool c2s) : StreamSplitter(c2s)
+DceHttpProxySplitter::DceHttpProxySplitter(bool c2s) : StreamSplitter(c2s)
{
cutover = false;
match_index = 0;
}
#endif
+
{ 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)
{
}
{
return (PegCount*)&dce_http_server_stats;
}
+
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;
}
#endif
+
* 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.
* 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,
if ((list == nullptr) || (n == nullptr))
return;
-
if (list->tail == nullptr)
{
list->tail = list->head = n;
* 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)
* 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.
*
********************************************************************/
* 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.
*
********************************************************************/
*
* 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 *
* 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)
* 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.
*
* 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:
*
* 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.
*
* 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)
*
* 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 *
* 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.
*
********************************************************************/
* 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.
*
********************************************************************/
* 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.
*
********************************************************************/
//--------------------------------------------------------------------------
// 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
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//--------------------------------------------------------------------------
-// dce_smb1.cc author Bhargava Jandhyala <bjandhya@cisco.com>
+// dce_smb.cc author Rashmi Pitre <rrp@cisco.com>
#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
//-------------------------------------------------------------------------
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
+};
+
--- /dev/null
+//--------------------------------------------------------------------------
+// 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 <rrp@cisco.com>
+// 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
+
+++ /dev/null
-//--------------------------------------------------------------------------
-// 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 <bjandhya@cisco.com>
-
-#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
-
#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",
"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<std::mutex> 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<std::recursive_mutex> 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;
{
//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));
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;
// 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)
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;
}
#ifndef DCE_SMB2_H
#define DCE_SMB2_H
-// This implements smb session data for SMBv2
-// Also provides SMBv2 related header structures
-
-#include <mutex>
-
+#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
{
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 */
};
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<uint64_t, DCE2_Smb2FileTracker*, std::hash<uint64_t> > DCE2_DbMapFtracker;
+typedef DCE2_DbMap<uint64_t, DCE2_Smb2RequestTracker*, std::hash<uint64_t> > 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<uint32_t, DCE2_Smb2TreeTracker*, std::hash<uint32_t> > DCE2_DbMapTtracker;
+typedef DCE2_DbMap<uint32_t, DCE2_Smb2SsnData*, std::hash<uint32_t> > 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<bool>(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<uint64_t, std::weak_ptr<DCE2_Smb2SessionTracker>, std::hash<uint64_t> > session_trackers;
+ DCE2_Smb2FileTracker* ftracker_tcp; //To keep tab of current file being transferred over TCP
+ std::unique_ptr<DCE2_Smb2LocalFileTracker> 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<DCE2_Smb2SessionTracker> 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<DCE2_Smb2SessionTracker> 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;
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 */
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 */
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 */
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 */
};
#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
#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<Dce2Smb2SessionTracker>;
-using Dce2Smb2SessionTrackerMap =
- std::unordered_map<uint64_t, Dce2Smb2SessionTrackerPtr, std::hash<uint64_t> >;
-
-using Dce2Smb2FileTrackerPtr = std::shared_ptr<Dce2Smb2FileTracker>;
-using Dce2Smb2FileTrackerMap =
- std::unordered_map<uint64_t, Dce2Smb2FileTrackerPtr, std::hash<uint64_t> >;
-
-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<uint32_t, Dce2Smb2SessionData*, std::hash<uint32_t> >;
+/* Check smb version based on smb header */
+DCE2_SmbVersion DCE2_Smb2Version(const snort::Packet* p);
#endif /* _DCE_SMB2_H_ */
--- /dev/null
+//--------------------------------------------------------------------------
+// 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 <bjandhya@cisco.com>
+// 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<DCE2_Smb2LocalFileTracker>(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<DCE2_Smb2LocalFileTracker>(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<DCE2_Smb2LocalFileTracker>(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);
+ }
+}
+
--- /dev/null
+//--------------------------------------------------------------------------
+// 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 <bjandhya@cisco.com>
+// 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
+
+++ /dev/null
-//--------------------------------------------------------------------------
-// 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 <dipandit@cisco.com>
-
-#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 <thread>
-#include "time/packet_time.h"
-
-#include <mutex>
-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<std::recursive_mutex> guard(flow->session_data_mutex);
- uint32_t current_flow_key = flow->get_flow_key();
- std::lock_guard<std::mutex> 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<std::mutex> 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<bool, Dce2Smb2SessionData*> Dce2Smb2FileTracker::update_processing_flow(
- Dce2Smb2SessionData* current_flow,Dce2Smb2SessionTrackerPtr session_tracker)
-{
- bool switched = false;
- Dce2Smb2SessionData* processing_flow = nullptr;
- std::lock_guard<std::recursive_mutex> 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<std::mutex> 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<std::recursive_mutex> 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<std::mutex> 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<std::recursive_mutex> 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<std::mutex> 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();
-}
-
+++ /dev/null
-//--------------------------------------------------------------------------
-// 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 <dipandit@cisco.com>
-
-#ifndef DCE_SMB2_FILE_H
-#define DCE_SMB2_FILE_H
-
-// This provides file tracker for SMBv2
-
-#include "dce_smb2.h"
-#include <atomic>
-
-class Dce2Smb2TreeTracker;
-using Dce2Smb2TreeTrackerPtr = std::shared_ptr<Dce2Smb2TreeTracker>;
-
-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<std::mutex> 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<uint32_t, tcp_flow_state, std::hash<uint32_t> > 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<bool, Dce2Smb2SessionData*> 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<uint64_t> file_size;
- uint64_t file_name_hash;
- char* file_name;
- FileDirection direction;
- Dce2Smb2TreeTrackerPtr parent_tree;
- std::unordered_map<uint32_t, tcp_flow_state, std::hash<uint32_t> > flow_state;
- uint64_t session_id;
- std::mutex process_file_mutex;
- std::mutex flow_state_mutex;
-};
-
-using Dce2Smb2FileTrackerPtr = std::shared_ptr<Dce2Smb2FileTracker>;
-using Dce2Smb2FileTrackerMap =
- std::unordered_map<uint64_t, Dce2Smb2FileTrackerPtr, std::hash<uint64_t> >;
-
-#endif
-
+++ /dev/null
-//--------------------------------------------------------------------------
-// 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 <bjandhya@cisco.com>
-
-#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<Dce2Smb2RequestTracker>;
-using Dce2Smb2RequestTrackerMap =
- std::unordered_map<Smb2MessageKey, Dce2Smb2RequestTrackerPtr, Smb2KeyHash>;
-
-#endif
-
+++ /dev/null
-//--------------------------------------------------------------------------
-// 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 <dipandit@cisco.com>
-
-#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 <numeric>
-
-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<std::recursive_mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<uint64_t> 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<uint64_t> 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<Dce2Smb2TreeTracker>(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<std::recursive_mutex> guard(attached_flows_mutex);
- attached_flows.clear();
-}
-
+++ /dev/null
-//--------------------------------------------------------------------------
-// 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 <dipandit@cisco.com>
-
-#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<uint64_t> missing_req_msg_ids;
- std::unordered_set<uint64_t> 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<std::mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::mutex> 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<std::mutex> guard(mid_mutex);
- std::vector<msgid_state*> 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<bool> reload_prune;
- std::atomic<bool> 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<uint32_t, msgid_state*, std::hash<uint32_t> > mid_map;
-};
-
-#endif
-
+++ /dev/null
-//--------------------------------------------------------------------------
-// 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 <bjandhya@cisco.com>
-
-#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 Key, typename Value, typename Hash, typename Eq = std::equal_to<Key>,
-typename Purgatory = std::vector<std::shared_ptr<Value> > >
-class Dce2Smb2SharedCache : public LruCacheShared<Key, Value, Hash, Eq, Purgatory>
-{
-public:
- Dce2Smb2SharedCache() = delete;
- Dce2Smb2SharedCache(const Dce2Smb2SharedCache& arg) = delete;
- Dce2Smb2SharedCache& operator=(const Dce2Smb2SharedCache& arg) = delete;
- Dce2Smb2SharedCache(const size_t initial_size) :
- LruCacheShared<Key, Value, Hash, Eq, Purgatory>(initial_size) { }
-
- using Data = std::shared_ptr<Value>;
-
- 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<std::mutex> 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<Key, Value, Hash, Eq, Purgatory>;
- 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<Smb2SessionKey, Dce2Smb2SessionTracker, Smb2KeyHash>;
-
-extern Dce2Smb2SessionCache smb2_session_cache;
-
-#endif
-
+++ /dev/null
-//--------------------------------------------------------------------------
-// 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 <dipandit@cisco.com>
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "dce_smb2_tree.h"
-
-#include "dce_smb2_session.h"
-#include <memory>
-
-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<Dce2Smb2FileTracker> ftracker = std::make_shared<Dce2Smb2FileTracker> (
- 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<Dce2Smb2RequestTracker>(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<Dce2Smb2RequestTracker>(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<Dce2Smb2RequestTracker>(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();
-}
-
+++ /dev/null
-//--------------------------------------------------------------------------
-// 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 <dipandit@cisco.com>
-
-#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<Dce2Smb2RequestTracker>;
-
-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<bool> 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<std::mutex> 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<Dce2Smb2TreeTracker>;
-using Dce2Smb2TreeTrackerMap =
- std::unordered_map<uint32_t, Dce2Smb2TreeTrackerPtr, std::hash<uint32_t> >;
-
-#endif
-
--- /dev/null
+//--------------------------------------------------------------------------
+// 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 <bjandhya@cisco.com>
+
+#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;
+}
+
--- /dev/null
+//--------------------------------------------------------------------------
+// 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 <bjandhya@cisco.com>
+// 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<typename Key, typename Value, typename Hash>
+class LruCacheLocalSmbMultiChannel : public LruCacheLocal <Key, Value, Hash>
+{
+public:
+ using LruLocal = LruCacheLocal<Key, Value, Hash>;
+ 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<Smb2SidHashKey, std::shared_ptr<DCE2_Smb2SessionTracker>,
+ 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_Smb2SessionTracker> 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_Smb2SessionTracker> 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<DCE2_Smb2SessionTracker> 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
+
//--------------------------------------------------------------------------
// 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
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);
}
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);
}
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);
}
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);
}
}
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;
}
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);
}
return DCE2_RET__SUCCESS;
}
+
#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*,
+++ /dev/null
-//--------------------------------------------------------------------------
-// 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 <dipandit@cisco.com>
-
-#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<std::mutex> 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<std::mutex> 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);
- }
- }
-}
-
+++ /dev/null
-//--------------------------------------------------------------------------
-// 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 <dipandit@cisco.com>
-
-#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
-
+++ /dev/null
-//--------------------------------------------------------------------------
-// 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 <dipandit@cisco.com>
-
-#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
-};
-
+++ /dev/null
-//--------------------------------------------------------------------------
-// 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 <dipandit@cisco.com>
-
-#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
-
#include "trace/trace.h"
#include "utils/util.h"
-#include "dce_smb_common.h"
+#include "dce_smb.h"
using namespace snort;
using namespace std;
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" },
{ 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" },
{ 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 }
};
"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 }
};
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));
}
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;
}
#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
#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,
#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
{
* 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);
* 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;
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;
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;
}
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;
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;
}
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;
}
// 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:
// 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;
}
// 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;
}
// 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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
return DCE2_RET__SUCCESS;
}
+
#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);
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;
}
}
- 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);
}
}
break;
}
- // fallthrough
+ // fallthrough
case DCE2_POLICY__WIN2003:
case DCE2_POLICY__WINXP:
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;
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;
}
}
}
- 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);
}
}
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;
{
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;
}
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)
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)
{
if (!file_flows)
return DCE2_RET__ERROR;
- std::lock_guard<std::mutex> 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;
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);
}
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);
#ifndef DCE_SMB_UTILS_H
#define DCE_SMB_UTILS_H
-#include "dce_smb1.h"
+#include "dce_smb.h"
#include "file_api/file_flows.h"
/********************************************************************
* 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);
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*);
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;
}
// class stuff
//-------------------------------------------------------------------------
Dce2Tcp::Dce2Tcp(const dce2TcpProtoConf& pc) :
- config(pc), esm(config) {}
+ config(pc), esm(config) { }
bool Dce2Tcp::configure(snort::SnortConfig* sc)
{
{
DCE2_ResetRopts(&dce2_tcp_sess->sd, p);
}
-
}
//-------------------------------------------------------------------------
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;
{ 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" },
{ 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" },
{ 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)
{
}
struct dce2TcpProtoConf
{
- dce2CoProtoConf common;
+ dce2CoProtoConf common = {};
};
class Dce2TcpModule : public snort::Module
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;
{
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)
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;
}
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 */
return StreamSplitter::SEARCH;
}
+
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;
//-------------------------------------------------------------------------
// 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;
}
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;
dce2UdpProtoConf config;
};
-Dce2Udp::Dce2Udp(const dce2UdpProtoConf& pc)
+Dce2Udp::Dce2Udp(const dce2UdpProtoConf& pc) : config(pc)
{
- config = pc;
}
void Dce2Udp::show(const SnortConfig*) const
{
DCE2_ResetRopts(&dce2_udp_sess->sd, p);
}
-
}
//-------------------------------------------------------------------------
{ 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*);
{ 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
struct dce2UdpProtoConf
{
- dce2CommonProtoConf common;
+ dce2CommonProtoConf common = {};
};
class Dce2UdpModule : public snort::Module
//--------------------------------------------------------------------------
// 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
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<uint8_t[]>(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;
}
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;
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));
-//--------------------------------------------------------------------------
+//-------------------------------------------------------------------------/
// 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
#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))
// 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)
// Prunes whitespace surrounding string.
// String must be 0 terminated.
-
inline char* DCE2_PruneWhiteSpace(char* str)
{
char* end;
// Checks if string is null, empty or just spaces.
// String must be 0 terminated.
-
inline bool DCE2_IsEmptyStr(char* str)
{
char* end;
}
#endif
+
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.
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().
private:
const RangeCheck version;
- const bool any_frag;
- const Uuid uuid;
+ const bool any_frag = false;
+ const Uuid uuid = {};
PatternMatchData pmd;
PatternMatchData alt_pmd;
};
}
}
-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));
}
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;
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;
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;
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;
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);
class Dce2StubDataOption : public IpsOption
{
public:
- Dce2StubDataOption() : IpsOption(s_name) { }
+ Dce2StubDataOption() : IpsOption(s_name) { }
uint32_t hash() const override;
bool operator==(const IpsOption&) const override;
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
}
// 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
#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"
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
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) &&
* 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.
}
}
+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()
*
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;
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))
{
}
}
+/* 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));
+ }
+}
+
********************************************************************/
struct SmbDeleteReq /* smb_wct = 1 */
{
- uint8_t smb_wct;
+ uint8_t smb_wct;
uint16_t smb_search_attrs;
uint16_t smb_bcc;
};
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)
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);
}
/********************************************************************
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)
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);
}
/********************************************************************
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)
#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