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_smb.h
dce_smb2.cc
dce_smb2.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_module.cc
DCE2_TransType get_dce2_trans_type(const Packet* p)
{
- DCE2_SmbSsnData* smb_data = get_dce2_smb_session_data(p->flow);
- DCE2_SsnData* sd = (smb_data != nullptr) ? &(smb_data->sd) : nullptr;
+ DCE2_SsnData* sd = get_dce2_session_data(p->flow);
if ((sd != nullptr) && (sd->trans == DCE2_TRANS_TYPE__SMB))
{
return DCE2_TRANS_TYPE__SMB;
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-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_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"
+
+// Callbacks
+typedef void (* DCE2_DbDataFree)(void*);
+
+template<typename Key, typename Value, typename Hash>
+class DCE2_Db
+{
+public:
+
+ virtual void Init(const DCE2_DbDataFree func) = 0;
+ virtual DCE2_Ret 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()
+ {
+ data_free = nullptr;
+ }
+
+ ~DCE2_DbMap()
+ {
+ auto it = Map.cbegin();
+ while (it != Map.cend())
+ {
+ if (data_free)
+ data_free((void*)(it->second));
+ else
+ delete it->second;
+ it = Map.erase(it);
+ }
+ }
+
+ void Init(const DCE2_DbDataFree func);
+ DCE2_Ret Insert(const Key& key, Value data);
+ Value Find(const Key& key);
+ void Remove(const Key& key);
+ int GetSize()
+ {
+ return Map.size();
+ }
+ std::vector< std::pair<Key, Value> > get_all_entry();
+
+private:
+ std::unordered_map<Key, Value, Hash> Map;
+ DCE2_DbDataFree data_free;
+};
+
+template<typename Key, typename Value, typename Hash>
+void DCE2_DbMap<Key, Value, Hash>::Init(const DCE2_DbDataFree df)
+{
+ data_free = df;
+}
+
+template<typename Key, typename Value, typename Hash>
+DCE2_Ret DCE2_DbMap<Key, Value, Hash>::Insert(const Key& key, Value data)
+{
+ Map[key] = data;
+ return DCE2_RET__SUCCESS;
+}
+
+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 (data_free)
+ data_free((void*)(elem->second));
+ else
+ 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;
+
+ for (auto& entry : Map )
+ {
+ vec.emplace_back(entry);
+ }
+
+ return vec;
+}
+#endif
#include "detection/detection_engine.h"
#include "file_api/file_service.h"
#include "protocols/packet.h"
-#include "utils/util.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_smb_utils.h"
#include "dce_smb2.h"
+#include "dce_smb2_utils.h"
using namespace snort;
void Dce2Smb::eval(Packet* p)
{
- DCE2_SmbSsnData* dce2_smb_sess;
+ 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);
assert(p->has_tcp_data());
assert(p->flow);
- dce2_smb_sess = dce2_handle_smb_session(p, &config);
-
- if (dce2_smb_sess)
+ Dce2SmbFlowData *smb_flowdata = (Dce2SmbFlowData*)p->flow->get_flow_data(Dce2SmbFlowData::inspector_id);
+ if (smb_flowdata and smb_flowdata->dce2_smb_session_data)
{
- p->packet_flags |= PKT_ALLOW_MULTIPLE_DETECT;
- dce2_detected = 0;
-
- p->endianness = new DceEndianness();
+ 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);
+ }
+ 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);
+ }
+ 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.
+ return;
+ }
+ }
- DCE2_SmbProcess(dce2_smb_sess);
+ // 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);
-
- delete p->endianness;
- p->endianness = nullptr;
}
+ else
+ {
+ DCE2_Smb2Process(dce2_smb2_sess);
+ if (!dce2_detected)
+ DCE2_Detect(&dce2_smb2_sess->sd);
+ }
+
+ delete(p->endianness);
+ p->endianness = nullptr;
}
void Dce2Smb::clear(Packet* p)
{
- DCE2_SmbSsnData* dce2_smb_sess = get_dce2_smb_session_data(p->flow);
- if ( dce2_smb_sess )
- {
- DCE2_ResetRopts(&dce2_smb_sess->sd, p);
- }
+ DCE2_SsnData* sd = get_dce2_session_data(p->flow);
+ if ( sd )
+ DCE2_ResetRopts(sd, p);
}
//-------------------------------------------------------------------------
DceContextData::init(DCE2_TRANS_TYPE__SMB);
}
+static void dce2_smb_thread_int()
+{
+ DCE2_SmbSessionCacheInit(session_cache_size);
+}
+
+static void dce_smb_thread_term()
+{
+ delete smb2_session_cache;
+}
+
static Inspector* dce2_smb_ctor(Module* m)
{
Dce2SmbModule* mod = (Dce2SmbModule*)m;
dce2SmbProtoConf config;
mod->get_data(config);
+ session_cache_size = DCE2_ScSmbMemcap(&config)/1024;
return new Dce2Smb(config);
}
"netbios-ssn",
dce2_smb_init,
nullptr, // pterm
- nullptr, // tinit
- nullptr, // tterm
+ dce2_smb_thread_int, // tinit
+ dce_smb_thread_term, // tterm
dce2_smb_ctor,
dce2_smb_dtor,
nullptr, // ssn
#ifndef DCE_SMB_H
#define DCE_SMB_H
-#include "framework/counts.h"
+#include "dce_co.h"
#include "protocols/packet.h"
#include "profiler/profiler_defs.h"
-
-#include "dce_co.h"
#include "smb_common.h"
#include "smb_message.h"
*/
PegCount smb_files_processed;
/* SMB2 stats */
- PegCount smb2_create;
- PegCount smb2_write;
- PegCount smb2_read;
- PegCount smb2_set_info;
- PegCount smb2_tree_connect;
- PegCount smb2_tree_disconnect;
- PegCount smb2_close;
+ 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_stinf;
+ 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;
};
enum DCE2_SmbVersion
{
- DCE2_SMB_VERISON_NULL,
- DCE2_SMB_VERISON_1,
- DCE2_SMB_VERISON_2
+ DCE2_SMB_VERSION_NULL,
+ DCE2_SMB_VERSION_1,
+ DCE2_SMB_VERSION_2
};
struct DCE2_SmbFileTracker
} file;
} tracker;
+ DCE2_SmbPduState smb2_pdu_state;
+
#define fid_v1 file_key.id_smb1.file_id
#define uid_v1 file_key.id_smb1.u_id
#define tid_v1 file_key.id_smb1.tree_id
struct DCE2_SmbSsnData
{
DCE2_SsnData sd; // This member must be first
-
DCE2_Policy policy;
int dialect_index;
// This is a reference to a file tracker so shouldn't be freed.
DCE2_SmbFileTracker* fapi_ftracker;
- Smb2Request* smb2_requests;
-
DCE2_SmbFileTracker* fb_ftracker;
bool block_pdus;
public:
static unsigned inspector_id;
- DCE2_SmbSsnData dce2_smb_session;
+ DCE2_SmbVersion smb_version;
+ void* dce2_smb_session_data;
};
// Used for reassembled packets
#define DCE2_MOCK_HDR_LEN__SMB_SRV \
((unsigned)(sizeof(NbssHdr) + sizeof(SmbNtHdr) + sizeof(SmbReadAndXResp)))
-DCE2_SmbSsnData* get_dce2_smb_session_data(snort::Flow*);
+DCE2_SsnData* get_dce2_session_data(snort::Flow*);
const char* get_smb_com_string(uint8_t);
#endif
#endif
#include "dce_smb2.h"
-
+#include "dce_smb2_commands.h"
#include "detection/detection_util.h"
-#include "file_api/file_flows.h"
-#include "file_api/file_service.h"
#include "main/snort_debug.h"
-#include "utils/util.h"
-
-#include "dce_smb_module.h"
-#include "dce_smb_utils.h"
using namespace snort;
-#define UNKNOWN_FILE_SIZE ~0
-#define SMB2_MAX_OUTSTANDING_REQUESTS 128
-
-// FIXIT-L port fileCache related code along with
-// DCE2_Smb2Init, DCE2_Smb2Close and DCE2_Smb2UpdateStats
-
-static void DCE2_Smb2Inspect(DCE2_SmbSsnData* ssd, const Smb2Hdr* smb_hdr,
- const uint8_t* end);
-
-static inline uint32_t Smb2Tid(const Smb2Hdr* hdr)
-{
- return alignedNtohl(&(((const Smb2SyncHdr*)hdr)->tree_id));
-}
-
-static int DCE2_Smb2TidCompare(const void* a, const void* b)
-{
- uint32_t x = (uint32_t)(uintptr_t)a;
- uint32_t y = (uint32_t)(uintptr_t)b;
-
- if (x == y)
- return 0;
-
- /* Only care about equality for finding */
- return -1;
-}
-
-static inline DCE2_Ret DCE2_Smb2InsertTid(DCE2_SmbSsnData* ssd, const uint32_t tid,
- const uint8_t share_type)
-{
- DCE2_Ret ret = DCE2_RET__ERROR;
-
- if ( (share_type == SMB2_SHARE_TYPE_DISK)and
- (ssd->max_file_depth ==
- -1 and DCE2_ScSmbFileDepth((dce2SmbProtoConf*)ssd->sd.config) == -1) )
- {
- debug_logf(dce_smb_trace, nullptr, "Not inserting TID (%u) for DISK share type "
- "as mandatory configuration max_file_depth is not present."
- "This will result in non-inspection of file data.\n", tid);
- return ret;
- }
-
- if (ssd->tids == nullptr)
- {
- ssd->tids = DCE2_ListNew(DCE2_LIST_TYPE__SPLAYED, DCE2_Smb2TidCompare,
- nullptr, nullptr, DCE2_LIST_FLAG__NO_DUPS);
-
- if (ssd->tids == nullptr)
- {
- return ret;
- }
- }
-
- if (ssd->outstanding_requests >= SMB2_MAX_OUTSTANDING_REQUESTS)
- {
- return ret;
- }
-
- ret = DCE2_ListInsert(ssd->tids, (void*)(uintptr_t)tid, (void*)(uintptr_t)share_type);
- if (DCE2_RET__SUCCESS == ret)
- {
- ssd->outstanding_requests++;
- }
-
- return ret;
-}
-
-static inline uint8_t DCE2_Smb2GetShareType(DCE2_SmbSsnData* ssd, const uint32_t tid)
-{
- if ( DCE2_RET__SUCCESS == DCE2_ListFindKey(ssd->tids, (void*)(uintptr_t)tid) )
- return ((uint8_t)(uintptr_t)DCE2_ListFind(ssd->tids, (void*)(uintptr_t)tid));
-
- return SMB2_SHARE_TYPE_NONE;
-}
-
-static inline void DCE2_Smb2RemoveTid(DCE2_SmbSsnData* ssd, const uint32_t tid)
-{
- if ( DCE2_RET__SUCCESS == DCE2_ListRemove(ssd->tids, (void*)(uintptr_t)tid) )
- ssd->outstanding_requests--;
-}
-
-static inline void DCE2_Smb2StoreRequest(DCE2_SmbSsnData* ssd,
- uint64_t message_id, uint64_t offset, uint64_t file_id)
-{
- Smb2Request* request = ssd->smb2_requests;
-
- while (request)
- {
- if (request->message_id == message_id)
- return;
- request = request->next;
- }
-
- if (ssd->outstanding_requests >= SMB2_MAX_OUTSTANDING_REQUESTS)
- {
- dce_alert(GID_DCE2, DCE2_SMB_MAX_REQS_EXCEEDED, (dce2CommonStats*)&dce2_smb_stats,
- ssd->sd);
- return;
- }
-
- request = ( Smb2Request* )snort_alloc( sizeof( *request ) );
-
- ssd->outstanding_requests++;
-
- request->message_id = message_id;
- request->offset = offset;
- request->file_id = file_id;
-
- request->next = ssd->smb2_requests;
- request->previous = nullptr;
- if (ssd->smb2_requests)
- ssd->smb2_requests->previous = request;
- ssd->smb2_requests = request;
-}
-
-static inline Smb2Request* DCE2_Smb2GetRequest(DCE2_SmbSsnData* ssd,
- uint64_t message_id)
-{
- Smb2Request* request = ssd->smb2_requests;
- while (request)
- {
- if (request->message_id == message_id)
- return request;
- request = request->next;
- }
-
- return nullptr;
-}
-
-static inline void DCE2_Smb2RemoveRequest(DCE2_SmbSsnData* ssd,
- Smb2Request* request)
-{
- if (request->previous)
- {
- request->previous->next = request->next;
- }
-
- if (request->next)
- {
- request->next->previous = request->previous;
- }
-
- if (request == ssd->smb2_requests)
- {
- ssd->smb2_requests = request->next;
- }
-
- ssd->outstanding_requests--;
- snort_free((void*)request);
-}
-
-static inline void DCE2_Smb2FreeFileName(DCE2_SmbFileTracker* ftracker)
-{
- if (ftracker->file_name)
- {
- snort_free((void*)ftracker->file_name);
- ftracker->file_name = nullptr;
- }
- ftracker->file_name_size = 0;
-}
-
-static inline void DCE2_Smb2ResetFileName(DCE2_SmbFileTracker* ftracker)
-{
- // FIXIT-L remove snort_free once file cache is ported.
- if (ftracker->file_name)
- {
- snort_free((void*)ftracker->file_name);
- }
- ftracker->file_name = nullptr;
- ftracker->file_name_size = 0;
-}
-
-static inline FileContext* get_file_context(uint64_t file_id)
-{
- FileFlows* file_flows = FileFlows::get_file_flows(DetectionEngine::get_current_packet()->flow);
-
- if ( !file_flows )
- return nullptr;
-
- return file_flows->get_file_context(file_id, true);
-}
-
-static inline void DCE2_Smb2ProcessFileData(DCE2_SmbSsnData* ssd, const uint8_t* file_data,
- uint32_t data_size, FileDirection dir)
-{
- 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.tracker.file.file_offset < (uint64_t)file_detection_depth)
- {
- if ( file_detection_depth - ssd->ftracker.tracker.file.file_offset < data_size )
- detection_size = file_detection_depth - ssd->ftracker.tracker.file.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();
- FileFlows* file_flows = FileFlows::get_file_flows(p->flow);
- if ( !file_flows )
- return;
-
- file_flows->file_process(p, ssd->ftracker.fid_v2, file_data, data_size,
- ssd->ftracker.tracker.file.file_offset, dir);
-}
-
-/********************************************************************
- *
- * Process tree connect command
- * Share type is defined here
- *
- ********************************************************************/
-static void DCE2_Smb2TreeConnect(DCE2_SmbSsnData* ssd, const Smb2Hdr* smb_hdr,
- const uint8_t* smb_data, const uint8_t* end)
-{
- /* Using structure size to decide whether it is response or request*/
- uint16_t structure_size;
- const Smb2TreeConnectResponseHdr* smb_tree_connect_hdr =
- (const Smb2TreeConnectResponseHdr*)smb_data;
-
- if ((const uint8_t*)smb_tree_connect_hdr + SMB2_TREE_CONNECT_RESPONSE_STRUC_SIZE > end)
- return;
-
- structure_size = alignedNtohs(&(smb_tree_connect_hdr->structure_size));
-
- if (structure_size == SMB2_TREE_CONNECT_RESPONSE_STRUC_SIZE)
- {
- DCE2_Smb2InsertTid(ssd, Smb2Tid(smb_hdr), smb_tree_connect_hdr->share_type);
- }
-}
-
-/********************************************************************
- *
- * Process tree connect command
- * Share type is defined here
- *
- ********************************************************************/
-static void DCE2_Smb2TreeDisconnect(DCE2_SmbSsnData* ssd, const Smb2Hdr* smb_hdr,
- const uint8_t* smb_data, const uint8_t* end)
+static inline bool DCE2_Smb2FindSidTid(DCE2_Smb2SsnData* ssd, const uint64_t sid,
+ const uint32_t tid, DCE2_Smb2SessionTracker** str, DCE2_Smb2TreeTracker** ttr)
{
- /* Using structure size to decide whether it is response or request*/
- uint16_t structure_size;
- const Smb2TreeDisConnectHdr* smb_tree_disconnect_hdr = (const Smb2TreeDisConnectHdr*)smb_data;
-
- if ((const uint8_t*)smb_tree_disconnect_hdr + SMB2_TREE_DISCONNECT_STRUC_SIZE > end)
- return;
+ *str = DCE2_Smb2FindSidInSsd(ssd, sid);
+ if (!*str)
+ return false;
- structure_size = alignedNtohs(&(smb_tree_disconnect_hdr->structure_size));
+ *ttr = (*str)->findTtracker(tid);
+ if (!*ttr)
+ return false;
- if (structure_size == SMB2_TREE_DISCONNECT_STRUC_SIZE)
- {
- DCE2_Smb2RemoveTid(ssd, Smb2Tid(smb_hdr));
- }
+ return true;
}
-/********************************************************************
- *
- * Process create request, first command for a file processing
- * Update file name
- *
- ********************************************************************/
-static void DCE2_Smb2CreateRequest(DCE2_SmbSsnData* ssd, const Smb2Hdr*,
- const Smb2CreateRequestHdr* smb_create_hdr,const uint8_t* end)
-{
- uint16_t name_offset = alignedNtohs(&(smb_create_hdr->name_offset));
-
- DCE2_Smb2InitFileTracker(&ssd->ftracker, false, 0);
-
- if (name_offset > SMB2_HEADER_LENGTH)
- {
- uint16_t size;
- const uint8_t* file_data = (const uint8_t*)smb_create_hdr + smb_create_hdr->name_offset -
- SMB2_HEADER_LENGTH;
- if (file_data >= end)
- return;
- size = alignedNtohs(&(smb_create_hdr->name_length));
- if (!size || (file_data + size > end))
- return;
- if (ssd->ftracker.file_name)
- {
- snort_free((void*)ssd->ftracker.file_name);
- ssd->ftracker.file_name_size = 0;
- }
- ssd->ftracker.file_name = DCE2_SmbGetFileName(file_data, size, true,
- &ssd->ftracker.file_name_size);
- }
-}
+// FIXIT-L port fileCache related code along with
+// DCE2_Smb2Init, DCE2_Smb2Close and DCE2_Smb2UpdateStats
-/********************************************************************
- *
- * Process create response, need to update file id
- * For downloading, file size is decided here
- *
- ********************************************************************/
-static void DCE2_Smb2CreateResponse(DCE2_SmbSsnData* ssd, const Smb2Hdr*,
- const Smb2CreateResponseHdr* smb_create_hdr, const uint8_t*)
+static void DCE2_Smb2Inspect(DCE2_Smb2SsnData* ssd, const Smb2Hdr* smb_hdr,
+ const uint8_t* end)
{
- uint64_t fileId_persistent;
- uint64_t file_size = UNKNOWN_FILE_SIZE;
+ const uint8_t* smb_data = (const uint8_t*)smb_hdr + SMB2_HEADER_LENGTH;
+ uint16_t command = alignedNtohs(&(smb_hdr->command));
+ DCE2_Smb2SessionTracker* str = nullptr;
+ DCE2_Smb2TreeTracker* ttr = nullptr;
- fileId_persistent = alignedNtohq((const uint64_t*)(&(smb_create_hdr->fileId_persistent)));
- ssd->ftracker.fid_v2 = fileId_persistent;
- if (smb_create_hdr->end_of_file)
- {
- file_size = alignedNtohq((const uint64_t*)(&(smb_create_hdr->end_of_file)));
- ssd->ftracker.tracker.file.file_size = file_size;
- }
+ uint64_t mid = Smb2Mid(smb_hdr);
+ uint64_t sid = Smb2Sid(smb_hdr);
+ uint32_t tid = Smb2Tid(smb_hdr);
- if (ssd->ftracker.file_name && ssd->ftracker.file_name_size)
+ switch (command)
{
- FileContext* file = get_file_context(ssd->ftracker.fid_v2);
- if (file)
+ case SMB2_COM_CREATE:
+ dce2_smb_stats.v2_crt++;
+ DCE2_Smb2Create(ssd, smb_hdr, smb_data, end, mid, sid, tid);
+ break;
+ case SMB2_COM_READ:
+ dce2_smb_stats.v2_read++;
+ if (!DCE2_Smb2FindSidTid(ssd, sid, tid, &str, &ttr) or
+ SMB2_SHARE_TYPE_DISK != ttr->get_share_type())
{
- file->set_file_size(file_size);
- file->set_file_name(ssd->ftracker.file_name, ssd->ftracker.file_name_size);
- }
- }
- DCE2_Smb2ResetFileName(&(ssd->ftracker));
-}
-
-/********************************************************************
- *
- * Process create command
- *
- ********************************************************************/
-static void DCE2_Smb2Create(DCE2_SmbSsnData* ssd, const Smb2Hdr* smb_hdr,
- const uint8_t* smb_data, const uint8_t* end)
-{
- uint16_t structure_size;
- const Smb2CreateRequestHdr* smb_create_hdr = (const Smb2CreateRequestHdr*)smb_data;
-
- structure_size = alignedNtohs(&(smb_create_hdr->structure_size));
-
- /* Using structure size to decide whether it is response or request */
- if (structure_size == SMB2_CREATE_REQUEST_STRUC_SIZE)
- {
- if ((const uint8_t*)smb_create_hdr + SMB2_CREATE_REQUEST_STRUC_SIZE - 1 > end)
- return;
- DCE2_Smb2CreateRequest(ssd, smb_hdr, smb_create_hdr, end);
- }
- else if (structure_size == SMB2_CREATE_RESPONSE_STRUC_SIZE)
- {
- if ((const uint8_t*)smb_create_hdr + SMB2_CREATE_RESPONSE_STRUC_SIZE -1 > end)
- return;
- DCE2_Smb2CreateResponse(ssd, smb_hdr, (const Smb2CreateResponseHdr*)smb_create_hdr, end);
- }
- else if (structure_size == SMB2_ERROR_RESPONSE_STRUC_SIZE)
- {
- const Smb2ErrorResponseHdr* smb_err_response_hdr = (const Smb2ErrorResponseHdr*)smb_data;
- if ((const uint8_t*)smb_create_hdr + SMB2_ERROR_RESPONSE_STRUC_SIZE - 1 > end)
+ dce2_smb_stats.v2_read_ignored++;
return;
- /* client will ignore when byte count is 0 */
- if (smb_err_response_hdr->byte_count)
- {
- /*Response error, clean up request state*/
- DCE2_Smb2FreeFileName(&(ssd->ftracker));
}
- }
-}
-
-/********************************************************************
- *
- * Process close command
- * For some upload, file_size is decided here.
- *
- ********************************************************************/
-static void DCE2_Smb2CloseCmd(DCE2_SmbSsnData* ssd, const Smb2Hdr*,
- const uint8_t* smb_data, const uint8_t* end)
-{
- /* Using structure size to decide whether it is response or request*/
- uint16_t structure_size;
- const Smb2CloseRequestHdr* smb_close_hdr = (const Smb2CloseRequestHdr*)smb_data;
-
- if ((const uint8_t*)smb_close_hdr + SMB2_CLOSE_REQUEST_STRUC_SIZE > end)
- return;
-
- structure_size = alignedNtohs(&(smb_close_hdr->structure_size));
- if ((structure_size == SMB2_CLOSE_REQUEST_STRUC_SIZE) &&
- !ssd->ftracker.tracker.file.file_size
- && ssd->ftracker.tracker.file.file_offset)
- {
- FileDirection dir = DetectionEngine::get_current_packet()->is_from_client() ?
- FILE_UPLOAD : FILE_DOWNLOAD;
-
- ssd->ftracker.tracker.file.file_size = ssd->ftracker.tracker.file.file_offset;
- uint64_t fileId_persistent = alignedNtohq(&(smb_close_hdr->fileId_persistent));
- FileContext* file = get_file_context(fileId_persistent);
- if (file)
+ DCE2_Smb2Read(ssd, smb_hdr, smb_data, end, str, ttr, mid);
+ break;
+ case SMB2_COM_WRITE:
+ dce2_smb_stats.v2_wrt++;
+ if (!DCE2_Smb2FindSidTid(ssd, sid, tid, &str, &ttr) or
+ SMB2_SHARE_TYPE_DISK != ttr->get_share_type())
{
- file->set_file_size(ssd->ftracker.tracker.file.file_size);
+ dce2_smb_stats.v2_wrt_ignored++;
+ return;
}
- DCE2_Smb2ProcessFileData(ssd, nullptr, 0, dir);
- }
- // FIXIT-L Close should probably remove file contexts from FileFlows
-}
-
-/********************************************************************
- *
- * Process set info command
- * For upload, file_size is decided here.
- *
- ********************************************************************/
-static void DCE2_Smb2SetInfo(DCE2_SmbSsnData* ssd, const Smb2Hdr*,
- const uint8_t* smb_data, const uint8_t* end)
-{
- /* Using structure size to decide whether it is response or request*/
- uint16_t structure_size;
- const Smb2SetInfoRequestHdr* smb_set_info_hdr = (const Smb2SetInfoRequestHdr*)smb_data;
-
- if ((const uint8_t*)smb_set_info_hdr + SMB2_SET_INFO_REQUEST_STRUC_SIZE > end)
- return;
-
- structure_size = alignedNtohs(&(smb_set_info_hdr->structure_size));
-
- if (structure_size == SMB2_SET_INFO_REQUEST_STRUC_SIZE)
- {
- 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)
+ DCE2_Smb2Write(ssd, smb_hdr, smb_data, end, str, ttr, mid);
+ break;
+ case SMB2_COM_SET_INFO:
+ dce2_smb_stats.v2_stinf++;
+ if (!DCE2_Smb2FindSidTid(ssd, sid, tid, &str, &ttr) or
+ SMB2_SHARE_TYPE_DISK != ttr->get_share_type())
{
- uint64_t file_size = alignedNtohq((const uint64_t*)file_data);
- ssd->ftracker.tracker.file.file_size = file_size;
- uint64_t fileId_persistent = alignedNtohq(&(smb_set_info_hdr->fileId_persistent));
- FileContext* file = get_file_context(fileId_persistent);
- if (file)
- {
- file->set_file_size(ssd->ftracker.tracker.file.file_size);
- }
- }
- }
-}
-
-/********************************************************************
- *
- * Process read request
- *
- ********************************************************************/
-static void DCE2_Smb2ReadRequest(DCE2_SmbSsnData* ssd, const Smb2Hdr* smb_hdr,
- const Smb2ReadRequestHdr* smb_read_hdr, const uint8_t*)
-{
- uint64_t message_id, offset;
- uint64_t fileId_persistent;
-
- message_id = alignedNtohq((const uint64_t*)(&(smb_hdr->message_id)));
- offset = alignedNtohq((const uint64_t*)(&(smb_read_hdr->offset)));
- fileId_persistent = alignedNtohq((const uint64_t*)(&(smb_read_hdr->fileId_persistent)));
- DCE2_Smb2StoreRequest(ssd, message_id, offset, fileId_persistent);
- if (fileId_persistent && (ssd->ftracker.fid_v2 != fileId_persistent))
- {
- ssd->ftracker.fid_v2 = fileId_persistent;
- }
- if (ssd->ftracker.tracker.file.file_size && (offset > ssd->ftracker.tracker.file.file_size))
- {
- dce_alert(GID_DCE2, DCE2_SMB_INVALID_FILE_OFFSET, (dce2CommonStats*)&dce2_smb_stats,
- ssd->sd);
- }
-}
-
-/********************************************************************
- *
- * Process read response
- *
- ********************************************************************/
-static void DCE2_Smb2ReadResponse(DCE2_SmbSsnData* ssd, const Smb2Hdr* smb_hdr,
- const Smb2ReadResponseHdr* smb_read_hdr, const uint8_t* end)
-{
- const uint8_t* file_data = (const uint8_t*)smb_read_hdr + SMB2_READ_RESPONSE_STRUC_SIZE - 1;
- int data_size = end - file_data;
- uint32_t total_data_length;
- uint64_t message_id;
- uint16_t data_offset;
- Smb2Request* request;
-
- message_id = alignedNtohq((const uint64_t*)(&(smb_hdr->message_id)));
- request = DCE2_Smb2GetRequest(ssd, message_id);
- if (!request)
- {
- return;
- }
- data_offset = alignedNtohs((const uint16_t*)(&(smb_read_hdr->data_offset)));
- if (data_offset + (const uint8_t*)smb_hdr > end)
- {
- dce_alert(GID_DCE2, DCE2_SMB_BAD_OFF, (dce2CommonStats*)&dce2_smb_stats, ssd->sd);
- }
-
- ssd->ftracker.tracker.file.file_offset = request->offset;
- ssd->ftracker.fid_v2 = request->file_id;
- ssd->ftracker.tracker.file.file_direction = DCE2_SMB_FILE_DIRECTION__DOWNLOAD;
-
- DCE2_Smb2RemoveRequest(ssd, request);
-
- DCE2_Smb2ProcessFileData(ssd, file_data, data_size, FILE_DOWNLOAD);
- ssd->ftracker.tracker.file.file_offset += data_size;
- total_data_length = alignedNtohl((const uint32_t*)&(smb_read_hdr->length));
- if (total_data_length > (uint32_t)data_size)
- ssd->pdu_state = DCE2_SMB_PDU_STATE__RAW_DATA;
-}
-
-/********************************************************************
- *
- * Process read command
- *
- ********************************************************************/
-static void DCE2_Smb2Read(DCE2_SmbSsnData* ssd, const Smb2Hdr* smb_hdr,
- const uint8_t* smb_data, const uint8_t* end)
-{
- uint16_t structure_size;
- const Smb2ReadRequestHdr* smb_read_hdr = (const Smb2ReadRequestHdr*)smb_data;
- structure_size = alignedNtohs(&(smb_read_hdr->structure_size));
-
- /* Using structure size to decide whether it is response or request*/
- if (structure_size == SMB2_READ_REQUEST_STRUC_SIZE)
- {
- if ((const uint8_t*)smb_read_hdr + SMB2_READ_REQUEST_STRUC_SIZE - 1 > end)
- return;
- DCE2_Smb2ReadRequest(ssd, smb_hdr, smb_read_hdr, end);
- }
- else if (structure_size == SMB2_READ_RESPONSE_STRUC_SIZE)
- {
- if ((const uint8_t*)smb_read_hdr + SMB2_READ_RESPONSE_STRUC_SIZE - 1 > end)
+ dce2_smb_stats.v2_stinf_ignored++;
return;
- DCE2_Smb2ReadResponse(ssd, smb_hdr, (const Smb2ReadResponseHdr*)smb_read_hdr, end);
- }
- else
- {
- uint64_t message_id;
- Smb2Request* request;
+ }
- message_id = alignedNtohq((const uint64_t*)(&(smb_hdr->message_id)));
- request = DCE2_Smb2GetRequest(ssd, message_id);
- if (!request)
+ DCE2_Smb2SetInfo(ssd, smb_hdr, smb_data, end, ttr);
+ break;
+ case SMB2_COM_CLOSE:
+ dce2_smb_stats.v2_cls++;
+ if (!DCE2_Smb2FindSidTid(ssd, sid, tid, &str, &ttr) or
+ SMB2_SHARE_TYPE_DISK != ttr->get_share_type())
{
+ dce2_smb_stats.v2_cls_ignored++;
return;
}
- DCE2_Smb2RemoveRequest(ssd, request);
- }
-}
-
-/********************************************************************
- *
- * Process write request
- *
- ********************************************************************/
-static void DCE2_Smb2WriteRequest(DCE2_SmbSsnData* ssd, const Smb2Hdr* smb_hdr,
- const Smb2WriteRequestHdr* smb_write_hdr, const uint8_t* end)
-{
- 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;
- uint32_t total_data_length;
-
- fileId_persistent = alignedNtohq((const uint64_t*)(&(smb_write_hdr->fileId_persistent)));
- if (fileId_persistent && (ssd->ftracker.fid_v2 != fileId_persistent))
- {
- ssd->ftracker.fid_v2 = fileId_persistent;
- }
- data_offset = alignedNtohs((const uint16_t*)(&(smb_write_hdr->data_offset)));
- if (data_offset + (const uint8_t*)smb_hdr > end)
- {
- dce_alert(GID_DCE2, DCE2_SMB_BAD_OFF, (dce2CommonStats*)&dce2_smb_stats, ssd->sd);
- }
- offset = alignedNtohq((const uint64_t*)(&(smb_write_hdr->offset)));
- if (ssd->ftracker.tracker.file.file_size && (offset > ssd->ftracker.tracker.file.file_size))
- {
- dce_alert(GID_DCE2, DCE2_SMB_INVALID_FILE_OFFSET, (dce2CommonStats*)&dce2_smb_stats,
- ssd->sd);
- }
- ssd->ftracker.tracker.file.file_direction = DCE2_SMB_FILE_DIRECTION__UPLOAD;
- ssd->ftracker.tracker.file.file_offset = offset;
-
- DCE2_Smb2ProcessFileData(ssd, file_data, data_size, FILE_UPLOAD);
- ssd->ftracker.tracker.file.file_offset += data_size;
- total_data_length = alignedNtohl((const uint32_t*)&(smb_write_hdr->length));
- if (total_data_length > (uint32_t)data_size)
- ssd->pdu_state = DCE2_SMB_PDU_STATE__RAW_DATA;
-}
-
-/********************************************************************
- *
- * Process write command
- *
- ********************************************************************/
-static void DCE2_Smb2Write(DCE2_SmbSsnData* ssd, const Smb2Hdr* smb_hdr,
- const uint8_t* smb_data, const uint8_t* end)
-{
- uint16_t structure_size;
- const Smb2WriteRequestHdr* smb_write_hdr = (const Smb2WriteRequestHdr*)smb_data;
- structure_size = alignedNtohs(&(smb_write_hdr->structure_size));
-
- /* Using structure size to decide whether it is response or request*/
- if (structure_size == SMB2_WRITE_REQUEST_STRUC_SIZE)
- {
- if ((const uint8_t*)smb_write_hdr + SMB2_WRITE_REQUEST_STRUC_SIZE - 1 > end)
- return;
- DCE2_Smb2WriteRequest(ssd, smb_hdr, smb_write_hdr, end);
- }
-}
-
-/********************************************************************
- *
- * Purpose:
- * Process SMB2 commands.
- *
- * Arguments:
- * DCE2_SmbSsnData * - the session data structure.
- * const Smb2Hdr * - pointer to the SMB2 header.
- * const uint8_t * - pointer to end of payload.
- * Returns: None
- *
- ********************************************************************/
-static void DCE2_Smb2Inspect(DCE2_SmbSsnData* 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));
- uint8_t share_type = DCE2_Smb2GetShareType(ssd, Smb2Tid(smb_hdr));
- switch (command)
- {
- case SMB2_COM_CREATE:
- dce2_smb_stats.smb2_create++;
-
- if ( SMB2_SHARE_TYPE_NONE == share_type )
- {
- if ( DCE2_RET__SUCCESS ==
- DCE2_Smb2InsertTid(ssd, Smb2Tid(smb_hdr), SMB2_SHARE_TYPE_DISK) )
- DCE2_Smb2Create(ssd, smb_hdr, smb_data, end);
- }
- else if ( SMB2_SHARE_TYPE_DISK == share_type )
- {
- DCE2_Smb2Create(ssd, smb_hdr, smb_data, end);
- }
- else
+ DCE2_Smb2CloseCmd(ssd, smb_hdr, smb_data, end, ttr);
+ 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)
{
- debug_logf(dce_smb_trace, nullptr, "Not handling create request for IPC with TID (%u)\n",
- Smb2Tid(smb_hdr));
+ DCE2_Smb2TreeConnect(ssd, smb_hdr, smb_data, end, str, tid);
}
break;
- case SMB2_COM_READ:
- dce2_smb_stats.smb2_read++;
- if ( SMB2_SHARE_TYPE_DISK != share_type )
- return;
- DCE2_Smb2Read(ssd, smb_hdr, smb_data, end);
- break;
- case SMB2_COM_WRITE:
- dce2_smb_stats.smb2_write++;
- if ( SMB2_SHARE_TYPE_DISK != share_type )
- return;
- DCE2_Smb2Write(ssd, smb_hdr, smb_data, end);
- break;
- case SMB2_COM_SET_INFO:
- dce2_smb_stats.smb2_set_info++;
- if ( SMB2_SHARE_TYPE_DISK != share_type )
- return;
- DCE2_Smb2SetInfo(ssd, smb_hdr, smb_data, end);
- break;
- case SMB2_COM_CLOSE:
- dce2_smb_stats.smb2_close++;
- if ( SMB2_SHARE_TYPE_DISK != share_type )
+ case SMB2_COM_TREE_DISCONNECT:
+ dce2_smb_stats.v2_tree_discn++;
+ if (!DCE2_Smb2FindSidTid(ssd, sid, tid, &str, &ttr))
+ {
+ dce2_smb_stats.v2_tree_discn_ignored++;
return;
- DCE2_Smb2CloseCmd(ssd, smb_hdr, smb_data, end);
+ }
+ DCE2_Smb2TreeDisconnect(ssd, smb_data, end, str, tid);
break;
- case SMB2_COM_TREE_CONNECT:
- dce2_smb_stats.smb2_tree_connect++;
- DCE2_Smb2TreeConnect(ssd, smb_hdr, smb_data, end);
+ case SMB2_COM_SESSION_SETUP:
+ dce2_smb_stats.v2_setup++;
+ DCE2_Smb2Setup(ssd, smb_hdr, sid, smb_data, end);
break;
- case SMB2_COM_TREE_DISCONNECT:
- dce2_smb_stats.smb2_tree_disconnect++;
- DCE2_Smb2TreeDisconnect(ssd, smb_hdr, smb_data, end);
+ case SMB2_COM_LOGOFF:
+ dce2_smb_stats.v2_logoff++;
+ DCE2_Smb2Logoff(ssd, smb_data, sid);
break;
default:
+ dce2_smb_stats.v2_msgs_uninspected++;
break;
}
}
// This is the main entry point for SMB2 processing.
-void DCE2_Smb2Process(DCE2_SmbSsnData* ssd)
+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;
- /*Check header length*/
+ // Check header length
if (data_len < sizeof(NbssHdr) + SMB2_HEADER_LENGTH)
- return;
-
- if (!ssd->ftracker.is_smb2)
{
- DCE2_Smb2InitFileTracker(&(ssd->ftracker), false, 0);
+ dce2_smb_stats.v2_hdr_err++;
+ return;
}
- /* Process the header */
+ // Process the header
if (p->is_pdu_start())
{
const Smb2Hdr* smb_hdr = (const Smb2Hdr*)(data_ptr + sizeof(NbssHdr));
uint32_t next_command_offset;
- /* SMB protocol allows multiple smb commands to be grouped in a single packet.
- So loop through to parse all the smb commands.
- Reference: https://msdn.microsoft.com/en-us/library/cc246614.aspx
- "A nonzero value for the NextCommand field in the SMB2 header indicates a compound
- request. NextCommand in the SMB2 header of a request specifies an offset, in bytes,
- from the beginning of the SMB2 header under consideration to the start of the 8-byte
- aligned SMB2 header of the subsequent request. Such compounding can be used to append
- multiple requests up to the maximum size<88> that is supported by the transport." */
+ uint8_t compound_request_index = 0;
+ // SMB protocol allows multiple smb commands to be grouped in a single packet.
+ // So loop through to parse all the smb commands.
+ // Reference: https://msdn.microsoft.com/en-us/library/cc246614.aspx
+ // "A nonzero value for the NextCommand field in the SMB2 header indicates a compound
+ // request. NextCommand in the SMB2 header of a request specifies an offset, in bytes,
+ // from the beginning of the SMB2 header under consideration to the start of the 8-byte
+ // aligned SMB2 header of the subsequent request. Such compounding can be used to append
+ // multiple requests up to the maximum size<88> that is supported by the transport."
do
{
DCE2_Smb2Inspect(ssd, smb_hdr, data_ptr + data_len);
- /* In case of message compounding, find the offset of the next smb command */
+ // 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, ssd->sd);
-
+ dce2_smb_stats.v2_bad_next_cmd_offset++;
return;
}
if (next_command_offset)
{
smb_hdr = (const Smb2Hdr*)((const uint8_t*)smb_hdr + next_command_offset);
+ compound_request_index++;
+ }
+
+ if (compound_request_index > DCE2_ScSmbMaxCompound((dce2SmbProtoConf*)ssd->sd.config))
+ {
+ dce2_smb_stats.v2_cmpnd_req_lt_crossed++;
+ return;
}
}
- while (next_command_offset && smb_hdr);
+ while (next_command_offset and smb_hdr);
}
- else if (ssd->pdu_state == DCE2_SMB_PDU_STATE__RAW_DATA)
+ else if ( ssd->ftracker_tcp and (ssd->ftracker_tcp->smb2_pdu_state ==
+ DCE2_SMB_PDU_STATE__RAW_DATA))
{
- /*continue processing raw data*/
+ debug_logf(dce_smb_trace, nullptr, "Processing raw data\n");
+ // continue processing raw data
FileDirection dir = p->is_from_client() ? FILE_UPLOAD : FILE_DOWNLOAD;
DCE2_Smb2ProcessFileData(ssd, data_ptr, data_len, dir);
- ssd->ftracker.tracker.file.file_offset += data_len;
+ ssd->ftracker_tcp->file_offset += data_len;
}
}
-/* Initialize smb2 file tracker */
-DCE2_Ret DCE2_Smb2InitFileTracker(DCE2_SmbFileTracker* ftracker,
- const bool is_ipc, const uint64_t fid)
+static inline void DCE2_Smb2FreeSessionData(void* str)
{
- if (ftracker == nullptr)
- return DCE2_RET__ERROR;
-
- DCE2_Smb2FreeFileName(ftracker);
- ftracker->fid_v2 = fid;
- ftracker->is_ipc = is_ipc;
- ftracker->is_smb2 = true;
-
- ftracker->ff_file_size = 0;
- ftracker->ff_file_offset = 0;
- ftracker->ff_file_direction = DCE2_SMB_FILE_DIRECTION__UNKNOWN;
+ DCE2_Smb2SessionTracker* stracker = (DCE2_Smb2SessionTracker*)str;
+ DCE2_SmbSessionCacheRemove(stracker->get_session_id());
+}
+DCE2_Ret DCE2_Smb2InitData(DCE2_Smb2SsnData* ssd)
+{
+ memset(&ssd->sd, 0, sizeof(DCE2_SsnData));
+ ssd->session_trackers.Init(DCE2_Smb2FreeSessionData);
+ memset(&ssd->policy, 0, sizeof(DCE2_Policy));
+ ssd->dialect_index = 0;
+ ssd->ssn_state_flags = 0;
+ ssd->ftracker_tcp = nullptr;
+ ssd->max_file_depth = FileService::get_max_file_depth();
return DCE2_RET__SUCCESS;
}
-/* Check whether the packet is smb2 */
+// Check whether the packet is smb2
DCE2_SmbVersion DCE2_Smb2Version(const Packet* p)
{
- /* Only check reassembled SMB2 packet*/
+ // Only check reassembled SMB2 packet
if ( p->has_paf_payload() and
(p->dsize > sizeof(NbssHdr) + DCE2_SMB_ID_SIZE) ) // DCE2_SMB_ID is u32
{
uint32_t smb_version_id = SmbId((const SmbNtHdr*)smb_hdr);
if (smb_version_id == DCE2_SMB_ID)
- return DCE2_SMB_VERISON_1;
-
+ return DCE2_SMB_VERSION_1;
else if (smb_version_id == DCE2_SMB2_ID)
- return DCE2_SMB_VERISON_2;
+ return DCE2_SMB_VERSION_2;
}
- return DCE2_SMB_VERISON_NULL;
-}
-
-void DCE2_Smb2CleanRequests(Smb2Request* requests)
-{
- Smb2Request* request = requests;
- while (request)
- {
- Smb2Request* next;
- next = request->next;
- snort_free((void*)request);
- request = next;
- }
+ return DCE2_SMB_VERSION_NULL;
}
-
#ifndef DCE_SMB2_H
#define DCE_SMB2_H
+#include "dce_db.h"
#include "dce_smb.h"
-
-#define SMB2_FLAGS_ASYNC_COMMAND 0x00000002
+#include "utils/util.h"
struct Smb2Hdr
{
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;
+
+ DCE2_Smb2RequestTracker(uint64_t offset_v, uint64_t file_id_v,
+ char* fname_v, uint16_t fname_len_v, DCE2_Smb2TreeTracker *ttr) :
+ fname_len(fname_len_v), fname(fname_v), offset(offset_v),
+ file_id(file_id_v), tree_trk(ttr)
+ {
+ // fname allocated by DCE2_SmbGetFileName
+ }
+
+ ~DCE2_Smb2RequestTracker()
+ {
+ if (fname != nullptr)
+ {
+ snort_free((void*)fname);
+ }
+ }
+
+ uint16_t get_file_name_len() { return fname_len; }
+ char* get_file_name() { return fname; }
+ uint64_t get_offset() { return offset; }
+ uint64_t get_file_id() { return file_id; }
+ DCE2_Smb2TreeTracker* get_tree_tracker() { return tree_trk; }
+
+private:
+
+ uint16_t fname_len;
+ char* fname;
+ uint64_t offset;
+ uint64_t file_id;
+ DCE2_Smb2TreeTracker* tree_trk;
+};
+
+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, char* file_name_v,
+ uint64_t file_size_v) : file_id(file_id_v), file_size(file_size_v)
+ {
+ if (file_name_v)
+ file_name.assign(file_name_v);
+
+ file_offset = 0;
+ bytes_processed = 0;
+ }
+
+ ~DCE2_Smb2FileTracker()
+ {
+ // Nothing to be done
+ }
+
+ uint64_t bytes_processed;
+ uint64_t file_offset;
+ uint64_t file_id;
+ uint64_t file_size = 0;
+ std::string file_name;
+ DCE2_SmbPduState smb2_pdu_state;
+};
+
+
+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) : share_type(
+ share_type_v), tid(tid_v)
+ {
+ }
+
+ DCE2_Smb2FileTracker* findFtracker(uint64_t file_id)
+ {
+ return file_trackers.Find(file_id);
+ }
+
+ void insertFtracker(uint64_t file_id, DCE2_Smb2FileTracker* ftracker)
+ {
+ file_trackers.Insert(file_id, ftracker);
+ }
+
+ void removeFtracker(uint64_t file_id)
+ {
+ removeDataRtrackerWithFid(file_id);
+ file_trackers.Remove(file_id);
+ }
+
+ DCE2_Smb2RequestTracker* findDataRtracker(uint64_t message_id)
+ {
+ return request_trackers.Find(message_id);
+ }
+
+ void insertDataRtracker(uint64_t message_id, DCE2_Smb2RequestTracker* readtracker)
+ {
+ request_trackers.Insert(message_id, readtracker);
+ }
+
+ void removeDataRtracker(uint64_t message_id)
+ {
+ if (findDataRtracker(message_id))
+ {
+ request_trackers.Remove(message_id);
+ }
+ }
+
+ void removeDataRtrackerWithFid(uint64_t fid)
+ {
+ auto all_requests = request_trackers.get_all_entry();
+ for ( auto & h : all_requests )
+ {
+ if (h.second->get_file_id() == fid)
+ removeDataRtracker(h.first); // this is message id
+ }
+ }
+
+ int getDataRtrackerSize()
+ {
+ return request_trackers.GetSize();
+ }
+
+ uint8_t get_share_type() { return share_type; }
+ uint32_t get_tid() { return tid; }
+private:
+ uint8_t share_type;
+ uint32_t tid;
+
+ DCE2_DbMapRtracker request_trackers;
+ DCE2_DbMapFtracker file_trackers;
+};
+
+typedef DCE2_DbMap<uint32_t, DCE2_Smb2TreeTracker*, std::hash<uint32_t> > DCE2_DbMapTtracker;
+class DCE2_Smb2SessionTracker
+{
+public:
+
+ DCE2_Smb2SessionTracker() { }
+
+ void insertTtracker(uint32_t tree_id, DCE2_Smb2TreeTracker* ttr)
+ {
+ 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)
+ {
+ // Remove any dangling request trackers with tree id
+ removeRtrackerWithTid(tree_id);
+ tree_trackers.Remove(tree_id);
+ }
+
+ DCE2_Smb2RequestTracker* findRtracker(uint64_t mid)
+ {
+ return create_request_trackers.Find(mid);
+ }
+
+ void insertRtracker(uint64_t message_id, DCE2_Smb2RequestTracker* rtracker)
+ {
+ create_request_trackers.Insert(message_id, rtracker);
+ }
+
+ void removeRtracker(uint64_t message_id)
+ {
+ create_request_trackers.Remove(message_id);
+ }
+
+ void removeRtrackerWithTid(uint32_t tid)
+ {
+ auto all_requests = create_request_trackers.get_all_entry();
+ for ( auto & h : all_requests )
+ {
+ if (h.second->get_tree_tracker() and h.second->get_tree_tracker()->get_tid() == tid)
+ removeRtracker(h.first); // this is message id
+ }
+ }
+
+ uint16_t getTotalRequestsPending()
+ {
+ uint16_t total_count = 0;
+ auto all_tree_trackers = tree_trackers.get_all_entry();
+ for ( auto & h : all_tree_trackers )
+ {
+ total_count += h.second->getDataRtrackerSize(); // all read/write
+ }
+ total_count += create_request_trackers.GetSize(); // all create
+ return total_count;
+ }
+
+ void set_session_id(uint64_t sid) { session_id = sid; }
+ uint64_t get_session_id() { return session_id; }
+
+private:
+ uint64_t session_id;
+ DCE2_DbMapTtracker tree_trackers;
+ DCE2_DbMapRtracker create_request_trackers;
+};
+
+typedef DCE2_DbMap<uint64_t, DCE2_Smb2SessionTracker*, std::hash<uint64_t> > DCE2_DbMapStracker;
+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
+ DCE2_DbMapStracker session_trackers;
+ DCE2_Smb2FileTracker* ftracker_tcp; //To keep tab of current file being transferred over TCP
+};
+
/* SMB2 command codes */
#define SMB2_COM_NEGOTIATE 0x00
#define SMB2_COM_SESSION_SETUP 0x01
uint64_t fileId_volatile; /* fileId that is volatile */
};
-#define SMB2_SHARE_TYPE_NONE 0x00
#define SMB2_SHARE_TYPE_DISK 0x01
#define SMB2_SHARE_TYPE_PIPE 0x02
#define SMB2_SHARE_TYPE_PRINT 0x03
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;
+};
+
#define SMB2_HEADER_LENGTH 64
#define SMB2_ERROR_RESPONSE_STRUC_SIZE 9
#define SMB2_CREATE_REQUEST_DATA_OFFSET 120
#define SMB2_CLOSE_REQUEST_STRUC_SIZE 24
+#define SMB2_CLOSE_RESPONSE_STRUC_SIZE 60
#define SMB2_WRITE_REQUEST_STRUC_SIZE 49
#define SMB2_WRITE_RESPONSE_STRUC_SIZE 17
#define SMB2_SET_INFO_REQUEST_STRUC_SIZE 33
#define SMB2_SET_INFO_RESPONSE_STRUC_SIZE 2
+#define SMB2_TREE_CONNECT_REQUEST_STRUC_SIZE 9
#define SMB2_TREE_CONNECT_RESPONSE_STRUC_SIZE 16
-#define SMB2_TREE_DISCONNECT_STRUC_SIZE 4
+#define SMB2_TREE_DISCONNECT_REQUEST_STRUC_SIZE 4
#define SMB2_FILE_ENDOFFILE_INFO 0x14
-/* Clean up all the pending requests*/
-void DCE2_Smb2CleanRequests(Smb2Request* requests);
+#define SMB2_SETUP_REQUEST_STRUC_SIZE 25
+#define SMB2_SETUP_RESPONSE_STRUC_SIZE 9
-/* Process smb2 message */
-void DCE2_Smb2Process(DCE2_SmbSsnData* ssd);
+#define SMB2_LOGOFF_REQUEST_STRUC_SIZE 4
-/* Initialize file tracker for smb2 processing */
-DCE2_Ret DCE2_Smb2InitFileTracker(DCE2_SmbFileTracker* ftracker,
- const bool is_ipc, const uint64_t fid);
+/* Process smb2 message */
+void DCE2_Smb2Process(DCE2_Smb2SsnData* ssd);
/* Check smb version based on smb header */
DCE2_SmbVersion DCE2_Smb2Version(const snort::Packet* p);
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2016-2019 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 "log/messages.h"
+#include "main/snort_debug.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)\
+{ \
+ if ((smb_data + (strcuture_size)) > end)\
+ {\
+ counter++;\
+ return;\
+ }\
+}
+
+static inline FileContext* get_smb_file_context(uint64_t file_id)
+{
+ FileFlows* file_flows = FileFlows::get_file_flows(DetectionEngine::get_current_packet()->flow);
+
+ if ( !file_flows )
+ {
+ dce2_smb_stats.v2_inv_file_ctx_err++;
+ return nullptr;
+ }
+
+ return file_flows->get_file_context(file_id, true);
+}
+
+void DCE2_Smb2ProcessFileData(DCE2_Smb2SsnData* ssd, const uint8_t* file_data,
+ uint32_t data_size, FileDirection dir)
+{
+ 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_tcp->file_offset < (uint64_t)file_detection_depth)
+ {
+ if ( file_detection_depth - ssd->ftracker_tcp->file_offset < data_size )
+ detection_size = file_detection_depth - ssd->ftracker_tcp->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();
+ ssd->ftracker_tcp->bytes_processed += detection_size;
+
+ // Do not process data beyond file size if file size is known.
+ FileFlows* file_flows = FileFlows::get_file_flows(p->flow);
+ if ( !file_flows or ( ssd->ftracker_tcp->file_size and
+ ssd->ftracker_tcp->bytes_processed > ssd->ftracker_tcp->file_size ) )
+ {
+ dce2_smb_stats.v2_extra_file_data_err++;
+ return;
+ }
+
+ file_flows->file_process(p, ssd->ftracker_tcp->file_id, file_data, data_size,
+ ssd->ftracker_tcp->file_offset, dir);
+}
+
+//-------------------------------------------------------------------------
+// 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))
+ {
+ 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)
+ DCE2_Smb2FindElseCreateSid(ssd, sid);
+ }
+ else if (structure_size != SMB2_SETUP_REQUEST_STRUC_SIZE)
+ {
+ 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))
+ {
+ 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)
+
+ if (!DCE2_Smb2FindElseCreateTid(ssd, tid,
+ ((const Smb2TreeConnectResponseHdr*)smb_data)->share_type, str))
+ dce2_smb_stats.v2_tree_cnct_ignored++;
+ }
+ else if (structure_size != SMB2_TREE_CONNECT_REQUEST_STRUC_SIZE)
+ {
+ 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, DCE2_Smb2SessionTracker* str, uint32_t tid)
+{
+ 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)
+ str->removeTtracker(tid);
+ }
+ else
+ {
+ dce2_smb_stats.v2_tree_discn_inv_str_sz++;
+ }
+}
+
+//-------------------------------------------------------------------------
+// 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++;
+ 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++;
+ return;
+ }
+
+ char* file_name = DCE2_SmbGetFileName(file_data, size, true,
+ &name_len);
+
+ if (ssd->max_outstanding_requests > str->getTotalRequestsPending())
+ {
+ DCE2_Smb2RequestTracker* rtracker = str->findRtracker(mid);
+ if (rtracker) // Cleanup existing tracker
+ str->removeRtracker(mid);
+
+ rtracker = new DCE2_Smb2RequestTracker(0, 0, file_name, name_len, ttr);
+
+ str->insertRtracker(mid, rtracker);
+ }
+ else
+ {
+ snort_free(file_name);
+ dce_alert(GID_DCE2, DCE2_SMB_MAX_REQS_EXCEEDED, (dce2CommonStats*)&dce2_smb_stats,
+ ssd->sd);
+ }
+ }
+ else
+ {
+ 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*,
+ const Smb2CreateResponseHdr* smb_create_hdr,
+ DCE2_Smb2RequestTracker* rtracker)
+{
+ uint64_t file_size = 0;
+ uint64_t fileId_persistent = alignedNtohq((const uint64_t*)(&(smb_create_hdr->fileId_persistent)));
+
+ if (smb_create_hdr->end_of_file)
+ {
+ file_size = alignedNtohq((const uint64_t*)(&(smb_create_hdr->end_of_file)));
+ }
+
+ DCE2_Smb2FileTracker* ftracker = rtracker->get_tree_tracker()->findFtracker(fileId_persistent);
+ if (!ftracker)
+ {
+ ftracker = new DCE2_Smb2FileTracker(
+ fileId_persistent, rtracker->get_file_name(), file_size);
+ }
+ else // compounded create request + read request case
+ {
+ ftracker->file_name.assign(rtracker->get_file_name());
+ ftracker->file_size = file_size;
+ }
+
+ if (rtracker->get_file_name() and rtracker->get_file_name_len())
+ {
+ FileContext* file = get_smb_file_context(fileId_persistent);
+ if (file)
+ {
+ file->set_file_size(!file_size ? UNKNOWN_FILE_SIZE : file_size);
+ file->set_file_name(rtracker->get_file_name(), rtracker->get_file_name_len());
+ }
+ }
+
+ rtracker->get_tree_tracker()->insertFtracker(fileId_persistent, ftracker);
+}
+
+//-------------------------------------------------------------------------
+// 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);
+ uint16_t structure_size = alignedNtohs((const uint16_t*)smb_data);
+
+ if (structure_size == SMB2_ERROR_RESPONSE_STRUC_SIZE and Smb2Error(smb_hdr))
+ {
+ //in case of compound create + read, a ftracker is already created, remove it
+ DCE2_Smb2RequestTracker* rtr = str->findRtracker(mid);
+ if ( rtr and rtr->get_tree_tracker() and rtr->get_file_id() )
+ {
+ if (ssd->ftracker_tcp->file_id == rtr->get_file_id())
+ ssd->ftracker_tcp = NULL;
+ rtr->get_tree_tracker()->removeFtracker(rtr->get_file_id());
+ }
+ str->removeRtracker(mid);
+ dce2_smb_stats.v2_crt_err_resp++;
+ }
+ // 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)
+
+ DCE2_Smb2TreeTracker* ttr = str->findTtracker(tid);
+ if (!ttr)
+ {
+ ttr = DCE2_Smb2InsertTid(ssd, tid, SMB2_SHARE_TYPE_DISK, str);
+ }
+ else if (SMB2_SHARE_TYPE_DISK != ttr->get_share_type())
+ {
+ debug_logf(dce_smb_trace, nullptr, "Not handling create request for IPC with TID (%u)\n",
+ tid);
+ dce2_smb_stats.v2_crt_req_ipc++;
+ return;
+ }
+ 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)
+
+ DCE2_Smb2RequestTracker* rtr = str->findRtracker(mid);
+ if (!rtr)
+ {
+ debug_logf(dce_smb_trace, nullptr,
+ "No create request received for this MID (%" PRIu64 ")\n", mid);
+ dce2_smb_stats.v2_crt_rtrkr_misng++;
+ return;
+ }
+ // Check required only for null tree tracker since for IPC,
+ // the request tracker itself is not added.
+ if (!rtr->get_tree_tracker())
+ {
+ debug_logf(dce_smb_trace, nullptr,
+ "Tree tracker is missing for create request\n");
+ dce2_smb_stats.v2_crt_tree_trkr_misng++;
+ str->removeRtracker(mid);
+ return;
+ }
+
+ DCE2_Smb2CreateResponse(ssd, (const Smb2CreateResponseHdr*)smb_data, rtr);
+ str->removeRtracker(mid);
+ }
+ else
+ {
+ 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)
+{
+ uint16_t structure_size = alignedNtohs((const uint16_t*)smb_data);
+
+ if (structure_size == SMB2_ERROR_RESPONSE_STRUC_SIZE and Smb2Error(smb_hdr))
+ {
+ 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)
+
+ 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++;
+ return;
+ }
+
+ if (!ftracker->file_size and ftracker->file_offset)
+ {
+ // If close command request comes just after create response, we dont have
+ // information to know the direction, hence below code was included.
+ FileDirection dir = DetectionEngine::get_current_packet()->is_from_client() ?
+ FILE_UPLOAD : FILE_DOWNLOAD;
+
+ ftracker->file_size = ftracker->file_offset;
+ FileContext* file = get_smb_file_context(fileId_persistent);
+ if (file)
+ {
+ file->set_file_size(ftracker->file_size);
+ }
+
+ // 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, dir);
+ }
+
+ if (ssd->ftracker_tcp and ssd->ftracker_tcp->file_id == fileId_persistent)
+ ssd->ftracker_tcp = nullptr;
+
+ ttr->removeFtracker(fileId_persistent);
+
+ }
+ else if (structure_size != SMB2_CLOSE_RESPONSE_STRUC_SIZE)
+ {
+ dce2_smb_stats.v2_cls_inv_str_sz++;
+ }
+}
+
+//-------------------------------------------------------------------------
+// Process set info request to update file size
+//-------------------------------------------------------------------------
+void DCE2_Smb2SetInfo(DCE2_Smb2SsnData*, 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))
+ {
+ 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)
+
+ 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)
+ {
+ 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)
+ {
+ ftracker->file_size = file_size;
+
+ FileContext* file = get_smb_file_context(fileId_persistent);
+ if (file)
+ {
+ file->set_file_size(ftracker->file_size);
+ }
+ }
+ else
+ dce2_smb_stats.v2_stinf_req_ftrkr_misng++;
+ }
+ else
+ dce2_smb_stats.v2_stinf_req_hdr_err++;
+ }
+ else if (structure_size != SMB2_SET_INFO_RESPONSE_STRUC_SIZE)
+ {
+ 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)
+{
+ DCE2_Smb2RequestTracker* readtracker = nullptr;
+
+ 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 > str->getTotalRequestsPending())
+ {
+ readtracker = new DCE2_Smb2RequestTracker(
+ offset, fileId_persistent, nullptr, 0, nullptr);
+ ttr->insertDataRtracker(message_id, readtracker);
+ }
+ else
+ {
+ 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) // compounded create request + read request case
+ {
+ ftracker = new DCE2_Smb2FileTracker(fileId_persistent, nullptr, 0);
+ ttr->insertFtracker(fileId_persistent, ftracker);
+ }
+
+ if (ftracker->file_size and (offset > ftracker->file_size))
+ {
+ 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;
+
+ request = ttr->findDataRtracker(message_id);
+ if (!request)
+ {
+ 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)
+ {
+ 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 ) // file tracker can never be NULL for read response
+ {
+ ftracker->file_offset = request->get_offset();
+ ttr->removeDataRtracker(message_id);
+ ssd->ftracker_tcp = ftracker;
+
+ DCE2_Smb2ProcessFileData(ssd, file_data, data_size, FILE_DOWNLOAD);
+ ftracker->file_offset += data_size;
+
+ uint32_t total_data_length = alignedNtohl((const uint32_t*)&(smb_read_hdr->length));
+ debug_logf(dce_smb_trace, nullptr, "smbv2 total_data=%d data_size=%d ssd=%p\n", total_data_length,data_size,
+ (void*)ssd);
+ if (total_data_length > (uint32_t)data_size)
+ {
+ ftracker->smb2_pdu_state = DCE2_SMB_PDU_STATE__RAW_DATA;
+ }
+ }
+}
+
+//-------------------------------------------------------------------------
+// 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 (Smb2Error(smb_hdr) and structure_size == SMB2_ERROR_RESPONSE_STRUC_SIZE)
+ {
+ DCE2_Smb2RequestTracker* rtr = ttr->findDataRtracker(mid);
+ if (rtr and rtr->get_file_id())
+ {
+ if (ssd->ftracker_tcp->file_id == rtr->get_file_id())
+ ssd->ftracker_tcp = NULL;
+ ttr->removeFtracker(rtr->get_file_id());
+ }
+ ttr->removeDataRtracker(mid);
+ dce2_smb_stats.v2_read_err_resp++;
+ }
+ // 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)
+ 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)
+
+ DCE2_Smb2ReadResponse(ssd, smb_hdr, (const Smb2ReadResponseHdr*)smb_data, end, ttr, mid);
+ }
+ else
+ {
+ dce2_smb_stats.v2_read_inv_str_sz++;
+ }
+}
+
+//-------------------------------------------------------------------------
+// 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;
+ DCE2_Smb2RequestTracker* writetracker = nullptr;
+
+ fileId_persistent = alignedNtohq((const uint64_t*)(&(smb_write_hdr->fileId_persistent)));
+
+ if (ssd->max_outstanding_requests > str->getTotalRequestsPending())
+ {
+ writetracker = new DCE2_Smb2RequestTracker(
+ 0, fileId_persistent, nullptr, 0, nullptr);
+ ttr->insertDataRtracker(mid, writetracker);
+ }
+ else
+ {
+ 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)
+ {
+ 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) // file tracker can not be NULL 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->file_offset = offset;
+ ssd->ftracker_tcp = ftracker;
+ DCE2_Smb2ProcessFileData(ssd, file_data, data_size, FILE_UPLOAD);
+ ftracker->file_offset += data_size;
+ uint32_t total_data_length = alignedNtohl((const uint32_t*)&(smb_write_hdr->length));
+ debug_logf(dce_smb_trace, nullptr, "smbv2 total_data=%d data_size=%d\n",total_data_length,data_size);
+ if (total_data_length > (uint32_t)data_size)
+ {
+ ftracker->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))
+ {
+ DCE2_Smb2RequestTracker* wtr = ttr->findDataRtracker(mid);
+ if (wtr and wtr->get_file_id())
+ {
+ if (ssd->ftracker_tcp->file_id == wtr->get_file_id())
+ ssd->ftracker_tcp = NULL;
+ ttr->removeFtracker(wtr->get_file_id());
+ }
+ ttr->removeDataRtracker(mid);
+ dce2_smb_stats.v2_wrt_err_resp++;
+ }
+ // 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)
+ DCE2_Smb2WriteRequest(ssd, smb_hdr, (const Smb2WriteRequestHdr*)smb_data, end, str, ttr, mid);
+ }
+ else if (structure_size == SMB2_WRITE_RESPONSE_STRUC_SIZE)
+ {
+ ttr->removeDataRtracker(mid);
+ }
+ else
+ {
+ 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)
+ {
+ DCE2_Smb2RemoveSidInSsd(ssd, sid);
+ }
+ else
+ {
+ dce2_smb_stats.v2_logoff_inv_str_sz++;
+ }
+}
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2016-2019 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, DCE2_Smb2SessionTracker* str, uint32_t tid);
+
+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);
+
+void DCE2_Smb2ProcessFileData(DCE2_Smb2SsnData*, const uint8_t* file_data,
+ uint32_t data_size, FileDirection dir);
+
+void DCE2_Smb2CloseCmd(DCE2_Smb2SsnData*, const Smb2Hdr*,
+ const uint8_t* smb_data, const uint8_t* end, DCE2_Smb2TreeTracker* ttr);
+
+void DCE2_Smb2Logoff(DCE2_Smb2SsnData*, const uint8_t* smb_data,
+ const uint64_t sid);
+
+#endif
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2019 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 "main/snort_debug.h"
+
+using namespace snort;
+
+size_t session_cache_size;
+THREAD_LOCAL SmbSessionCache* smb2_session_cache;
+
+DCE2_Smb2SessionTracker* DCE2_Smb2FindElseCreateSid(DCE2_Smb2SsnData* ssd, const
+ uint64_t sid)
+{
+ // Local MAP search
+ DCE2_Smb2SessionTracker* stracker = DCE2_Smb2FindSidInSsd(ssd, sid);
+
+ if (!stracker)
+ {
+ // Global Hash Search
+ bool entry_created = false;
+ stracker = DCE2_SmbSessionCacheFindElseCreate(sid, &entry_created);
+ assert(stracker);
+ if (entry_created)
+ {
+ stracker->set_session_id(sid);
+ }
+ DCE2_Smb2InsertSidInSsd(ssd, sid, stracker);
+ }
+
+ return stracker;
+}
+
+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)
+ {
+ debug_logf(dce_smb_trace, nullptr, "Not inserting TID (%u) because it's "
+ "not IPC and not inspecting normal file data.\n", tid);
+ return nullptr;
+ }
+
+ DCE2_Smb2TreeTracker* ttracker = new DCE2_Smb2TreeTracker(tid, share_type);
+ str->insertTtracker(tid, ttracker);
+ return ttracker;
+}
+
+DCE2_Smb2TreeTracker* DCE2_Smb2FindElseCreateTid(DCE2_Smb2SsnData* ssd, const uint32_t tid,
+ uint8_t share_type, DCE2_Smb2SessionTracker* str)
+{
+ DCE2_Smb2TreeTracker* ttr = str->findTtracker(tid);
+ if (!ttr)
+ {
+ ttr = DCE2_Smb2InsertTid(ssd, tid, share_type, str);
+ }
+
+ return ttr;
+}
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2016-2019 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"
+#include "hash/lru_cache_shared.h"
+
+#define SMB2_SID_HASH(sid) std::hash<uint64_t>()(sid)
+
+template<typename Key, typename Value, typename Hash>
+class SmbSessionCache_map : public LruCacheShared<Key, Value, Hash>
+{
+public:
+ SmbSessionCache_map() = delete;
+ SmbSessionCache_map(const SmbSessionCache_map& arg) = delete;
+ SmbSessionCache_map& operator=(const SmbSessionCache_map& arg) = delete;
+ SmbSessionCache_map(const size_t initial_size) : LruCacheShared<Key, Value, Hash>(initial_size) {}
+ virtual ~SmbSessionCache_map() {}
+};
+
+typedef SmbSessionCache_map<uint64_t, DCE2_Smb2SessionTracker, std::hash<uint64_t> > SmbSessionCache;
+
+extern THREAD_LOCAL SmbSessionCache* smb2_session_cache;
+extern size_t session_cache_size;
+
+// SMB2 Session cache manipulation functions
+inline void DCE2_SmbSessionCacheInit(const size_t cache_size)
+{
+ smb2_session_cache = new SmbSessionCache(cache_size);
+}
+
+inline DCE2_Smb2SessionTracker* DCE2_SmbSessionCacheFind(uint64_t sid)
+{
+ return (smb2_session_cache->find(SMB2_SID_HASH(sid))).get();
+}
+
+inline DCE2_Smb2SessionTracker* DCE2_SmbSessionCacheFindElseCreate(uint64_t sid,
+ bool* entry_created)
+{
+ return (smb2_session_cache->find_else_create(SMB2_SID_HASH(sid), entry_created)).get();
+}
+
+inline bool DCE2_SmbSessionCacheRemove(uint64_t sid)
+{
+ return smb2_session_cache->remove(SMB2_SID_HASH(sid));
+}
+
+// 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 (SMB_NT_STATUS_SEVERITY__ERROR == (uint8_t)(hdr->status >> 30));
+}
+
+inline DCE2_Smb2SessionTracker* DCE2_Smb2FindSidInSsd(DCE2_Smb2SsnData* ssd, const
+ uint64_t sid)
+{
+ return (DCE2_Smb2SessionTracker*)(ssd->session_trackers.Find(sid));
+}
+
+inline void DCE2_Smb2InsertSidInSsd(DCE2_Smb2SsnData* ssd, const uint64_t sid,
+ DCE2_Smb2SessionTracker* stracker)
+{
+ ssd->session_trackers.Insert(sid, stracker);
+}
+
+inline void DCE2_Smb2RemoveSidInSsd(DCE2_Smb2SsnData* ssd, const uint64_t sid)
+{
+ ssd->session_trackers.Remove(sid);
+}
+
+DCE2_Smb2TreeTracker* DCE2_Smb2InsertTid(DCE2_Smb2SsnData*, const uint32_t tid, uint8_t share_type,
+ DCE2_Smb2SessionTracker*);
+
+DCE2_Smb2TreeTracker* DCE2_Smb2FindElseCreateTid(DCE2_Smb2SsnData*, const uint32_t tid,
+ uint8_t share_type, DCE2_Smb2SessionTracker*);
+
+DCE2_Smb2SessionTracker* DCE2_Smb2FindElseCreateSid(DCE2_Smb2SsnData*, const uint64_t sid);
+
+DCE2_Ret DCE2_Smb2InitData(DCE2_Smb2SsnData*);
+
+#endif
+
{ CountType::SUM, "smb_server_segs_reassembled", "total smb server segments reassembled" },
{ CountType::SUM, "max_outstanding_requests", "total smb maximum outstanding requests" },
{ CountType::SUM, "files_processed", "total smb files processed" },
- { CountType::SUM, "smbv2_create", "total number of SMBv2 create packets seen" },
- { CountType::SUM, "smbv2_write", "total number of SMBv2 write packets seen" },
- { CountType::SUM, "smbv2_read", "total number of SMBv2 read packets seen" },
- { CountType::SUM, "smbv2_set_info", "total number of SMBv2 set info packets seen" },
- { CountType::SUM, "smbv2_tree_connect", "total number of SMBv2 tree connect packets seen" },
- { CountType::SUM, "smbv2_tree_disconnect",
+ { 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_inv_str_sz",
+ "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" },
+ { 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" },
+ { CountType::SUM, "v2_tree_cnct_ignored",
+ "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" },
+ { CountType::SUM, "v2_tree_cnct_resp_hdr_err",
+ "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_inv_file_data",
+ "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" },
+ { CountType::SUM, "v2_crt_resp_hdr_err",
+ "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" },
+ { CountType::SUM, "v2_crt_rtrkr_misng",
+ "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" },
+ { CountType::SUM, "v2_crt_tree_trkr_misng",
+ "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_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" },
+ { CountType::SUM, "v2_wrt_req_hdr_err",
+ "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_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" },
+ { CountType::SUM, "v2_read_rtrkr_misng",
+ "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" },
+ { CountType::SUM, "v2_read_req_hdr_err",
+ "total number of SMBv2 read request packets ignored due to corrupted header" },
+ { CountType::SUM, "v2_stinf", "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_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" },
+ { CountType::SUM, "v2_stinf_req_ftrkr_misng",
+ "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" },
+ { 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_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" },
+ { CountType::SUM, "v2_cls_req_ftrkr_misng",
+ "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" },
+ { CountType::SUM, "v2_tree_discn",
"total number of SMBv2 tree disconnect packets seen" },
- { CountType::SUM, "smbv2_close", "total number of SMBv2 close packets seen" },
+ { CountType::SUM, "v2_tree_discn_ignored",
+ "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" },
+ { CountType::SUM, "v2_tree_discn_req_hdr_err",
+ "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" },
+ { 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" },
+ { 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" },
+ { CountType::SUM, "v2_msgs_uninspected",
+ "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::NOW, "concurrent_sessions", "total concurrent sessions" },
{ CountType::MAX, "max_concurrent_sessions", "maximum concurrent sessions" },
{ CountType::END, nullptr, nullptr }
{ "smb_legacy_mode", Parameter::PT_BOOL, nullptr, "false",
"inspect only SMBv1" },
+ { "smb_max_credit", Parameter::PT_INT, "1:65536", "8192",
+ "Maximum number of outstanding request" },
+
+ { "memcap", Parameter::PT_INT, "512:maxSZ", "8388608",
+ "Memory utilization limit on smb" },
+
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
else if ( v.is("smb_legacy_mode"))
config.legacy_mode = v.get_bool();
+ else if ( v.is("smb_max_credit") )
+ config.smb_max_credit = v.get_uint16();
+
+ else if ( v.is("memcap") )
+ config.memcap = v.get_size();
+
return true;
}
ConfigLogger::log_list("smb_invalid_shares",
get_shares(config.smb_invalid_shares).c_str());
ConfigLogger::log_flag("smb_legacy_mode", config.legacy_mode);
+ ConfigLogger::log_limit("smb_max_credit", config.smb_max_credit, 0, 1);
+
}
int16_t smb_file_depth;
DCE2_List* smb_invalid_shares;
bool legacy_mode;
+ uint16_t smb_max_credit;
+ size_t memcap;
};
class Dce2SmbModule : public snort::Module
return sc->smb_invalid_shares;
}
+inline uint16_t DCE2_ScSmbMaxCredit(const dce2SmbProtoConf* sc)
+{
+ if (sc == nullptr)
+ return 8192;
+ return sc->smb_max_credit;
+}
+
+inline size_t DCE2_ScSmbMemcap(const dce2SmbProtoConf* sc)
+{
+ if (sc == nullptr)
+ return 8388608;
+ return sc->memcap;
+}
+
+inline uint16_t DCE2_ScSmbMaxCompound(const dce2SmbProtoConf* sc)
+{
+ if (sc == nullptr)
+ return 3;
+ return sc->smb_max_compound;
+}
+
inline bool DCE2_GcSmbFingerprintClient(const dce2SmbProtoConf* sc)
{
if (sc == nullptr)
const SmbNtHdr* nt_hdr = nullptr;
uint32_t nb_len = 0;
- DCE2_SmbSsnData* sd = get_dce2_smb_session_data(flow);
+ DCE2_SsnData* sd = get_dce2_session_data(flow);
- if ( dce2_paf_abort((DCE2_SsnData*)sd) )
+ if ( dce2_paf_abort(sd) )
{
return StreamSplitter::ABORT;
}
inspectors. These inspectors only serve to locate the 'tunnel' setup
content. If/when the setup content is located, the session is transfered
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.
+For SMBv2, it supports TCP as transport and it also supports
+Multiple File transfer on single SMB2 connection.
#include "config.h"
#endif
-#include "dce_smb.h"
+#include "smb_message.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 "main/snort_debug.h"
+#include "packet_io/active.h"
#include "protocols/packet.h"
#include "utils/util.h"
-#include "packet_io/active.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_smb_utils.h"
-#include "dce_smb2.h"
using namespace snort;
}
}
-static void DCE2_SmbDataFree(DCE2_SmbSsnData* ssd)
+void DCE2_SmbDataFree(DCE2_SmbSsnData* ssd)
{
if (ssd == nullptr)
return;
DCE2_BufferDestroy(ssd->srv_seg);
ssd->srv_seg = nullptr;
}
-
- if (ssd->smb2_requests != nullptr)
- {
- DCE2_Smb2CleanRequests(ssd->smb2_requests);
- ssd->smb2_requests = nullptr;
- }
}
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()
{
- DCE2_SmbDataFree(&dce2_smb_session);
+ 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;
-DCE2_SmbSsnData* get_dce2_smb_session_data(Flow* flow)
-{
- Dce2SmbFlowData* fd = (Dce2SmbFlowData*)flow->get_flow_data(Dce2SmbFlowData::inspector_id);
- return fd ? &fd->dce2_smb_session : nullptr;
-}
-
-static DCE2_SmbSsnData* set_new_dce2_smb_session(Packet* p)
+static inline DCE2_SmbSsnData* set_new_dce2_smb_session(Packet* p)
{
Dce2SmbFlowData* fd = new Dce2SmbFlowData;
- memset(&fd->dce2_smb_session,0,sizeof(DCE2_SmbSsnData));
+ fd->smb_version = DCE2_SMB_VERSION_1;
+ fd->dce2_smb_session_data = new DCE2_SmbSsnData();
p->flow->set_flow_data(fd);
- return(&fd->dce2_smb_session);
+ return (DCE2_SmbSsnData*)(fd->dce2_smb_session_data);
}
-static DCE2_SmbSsnData* dce2_create_new_smb_session(Packet* p, dce2SmbProtoConf* config)
+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 )
}
// This is the main entry point for SMB1 processing.
-static void DCE2_Smb1Process(DCE2_SmbSsnData* ssd)
+void DCE2_Smb1Process(DCE2_SmbSsnData* ssd)
{
dce2_smb_stats.smb_pkts++;
- const Packet* p = DetectionEngine::get_current_packet();
+ Packet* p = DetectionEngine::get_current_packet();
const uint8_t* data_ptr = p->data;
uint16_t data_len = p->dsize;
DCE2_Buffer** seg_buf = DCE2_SmbGetSegBuffer(ssd);
if (SmbId(smb_hdr) == DCE2_SMB2_ID)
{
- ssd->sd.flags |= DCE2_SSN_FLAG__SMB2;
if (!DCE2_GcIsLegacyMode((dce2SmbProtoConf*)ssd->sd.config))
{
- DCE2_Smb2InitFileTracker(&(ssd->ftracker), false, 0);
- DCE2_Smb2Process(ssd);
+ // Upgrade connection to SMBv2
+ dce2SmbProtoConf* config = (dce2SmbProtoConf*)ssd->sd.config;
+ Dce2SmbFlowData* fd = (Dce2SmbFlowData*)p->flow->get_flow_data(Dce2SmbFlowData::inspector_id);
+ 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;
return;
}
}
}
-DCE2_SmbSsnData* dce2_handle_smb_session(Packet* p, dce2SmbProtoConf* config)
-{
- DCE2_SmbSsnData* dce2_smb_sess = get_dce2_smb_session_data(p->flow);
+/* smb2 Functions */
- if (dce2_smb_sess == nullptr)
- {
- dce2_smb_sess = dce2_create_new_smb_session(p, config);
- }
-
- return dce2_smb_sess;
+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();
+ DCE2_Smb2InitData((DCE2_Smb2SsnData*)fd->dce2_smb_session_data);
+ p->flow->set_flow_data(fd);
+ return((DCE2_Smb2SsnData*)fd->dce2_smb_session_data);
}
-// This is the main entry point for SMB processing
-void DCE2_SmbProcess(DCE2_SmbSsnData* ssd)
+DCE2_Smb2SsnData* dce2_create_new_smb2_session(Packet* p, dce2SmbProtoConf* config)
{
- if (DCE2_GcIsLegacyMode((dce2SmbProtoConf*)ssd->sd.config))
+ DCE2_Smb2SsnData* dce2_smb2_sess = set_new_dce2_smb2_session(p);
+ if ( dce2_smb2_sess )
{
- DCE2_Smb1Process(ssd);
- return;
- }
+ dce2_smb2_sess->sd.flags |= DCE2_SSN_FLAG__SMB2;
+ dce2_smb2_sess->dialect_index = DCE2_SENTINEL;
- Packet* p = DetectionEngine::get_current_packet();
- DCE2_SmbVersion smb_version = DCE2_Smb2Version(p);
- if (smb_version == DCE2_SMB_VERISON_1)
- {
- if ((ssd->sd.flags & DCE2_SSN_FLAG__SMB2))
- {
- ssd->sd.flags &= ~DCE2_SSN_FLAG__SMB2;
- DCE2_SmbCleanFileTracker(&(ssd->ftracker));
- ssd->ftracker.is_smb2 = false;
- }
- }
- else if (smb_version == DCE2_SMB_VERISON_2)
- {
- if (!(ssd->sd.flags & DCE2_SSN_FLAG__SMB2))
- {
- DCE2_SmbCleanFileTracker(&(ssd->ftracker));
- DCE2_Smb2InitFileTracker(&(ssd->ftracker), false, 0);
- ssd->sd.flags |= DCE2_SSN_FLAG__SMB2;
- }
+ DCE2_ResetRopts(&dce2_smb2_sess->sd, p);
+
+ dce2_smb_stats.smb_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);
}
- if (ssd->sd.flags & DCE2_SSN_FLAG__SMB2)
- DCE2_Smb2Process(ssd);
- else
- DCE2_Smb1Process(ssd);
+ 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;
}
#include <cstdint>
-namespace snort
-{
-struct Packet;
-}
+#include "protocols/packet.h"
+#include "smb_common.h"
#pragma pack(1)
#pragma pack()
void DCE2_SmbInitGlobals();
-void DCE2_SmbProcess(struct DCE2_SmbSsnData*);
-DCE2_SmbSsnData* dce2_handle_smb_session(snort::Packet*, struct dce2SmbProtoConf*);
+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*);
#endif