dce_common.h
dce_context_data.cc
dce_context_data.h
- dce_db.h
dce_expected_session.cc
dce_expected_session.h
dce_http_proxy.cc
dce_http_server_module.h
dce_http_server_splitter.cc
dce_http_server_splitter.h
- dce_list.h
dce_list.cc
- dce_smb.cc
- dce_smb.h
+ dce_list.h
+ dce_smb1.cc
+ dce_smb1.h
dce_smb2.cc
dce_smb2.h
- dce_smb2_commands.cc
- dce_smb2_commands.h
- dce_smb2_utils.cc
- dce_smb2_utils.h
+ dce_smb2_file.cc
+ dce_smb2_file.h
+ dce_smb2_request.h
+ dce_smb2_session.cc
+ dce_smb2_session.h
+ dce_smb2_tree.cc
+ dce_smb2_tree.h
dce_smb_commands.cc
dce_smb_commands.h
+ dce_smb_common.cc
+ dce_smb_common.h
+ dce_smb_inspector.cc
+ dce_smb_inspector.h
dce_smb_module.cc
dce_smb_module.h
dce_smb_paf.cc
#include "utils/util.h"
#include "dce_expected_session.h"
-#include "dce_smb.h"
+#include "dce_smb1.h"
#include "dce_smb_module.h"
#include "dce_smb_utils.h"
#include "dce_tcp.h"
#include "dce_context_data.h"
#include "dce_http_proxy_module.h"
#include "dce_http_server_module.h"
+#include "dce_smb1.h"
+#include "dce_smb_common.h"
#include "dce_smb_utils.h"
#include "dce_tcp.h"
#include "dce_udp.h"
void DCE2_Detect(DCE2_SsnData* sd)
{
+ if (!sd) return ;
DceContextData::set_current_ropts(sd);
if ( using_rpkt )
{
void reset();
};
-inline void DCE2_ResetRopts(DCE2_SsnData* sd, snort::Packet* p)
+inline void DCE2_ResetRopts(DCE2_SsnData* sd, const snort::Packet* p)
{
sd->ropts.first_frag = DCE2_SENTINEL;
sd->ropts.opnum = DCE2_SENTINEL;
+++ /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"
-
-template<typename Key, typename Value, typename Hash>
-class DCE2_Db
-{
-public:
-
- virtual void SetDoNotFree() = 0;
- virtual bool Insert(const Key& key, Value data) = 0;
- virtual Value Find(const Key& key) = 0;
- virtual void Remove(const Key& key) = 0;
- virtual int GetSize() = 0;
- virtual std::vector< std::pair<Key, Value> > get_all_entry() = 0;
-};
-
-template<typename Key, typename Value, typename Hash>
-class DCE2_DbMap : public DCE2_Db<Key, Value, Hash>
-{
-public:
-
- DCE2_DbMap() = default;
-
- ~DCE2_DbMap()
- {
- auto it = Map.cbegin();
- while (it != Map.cend())
- {
- if (!do_not_free)
- delete it->second;
- it = Map.erase(it);
- }
- }
-
- void SetDoNotFree() override;
- bool Insert(const Key& key, Value data) override;
- Value Find(const Key& key) override;
- void Remove(const Key& key) override;
- int GetSize() override
- {
- return Map.size();
- }
-
- std::vector< std::pair<Key, Value> > get_all_entry() override;
-
-private:
- std::unordered_map<Key, Value, Hash> Map;
- bool do_not_free = false;
-};
-
-template<typename Key, typename Value, typename Hash>
-void DCE2_DbMap<Key, Value, Hash>::SetDoNotFree()
-{
- do_not_free = true;
-}
-
-template<typename Key, typename Value, typename Hash>
-bool DCE2_DbMap<Key, Value, Hash>::Insert(const Key& key, Value data)
-{
- return Map.insert(std::make_pair(key,data)).second;
-}
-
-template<typename Key, typename Value, typename Hash>
-Value DCE2_DbMap<Key, Value, Hash>::Find(const Key& key)
-{
- auto elem = Map.find(key);
- if (elem != Map.end())
- return elem->second;
- return nullptr;
-}
-
-template<typename Key, typename Value, typename Hash>
-void DCE2_DbMap<Key, Value, Hash>::Remove(const Key& key)
-{
- auto elem = Map.find(key);
- if (elem != Map.end())
- {
- if (!do_not_free)
- 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
-
+++ /dev/null
-//--------------------------------------------------------------------------
-// Copyright (C) 2016-2020 Cisco and/or its affiliates. All rights reserved.
-//
-// This program is free software; you can redistribute it and/or modify it
-// under the terms of the GNU General Public License Version 2 as published
-// by the Free Software Foundation. You may not use, modify or distribute
-// this program under any other version of the GNU General Public License.
-//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License along
-// with this program; if not, write to the Free Software Foundation, Inc.,
-// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-//--------------------------------------------------------------------------
-
-// dce_smb.h author Rashmi Pitre <rrp@cisco.com>
-// based on work by Todd Wease
-
-#ifndef DCE_SMB_H
-#define DCE_SMB_H
-
-#include "dce_co.h"
-#include "protocols/packet.h"
-#include "profiler/profiler_defs.h"
-#include "smb_common.h"
-#include "smb_message.h"
-
-#define DCE2_SMB_NAME "dce_smb"
-#define DCE2_SMB_HELP "dce over smb inspection"
-#define DCE2_SMB_RPKT_TYPE_MAX 4
-#define DCE2_SMB_RPKT_TYPE_START 1
-
-#define DCE2_SMB_BAD_NBSS_TYPE 2
-#define DCE2_SMB_BAD_TYPE 3
-#define DCE2_SMB_BAD_ID 4
-#define DCE2_SMB_BAD_WCT 5
-#define DCE2_SMB_BAD_BCC 6
-#define DCE2_SMB_BAD_FORM 7
-#define DCE2_SMB_BAD_OFF 8
-#define DCE2_SMB_TDCNT_ZE 9
-#define DCE2_SMB_NB_LT_SMBHDR 10
-#define DCE2_SMB_NB_LT_COM 11
-#define DCE2_SMB_NB_LT_BCC 12
-#define DCE2_SMB_NB_LT_DSIZE 13
-#define DCE2_SMB_TDCNT_LT_DSIZE 14
-#define DCE2_SMB_DSENT_GT_TDCNT 15
-#define DCE2_SMB_BCC_LT_DSIZE 16
-#define DCE2_SMB_INVALID_DSIZE 17
-#define DCE2_SMB_EXCESSIVE_TREE_CONNECTS 18
-#define DCE2_SMB_EXCESSIVE_READS 19
-#define DCE2_SMB_EXCESSIVE_CHAINING 20
-#define DCE2_SMB_MULT_CHAIN_SS 21
-#define DCE2_SMB_MULT_CHAIN_TC 22
-#define DCE2_SMB_CHAIN_SS_LOGOFF 23
-#define DCE2_SMB_CHAIN_TC_TDIS 24
-#define DCE2_SMB_CHAIN_OPEN_CLOSE 25
-#define DCE2_SMB_INVALID_SHARE 26
-
-#define DCE2_SMB_V1 44
-#define DCE2_SMB_V2 45
-#define DCE2_SMB_INVALID_BINDING 46
-#define DCE2_SMB2_EXCESSIVE_COMPOUNDING 47
-#define DCE2_SMB_DCNT_ZERO 48
-#define DCE2_SMB_DCNT_MISMATCH 49
-#define DCE2_SMB_MAX_REQS_EXCEEDED 50
-#define DCE2_SMB_REQS_SAME_MID 51
-#define DCE2_SMB_DEPR_DIALECT_NEGOTIATED 52
-#define DCE2_SMB_DEPR_COMMAND_USED 53
-#define DCE2_SMB_UNUSUAL_COMMAND_USED 54
-#define DCE2_SMB_INVALID_SETUP_COUNT 55
-#define DCE2_SMB_MULTIPLE_NEGOTIATIONS 56
-#define DCE2_SMB_EVASIVE_FILE_ATTRS 57
-#define DCE2_SMB_INVALID_FILE_OFFSET 58
-#define DCE2_SMB_BAD_NEXT_COMMAND_OFFSET 59
-
-#define DCE2_SMB_BAD_NBSS_TYPE_STR "SMB - bad NetBIOS session service session type"
-#define DCE2_SMB_BAD_TYPE_STR "SMB - bad SMB message type"
-#define DCE2_SMB_BAD_ID_STR "SMB - bad SMB Id (not \\xffSMB for SMB1 or not \\xfeSMB for SMB2)"
-#define DCE2_SMB_BAD_WCT_STR "SMB - bad word count or structure size"
-#define DCE2_SMB_BAD_BCC_STR "SMB - bad byte count"
-#define DCE2_SMB_BAD_FORM_STR "SMB - bad format type"
-#define DCE2_SMB_BAD_OFF_STR "SMB - bad offset"
-#define DCE2_SMB_TDCNT_ZE_STR "SMB - zero total data count"
-#define DCE2_SMB_NB_LT_SMBHDR_STR "SMB - NetBIOS data length less than SMB header length"
-#define DCE2_SMB_NB_LT_COM_STR "SMB - remaining NetBIOS data length less than command length"
-#define DCE2_SMB_NB_LT_BCC_STR "SMB - remaining NetBIOS data length less than command byte count"
-#define DCE2_SMB_NB_LT_DSIZE_STR \
- "SMB - remaining NetBIOS data length less than command data size"
-#define DCE2_SMB_TDCNT_LT_DSIZE_STR \
- "SMB - remaining total data count less than this command data size"
-#define DCE2_SMB_DSENT_GT_TDCNT_STR \
- "SMB - total data sent (STDu64) greater than command total data expected"
-#define DCE2_SMB_BCC_LT_DSIZE_STR "SMB - byte count less than command data size (STDu64)"
-#define DCE2_SMB_INVALID_DSIZE_STR "SMB - invalid command data size for byte count"
-#define DCE2_SMB_EXCESSIVE_TREE_CONNECTS_STR \
- "SMB - excessive tree connect requests with pending tree connect responses"
-#define DCE2_SMB_EXCESSIVE_READS_STR "SMB - excessive read requests with pending read responses"
-#define DCE2_SMB_EXCESSIVE_CHAINING_STR "SMB - excessive command chaining"
-#define DCE2_SMB_MULT_CHAIN_SS_STR "SMB - multiple chained tree connect requests"
-#define DCE2_SMB_MULT_CHAIN_TC_STR "SMB - multiple chained tree connect requests"
-#define DCE2_SMB_CHAIN_SS_LOGOFF_STR "SMB - chained/compounded login followed by logoff"
-#define DCE2_SMB_CHAIN_TC_TDIS_STR \
- "SMB - chained/compounded tree connect followed by tree disconnect"
-#define DCE2_SMB_CHAIN_OPEN_CLOSE_STR \
- "SMB - chained/compounded open pipe followed by close pipe"
-#define DCE2_SMB_INVALID_SHARE_STR "SMB - invalid share access"
-
-#define DCE2_SMB_V1_STR "SMB - invalid SMB version 1 seen"
-#define DCE2_SMB_V2_STR "SMB - invalid SMB version 2 seen"
-#define DCE2_SMB_INVALID_BINDING_STR "SMB - invalid user, tree connect, file binding"
-#define DCE2_SMB2_EXCESSIVE_COMPOUNDING_STR "SMB - excessive command compounding"
-#define DCE2_SMB_DCNT_ZERO_STR "SMB - zero data count"
-#define DCE2_SMB_DCNT_MISMATCH_STR "SMB - data count mismatch in command and format"
-#define DCE2_SMB_MAX_REQS_EXCEEDED_STR "SMB - maximum number of outstanding requests exceeded"
-#define DCE2_SMB_REQS_SAME_MID_STR "SMB - outstanding requests with same MID"
-#define DCE2_SMB_DEPR_DIALECT_NEGOTIATED_STR "SMB - deprecated dialect negotiated"
-#define DCE2_SMB_DEPR_COMMAND_USED_STR "SMB - deprecated command used"
-#define DCE2_SMB_UNUSUAL_COMMAND_USED_STR "SMB - unusual command used"
-#define DCE2_SMB_INVALID_SETUP_COUNT_STR "SMB - invalid setup count for command"
-#define DCE2_SMB_MULTIPLE_NEGOTIATIONS_STR \
- "SMB - client attempted multiple dialect negotiations on session"
-#define DCE2_SMB_EVASIVE_FILE_ATTRS_STR \
- "SMB - client attempted to create or set a file's attributes to readonly/hidden/system"
-#define DCE2_SMB_INVALID_FILE_OFFSET_STR \
- "SMB - file offset provided is greater than file size specified"
-#define DCE2_SMB_BAD_NEXT_COMMAND_OFFSET_STR \
- "SMB - next command specified in SMB2 header is beyond payload boundary"
-
-struct dce2SmbStats
-{
- PegCount events;
-
- PegCount co_pdus;
- PegCount co_bind;
- PegCount co_bind_ack;
- PegCount co_alter_ctx;
- PegCount co_alter_ctx_resp;
- PegCount co_bind_nack;
- PegCount co_request;
- PegCount co_response;
- PegCount co_cancel;
- PegCount co_orphaned;
- PegCount co_fault;
- PegCount co_auth3;
- PegCount co_shutdown;
- PegCount co_reject;
- PegCount co_ms_pdu;
- PegCount co_other_req;
- PegCount co_other_resp;
- PegCount co_req_fragments;
- PegCount co_resp_fragments;
- PegCount co_cli_max_frag_size;
- PegCount co_cli_min_frag_size;
- PegCount co_cli_seg_reassembled;
- PegCount co_cli_frag_reassembled;
- PegCount co_srv_max_frag_size;
- PegCount co_srv_min_frag_size;
- PegCount co_srv_seg_reassembled;
- PegCount co_srv_frag_reassembled;
-
- PegCount smb_sessions;
- PegCount smb_pkts;
- PegCount smb_ignored_bytes;
- PegCount smb_cli_seg_reassembled;
- PegCount smb_srv_seg_reassembled;
- PegCount smb_max_outstanding_requests;
- // FIXIT-M more peg count foo
- /*uint64_t smb_com_stats[2][SMB_MAX_NUM_COMS];
- uint64_t smb_chained_stats[2][SMB_ANDX_COM__MAX][SMB_MAX_NUM_COMS];
- // The +1 is for codes beyond the range of the highest valid subcommand code
- // Indicates a bogus subcommand
- uint64_t smb_trans_subcom_stats[2][TRANS_SUBCOM_MAX+1];
- uint64_t smb_trans2_subcom_stats[2][TRANS2_SUBCOM_MAX+1];
- uint64_t smb_nt_transact_subcom_stats[2][NT_TRANSACT_SUBCOM_MAX+1];
- */
- PegCount smb_files_processed;
- /* SMB2 stats */
- PegCount v2_setup;
- PegCount v2_setup_err_resp;
- PegCount v2_setup_inv_str_sz;
- PegCount v2_setup_resp_hdr_err;
- PegCount v2_tree_cnct;
- PegCount v2_tree_cnct_err_resp;
- PegCount v2_tree_cnct_ignored;
- PegCount v2_tree_cnct_inv_str_sz;
- PegCount v2_tree_cnct_resp_hdr_err;
- PegCount v2_crt;
- PegCount v2_crt_err_resp;
- PegCount v2_crt_inv_file_data;
- PegCount v2_crt_inv_str_sz;
- PegCount v2_crt_resp_hdr_err;
- PegCount v2_crt_req_hdr_err;
- PegCount v2_crt_rtrkr_misng;
- PegCount v2_crt_req_ipc;
- PegCount v2_crt_tree_trkr_misng;
- PegCount v2_wrt;
- PegCount v2_wrt_err_resp;
- PegCount v2_wrt_ignored;
- PegCount v2_wrt_inv_str_sz;
- PegCount v2_wrt_req_hdr_err;
- PegCount v2_read;
- PegCount v2_read_err_resp;
- PegCount v2_read_ignored;
- PegCount v2_read_inv_str_sz;
- PegCount v2_read_rtrkr_misng;
- PegCount v2_read_resp_hdr_err;
- PegCount v2_read_req_hdr_err;
- PegCount v2_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;
-};
-
-extern THREAD_LOCAL dce2SmbStats dce2_smb_stats;
-extern THREAD_LOCAL snort::ProfileStats dce2_smb_pstat_main;
-
-enum DCE2_SmbSsnState
-{
- DCE2_SMB_SSN_STATE__START = 0x00,
- DCE2_SMB_SSN_STATE__NEGOTIATED = 0x01,
- DCE2_SMB_SSN_STATE__FP_CLIENT = 0x02, // Fingerprinted client
- DCE2_SMB_SSN_STATE__FP_SERVER = 0x04 // Fingerprinted server
-};
-
-enum DCE2_SmbDataState
-{
- DCE2_SMB_DATA_STATE__NETBIOS_HEADER,
- DCE2_SMB_DATA_STATE__SMB_HEADER,
- DCE2_SMB_DATA_STATE__NETBIOS_PDU
-};
-
-enum DCE2_SmbPduState
-{
- DCE2_SMB_PDU_STATE__COMMAND,
- DCE2_SMB_PDU_STATE__RAW_DATA
-};
-
-enum DCE2_SmbFileDirection
-{
- DCE2_SMB_FILE_DIRECTION__UNKNOWN = 0,
- DCE2_SMB_FILE_DIRECTION__UPLOAD,
- DCE2_SMB_FILE_DIRECTION__DOWNLOAD
-};
-
-enum SmbAndXCom
-{
- SMB_ANDX_COM__NONE,
- SMB_ANDX_COM__OPEN_ANDX,
- SMB_ANDX_COM__READ_ANDX,
- SMB_ANDX_COM__WRITE_ANDX,
- SMB_ANDX_COM__TREE_CONNECT_ANDX,
- SMB_ANDX_COM__SESSION_SETUP_ANDX,
- SMB_ANDX_COM__LOGOFF_ANDX,
- SMB_ANDX_COM__NT_CREATE_ANDX,
- SMB_ANDX_COM__MAX
-};
-
-struct DCE2_SmbWriteAndXRaw
-{
- int remaining; // A signed integer so it can be negative
- DCE2_Buffer* buf;
-};
-
-struct DCE2_SmbFileChunk
-{
- uint64_t offset;
- uint32_t length;
- uint8_t* data;
-};
-
-enum DCE2_SmbVersion
-{
- DCE2_SMB_VERSION_NULL,
- DCE2_SMB_VERSION_1,
- DCE2_SMB_VERSION_2
-};
-
-struct DCE2_SmbFileTracker
-{
- union
- {
- struct
- {
- int file_id; // A signed integer so it can be set to sentinel
- uint16_t u_id;
- uint16_t tree_id;
- } id_smb1;
-
- struct
- {
- uint64_t file_id;
- } id_smb2;
- } file_key;
-
- bool is_ipc;
- bool is_smb2;
- char* file_name;
- uint16_t file_name_size;
- uint64_t file_name_hash;
-
- union
- {
- struct
- {
- // If pipe has been set to byte mode via TRANS_SET_NMPIPE_STATE
- bool byte_mode;
-
- // For Windows 2000
- bool used;
-
- // For WriteAndX requests that use raw mode flag
- // Windows only
- DCE2_SmbWriteAndXRaw* writex_raw;
-
- // Connection-oriented DCE/RPC tracker
- DCE2_CoTracker* co_tracker;
- } nmpipe;
-
- struct
- {
- uint64_t file_size;
- uint64_t file_offset;
- uint64_t bytes_processed;
- DCE2_List* file_chunks;
- uint32_t bytes_queued;
- DCE2_SmbFileDirection file_direction;
- bool sequential_only;
- } file;
- } tracker;
-
- DCE2_SmbPduState smb2_pdu_state;
-
-#define fid_v1 file_key.id_smb1.file_id
-#define uid_v1 file_key.id_smb1.u_id
-#define tid_v1 file_key.id_smb1.tree_id
-#define fid_v2 file_key.id_smb2.file_id
-#define fp_byte_mode tracker.nmpipe.byte_mode
-#define fp_used tracker.nmpipe.used
-#define fp_writex_raw tracker.nmpipe.writex_raw
-#define fp_co_tracker tracker.nmpipe.co_tracker
-#define ff_file_size tracker.file.file_size
-#define ff_file_offset tracker.file.file_offset
-#define ff_bytes_processed tracker.file.bytes_processed
-#define ff_file_direction tracker.file.file_direction
-#define ff_file_chunks tracker.file.file_chunks
-#define ff_bytes_queued tracker.file.bytes_queued
-#define ff_sequential_only tracker.file.sequential_only
-};
-
-struct Smb2Request
-{
- uint64_t message_id; /* identifies a message uniquely on connection */
- uint64_t offset; /* data offset */
- uint64_t file_id; /* file id */
- struct Smb2Request* next;
- struct Smb2Request* previous;
-};
-
-struct DCE2_SmbTransactionTracker
-{
- int smb_type;
- uint8_t subcom;
- bool one_way;
- bool disconnect_tid;
- bool pipe_byte_mode;
- uint32_t tdcnt;
- uint32_t dsent;
- DCE2_Buffer* dbuf;
- uint32_t tpcnt;
- uint32_t psent;
- DCE2_Buffer* pbuf;
- // For Transaction2/Query File Information
- uint16_t info_level;
-};
-
-struct DCE2_SmbRequestTracker
-{
- int smb_com;
-
- int mid; // A signed integer so it can be set to sentinel
- uint16_t uid;
- uint16_t tid;
- uint16_t pid;
-
- // For WriteRaw
- bool writeraw_writethrough;
- uint32_t writeraw_remaining;
-
- // For Transaction/Transaction2/NtTransact
- DCE2_SmbTransactionTracker ttracker;
-
- // Client can chain a write to an open. Need to write data, but also
- // need to associate tracker with fid returned from server
- DCE2_Queue* ft_queue;
-
- // This is a reference to an existing file tracker
- DCE2_SmbFileTracker* ftracker;
-
- // Used for requests to cache data that will ultimately end up in
- // the file tracker upon response.
- char* file_name;
- uint16_t file_name_size;
- uint64_t file_size;
- uint64_t file_offset;
- bool sequential_only;
-
- // For TreeConnect to know whether it's to IPC
- bool is_ipc;
-};
-
-struct DCE2_SmbSsnData
-{
- DCE2_SsnData sd; // This member must be first
- DCE2_Policy policy;
-
- int dialect_index;
- int ssn_state_flags;
-
- DCE2_SmbDataState cli_data_state;
- DCE2_SmbDataState srv_data_state;
-
- DCE2_SmbPduState pdu_state;
-
- int uid; // A signed integer so it can be set to sentinel
- int tid; // A signed integer so it can be set to sentinel
- DCE2_List* uids;
- DCE2_List* tids;
-
- // For tracking files and named pipes
- DCE2_SmbFileTracker ftracker;
- DCE2_List* ftrackers; // List of DCE2_SmbFileTracker
-
- // For tracking requests / responses
- DCE2_SmbRequestTracker rtracker;
- DCE2_Queue* rtrackers;
- uint16_t max_outstanding_requests;
- uint16_t outstanding_requests;
-
- // The current pid/mid node for this request/response
- DCE2_SmbRequestTracker* cur_rtracker;
-
- // Used for TCP segmentation to get full PDU
- DCE2_Buffer* cli_seg;
- DCE2_Buffer* srv_seg;
-
- // These are used for commands we don't need to process
- uint32_t cli_ignore_bytes;
- uint32_t srv_ignore_bytes;
-
- // The file API supports one concurrent upload/download per session.
- // This is a reference to a file tracker so shouldn't be freed.
- DCE2_SmbFileTracker* fapi_ftracker;
-
- DCE2_SmbFileTracker* fb_ftracker;
- bool block_pdus;
-
- // Maximum file depth as returned from file API
- int64_t max_file_depth;
-};
-
-struct DCE2_SmbFsm
-{
- char input;
- int next_state;
- int fail_state;
-};
-
-class Dce2SmbFlowData : public snort::FlowData
-{
-public:
- Dce2SmbFlowData();
- ~Dce2SmbFlowData() override;
-
- static void init()
- { inspector_id = snort::FlowData::create_flow_data_id(); }
-
- size_t size_of() override
- { return sizeof(*this); }
-
-public:
- static unsigned inspector_id;
- DCE2_SmbVersion smb_version;
- void* dce2_smb_session_data;
-};
-
-// Used for reassembled packets
-#define DCE2_MOCK_HDR_LEN__SMB_CLI \
- ((unsigned)(sizeof(NbssHdr) + sizeof(SmbNtHdr) + sizeof(SmbWriteAndXReq)))
-#define DCE2_MOCK_HDR_LEN__SMB_SRV \
- ((unsigned)(sizeof(NbssHdr) + sizeof(SmbNtHdr) + sizeof(SmbReadAndXResp)))
-
-DCE2_SsnData* get_dce2_session_data(snort::Flow*);
-
-const char* get_smb_com_string(uint8_t);
-#endif
-
//--------------------------------------------------------------------------
-// Copyright (C) 2016-2020 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2020-2021 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
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//--------------------------------------------------------------------------
-// dce_smb.cc author Rashmi Pitre <rrp@cisco.com>
+// dce_smb1.cc author Bhargava Jandhyala <bjandhya@cisco.com>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
-#include "dce_smb.h"
-
-#include "detection/detection_engine.h"
-#include "file_api/file_service.h"
-#include "main/snort_debug.h"
-#include "managers/inspector_manager.h"
-#include "protocols/packet.h"
-
-#include "dce_context_data.h"
-#include "dce_smb_commands.h"
-#include "dce_smb_module.h"
-#include "dce_smb_paf.h"
-#include "dce_smb_transaction.h"
-#include "dce_smb2.h"
-#include "dce_smb2_utils.h"
+#include "dce_smb1.h"
using namespace snort;
-THREAD_LOCAL dce2SmbStats dce2_smb_stats;
-THREAD_LOCAL ProfileStats dce2_smb_pstat_main;
-
//-------------------------------------------------------------------------
// debug stuff
//-------------------------------------------------------------------------
{ return smb_com_strings[b]; }
#endif
-//-------------------------------------------------------------------------
-// class stuff
-//-------------------------------------------------------------------------
-
-class Dce2Smb : public Inspector
-{
-public:
- Dce2Smb(const dce2SmbProtoConf&);
- ~Dce2Smb() override;
-
- void show(const SnortConfig*) const override;
- void eval(Packet*) override;
- void clear(Packet*) override;
-
- StreamSplitter* get_splitter(bool c2s) override
- { return new Dce2SmbSplitter(c2s); }
-
- bool can_carve_files() const override
- { return true; }
-
-private:
- dce2SmbProtoConf config;
-};
-
-Dce2Smb::Dce2Smb(const dce2SmbProtoConf& pc)
-{
- config = pc;
-}
-
-Dce2Smb::~Dce2Smb()
-{
- if (config.smb_invalid_shares)
- {
- DCE2_ListDestroy(config.smb_invalid_shares);
- }
-}
-
-void Dce2Smb::show(const SnortConfig*) const
-{
- print_dce2_smb_conf(config);
-}
-
-void Dce2Smb::eval(Packet* p)
-{
- DCE2_SmbSsnData* dce2_smb_sess = nullptr;
- DCE2_Smb2SsnData* dce2_smb2_sess = nullptr;
- DCE2_SmbVersion smb_version = DCE2_SMB_VERSION_NULL;
- Profile profile(dce2_smb_pstat_main);
-
- assert(p->has_tcp_data());
- assert(p->flow);
-
- Dce2SmbFlowData *smb_flowdata = (Dce2SmbFlowData*)p->flow->get_flow_data(Dce2SmbFlowData::inspector_id);
- if (smb_flowdata and smb_flowdata->dce2_smb_session_data)
- {
- smb_version = smb_flowdata->smb_version;
- if (DCE2_SMB_VERSION_1 == smb_version)
- dce2_smb_sess = (DCE2_SmbSsnData*)smb_flowdata->dce2_smb_session_data;
- else
- dce2_smb2_sess = (DCE2_Smb2SsnData*)smb_flowdata->dce2_smb_session_data;
- }
- else
- {
- smb_version = DCE2_Smb2Version(p);
-
- if (DCE2_SMB_VERSION_1 == smb_version)
- {
- //1st packet of flow in smb1 session, create smb1 session and flowdata
- dce2_smb_sess = dce2_create_new_smb_session(p, &config);
- debug_logf(dce_smb_trace, p, "smb1 session created\n");
- }
- else if (DCE2_SMB_VERSION_2 == smb_version)
- {
- //1st packet of flow in smb2 session, create smb2 session and flowdata
- dce2_smb2_sess = dce2_create_new_smb2_session(p, &config);
- debug_logf(dce_smb_trace, p, "smb2 session created\n");
- }
- else
- {
- //smb_version is DCE2_SMB_VERSION_NULL
- //This means there is no flow data and this is not an SMB packet
- //if it is a TCP packet for smb data, the flow must have been
- //already identified with version.
- debug_logf(dce_smb_trace, p, "non-smb packet detected\n");
- return;
- }
- }
-
- // By this time we must know the smb version, have correct smb session data and created flowdata
- p->packet_flags |= PKT_ALLOW_MULTIPLE_DETECT;
- dce2_detected = 0;
- p->endianness = new DceEndianness();
-
- if (DCE2_SMB_VERSION_1 == smb_version)
- {
- DCE2_Smb1Process(dce2_smb_sess);
- if (!dce2_detected)
- DCE2_Detect(&dce2_smb_sess->sd);
- }
- else
- {
- DCE2_Smb2Process(dce2_smb2_sess);
- if (!dce2_detected)
- DCE2_Detect(&dce2_smb2_sess->sd);
- }
-
- delete(p->endianness);
- p->endianness = nullptr;
-}
-
-void Dce2Smb::clear(Packet* p)
-{
- DCE2_SsnData* sd = get_dce2_session_data(p->flow);
- if ( sd )
- DCE2_ResetRopts(sd, p);
-}
-
-//-------------------------------------------------------------------------
-// api stuff
-//-------------------------------------------------------------------------
-
-static Module* mod_ctor()
-{
- return new Dce2SmbModule;
-}
-
-static void mod_dtor(Module* m)
-{
- delete m;
-}
-
-static void dce2_smb_init()
-{
- Dce2SmbFlowData::init();
- DCE2_SmbInitGlobals();
- DCE2_SmbInitDeletePdu();
- DceContextData::init(DCE2_TRANS_TYPE__SMB);
-}
-
-static void dce2_smb_thread_int()
-{
- DCE2_SmbSessionCacheInit(session_cache_size);
-}
-
-static void dce_smb_thread_term()
+Dce2Smb1SessionData::Dce2Smb1SessionData(const Packet* p,
+ const dce2SmbProtoConf* proto) : Dce2SmbSessionData(p, proto)
{
- delete smb2_session_cache;
+ ssd = { };
+ ssd.max_outstanding_requests = 10; // Until Negotiate/SessionSetupAndX
+ ssd.cli_data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER;
+ ssd.srv_data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER;
+ ssd.pdu_state = DCE2_SMB_PDU_STATE__COMMAND;
+ ssd.uid = DCE2_SENTINEL;
+ ssd.tid = DCE2_SENTINEL;
+ ssd.ftracker.fid_v1 = DCE2_SENTINEL;
+ ssd.rtracker.mid = DCE2_SENTINEL;
+ ssd.dialect_index = dialect_index;
+ ssd.max_file_depth = max_file_depth;
+ ssd.sd = sd;
+ ssd.policy = policy;
+ debug_logf(dce_smb_trace, p, "smb1 session created\n");
}
-static size_t get_max_smb_session(dce2SmbProtoConf* config)
+void Dce2Smb1SessionData::process()
{
- size_t smb_sess_storage_req = (sizeof(DCE2_Smb2SessionTracker) +
- sizeof(DCE2_Smb2TreeTracker) + sizeof(DCE2_Smb2RequestTracker) +
- (sizeof(DCE2_Smb2FileTracker) * SMB_AVG_FILES_PER_SESSION));
-
- size_t max_smb_sess = DCE2_ScSmbMemcap(config);
-
- return (max_smb_sess/smb_sess_storage_req);
+ DCE2_Smb1Process(&ssd);
}
-static Inspector* dce2_smb_ctor(Module* m)
-{
- Dce2SmbModule* mod = (Dce2SmbModule*)m;
- dce2SmbProtoConf config;
- mod->get_data(config);
- session_cache_size = get_max_smb_session(&config);
- return new Dce2Smb(config);
-}
-
-static void dce2_smb_dtor(Inspector* p)
-{
- delete p;
-}
-
-const InspectApi dce2_smb_api =
-{
- {
- PT_INSPECTOR,
- sizeof(InspectApi),
- INSAPI_VERSION,
- 0,
- API_RESERVED,
- API_OPTIONS,
- DCE2_SMB_NAME,
- DCE2_SMB_HELP,
- mod_ctor,
- mod_dtor
- },
- IT_SERVICE,
- PROTO_BIT__PDU,
- nullptr, // buffers
- "netbios-ssn",
- dce2_smb_init,
- nullptr, // pterm
- dce2_smb_thread_int, // tinit
- dce_smb_thread_term, // tterm
- dce2_smb_ctor,
- dce2_smb_dtor,
- nullptr, // ssn
- nullptr // reset
-};
-
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2021 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// dce_smb1.h author Bhargava Jandhyala <bjandhya@cisco.com>
+
+#ifndef DCE_SMB1_H
+#define DCE_SMB1_H
+
+// This provides smb session data and SMBv1 specific trackers
+
+#include "protocols/packet.h"
+#include "profiler/profiler_defs.h"
+
+#include "dce_co.h"
+#include "dce_smb_common.h"
+#include "dce_smb_module.h"
+#include "smb_message.h"
+
+enum DCE2_SmbSsnState
+{
+ DCE2_SMB_SSN_STATE__START = 0x00,
+ DCE2_SMB_SSN_STATE__NEGOTIATED = 0x01,
+ DCE2_SMB_SSN_STATE__FP_CLIENT = 0x02, // Fingerprinted client
+ DCE2_SMB_SSN_STATE__FP_SERVER = 0x04 // Fingerprinted server
+};
+
+enum DCE2_SmbDataState
+{
+ DCE2_SMB_DATA_STATE__NETBIOS_HEADER,
+ DCE2_SMB_DATA_STATE__SMB_HEADER,
+ DCE2_SMB_DATA_STATE__NETBIOS_PDU
+};
+
+enum DCE2_SmbFileDirection
+{
+ DCE2_SMB_FILE_DIRECTION__UNKNOWN = 0,
+ DCE2_SMB_FILE_DIRECTION__UPLOAD,
+ DCE2_SMB_FILE_DIRECTION__DOWNLOAD
+};
+
+enum SmbAndXCom
+{
+ SMB_ANDX_COM__NONE,
+ SMB_ANDX_COM__OPEN_ANDX,
+ SMB_ANDX_COM__READ_ANDX,
+ SMB_ANDX_COM__WRITE_ANDX,
+ SMB_ANDX_COM__TREE_CONNECT_ANDX,
+ SMB_ANDX_COM__SESSION_SETUP_ANDX,
+ SMB_ANDX_COM__LOGOFF_ANDX,
+ SMB_ANDX_COM__NT_CREATE_ANDX,
+ SMB_ANDX_COM__MAX
+};
+
+struct DCE2_SmbWriteAndXRaw
+{
+ int remaining; // A signed integer so it can be negative
+ DCE2_Buffer* buf;
+};
+
+struct DCE2_SmbFileChunk
+{
+ uint64_t offset;
+ uint32_t length;
+ uint8_t* data;
+};
+
+struct DCE2_SmbFileTracker
+{
+ struct
+ {
+ int file_id; // A signed integer so it can be set to sentinel
+ uint16_t u_id;
+ uint16_t tree_id;
+ } file_key;
+
+ bool is_ipc;
+ bool is_smb2;
+ char* file_name;
+ uint16_t file_name_size;
+ uint64_t file_name_hash;
+
+ union
+ {
+ struct
+ {
+ // If pipe has been set to byte mode via TRANS_SET_NMPIPE_STATE
+ bool byte_mode;
+
+ // For Windows 2000
+ bool used;
+
+ // For WriteAndX requests that use raw mode flag
+ // Windows only
+ DCE2_SmbWriteAndXRaw* writex_raw;
+
+ // Connection-oriented DCE/RPC tracker
+ DCE2_CoTracker* co_tracker;
+ } nmpipe;
+
+ struct
+ {
+ uint64_t file_size;
+ uint64_t file_offset;
+ uint64_t bytes_processed;
+ DCE2_List* file_chunks;
+ uint32_t bytes_queued;
+ DCE2_SmbFileDirection file_direction;
+ bool sequential_only;
+ } file;
+ } tracker;
+
+#define fid_v1 file_key.file_id
+#define uid_v1 file_key.u_id
+#define tid_v1 file_key.tree_id
+#define fp_byte_mode tracker.nmpipe.byte_mode
+#define fp_used tracker.nmpipe.used
+#define fp_writex_raw tracker.nmpipe.writex_raw
+#define fp_co_tracker tracker.nmpipe.co_tracker
+#define ff_file_size tracker.file.file_size
+#define ff_file_offset tracker.file.file_offset
+#define ff_bytes_processed tracker.file.bytes_processed
+#define ff_file_direction tracker.file.file_direction
+#define ff_file_chunks tracker.file.file_chunks
+#define ff_bytes_queued tracker.file.bytes_queued
+#define ff_sequential_only tracker.file.sequential_only
+};
+
+struct Smb2Request
+{
+ uint64_t message_id; /* identifies a message uniquely on connection */
+ uint64_t offset; /* data offset */
+ uint64_t file_id; /* file id */
+ struct Smb2Request* next;
+ struct Smb2Request* previous;
+};
+
+struct DCE2_SmbTransactionTracker
+{
+ int smb_type;
+ uint8_t subcom;
+ bool one_way;
+ bool disconnect_tid;
+ bool pipe_byte_mode;
+ uint32_t tdcnt;
+ uint32_t dsent;
+ DCE2_Buffer* dbuf;
+ uint32_t tpcnt;
+ uint32_t psent;
+ DCE2_Buffer* pbuf;
+ // For Transaction2/Query File Information
+ uint16_t info_level;
+};
+
+struct DCE2_SmbRequestTracker
+{
+ int smb_com;
+
+ int mid; // A signed integer so it can be set to sentinel
+ uint16_t uid;
+ uint16_t tid;
+ uint16_t pid;
+
+ // For WriteRaw
+ bool writeraw_writethrough;
+ uint32_t writeraw_remaining;
+
+ // For Transaction/Transaction2/NtTransact
+ DCE2_SmbTransactionTracker ttracker;
+
+ // Client can chain a write to an open. Need to write data, but also
+ // need to associate tracker with fid returned from server
+ DCE2_Queue* ft_queue;
+
+ // This is a reference to an existing file tracker
+ DCE2_SmbFileTracker* ftracker;
+
+ // Used for requests to cache data that will ultimately end up in
+ // the file tracker upon response.
+ char* file_name;
+ uint16_t file_name_size;
+ uint64_t file_size;
+ uint64_t file_offset;
+ bool sequential_only;
+
+ // For TreeConnect to know whether it's to IPC
+ bool is_ipc;
+};
+
+struct DCE2_SmbSsnData
+{
+ DCE2_SsnData sd; // This member must be first
+ DCE2_Policy policy;
+
+ int dialect_index;
+ int ssn_state_flags;
+
+ DCE2_SmbDataState cli_data_state;
+ DCE2_SmbDataState srv_data_state;
+
+ Dce2SmbPduState pdu_state;
+
+ int uid; // A signed integer so it can be set to sentinel
+ int tid; // A signed integer so it can be set to sentinel
+ DCE2_List* uids;
+ DCE2_List* tids;
+
+ // For tracking files and named pipes
+ DCE2_SmbFileTracker ftracker;
+ DCE2_List* ftrackers; // List of DCE2_SmbFileTracker
+
+ // For tracking requests / responses
+ DCE2_SmbRequestTracker rtracker;
+ DCE2_Queue* rtrackers;
+ uint16_t max_outstanding_requests;
+ uint16_t outstanding_requests;
+
+ // The current pid/mid node for this request/response
+ DCE2_SmbRequestTracker* cur_rtracker;
+
+ // Used for TCP segmentation to get full PDU
+ DCE2_Buffer* cli_seg;
+ DCE2_Buffer* srv_seg;
+
+ // These are used for commands we don't need to process
+ uint32_t cli_ignore_bytes;
+ uint32_t srv_ignore_bytes;
+
+ // The file API supports one concurrent upload/download per session.
+ // This is a reference to a file tracker so shouldn't be freed.
+ DCE2_SmbFileTracker* fapi_ftracker;
+
+ DCE2_SmbFileTracker* fb_ftracker;
+ bool block_pdus;
+
+ // Maximum file depth as returned from file API
+ int64_t max_file_depth;
+};
+
+struct DCE2_SmbFsm
+{
+ char input;
+ int next_state;
+ int fail_state;
+};
+
+// Used for reassembled packets
+#define DCE2_MOCK_HDR_LEN__SMB_CLI \
+ ((unsigned)(sizeof(NbssHdr) + sizeof(SmbNtHdr) + sizeof(SmbWriteAndXReq)))
+#define DCE2_MOCK_HDR_LEN__SMB_SRV \
+ ((unsigned)(sizeof(NbssHdr) + sizeof(SmbNtHdr) + sizeof(SmbReadAndXResp)))
+
+DCE2_SsnData* get_dce2_session_data(snort::Flow*);
+
+const char* get_smb_com_string(uint8_t);
+
+class Dce2Smb1SessionData : public Dce2SmbSessionData
+{
+public:
+ Dce2Smb1SessionData() = delete;
+ Dce2Smb1SessionData(const snort::Packet*, const dce2SmbProtoConf* proto);
+ ~Dce2Smb1SessionData() override
+ { DCE2_SmbDataFree(&ssd); }
+ void process() override;
+ void handle_retransmit(FilePosition, FileVerdict) override { }
+
+private:
+ DCE2_SmbSsnData ssd;
+};
+
+#endif
+
//--------------------------------------------------------------------------
-// Copyright (C) 2015-2020 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2015-2021 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
#endif
#include "dce_smb2.h"
-#include "dce_smb2_commands.h"
+
#include "detection/detection_util.h"
#include "flow/flow_key.h"
-#include "main/snort_debug.h"
+
+#include "dce_smb2_file.h"
+#include "dce_smb2_session.h"
+#include "dce_smb2_session_cache.h"
+#include "dce_smb2_tree.h"
using namespace snort;
+THREAD_LOCAL Dce2Smb2SessionCache* smb2_session_cache;
+
const char* smb2_command_string[SMB2_COM_MAX] = {
"SMB2_COM_NEGOTIATE",
"SMB2_COM_SESSION_SETUP",
"SMB2_COM_CHANGE_NOTIFY",
"SMB2_COM_QUERY_INFO",
"SMB2_COM_SET_INFO",
- "SMB2_COM_OPLOCK_BREAK"};
+ "SMB2_COM_OPLOCK_BREAK"
+};
+
+static inline uint64_t Smb2Sid(const Smb2Hdr* hdr)
+{
+ return alignedNtohq(&(hdr->session_id));
+}
+
+static inline bool Smb2Error(const Smb2Hdr* hdr)
+{
+ return (SMB_NT_STATUS_SEVERITY__ERROR == (uint8_t)(hdr->status >> 30));
+}
-static inline SmbFlowKey get_flow_key()
+Smb2FlowKey get_smb2_flow_key(void)
{
- SmbFlowKey key;
+ Smb2FlowKey key;
const FlowKey* flow_key = DetectionEngine::get_current_packet()->flow->key;
key.ip_l[0] = flow_key->ip_l[0];
return key;
}
-DCE2_Smb2RequestTracker::DCE2_Smb2RequestTracker(uint64_t file_id_v,
- uint64_t offset_v) : file_id(file_id_v), offset(offset_v)
+//Dce2Smb2SessionData member functions
+
+Dce2Smb2SessionData::Dce2Smb2SessionData(const Packet* p,
+ const dce2SmbProtoConf* proto) : Dce2SmbSessionData(p, proto)
{
- debug_logf(dce_smb_trace, nullptr, "request tracker created\n");
- memory::MemoryCap::update_allocations(sizeof(*this));
+ tcp_file_tracker = nullptr;
+ flow_key = get_smb2_flow_key();
+ debug_logf(dce_smb_trace, p, "smb2 session created\n");
}
-DCE2_Smb2RequestTracker::DCE2_Smb2RequestTracker(char* fname_v,
- uint16_t fname_len_v) : fname(fname_v), fname_len(fname_len_v)
+Dce2Smb2SessionData::~Dce2Smb2SessionData(void)
{
- debug_logf(dce_smb_trace, nullptr, "request tracker created\n");
- memory::MemoryCap::update_allocations(sizeof(*this));
+ for (auto it_session : connected_sessions)
+ {
+ if (it_session.second->detach_flow(flow_key))
+ smb2_session_cache->remove(it_session.second->get_key());
+ }
}
-DCE2_Smb2RequestTracker::~DCE2_Smb2RequestTracker()
+void Dce2Smb2SessionData::reset_matching_tcp_file_tracker(
+ Dce2Smb2FileTracker* file_tracker)
{
- debug_logf(dce_smb_trace, nullptr, "request tracker terminating\n");
- if (!file_id and fname)
- snort_free(fname);
- memory::MemoryCap::update_deallocations(sizeof(*this));
+ if (tcp_file_tracker == file_tracker)
+ tcp_file_tracker = nullptr;
}
-DCE2_Smb2FileTracker::DCE2_Smb2FileTracker(uint64_t file_id_v, DCE2_Smb2TreeTracker* ttr_v,
- DCE2_Smb2SessionTracker* str_v, Flow* flow_v) : file_id(file_id_v), ttr(ttr_v),
- str(str_v), flow(flow_v)
+Smb2SessionKey Dce2Smb2SessionData::get_session_key(uint64_t session_id)
{
- debug_logf(dce_smb_trace, nullptr, "file tracker %" PRIu64 " created\n", file_id);
- memory::MemoryCap::update_allocations(sizeof(*this));
+ Smb2SessionKey key;
+ Flow* flow = DetectionEngine::get_current_packet()->flow;
+ memcpy(key.cip, flow->client_ip.get_ip6_ptr(), 4*sizeof(uint32_t));
+ memcpy(key.sip, flow->server_ip.get_ip6_ptr(), 4*sizeof(uint32_t));
+ key.sid = session_id;
+ key.cgroup = flow->client_group;
+ key.sgroup = flow->server_group;
+ key.asid = flow->key->addressSpaceId;
+ key.padding = 0;
+ return key;
}
-DCE2_Smb2FileTracker::~DCE2_Smb2FileTracker()
+Dce2Smb2SessionTracker* Dce2Smb2SessionData::find_session(uint64_t session_id)
{
- debug_logf(dce_smb_trace, nullptr,
- "file tracker %" PRIu64 " file name hash %" PRIu64 " terminating\n",
- file_id, file_name_hash);
-
- FileFlows* file_flows = FileFlows::get_file_flows(flow, false);
- if (file_flows)
+ auto it_session = connected_sessions.find(session_id);
+ if (it_session != connected_sessions.end())
{
- file_flows->remove_processed_file_context(file_name_hash, file_id);
+ Dce2Smb2SessionTracker* session = it_session->second;
+ //we already have the session, but call find to update the LRU
+ smb2_session_cache->find_session(session->get_key());
+ return session;
}
-
- if (file_name)
- snort_free((void*)file_name);
-
- memory::MemoryCap::update_deallocations(sizeof(*this));
-}
-
-DCE2_Smb2TreeTracker::DCE2_Smb2TreeTracker (uint32_t tid_v, uint8_t share_type_v) :
- share_type(share_type_v), tid(tid_v)
-{
- debug_logf(dce_smb_trace, nullptr, "tree tracker %" PRIu32 " created\n", tid);
- memory::MemoryCap::update_allocations(sizeof(*this));
-}
-
-DCE2_Smb2TreeTracker::~DCE2_Smb2TreeTracker()
-{
- debug_logf(dce_smb_trace, nullptr, "tree tracker %" PRIu32 " terminating\n", tid);
-
- auto all_req_trackers = req_trackers.get_all_entry();
- if (all_req_trackers.size())
+ else
{
- debug_logf(dce_smb_trace, nullptr, "cleanup pending requests for below MIDs:\n");
- for ( auto& h : all_req_trackers )
+ Dce2Smb2SessionTracker* session = smb2_session_cache->find_session(
+ get_session_key(session_id));
+ if (session)
{
- debug_logf(dce_smb_trace, nullptr, "mid %" PRIu64 "\n", h.first);
- removeRtracker(h.first);
+ session->attach_flow(flow_key, this);
+ connected_sessions.insert(std::make_pair(session_id,session));
}
+ return session;
}
- memory::MemoryCap::update_deallocations(sizeof(*this));
}
-DCE2_Smb2SessionTracker::DCE2_Smb2SessionTracker()
+// Caller must ensure that the session is not already present in flow
+Dce2Smb2SessionTracker* Dce2Smb2SessionData::create_session(uint64_t session_id)
{
- debug_logf(dce_smb_trace, nullptr, "session tracker %" PRIu64 " created\n", session_id);
- memory::MemoryCap::update_allocations(sizeof(*this));
+ Smb2SessionKey session_key = get_session_key(session_id);
+ Dce2Smb2SessionTracker* session = smb2_session_cache->find_else_create_session(session_key);
+ session->init(session_id, session_key);
+ session->attach_flow(flow_key, this);
+ connected_sessions.insert(std::make_pair(session_id, session));
+ return session;
}
-DCE2_Smb2SessionTracker::~DCE2_Smb2SessionTracker()
+void Dce2Smb2SessionData::remove_session(uint64_t session_id)
{
- debug_logf(dce_smb_trace, nullptr, "session tracker %" PRIu64 " terminating\n", session_id);
- removeSessionFromAllConnection();
- memory::MemoryCap::update_deallocations(sizeof(*this));
+ connected_sessions.erase(session_id);
+ smb2_session_cache->remove(get_session_key(session_id));
}
-void DCE2_Smb2SessionTracker::removeSessionFromAllConnection()
+void Dce2Smb2SessionData::process_command(const Smb2Hdr* smb_hdr,
+ const uint8_t* end)
{
- auto all_conn_trackers = conn_trackers.get_all_entry();
- auto all_tree_trackers = tree_trackers.get_all_entry();
- for ( auto& h : all_conn_trackers )
- {
- if (h.second->ftracker_tcp)
- {
- for (auto& t : all_tree_trackers)
- {
- DCE2_Smb2FileTracker* ftr = t.second->findFtracker(
- h.second->ftracker_tcp->file_id);
- if (ftr and ftr == h.second->ftracker_tcp)
- {
- h.second->ftracker_tcp = nullptr;
- break;
- }
- }
- }
- DCE2_Smb2RemoveSidInSsd(h.second, session_id);
+ const uint8_t* smb_data = (const uint8_t*)smb_hdr + SMB2_HEADER_LENGTH;
+ uint16_t structure_size = alignedNtohs((const uint16_t*)smb_data);
+
+// Macro and shorthand to save some repetitive code
+// Should only be used in this function
+#define SMB2_COMMAND_TYPE(cmd, type) \
+ (structure_size == SMB2_ ## cmd ## _ ## type ## _STRUC_SIZE)
+
+#define SMB2_GET_COMMAND_TYPE(cmd) \
+ (SMB2_COMMAND_TYPE(ERROR,RESPONSE) and Smb2Error(smb_hdr)) ? \
+ SMB2_CMD_TYPE_ERROR_RESPONSE : (SMB2_COMMAND_TYPE(cmd, REQUEST) ? \
+ SMB2_CMD_TYPE_REQUEST : (SMB2_COMMAND_TYPE(cmd, RESPONSE) ? \
+ SMB2_CMD_TYPE_RESPONSE : SMB2_CMD_TYPE_INVALID))
+
+#define SMB2_HANDLE_HEADER_ERROR(cmd, type, counter) \
+ { \
+ if (smb_data + SMB2_ ## cmd ## _ ## type ## _STRUC_SIZE - 1 > end) \
+ { \
+ dce2_smb_stats.v2_ ## counter ## _hdr_err++; \
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET, \
+ "%s : smb data beyond end detected\n", \
+ smb2_command_string[command]); \
+ return; \
+ } \
}
-}
-
-static inline bool DCE2_Smb2FindSidTid(DCE2_Smb2SsnData* ssd, const uint64_t sid,
- const uint32_t tid, const uint32_t mid, DCE2_Smb2SessionTracker** str, DCE2_Smb2TreeTracker** ttr)
-{
- *str = DCE2_Smb2FindSidInSsd(ssd, sid);
- if (!*str)
- return false;
-
- if(!tid)
- *ttr = find_tree_for_message(*str, mid);
- else
- *ttr = (*str)->findTtracker(tid);
-
- if(!*ttr)
- return false;
- return true;
-}
+#define SMB2_HANDLE_ERROR_RESPONSE(counter) \
+ { \
+ if (SMB2_COMMAND_TYPE(ERROR, RESPONSE) and Smb2Error(smb_hdr)) \
+ { \
+ dce2_smb_stats.v2_ ## counter ## _err_resp++; \
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "%s_RESP: error\n", \
+ smb2_command_string[command]); \
+ return; \
+ } \
+ }
-// FIXIT-L port fileCache related code along with
-// DCE2_Smb2Init, DCE2_Smb2Close and DCE2_Smb2UpdateStats
+#define SMB2_HANDLE_INVALID_STRUC_SIZE(counter) \
+ { \
+ dce2_smb_stats.v2_ ## counter ## _inv_str_sz++; \
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "%s: invalid struct size\n", \
+ smb2_command_string[command]); \
+ return; \
+ }
-static void DCE2_Smb2Inspect(DCE2_Smb2SsnData* ssd, const Smb2Hdr* smb_hdr,
- const uint8_t* end)
-{
- const uint8_t* smb_data = (const uint8_t*)smb_hdr + SMB2_HEADER_LENGTH;
uint16_t command = alignedNtohs(&(smb_hdr->command));
- DCE2_Smb2SessionTracker* str = nullptr;
- DCE2_Smb2TreeTracker* ttr = nullptr;
-
- uint64_t mid = Smb2Mid(smb_hdr);
- uint64_t sid = Smb2Sid(smb_hdr);
- uint32_t tid = Smb2Tid(smb_hdr);
-
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
+ uint64_t session_id = Smb2Sid(smb_hdr);
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
"%s : mid %" PRIu64 " sid %" PRIu64 " tid %" PRIu32 "\n",
- (command <= SMB2_COM_OPLOCK_BREAK ? smb2_command_string[command] : "unknown"),
- mid, sid, tid);
+ (command < SMB2_COM_MAX ? smb2_command_string[command] : "unknown"),
+ Smb2Mid(smb_hdr), session_id, Smb2Tid(smb_hdr));
+ // Try to find the session.
+ // The case when session is not available will be handled per command.
+ Dce2Smb2SessionTracker* session = find_session(session_id);
+
switch (command)
{
- 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, mid, &str, &ttr) or
- SMB2_SHARE_TYPE_DISK != ttr->get_share_type())
+ //commands processed by flow
+ case SMB2_COM_SESSION_SETUP:
+ dce2_smb_stats.v2_setup++;
+ SMB2_HANDLE_ERROR_RESPONSE(setup)
+ if (SMB2_COMMAND_TYPE(SETUP, RESPONSE))
{
- dce2_smb_stats.v2_read_ignored++;
- return;
+ SMB2_HANDLE_HEADER_ERROR(SETUP, RESPONSE, setup_resp)
+ if (!session)
+ create_session(session_id);
}
+ else if (!SMB2_COMMAND_TYPE(SETUP, REQUEST))
+ SMB2_HANDLE_INVALID_STRUC_SIZE(setup)
+ break;
- DCE2_Smb2Read(ssd, smb_hdr, smb_data, end, str, ttr, mid);
+ case SMB2_COM_LOGOFF:
+ dce2_smb_stats.v2_logoff++;
+ if (SMB2_COMMAND_TYPE(LOGOFF, REQUEST))
+ remove_session(session_id);
+ else
+ SMB2_HANDLE_INVALID_STRUC_SIZE(logoff)
break;
- case SMB2_COM_WRITE:
- dce2_smb_stats.v2_wrt++;
- if (!DCE2_Smb2FindSidTid(ssd, sid, tid, mid, &str, &ttr) or
- SMB2_SHARE_TYPE_DISK != ttr->get_share_type())
+ //commands processed by session
+ case SMB2_COM_TREE_CONNECT:
+ dce2_smb_stats.v2_tree_cnct++;
+
+ SMB2_HANDLE_ERROR_RESPONSE(tree_cnct)
+ if (SMB2_COMMAND_TYPE(TREE_CONNECT, RESPONSE))
{
- dce2_smb_stats.v2_wrt_ignored++;
- return;
+ SMB2_HANDLE_HEADER_ERROR(TREE_CONNECT, RESPONSE, tree_cnct_resp)
+ if (!session)
+ session = create_session(session_id);
+ session->process(command, SMB2_CMD_TYPE_RESPONSE, smb_hdr, end);
}
-
- DCE2_Smb2Write(ssd, smb_hdr, smb_data, end, str, ttr, mid);
+ else if (!SMB2_COMMAND_TYPE(TREE_CONNECT,REQUEST))
+ SMB2_HANDLE_INVALID_STRUC_SIZE(tree_cnct)
break;
- case SMB2_COM_SET_INFO:
- dce2_smb_stats.v2_stinf++;
- if (!DCE2_Smb2FindSidTid(ssd, sid, tid, mid, &str, &ttr) or
- SMB2_SHARE_TYPE_DISK != ttr->get_share_type())
+
+ case SMB2_COM_TREE_DISCONNECT:
+ dce2_smb_stats.v2_tree_discn++;
+
+ if (session)
{
- dce2_smb_stats.v2_stinf_ignored++;
- return;
+ if (SMB2_COMMAND_TYPE(TREE_DISCONNECT, REQUEST))
+ {
+ SMB2_HANDLE_HEADER_ERROR(TREE_DISCONNECT, REQUEST, tree_discn_req)
+ session->process(command, SMB2_CMD_TYPE_REQUEST, smb_hdr, end);
+ }
+ else
+ {
+ SMB2_HANDLE_INVALID_STRUC_SIZE(tree_discn)
+ }
}
+ else
+ dce2_smb_stats.v2_session_ignored++;
+ break;
+ //commands processed by tree
+ case SMB2_COM_CREATE:
+ {
+ dce2_smb_stats.v2_crt++;
- DCE2_Smb2SetInfo(ssd, smb_hdr, smb_data, end, ttr);
+ uint8_t command_type = SMB2_GET_COMMAND_TYPE(CREATE);
+ if (SMB2_CMD_TYPE_INVALID == command_type)
+ SMB2_HANDLE_INVALID_STRUC_SIZE(crt)
+ else if (SMB2_COMMAND_TYPE(CREATE, REQUEST))
+ SMB2_HANDLE_HEADER_ERROR(CREATE, REQUEST, crt_req)
+ else if (SMB2_COMMAND_TYPE(CREATE, RESPONSE))
+ SMB2_HANDLE_HEADER_ERROR(CREATE, RESPONSE, crt_resp)
+
+ if (!session)
+ session = create_session(session_id);
+ session->process(command, command_type, smb_hdr, end);
+ }
break;
+
case SMB2_COM_CLOSE:
dce2_smb_stats.v2_cls++;
- if (!DCE2_Smb2FindSidTid(ssd, sid, tid, mid, &str, &ttr) or
- SMB2_SHARE_TYPE_DISK != ttr->get_share_type())
+ SMB2_HANDLE_ERROR_RESPONSE(cls)
+ if (session)
{
- dce2_smb_stats.v2_cls_ignored++;
- return;
+ if (SMB2_COMMAND_TYPE(CLOSE, REQUEST))
+ {
+ SMB2_HANDLE_HEADER_ERROR(CLOSE, REQUEST, cls_req)
+ session->process(command, SMB2_CMD_TYPE_REQUEST, smb_hdr, end);
+ }
+ else if (!SMB2_COMMAND_TYPE(CLOSE, RESPONSE))
+ {
+ SMB2_HANDLE_INVALID_STRUC_SIZE(cls)
+ }
}
-
- DCE2_Smb2CloseCmd(ssd, smb_hdr, smb_data, end, ttr, str);
+ else
+ dce2_smb_stats.v2_session_ignored++;
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)
+
+ case SMB2_COM_SET_INFO:
+ dce2_smb_stats.v2_setinfo++;
+ SMB2_HANDLE_ERROR_RESPONSE(stinf)
+ if (session)
{
- DCE2_Smb2TreeConnect(ssd, smb_hdr, smb_data, end, str, tid);
+ if (SMB2_COMMAND_TYPE(SET_INFO, REQUEST))
+ {
+ SMB2_HANDLE_HEADER_ERROR(SET_INFO, REQUEST, stinf_req)
+ session->process(command, SMB2_CMD_TYPE_REQUEST, smb_hdr, end);
+ }
+ else if (!SMB2_COMMAND_TYPE(SET_INFO, RESPONSE))
+ {
+ SMB2_HANDLE_INVALID_STRUC_SIZE(stinf)
+ }
}
+ else
+ dce2_smb_stats.v2_session_ignored++;
break;
- case SMB2_COM_TREE_DISCONNECT:
- dce2_smb_stats.v2_tree_discn++;
- if (!DCE2_Smb2FindSidTid(ssd, sid, tid, mid, &str, &ttr))
+
+ case SMB2_COM_READ:
+ dce2_smb_stats.v2_read++;
+ if (session)
{
- dce2_smb_stats.v2_tree_discn_ignored++;
- return;
+ uint8_t command_type;
+ if (SMB2_COMMAND_TYPE(ERROR, RESPONSE) and Smb2Error(smb_hdr))
+ command_type = SMB2_CMD_TYPE_ERROR_RESPONSE;
+ else if (SMB2_COMMAND_TYPE(READ, REQUEST))
+ {
+ SMB2_HANDLE_HEADER_ERROR(READ, REQUEST, read_req)
+ command_type = SMB2_CMD_TYPE_REQUEST;
+ }
+ else if (SMB2_COMMAND_TYPE(READ, RESPONSE))
+ {
+ SMB2_HANDLE_HEADER_ERROR(READ, RESPONSE, read_resp)
+ command_type = SMB2_CMD_TYPE_RESPONSE;
+ }
+ else
+ SMB2_HANDLE_INVALID_STRUC_SIZE(read)
+ session->process(command, command_type, smb_hdr, end);
}
- DCE2_Smb2TreeDisconnect(ssd, smb_data, end, str, tid);
- break;
- case SMB2_COM_SESSION_SETUP:
- dce2_smb_stats.v2_setup++;
- DCE2_Smb2Setup(ssd, smb_hdr, sid, smb_data, end);
+ else
+ dce2_smb_stats.v2_session_ignored++;
break;
- case SMB2_COM_LOGOFF:
- dce2_smb_stats.v2_logoff++;
- DCE2_Smb2Logoff(ssd, smb_data, sid);
+
+ case SMB2_COM_WRITE:
+ dce2_smb_stats.v2_wrt++;
+ if (session)
+ {
+ uint8_t command_type;
+ if (SMB2_COMMAND_TYPE(ERROR, RESPONSE) and Smb2Error(smb_hdr))
+ command_type = SMB2_CMD_TYPE_ERROR_RESPONSE;
+ else if (SMB2_COMMAND_TYPE(WRITE, REQUEST))
+ {
+ SMB2_HANDLE_HEADER_ERROR(WRITE, REQUEST, wrt_req)
+ command_type = SMB2_CMD_TYPE_REQUEST;
+ }
+ else if (SMB2_COMMAND_TYPE(WRITE, RESPONSE))
+ {
+ SMB2_HANDLE_HEADER_ERROR(WRITE, RESPONSE, wrt_resp)
+ command_type = SMB2_CMD_TYPE_RESPONSE;
+ }
+ else
+ SMB2_HANDLE_INVALID_STRUC_SIZE(wrt)
+ session->process(command, command_type, smb_hdr, end);
+ }
+ else
+ dce2_smb_stats.v2_session_ignored++;
break;
+
default:
dce2_smb_stats.v2_msgs_uninspected++;
break;
}
// This is the main entry point for SMB2 processing.
-void DCE2_Smb2Process(DCE2_Smb2SsnData* ssd)
+void Dce2Smb2SessionData::process()
{
Packet* p = DetectionEngine::get_current_packet();
const uint8_t* data_ptr = p->data;
// Check header length
if (data_len < sizeof(NbssHdr) + SMB2_HEADER_LENGTH)
{
- dce2_smb_stats.v2_hdr_err++;
debug_logf(dce_smb_trace, p, "Header error with data length %d\n",data_len);
+ dce2_smb_stats.v2_hdr_err++;
return;
}
// multiple requests up to the maximum size<88> that is supported by the transport."
do
{
- DCE2_Smb2Inspect(ssd, smb_hdr, data_ptr + data_len);
+ process_command(smb_hdr, data_ptr + data_len);
+
// In case of message compounding, find the offset of the next smb command
next_command_offset = alignedNtohl(&(smb_hdr->next_command));
if (next_command_offset + (const uint8_t*)smb_hdr > (data_ptr + data_len))
{
dce_alert(GID_DCE2, DCE2_SMB_BAD_NEXT_COMMAND_OFFSET,
- (dce2CommonStats*)&dce2_smb_stats, ssd->sd);
+ (dce2CommonStats*)&dce2_smb_stats, sd);
debug_logf(dce_smb_trace, p, "bad next command offset\n");
dce2_smb_stats.v2_bad_next_cmd_offset++;
return;
compound_request_index++;
}
- if (compound_request_index > DCE2_ScSmbMaxCompound((dce2SmbProtoConf*)ssd->sd.config))
+ if (compound_request_index > get_smb_max_compound())
{
dce2_smb_stats.v2_cmpnd_req_lt_crossed++;
- debug_logf(dce_smb_trace, p, "compound req limit reached %" PRIu8 "\n",
- compound_request_index);
+ debug_logf(dce_smb_trace, p, "compound request limit"
+ " reached %" PRIu8 "\n",compound_request_index);
return;
}
}
while (next_command_offset and smb_hdr);
}
- else if ( ssd->ftracker_tcp and (ssd->ftracker_tcp->smb2_pdu_state ==
- DCE2_SMB_PDU_STATE__RAW_DATA))
- {
- debug_logf(dce_smb_trace, p,
- "raw data file_name_hash %" PRIu64 " fid %" PRIu64 " dir %s\n",
- ssd->ftracker_tcp->file_name_hash, ssd->ftracker_tcp->file_id,
- ssd->ftracker_tcp->upload ? "upload" : "download");
-
- if (!DCE2_Smb2ProcessFileData(ssd, data_ptr, data_len))
- return;
- ssd->ftracker_tcp->file_offset += data_len;
- }
-}
-
-DCE2_Ret DCE2_Smb2InitData(DCE2_Smb2SsnData* ssd)
-{
- memset(&ssd->sd, 0, sizeof(DCE2_SsnData));
- ssd->session_trackers.SetDoNotFree();
- 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();
- ssd->flow_key = get_flow_key();
- return DCE2_RET__SUCCESS;
-}
-
-// Check whether the packet is smb2
-DCE2_SmbVersion DCE2_Smb2Version(const Packet* p)
-{
- // Only check reassembled SMB2 packet
- if ( p->has_paf_payload() and
- (p->dsize > sizeof(NbssHdr) + DCE2_SMB_ID_SIZE) ) // DCE2_SMB_ID is u32
+ else if ( tcp_file_tracker and tcp_file_tracker->accepting_raw_data())
{
- const Smb2Hdr* smb_hdr = (const Smb2Hdr*)(p->data + sizeof(NbssHdr));
- uint32_t smb_version_id = SmbId((const SmbNtHdr*)smb_hdr);
-
- if (smb_version_id == DCE2_SMB_ID)
- return DCE2_SMB_VERSION_1;
- else if (smb_version_id == DCE2_SMB2_ID)
- return DCE2_SMB_VERSION_2;
+ debug_logf(dce_smb_trace, p, "processing raw data for file id %" PRIu64 "\n",
+ tcp_file_tracker->get_file_id());
+
+ if (!tcp_file_tracker->process_data(data_ptr, data_len))
+ tcp_file_tracker->get_parent()->close_file(tcp_file_tracker->get_file_id());
}
-
- return DCE2_SMB_VERSION_NULL;
}
#ifndef DCE_SMB2_H
#define DCE_SMB2_H
-#include "dce_db.h"
-#include "dce_smb.h"
-#include "hash/lru_cache_shared.h"
+// This implements smb session data for SMBv2
+// Also provides SMBv2 related header structures
+
#include "main/thread_config.h"
#include "memory/memory_cap.h"
#include "utils/util.h"
+#include "dce_smb_common.h"
+
+/* SMB2 command codes */
+#define SMB2_COM_NEGOTIATE 0x00
+#define SMB2_COM_SESSION_SETUP 0x01
+#define SMB2_COM_LOGOFF 0x02
+#define SMB2_COM_TREE_CONNECT 0x03
+#define SMB2_COM_TREE_DISCONNECT 0x04
+#define SMB2_COM_CREATE 0x05
+#define SMB2_COM_CLOSE 0x06
+#define SMB2_COM_FLUSH 0x07
+#define SMB2_COM_READ 0x08
+#define SMB2_COM_WRITE 0x09
+#define SMB2_COM_LOCK 0x0A
+#define SMB2_COM_IOCTL 0x0B
+#define SMB2_COM_CANCEL 0x0C
+#define SMB2_COM_ECHO 0x0D
+#define SMB2_COM_QUERY_DIRECTORY 0x0E
+#define SMB2_COM_CHANGE_NOTIFY 0x0F
+#define SMB2_COM_QUERY_INFO 0x10
+#define SMB2_COM_SET_INFO 0x11
+#define SMB2_COM_OPLOCK_BREAK 0x12
+#define SMB2_COM_MAX 0x13
+
+extern const char* smb2_command_string[SMB2_COM_MAX];
+
+// file attribute for create response
+#define SMB2_CREATE_RESPONSE_DIRECTORY 0x10
#define SMB_AVG_FILES_PER_SESSION 5
+#define SMB2_SHARE_TYPE_DISK 0x01
+#define SMB2_SHARE_TYPE_PIPE 0x02
+#define SMB2_SHARE_TYPE_PRINT 0x03
+
+#define SMB2_CMD_TYPE_ERROR_RESPONSE 0
+#define SMB2_CMD_TYPE_REQUEST 1
+#define SMB2_CMD_TYPE_RESPONSE 2
+#define SMB2_CMD_TYPE_INVALID 3
+
struct Smb2Hdr
{
uint8_t smb_idf[4]; /* contains 0xFE,’SMB’ */
uint8_t signature[16]; /* signature of the message */
};
-struct Smb2ASyncHdr
-{
- uint8_t smb_idf[4]; /* contains 0xFE,’SMB’ */
- uint16_t structure_size; /* This MUST be set to 64 */
- uint16_t credit_charge; /* # of credits that this request consumes */
- uint32_t status; /* depends */
- uint16_t command; /* command code */
- uint16_t credit; /* # of credits requesting/granted */
- uint32_t flags; /* flags */
- uint32_t next_command; /* used for compounded request */
- uint64_t message_id; /* identifies a message uniquely on connection */
- uint64_t async_id; /* handle operations asynchronously */
- uint64_t session_id; /* identifies the established session for the command*/
- uint8_t signature[16]; /* signature of the message */
-};
-
struct Smb2SyncHdr
{
uint8_t smb_idf[4]; /* contains 0xFE,’SMB’ */
uint8_t signature[16]; /* signature of the message */
};
-struct Smb2ErrorResponseHdr
-{
- uint16_t structure_size; /* This MUST be set to 9 */
- uint16_t reserved; /* reserved */
- uint32_t byte_count; /* The number of bytes of error_data */
- uint8_t error_data[1]; /* If byte_count is 0, this MUST be 0*/
-};
-
-class DCE2_Smb2TreeTracker;
-
-class DCE2_Smb2RequestTracker
-{
-public:
-
- DCE2_Smb2RequestTracker() = delete;
- DCE2_Smb2RequestTracker(const DCE2_Smb2RequestTracker& arg) = delete;
- DCE2_Smb2RequestTracker& operator=(const DCE2_Smb2RequestTracker& arg) = delete;
-
- DCE2_Smb2RequestTracker(uint64_t file_id_v, uint64_t offset_v = 0);
- DCE2_Smb2RequestTracker(char* fname_v, uint16_t fname_len_v);
- ~DCE2_Smb2RequestTracker();
-
- uint64_t get_offset()
- {
- return offset;
- }
-
- uint64_t get_file_id()
- {
- return file_id;
- }
-
- void set_file_id(uint64_t fid)
- {
- file_id = fid;
- }
-
- char* fname = nullptr;
- uint16_t fname_len = 0;
-
-private:
-
- uint64_t file_id = 0;
- uint64_t offset = 0;
-};
-
-struct DCE2_Smb2SsnData;
-class DCE2_Smb2SessionTracker;
-
-class DCE2_Smb2FileTracker
-{
-public:
-
- DCE2_Smb2FileTracker() = delete;
- DCE2_Smb2FileTracker(const DCE2_Smb2FileTracker& arg) = delete;
- DCE2_Smb2FileTracker& operator=(const DCE2_Smb2FileTracker& arg) = delete;
-
- DCE2_Smb2FileTracker(uint64_t file_id_v, DCE2_Smb2TreeTracker* ttr_v,
- DCE2_Smb2SessionTracker* str_v, snort::Flow* flow_v);
- ~DCE2_Smb2FileTracker();
-
- bool ignore = false;
- bool upload = false;
- uint16_t file_name_len = 0;
- uint64_t bytes_processed = 0;
- uint64_t file_offset = 0;
- uint64_t file_id = 0;
- uint64_t file_size = 0;
- uint64_t file_name_hash = 0;
- char* file_name = nullptr;
- DCE2_SmbPduState smb2_pdu_state;
- DCE2_Smb2TreeTracker* ttr = nullptr;
- DCE2_Smb2SessionTracker* str = nullptr;
- snort::Flow *flow = nullptr;
-};
-
-typedef DCE2_DbMap<uint64_t, DCE2_Smb2FileTracker*, std::hash<uint64_t> > DCE2_DbMapFtracker;
-typedef DCE2_DbMap<uint64_t, DCE2_Smb2RequestTracker*, std::hash<uint64_t> > DCE2_DbMapRtracker;
-class DCE2_Smb2TreeTracker
-{
-public:
-
- DCE2_Smb2TreeTracker() = delete;
- DCE2_Smb2TreeTracker(const DCE2_Smb2TreeTracker& arg) = delete;
- DCE2_Smb2TreeTracker& operator=(const DCE2_Smb2TreeTracker& arg) = delete;
-
- DCE2_Smb2TreeTracker (uint32_t tid_v, uint8_t share_type_v);
- ~DCE2_Smb2TreeTracker();
-
- // File Tracker
- DCE2_Smb2FileTracker* findFtracker(uint64_t file_id)
- {
- return file_trackers.Find(file_id);
- }
-
- bool insertFtracker(uint64_t file_id, DCE2_Smb2FileTracker* ftracker)
- {
- return file_trackers.Insert(file_id, ftracker);
- }
-
- void removeFtracker(uint64_t file_id)
- {
- file_trackers.Remove(file_id);
- }
-
- // Request Tracker
- DCE2_Smb2RequestTracker* findRtracker(uint64_t mid)
- {
- return req_trackers.Find(mid);
- }
-
- bool insertRtracker(uint64_t message_id, DCE2_Smb2RequestTracker* rtracker)
- {
- return req_trackers.Insert(message_id, rtracker);
- }
-
- void removeRtracker(uint64_t message_id)
- {
- req_trackers.Remove(message_id);
- }
-
- int getRtrackerSize()
- {
- return req_trackers.GetSize();
- }
-
- // common methods
- uint8_t get_share_type()
- {
- return share_type;
- }
-
- uint32_t get_tid()
- {
- return tid;
- }
-
-private:
- uint8_t share_type = 0;
- uint32_t tid = 0;
-
- DCE2_DbMapRtracker req_trackers;
- DCE2_DbMapFtracker file_trackers;
-};
-
-PADDING_GUARD_BEGIN
-struct Smb2SidHashKey
-{
- //must be of size 3*x*sizeof(uint32_t)
- uint32_t cip[4];
- uint32_t sip[4];
- uint64_t sid;
- int16_t cgroup;
- int16_t sgroup;
- uint16_t asid;
- uint16_t padding;
-
- bool operator== (const Smb2SidHashKey &other) const
- {
- return( sid == other.sid and
- cip[0] == other.cip[0] and
- cip[1] == other.cip[1] and
- cip[2] == other.cip[2] and
- cip[3] == other.cip[3] and
- sip[0] == other.sip[0] and
- sip[1] == other.sip[1] and
- sip[2] == other.sip[2] and
- sip[3] == other.sip[3] and
- cgroup == other.cgroup and
- sgroup == other.sgroup and
- asid == other.asid);
- }
-};
-
-struct SmbFlowKey
-{
- uint32_t ip_l[4]; /* Low IP */
- uint32_t ip_h[4]; /* High IP */
- uint32_t mplsLabel;
- uint16_t port_l; /* Low Port - 0 if ICMP */
- uint16_t port_h; /* High Port - 0 if ICMP */
- int16_t group_l;
- int16_t group_h;
- uint16_t vlan_tag;
- uint16_t addressSpaceId;
- uint8_t ip_protocol;
- uint8_t pkt_type;
- uint8_t version;
- uint8_t padding;
-
- bool operator==(const SmbFlowKey& other) const
- {
- return (ip_l[0] == other.ip_l[0] and
- ip_l[1] == other.ip_l[1] and
- ip_l[2] == other.ip_l[2] and
- ip_l[3] == other.ip_l[3] and
- ip_h[0] == other.ip_h[0] and
- ip_l[1] == other.ip_l[1] and
- ip_l[2] == other.ip_l[2] and
- ip_l[3] == other.ip_l[3] and
- mplsLabel == other.mplsLabel and
- port_l == other.port_l and
- port_h == other.port_h and
- group_l == other.group_l and
- group_h == other.group_h and
- vlan_tag == other.vlan_tag and
- addressSpaceId == other.addressSpaceId and
- ip_protocol == other.ip_protocol and
- pkt_type == other.pkt_type and
- version == other.version);
- }
-};
-PADDING_GUARD_END
-
-//The below value is taken from Hash Key class static hash hardener
-#define SMB_KEY_HASH_HARDENER 133824503
-
-struct SmbKeyHash
-{
- size_t operator() (const SmbFlowKey& key) const
- {
- return do_hash_flow_key((const uint32_t*)&key);
- }
-
- size_t operator() (const Smb2SidHashKey& key) const
- {
- return do_hash((const uint32_t*)&key);
- }
-
-private:
- size_t do_hash(const uint32_t* d) const
- {
- uint32_t a, b, c;
- a = b = c = SMB_KEY_HASH_HARDENER;
- a += d[0]; b += d[1]; c += d[2]; mix(a, b, c);
- a += d[3]; b += d[4]; c += d[5]; mix(a, b, c);
- a += d[6]; b += d[7]; c += d[8]; mix(a, b, c);
- a += d[9]; b += d[10]; c += d[11]; finalize(a, b, c);
- return c;
- }
-
- size_t do_hash_flow_key(const uint32_t* d) const
- {
- uint32_t a, b, c;
- a = b = c = SMB_KEY_HASH_HARDENER;
- a += d[0]; b += d[1]; c += d[2]; mix(a, b, c);
- a += d[3]; b += d[4]; c += d[5]; mix(a, b, c);
- a += d[6]; b += d[7]; c += d[8]; mix(a, b, c);
- a += d[9]; b += d[10]; c += d[11]; mix(a, b, c);
- a += d[12]; finalize(a, b, c);
- return c;
- }
-
- inline uint32_t rot(uint32_t x, unsigned k) const
- { return (x << k) | (x >> (32 - k)); }
-
- inline void mix(uint32_t& a, uint32_t& b, uint32_t& c) const
- {
- a -= c; a ^= rot(c, 4); c += b;
- b -= a; b ^= rot(a, 6); a += c;
- c -= b; c ^= rot(b, 8); b += a;
- a -= c; a ^= rot(c,16); c += b;
- b -= a; b ^= rot(a,19); a += c;
- c -= b; c ^= rot(b, 4); b += a;
- }
-
- inline void finalize(uint32_t& a, uint32_t& b, uint32_t& c) const
- {
- c ^= b; c -= rot(b,14);
- a ^= c; a -= rot(c,11);
- b ^= a; b -= rot(a,25);
- c ^= b; c -= rot(b,16);
- a ^= c; a -= rot(c,4);
- b ^= a; b -= rot(a,14);
- c ^= b; c -= rot(b,24);
- }
-};
-
-typedef DCE2_DbMap<uint32_t, DCE2_Smb2TreeTracker*, std::hash<uint32_t> > DCE2_DbMapTtracker;
-typedef DCE2_DbMap<struct SmbFlowKey, DCE2_Smb2SsnData*, SmbKeyHash> DCE2_DbMapConntracker;
-class DCE2_Smb2SessionTracker
-{
-public:
-
- DCE2_Smb2SessionTracker();
- ~DCE2_Smb2SessionTracker();
-
- void removeSessionFromAllConnection();
-
- // tree tracker
- bool insertTtracker(uint32_t tree_id, DCE2_Smb2TreeTracker* ttr)
- {
- return tree_trackers.Insert(tree_id, ttr);
- }
-
- DCE2_Smb2TreeTracker* findTtracker(uint32_t tree_id)
- {
- return tree_trackers.Find(tree_id);
- }
-
- void removeTtracker(uint32_t tree_id)
- {
- tree_trackers.Remove(tree_id);
- }
-
- // ssd tracker
- bool insertConnTracker(SmbFlowKey key, DCE2_Smb2SsnData* ssd)
- {
- return conn_trackers.Insert(key, ssd);
- }
-
- DCE2_Smb2SsnData* findConnTracker(SmbFlowKey key)
- {
- return conn_trackers.Find(key);
- }
-
- void removeConnTracker(SmbFlowKey key)
- {
- conn_trackers.Remove(key);
- }
-
- int getConnTrackerSize()
- {
- return conn_trackers.GetSize();
- }
-
- 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->getRtrackerSize();
- }
- return total_count;
- }
-
- void set_session_id(uint64_t sid)
- {
- session_id = sid;
- conn_trackers.SetDoNotFree();
- }
-
- DCE2_DbMapConntracker conn_trackers;
- DCE2_DbMapTtracker tree_trackers;
- Smb2SidHashKey session_key;
- uint64_t session_id = 0;
-};
-
-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
- SmbFlowKey flow_key;
-};
-
-/* SMB2 command codes */
-#define SMB2_COM_NEGOTIATE 0x00
-#define SMB2_COM_SESSION_SETUP 0x01
-#define SMB2_COM_LOGOFF 0x02
-#define SMB2_COM_TREE_CONNECT 0x03
-#define SMB2_COM_TREE_DISCONNECT 0x04
-#define SMB2_COM_CREATE 0x05
-#define SMB2_COM_CLOSE 0x06
-#define SMB2_COM_FLUSH 0x07
-#define SMB2_COM_READ 0x08
-#define SMB2_COM_WRITE 0x09
-#define SMB2_COM_LOCK 0x0A
-#define SMB2_COM_IOCTL 0x0B
-#define SMB2_COM_CANCEL 0x0C
-#define SMB2_COM_ECHO 0x0D
-#define SMB2_COM_QUERY_DIRECTORY 0x0E
-#define SMB2_COM_CHANGE_NOTIFY 0x0F
-#define SMB2_COM_QUERY_INFO 0x10
-#define SMB2_COM_SET_INFO 0x11
-#define SMB2_COM_OPLOCK_BREAK 0x12
-#define SMB2_COM_MAX 0x13
-
struct Smb2WriteRequestHdr
{
uint16_t structure_size; /* This MUST be set to 49 */
uint32_t create_contexts_length; /* length of contexts */
};
-// file attribute for create response
-#define SMB2_CREATE_RESPONSE_DIRECTORY 0x10
-
struct Smb2CreateResponseHdr
{
uint16_t structure_size; /* This MUST be set to 89 */
uint32_t create_contexts_length; /* */
};
+struct Smb2CreateContextHdr
+{
+ uint32_t next; /* next context header*/
+ uint16_t name_offset; /* name offset */
+ uint16_t name_length; /* name length */
+ uint16_t reserved; /* reserved */
+ uint16_t data_offset; /* data offset */
+ uint32_t data_length; /* data length */
+};
+
struct Smb2CloseRequestHdr
{
uint16_t structure_size; /* This MUST be set to 24 */
uint64_t fileId_volatile; /* fileId that is volatile */
};
-#define SMB2_SHARE_TYPE_DISK 0x01
-#define SMB2_SHARE_TYPE_PIPE 0x02
-#define SMB2_SHARE_TYPE_PRINT 0x03
-
struct Smb2TreeConnectResponseHdr
{
uint16_t structure_size; /* This MUST be set to 16 */
uint32_t maximal_access; /* maximal access for the user */
};
-struct Smb2TreeDisConnectHdr
-{
- uint16_t structure_size; /* This MUST be set to 4 */
- uint16_t reserved; /* reserved */
-};
-
-struct Smb2SetupRequestHdr
-{
- uint16_t structure_size; /* This MUST be set to 25 (0x19) bytes */
- uint8_t flags;
- uint8_t security_mode;
- uint32_t capabilities;
- uint32_t channel;
- uint16_t secblob_ofs;
- uint16_t secblob_size;
- uint64_t previous_sessionid;
-};
-
-struct Smb2SetupResponseHdr
-{
- uint16_t structure_size; /* This MUST be set to 9 (0x09) bytes */
- uint16_t session_flags;
- uint16_t secblob_ofs;
- uint16_t secblob_size;
-};
-
#define SMB2_HEADER_LENGTH 64
#define SMB2_ERROR_RESPONSE_STRUC_SIZE 9
#define SMB2_CREATE_REQUEST_STRUC_SIZE 57
#define SMB2_CREATE_RESPONSE_STRUC_SIZE 89
-#define SMB2_CREATE_REQUEST_DATA_OFFSET 120
#define SMB2_CLOSE_REQUEST_STRUC_SIZE 24
#define SMB2_CLOSE_RESPONSE_STRUC_SIZE 60
#define SMB2_TREE_CONNECT_REQUEST_STRUC_SIZE 9
#define SMB2_TREE_CONNECT_RESPONSE_STRUC_SIZE 16
#define SMB2_TREE_DISCONNECT_REQUEST_STRUC_SIZE 4
+#define SMB2_TREE_DISCONNECT_RESPONSE_STRUC_SIZE 4
#define SMB2_FILE_ENDOFFILE_INFO 0x14
#define SMB2_SETUP_RESPONSE_STRUC_SIZE 9
#define SMB2_LOGOFF_REQUEST_STRUC_SIZE 4
+#define SMB2_LOGOFF_RESPONSE_STRUC_SIZE 4
-extern const char* smb2_command_string[SMB2_COM_MAX];
-/* Process smb2 message */
-void DCE2_Smb2Process(DCE2_Smb2SsnData* ssd);
+#define GET_CURRENT_PACKET snort::DetectionEngine::get_current_packet()
+
+class Dce2Smb2FileTracker;
+class Dce2Smb2SessionTracker;
+
+using Dce2Smb2SessionTrackerMap =
+ std::unordered_map<uint64_t, Dce2Smb2SessionTracker*, std::hash<uint64_t> >;
+
+PADDING_GUARD_BEGIN
+struct Smb2SessionKey
+{
+ uint32_t cip[4];
+ uint32_t sip[4];
+ uint64_t sid;
+ int16_t cgroup;
+ int16_t sgroup;
+ uint16_t asid;
+ uint16_t padding;
+
+ bool operator==(const Smb2SessionKey& other) const
+ {
+ return( sid == other.sid and
+ cip[0] == other.cip[0] and
+ cip[1] == other.cip[1] and
+ cip[2] == other.cip[2] and
+ cip[3] == other.cip[3] and
+ sip[0] == other.sip[0] and
+ sip[1] == other.sip[1] and
+ sip[2] == other.sip[2] and
+ sip[3] == other.sip[3] and
+ cgroup == other.cgroup and
+ sgroup == other.sgroup and
+ asid == other.asid );
+ }
+};
+
+struct Smb2FlowKey
+{
+ uint32_t ip_l[4]; // Low IP
+ uint32_t ip_h[4]; // High IP
+ uint32_t mplsLabel;
+ uint16_t port_l; // Low Port - 0 if ICMP
+ uint16_t port_h; // High Port - 0 if ICMP
+ int16_t group_l;
+ int16_t group_h;
+ uint16_t vlan_tag;
+ uint16_t addressSpaceId;
+ uint8_t ip_protocol;
+ uint8_t pkt_type;
+ uint8_t version;
+ uint8_t padding;
+
+ bool operator==(const Smb2FlowKey& other) const
+ {
+ return (ip_l[0] == other.ip_l[0] and
+ ip_l[1] == other.ip_l[1] and
+ ip_l[2] == other.ip_l[2] and
+ ip_l[3] == other.ip_l[3] and
+ ip_h[0] == other.ip_h[0] and
+ ip_l[1] == other.ip_l[1] and
+ ip_l[2] == other.ip_l[2] and
+ ip_l[3] == other.ip_l[3] and
+ mplsLabel == other.mplsLabel and
+ port_l == other.port_l and
+ port_h == other.port_h and
+ group_l == other.group_l and
+ group_h == other.group_h and
+ vlan_tag == other.vlan_tag and
+ addressSpaceId == other.addressSpaceId and
+ ip_protocol == other.ip_protocol and
+ pkt_type == other.pkt_type and
+ version == other.version);
+ }
+};
+PADDING_GUARD_END
+
+//The below value is taken from Hash Key class static hash hardener
+#define SMB_KEY_HASH_HARDENER 133824503
+
+struct Smb2KeyHash
+{
+ size_t operator()(const Smb2FlowKey& key) const
+ {
+ return do_hash_flow_key((const uint32_t*)&key);
+ }
+
+ size_t operator()(const Smb2SessionKey& key) const
+ {
+ return do_hash_session_key((const uint32_t*)&key);
+ }
+
+private:
+ size_t do_hash_flow_key(const uint32_t* d) const
+ {
+ uint32_t a, b, c;
+ a = b = c = SMB_KEY_HASH_HARDENER;
+ a += d[0]; b += d[1]; c += d[2]; mix(a, b, c);
+ a += d[3]; b += d[4]; c += d[5]; mix(a, b, c);
+ a += d[6]; b += d[7]; c += d[8]; mix(a, b, c);
+ a += d[9]; b += d[10]; c += d[11]; mix(a, b, c);
+ a += d[12]; finalize(a, b, c);
+ return c;
+ }
+
+ size_t do_hash_session_key(const uint32_t* d) const
+ {
+ uint32_t a, b, c;
+ a = b = c = SMB_KEY_HASH_HARDENER;
+ a += d[0]; b += d[1]; c += d[2]; mix(a, b, c);
+ a += d[3]; b += d[4]; c += d[5]; mix(a, b, c);
+ a += d[6]; b += d[7]; c += d[8]; mix(a, b, c);
+ a += d[9]; b += d[10]; c += d[11]; finalize(a, b, c);
+ return c;
+ }
+
+ inline uint32_t rot(uint32_t x, unsigned k) const
+ { return (x << k) | (x >> (32 - k)); }
+
+ inline void mix(uint32_t& a, uint32_t& b, uint32_t& c) const
+ {
+ a -= c; a ^= rot(c, 4); c += b;
+ b -= a; b ^= rot(a, 6); a += c;
+ c -= b; c ^= rot(b, 8); b += a;
+ a -= c; a ^= rot(c,16); c += b;
+ b -= a; b ^= rot(a,19); a += c;
+ c -= b; c ^= rot(b, 4); b += a;
+ }
+
+ inline void finalize(uint32_t& a, uint32_t& b, uint32_t& c) const
+ {
+ c ^= b; c -= rot(b,14);
+ a ^= c; a -= rot(c,11);
+ b ^= a; b -= rot(a,25);
+ c ^= b; c -= rot(b,16);
+ a ^= c; a -= rot(c,4);
+ b ^= a; b -= rot(a,14);
+ c ^= b; c -= rot(b,24);
+ }
+};
+
+Smb2FlowKey get_smb2_flow_key(void);
+
+class Dce2Smb2SessionData : public Dce2SmbSessionData
+{
+public:
+ Dce2Smb2SessionData() = delete;
+ Dce2Smb2SessionData(const snort::Packet*, const dce2SmbProtoConf* proto);
+ ~Dce2Smb2SessionData() override;
+ void process() override;
+ void remove_session(uint64_t);
+ void handle_retransmit(FilePosition, FileVerdict) override { }
+ void reset_matching_tcp_file_tracker(Dce2Smb2FileTracker*);
+ void set_tcp_file_tracker(Dce2Smb2FileTracker* file_tracker)
+ { tcp_file_tracker = file_tracker; }
+
+private:
+ void process_command(const Smb2Hdr*, const uint8_t*);
+ Smb2SessionKey get_session_key(uint64_t);
+ Dce2Smb2SessionTracker* create_session(uint64_t);
+ Dce2Smb2SessionTracker* find_session(uint64_t);
+
+ Smb2FlowKey flow_key;
+ Dce2Smb2FileTracker* tcp_file_tracker;
+ Dce2Smb2SessionTrackerMap connected_sessions;
+};
-/* Check smb version based on smb header */
-DCE2_SmbVersion DCE2_Smb2Version(const snort::Packet* p);
+using Dce2Smb2SessionDataMap =
+ std::unordered_map<Smb2FlowKey, Dce2Smb2SessionData*, Smb2KeyHash>;
#endif /* _DCE_SMB2_H_ */
+++ /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 "hash/hash_key_operations.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, cmd) \
- { \
- if ((smb_data + (strcuture_size)) > end) \
- { \
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(), \
- "%s : smb data beyond end detected\n", smb2_command_string[cmd]); \
- counter ++; \
- return; \
- } \
- }
-
-static inline FileContext* get_smb_file_context(uint64_t file_id, uint64_t
- multi_file_processing_id,
- bool to_create = false)
-{
- 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, to_create, multi_file_processing_id);
-}
-
-static void DCE2_Smb2CleanFtrackerTcpRef(DCE2_Smb2SessionTracker* str, uint64_t file_id)
-{
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "updating conn for fid %" PRIu64 "\n", file_id);
- auto all_conn_trackers = str->conn_trackers.get_all_entry();
- for ( auto& h : all_conn_trackers )
- {
- if (h.second->ftracker_tcp)
- {
- if (h.second->ftracker_tcp->file_id == file_id)
- {
- h.second->ftracker_tcp = nullptr;
- }
- }
- }
-}
-
-DCE2_Smb2TreeTracker *find_tree_for_message(DCE2_Smb2SessionTracker *str, const uint64_t mid)
-{
- auto all_tree_trackers = str->tree_trackers.get_all_entry();
- for ( auto& h : all_tree_trackers )
- {
- if(h.second->findRtracker(mid))
- return h.second;
- }
- return nullptr;
-}
-
-bool DCE2_Smb2ProcessFileData(DCE2_Smb2SsnData* ssd, const uint8_t* file_data,
- uint32_t data_size)
-{
- 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;
- FileDirection dir = ssd->ftracker_tcp->upload ? FILE_UPLOAD : FILE_DOWNLOAD;
-
- debug_logf(dce_smb_trace, p, "file_process fid %" PRIu64 " data_size %" PRIu32 ""
- " offset %" PRIu64 " bytes processed %" PRIu64 "\n", ssd->ftracker_tcp->file_id,
- data_size, ssd->ftracker_tcp->file_offset, ssd->ftracker_tcp->bytes_processed);
-
- // 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++;
- debug_logf(dce_smb_trace, p, "extra file data\n");
-
- DCE2_Smb2TreeTracker* ttr = ssd->ftracker_tcp->ttr;
- uint64_t file_id = ssd->ftracker_tcp->file_id;
- DCE2_Smb2CleanFtrackerTcpRef(ssd->ftracker_tcp->str, file_id);
- ttr->removeFtracker(file_id);
-
- return false;
- }
-
- if (!file_flows->file_process(p, ssd->ftracker_tcp->file_name_hash, file_data, data_size,
- ssd->ftracker_tcp->file_offset, dir, ssd->ftracker_tcp->file_id) and detection_size)
- {
- debug_logf(dce_smb_trace, p, "file_process completed\n");
-
- DCE2_Smb2TreeTracker* ttr = ssd->ftracker_tcp->ttr;
- uint64_t file_id = ssd->ftracker_tcp->file_id;
- DCE2_Smb2CleanFtrackerTcpRef(ssd->ftracker_tcp->str, file_id);
- ttr->removeFtracker(file_id);
-
- return false;
- }
- return true;
-}
-
-//-------------------------------------------------------------------------
-// Process session setup response to find/create session tracker
-//-------------------------------------------------------------------------
-void DCE2_Smb2Setup(DCE2_Smb2SsnData* ssd, const Smb2Hdr* smb_hdr, const uint64_t sid,
- const uint8_t* smb_data, const uint8_t* end)
-{
- uint16_t structure_size = alignedNtohs((const uint16_t*)smb_data);
-
- if (structure_size == SMB2_ERROR_RESPONSE_STRUC_SIZE and Smb2Error(smb_hdr))
- {
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s_RESP: error\n", smb2_command_string[SMB2_COM_SESSION_SETUP]);
- dce2_smb_stats.v2_setup_err_resp++;
- }
- else if (structure_size == SMB2_SETUP_RESPONSE_STRUC_SIZE)
- {
- SMB2_CHECK_HDR_ERROR(
- smb_data, end, SMB2_SETUP_RESPONSE_STRUC_SIZE - 1,
- dce2_smb_stats.v2_setup_resp_hdr_err, SMB2_COM_SESSION_SETUP)
- DCE2_Smb2FindElseCreateSid(ssd, sid);
- }
- else if (structure_size != SMB2_SETUP_REQUEST_STRUC_SIZE)
- {
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s: invalid struct size\n", smb2_command_string[SMB2_COM_SESSION_SETUP]);
- dce2_smb_stats.v2_setup_inv_str_sz++;
- }
-}
-
-//-------------------------------------------------------------------------
-// Process tree connect response to find/create tree tracker
-//-------------------------------------------------------------------------
-void DCE2_Smb2TreeConnect(DCE2_Smb2SsnData* ssd, const Smb2Hdr* smb_hdr,
- const uint8_t* smb_data, const uint8_t* end, DCE2_Smb2SessionTracker* str, uint32_t tid)
-{
- uint16_t structure_size = alignedNtohs((const uint16_t*)smb_data);
-
- if (structure_size == SMB2_ERROR_RESPONSE_STRUC_SIZE and Smb2Error(smb_hdr))
- {
- dce2_smb_stats.v2_tree_cnct_err_resp++;
- }
- else if (structure_size == SMB2_TREE_CONNECT_RESPONSE_STRUC_SIZE)
- {
- SMB2_CHECK_HDR_ERROR(
- smb_data, end, SMB2_TREE_CONNECT_RESPONSE_STRUC_SIZE,
- dce2_smb_stats.v2_tree_cnct_resp_hdr_err, SMB2_COM_TREE_CONNECT)
-
- if (!DCE2_Smb2InsertTid(ssd, tid,
- ((const Smb2TreeConnectResponseHdr*)smb_data)->share_type, str))
- {
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s: ignored %d\n", smb2_command_string[SMB2_COM_TREE_CONNECT], tid);
- dce2_smb_stats.v2_tree_cnct_ignored++;
- }
- }
- else if (structure_size != SMB2_TREE_CONNECT_REQUEST_STRUC_SIZE)
- {
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s: invalid struct size\n", smb2_command_string[SMB2_COM_TREE_CONNECT]);
- dce2_smb_stats.v2_tree_cnct_inv_str_sz++;
- }
-}
-
-//-------------------------------------------------------------------------
-// Process tree disconnect request to cleanup tree tracker and its
-// corresponding request trackers and file trackers
-//-------------------------------------------------------------------------
-void DCE2_Smb2TreeDisconnect(DCE2_Smb2SsnData*, const uint8_t* smb_data,
- const uint8_t* end, 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, SMB2_COM_TREE_DISCONNECT)
- str->removeTtracker(tid);
- }
- else
- {
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s: invalid struct size\n", smb2_command_string[SMB2_COM_TREE_DISCONNECT]);
- dce2_smb_stats.v2_tree_discn_inv_str_sz++;
- }
-}
-
-//-------------------------------------------------------------------------
-// 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++;
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s_REQ: invalid file data seen\n", smb2_command_string[SMB2_COM_CREATE]);
- return;
- }
-
- uint16_t size = alignedNtohs(&(smb_create_hdr->name_length));
- if (!size or (file_data + size > end))
- {
- dce2_smb_stats.v2_crt_inv_file_data++;
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s_REQ: invalid file data seen with size %" PRIu16 "\n",
- smb2_command_string[SMB2_COM_CREATE], size);
-
- return;
- }
-
- if (ssd->max_outstanding_requests > str->getTotalRequestsPending())
- {
- DCE2_Smb2RequestTracker* rtracker = ttr->findRtracker(mid);
- if (rtracker) // Cleanup existing tracker
- ttr->removeRtracker(mid);
-
- char* file_name = DCE2_SmbGetFileName(file_data, size, true, &name_len);
-
- rtracker = new DCE2_Smb2RequestTracker(file_name, name_len);
- ttr->insertRtracker(mid, rtracker);
- }
- else
- {
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s_REQ: max req exceeded\n", smb2_command_string[SMB2_COM_CREATE]);
- dce_alert(GID_DCE2, DCE2_SMB_MAX_REQS_EXCEEDED, (dce2CommonStats*)&dce2_smb_stats,
- ssd->sd);
- }
- }
- else
- {
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s_REQ: name_offset %" PRIu16 "\n", smb2_command_string[SMB2_COM_CREATE], name_offset);
- dce2_smb_stats.v2_crt_req_hdr_err++;
- }
-}
-
-//-------------------------------------------------------------------------
-// Process create response to create file tracker with file id and file
-// size. Request tracker is cleaned after updating file name in file tracker
-//-------------------------------------------------------------------------
-static void DCE2_Smb2CreateResponse(DCE2_Smb2SsnData*,
- const Smb2CreateResponseHdr* smb_create_hdr, DCE2_Smb2RequestTracker* rtracker,
- DCE2_Smb2TreeTracker* ttr, DCE2_Smb2SessionTracker* str, uint64_t fileId_persistent)
-{
- uint64_t file_size = 0;
-
- if (smb_create_hdr->end_of_file)
- {
- file_size = alignedNtohq((const uint64_t*)(&(smb_create_hdr->end_of_file)));
- }
-
- DCE2_Smb2FileTracker* ftracker = ttr->findFtracker(fileId_persistent);
- if (!ftracker)
- {
- ftracker = new DCE2_Smb2FileTracker(fileId_persistent, ttr, str, DetectionEngine::get_current_packet()->flow);
- ttr->insertFtracker(fileId_persistent, ftracker);
- }
- ftracker->file_name = rtracker->fname;
- ftracker->file_name_len = rtracker->fname_len;
- ftracker->file_size = file_size;
-
- if (rtracker->fname and rtracker->fname_len)
- {
- ftracker->file_name_hash = str_to_hash(
- (const uint8_t*)rtracker->fname, rtracker->fname_len);
-
- FileContext* file = get_smb_file_context(ftracker->file_name_hash, fileId_persistent,
- true);
-
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s_RESP: file size %" PRIu64 " fid %" PRIu64 ""
- "file_name_hash %" PRIu64 " file context %s\n", smb2_command_string[SMB2_COM_CREATE],
- file_size, fileId_persistent, ftracker->file_name_hash, (file ? "found" : "not found"));
-
- if (file)
- {
- if (file->verdict == FILE_VERDICT_UNKNOWN)
- {
- file->set_file_size(!file_size ? UNKNOWN_FILE_SIZE : file_size);
- file->set_file_name(ftracker->file_name, ftracker->file_name_len);
- }
- }
- else
- {
- ftracker->ignore = true; // could not create file context, hence this file transfer
- // cant be inspected
- }
- rtracker->set_file_id(fileId_persistent); // to ensure file tracker will free file name
- }
- else
- {
- ftracker->ignore = true; // file can not be inspected as file name is null
- }
-}
-
-//-------------------------------------------------------------------------
-// Process create request to handle mid stream sessions by adding tree
-// tracker if not already present. Process create response for only disk
-// share type.
-//-------------------------------------------------------------------------
-void DCE2_Smb2Create(DCE2_Smb2SsnData* ssd, const Smb2Hdr* smb_hdr,
- const uint8_t* smb_data, const uint8_t* end, uint64_t mid, uint64_t sid, uint32_t tid)
-{
- DCE2_Smb2SessionTracker* str = DCE2_Smb2FindElseCreateSid(ssd, sid);
- DCE2_Smb2TreeTracker* ttr = str->findTtracker(tid);
- uint16_t structure_size = alignedNtohs((const uint16_t*)smb_data);
-
- if (structure_size == SMB2_ERROR_RESPONSE_STRUC_SIZE and Smb2Error(smb_hdr))
- {
- if (ttr)
- ttr->removeRtracker(mid);
-
- dce2_smb_stats.v2_crt_err_resp++;
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s_RESP: error\n", smb2_command_string[SMB2_COM_CREATE]);
- }
- // Using structure size to decide whether it is response or request
- else if (structure_size == SMB2_CREATE_REQUEST_STRUC_SIZE)
- {
- SMB2_CHECK_HDR_ERROR(
- smb_data, end, SMB2_CREATE_REQUEST_STRUC_SIZE - 1,
- dce2_smb_stats.v2_crt_req_hdr_err, SMB2_COM_CREATE)
-
- if (!ttr)
- {
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s_REQ: mid stream session detected\n", smb2_command_string[SMB2_COM_CREATE]);
- ttr = DCE2_Smb2InsertTid(ssd, tid, SMB2_SHARE_TYPE_DISK, str);
- if (!ttr)
- {
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s_REQ: insert tree tracker failed\n", smb2_command_string[SMB2_COM_CREATE]);
- return;
- }
- }
- else if (SMB2_SHARE_TYPE_DISK != ttr->get_share_type())
- {
- dce2_smb_stats.v2_crt_req_ipc++;
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s_REQ: ignored for ipc share\n", smb2_command_string[SMB2_COM_CREATE]);
- 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, SMB2_COM_CREATE)
-
- if(!tid)
- ttr = find_tree_for_message(str, mid);
- if (!ttr)
- {
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s_RESP: tree tracker missing\n", smb2_command_string[SMB2_COM_CREATE]);
- dce2_smb_stats.v2_crt_tree_trkr_misng++;
- return;
- }
-
- DCE2_Smb2RequestTracker* rtr = ttr->findRtracker(mid);
- if (!rtr)
- {
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s_RESP: req tracker missing\n", smb2_command_string[SMB2_COM_CREATE]);
- dce2_smb_stats.v2_crt_rtrkr_misng++;
- return;
- }
-
- uint64_t fileId_persistent = alignedNtohq((const uint64_t*)(
- &(((const Smb2CreateResponseHdr*)smb_data)->fileId_persistent)));
-
- if (((const Smb2CreateResponseHdr*)smb_data)->file_attributes &
- SMB2_CREATE_RESPONSE_DIRECTORY)
- {
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s_RESP: not processing for directory\n", smb2_command_string[SMB2_COM_CREATE]);
- ttr->removeRtracker(mid);
- DCE2_Smb2CleanFtrackerTcpRef(str, fileId_persistent);
- ttr->removeFtracker(fileId_persistent);
- return;
- }
-
- DCE2_Smb2CreateResponse(ssd, (const Smb2CreateResponseHdr*)smb_data, rtr, ttr,
- str, fileId_persistent);
- ttr->removeRtracker(mid);
- }
- else
- {
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s: invalid struct size\n", smb2_command_string[SMB2_COM_CREATE]);
- dce2_smb_stats.v2_crt_inv_str_sz++;
- }
-}
-
-//-------------------------------------------------------------------------
-// Process close command request to do file processing for an upload or
-// download request with unknown size.
-//-------------------------------------------------------------------------
-void DCE2_Smb2CloseCmd(DCE2_Smb2SsnData* ssd, const Smb2Hdr* smb_hdr,
- const uint8_t* smb_data, const uint8_t* end, DCE2_Smb2TreeTracker* ttr,
- DCE2_Smb2SessionTracker* str)
-{
- uint16_t structure_size = alignedNtohs((const uint16_t*)smb_data);
-
- if (structure_size == SMB2_ERROR_RESPONSE_STRUC_SIZE and Smb2Error(smb_hdr))
- {
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s_RESP: error\n", smb2_command_string[SMB2_COM_CLOSE]);
- dce2_smb_stats.v2_cls_err_resp++;
- }
- // Using structure size to decide whether it is response or request
- else if (structure_size == SMB2_CLOSE_REQUEST_STRUC_SIZE)
- {
- SMB2_CHECK_HDR_ERROR(
- smb_data, end, SMB2_CLOSE_REQUEST_STRUC_SIZE,
- dce2_smb_stats.v2_cls_req_hdr_err, SMB2_COM_CLOSE)
-
- uint64_t fileId_persistent = alignedNtohq(&(((const
- Smb2CloseRequestHdr*)smb_data)->fileId_persistent));
- DCE2_Smb2FileTracker* ftracker = ttr->findFtracker(fileId_persistent);
- if (!ftracker)
- {
- dce2_smb_stats.v2_cls_req_ftrkr_misng++;
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s_REQ: ftracker missing %" PRIu64 "\n",
- smb2_command_string[SMB2_COM_CLOSE], fileId_persistent);
- return;
- }
-
- if (!ftracker->ignore and !ftracker->file_size and ftracker->file_offset)
- {
- ftracker->file_size = ftracker->file_offset;
- FileContext* file = get_smb_file_context(ftracker->file_name_hash, fileId_persistent);
- if (file)
- {
- file->set_file_size(ftracker->file_size);
- }
-
- ssd->ftracker_tcp = ftracker;
-
- // In case of upload/download of file with UNKNOWN size, we will not be able to
- // detect malicious file during write request or read response. Once the close
- // command request comes, we will go for file inspection and block an subsequent
- // upload/download request for this file even with unknown size
- DCE2_Smb2ProcessFileData(ssd, nullptr, 0);
- }
- else
- {
- DCE2_Smb2CleanFtrackerTcpRef(str, fileId_persistent);
- ttr->removeFtracker(fileId_persistent);
- }
- }
- else if (structure_size != SMB2_CLOSE_RESPONSE_STRUC_SIZE)
- {
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s: invalid struct size\n", smb2_command_string[SMB2_COM_CLOSE]);
- 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))
- {
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s: error resp\n", smb2_command_string[SMB2_COM_SET_INFO]);
- dce2_smb_stats.v2_stinf_err_resp++;
- }
- else if (structure_size == SMB2_SET_INFO_REQUEST_STRUC_SIZE)
- {
- SMB2_CHECK_HDR_ERROR(
- smb_data, end, SMB2_SET_INFO_REQUEST_STRUC_SIZE,
- dce2_smb_stats.v2_stinf_req_hdr_err, SMB2_COM_SET_INFO)
-
- const Smb2SetInfoRequestHdr* smb_set_info_hdr = (const Smb2SetInfoRequestHdr*)smb_data;
- const uint8_t* file_data = (const uint8_t*)smb_set_info_hdr +
- SMB2_SET_INFO_REQUEST_STRUC_SIZE - 1;
-
- if (smb_set_info_hdr->file_info_class == SMB2_FILE_ENDOFFILE_INFO)
- {
- uint64_t file_size = alignedNtohq((const uint64_t*)file_data);
- uint64_t fileId_persistent = alignedNtohq(&(smb_set_info_hdr->fileId_persistent));
- DCE2_Smb2FileTracker* ftracker = ttr->findFtracker(fileId_persistent);
- if (ftracker and !ftracker->ignore)
- {
- ftracker->file_size = file_size;
- FileContext* file = get_smb_file_context(ftracker->file_name_hash,
- fileId_persistent);
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s_REQ: set file size %" PRIu64 " fid %" PRIu64 " file context %s\n",
- smb2_command_string[SMB2_COM_SET_INFO], file_size, fileId_persistent,
- file ? "found" : "not found");
- if (file)
- {
- file->set_file_size(ftracker->file_size);
- }
- }
- else
- {
- dce2_smb_stats.v2_stinf_req_ftrkr_misng++;
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s_REQ: ftracker missing\n", smb2_command_string[SMB2_COM_SET_INFO]);
- }
- }
- else
- {
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s_REQ: header error\n", smb2_command_string[SMB2_COM_SET_INFO]);
- dce2_smb_stats.v2_stinf_req_hdr_err++;
- }
- }
- else if (structure_size != SMB2_SET_INFO_RESPONSE_STRUC_SIZE)
- {
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s: invalid struct size\n", smb2_command_string[SMB2_COM_SET_INFO]);
- dce2_smb_stats.v2_stinf_inv_str_sz++;
- }
-}
-
-//-------------------------------------------------------------------------
-// Process read request to create read request trackers to get file offset
-//-------------------------------------------------------------------------
-static void DCE2_Smb2ReadRequest(DCE2_Smb2SsnData* ssd,
- const Smb2ReadRequestHdr* smb_read_hdr, const uint8_t*, DCE2_Smb2SessionTracker* str,
- DCE2_Smb2TreeTracker* ttr, uint64_t message_id)
-{
- uint64_t offset = alignedNtohq((const uint64_t*)(&(smb_read_hdr->offset)));
- uint64_t fileId_persistent = alignedNtohq((const
- uint64_t*)(&(smb_read_hdr->fileId_persistent)));
-
- if (ssd->max_outstanding_requests > str->getTotalRequestsPending())
- {
- DCE2_Smb2RequestTracker* readtracker = ttr->findRtracker(message_id);
- if (!readtracker)
- {
- readtracker = new DCE2_Smb2RequestTracker(fileId_persistent, offset);
- ttr->insertRtracker(message_id, readtracker);
- }
- }
- else
- {
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s_REQ: max req exceeded\n", smb2_command_string[SMB2_COM_READ]);
- dce_alert(GID_DCE2, DCE2_SMB_MAX_REQS_EXCEEDED, (dce2CommonStats*)&dce2_smb_stats,
- ssd->sd);
- return;
- }
-
- DCE2_Smb2FileTracker* ftracker = ttr->findFtracker(fileId_persistent);
- if (!ftracker) // compounded create request + read request case
- {
- ftracker = new DCE2_Smb2FileTracker(fileId_persistent, ttr, str, DetectionEngine::get_current_packet()->flow);
- ttr->insertFtracker(fileId_persistent, ftracker);
- }
-
- if (ftracker->file_size and (offset > ftracker->file_size))
- {
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s_REQ: invalid file offset\n", smb2_command_string[SMB2_COM_READ]);
- dce_alert(GID_DCE2, DCE2_SMB_INVALID_FILE_OFFSET, (dce2CommonStats*)&dce2_smb_stats,
- ssd->sd);
- }
-}
-
-//-------------------------------------------------------------------------
-// Process read response to send file data for inspection. read request
-// trackers is cleaned after updating file offset in file tracker
-//-------------------------------------------------------------------------
-static void DCE2_Smb2ReadResponse(DCE2_Smb2SsnData* ssd, const Smb2Hdr* smb_hdr,
- const Smb2ReadResponseHdr* smb_read_hdr, const uint8_t* end, DCE2_Smb2TreeTracker* ttr,
- uint64_t message_id)
-{
- const uint8_t* file_data = (const uint8_t*)smb_read_hdr + SMB2_READ_RESPONSE_STRUC_SIZE - 1;
- int data_size = end - file_data;
- uint16_t data_offset;
- DCE2_Smb2RequestTracker* request;
-
- request = ttr->findRtracker(message_id);
- if (!request)
- {
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s_RESP: request tracker missing\n", smb2_command_string[SMB2_COM_READ]);
- dce2_smb_stats.v2_read_rtrkr_misng++;
- return;
- }
- data_offset = alignedNtohs((const uint16_t*)(&(smb_read_hdr->data_offset)));
- if (data_offset + (const uint8_t*)smb_hdr > end)
- {
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s_RESP: bad offset\n", smb2_command_string[SMB2_COM_READ]);
- dce_alert(GID_DCE2, DCE2_SMB_BAD_OFF, (dce2CommonStats*)&dce2_smb_stats, ssd->sd);
- }
-
- DCE2_Smb2FileTracker* ftracker = ttr->findFtracker(request->get_file_id());
- if ( ftracker and !ftracker->ignore )
- {
- ftracker->file_offset = request->get_offset();
- ttr->removeRtracker(message_id);
-
- ssd->ftracker_tcp = ftracker;
-
- if (!DCE2_Smb2ProcessFileData(ssd, file_data, data_size))
- return;
- ftracker->file_offset += data_size;
-
- uint32_t total_data_length = alignedNtohl((const uint32_t*)&(smb_read_hdr->length));
- 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->findRtracker(mid);
- if (rtr and rtr->get_file_id())
- {
- DCE2_Smb2CleanFtrackerTcpRef(str, rtr->get_file_id());
- ttr->removeFtracker(rtr->get_file_id());
- }
- ttr->removeRtracker(mid);
- dce2_smb_stats.v2_read_err_resp++;
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s_RESP: error\n", smb2_command_string[SMB2_COM_WRITE]);
- }
- // Using structure size to decide whether it is response or request
- else if (structure_size == SMB2_READ_REQUEST_STRUC_SIZE)
- {
- SMB2_CHECK_HDR_ERROR(
- smb_data, end, SMB2_READ_REQUEST_STRUC_SIZE - 1,
- dce2_smb_stats.v2_read_req_hdr_err, SMB2_COM_READ)
- DCE2_Smb2ReadRequest(ssd, (const Smb2ReadRequestHdr*)smb_data, end, str, ttr, mid);
- }
- else if (structure_size == SMB2_READ_RESPONSE_STRUC_SIZE)
- {
- SMB2_CHECK_HDR_ERROR(
- smb_data, end, SMB2_READ_RESPONSE_STRUC_SIZE - 1,
- dce2_smb_stats.v2_read_resp_hdr_err, SMB2_COM_READ)
-
- DCE2_Smb2ReadResponse(ssd, smb_hdr, (const Smb2ReadResponseHdr*)smb_data, end, ttr, mid);
- }
- else
- {
- dce2_smb_stats.v2_read_inv_str_sz++;
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s: invalid struct size\n", smb2_command_string[SMB2_COM_WRITE]);
- }
-}
-
-//-------------------------------------------------------------------------
-// Process write request to create write trackers (to enforce credits limit)
-// and to send file data for inspection.
-//-------------------------------------------------------------------------
-static void DCE2_Smb2WriteRequest(DCE2_Smb2SsnData* ssd, const Smb2Hdr* smb_hdr,
- const Smb2WriteRequestHdr* smb_write_hdr, const uint8_t* end, DCE2_Smb2SessionTracker* str,
- DCE2_Smb2TreeTracker* ttr, uint64_t mid)
-{
- const uint8_t* file_data = (const uint8_t*)smb_write_hdr + SMB2_WRITE_REQUEST_STRUC_SIZE - 1;
- int data_size = end - file_data;
- uint64_t fileId_persistent, offset;
- uint16_t data_offset;
-
- fileId_persistent = alignedNtohq((const uint64_t*)(&(smb_write_hdr->fileId_persistent)));
-
- if (ssd->max_outstanding_requests > str->getTotalRequestsPending())
- {
- DCE2_Smb2RequestTracker* writetracker = ttr->findRtracker(mid);
- if (!writetracker)
- {
- writetracker = new DCE2_Smb2RequestTracker(fileId_persistent);
- ttr->insertRtracker(mid, writetracker);
- }
- }
- else
- {
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s_REQ: max req exceeded\n", smb2_command_string[SMB2_COM_WRITE]);
- dce_alert(GID_DCE2, DCE2_SMB_MAX_REQS_EXCEEDED, (dce2CommonStats*)&dce2_smb_stats,
- ssd->sd);
- return;
- }
-
- data_offset = alignedNtohs((const uint16_t*)(&(smb_write_hdr->data_offset)));
- if (data_offset + (const uint8_t*)smb_hdr > end)
- {
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s_REQ: bad offset\n", smb2_command_string[SMB2_COM_WRITE]);
- dce_alert(GID_DCE2, DCE2_SMB_BAD_OFF, (dce2CommonStats*)&dce2_smb_stats, ssd->sd);
- }
-
- offset = alignedNtohq((const uint64_t*)(&(smb_write_hdr->offset)));
- DCE2_Smb2FileTracker* ftracker = ttr->findFtracker(fileId_persistent);
- if (!ftracker) // compounded create request + write request case
- {
- ftracker = new DCE2_Smb2FileTracker(fileId_persistent, ttr, str, DetectionEngine::get_current_packet()->flow);
- ttr->insertFtracker(fileId_persistent, ftracker);
- }
- if (!ftracker->ignore) // file tracker can not be nullptr here
- {
- if (ftracker->file_size and (offset > ftracker->file_size))
- {
- dce_alert(GID_DCE2, DCE2_SMB_INVALID_FILE_OFFSET, (dce2CommonStats*)&dce2_smb_stats,
- ssd->sd);
- }
- ftracker->file_offset = offset;
- ftracker->upload = true;
-
- ssd->ftracker_tcp = ftracker;
-
- if (!DCE2_Smb2ProcessFileData(ssd, file_data, data_size))
- return;
- ftracker->file_offset += data_size;
- uint32_t total_data_length = alignedNtohl((const uint32_t*)&(smb_write_hdr->length));
- 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->findRtracker(mid);
- if (wtr and wtr->get_file_id())
- {
- DCE2_Smb2CleanFtrackerTcpRef(str, wtr->get_file_id());
- ttr->removeFtracker(wtr->get_file_id());
- }
- ttr->removeRtracker(mid);
- dce2_smb_stats.v2_wrt_err_resp++;
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s_RESP: error\n", smb2_command_string[SMB2_COM_WRITE]);
- }
- // Using structure size to decide whether it is response or request
- else if (structure_size == SMB2_WRITE_REQUEST_STRUC_SIZE)
- {
- SMB2_CHECK_HDR_ERROR(
- smb_data, end, SMB2_WRITE_REQUEST_STRUC_SIZE - 1,
- dce2_smb_stats.v2_wrt_req_hdr_err, SMB2_COM_WRITE)
- DCE2_Smb2WriteRequest(ssd, smb_hdr, (const Smb2WriteRequestHdr*)smb_data, end, str, ttr,
- mid);
- }
- else if (structure_size == SMB2_WRITE_RESPONSE_STRUC_SIZE)
- {
- ttr->removeRtracker(mid);
- }
- else
- {
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s: invalid struct size\n", smb2_command_string[SMB2_COM_WRITE]);
- dce2_smb_stats.v2_wrt_inv_str_sz++;
- }
-}
-
-//-------------------------------------------------------------------------
-// Process logoff to cleanup session tracker and their corresponding tree
-// trackers and their corresponding file trackers
-//-------------------------------------------------------------------------
-void DCE2_Smb2Logoff(DCE2_Smb2SsnData* ssd, const uint8_t* smb_data,
- const uint64_t sid)
-{
- if (alignedNtohs((const uint16_t*)smb_data) == SMB2_LOGOFF_REQUEST_STRUC_SIZE)
- {
- DCE2_Smb2SessionTracker* str = DCE2_Smb2FindSidInSsd(ssd, sid);
- if (str)
- {
- str->removeSessionFromAllConnection();
- DCE2_SmbSessionCacheRemove(str->session_key);
- }
- }
- else
- {
- debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
- "%s: invalid struct size\n", smb2_command_string[SMB2_COM_LOGOFF]);
- 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);
-
-bool DCE2_Smb2ProcessFileData(DCE2_Smb2SsnData*, const uint8_t* file_data,
- uint32_t data_size);
-
-void DCE2_Smb2CloseCmd(DCE2_Smb2SsnData*, const Smb2Hdr*,
- const uint8_t* smb_data, const uint8_t* end, DCE2_Smb2TreeTracker* ttr,
- DCE2_Smb2SessionTracker* str);
-
-void DCE2_Smb2Logoff(DCE2_Smb2SsnData*, const uint8_t* smb_data,
- const uint64_t sid);
-
-DCE2_Smb2TreeTracker *find_tree_for_message(DCE2_Smb2SessionTracker*, const uint64_t);
-
-#endif
-
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2021 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// dce_smb2_file.cc author Dipta Pandit <dipandit@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "dce_smb2_file.h"
+
+#include "file_api/file_flows.h"
+#include "hash/hash_key_operations.h"
+
+#include "dce_smb2_session.h"
+#include "dce_smb2_tree.h"
+
+using namespace snort;
+
+#define UNKNOWN_FILE_SIZE (~0)
+
+void Dce2Smb2FileTracker::accept_raw_data_from(Dce2Smb2SessionData* flow)
+{
+ if (flow)
+ {
+ smb2_pdu_state = DCE2_SMB_PDU_STATE__RAW_DATA;
+ flow->set_tcp_file_tracker(this);
+ }
+}
+
+inline void Dce2Smb2FileTracker::file_detect()
+{
+ DetectionEngine::detect(DetectionEngine::get_current_packet());
+ dce2_detected = 1;
+}
+
+void Dce2Smb2FileTracker::set_info(char* file_name_v, uint16_t name_len_v,
+ uint64_t size_v, bool create)
+{
+ if (file_name_v and name_len_v)
+ {
+ file_name = file_name_v;
+ file_name_len = name_len_v;
+ file_name_hash = str_to_hash((uint8_t*)file_name, file_name_len);
+ }
+ file_size = size_v;
+ FileContext* file = get_smb_file_context(file_name_hash, file_id, create);
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "set file info: file size %"
+ PRIu64 " fid %" PRIu64 " file_name_hash %" PRIu64 " file context "
+ "%sfound\n", file_size, file_id, file_name_hash, (file ? "" : "not "));
+ if (file)
+ {
+ ignore = false;
+ if (file->verdict == FILE_VERDICT_UNKNOWN)
+ {
+ if (file_name_v and name_len_v)
+ file->set_file_name(file_name, file_name_len);
+ file->set_file_size(file_size ? file_size : UNKNOWN_FILE_SIZE);
+ }
+ }
+}
+
+bool Dce2Smb2FileTracker::close()
+{
+ if (!ignore and !file_size and file_offset)
+ {
+ file_size = file_offset;
+ FileContext* file =
+ get_smb_file_context(file_name_hash, file_id, false);
+ if (file)
+ file->set_file_size(file_size);
+ return (!process_data(nullptr, 0));
+ }
+ return true;
+}
+
+bool Dce2Smb2FileTracker::process_data(const uint8_t* file_data,
+ uint32_t data_size, uint64_t offset)
+{
+ file_offset = offset;
+ return process_data(file_data, data_size);
+}
+
+bool Dce2Smb2FileTracker::process_data(const uint8_t* file_data,
+ uint32_t data_size)
+{
+ Dce2Smb2SessionData* current_flow = parent_tree->get_parent()->get_current_flow();
+ int64_t file_detection_depth = current_flow->get_smb_file_depth();
+ int64_t detection_size = 0;
+
+ if (file_detection_depth == 0)
+ detection_size = data_size;
+ else if ( file_offset < (uint64_t)file_detection_depth)
+ {
+ if ( file_detection_depth - file_offset < data_size )
+ detection_size = file_detection_depth - file_offset;
+ else
+ detection_size = data_size;
+ }
+
+ if (detection_size)
+ {
+ set_file_data(file_data, (detection_size > UINT16_MAX) ?
+ UINT16_MAX : (uint16_t)detection_size);
+ file_detect();
+ }
+
+ if (ignore)
+ return true;
+
+ Packet* p = DetectionEngine::get_current_packet();
+
+ if (file_size and file_offset > file_size)
+ {
+ debug_logf(dce_smb_trace, p, "file_process: bad offset\n");
+ dce_alert(GID_DCE2, DCE2_SMB_INVALID_FILE_OFFSET, (dce2CommonStats*)
+ &dce2_smb_stats, *(current_flow->get_dce2_session_data()));
+ }
+
+ debug_logf(dce_smb_trace, p, "file_process fid %" PRIu64 " data_size %"
+ PRIu32 " offset %" PRIu64 "\n", file_id, data_size, file_offset);
+
+ FileFlows* file_flows = FileFlows::get_file_flows(p->flow);
+
+ if (!file_flows)
+ return true;
+
+ if (!file_flows->file_process(p, file_name_hash, file_data, data_size,
+ file_offset, direction, file_id))
+ {
+ debug_logf(dce_smb_trace, p, "file_process completed\n");
+ return false;
+ }
+
+ file_offset += data_size;
+ return true;
+}
+
+Dce2Smb2FileTracker::~Dce2Smb2FileTracker(void)
+{
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "file tracker %" PRIu64
+ " file name hash %" PRIu64 " terminating\n", file_id, file_name_hash);
+
+ if (file_name)
+ snort_free((void*)file_name);
+
+ Dce2Smb2SessionDataMap attached_flows = parent_tree->get_parent()->get_attached_flows();
+
+ for (auto it_flow : attached_flows)
+ {
+ FileFlows* file_flows = FileFlows::get_file_flows(it_flow.second->get_flow(), false);
+ if (file_flows)
+ file_flows->remove_processed_file_context(file_name_hash, file_id);
+ it_flow.second->reset_matching_tcp_file_tracker(this);
+ }
+
+ parent_tree->close_file(file_id, false);
+
+ memory::MemoryCap::update_deallocations(sizeof(*this));
+}
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2021 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// dce_smb2_file.h author Dipta Pandit <dipandit@cisco.com>
+
+#ifndef DCE_SMB2_FILE_H
+#define DCE_SMB2_FILE_H
+
+// This provides file tracker for SMBv2
+
+#include "dce_smb2.h"
+
+class Dce2Smb2TreeTracker;
+
+class Dce2Smb2FileTracker
+{
+public:
+
+ Dce2Smb2FileTracker() = delete;
+ Dce2Smb2FileTracker(const Dce2Smb2FileTracker& arg) = delete;
+ Dce2Smb2FileTracker& operator=(const Dce2Smb2FileTracker& arg) = delete;
+
+ Dce2Smb2FileTracker(uint64_t file_idv, Dce2Smb2TreeTracker* p_tree) : ignore(true),
+ file_name_len(0), file_offset(0), file_id(file_idv), file_size(0), file_name_hash(0),
+ file_name(nullptr), direction(FILE_DOWNLOAD), smb2_pdu_state(DCE2_SMB_PDU_STATE__COMMAND),
+ parent_tree(p_tree)
+ {
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+ "file tracker %" PRIu64 " created\n", file_id);
+ memory::MemoryCap::update_allocations(sizeof(*this));
+ }
+
+ ~Dce2Smb2FileTracker();
+ bool process_data(const uint8_t*, uint32_t, uint64_t);
+ bool process_data(const uint8_t*, uint32_t);
+ bool close();
+ void set_info(char*, uint16_t, uint64_t, bool = false);
+ void accept_raw_data_from(Dce2Smb2SessionData*);
+
+ bool accepting_raw_data()
+ { return (smb2_pdu_state == DCE2_SMB_PDU_STATE__RAW_DATA); }
+
+ void set_direction(FileDirection dir) { direction = dir; }
+ Dce2Smb2TreeTracker* get_parent() { return parent_tree; }
+ uint64_t get_file_id() { return file_id; }
+
+private:
+ void file_detect();
+ bool ignore;
+ uint16_t file_name_len;
+ uint64_t file_offset;
+ uint64_t file_id;
+ uint64_t file_size;
+ uint64_t file_name_hash;
+ char* file_name;
+ FileDirection direction;
+ Dce2SmbPduState smb2_pdu_state;
+ Dce2Smb2TreeTracker* parent_tree;
+};
+
+using Dce2Smb2FileTrackerMap =
+ std::unordered_map<uint64_t, Dce2Smb2FileTracker*, std::hash<uint64_t> >;
+
+#endif
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2021 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// dce_smb2_request.h author Bhargava Jandhyala <bjandhya@cisco.com>
+
+#ifndef DCE_SMB2_REQUEST_H
+#define DCE_SMB2_REQUEST_H
+
+// This provides request trackers for SMBv2.
+// Request trackers are used to track CREATE, READ and WRITE requests
+
+#include "dce_smb2.h"
+
+class Dce2Smb2RequestTracker
+{
+public:
+
+ Dce2Smb2RequestTracker() = delete;
+ Dce2Smb2RequestTracker(const Dce2Smb2RequestTracker& arg) = delete;
+ Dce2Smb2RequestTracker& operator=(const Dce2Smb2RequestTracker& arg) = delete;
+
+ Dce2Smb2RequestTracker(uint64_t file_id_v, uint64_t offset_v = 0)
+ : fname(nullptr), fname_len(0), file_id(file_id_v), offset(offset_v)
+ {
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "request tracker created\n");
+ memory::MemoryCap::update_allocations(sizeof(*this));
+ }
+
+ Dce2Smb2RequestTracker(char* fname_v, uint16_t fname_len_v)
+ : fname(fname_v), fname_len(fname_len_v), file_id(0), offset(0)
+ {
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "request tracker created\n");
+ memory::MemoryCap::update_allocations(sizeof(*this));
+ }
+
+ ~Dce2Smb2RequestTracker()
+ {
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "request tracker terminating\n");
+ if (fname)
+ snort_free(fname);
+ memory::MemoryCap::update_deallocations(sizeof(*this));
+ }
+
+ void reset_file_name() { fname = nullptr; fname_len = 0; }
+ uint64_t get_offset() { return offset; }
+ uint64_t get_file_id() { return file_id; }
+ char* get_file_name() { return fname; }
+ uint16_t get_file_name_size() { return fname_len; }
+
+private:
+ char* fname;
+ uint16_t fname_len;
+ uint64_t file_id;
+ uint64_t offset;
+};
+
+using Dce2Smb2RequestTrackerMap =
+ std::unordered_map<uint64_t, Dce2Smb2RequestTracker*, std::hash<uint64_t> >;
+
+#endif
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2021 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// dce_smb2_session.cc author Dipta Pandit <dipandit@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "dce_smb2_session.h"
+
+inline uint32_t Smb2Tid(const Smb2Hdr* hdr)
+{
+ return snort::alignedNtohl(&(((const Smb2SyncHdr*)hdr)->tree_id));
+}
+
+//init must be called when a session tracker is created.
+void Dce2Smb2SessionTracker::init(uint64_t sid,
+ const Smb2SessionKey& session_key_v)
+{
+ session_id = sid;
+ session_key = session_key_v;
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "session tracker %" PRIu64
+ " created\n", session_id);
+}
+
+Dce2Smb2SessionData* Dce2Smb2SessionTracker::get_current_flow()
+{
+ Smb2FlowKey flow_key = get_smb2_flow_key();
+ auto it_flow = attached_flows.find(flow_key);
+ return (it_flow != attached_flows.end()) ? it_flow->second : nullptr;
+}
+
+Dce2Smb2TreeTracker* Dce2Smb2SessionTracker::find_tree_for_message(
+ uint64_t message_id)
+{
+ for (auto it_tree : connected_trees)
+ {
+ Dce2Smb2RequestTracker* request = it_tree.second->find_request(message_id);
+ if (request)
+ return it_tree.second;
+ }
+ return nullptr;
+}
+
+void Dce2Smb2SessionTracker::process(uint16_t command, uint8_t command_type,
+ const Smb2Hdr* smb_header, const uint8_t* end)
+{
+ Dce2Smb2TreeTracker* tree = nullptr;
+ uint32_t tree_id = Smb2Tid(smb_header);
+
+ if (tree_id)
+ {
+ auto it_tree = connected_trees.find(tree_id);
+ if (it_tree != connected_trees.end())
+ tree = it_tree->second;
+ }
+ else
+ {
+ //async response case
+ tree = find_tree_for_message(Smb2Mid(smb_header));
+ }
+
+ switch (command)
+ {
+ case SMB2_COM_TREE_CONNECT:
+ {
+ uint8_t share_type = ((const Smb2TreeConnectResponseHdr*)
+ ((const uint8_t*)smb_header + SMB2_HEADER_LENGTH))->share_type;
+ connect_tree(tree_id, share_type);
+ }
+ break;
+
+ case SMB2_COM_TREE_DISCONNECT:
+ if (tree)
+ {
+ delete tree;
+ connected_trees.erase(tree_id);
+ }
+ else
+ dce2_smb_stats.v2_tree_discn_ignored++;
+ break;
+
+ //for all other cases, tree tracker should handle the command
+ case SMB2_COM_CREATE:
+ if (!tree and SMB2_CMD_TYPE_REQUEST == command_type)
+ {
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+ "%s_REQ: mid-stream session detected\n",
+ smb2_command_string[command]);
+ tree = connect_tree(tree_id);
+ if (!tree)
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+ "%s_REQ: insert tree tracker failed\n",
+ smb2_command_string[command]);
+ }
+ // fallthrough
+ default:
+ if (tree)
+ tree->process(command, command_type, smb_header, end);
+ else
+ {
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+ "%s: tree tracker missing\n", smb2_command_string[command]);
+ dce2_smb_stats.v2_tree_ignored++;
+ }
+ break;
+ }
+}
+
+Dce2Smb2TreeTracker* Dce2Smb2SessionTracker::connect_tree(uint32_t tree_id,
+ uint8_t share_type)
+{
+ Dce2Smb2SessionData* current_flow = get_current_flow();
+ if ((SMB2_SHARE_TYPE_DISK == share_type) and (-1 == current_flow->get_max_file_depth()) and
+ (-1 == current_flow->get_smb_file_depth()))
+ {
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "Not inserting TID (%u) "
+ "because it's not IPC and not inspecting normal file data.\n", tree_id);
+ dce2_smb_stats.v2_tree_cnct_ignored++;
+ return nullptr;
+ }
+ Dce2Smb2TreeTracker* tree = nullptr;
+ auto it_tree = connected_trees.find(tree_id);
+ if (it_tree != connected_trees.end())
+ tree = it_tree->second;
+ if (!tree)
+ {
+ tree = new Dce2Smb2TreeTracker(tree_id, this, share_type);
+ connected_trees.insert(std::make_pair(tree_id, tree));
+ }
+ return tree;
+}
+
+void Dce2Smb2SessionTracker::attach_flow(Smb2FlowKey flow_key,
+ Dce2Smb2SessionData* ssd)
+{
+ attached_flows.insert(std::make_pair(flow_key,ssd));
+}
+
+bool Dce2Smb2SessionTracker::detach_flow(Smb2FlowKey& flow_key)
+{
+ attached_flows.erase(flow_key);
+ return (0 == attached_flows.size());
+}
+
+// Session Tracker is created and destroyed only from session cache
+Dce2Smb2SessionTracker::~Dce2Smb2SessionTracker(void)
+{
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "session tracker %" PRIu64
+ " terminating\n", session_id);
+ auto it_tree = connected_trees.begin();
+ while (it_tree != connected_trees.end())
+ {
+ Dce2Smb2TreeTracker* tree = it_tree->second;
+ it_tree = connected_trees.erase(it_tree);
+ delete tree;
+ }
+
+ for (auto it_flow : attached_flows)
+ it_flow.second->remove_session(session_id);
+
+ memory::MemoryCap::update_deallocations(sizeof(*this));
+}
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2021 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// dce_smb2_session.h author Dipta Pandit <dipandit@cisco.com>
+
+#ifndef DCE_SMB2_SESSION_H
+#define DCE_SMB2_SESSION_H
+
+// This provides session tracker for SMBv2
+
+#include "dce_smb2.h"
+#include "dce_smb2_tree.h"
+
+uint32_t Smb2Tid(const Smb2Hdr* hdr);
+
+class Dce2Smb2SessionTracker
+{
+public:
+ Dce2Smb2SessionTracker()
+ {
+ session_id = 0;
+ session_key = { };
+ memory::MemoryCap::update_allocations(sizeof(*this));
+ }
+
+ ~Dce2Smb2SessionTracker();
+ void init(uint64_t, const Smb2SessionKey&);
+ void attach_flow(Smb2FlowKey, Dce2Smb2SessionData*);
+ bool detach_flow(Smb2FlowKey&);
+ void process(uint16_t, uint8_t, const Smb2Hdr*, const uint8_t*);
+ void disconnect_tree(uint32_t tree_id) { connected_trees.erase(tree_id); }
+ Dce2Smb2SessionData* get_current_flow();
+ Smb2SessionKey get_key() { return session_key; }
+ Dce2Smb2SessionDataMap get_attached_flows() { return attached_flows; }
+ Dce2Smb2TreeTracker* connect_tree(uint32_t, uint8_t=SMB2_SHARE_TYPE_DISK);
+
+private:
+ Dce2Smb2TreeTracker* find_tree_for_message(uint64_t);
+ uint64_t session_id;
+ Smb2SessionKey session_key;
+ Dce2Smb2SessionDataMap attached_flows;
+ Dce2Smb2TreeTrackerMap connected_trees;
+};
+
+#endif
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2021 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// dce_smb2_session_cache.h author Bhargava Jandhyala <bjandhya@cisco.com>
+
+#ifndef DCE_SMB2_SESSION_CACHE_H
+#define DCE_SMB2_SESSION_CACHE_H
+
+// This provides a wrapper over LRU cache shared for SMBv2 Session trackers
+
+#include "hash/lru_cache_shared.h"
+
+#include "dce_smb2_session.h"
+
+#define SMB_AVG_FILES_PER_SESSION 5
+
+template<typename Key, typename Value, typename Hash>
+class Dce2Smb2SharedCache : public LruCacheShared<Key, Value, Hash>
+{
+public:
+ Dce2Smb2SharedCache() = delete;
+ Dce2Smb2SharedCache(const Dce2Smb2SharedCache& arg) = delete;
+ Dce2Smb2SharedCache& operator=(const Dce2Smb2SharedCache& arg) = delete;
+ Dce2Smb2SharedCache(const size_t initial_size) :
+ LruCacheShared<Key, Value, Hash>(initial_size) { }
+ virtual ~Dce2Smb2SharedCache() { }
+
+ Value* find_session(Key key)
+ { return this->find(key).get(); }
+ Value* find_else_create_session(Key key)
+ { return this->find_else_create(key, nullptr).get(); }
+};
+
+using Dce2Smb2SessionCache =
+ Dce2Smb2SharedCache<Smb2SessionKey, Dce2Smb2SessionTracker, Smb2KeyHash>;
+
+extern THREAD_LOCAL Dce2Smb2SessionCache* smb2_session_cache;
+
+inline void DCE2_SmbSessionCacheInit(const size_t cache_size)
+{
+ smb2_session_cache = new Dce2Smb2SessionCache(cache_size);
+}
+
+#endif
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2021 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// dce_smb2_tree.cc author Dipta Pandit <dipandit@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "dce_smb2_tree.h"
+
+#include "dce_smb2_session.h"
+
+using namespace snort;
+
+#define SMB2_CREATE_DURABLE_RECONNECT "DHnC"
+#define SMB2_CREATE_DURABLE_RECONNECT_V2 "DH2C"
+
+uint64_t Smb2Mid(const Smb2Hdr* hdr)
+{
+ return alignedNtohq(&(hdr->message_id));
+}
+
+Dce2Smb2FileTracker* Dce2Smb2TreeTracker::find_file(uint64_t file_id)
+{
+ auto it_file = opened_files.find(file_id);
+ if (it_file != opened_files.end())
+ return it_file->second;
+ return nullptr;
+}
+
+void Dce2Smb2TreeTracker::close_file(uint64_t file_id, bool destroy)
+{
+ auto it_file = opened_files.find(file_id);
+ if (it_file != opened_files.end())
+ {
+ Dce2Smb2FileTracker* file = it_file->second;
+ if (opened_files.erase(file_id) and destroy)
+ delete file;
+ }
+}
+
+Dce2Smb2RequestTracker* Dce2Smb2TreeTracker::find_request(uint64_t message_id)
+{
+ auto request_it = active_requests.find(message_id);
+ return (request_it == active_requests.end()) ?
+ nullptr : request_it->second;
+}
+
+bool Dce2Smb2TreeTracker::remove_request(uint64_t message_id)
+{
+ auto request_it = active_requests.find(message_id);
+ if (request_it != active_requests.end())
+ {
+ delete request_it->second;
+ return active_requests.erase(message_id);
+ }
+ return false;
+}
+
+void Dce2Smb2TreeTracker::process_set_info_request(const Smb2Hdr* smb_header)
+{
+ const uint8_t* smb_data = (const uint8_t*)smb_header + SMB2_HEADER_LENGTH;
+ const Smb2SetInfoRequestHdr* set_info_hdr = (const Smb2SetInfoRequestHdr*)smb_data;
+
+ if (set_info_hdr->file_info_class == SMB2_FILE_ENDOFFILE_INFO)
+ {
+ uint64_t file_size = alignedNtohq((const uint64_t*)((const uint8_t*)
+ set_info_hdr + SMB2_SET_INFO_REQUEST_STRUC_SIZE - 1));
+ uint64_t file_id = alignedNtohq(&(set_info_hdr->fileId_persistent));
+ Dce2Smb2FileTracker* file_tracker = find_file(file_id);
+ if (file_tracker)
+ file_tracker->set_info(nullptr, 0, file_size);
+ else
+ {
+ dce2_smb_stats.v2_stinf_req_ftrkr_misng++;
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "%s_REQ: ftracker missing\n",
+ smb2_command_string[SMB2_COM_SET_INFO]);
+ }
+ }
+ else
+ {
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "%s_REQ: header error\n",
+ smb2_command_string[SMB2_COM_SET_INFO]);
+ dce2_smb_stats.v2_stinf_req_hdr_err++;
+ }
+}
+
+void Dce2Smb2TreeTracker::process_close_request(const Smb2Hdr* smb_header)
+{
+ const uint8_t* smb_data = (const uint8_t*)smb_header + SMB2_HEADER_LENGTH;
+ uint64_t file_id = alignedNtohq(&(((const Smb2CloseRequestHdr*)
+ smb_data)->fileId_persistent));
+ Dce2Smb2FileTracker* file_tracker = find_file(file_id);
+ if (!file_tracker)
+ {
+ dce2_smb_stats.v2_cls_req_ftrkr_misng++;
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "%s_REQ: ftracker missing %" PRIu64 "\n",
+ smb2_command_string[SMB2_COM_CLOSE], file_id);
+ return;
+ }
+ if (file_tracker->close())
+ close_file(file_id);
+}
+
+uint64_t Dce2Smb2TreeTracker::get_durable_file_id(
+ const Smb2CreateRequestHdr* smb_create_hdr, const uint8_t* end)
+{
+ const uint8_t* data = (const uint8_t*)smb_create_hdr +
+ alignedNtohl(&smb_create_hdr->create_contexts_offset) - SMB2_HEADER_LENGTH;
+ uint32_t remaining = alignedNtohl(&smb_create_hdr->create_contexts_length);
+
+ while (remaining > sizeof(Smb2CreateContextHdr) and data < end)
+ {
+ const Smb2CreateContextHdr* context = (const Smb2CreateContextHdr*)data;
+ uint32_t next = alignedNtohl(&context->next);
+ uint16_t name_offset = alignedNtohs(&context->name_offset);
+ uint16_t name_length = alignedNtohs(&context->name_length);
+ uint16_t data_offset = alignedNtohs(&context->data_offset);
+ uint32_t data_length = alignedNtohl(&context->data_length);
+
+ /* Check for general error condition */
+ if (((next & 0x7) != 0) or (next > remaining) or (name_offset != 16) or
+ (name_length != 4) or (name_offset + name_length > remaining) or
+ ((data_offset & 0x7) != 0) or
+ (data_offset and (data_offset < name_offset + name_length)) or
+ (data_offset > remaining) or (data_offset + data_length > remaining))
+ {
+ return 0;
+ }
+
+ if ((strncmp((const char*)context+name_offset,
+ SMB2_CREATE_DURABLE_RECONNECT_V2, name_length) == 0) or
+ (strncmp((const char*)context+name_offset,
+ SMB2_CREATE_DURABLE_RECONNECT, name_length) == 0))
+ {
+ return alignedNtohq((const uint64_t*)(((const uint8_t*)context) +
+ data_offset));
+ }
+
+ if (!next)
+ break;
+
+ data += next;
+ remaining -= next;
+ }
+ return 0;
+}
+
+void Dce2Smb2TreeTracker::process_create_response(uint64_t message_id,
+ const Smb2Hdr* smb_header)
+{
+ const uint8_t* smb_data = (const uint8_t*)smb_header + SMB2_HEADER_LENGTH;
+ const Smb2CreateResponseHdr* create_res_hdr = (const Smb2CreateResponseHdr*)smb_data;
+ uint64_t file_size = 0;
+ uint64_t file_id = alignedNtohq((const uint64_t*)(&(create_res_hdr->fileId_persistent)));
+ if (create_res_hdr->end_of_file)
+ file_size = alignedNtohq((const uint64_t*)(&(create_res_hdr->end_of_file)));
+ if (create_res_hdr->file_attributes & SMB2_CREATE_RESPONSE_DIRECTORY)
+ {
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "%s_RESP: not processing for directory\n",
+ smb2_command_string[SMB2_COM_CREATE]);
+ close_file(file_id);
+ }
+ else
+ {
+ Dce2Smb2RequestTracker* create_request = find_request(message_id);
+ if (create_request)
+ {
+ Dce2Smb2FileTracker* file_tracker = find_file(file_id);
+ if (!file_tracker)
+ {
+ file_tracker = new Dce2Smb2FileTracker(file_id, this);
+ opened_files.insert(std::make_pair(file_id, file_tracker));
+ }
+ file_tracker->set_info(create_request->get_file_name(),
+ create_request->get_file_name_size(), file_size, true);
+ create_request->reset_file_name();
+ }
+ else
+ {
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "%s_RESP: req tracker missing\n",
+ smb2_command_string[SMB2_COM_CREATE]);
+ dce2_smb_stats.v2_crt_rtrkr_misng++;
+ }
+ }
+}
+
+void Dce2Smb2TreeTracker::process_create_request(uint64_t message_id,
+ const Smb2Hdr* smb_header, const uint8_t* end)
+{
+ const uint8_t* smb_data = (const uint8_t*)smb_header + SMB2_HEADER_LENGTH;
+ const Smb2CreateRequestHdr* create_req_hdr = (const Smb2CreateRequestHdr*)smb_data;
+ if (alignedNtohs(&(create_req_hdr->name_offset)) <= SMB2_HEADER_LENGTH)
+ {
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "%s_REQ: name_offset %" PRIu16 "\n",
+ smb2_command_string[SMB2_COM_CREATE], create_req_hdr->name_offset);
+ dce2_smb_stats.v2_crt_req_hdr_err++;
+ return;
+ }
+ const uint8_t* file_name_offset = (const uint8_t*)smb_header +
+ create_req_hdr->name_offset;
+ uint16_t file_name_size = alignedNtohs(&(create_req_hdr->name_length));
+ if (!file_name_size or (file_name_offset >= end) or
+ (file_name_offset + file_name_size > end))
+ {
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+ "%s_REQ: invalid file name data seen with size %" PRIu16 "\n",
+ smb2_command_string[SMB2_COM_CREATE], file_name_size);
+ dce2_smb_stats.v2_crt_inv_file_data++;
+ return;
+ }
+
+ uint16_t name_len = 0;
+ char* file_name = get_smb_file_name(file_name_offset, file_name_size, true, &name_len);
+ //keep a request tracker with the available info
+ Dce2Smb2RequestTracker* create_request = new Dce2Smb2RequestTracker(file_name, name_len);
+ store_request(message_id, create_request);
+ //check if file_id is available form a durable reconnect request.
+ //if present we can create a file tracker right now.
+ //mostly this is the case for compound request.
+ uint64_t file_id = get_durable_file_id(create_req_hdr, end);
+ if (file_id)
+ {
+ Dce2Smb2FileTracker* file_tracker = find_file(file_id);
+ if (!file_tracker)
+ {
+ file_tracker = new Dce2Smb2FileTracker(file_id, this);
+ file_tracker->set_info(file_name, name_len, 0, true);
+ create_request->reset_file_name();
+ opened_files.insert(std::make_pair(file_id, file_tracker));
+ }
+ }
+}
+
+void Dce2Smb2TreeTracker::process_read_response(uint64_t message_id,
+ const Smb2Hdr* smb_header, const uint8_t* end)
+{
+ const uint8_t* smb_data = (const uint8_t*)smb_header + SMB2_HEADER_LENGTH;
+ const Smb2ReadResponseHdr* read_resp_hdr = (const Smb2ReadResponseHdr*)smb_data;
+
+ Dce2Smb2RequestTracker* read_request = find_request(message_id);
+ if (!read_request)
+ {
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+ "SMB2_COM_READ_RESP: request tracker missing\n");
+ dce2_smb_stats.v2_read_rtrkr_misng++;
+ return;
+ }
+ uint16_t data_offset = alignedNtohs((const uint16_t*)(&(read_resp_hdr->data_offset)));
+ Dce2Smb2SessionData* current_flow = parent_session->get_current_flow();
+ if (data_offset + (const uint8_t*)smb_header > end)
+ {
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "SMB2_COM_READ_RESP: bad offset\n");
+ if (current_flow)
+ dce_alert(GID_DCE2, DCE2_SMB_BAD_OFF, (dce2CommonStats*)&dce2_smb_stats,
+ *current_flow->get_dce2_session_data());
+ }
+ Dce2Smb2FileTracker* file_tracker = find_file(read_request->get_file_id());
+ if (file_tracker)
+ {
+ const uint8_t* file_data = (const uint8_t*)read_resp_hdr +
+ SMB2_READ_RESPONSE_STRUC_SIZE - 1;
+ int data_size = end - file_data;
+ if (file_tracker->process_data(file_data, data_size, read_request->get_offset()))
+ {
+ if ((uint32_t)data_size < alignedNtohl((const uint32_t*)&(read_resp_hdr->length)))
+ {
+ file_tracker->accept_raw_data_from(current_flow);
+ }
+ }
+ else
+ close_file(file_tracker->get_file_id());
+ }
+ else
+ {
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+ "SMB2_COM_READ_RESP: file tracker missing\n");
+ }
+}
+
+void Dce2Smb2TreeTracker::process_read_request(uint64_t message_id,
+ const Smb2Hdr* smb_header)
+{
+ const uint8_t* smb_data = (const uint8_t*)smb_header + SMB2_HEADER_LENGTH;
+ const Smb2ReadRequestHdr* read_req_hdr = (const Smb2ReadRequestHdr*)smb_data;
+ uint64_t file_id = alignedNtohq((const uint64_t*)(&(read_req_hdr->fileId_persistent)));
+ uint64_t offset = alignedNtohq((const uint64_t*)(&(read_req_hdr->offset)));
+ Dce2Smb2RequestTracker* read_request = new Dce2Smb2RequestTracker(file_id, offset);
+ store_request(message_id, read_request);
+}
+
+void Dce2Smb2TreeTracker::process_write_request(uint64_t message_id,
+ const Smb2Hdr* smb_header, const uint8_t* end)
+{
+ const uint8_t* smb_data = (const uint8_t*)smb_header + SMB2_HEADER_LENGTH;
+ const Smb2WriteRequestHdr* write_req_hdr = (const Smb2WriteRequestHdr*)smb_data;
+ uint64_t file_id = alignedNtohq((const uint64_t*)(&(write_req_hdr->fileId_persistent)));
+ Dce2Smb2SessionData* current_flow = parent_session->get_current_flow();
+ if ((alignedNtohs((const uint16_t*)(&(write_req_hdr->data_offset))) +
+ (const uint8_t*)smb_header > end) and current_flow)
+ {
+ dce_alert(GID_DCE2, DCE2_SMB_BAD_OFF, (dce2CommonStats*)&dce2_smb_stats,
+ *current_flow->get_dce2_session_data());
+ }
+ //track this request to clean up opened file in case of error response
+ Dce2Smb2RequestTracker* write_request = new Dce2Smb2RequestTracker(file_id);
+ store_request(message_id, write_request);
+ const uint8_t* file_data = (const uint8_t*)write_req_hdr + SMB2_WRITE_REQUEST_STRUC_SIZE - 1;
+ Dce2Smb2FileTracker* file_tracker = find_file(file_id);
+ if (file_tracker)
+ {
+ file_tracker->set_direction(FILE_UPLOAD);
+ int data_size = end - file_data;
+ uint64_t offset = alignedNtohq((const uint64_t*)(&(write_req_hdr->offset)));
+ if (file_tracker->process_data(file_data, data_size, offset))
+ {
+ if ((uint32_t)data_size < alignedNtohl((const uint32_t*)&(write_req_hdr->length)))
+ {
+ file_tracker->accept_raw_data_from(current_flow);
+ }
+ }
+ else
+ close_file(file_tracker->get_file_id());
+ }
+ else
+ {
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+ "SMB2_COM_WRITE_REQ: file tracker missing\n");
+ }
+}
+
+void Dce2Smb2TreeTracker::process(uint16_t command, uint8_t command_type,
+ const Smb2Hdr* smb_header, const uint8_t* end)
+{
+ Dce2Smb2SessionData* current_flow = parent_session->get_current_flow();
+ if (SMB2_CMD_TYPE_REQUEST == command_type and current_flow and
+ active_requests.size() >= current_flow->get_max_outstanding_requests())
+ {
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+ "%s_REQ: max req exceeded\n", smb2_command_string[command]);
+ dce_alert(GID_DCE2, DCE2_SMB_MAX_REQS_EXCEEDED, (dce2CommonStats*)&dce2_smb_stats,
+ *current_flow->get_dce2_session_data());
+
+ return;
+ }
+ uint64_t message_id = Smb2Mid(smb_header);
+
+ switch (command)
+ {
+ case SMB2_COM_CREATE:
+ if (SMB2_CMD_TYPE_ERROR_RESPONSE == command_type)
+ {
+ dce2_smb_stats.v2_crt_err_resp++;
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+ "%s_RESP: error\n", smb2_command_string[command]);
+ }
+ else if (SMB2_CMD_TYPE_REQUEST == command_type)
+ {
+ if (SMB2_SHARE_TYPE_DISK != share_type)
+ {
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET, "%s_REQ:"
+ " ignored for ipc share\n", smb2_command_string[command]);
+ dce2_smb_stats.v2_crt_req_ipc++;
+ return;
+ }
+ process_create_request(message_id, smb_header, end);
+ }
+ else if (SMB2_CMD_TYPE_RESPONSE == command_type)
+ process_create_response(message_id, smb_header);
+ break;
+ case SMB2_COM_CLOSE:
+ process_close_request(smb_header);
+ break;
+ case SMB2_COM_SET_INFO:
+ process_set_info_request(smb_header);
+ break;
+ case SMB2_COM_READ:
+ if (SMB2_CMD_TYPE_ERROR_RESPONSE == command_type)
+ {
+ dce2_smb_stats.v2_read_err_resp++;
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+ "%s_RESP: error\n", smb2_command_string[command]);
+ Dce2Smb2RequestTracker* request = find_request(message_id);
+ if (request)
+ close_file(request->get_file_id());
+ }
+ else if (SMB2_CMD_TYPE_REQUEST == command_type)
+ process_read_request(message_id, smb_header);
+ else if (SMB2_CMD_TYPE_RESPONSE == command_type)
+ process_read_response(message_id, smb_header, end);
+ break;
+ case SMB2_COM_WRITE:
+ if (SMB2_CMD_TYPE_ERROR_RESPONSE == command_type)
+ {
+ dce2_smb_stats.v2_wrt_err_resp++;
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+ "%s_RESP: error\n", smb2_command_string[command]);
+ Dce2Smb2RequestTracker* request = find_request(message_id);
+ if (request)
+ close_file(request->get_file_id());
+ }
+ else if (SMB2_CMD_TYPE_REQUEST == command_type)
+ process_write_request(message_id, smb_header, end);
+ break;
+ }
+ if (SMB2_CMD_TYPE_RESPONSE == command_type or SMB2_CMD_TYPE_ERROR_RESPONSE == command_type)
+ remove_request(message_id);
+}
+
+Dce2Smb2TreeTracker::~Dce2Smb2TreeTracker(void)
+{
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+ "tree tracker %" PRIu32 " terminating\n", tree_id);
+ if (active_requests.size())
+ {
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+ "cleanup pending requests for below MIDs:\n");
+ for (auto it_request : active_requests)
+ {
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+ "mid %" PRIu64 "\n", it_request.first);
+ delete it_request.second;
+ }
+ }
+
+ auto it_file = opened_files.begin();
+ while (it_file != opened_files.end())
+ {
+ Dce2Smb2FileTracker* file = it_file->second;
+ it_file = opened_files.erase(it_file);
+ delete file;
+ }
+ parent_session->disconnect_tree(tree_id);
+ memory::MemoryCap::update_deallocations(sizeof(*this));
+}
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2021 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// dce_smb2_tree.h author Dipta Pandit <dipandit@cisco.com>
+
+#ifndef DCE_SMB2_TREE_H
+#define DCE_SMB2_TREE_H
+
+// This provides tree trackers for SMBv2.
+// Tree trackers are used to identify and track an opened share
+
+#include "dce_smb2.h"
+#include "dce_smb2_file.h"
+#include "dce_smb2_request.h"
+
+uint64_t Smb2Mid(const Smb2Hdr* hdr);
+
+class Dce2Smb2SessionTracker;
+
+class Dce2Smb2TreeTracker
+{
+public:
+ Dce2Smb2TreeTracker() = delete;
+ Dce2Smb2TreeTracker(const Dce2Smb2TreeTracker&) = delete;
+ Dce2Smb2TreeTracker& operator=(const Dce2Smb2TreeTracker&) = delete;
+
+ Dce2Smb2TreeTracker(uint32_t tree_id_v, Dce2Smb2SessionTracker* p_session, uint8_t sharetype)
+ : tree_id(tree_id_v), share_type(sharetype), parent_session(p_session)
+ {
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+ "tree tracker %" PRIu32 " created\n", tree_id);
+ memory::MemoryCap::update_allocations(sizeof(*this));
+ }
+
+ ~Dce2Smb2TreeTracker();
+
+ void open_file(uint64_t);
+ void close_file(uint64_t, bool=true);
+ Dce2Smb2FileTracker* find_file(uint64_t);
+ Dce2Smb2RequestTracker* find_request(uint64_t);
+ void process(uint16_t, uint8_t, const Smb2Hdr*, const uint8_t*);
+ Dce2Smb2SessionTracker* get_parent() { return parent_session; }
+
+private:
+ void process_set_info_request(const Smb2Hdr*);
+ void process_close_request(const Smb2Hdr*);
+ void process_create_response(uint64_t, const Smb2Hdr*);
+ void process_create_request(uint64_t, const Smb2Hdr*, const uint8_t*);
+ void process_read_response(uint64_t, const Smb2Hdr*, const uint8_t*);
+ void process_read_request(uint64_t, const Smb2Hdr*);
+ void process_write_request(uint64_t, const Smb2Hdr*, const uint8_t*);
+ uint64_t get_durable_file_id(const Smb2CreateRequestHdr*, const uint8_t*);
+ bool remove_request(uint64_t);
+ void store_request(uint64_t message_id, Dce2Smb2RequestTracker* request)
+ { active_requests.insert(std::make_pair(message_id, request)); }
+
+ uint32_t tree_id;
+ uint8_t share_type;
+ Dce2Smb2FileTrackerMap opened_files;
+ Dce2Smb2RequestTrackerMap active_requests;
+ Dce2Smb2SessionTracker* parent_session;
+};
+
+using Dce2Smb2TreeTrackerMap =
+ std::unordered_map<uint32_t, Dce2Smb2TreeTracker*, std::hash<uint32_t> >;
+
+#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 "flow/flow_key.h"
-#include "main/snort_debug.h"
-
-using namespace snort;
-
-size_t session_cache_size;
-THREAD_LOCAL SmbSessionCache* smb2_session_cache;
-
-Smb2SidHashKey get_key(uint64_t sid)
-{
- Smb2SidHashKey key;
- Flow* flow = DetectionEngine::get_current_packet()->flow;
- memcpy(key.cip, flow->client_ip.get_ip6_ptr(), 4*sizeof(uint32_t));
- memcpy(key.sip, flow->server_ip.get_ip6_ptr(), 4*sizeof(uint32_t));
- key.sid = sid;
- key.cgroup = flow->client_group;
- key.sgroup = flow->server_group;
- key.asid = flow->key->addressSpaceId;
- key.padding = 0;
- return key;
-}
-
-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);
- stracker->session_key = get_key(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, DetectionEngine::get_current_packet(),
- "Not inserting TID (%u) because it's "
- "not IPC and not inspecting normal file data.\n", tid);
- return nullptr;
- }
-
- DCE2_Smb2TreeTracker* ttracker = str->findTtracker(tid);
- if (!ttracker)
- {
- ttracker = new DCE2_Smb2TreeTracker(tid, share_type);
- str->insertTtracker(tid, ttracker);
- }
-
- return ttracker;
-}
-
-void DCE2_Smb2RemoveAllSession(DCE2_Smb2SsnData* ssd)
-{
- ssd->ftracker_tcp = nullptr;
-
- // iterate over smb sessions for this tcp connection and cleanup its instance from them
- auto all_session_trackers = ssd->session_trackers.get_all_entry();
- for ( auto& h : all_session_trackers )
- {
- ssd->session_trackers.Remove(h.second->session_id); // remove session tracker from this
- // tcp conn
- h.second->removeConnTracker(ssd->flow_key); // remove tcp connection from session tracker
- if (!h.second->getConnTrackerSize()) // if no tcp connection present in session tracker,
- // delete session tracker
- {
- DCE2_SmbSessionCacheRemove(h.second->session_key);
- }
- }
-}
+++ /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"
-
-Smb2SidHashKey get_key(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)
- {
- }
- ~SmbSessionCache_map() override = default;
-};
-
-typedef SmbSessionCache_map<Smb2SidHashKey, DCE2_Smb2SessionTracker, SmbKeyHash> 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(get_key(sid))).get();
-}
-
-inline DCE2_Smb2SessionTracker* DCE2_SmbSessionCacheFindElseCreate(uint64_t sid,
- bool* entry_created)
-{
- return (smb2_session_cache->find_else_create(get_key(sid), entry_created)).get();
-}
-
-inline bool DCE2_SmbSessionCacheRemove(Smb2SidHashKey key)
-{
- return smb2_session_cache->remove(key);
-}
-
-// SMB2 functions for fetching sid, tid, request type and so on.
-inline uint64_t Smb2Sid(const Smb2Hdr* hdr)
-{
- return snort::alignedNtohq(&(((const Smb2SyncHdr*)hdr)->session_id));
-}
-
-inline uint32_t Smb2Tid(const Smb2Hdr* hdr)
-{
- return snort::alignedNtohl(&(((const Smb2SyncHdr*)hdr)->tree_id));
-}
-
-inline uint64_t Smb2Mid(const Smb2Hdr* hdr)
-{
- return snort::alignedNtohq(&(((const Smb2SyncHdr*)hdr)->message_id));
-}
-
-inline bool Smb2Error(const Smb2Hdr* hdr)
-{
- return (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)
-{
- // add ssd in session tracker's tcp trackers database
- stracker->insertConnTracker(ssd->flow_key, ssd);
-
- 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_Smb2SessionTracker* DCE2_Smb2FindElseCreateSid(DCE2_Smb2SsnData*, const uint64_t sid);
-
-DCE2_Ret DCE2_Smb2InitData(DCE2_Smb2SsnData*);
-
-void DCE2_Smb2RemoveAllSession(DCE2_Smb2SsnData* ssd);
-
-#endif
-
dce2_move(nb_ptr, nb_len, 1);
ssd->cur_rtracker->file_name =
- DCE2_SmbGetFileName(nb_ptr, nb_len, SmbUnicode(smb_hdr),
+ get_smb_file_name(nb_ptr, nb_len, SmbUnicode(smb_hdr),
&ssd->cur_rtracker->file_name_size);
}
dce2_move(nb_ptr, nb_len, 1);
ssd->cur_rtracker->file_name =
- DCE2_SmbGetFileName(nb_ptr, nb_len, SmbUnicode(smb_hdr),
+ get_smb_file_name(nb_ptr, nb_len, SmbUnicode(smb_hdr),
&ssd->cur_rtracker->file_name_size);
}
dce2_move(nb_ptr, nb_len, 1);
ssd->cur_rtracker->file_name =
- DCE2_SmbGetFileName(nb_ptr, nb_len, SmbUnicode(smb_hdr),
+ get_smb_file_name(nb_ptr, nb_len, SmbUnicode(smb_hdr),
&ssd->cur_rtracker->file_name_size);
}
if (ssd->cur_rtracker->file_name == nullptr)
{
ssd->cur_rtracker->file_name =
- DCE2_SmbGetFileName(nb_ptr, nb_len, unicode, &ssd->cur_rtracker->file_name_size);
+ get_smb_file_name(nb_ptr, nb_len, unicode, &ssd->cur_rtracker->file_name_size);
}
}
if (ssd->cur_rtracker->file_name == nullptr)
{
ssd->cur_rtracker->file_name =
- DCE2_SmbGetFileName(nb_ptr, file_name_length, unicode,
+ get_smb_file_name(nb_ptr, file_name_length, unicode,
&ssd->cur_rtracker->file_name_size);
}
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2021 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// dce_smb_common.cc author Dipta Pandit <dipandit@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "dce_smb_common.h"
+
+#include "file_api/file_flows.h"
+#include "file_api/file_service.h"
+#include "memory/memory_cap.h"
+
+#include "dce_smb1.h"
+#include "dce_smb2.h"
+
+using namespace snort;
+
+THREAD_LOCAL dce2SmbStats dce2_smb_stats;
+THREAD_LOCAL ProfileStats dce2_smb_pstat_main;
+
+//Dce2SmbFlowData members
+
+unsigned Dce2SmbFlowData::inspector_id = 0;
+
+Dce2SmbFlowData::Dce2SmbFlowData(Dce2SmbSessionData* ssd_v) : FlowData(inspector_id)
+{
+ dce2_smb_stats.concurrent_sessions++;
+ if (dce2_smb_stats.max_concurrent_sessions < dce2_smb_stats.concurrent_sessions)
+ dce2_smb_stats.max_concurrent_sessions = dce2_smb_stats.concurrent_sessions;
+ ssd = ssd_v;
+ memory::MemoryCap::update_allocations(sizeof(*this));
+}
+
+Dce2SmbSessionData* Dce2SmbFlowData::upgrade(const Packet* p)
+{
+ dce2SmbProtoConf* config =
+ (dce2SmbProtoConf*)ssd->get_dce2_session_data()->config;
+ delete ssd;
+ ssd = new Dce2Smb2SessionData(p, config);
+ return ssd;
+}
+
+void Dce2SmbFlowData::handle_retransmit(Packet* p)
+{
+ FilePosition position = get_file_position(p);
+ if (!(SNORT_FILE_FULL == position or SNORT_FILE_END == position))
+ return;
+ FileContext* context = get_smb_file_context(p);
+ FileVerdict verdict = context ? context->verdict : FILE_VERDICT_UNKNOWN;
+ ssd->handle_retransmit(position, verdict);
+}
+
+Dce2SmbFlowData::~Dce2SmbFlowData()
+{
+ delete ssd;
+ assert(dce2_smb_stats.concurrent_sessions > 0);
+ dce2_smb_stats.concurrent_sessions--;
+ memory::MemoryCap::update_deallocations(sizeof(*this));
+}
+
+//Dce2SmbSessionData members
+
+Dce2SmbSessionData::Dce2SmbSessionData(const Packet* p,
+ const dce2SmbProtoConf* config)
+{
+ sd = { };
+ policy = { };
+ tcp_flow = p->flow;
+ DCE2_ResetRopts(&sd, p);
+ sd.trans = DCE2_TRANS_TYPE__SMB;
+ sd.server_policy = config->common.policy;
+ sd.client_policy = DCE2_POLICY__WINXP;
+ sd.config = (void*)config;
+ dialect_index = DCE2_SENTINEL;
+ max_file_depth = FileService::get_max_file_depth();
+ dce2_smb_stats.smb_sessions++;
+}
+
+//Helper functions
+
+static inline DCE2_SmbVersion get_smb_version(const Packet* p)
+{
+ // Only check reassembled SMB2 packet
+ if ( p->has_paf_payload() and
+ (p->dsize > sizeof(NbssHdr) + DCE2_SMB_ID_SIZE))
+ {
+ const SmbNtHdr* smb_hdr = (const SmbNtHdr*)(p->data + sizeof(NbssHdr));
+ uint32_t smb_version_id = SmbId(smb_hdr);
+
+ if (smb_version_id == DCE2_SMB_ID)
+ return DCE2_SMB_VERSION_1;
+ else if (smb_version_id == DCE2_SMB2_ID)
+ return DCE2_SMB_VERSION_2;
+ }
+
+ return DCE2_SMB_VERSION_NULL;
+}
+
+Dce2SmbSessionData* create_new_smb_session(const Packet* p,
+ dce2SmbProtoConf* config)
+{
+ DCE2_SmbVersion smb_version = get_smb_version(p);
+
+ if (DCE2_SMB_VERSION_NULL == smb_version)
+ return nullptr;
+
+ Dce2SmbSessionData* ssd = (DCE2_SMB_VERSION_1 == smb_version) ?
+ (Dce2SmbSessionData*)new Dce2Smb1SessionData(p, config) :
+ (Dce2SmbSessionData*)new Dce2Smb2SessionData(p, config);
+
+ Dce2SmbFlowData* flow_data = new Dce2SmbFlowData(ssd);
+ p->flow->set_flow_data(flow_data);
+
+ return ssd;
+}
+
+DCE2_SsnData* get_dce2_session_data(snort::Flow* flow)
+{
+ Dce2SmbFlowData* fd = (Dce2SmbFlowData*)flow->get_flow_data(Dce2SmbFlowData::inspector_id);
+ return fd ? fd->get_smb_session_data()->get_dce2_session_data() : nullptr;
+}
+
+inline FileContext* get_smb_file_context(const Packet* p)
+{
+ FileFlows* file_flows = FileFlows::get_file_flows(p->flow);
+ return file_flows ? file_flows->get_current_file_context() : nullptr;
+}
+
+FileContext* get_smb_file_context(uint64_t file_id,
+ uint64_t multi_file_processing_id, bool to_create)
+{
+ 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, to_create, multi_file_processing_id);
+}
+
+char* get_smb_file_name(const uint8_t* data, uint32_t data_len, bool unicode,
+ uint16_t* file_name_len)
+{
+ const uint8_t inc = unicode ? 2 : 1;
+ if (data_len < inc)
+ return nullptr;
+
+ const uint32_t max_len = unicode ? data_len - 1 : data_len;
+ // Move forward. Don't know if the end of data is actually
+ // the end of the string.
+ uint32_t i;
+ for (i = 0; i < max_len; i += inc)
+ {
+ uint16_t uchar = unicode ? extract_16bits(data + i) : data[i];
+ if (uchar == 0)
+ break;
+ }
+
+ char* fname = nullptr;
+ const uint32_t real_len = i;
+
+ if (unicode)
+ {
+ fname = (char*)snort_calloc(real_len + UTF_16_LE_BOM_LEN + 2);
+ memcpy(fname, UTF_16_LE_BOM, UTF_16_LE_BOM_LEN);//Prepend with BOM
+ memcpy(fname + UTF_16_LE_BOM_LEN, data, real_len);
+ *file_name_len = real_len + UTF_16_LE_BOM_LEN;
+ }
+ else
+ {
+ fname = (char*)snort_alloc(real_len + 1);
+ memcpy(fname, data, real_len);
+ fname[real_len] = 0;
+ *file_name_len = real_len;
+ }
+ return fname;
+}
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2021 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// dce_smb_common.h author Dipta Pandit <dipandit@cisco.com>
+
+#ifndef DCE_SMB_COMMON_H
+#define DCE_SMB_COMMON_H
+
+// This provides SMB flow data and base class for SMB session data
+// Also provides common functions used by both versions
+
+#include "file_api/file_api.h"
+#include "main/snort_debug.h"
+#include "protocols/packet.h"
+#include "profiler/profiler_defs.h"
+
+#include "dce_common.h"
+#include "dce_smb_module.h"
+#include "smb_common.h"
+
+#define DCE2_SMB_NAME "dce_smb"
+#define DCE2_SMB_HELP "dce over smb inspection"
+
+#define DCE2_SMB_ID 0xff534d42 /* \xffSMB */
+#define DCE2_SMB2_ID 0xfe534d42 /* \xfeSMB */
+#define DCE2_SMB_ID_SIZE 4
+
+#define SMB_DEFAULT_MAX_CREDIT 8192
+#define SMB_DEFAULT_MEMCAP 8388608
+#define SMB_DEFAULT_MAX_COMPOUND_REQ 3
+
+#define DCE2_SMB_RPKT_TYPE_MAX 4
+#define DCE2_SMB_RPKT_TYPE_START 1
+
+#define DCE2_SMB_BAD_NBSS_TYPE 2
+#define DCE2_SMB_BAD_TYPE 3
+#define DCE2_SMB_BAD_ID 4
+#define DCE2_SMB_BAD_WCT 5
+#define DCE2_SMB_BAD_BCC 6
+#define DCE2_SMB_BAD_FORM 7
+#define DCE2_SMB_BAD_OFF 8
+#define DCE2_SMB_TDCNT_ZE 9
+#define DCE2_SMB_NB_LT_SMBHDR 10
+#define DCE2_SMB_NB_LT_COM 11
+#define DCE2_SMB_NB_LT_BCC 12
+#define DCE2_SMB_NB_LT_DSIZE 13
+#define DCE2_SMB_TDCNT_LT_DSIZE 14
+#define DCE2_SMB_DSENT_GT_TDCNT 15
+#define DCE2_SMB_BCC_LT_DSIZE 16
+#define DCE2_SMB_INVALID_DSIZE 17
+#define DCE2_SMB_EXCESSIVE_TREE_CONNECTS 18
+#define DCE2_SMB_EXCESSIVE_READS 19
+#define DCE2_SMB_EXCESSIVE_CHAINING 20
+#define DCE2_SMB_MULT_CHAIN_SS 21
+#define DCE2_SMB_MULT_CHAIN_TC 22
+#define DCE2_SMB_CHAIN_SS_LOGOFF 23
+#define DCE2_SMB_CHAIN_TC_TDIS 24
+#define DCE2_SMB_CHAIN_OPEN_CLOSE 25
+#define DCE2_SMB_INVALID_SHARE 26
+
+#define DCE2_SMB_V1 44
+#define DCE2_SMB_V2 45
+#define DCE2_SMB_INVALID_BINDING 46
+#define DCE2_SMB2_EXCESSIVE_COMPOUNDING 47
+#define DCE2_SMB_DCNT_ZERO 48
+#define DCE2_SMB_DCNT_MISMATCH 49
+#define DCE2_SMB_MAX_REQS_EXCEEDED 50
+#define DCE2_SMB_REQS_SAME_MID 51
+#define DCE2_SMB_DEPR_DIALECT_NEGOTIATED 52
+#define DCE2_SMB_DEPR_COMMAND_USED 53
+#define DCE2_SMB_UNUSUAL_COMMAND_USED 54
+#define DCE2_SMB_INVALID_SETUP_COUNT 55
+#define DCE2_SMB_MULTIPLE_NEGOTIATIONS 56
+#define DCE2_SMB_EVASIVE_FILE_ATTRS 57
+#define DCE2_SMB_INVALID_FILE_OFFSET 58
+#define DCE2_SMB_BAD_NEXT_COMMAND_OFFSET 59
+
+struct dce2SmbStats
+{
+ PegCount events;
+
+ PegCount co_pdus;
+ PegCount co_bind;
+ PegCount co_bind_ack;
+ PegCount co_alter_ctx;
+ PegCount co_alter_ctx_resp;
+ PegCount co_bind_nack;
+ PegCount co_request;
+ PegCount co_response;
+ PegCount co_cancel;
+ PegCount co_orphaned;
+ PegCount co_fault;
+ PegCount co_auth3;
+ PegCount co_shutdown;
+ PegCount co_reject;
+ PegCount co_ms_pdu;
+ PegCount co_other_req;
+ PegCount co_other_resp;
+ PegCount co_req_fragments;
+ PegCount co_resp_fragments;
+ PegCount co_cli_max_frag_size;
+ PegCount co_cli_min_frag_size;
+ PegCount co_cli_seg_reassembled;
+ PegCount co_cli_frag_reassembled;
+ PegCount co_srv_max_frag_size;
+ PegCount co_srv_min_frag_size;
+ PegCount co_srv_seg_reassembled;
+ PegCount co_srv_frag_reassembled;
+
+ PegCount smb_sessions;
+ PegCount smb_pkts;
+ PegCount smb_ignored_bytes;
+ PegCount smb_cli_seg_reassembled;
+ PegCount smb_srv_seg_reassembled;
+ PegCount smb_max_outstanding_requests;
+ // FIXIT-M more peg count foo
+ /*uint64_t smb_com_stats[2][SMB_MAX_NUM_COMS];
+ uint64_t smb_chained_stats[2][SMB_ANDX_COM__MAX][SMB_MAX_NUM_COMS];
+ // The +1 is for codes beyond the range of the highest valid subcommand code
+ // Indicates a bogus subcommand
+ uint64_t smb_trans_subcom_stats[2][TRANS_SUBCOM_MAX+1];
+ uint64_t smb_trans2_subcom_stats[2][TRANS2_SUBCOM_MAX+1];
+ uint64_t smb_nt_transact_subcom_stats[2][NT_TRANSACT_SUBCOM_MAX+1];
+ */
+ PegCount smb_files_processed;
+ /* SMB2 stats */
+ PegCount v2_setup;
+ PegCount v2_setup_err_resp;
+ PegCount v2_setup_inv_str_sz;
+ PegCount v2_setup_resp_hdr_err;
+ PegCount v2_tree_cnct;
+ PegCount v2_tree_cnct_err_resp;
+ PegCount v2_tree_cnct_ignored;
+ PegCount v2_tree_cnct_inv_str_sz;
+ PegCount v2_tree_cnct_resp_hdr_err;
+ PegCount v2_crt;
+ PegCount v2_crt_err_resp;
+ PegCount v2_crt_inv_file_data;
+ PegCount v2_crt_inv_str_sz;
+ PegCount v2_crt_resp_hdr_err;
+ PegCount v2_crt_req_hdr_err;
+ PegCount v2_crt_rtrkr_misng;
+ PegCount v2_crt_req_ipc;
+ PegCount v2_crt_tree_trkr_misng;
+ PegCount v2_wrt;
+ PegCount v2_wrt_err_resp;
+ PegCount v2_wrt_inv_str_sz;
+ PegCount v2_wrt_req_hdr_err;
+ PegCount v2_wrt_resp_hdr_err;
+ PegCount v2_read;
+ PegCount v2_read_err_resp;
+ PegCount v2_read_inv_str_sz;
+ PegCount v2_read_rtrkr_misng;
+ PegCount v2_read_resp_hdr_err;
+ PegCount v2_read_req_hdr_err;
+ PegCount v2_setinfo;
+ PegCount v2_stinf_err_resp;
+ PegCount v2_stinf_inv_str_sz;
+ PegCount v2_stinf_req_ftrkr_misng;
+ PegCount v2_stinf_req_hdr_err;
+ PegCount v2_cls;
+ PegCount v2_cls_err_resp;
+ PegCount v2_cls_inv_str_sz;
+ PegCount v2_cls_req_ftrkr_misng;
+ PegCount v2_cls_req_hdr_err;
+ PegCount v2_tree_discn;
+ PegCount v2_tree_discn_ignored;
+ PegCount v2_tree_discn_inv_str_sz;
+ PegCount v2_tree_discn_req_hdr_err;
+ PegCount v2_logoff;
+ PegCount v2_logoff_inv_str_sz;
+ PegCount v2_hdr_err;
+ PegCount v2_bad_next_cmd_offset;
+ PegCount v2_inv_file_ctx_err;
+ PegCount v2_msgs_uninspected;
+ PegCount v2_cmpnd_req_lt_crossed;
+ PegCount v2_tree_ignored;
+ PegCount v2_session_ignored;
+ PegCount concurrent_sessions;
+ PegCount max_concurrent_sessions;
+};
+
+enum DCE2_SmbVersion
+{
+ DCE2_SMB_VERSION_NULL,
+ DCE2_SMB_VERSION_1,
+ DCE2_SMB_VERSION_2
+};
+
+enum Dce2SmbPduState
+{
+ DCE2_SMB_PDU_STATE__COMMAND,
+ DCE2_SMB_PDU_STATE__RAW_DATA
+};
+
+extern THREAD_LOCAL dce2SmbStats dce2_smb_stats;
+extern THREAD_LOCAL snort::ProfileStats dce2_smb_pstat_main;
+
+class Dce2SmbSessionData
+{
+public:
+ Dce2SmbSessionData() = delete;
+ Dce2SmbSessionData(const snort::Packet*, const dce2SmbProtoConf*);
+ virtual ~Dce2SmbSessionData() { }
+
+ virtual void process() = 0;
+ virtual void handle_retransmit(FilePosition, FileVerdict) = 0;
+
+ DCE2_SsnData* get_dce2_session_data()
+ { return &sd; }
+
+ snort::Flow* get_flow()
+ { return tcp_flow; }
+
+ int64_t get_max_file_depth()
+ { return max_file_depth; }
+
+ uint16_t get_max_outstanding_requests()
+ {
+ return sd.config ? ((dce2SmbProtoConf*)sd.config)->smb_max_credit :
+ SMB_DEFAULT_MAX_CREDIT;
+ }
+
+ int64_t get_smb_file_depth()
+ {
+ return ((dce2SmbProtoConf*)sd.config)->smb_file_depth;
+ }
+
+ uint16_t get_smb_max_compound()
+ {
+ return sd.config ? ((dce2SmbProtoConf*)sd.config)->smb_max_compound :
+ SMB_DEFAULT_MAX_COMPOUND_REQ;
+ }
+
+protected:
+ DCE2_SsnData sd;
+ DCE2_Policy policy;
+ int64_t max_file_depth;
+ int dialect_index;
+ snort::Flow* tcp_flow;
+};
+
+class Dce2SmbFlowData : public snort::FlowData
+{
+public:
+ Dce2SmbFlowData(Dce2SmbSessionData*);
+ ~Dce2SmbFlowData() override;
+
+ static void init()
+ { inspector_id = snort::FlowData::create_flow_data_id(); }
+
+ size_t size_of() override
+ { return sizeof(*this); }
+
+ Dce2SmbSessionData* get_smb_session_data()
+ { return ssd; }
+
+ Dce2SmbSessionData* upgrade(const snort::Packet*);
+ void handle_retransmit(snort::Packet*) override;
+
+public:
+ static unsigned inspector_id;
+
+private:
+ Dce2SmbSessionData* ssd;
+};
+
+Dce2SmbSessionData* create_new_smb_session(const snort::Packet*, dce2SmbProtoConf*);
+DCE2_SsnData* get_dce2_session_data(snort::Flow*);
+snort::FileContext* get_smb_file_context(const snort::Packet*);
+snort::FileContext* get_smb_file_context(uint64_t, uint64_t, bool);
+char* get_smb_file_name(const uint8_t*, uint32_t, bool, uint16_t*);
+
+#endif
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2021 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// dce_smb_inspector.h author Dipta Pandit <dipandit@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "dce_smb_inspector.h"
+
+#include "dce_smb_common.h"
+#include "dce_smb_module.h"
+#include "dce_smb_utils.h"
+#include "dce_smb2_session_cache.h"
+
+using namespace snort;
+
+Dce2Smb::Dce2Smb(const dce2SmbProtoConf& pc)
+{
+ config = pc;
+}
+
+Dce2Smb::~Dce2Smb()
+{
+ if (config.smb_invalid_shares)
+ {
+ DCE2_ListDestroy(config.smb_invalid_shares);
+ }
+}
+
+void Dce2Smb::show(const SnortConfig*) const
+{
+ print_dce2_smb_conf(config);
+}
+
+void Dce2Smb::eval(Packet* p)
+{
+ Profile profile(dce2_smb_pstat_main);
+
+ assert(p->has_tcp_data());
+ assert(p->flow);
+
+ Dce2SmbFlowData* smb_flowdata =
+ (Dce2SmbFlowData*)p->flow->get_flow_data(Dce2SmbFlowData::inspector_id);
+
+ Dce2SmbSessionData* smb_session_data;
+ if (smb_flowdata)
+ smb_session_data = smb_flowdata->get_smb_session_data();
+ else
+ smb_session_data = create_new_smb_session(p, &config);
+
+ if (smb_session_data)
+ {
+ dce2_detected = 0;
+ p->packet_flags |= PKT_ALLOW_MULTIPLE_DETECT;
+ p->endianness = new DceEndianness();
+
+ smb_session_data->process();
+
+ //smb_session_data may not be valid anymore in case of upgrade
+ //but flow will always have updated session
+ if (!dce2_detected)
+ DCE2_Detect(get_dce2_session_data(p->flow));
+
+ delete(p->endianness);
+ p->endianness = nullptr;
+ }
+ else
+ debug_logf(dce_smb_trace, p, "non-smb packet detected\n");
+}
+
+void Dce2Smb::clear(Packet* p)
+{
+ DCE2_SsnData* sd = get_dce2_session_data(p->flow);
+ if (sd)
+ DCE2_ResetRopts(sd, p);
+}
+
+//-------------------------------------------------------------------------
+// api stuff
+//-------------------------------------------------------------------------
+
+size_t session_cache_size;
+
+static Module* mod_ctor()
+{
+ return new Dce2SmbModule;
+}
+
+static void mod_dtor(Module* m)
+{
+ delete m;
+}
+
+static void dce2_smb_init()
+{
+ Dce2SmbFlowData::init();
+ DCE2_SmbInitGlobals();
+ DCE2_SmbInitDeletePdu();
+ DceContextData::init(DCE2_TRANS_TYPE__SMB);
+}
+
+static void dce2_smb_thread_int()
+{
+ DCE2_SmbSessionCacheInit(session_cache_size);
+}
+
+static void dce_smb_thread_term()
+{
+ delete smb2_session_cache;
+}
+
+static size_t get_max_smb_session(dce2SmbProtoConf* config)
+{
+ size_t smb_sess_storage_req = (sizeof(Dce2Smb2SessionTracker) +
+ sizeof(Dce2Smb2TreeTracker) + sizeof(Dce2Smb2RequestTracker) +
+ (sizeof(Dce2Smb2FileTracker) * SMB_AVG_FILES_PER_SESSION));
+
+ size_t max_smb_mem = DCE2_ScSmbMemcap(config);
+
+ return (max_smb_mem/smb_sess_storage_req);
+}
+
+static Inspector* dce2_smb_ctor(Module* m)
+{
+ Dce2SmbModule* mod = (Dce2SmbModule*)m;
+ dce2SmbProtoConf config;
+ mod->get_data(config);
+ session_cache_size = get_max_smb_session(&config);
+ return new Dce2Smb(config);
+}
+
+static void dce2_smb_dtor(Inspector* p)
+{
+ delete p;
+}
+
+const InspectApi dce2_smb_api =
+{
+ {
+ PT_INSPECTOR,
+ sizeof(InspectApi),
+ INSAPI_VERSION,
+ 0,
+ API_RESERVED,
+ API_OPTIONS,
+ DCE2_SMB_NAME,
+ DCE2_SMB_HELP,
+ mod_ctor,
+ mod_dtor
+ },
+ IT_SERVICE,
+ PROTO_BIT__PDU,
+ nullptr, // buffers
+ "netbios-ssn",
+ dce2_smb_init,
+ nullptr, // pterm
+ dce2_smb_thread_int, // tinit
+ dce_smb_thread_term, // tterm
+ dce2_smb_ctor,
+ dce2_smb_dtor,
+ nullptr, // ssn
+ nullptr // reset
+};
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2021 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// dce_smb_inspector.h author Dipta Pandit <dipandit@cisco.com>
+
+#ifndef DCE_SMB_INSPECTOR_H
+#define DCE_SMB_INSPECTOR_H
+
+#include "managers/inspector_manager.h"
+
+#include "dce_smb_module.h"
+#include "dce_smb_paf.h"
+
+class Dce2Smb : public snort::Inspector
+{
+public:
+ Dce2Smb(const dce2SmbProtoConf&);
+ ~Dce2Smb() override;
+
+ void show(const snort::SnortConfig*) const override;
+ void eval(snort::Packet*) override;
+ void clear(snort::Packet*) override;
+
+ snort::StreamSplitter* get_splitter(bool c2s) override
+ { return new Dce2SmbSplitter(c2s); }
+
+ bool can_carve_files() const override
+ { return true; }
+
+private:
+ dce2SmbProtoConf config;
+};
+
+#endif
+
#include "trace/trace.h"
#include "utils/util.h"
-#include "dce_smb.h"
+#include "dce_smb_common.h"
using namespace snort;
using namespace std;
{ CountType::SUM, "max_outstanding_requests", "total smb maximum outstanding requests" },
{ CountType::SUM, "files_processed", "total smb files processed" },
{ CountType::SUM, "v2_setup", "total number of SMBv2 setup packets seen" },
- { CountType::SUM, "v2_setup_err_resp", "total number of SMBv2 setup error response packets seen" },
+ { CountType::SUM, "v2_setup_err_resp",
+ "total number of SMBv2 setup error response packets seen" },
{ CountType::SUM, "v2_setup_inv_str_sz",
"total number of SMBv2 setup packets seen with invalid structure size" },
{ CountType::SUM, "v2_setup_resp_hdr_err",
{ 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_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" },
+ "total number of SMBv2 create response packets ignored due to corrupted header" },
{ CountType::SUM, "v2_crt_req_hdr_err",
- "total number of SMBv2 create request packets ignored due to corrupted header" },
+ "total number of SMBv2 create request packets ignored due to corrupted header" },
{ CountType::SUM, "v2_crt_rtrkr_misng",
"total number of SMBv2 create response packets ignored due to missing create request tracker" },
{ CountType::SUM, "v2_crt_req_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_err_resp",
+ "total number of SMBv2 write error response packets seen" },
{ 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_wrt_resp_hdr_err",
+ "total number of SMBv2 write response 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_err_resp",
+ "total number of SMBv2 read error response packets seen" },
{ 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 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_setinfo", "total number of SMBv2 set info packets seen" },
+ { CountType::SUM, "v2_stinf_err_resp",
+ "total number of SMBv2 set info error response packets seen" },
{ CountType::SUM, "v2_stinf_inv_str_sz",
"total number of SMBv2 set info packets seen with invalid structure size" },
{ CountType::SUM, "v2_stinf_req_ftrkr_misng",
{ 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_err_resp",
+ "total number of SMBv2 close error response packets seen" },
{ 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",
{ 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::SUM, "v2_tree_ignored",
+ "total number of packets ignored due to missing tree tracker" },
+ { CountType::SUM, "v2_session_ignored",
+ "total number of packets ignored due to missing session tracker" },
{ CountType::NOW, "concurrent_sessions", "total concurrent sessions" },
{ CountType::MAX, "max_concurrent_sessions", "maximum concurrent sessions" },
{ CountType::END, nullptr, nullptr }
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);
-
}
#ifndef DCE_SMB_MODULE_H
#define DCE_SMB_MODULE_H
-#include "dce_common.h"
#include "framework/module.h"
+
+#include "dce_common.h"
#include "dce_list.h"
namespace snort
#define DCE2_VALID_SMB_VERSION_FLAG_V1 1
#define DCE2_VALID_SMB_VERSION_FLAG_V2 2
+#define DCE2_SMB_BAD_NBSS_TYPE_STR "SMB - bad NetBIOS session service session type"
+#define DCE2_SMB_BAD_TYPE_STR "SMB - bad SMB message type"
+#define DCE2_SMB_BAD_ID_STR "SMB - bad SMB Id (not \\xffSMB for SMB1 or not \\xfeSMB for SMB2)"
+#define DCE2_SMB_BAD_WCT_STR "SMB - bad word count or structure size"
+#define DCE2_SMB_BAD_BCC_STR "SMB - bad byte count"
+#define DCE2_SMB_BAD_FORM_STR "SMB - bad format type"
+#define DCE2_SMB_BAD_OFF_STR "SMB - bad offset"
+#define DCE2_SMB_TDCNT_ZE_STR "SMB - zero total data count"
+#define DCE2_SMB_NB_LT_SMBHDR_STR "SMB - NetBIOS data length less than SMB header length"
+#define DCE2_SMB_NB_LT_COM_STR "SMB - remaining NetBIOS data length less than command length"
+#define DCE2_SMB_NB_LT_BCC_STR "SMB - remaining NetBIOS data length less than command byte count"
+#define DCE2_SMB_NB_LT_DSIZE_STR \
+ "SMB - remaining NetBIOS data length less than command data size"
+#define DCE2_SMB_TDCNT_LT_DSIZE_STR \
+ "SMB - remaining total data count less than this command data size"
+#define DCE2_SMB_DSENT_GT_TDCNT_STR \
+ "SMB - total data sent (STDu64) greater than command total data expected"
+#define DCE2_SMB_BCC_LT_DSIZE_STR "SMB - byte count less than command data size (STDu64)"
+#define DCE2_SMB_INVALID_DSIZE_STR "SMB - invalid command data size for byte count"
+#define DCE2_SMB_EXCESSIVE_TREE_CONNECTS_STR \
+ "SMB - excessive tree connect requests with pending tree connect responses"
+#define DCE2_SMB_EXCESSIVE_READS_STR "SMB - excessive read requests with pending read responses"
+#define DCE2_SMB_EXCESSIVE_CHAINING_STR "SMB - excessive command chaining"
+#define DCE2_SMB_MULT_CHAIN_SS_STR "SMB - multiple chained tree connect requests"
+#define DCE2_SMB_MULT_CHAIN_TC_STR "SMB - multiple chained tree connect requests"
+#define DCE2_SMB_CHAIN_SS_LOGOFF_STR "SMB - chained/compounded login followed by logoff"
+#define DCE2_SMB_CHAIN_TC_TDIS_STR \
+ "SMB - chained/compounded tree connect followed by tree disconnect"
+#define DCE2_SMB_CHAIN_OPEN_CLOSE_STR \
+ "SMB - chained/compounded open pipe followed by close pipe"
+#define DCE2_SMB_INVALID_SHARE_STR "SMB - invalid share access"
+
+#define DCE2_SMB_V1_STR "SMB - invalid SMB version 1 seen"
+#define DCE2_SMB_V2_STR "SMB - invalid SMB version 2 seen"
+#define DCE2_SMB_INVALID_BINDING_STR "SMB - invalid user, tree connect, file binding"
+#define DCE2_SMB2_EXCESSIVE_COMPOUNDING_STR "SMB - excessive command compounding"
+#define DCE2_SMB_DCNT_ZERO_STR "SMB - zero data count"
+#define DCE2_SMB_DCNT_MISMATCH_STR "SMB - data count mismatch in command and format"
+#define DCE2_SMB_MAX_REQS_EXCEEDED_STR "SMB - maximum number of outstanding requests exceeded"
+#define DCE2_SMB_REQS_SAME_MID_STR "SMB - outstanding requests with same MID"
+#define DCE2_SMB_DEPR_DIALECT_NEGOTIATED_STR "SMB - deprecated dialect negotiated"
+#define DCE2_SMB_DEPR_COMMAND_USED_STR "SMB - deprecated command used"
+#define DCE2_SMB_UNUSUAL_COMMAND_USED_STR "SMB - unusual command used"
+#define DCE2_SMB_INVALID_SETUP_COUNT_STR "SMB - invalid setup count for command"
+#define DCE2_SMB_MULTIPLE_NEGOTIATIONS_STR \
+ "SMB - client attempted multiple dialect negotiations on session"
+#define DCE2_SMB_EVASIVE_FILE_ATTRS_STR \
+ "SMB - client attempted to create or set a file's attributes to readonly/hidden/system"
+#define DCE2_SMB_INVALID_FILE_OFFSET_STR \
+ "SMB - file offset provided is greater than file size specified"
+#define DCE2_SMB_BAD_NEXT_COMMAND_OFFSET_STR \
+ "SMB - next command specified in SMB2 header is beyond payload boundary"
+
enum dce2SmbFingerprintPolicy
{
DCE2_SMB_FINGERPRINT_POLICY_NONE = 0,
#include "dce_smb_paf.h"
-#include "dce_smb.h"
+#include "dce_smb_common.h"
namespace
{
* junk states, header type must be Session Message.
*
*********************************************************************/
-static inline bool DCE2_PafSmbIsValidNetbiosHdr(uint32_t nb_hdr, bool junk, const SmbNtHdr* nt_hdr,
- uint32_t* nb_len)
+static inline bool DCE2_PafSmbIsValidNetbiosHdr(uint32_t nb_hdr, bool junk,
+ const SmbNtHdr* nt_hdr, uint32_t* nb_len)
{
uint8_t type = (uint8_t)(nb_hdr >> 24);
uint8_t bit = (uint8_t)((nb_hdr & 0x00ff0000) >> 16);
//See [MS-SMB] 2.1 Transport. There is no such limit for SMB2 or SMB3
if (smb_id == DCE2_SMB_ID)
{
- if ((bit != 0x00) && (bit != 0x01))
+ if ((bit != 0x00) and (bit != 0x01))
return false;
}
nbs_hdr = htonl(nb_hdr);
* state 7 until this is the case.
*
*********************************************************************/
-static StreamSplitter::Status dce2_smb_paf(DCE2_PafSmbData* ss, Flow* flow, const uint8_t* data,
- uint32_t len, uint32_t, uint32_t* fp)
+static StreamSplitter::Status dce2_smb_paf(DCE2_PafSmbData* ss, Flow* flow,
+ const uint8_t* data, uint32_t len, uint32_t, uint32_t* fp)
{
uint32_t n = 0;
StreamSplitter::Status ps = StreamSplitter::SEARCH;
dce2_move(param_ptr, param_len, pad);
ssd->cur_rtracker->file_name =
- DCE2_SmbGetFileName(param_ptr, file_name_length, unicode, &ssd->cur_rtracker->file_name_size);
+ get_smb_file_name(param_ptr, file_name_length, unicode, &ssd->cur_rtracker->file_name_size);
return DCE2_RET__SUCCESS;
}
dce2_move(param_ptr, param_len, sizeof(SmbTrans2Open2ReqParams));
ssd->cur_rtracker->file_name =
- DCE2_SmbGetFileName(param_ptr, param_len, unicode, &ssd->cur_rtracker->file_name_size);
+ get_smb_file_name(param_ptr, param_len, unicode, &ssd->cur_rtracker->file_name_size);
return DCE2_RET__SUCCESS;
}
#ifndef DCE_SMB_TRANSACTION_UTILS_H
#define DCE_SMB_TRANSACTION_UTILS_H
-#include "dce_smb.h"
+#include "dce_smb1.h"
DCE2_Ret DCE2_SmbTransactionGetName(const uint8_t* nb_ptr,
uint32_t nb_len, uint16_t bcc, bool unicode);
return false;
}
-// Extract file name from data. Supports ASCII and UTF-16LE.
-// Returns byte stream (ASCII or UTF-16LE with BOM)
-char* DCE2_SmbGetFileName(const uint8_t* data, uint32_t data_len, bool unicode,
- uint16_t* file_name_len)
-{
- const uint8_t inc = unicode ? 2 : 1;
- if (data_len < inc)
- return nullptr;
-
- const uint32_t max_len = unicode ? data_len - 1 : data_len;
- // Move forward. Don't know if the end of data is actually
- // the end of the string.
- uint32_t i;
- for (i = 0; i < max_len; i += inc)
- {
- uint16_t uchar = unicode ? extract_16bits(data + i) : data[i];
- if (uchar == 0)
- break;
- }
-
- char* fname = nullptr;
- const uint32_t real_len = i;
-
- if (unicode)
- {
- fname = (char*)snort_calloc(real_len + UTF_16_LE_BOM_LEN + 2);
- memcpy(fname, UTF_16_LE_BOM, UTF_16_LE_BOM_LEN);//Prepend with BOM
- memcpy(fname + UTF_16_LE_BOM_LEN, data, real_len);
- *file_name_len = real_len + UTF_16_LE_BOM_LEN;
- }
- else
- {
- fname = (char*)snort_alloc(real_len + 1);
- memcpy(fname, data, real_len);
- fname[real_len] = 0;
- *file_name_len = real_len;
- }
-
- return fname;
-}
-
int DCE2_SmbUidTidFidCompare(const void* a, const void* b)
{
int x = (int)(uintptr_t)a;
}
else if (ftracker->ff_file_offset < ftracker->ff_bytes_processed)
{
- debug_logf(dce_smb_trace, nullptr, "File offset %" PRIu64 " is "
- "less than bytes processed %" PRIu64 " - aborting.\n",
- ftracker->ff_file_offset, ftracker->ff_bytes_processed);
+ debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
+ "File offset %" PRIu64 " is less than bytes processed %"
+ PRIu64 " - aborting.\n", ftracker->ff_file_offset,
+ ftracker->ff_bytes_processed);
DCE2_SmbAbortFileAPI(ssd);
DCE2_SmbSetNewFileAPIFileTracker(ssd);
#ifndef DCE_SMB_UTILS_H
#define DCE_SMB_UTILS_H
-#include "dce_smb.h"
+#include "dce_smb1.h"
#include "file_api/file_flows.h"
/********************************************************************
* Function prototypes
********************************************************************/
bool DCE2_SmbIsTidIPC(DCE2_SmbSsnData*, const uint16_t);
-char* DCE2_SmbGetFileName(const uint8_t *data, uint32_t data_len, bool unicode, uint16_t *file_name_len);
int DCE2_SmbUidTidFidCompare(const void*, const void*);
DCE2_Ret DCE2_SmbFindUid(DCE2_SmbSsnData*, const uint16_t);
void DCE2_SmbInsertUid(DCE2_SmbSsnData*, const uint16_t);
uint32_t data_len, bool upload);
void DCE2_FileDetect();
FileVerdict DCE2_get_file_verdict();
+void DCE2_SmbInitGlobals();
void DCE2_SmbInitDeletePdu();
void DCE2_Update_Ftracker_from_ReqTracker(DCE2_SmbFileTracker*, DCE2_SmbRequestTracker*);
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.
+For SMBv2, it supports TCP as transport and it also supports multiple File transfer
+on single SMB2 connection.
+The SMB inspector implements base class for smb flow data,
+which all versions now inherits and implements. SMBv1 and SMBv2 code is completely
+segregated, maintaining common code in separate file to reduce redundancy.
+The common functionality used by both versions are in dce_smb_common files.
+SMBv2 specific trackers are in there own file now.
+
+The inspector eval function checks for the presence of SMB flow data in the flow,
+if not present, it creates an SMB flow data according to detected version, otherwise
+calls the respective process function.
+The process functions processes the commands according to respective versions and when
+file transfer is detected, it calls file_flow process().
\ No newline at end of file
#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"
{
int smb_com = SmbCom(smb_hdr);
+ if (smb_com < 0 or smb_com > 255) return nullptr;
+
debug_logf(dce_smb_trace, DetectionEngine::get_current_packet(),
"SMB command: %s (0x%02X)\n", get_smb_com_string(smb_com), smb_com);
}
}
-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;
- memory::MemoryCap::update_allocations(sizeof(*this));
-}
-
-Dce2SmbFlowData::~Dce2SmbFlowData()
-{
- if (DCE2_SMB_VERSION_1 == smb_version)
- {
- DCE2_SmbDataFree((DCE2_SmbSsnData*)dce2_smb_session_data);
- delete (DCE2_SmbSsnData*)dce2_smb_session_data;
- }
- else
- {
- DCE2_Smb2RemoveAllSession((DCE2_Smb2SsnData*)dce2_smb_session_data);
- delete (DCE2_Smb2SsnData*)dce2_smb_session_data;
- memory::MemoryCap::update_deallocations(sizeof(*(DCE2_Smb2SsnData*)dce2_smb_session_data));
- }
- assert(dce2_smb_stats.concurrent_sessions > 0);
- dce2_smb_stats.concurrent_sessions--;
- memory::MemoryCap::update_deallocations(sizeof(*this));
-}
-
-unsigned Dce2SmbFlowData::inspector_id = 0;
-
-static inline DCE2_SmbSsnData* set_new_dce2_smb_session(Packet* p)
-{
- Dce2SmbFlowData* fd = new Dce2SmbFlowData;
- fd->smb_version = DCE2_SMB_VERSION_1;
- fd->dce2_smb_session_data = new DCE2_SmbSsnData();
- p->flow->set_flow_data(fd);
- return (DCE2_SmbSsnData*)(fd->dce2_smb_session_data);
-}
-
-DCE2_SmbSsnData* dce2_create_new_smb_session(Packet* p, dce2SmbProtoConf* config)
-{
- DCE2_SmbSsnData* dce2_smb_sess = set_new_dce2_smb_session(p);
- if ( dce2_smb_sess )
- {
- dce2_smb_sess->dialect_index = DCE2_SENTINEL;
- dce2_smb_sess->max_outstanding_requests = 10; // Until Negotiate/SessionSetupAndX
- dce2_smb_sess->cli_data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER;
- dce2_smb_sess->srv_data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER;
- dce2_smb_sess->pdu_state = DCE2_SMB_PDU_STATE__COMMAND;
- dce2_smb_sess->uid = DCE2_SENTINEL;
- dce2_smb_sess->tid = DCE2_SENTINEL;
- dce2_smb_sess->ftracker.fid_v1 = DCE2_SENTINEL;
- dce2_smb_sess->rtracker.mid = DCE2_SENTINEL;
- dce2_smb_sess->max_file_depth = FileService::get_max_file_depth();
-
- DCE2_ResetRopts(&dce2_smb_sess->sd, p);
-
- dce2_smb_stats.smb_sessions++;
-
- dce2_smb_sess->sd.trans = DCE2_TRANS_TYPE__SMB;
- dce2_smb_sess->sd.server_policy = config->common.policy;
- dce2_smb_sess->sd.client_policy = DCE2_POLICY__WINXP;
- dce2_smb_sess->sd.config = (void*)config;
- }
-
- return dce2_smb_sess;
-}
-
/********************************************************************
* Function: DCE2_NbssHdrChecks()
*
{
// Upgrade connection to SMBv2
debug_log(dce_smb_trace, p, "upgrading to smb2 session\n");
- dce2SmbProtoConf* config = (dce2SmbProtoConf*)ssd->sd.config;
Dce2SmbFlowData* fd = (Dce2SmbFlowData*)p->flow->get_flow_data(
Dce2SmbFlowData::inspector_id);
- 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);
+ if (fd)
+ {
+ Dce2SmbSessionData* dce2_smb2_sess = fd->upgrade(p);
+ dce2_smb2_sess->process();
+ }
}
else
ssd->sd.flags |= DCE2_SSN_FLAG__SMB2;
}
}
-/* smb2 Functions */
-
-static inline DCE2_Smb2SsnData* set_new_dce2_smb2_session(Packet* p)
-{
- Dce2SmbFlowData* fd = new Dce2SmbFlowData;
- fd->smb_version = DCE2_SMB_VERSION_2;
- fd->dce2_smb_session_data = new DCE2_Smb2SsnData();
- memory::MemoryCap::update_allocations(sizeof(*(DCE2_Smb2SsnData*)(fd->dce2_smb_session_data)));
- DCE2_Smb2InitData((DCE2_Smb2SsnData*)fd->dce2_smb_session_data);
- p->flow->set_flow_data(fd);
- return((DCE2_Smb2SsnData*)fd->dce2_smb_session_data);
-}
-
-DCE2_Smb2SsnData* dce2_create_new_smb2_session(Packet* p, dce2SmbProtoConf* config)
-{
- DCE2_Smb2SsnData* dce2_smb2_sess = set_new_dce2_smb2_session(p);
- if ( dce2_smb2_sess )
- {
- dce2_smb2_sess->sd.flags |= DCE2_SSN_FLAG__SMB2;
- dce2_smb2_sess->dialect_index = DCE2_SENTINEL;
-
- DCE2_ResetRopts(&dce2_smb2_sess->sd, p);
-
- dce2_smb_stats.smb_sessions++;
-
- dce2_smb2_sess->sd.trans = DCE2_TRANS_TYPE__SMB;
- dce2_smb2_sess->sd.server_policy = config->common.policy;
- dce2_smb2_sess->sd.client_policy = DCE2_POLICY__WINXP;
- dce2_smb2_sess->sd.config = (void*)config;
- dce2_smb2_sess->max_outstanding_requests = DCE2_ScSmbMaxCredit(config);
- }
-
- return dce2_smb2_sess;
-}
-
-DCE2_SsnData* get_dce2_session_data(snort::Flow* flow)
-{
- Dce2SmbFlowData* fd = (Dce2SmbFlowData*)flow->get_flow_data(Dce2SmbFlowData::inspector_id);
- if (fd and fd->dce2_smb_session_data)
- return (fd->smb_version == DCE2_SMB_VERSION_1) ?
- (DCE2_SsnData*)(&((DCE2_SmbSsnData*)fd->dce2_smb_session_data)->sd) :
- (DCE2_SsnData*)(&((DCE2_Smb2SsnData*)fd->dce2_smb_session_data)->sd);
- else
- return nullptr;
-}
-
#pragma pack()
-void DCE2_SmbInitGlobals();
void DCE2_Smb1Process(struct DCE2_SmbSsnData*);
-struct DCE2_SmbSsnData* dce2_create_new_smb_session(snort::Packet*, struct dce2SmbProtoConf*);
-struct DCE2_Smb2SsnData* dce2_create_new_smb2_session(snort::Packet*, struct dce2SmbProtoConf*);
void DCE2_SmbDataFree(DCE2_SmbSsnData*);
#endif