bool is_from_server() const
{ return (packet_flags & PKT_FROM_SERVER) != 0; }
- bool is_portscan()
+ bool is_portscan() const
{ return is_cooked() and (pseudo_type == PSEUDO_PKT_PS); }
- bool is_full_pdu()
+ bool is_full_pdu() const
{ return (packet_flags & PKT_PDU_FULL) == PKT_PDU_FULL; }
- bool is_pdu_start()
+ bool is_pdu_start() const
{ return (packet_flags & PKT_PDU_HEAD) != 0; }
- bool has_paf_payload()
+ bool has_paf_payload() const
{ return (packet_flags & PKT_REBUILT_STREAM) or is_full_pdu(); }
- bool is_rebuilt()
+ bool is_rebuilt() const
{ return (packet_flags & (PKT_REBUILT_STREAM|PKT_REBUILT_FRAG)) != 0; }
int16_t get_application_protocol()
dce_list.cc
dce_smb.cc
dce_smb.h
+ dce_smb2.cc
+ dce_smb2.h
dce_smb_commands.cc
dce_smb_commands.h
dce_smb_module.cc
dce_list.h \
dce_smb.cc \
dce_smb.h \
+dce_smb2.cc \
+dce_smb2.h \
dce_smb_commands.cc \
dce_smb_commands.h \
dce_smb_module.cc \
DCE2_SSN_FLAG__NONE = 0x0000,
DCE2_SSN_FLAG__AUTODETECTED = 0x0001,
DCE2_SSN_FLAG__NO_INSPECT = 0x0002,
+ DCE2_SSN_FLAG__SMB2 = 0x0004,
DCE2_SSN_FLAG__ALL = 0xffff
};
// dce_smb.cc author Rashmi Pitre <rrp@cisco.com>
#include "dce_smb.h"
+#include "dce_smb2.h"
#include "dce_smb_utils.h"
#include "dce_smb_paf.h"
#include "dce_smb_module.h"
if (DCE2_SsnFromClient(ssd->sd.wire_pkt))
{
DebugMessage(DEBUG_DCE_SMB, "Raw data: Write Raw\n");
- DebugFormat(DEBUG_DCE_SMB, "Request Fid: 0x%04X\n", ftracker->fid);
+ DebugFormat(DEBUG_DCE_SMB, "Request Fid: 0x%04X\n", ftracker->fid_v1);
if (nb_len > ssd->cur_rtracker->writeraw_remaining)
{
else
{
DebugMessage(DEBUG_DCE_SMB, "Raw data: Read Raw\n");
- DebugFormat(DEBUG_DCE_SMB, "Response Fid: 0x%04X\n", ftracker->fid);
+ DebugFormat(DEBUG_DCE_SMB, "Response Fid: 0x%04X\n", ftracker->fid_v1);
remove_rtracker = true;
}
DCE2_BufferDestroy(ssd->srv_seg);
ssd->srv_seg = nullptr;
}
+
+ if (ssd->smb2_requests != nullptr)
+ {
+ DCE2_Smb2CleanRequests(ssd->smb2_requests);
+ ssd->smb2_requests = nullptr;
+ }
}
Dce2SmbFlowData::Dce2SmbFlowData() : FlowData(flow_id)
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 = 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();
return DCE2_RET__IGNORE;
}
-/********************************************************************
- * Function: DCE2_SmbProcess()
- *
- * Purpose:
- * This is the main entry point for SMB processing.
- *
- * Arguments:
- * DCE2_SmbSsnData * - the session data structure.
- *
- * Returns: None
- *
- ********************************************************************/
-static void DCE2_SmbProcess(DCE2_SmbSsnData* ssd)
+
+// This is the main entry point for SMB1 processing.
+static void DCE2_Smb1Process(DCE2_SmbSsnData* ssd)
{
DebugMessage(DEBUG_DCE_SMB, "Processing SMB packet.\n");
dce2_smb_stats.smb_pkts++;
smb_hdr = (SmbNtHdr*)(DCE2_BufferData(*seg_buf) + sizeof(NbssHdr));
}
- // FIXIT-L Don't support SMB2 yet
if (SmbId(smb_hdr) == DCE2_SMB2_ID)
{
- ssd->sd.flags |= DCE2_SSN_FLAG__NO_INSPECT;
+ ssd->sd.flags |= DCE2_SSN_FLAG__SMB2;
+ if (!DCE2_GcIsLegacyMode((dce2SmbProtoConf*)ssd->sd.config))
+ {
+ DCE2_Smb2InitFileTracker(&(ssd->ftracker), false, 0);
+ DCE2_Smb2Process(ssd);
+ }
return;
}
}
}
+// This is the main entry point for SMB processing
+void DCE2_SmbProcess(DCE2_SmbSsnData* ssd)
+{
+ if (DCE2_GcIsLegacyMode((dce2SmbProtoConf*)ssd->sd.config))
+ {
+ DCE2_Smb1Process(ssd);
+ return;
+ }
+
+ Packet* p = ssd->sd.wire_pkt;
+ DCE2_SmbVersion smb_version = DCE2_Smb2Version(p);
+ if (smb_version == DCE2_SMB_VERISON_1)
+ {
+ if ((ssd->sd.flags & DCE2_SSN_FLAG__SMB2))
+ {
+ DebugMessage(DEBUG_DCE_SMB, "SMB1 packet detected!\n");
+ ssd->sd.flags &= ~DCE2_SSN_FLAG__SMB2;
+ DCE2_SmbCleanFileTracker(&(ssd->ftracker));
+ ssd->ftracker.is_smb2 = false;
+ }
+ }
+ else if (smb_version == DCE2_SMB_VERISON_2)
+ {
+ if (!(ssd->sd.flags & DCE2_SSN_FLAG__SMB2))
+ {
+ DebugMessage(DEBUG_DCE_SMB, "SMB2 packet detected!\n");
+ DCE2_SmbCleanFileTracker(&(ssd->ftracker));
+ DCE2_Smb2InitFileTracker(&(ssd->ftracker), 0, 0);
+ ssd->sd.flags |= DCE2_SSN_FLAG__SMB2;
+ }
+ }
+
+ if (ssd->sd.flags & DCE2_SSN_FLAG__SMB2)
+ DCE2_Smb2Process(ssd);
+ else
+ DCE2_Smb1Process(ssd);
+}
+
/********************************************************************
* Function: DCE2_SmbInitGlobals()
*
#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."
"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"
#define SMB_MAX_NUM_COMS 256
uint64_t smb_nt_transact_subcom_stats[2][NT_TRANSACT_SUBCOM_MAX+1];
*/
PegCount smb_files_processed;
+ /* SMB2 stats */
+ PegCount smb2_create;
+ PegCount smb2_write;
+ PegCount smb2_read;
+ PegCount smb2_set_info;
+ PegCount smb2_tree_connect;
+ PegCount smb2_tree_disconnect;
+ PegCount smb2_close;
};
extern THREAD_LOCAL dce2SmbStats dce2_smb_stats;
struct DCE2_SmbFileTracker
{
- int fid; // A signed integer so it can be set to sentinel
- uint16_t uid;
- uint16_t tid;
+ 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;
union
{
} file;
} tracker;
+#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 ff_sequential_only tracker.file.sequential_only
};
+enum DCE2_SmbVersion
+{
+ DCE2_SMB_VERISON_NULL,
+ DCE2_SMB_VERISON_1,
+ DCE2_SMB_VERISON_2
+};
+
+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;
// This is a reference to a file tracker so shouldn't be freed.
DCE2_SmbFileTracker* fapi_ftracker;
+ Smb2Request* smb2_requests;
+
#ifdef ACTIVE_RESPONSE
DCE2_SmbFileTracker* fb_ftracker;
bool block_pdus;
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2016 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 file processing
+// Author(s): Hui Cao <huica@cisco.com>
+
+#include "dce_smb2.h"
+#include "dce_list.h"
+#include "dce_smb_module.h"
+#include "dce_smb_utils.h"
+#include "detection/detection_util.h"
+#include "main/snort_debug.h"
+
+#define UNKNOWN_FILE_SIZE ~0
+
+// FIXIT-L port fileCache related code along with
+// DCE2_Smb2Init, DCE2_Smb2Close and DCE2_Smb2UpdateStats
+
+static void DCE2_Smb2Inspect(DCE2_SmbSsnData* ssd, const Smb2Hdr* smb_hdr,
+ const uint8_t* end);
+
+static char* DCE2_Smb2GetFileName(const uint8_t* data,
+ uint32_t data_len, bool unicode, bool file_name_only)
+{
+ char* str;
+ uint32_t path_end, name_start, str_len = unicode ? data_len - 1 : data_len;
+ const uint8_t inc = unicode ? 2 : 1;
+
+ if (data_len < inc)
+ return nullptr;
+
+ // Move forward. Don't know if the end of data is actually
+ // the end of the string.
+ for (path_end = 0, name_start = 0; path_end < str_len; path_end += inc)
+ {
+ uint16_t uchar = unicode ? alignedNtohs((uint16_t*)(data + path_end)) : data[path_end];
+
+ if (uchar == 0)
+ break;
+ else if (file_name_only && ((uchar == 0x002F) || (uchar == 0x005C))) // slash and
+ // back-slash
+ name_start = path_end + inc;
+ }
+
+ // Only got a NULL byte or nothing after slash/back-slash or too big.
+ if ((path_end == 0) || (name_start == path_end)
+ || (file_name_only && (path_end > DCE2_SMB_MAX_COMP_LEN))
+ || (path_end > DCE2_SMB_MAX_PATH_LEN))
+ return nullptr;
+
+ str = (char*)snort_calloc(((path_end-name_start)>>(inc-1))+1);
+
+ uint32_t ind;
+ for (ind = 0; name_start < path_end; name_start += inc, ind++)
+ {
+ if ((int)data[name_start])
+ str[ind] = (char)data[name_start];
+ else
+ str[ind] = '.';
+ }
+
+ str[ind] = 0;
+
+ return str;
+}
+
+static inline uint32_t Smb2Tid(const Smb2Hdr* hdr)
+{
+ return alignedNtohl(&(((Smb2SyncHdr*)hdr)->tree_id));
+}
+
+static int DCE2_Smb2TidCompare(const void* a, const void* b)
+{
+ uint32_t x = (uint32_t)(uintptr_t)a;
+ uint32_t y = (uint32_t)(uintptr_t)b;
+
+ if (x == y)
+ return 0;
+
+ /* Only care about equality for finding */
+ return -1;
+}
+
+static inline void DCE2_Smb2InsertTid(DCE2_SmbSsnData* ssd, const uint32_t tid,
+ const uint8_t share_type)
+{
+ bool is_ipc = (share_type != SMB2_SHARE_TYPE_DISK);
+
+ if (!is_ipc && (!DCE2_ScSmbFileInspection((dce2SmbProtoConf*)ssd->sd.config)
+ || ((ssd->max_file_depth == -1) && DCE2_ScSmbFileDepth(
+ (dce2SmbProtoConf*)ssd->sd.config) == -1)))
+ {
+ DebugFormat(DEBUG_DCE_SMB, "Not inserting TID (%u) "
+ "because it's not IPC and not inspecting normal file "
+ "data.", tid);
+ return;
+ }
+
+ if (is_ipc)
+ {
+ DebugFormat(DEBUG_DCE_SMB, "Not inserting TID (%u) "
+ "because it's IPC and only inspecting normal file data.", tid);
+ return;
+ }
+
+ DebugFormat(DEBUG_DCE_SMB, "Inserting Tid: %u\n", tid);
+
+ if (ssd->tids == nullptr)
+ {
+ ssd->tids = DCE2_ListNew(DCE2_LIST_TYPE__SPLAYED, DCE2_Smb2TidCompare,
+ nullptr, nullptr, DCE2_LIST_FLAG__NO_DUPS);
+
+ if (ssd->tids == nullptr)
+ {
+ return;
+ }
+ }
+
+ DCE2_ListInsert(ssd->tids, (void*)(uintptr_t)tid, (void*)(uintptr_t)share_type);
+}
+
+static DCE2_Ret DCE2_Smb2FindTid(DCE2_SmbSsnData* ssd, const Smb2Hdr* smb_hdr)
+{
+ /* Still process async commands*/
+ if (alignedNtohl(&(smb_hdr->flags)) & SMB2_FLAGS_ASYNC_COMMAND)
+ return DCE2_RET__SUCCESS;
+
+ return DCE2_ListFindKey(ssd->tids, (void*)(uintptr_t)Smb2Tid(smb_hdr));
+}
+
+static inline void DCE2_Smb2RemoveTid(DCE2_SmbSsnData* ssd, const uint32_t tid)
+{
+ DCE2_ListRemove(ssd->tids, (void*)(uintptr_t)tid);
+}
+
+static inline void DCE2_Smb2StoreRequest(DCE2_SmbSsnData* ssd,
+ uint64_t message_id, uint64_t offset, uint64_t file_id)
+{
+ Smb2Request* request = ssd->smb2_requests;
+ ssd->max_outstanding_requests = 128; /* windows client max */
+
+ while (request)
+ {
+ if (request->message_id == message_id)
+ return;
+ request = request->next;
+ }
+
+ request = (Smb2Request*)snort_calloc(sizeof(*request));
+
+ ssd->outstanding_requests++;
+
+ if (ssd->outstanding_requests >= ssd->max_outstanding_requests)
+ {
+ dce_alert(GID_DCE2, DCE2_SMB_MAX_REQS_EXCEEDED, (dce2CommonStats*)&dce2_smb_stats);
+ snort_free((void*)request);
+ return;
+ }
+
+ request->message_id = message_id;
+ request->offset = offset;
+ request->file_id = file_id;
+
+ request->next = ssd->smb2_requests;
+ request->previous = nullptr;
+ if (ssd->smb2_requests)
+ ssd->smb2_requests->previous = request;
+ ssd->smb2_requests = request;
+}
+
+static inline Smb2Request* DCE2_Smb2GetRequest(DCE2_SmbSsnData* ssd,
+ uint64_t message_id)
+{
+ Smb2Request* request = ssd->smb2_requests;
+ while (request)
+ {
+ if (request->message_id == message_id)
+ return request;
+ request = request->next;
+ }
+
+ return nullptr;
+}
+
+static inline void DCE2_Smb2RemoveRequest(DCE2_SmbSsnData* ssd,
+ Smb2Request* request)
+{
+ if (request->previous)
+ {
+ request->previous->next = request->next;
+ }
+
+ if (request->next)
+ {
+ request->next->previous = request->previous;
+ }
+
+ if (request == ssd->smb2_requests)
+ {
+ ssd->smb2_requests = request->next;
+ }
+
+ ssd->outstanding_requests--;
+ snort_free((void*)request);
+}
+
+static inline void DCE2_Smb2FreeFileName(DCE2_SmbFileTracker* ftracker)
+{
+ if (ftracker->file_name)
+ {
+ snort_free((void*)ftracker->file_name);
+ ftracker->file_name = nullptr;
+ }
+ ftracker->file_name_size = 0;
+}
+
+static inline void DCE2_Smb2ResetFileName(DCE2_SmbFileTracker* ftracker)
+{
+ // FIXIT-L remove snort_free once file cache is ported.
+ if (ftracker->file_name)
+ {
+ snort_free((void*)ftracker->file_name);
+ }
+ ftracker->file_name = nullptr;
+ ftracker->file_name_size = 0;
+}
+
+static inline void DCE2_Smb2ProcessFileData(DCE2_SmbSsnData* ssd, const uint8_t* file_data,
+ uint32_t data_size, bool)
+{
+ int64_t file_detection_depth = DCE2_ScSmbFileDepth((dce2SmbProtoConf*)ssd->sd.config);
+ int64_t detection_size = 0;
+
+ if (file_detection_depth == 0)
+ detection_size = data_size;
+ else if ( ssd->ftracker.tracker.file.file_offset < (uint64_t)file_detection_depth)
+ {
+ if ( file_detection_depth - ssd->ftracker.tracker.file.file_offset < data_size )
+ detection_size = file_detection_depth - ssd->ftracker.tracker.file.file_offset;
+ else
+ detection_size = data_size;
+ }
+
+ if (detection_size)
+ {
+ set_file_data((uint8_t*)file_data,
+ (detection_size > UINT16_MAX) ? UINT16_MAX : (uint16_t)detection_size);
+
+ DCE2_FileDetect();
+ }
+
+// FIXIT-L port file processing
+/*
+ _dpd.fileAPI->file_segment_process(fileCache, (void *)ssd->sd.wire_pkt,
+ ssd->ftracker.fid_v2, ssd->ftracker.tracker.file.file_size,
+ file_data, data_size, ssd->ftracker.tracker.file.file_offset,
+ upload);
+*/
+}
+
+/********************************************************************
+ *
+ * Process tree connect command
+ * Share type is defined here
+ *
+ ********************************************************************/
+static void DCE2_Smb2TreeConnect(DCE2_SmbSsnData* ssd, const Smb2Hdr* smb_hdr,
+ uint8_t* smb_data, const uint8_t* end)
+{
+ /* Using structure size to decide whether it is response or request*/
+ uint16_t structure_size;
+ Smb2TreeConnectResponseHdr* smb_tree_connect_hdr = (Smb2TreeConnectResponseHdr*)smb_data;
+
+ if ((const uint8_t*)smb_tree_connect_hdr + SMB2_TREE_CONNECT_RESPONSE_STRUC_SIZE > end)
+ return;
+
+ structure_size = alignedNtohs(&(smb_tree_connect_hdr->structure_size));
+
+ if (structure_size == SMB2_TREE_CONNECT_RESPONSE_STRUC_SIZE)
+ {
+ DCE2_Smb2InsertTid(ssd, Smb2Tid(smb_hdr), smb_tree_connect_hdr->share_type);
+ }
+}
+
+/********************************************************************
+ *
+ * Process tree connect command
+ * Share type is defined here
+ *
+ ********************************************************************/
+static void DCE2_Smb2TreeDisconnect(DCE2_SmbSsnData* ssd, const Smb2Hdr* smb_hdr,
+ uint8_t* smb_data, const uint8_t* end)
+{
+ /* Using structure size to decide whether it is response or request*/
+ uint16_t structure_size;
+ Smb2TreeDisConnectHdr* smb_tree_disconnect_hdr = (Smb2TreeDisConnectHdr*)smb_data;
+
+ if ((const uint8_t*)smb_tree_disconnect_hdr + SMB2_TREE_DISCONNECT_STRUC_SIZE > end)
+ return;
+
+ structure_size = alignedNtohs(&(smb_tree_disconnect_hdr->structure_size));
+
+ if (structure_size == SMB2_TREE_DISCONNECT_STRUC_SIZE)
+ {
+ DCE2_Smb2RemoveTid(ssd, Smb2Tid(smb_hdr));
+ }
+}
+
+/********************************************************************
+ *
+ * Process create request, first command for a file processing
+ * Update file name
+ *
+ ********************************************************************/
+static void DCE2_Smb2CreateRequest(DCE2_SmbSsnData* ssd, const Smb2Hdr*,
+ Smb2CreateRequestHdr* smb_create_hdr,const uint8_t* end)
+{
+ uint16_t name_offset = alignedNtohs(&(smb_create_hdr->name_offset));
+ DebugMessage(DEBUG_DCE_SMB, "Processing create request command!\n");
+ DCE2_Smb2InitFileTracker(&ssd->ftracker, false, 0);
+
+ if (name_offset > SMB2_HEADER_LENGTH)
+ {
+ uint16_t size;
+ uint8_t* file_data = (uint8_t*)smb_create_hdr + smb_create_hdr->name_offset -
+ SMB2_HEADER_LENGTH;
+ if (file_data >= end)
+ return;
+ size = alignedNtohs(&(smb_create_hdr->name_length));
+ if (!size || (file_data + size > end))
+ return;
+ if (ssd->ftracker.file_name)
+ {
+ snort_free((void*)ssd->ftracker.file_name);
+ }
+ ssd->ftracker.file_name = DCE2_Smb2GetFileName(file_data, size, true, false);
+ if (ssd->ftracker.file_name)
+ ssd->ftracker.file_name_size = strlen(ssd->ftracker.file_name) + 1;
+ }
+}
+
+/********************************************************************
+ *
+ * Process create response, need to update file id
+ * For downloading, file size is decided here
+ *
+ ********************************************************************/
+static void DCE2_Smb2CreateResponse(DCE2_SmbSsnData* ssd, const Smb2Hdr*,
+ Smb2CreateResponseHdr* smb_create_hdr, const uint8_t*)
+{
+ uint64_t fileId_persistent;
+ uint64_t file_size = UNKNOWN_FILE_SIZE;
+ DebugMessage(DEBUG_DCE_SMB, "Processing create response command!\n");
+
+ fileId_persistent = alignedNtohq((const uint64_t*)(&(smb_create_hdr->fileId_persistent)));
+ ssd->ftracker.fid_v2 = fileId_persistent;
+ if (smb_create_hdr->end_of_file)
+ {
+ file_size = alignedNtohq((const uint64_t*)(&(smb_create_hdr->end_of_file)));
+ DebugFormat(DEBUG_DCE_SMB, "Get file size %lu!\n", file_size);
+ ssd->ftracker.tracker.file.file_size = file_size;
+ }
+
+ if (ssd->ftracker.file_name && ssd->ftracker.file_name_size)
+ {
+// FIXIT-L port file processing
+/*
+ _dpd.fileAPI->file_cache_update_entry(fileCache, (void *)ssd->sd.wire_pkt, ssd->ftracker.fid_v2,
+ (uint8_t *) ssd->ftracker.file_name, ssd->ftracker.file_name_size, file_size);
+*/
+ }
+ DCE2_Smb2ResetFileName(&(ssd->ftracker));
+}
+
+/********************************************************************
+ *
+ * Process create command
+ *
+ ********************************************************************/
+static void DCE2_Smb2Create(DCE2_SmbSsnData* ssd, const Smb2Hdr* smb_hdr,
+ uint8_t* smb_data, const uint8_t* end)
+{
+ uint16_t structure_size;
+ Smb2CreateRequestHdr* smb_create_hdr = (Smb2CreateRequestHdr*)smb_data;
+
+ structure_size = alignedNtohs(&(smb_create_hdr->structure_size));
+
+ /* Using structure size to decide whether it is response or request */
+ if (structure_size == SMB2_CREATE_REQUEST_STRUC_SIZE)
+ {
+ if ((const uint8_t*)smb_create_hdr + SMB2_CREATE_REQUEST_STRUC_SIZE - 1 > end)
+ return;
+ DCE2_Smb2CreateRequest(ssd, smb_hdr, (Smb2CreateRequestHdr*)smb_create_hdr, end);
+ }
+ else if (structure_size == SMB2_CREATE_RESPONSE_STRUC_SIZE)
+ {
+ if ((const uint8_t*)smb_create_hdr + SMB2_CREATE_RESPONSE_STRUC_SIZE -1 > end)
+ return;
+ DCE2_Smb2CreateResponse(ssd, smb_hdr, (Smb2CreateResponseHdr*)smb_create_hdr, end);
+ }
+ else if (structure_size == SMB2_ERROR_RESPONSE_STRUC_SIZE)
+ {
+ Smb2ErrorResponseHdr* smb_err_response_hdr = (Smb2ErrorResponseHdr*)smb_data;
+ if ((const uint8_t*)smb_create_hdr + SMB2_ERROR_RESPONSE_STRUC_SIZE - 1 > end)
+ return;
+ /* client will ignore when byte count is 0 */
+ if (smb_err_response_hdr->byte_count)
+ {
+ /*Response error, clean up request state*/
+ DCE2_Smb2FreeFileName(&(ssd->ftracker));
+ }
+ }
+ else
+ {
+ DebugMessage(DEBUG_DCE_SMB, "Wrong format for smb create command!\n");
+ }
+}
+
+/********************************************************************
+ *
+ * Process close command
+ * For some upload, file_size is decided here.
+ *
+ ********************************************************************/
+static void DCE2_Smb2CloseCmd(DCE2_SmbSsnData* ssd, const Smb2Hdr*,
+ uint8_t* smb_data, const uint8_t* end)
+{
+ /* Using structure size to decide whether it is response or request*/
+ uint16_t structure_size;
+ Smb2CloseRequestHdr* smb_close_hdr = (Smb2CloseRequestHdr*)smb_data;
+
+ if ((const uint8_t*)smb_close_hdr + SMB2_CLOSE_REQUEST_STRUC_SIZE > end)
+ return;
+
+ structure_size = alignedNtohs(&(smb_close_hdr->structure_size));
+
+ if ((structure_size == SMB2_CLOSE_REQUEST_STRUC_SIZE) &&
+ !ssd->ftracker.tracker.file.file_size
+ && ssd->ftracker.tracker.file.file_offset)
+ {
+ bool upload = DCE2_SsnFromClient(ssd->sd.wire_pkt) ? true : false;
+ ssd->ftracker.tracker.file.file_size = ssd->ftracker.tracker.file.file_offset;
+// FIXIT-L port file processing
+/*
+ uint64_t fileId_persistent = alignedNtohq((const uint64_t *)(&(smb_close_hdr->fileId_persistent)));
+ _dpd.fileAPI->file_cache_update_entry(fileCache, (void *)ssd->sd.wire_pkt,
+ fileId_persistent, nullptr, 0, ssd->ftracker.tracker.file.file_size);
+*/
+ DCE2_Smb2ProcessFileData(ssd, nullptr, 0, upload);
+ }
+}
+
+/********************************************************************
+ *
+ * Process set info command
+ * For upload, file_size is decided here.
+ *
+ ********************************************************************/
+static void DCE2_Smb2SetInfo(DCE2_SmbSsnData* ssd, const Smb2Hdr*,
+ uint8_t* smb_data, const uint8_t* end)
+{
+ /* Using structure size to decide whether it is response or request*/
+ uint16_t structure_size;
+ Smb2SetInfoRequestHdr* smb_set_info_hdr = (Smb2SetInfoRequestHdr*)smb_data;
+
+ if ((const uint8_t*)smb_set_info_hdr + SMB2_SET_INFO_REQUEST_STRUC_SIZE > end)
+ return;
+
+ structure_size = alignedNtohs(&(smb_set_info_hdr->structure_size));
+
+ if (structure_size == SMB2_SET_INFO_REQUEST_STRUC_SIZE)
+ {
+ uint8_t* file_data = (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);
+ DebugFormat(DEBUG_DCE_SMB, "Get file size %lu!\n", file_size);
+ ssd->ftracker.tracker.file.file_size = file_size;
+//FIXIT-L port file processing
+/*
+ uint64_t fileId_persistent = alignedNtohq((const uint64_t *)(&(smb_set_info_hdr->fileId_persistent)));
+ _dpd.fileAPI->file_cache_update_entry(fileCache, (void *)ssd->sd.wire_pkt,
+ fileId_persistent, nullptr, 0, file_size);
+*/
+ }
+ }
+}
+
+/********************************************************************
+ *
+ * Process read request
+ *
+ ********************************************************************/
+static void DCE2_Smb2ReadRequest(DCE2_SmbSsnData* ssd, const Smb2Hdr* smb_hdr,
+ Smb2ReadRequestHdr* smb_read_hdr, const uint8_t*)
+{
+ uint64_t message_id, offset;
+ uint64_t fileId_persistent;
+ DebugMessage(DEBUG_DCE_SMB, "Processing read request command!\n");
+ message_id = alignedNtohq((const uint64_t*)(&(smb_hdr->message_id)));
+ offset = alignedNtohq((const uint64_t*)(&(smb_read_hdr->offset)));
+ fileId_persistent = alignedNtohq((const uint64_t*)(&(smb_read_hdr->fileId_persistent)));
+ DCE2_Smb2StoreRequest(ssd, message_id, offset, fileId_persistent);
+ if (fileId_persistent && (ssd->ftracker.fid_v2 != fileId_persistent))
+ {
+ DebugMessage(DEBUG_DCE_SMB, "Persistent file ID changed read request command!\n");
+ ssd->ftracker.fid_v2 = fileId_persistent;
+ }
+ if (ssd->ftracker.tracker.file.file_size && (offset > ssd->ftracker.tracker.file.file_size))
+ {
+ dce_alert(GID_DCE2, DCE2_SMB_INVALID_FILE_OFFSET, (dce2CommonStats*)&dce2_smb_stats);
+ }
+}
+
+/********************************************************************
+ *
+ * Process read response
+ *
+ ********************************************************************/
+static void DCE2_Smb2ReadResponse(DCE2_SmbSsnData* ssd, const Smb2Hdr* smb_hdr,
+ Smb2ReadResponseHdr* smb_read_hdr, const uint8_t* end)
+{
+ uint8_t* file_data = (uint8_t*)smb_read_hdr + SMB2_READ_RESPONSE_STRUC_SIZE - 1;
+ int data_size = end - file_data;
+ uint32_t total_data_length;
+ uint64_t message_id;
+ uint16_t data_offset;
+ Smb2Request* request;
+
+ DebugMessage(DEBUG_DCE_SMB, "Processing read response command!\n");
+
+ message_id = alignedNtohq((const uint64_t*)(&(smb_hdr->message_id)));
+ request = DCE2_Smb2GetRequest(ssd, message_id);
+ if (!request)
+ {
+ return;
+ }
+ data_offset = alignedNtohs((const uint16_t*)(&(smb_read_hdr->data_offset)));
+ if (data_offset + (const uint8_t*)smb_hdr > end)
+ {
+ dce_alert(GID_DCE2, DCE2_SMB_BAD_OFF, (dce2CommonStats*)&dce2_smb_stats);
+ }
+
+ ssd->ftracker.tracker.file.file_offset = request->offset;
+ ssd->ftracker.fid_v2 = request->file_id;
+ ssd->ftracker.tracker.file.file_direction = DCE2_SMB_FILE_DIRECTION__DOWNLOAD;
+
+ DCE2_Smb2RemoveRequest(ssd, request);
+
+ DCE2_Smb2ProcessFileData(ssd, file_data, data_size, false);
+ ssd->ftracker.tracker.file.file_offset += data_size;
+ total_data_length = alignedNtohl((const uint32_t*)&(smb_read_hdr->length));
+ if (total_data_length > (uint32_t)data_size)
+ ssd->pdu_state = DCE2_SMB_PDU_STATE__RAW_DATA;
+}
+
+/********************************************************************
+ *
+ * Process read command
+ *
+ ********************************************************************/
+static void DCE2_Smb2Read(DCE2_SmbSsnData* ssd, const Smb2Hdr* smb_hdr,
+ uint8_t* smb_data, const uint8_t* end)
+{
+ uint16_t structure_size;
+ Smb2ReadRequestHdr* smb_read_hdr = (Smb2ReadRequestHdr*)smb_data;
+ structure_size = alignedNtohs(&(smb_read_hdr->structure_size));
+
+ /* Using structure size to decide whether it is response or request*/
+ if (structure_size == SMB2_READ_REQUEST_STRUC_SIZE)
+ {
+ if ((const uint8_t*)smb_read_hdr + SMB2_READ_REQUEST_STRUC_SIZE - 1 > end)
+ return;
+ DCE2_Smb2ReadRequest(ssd, smb_hdr, (Smb2ReadRequestHdr*)smb_read_hdr, end);
+ }
+ else if (structure_size == SMB2_READ_RESPONSE_STRUC_SIZE)
+ {
+ if ((const uint8_t*)smb_read_hdr + SMB2_READ_RESPONSE_STRUC_SIZE - 1 > end)
+ return;
+ DCE2_Smb2ReadResponse(ssd, smb_hdr, (Smb2ReadResponseHdr*)smb_read_hdr, end);
+ }
+ else
+ {
+ uint64_t message_id;
+ Smb2Request* request;
+ DebugMessage(DEBUG_DCE_SMB, "Wrong format for smb read command!\n");
+ message_id = alignedNtohq((const uint64_t*)(&(smb_hdr->message_id)));
+ request = DCE2_Smb2GetRequest(ssd, message_id);
+ if (!request)
+ {
+ return;
+ }
+ DCE2_Smb2RemoveRequest(ssd, request);
+ }
+}
+
+/********************************************************************
+ *
+ * Process write request
+ *
+ ********************************************************************/
+static void DCE2_Smb2WriteRequest(DCE2_SmbSsnData* ssd, const Smb2Hdr* smb_hdr,
+ Smb2WriteRequestHdr* smb_write_hdr, const uint8_t* end)
+{
+ uint8_t* file_data = (uint8_t*)smb_write_hdr + SMB2_WRITE_REQUEST_STRUC_SIZE - 1;
+ int data_size = end - file_data;
+ uint64_t fileId_persistent, offset;
+ uint16_t data_offset;
+ uint32_t total_data_length;
+
+ DebugMessage(DEBUG_DCE_SMB, "Processing write request command!\n");
+
+ fileId_persistent = alignedNtohq((const uint64_t*)(&(smb_write_hdr->fileId_persistent)));
+ if (fileId_persistent && (ssd->ftracker.fid_v2 != fileId_persistent))
+ {
+ DebugMessage(DEBUG_DCE_SMB, "Persistent file ID changed read request command!\n");
+ ssd->ftracker.fid_v2 = fileId_persistent;
+ }
+ data_offset = alignedNtohs((const uint16_t*)(&(smb_write_hdr->data_offset)));
+ if (data_offset + (const uint8_t*)smb_hdr > end)
+ {
+ dce_alert(GID_DCE2, DCE2_SMB_BAD_OFF, (dce2CommonStats*)&dce2_smb_stats);
+ }
+
+ offset = alignedNtohq((const uint64_t*)(&(smb_write_hdr->offset)));
+ if (ssd->ftracker.tracker.file.file_size && (offset > ssd->ftracker.tracker.file.file_size))
+ {
+ dce_alert(GID_DCE2, DCE2_SMB_INVALID_FILE_OFFSET, (dce2CommonStats*)&dce2_smb_stats);
+ }
+ ssd->ftracker.tracker.file.file_direction = DCE2_SMB_FILE_DIRECTION__UPLOAD;
+ ssd->ftracker.tracker.file.file_offset = offset;
+
+ DCE2_Smb2ProcessFileData(ssd, file_data, data_size, true);
+ ssd->ftracker.tracker.file.file_offset += data_size;
+ total_data_length = alignedNtohl((const uint32_t*)&(smb_write_hdr->length));
+ if (total_data_length > (uint32_t)data_size)
+ ssd->pdu_state = DCE2_SMB_PDU_STATE__RAW_DATA;
+}
+
+/********************************************************************
+ *
+ * Process write response
+ *
+ ********************************************************************/
+static void DCE2_Smb2WriteResponse(DCE2_SmbSsnData*, const Smb2Hdr*,
+ Smb2WriteResponseHdr*, const uint8_t*)
+{
+ DebugMessage(DEBUG_DCE_SMB, "Processing write response command!\n");
+}
+
+/********************************************************************
+ *
+ * Process write command
+ *
+ ********************************************************************/
+static void DCE2_Smb2Write(DCE2_SmbSsnData* ssd, const Smb2Hdr* smb_hdr,
+ uint8_t* smb_data, const uint8_t* end)
+{
+ uint16_t structure_size;
+ Smb2WriteRequestHdr* smb_write_hdr = (Smb2WriteRequestHdr*)smb_data;
+ structure_size = alignedNtohs(&(smb_write_hdr->structure_size));
+
+ /* Using structure size to decide whether it is response or request*/
+ if (structure_size == SMB2_WRITE_REQUEST_STRUC_SIZE)
+ {
+ if ((const uint8_t*)smb_write_hdr + SMB2_WRITE_REQUEST_STRUC_SIZE - 1 > end)
+ return;
+ DCE2_Smb2WriteRequest(ssd, smb_hdr, (Smb2WriteRequestHdr*)smb_write_hdr, end);
+ }
+ else if (structure_size == SMB2_WRITE_RESPONSE_STRUC_SIZE)
+ {
+ if ((const uint8_t*)smb_write_hdr + SMB2_WRITE_RESPONSE_STRUC_SIZE - 1 > end)
+ return;
+ DCE2_Smb2WriteResponse(ssd, smb_hdr, (Smb2WriteResponseHdr*)smb_write_hdr, end);
+ }
+ else
+ {
+ DebugMessage(DEBUG_DCE_SMB, "Wrong format for smb write command!\n");
+ }
+}
+
+/********************************************************************
+ *
+ * Purpose:
+ * Process SMB2 commands.
+ *
+ * Arguments:
+ * DCE2_SmbSsnData * - the session data structure.
+ * const Smb2Hdr * - pointer to the SMB2 header.
+ * const uint8_t * - pointer to end of payload.
+ * Returns: None
+ *
+ ********************************************************************/
+static void DCE2_Smb2Inspect(DCE2_SmbSsnData* ssd, const Smb2Hdr* smb_hdr, const uint8_t* end)
+{
+ uint8_t* smb_data = (uint8_t*)smb_hdr + SMB2_HEADER_LENGTH;
+ uint16_t command = alignedNtohs(&(smb_hdr->command));
+ switch (command)
+ {
+ case SMB2_COM_CREATE:
+ DebugMessage(DEBUG_DCE_SMB, "Create command.\n");
+ dce2_smb_stats.smb2_create++;
+ if (DCE2_Smb2FindTid(ssd, smb_hdr) != DCE2_RET__SUCCESS)
+ return;
+ DCE2_Smb2Create(ssd, smb_hdr, smb_data, end);
+ break;
+ case SMB2_COM_READ:
+ DebugMessage(DEBUG_DCE_SMB, "Read command.\n");
+ dce2_smb_stats.smb2_read++;
+ if (DCE2_Smb2FindTid(ssd, smb_hdr) != DCE2_RET__SUCCESS)
+ return;
+ DCE2_Smb2Read(ssd, smb_hdr, smb_data, end);
+ break;
+ case SMB2_COM_WRITE:
+ DebugMessage(DEBUG_DCE_SMB, "Write command.\n");
+ dce2_smb_stats.smb2_write++;
+ if (DCE2_Smb2FindTid(ssd, smb_hdr) != DCE2_RET__SUCCESS)
+ return;
+ DCE2_Smb2Write(ssd, smb_hdr, smb_data, end);
+ break;
+ case SMB2_COM_SET_INFO:
+ DebugMessage(DEBUG_DCE_SMB, "Set info command.\n");
+ dce2_smb_stats.smb2_set_info++;
+ if (DCE2_Smb2FindTid(ssd, smb_hdr) != DCE2_RET__SUCCESS)
+ return;
+ DCE2_Smb2SetInfo(ssd, smb_hdr, smb_data, end);
+ break;
+ case SMB2_COM_CLOSE:
+ DebugMessage(DEBUG_DCE_SMB, "Close command.\n");
+ dce2_smb_stats.smb2_close++;
+ if (DCE2_Smb2FindTid(ssd, smb_hdr) != DCE2_RET__SUCCESS)
+ return;
+ DCE2_Smb2CloseCmd(ssd, smb_hdr, smb_data, end);
+ break;
+ case SMB2_COM_TREE_CONNECT:
+ DebugMessage(DEBUG_DCE_SMB, "Tree connect command.\n");
+ dce2_smb_stats.smb2_tree_connect++;
+ DCE2_Smb2TreeConnect(ssd, smb_hdr, smb_data, end);
+ break;
+ case SMB2_COM_TREE_DISCONNECT:
+ DebugMessage(DEBUG_DCE_SMB, "Tree disconnect command.\n");
+ dce2_smb_stats.smb2_tree_disconnect++;
+ DCE2_Smb2TreeDisconnect(ssd, smb_hdr, smb_data, end);
+ break;
+ default:
+ DebugMessage(DEBUG_DCE_SMB, "command ignored!\n");
+ break;
+ }
+}
+
+// This is the main entry point for SMB2 processing.
+void DCE2_Smb2Process(DCE2_SmbSsnData* ssd)
+{
+ Packet* p = ssd->sd.wire_pkt;
+ const uint8_t* data_ptr = p->data;
+ uint16_t data_len = p->dsize;
+ Smb2Hdr* smb_hdr;
+ const uint8_t* end = data_ptr + data_len;
+
+ /*Check header length*/
+ if (data_len < sizeof(NbssHdr) + SMB2_HEADER_LENGTH)
+ return;
+
+ if (!ssd->ftracker.is_smb2)
+ {
+ DCE2_Smb2InitFileTracker(&(ssd->ftracker), 0, 0);
+ }
+
+ /* Process the header */
+ if (p->is_pdu_start())
+ {
+ uint32_t next_command_offset;
+ smb_hdr = (Smb2Hdr*)(data_ptr + sizeof(NbssHdr));
+ next_command_offset = alignedNtohl(&(smb_hdr->next_command));
+ if (next_command_offset + sizeof(NbssHdr) > p->dsize)
+ {
+ dce_alert(GID_DCE2, DCE2_SMB_BAD_NEXT_COMMAND_OFFSET,
+ (dce2CommonStats*)&dce2_smb_stats);
+ }
+ DCE2_Smb2Inspect(ssd, (Smb2Hdr*)smb_hdr, end);
+ }
+ else if (ssd->pdu_state == DCE2_SMB_PDU_STATE__RAW_DATA)
+ {
+ /*continue processing raw data*/
+ bool upload = DCE2_SsnFromClient(ssd->sd.wire_pkt) ? true : false;
+ DCE2_Smb2ProcessFileData(ssd, data_ptr, data_len, upload);
+ ssd->ftracker.tracker.file.file_offset += data_len;
+ }
+}
+
+/* Initialize smb2 file tracker */
+DCE2_Ret DCE2_Smb2InitFileTracker(DCE2_SmbFileTracker* ftracker,
+ const bool is_ipc, const uint64_t fid)
+{
+ if (ftracker == nullptr)
+ return DCE2_RET__ERROR;
+
+ DCE2_Smb2FreeFileName(ftracker);
+ ftracker->fid_v2 = fid;
+ ftracker->is_ipc = is_ipc;
+ ftracker->is_smb2 = true;
+
+ ftracker->ff_file_size = 0;
+ ftracker->ff_file_offset = 0;
+ ftracker->ff_file_direction = DCE2_SMB_FILE_DIRECTION__UNKNOWN;
+
+ 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() &&
+ (p->dsize > sizeof(NbssHdr) + sizeof(DCE2_SMB_ID)))
+ {
+ Smb2Hdr* smb_hdr = (Smb2Hdr*)(p->data + sizeof(NbssHdr));
+ uint32_t smb_version_id = SmbId((SmbNtHdr*)smb_hdr);
+ if (smb_version_id == DCE2_SMB_ID)
+ return DCE2_SMB_VERISON_1;
+ else if (smb_version_id == DCE2_SMB2_ID)
+ return DCE2_SMB_VERISON_2;
+ }
+
+ return DCE2_SMB_VERISON_NULL;
+}
+
+void DCE2_Smb2CleanRequests(Smb2Request* requests)
+{
+ Smb2Request* request = requests;
+ while (request)
+ {
+ Smb2Request* next;
+ next = request->next;
+ snort_free((void*)request);
+ request = next;
+ }
+}
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2016 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 file processing
+// Author(s): Hui Cao <huica@cisco.com>
+
+#ifndef _DCE_SMB2_H_
+#define _DCE_SMB2_H_
+
+#include "dce_smb.h"
+#include "dce_utils.h"
+
+#define SMB2_FLAGS_ASYNC_COMMAND 0x00000002
+
+struct Smb2Hdr
+{
+ 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_sync; /* used for async and sync differently */
+ uint64_t session_id; /* identifies the established session for the command*/
+ uint8_t signature[16]; /* signature of the message */
+};
+
+struct Smb2ASyncHdr
+{
+ uint8_t smb_idf[4]; /* contains 0xFE,’SMB’ */
+ uint16_t structure_size; /* This MUST be set to 64 */
+ uint16_t credit_charge; /* # of credits that this request consumes */
+ uint32_t status; /* depends */
+ uint16_t command; /* command code */
+ uint16_t credit; /* # of credits requesting/granted */
+ uint32_t flags; /* flags */
+ uint32_t next_command; /* used for compounded request */
+ uint64_t message_id; /* identifies a message uniquely on connection */
+ uint64_t async_id; /* handle operations asynchronously */
+ uint64_t session_id; /* identifies the established session for the command*/
+ uint8_t signature[16]; /* signature of the message */
+};
+
+struct Smb2SyncHdr
+{
+ 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 */
+ uint32_t reserved; /* reserved */
+ uint32_t tree_id; /* identifies the tree connect for the command */
+ uint64_t session_id; /* identifies the established session for the command*/
+ 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*/
+};
+
+/* 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
+
+struct Smb2WriteRequestHdr
+{
+ uint16_t structure_size; /* This MUST be set to 49 */
+ uint16_t data_offset; /* offset in bytes from the beginning of smb2 header */
+ uint32_t length; /* length of data being written in bytes */
+ uint64_t offset; /* offset in the destination file */
+ uint64_t fileId_persistent; /* fileId that is persistent */
+ uint64_t fileId_volatile; /* fileId that is volatile */
+ uint32_t channel; /* channel */
+ uint32_t remaining_bytes; /* subsequent bytes the client intends to write*/
+ uint16_t write_channel_info_offset; /* channel data info */
+ uint16_t write_channel_info_length; /* channel data info */
+ uint32_t flags; /* flags*/
+};
+
+struct Smb2WriteResponseHdr
+{
+ uint16_t structure_size; /* This MUST be set to 17 */
+ uint16_t reserved; /* reserved */
+ uint32_t count; /* The number of bytes written */
+ uint32_t remaining; /* MUST be 0*/
+ uint16_t write_channel_info_offset; /* channel data info */
+ uint16_t write_channel_info_length; /* channel data info */
+};
+
+struct Smb2ReadRequestHdr
+{
+ uint16_t structure_size; /* This MUST be set to 49 */
+ uint8_t padding; /* Padding */
+ uint8_t flags; /* Flags */
+ uint32_t length; /* length of data to read from the file */
+ uint64_t offset; /* offset in the destination file */
+ uint64_t fileId_persistent; /* fileId that is persistent */
+ uint64_t fileId_volatile; /* fileId that is volatile */
+ uint32_t minimum_count; /* The minimum # of bytes to be read */
+ uint32_t channel; /* channel */
+ uint32_t remaining_bytes; /* subsequent bytes the client intends to read*/
+ uint16_t read_channel_info_offset; /* channel data info */
+ uint16_t read_channel_info_length; /* channel data info */
+};
+
+struct Smb2ReadResponseHdr
+{
+ uint16_t structure_size; /* This MUST be set to 17 */
+ uint8_t data_offset; /* offset in bytes from beginning of smb2 header*/
+ uint8_t reserved; /* reserved */
+ uint32_t length; /* The number of bytes being returned in response */
+ uint32_t remaining; /* The number of data being sent on the channel*/
+ uint32_t reserved2; /* reserved */
+};
+
+struct Smb2SetInfoRequestHdr
+{
+ uint16_t structure_size; /* This MUST be set to 33 */
+ uint8_t info_type; /* info type */
+ uint8_t file_info_class; /* file info class after header */
+ uint32_t buffer_length; /* buffer length */
+ uint16_t buffer_offset; /* buffer offset */
+ uint16_t reserved; /* reserved */
+ uint32_t additional_info; /* additional information */
+ uint64_t fileId_persistent;/* fileId that is persistent */
+ uint64_t fileId_volatile; /* fileId that is volatile */
+};
+
+struct Smb2CreateRequestHdr
+{
+ uint16_t structure_size; /* This MUST be set to 57 */
+ uint8_t security_flags; /* security flag, should be 0 */
+ uint8_t requested_oplock_level; /* */
+ uint32_t impersonation_level; /* */
+ uint64_t smb_create_flags; /* should be 0 */
+ uint64_t reserved; /* can be any value */
+ uint32_t desired_access; /* */
+ uint32_t file_attributes; /* */
+ uint32_t share_access; /* READ WRITE DELETE etc */
+ uint32_t create_disposition; /* actions when file exists*/
+ uint32_t create_options; /* options for creating file*/
+ uint16_t name_offset; /* file name offset from SMB2 header */
+ uint16_t name_length; /* length of file name */
+ uint32_t create_contexts_offset; /* offset of contexts from beginning of header */
+ uint32_t create_contexts_length; /* length of contexts */
+};
+
+struct Smb2CreateResponseHdr
+{
+ uint16_t structure_size; /* This MUST be set to 89 */
+ uint8_t oplock_level; /* oplock level granted, values limited */
+ uint8_t flags; /* flags, values limited */
+ uint32_t create_action; /* action taken, values limited */
+ uint64_t creation_time; /* time created */
+ uint64_t last_access_time; /* access time */
+ uint64_t last_write_time; /* write time */
+ uint64_t change_time; /* time modified*/
+ uint64_t allocation_size; /* size allocated */
+ uint64_t end_of_file; /* file size*/
+ uint32_t file_attributes; /* attributes of the file*/
+ uint32_t reserved2; /* */
+ uint64_t fileId_persistent; /* fileId that is persistent */
+ uint64_t fileId_volatile; /* fileId that is volatile */
+ uint32_t create_contexts_offset; /* */
+ uint32_t create_contexts_length; /* */
+};
+
+struct Smb2CloseRequestHdr
+{
+ uint16_t structure_size; /* This MUST be set to 24 */
+ uint16_t flags; /* flags */
+ uint32_t reserved; /* can be any value */
+ uint64_t fileId_persistent; /* fileId that is persistent */
+ 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 */
+ uint8_t share_type; /* type of share being accessed */
+ uint8_t reserved; /* reserved */
+ uint32_t share_flags; /* properties for this share*/
+ uint32_t capabilities; /* various capabilities for this share */
+ 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 */
+};
+
+#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_WRITE_REQUEST_STRUC_SIZE 49
+#define SMB2_WRITE_RESPONSE_STRUC_SIZE 17
+
+#define SMB2_READ_REQUEST_STRUC_SIZE 49
+#define SMB2_READ_RESPONSE_STRUC_SIZE 17
+
+#define SMB2_SET_INFO_REQUEST_STRUC_SIZE 33
+#define SMB2_SET_INFO_RESPONSE_STRUC_SIZE 2
+
+#define SMB2_TREE_CONNECT_RESPONSE_STRUC_SIZE 16
+#define SMB2_TREE_DISCONNECT_STRUC_SIZE 4
+
+#define SMB2_FILE_ENDOFFILE_INFO 0x14
+
+/* Clean up all the pending requests*/
+void DCE2_Smb2CleanRequests(Smb2Request* requests);
+
+/* Process smb2 message */
+void DCE2_Smb2Process(DCE2_SmbSsnData* ssd);
+
+/* Initialize file tracker for smb2 processing */
+DCE2_Ret DCE2_Smb2InitFileTracker(DCE2_SmbFileTracker* ftracker,
+ const bool is_ipc, const uint64_t fid);
+
+/* Check smb version based on smb header */
+DCE2_SmbVersion DCE2_Smb2Version(const Packet* p);
+
+#endif /* _DCE_SMB2_H_ */
+
"total connection-oriented server fragments reassembled" },
{ "Sessions", "total smb sessions" },
{ "Packets", "total smb packets" },
+ { "Ignored bytes", "total ignored bytes" },
{ "Client segs reassembled", "total smb client segments reassembled" },
{ "Server segs reassembled", "total smb server segments reassembled" },
{ "Max outstanding requests", "total smb maximum outstanding requests" },
{ "Files processed", "total smb files processed" },
+ { "SMBv2 create", "total number of SMBv2 create packets seen" },
+ { "SMBv2 write", "total number of SMBv2 write packets seen" },
+ { "SMBv2 read", "total number of SMBv2 read packets seen" },
+ { "SMBv2 set info", "total number of SMBv2 set info packets seen" },
+ { "SMBv2 tree connect", "total number of SMBv2 tree connect packets seen" },
+ { "SMBv2 tree disconnect", "total number of SMBv2 tree disconnect packets seen" },
+ { "SMBv2 close", "total number of SMBv2 close packets seen" },
{ nullptr, nullptr }
};
" SMB file depth for file data" },
{ "smb_invalid_shares", Parameter::PT_STRING, nullptr, nullptr,
"SMB shares to alert on " },
-
+ { "smb_legacy_mode", Parameter::PT_BOOL, nullptr, "false",
+ "inspect only SMBv1" },
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
{ DCE2_SMB_INVALID_SETUP_COUNT, DCE2_SMB_INVALID_SETUP_COUNT_STR },
{ DCE2_SMB_MULTIPLE_NEGOTIATIONS, DCE2_SMB_MULTIPLE_NEGOTIATIONS_STR },
{ DCE2_SMB_EVASIVE_FILE_ATTRS, DCE2_SMB_EVASIVE_FILE_ATTRS_STR },
+ { DCE2_SMB_INVALID_FILE_OFFSET, DCE2_SMB_INVALID_FILE_OFFSET_STR },
+ { DCE2_SMB_BAD_NEXT_COMMAND_OFFSET, DCE2_SMB_BAD_NEXT_COMMAND_OFFSET_STR },
{ 0, nullptr }
};
config.smb_file_depth = v.get_long();
else if ( v.is("smb_invalid_shares") )
return(set_smb_invalid_shares(config,v));
+ else if ( v.is("smb_legacy_mode"))
+ config.legacy_mode = v.get_bool();
else
return false;
return true;
LogMessage(" %s\n",share->ascii_str);
}
}
+ if (config.legacy_mode)
+ LogMessage(" SMB legacy mode enabled\n");
}
dce2SmbFileInspection smb_file_inspection;
int16_t smb_file_depth;
DCE2_List* smb_invalid_shares;
+ bool legacy_mode;
};
class Dce2SmbModule : public Module
& DCE2_SMB_FINGERPRINT_POLICY_SERVER ? true : false;
}
+inline bool DCE2_GcIsLegacyMode(const dce2SmbProtoConf* sc)
+{
+ if (sc == nullptr)
+ return false;
+ return sc->legacy_mode;
+}
+
#endif
/********************************************************************
* Private function prototypes
********************************************************************/
-static void DCE2_FileDetect();
static void DCE2_SmbSetNewFileAPIFileTracker(DCE2_SmbSsnData* ssd);
static void DCE2_SmbResetFileChunks(DCE2_SmbFileTracker* ssd);
static void DCE2_SmbFinishFileAPI(DCE2_SmbSsnData* ssd);
case DCE2_POLICY__SAMBA:
case DCE2_POLICY__SAMBA_3_0_37:
// Removing uid invalidates any fid that was created with it */
- if ((ssd->ftracker.fid != DCE2_SENTINEL) &&
- (ssd->ftracker.uid == uid))
+ if ((ssd->ftracker.fid_v1 != DCE2_SENTINEL) &&
+ (ssd->ftracker.uid_v1 == uid))
{
DCE2_SmbRemoveFileTracker(ssd, &ssd->ftracker);
}
ftracker != nullptr;
ftracker = (DCE2_SmbFileTracker*)DCE2_ListNext(ssd->ftrackers))
{
- if (ftracker->uid == uid)
+ if (ftracker->uid_v1 == uid)
{
if (ssd->fapi_ftracker == ftracker)
DCE2_SmbFinishFileAPI(ssd);
"with Uid: %hu, Tid: %hu, Fid: 0x%04X\n", uid, tid, fid);
DCE2_SmbFileTracker* ftracker = nullptr;
- if (ssd->ftracker.fid == DCE2_SENTINEL)
+ if (ssd->ftracker.fid_v1 == DCE2_SENTINEL)
{
ftracker = &ssd->ftracker;
if (DCE2_SmbInitFileTracker(ssd, ftracker, is_ipc, uid, tid, (int)fid) !=
if (ftracker == nullptr)
return DCE2_RET__ERROR;
- ftracker->uid = uid;
- ftracker->tid = tid;
- ftracker->fid = fid;
+ ftracker->uid_v1 = uid;
+ ftracker->tid_v1 = tid;
+ ftracker->fid_v1 = fid;
ftracker->is_ipc = is_ipc;
+ ftracker->is_smb2 = false;
ftracker->file_name = nullptr;
+ ftracker->file_name_size = 0;
if (is_ipc)
{
DCE2_CoTracker* co_tracker = (DCE2_CoTracker*)snort_calloc(sizeof(DCE2_CoTracker));
"Uid: %hu, Tid: %hu, Fid: 0x%04X ... ", uid, tid, fid);
DCE2_SmbFileTracker* ftracker;
- if ((ssd->ftracker.fid != DCE2_SENTINEL) && (ssd->ftracker.fid == (int)fid))
+ if ((ssd->ftracker.fid_v1 != DCE2_SENTINEL) && (ssd->ftracker.fid_v1 == (int)fid))
{
ftracker = &ssd->ftracker;
}
case DCE2_POLICY__SAMBA:
case DCE2_POLICY__SAMBA_3_0_37:
// Only Uid used to open file can be used to make a request
- if (ftracker->uid != uid)
+ if (ftracker->uid_v1 != uid)
{
DebugMessage(DEBUG_DCE_SMB, "Not found.\n");
return nullptr;
case DCE2_POLICY__WIN2008:
case DCE2_POLICY__WIN7:
// Both Uid and Tid used to create file must be used to make a request
- if ((ftracker->uid != uid) || (ftracker->tid != tid))
+ if ((ftracker->uid_v1 != uid) || (ftracker->tid_v1 != tid))
{
DebugMessage(DEBUG_DCE_SMB, "Not found.\n");
return nullptr;
DebugFormat(DEBUG_DCE_SMB, "Found with "
"Uid: %hu, Tid: %hu, Fid: 0x%04X\n",
- ftracker->uid, ftracker->tid, ftracker->fid);
+ ftracker->uid_v1, ftracker->tid_v1, ftracker->fid_v1);
return ftracker;
}
Profile profile(dce2_smb_pstat_smb_fid);
DebugFormat(DEBUG_DCE_SMB,
- "Removing file tracker with Fid: 0x%04X\n", ftracker->fid);
+ "Removing file tracker with Fid: 0x%04X\n", ftracker->fid_v1);
if (ssd->fapi_ftracker == ftracker)
DCE2_SmbFinishFileAPI(ssd);
if (ftracker == &ssd->ftracker)
DCE2_SmbCleanFileTracker(&ssd->ftracker);
else if (ssd->ftrackers != nullptr)
- DCE2_ListRemove(ssd->ftrackers, (void*)(uintptr_t)ftracker->fid);
+ DCE2_ListRemove(ssd->ftrackers, (void*)(uintptr_t)ftracker->fid_v1);
DCE2_SmbRemoveFileTrackerFromRequestTrackers(ssd, ftracker);
}
Profile profile(dce2_smb_pstat_smb_fid);
- ftracker->fid = DCE2_SENTINEL;
+ ftracker->fid_v1 = DCE2_SENTINEL;
if (ftracker->file_name != nullptr)
{
snort_free((void*)ftracker->file_name);
ftracker->file_name = nullptr;
+ ftracker->file_name_size = 0;
}
if (ftracker->is_ipc)
DebugFormat(DEBUG_DCE_SMB, "Freeing file tracker: "
"Uid: %hu, Tid: %hu, Fid: 0x%04X\n",
- ftracker->uid, ftracker->tid, ftracker->fid);
+ ftracker->uid_v1, ftracker->tid_v1, ftracker->fid_v1);
DCE2_SmbCleanFileTracker(ftracker);
snort_free((void*)ftracker);
return nullptr;
}
- if (ssd->ftracker.fid == DCE2_SENTINEL)
+ if (ssd->ftracker.fid_v1 == DCE2_SENTINEL)
{
memcpy(&ssd->ftracker, ftracker, sizeof(DCE2_SmbFileTracker));
snort_free((void*)ftracker);
}
// Other values were intialized when queueing.
- ftracker->fid = (int)fid;
+ ftracker->fid_v1 = (int)fid;
return ftracker;
}
DCE2_ListRemove(ssd->tids, (void*)(uintptr_t)tid);
// Removing Tid invalidates files created with it
- if ((ssd->ftracker.fid != DCE2_SENTINEL)
- && (ssd->ftracker.tid == tid))
+ if ((ssd->ftracker.fid_v1 != DCE2_SENTINEL)
+ && (ssd->ftracker.tid_v1 == tid))
{
DCE2_SmbRemoveFileTracker(ssd, &ssd->ftracker);
}
ftracker != nullptr;
ftracker = (DCE2_SmbFileTracker*)DCE2_ListNext(ssd->ftrackers))
{
- if (ftracker->tid == (int)tid)
+ if (ftracker->tid_v1 == (int)tid)
{
if (ssd->fapi_ftracker == ftracker)
DCE2_SmbFinishFileAPI(ssd);
return DCE2_RET__ERROR;
DebugFormat(DEBUG_DCE_SMB,
- "Processing request data with Fid: 0x%04X ~~~~~~~~~~~~~~~~~\n", ftracker->fid);
+ "Processing request data with Fid: 0x%04X ~~~~~~~~~~~~~~~~~\n", ftracker->fid_v1);
// Set this in case of chained commands or reassembled packet
ssd->cur_rtracker->ftracker = ftracker;
return DCE2_RET__ERROR;
DebugFormat(DEBUG_DCE_SMB,
- "Processing response data with Fid: 0x%04X ~~~~~~~~~~~~~~~~\n", ftracker->fid);
+ "Processing response data with Fid: 0x%04X ~~~~~~~~~~~~~~~~\n", ftracker->fid_v1);
if (ftracker->is_ipc)
{
nb_hdr->length = htons((uint16_t)nb_len);
- if ((ftracker != nullptr) && (ftracker->fid > 0))
+ if ((ftracker != nullptr) && (ftracker->fid_v1 > 0))
{
- uint16_t fid = (uint16_t)ftracker->fid;
+ uint16_t fid = (uint16_t)ftracker->fid_v1;
writex->smb_fid = SmbHtons(&fid);
}
else
{
DebugFormat(DEBUG_DCE_SMB, "File API returned FAILURE "
"for \"%s\" (0x%02X) %s\n", ftracker->file_name,
- ftracker->fid, upload ? "UPLOAD" : "DOWNLOAD");
+ ftracker->fid_v1, upload ? "UPLOAD" : "DOWNLOAD");
// Failure. Abort tracking this file under file API
return DCE2_RET__ERROR;
{
DebugFormat(DEBUG_DCE_SMB, "File API returned SUCCESS "
"for \"%s\" (0x%02X) %s\n", ftracker->file_name,
- ftracker->fid, upload ? "UPLOAD" : "DOWNLOAD");
+ ftracker->fid_v1, upload ? "UPLOAD" : "DOWNLOAD");
if (((position == SNORT_FILE_START) || (position == SNORT_FILE_FULL))
&& (strlen(ftracker->file_name) != 0))
(void*)file_chunk, (void*)file_chunk)) != DCE2_RET__SUCCESS)
{
DebugFormat(DEBUG_DCE_SMB, "Insert file chunk failed: "
- "0x%02X.\n", ftracker->fid);
+ "0x%02X.\n", ftracker->fid_v1);
snort_free((void*)file_chunk->data);
snort_free((void*)file_chunk);
}
}
-static void DCE2_FileDetect()
+void DCE2_FileDetect()
{
Packet* top_pkt = (Packet*)DCE2_CStackTop(dce2_pkt_stack);
if (top_pkt == nullptr)
while (ftracker != nullptr)
{
- if ((ftracker != ssd->fapi_ftracker) && (ftracker->fid != DCE2_SENTINEL)
+ if ((ftracker != ssd->fapi_ftracker) && (ftracker->fid_v1 != DCE2_SENTINEL)
&& !ftracker->is_ipc && ftracker->ff_sequential_only
&& (ftracker->ff_bytes_processed == 0))
{
DebugFormat(DEBUG_DCE_SMB, "Designating file tracker "
"for file API processing: \"%s\" (0x%04X)\n",
- ftracker->file_name, (uint16_t)ftracker->fid);
+ ftracker->file_name, (uint16_t)ftracker->fid_v1);
break;
}
void DCE2_SmbProcessFileData(DCE2_SmbSsnData* ssd,
DCE2_SmbFileTracker* ftracker, const uint8_t* data_ptr,
uint32_t data_len, bool upload);
+void DCE2_FileDetect();
/********************************************************************
* Inline functions
bool add_option_to_all(std::string option, const bool val);
bool add_option_to_all(std::string option, const int val);
bool add_option_to_type(std::string type, std::string option, std::string value);
+ bool add_option_to_type(std::string type, std::string option);
bool parse_int_and_add_to_all(std::string opt_name, std::istringstream& stream);
bool parse_string_and_add_to_type(std::string type, std::string opt_name,
std::istringstream& stream);
return tmpval;
}
+bool Dcerpc::add_option_to_type(std::string type, std::string option)
+{
+ bool tmpval = add_option_to_table(table_api, "dce_" + type, option, true);
+ for (int i=0; i < DcerpcServer::get_binding_id(); i++)
+ {
+ tmpval = add_option_to_table(table_api, "dce_" + type + std::to_string(i), option, true) &&
+ tmpval;
+ }
+
+ return tmpval;
+}
+
bool Dcerpc::add_deleted_comment_to_defaults(std::string option)
{
bool tmpval = true;
tmpval = parse_string_and_add_to_type("smb", "smb_fingerprint_policy", data_stream);
else if (!keyword.compare("smb_legacy_mode"))
- tmpval = add_deleted_comment_to_table("dce_smb", "smb_legacy_mode");
+ tmpval = add_option_to_type("smb", "smb_legacy_mode");
else
{
tmpval = false;
tmpval;
table_api.open_table("dce_smb");
}
+ if (table_api.option_exists("smb_legacy_mode"))
+ {
+ table_api.close_table();
+ tmpval = add_option_to_table(table_api,table_name["smb"], "smb_legacy_mode", true) &&
+ tmpval;
+ table_api.open_table("dce_smb");
+ }
table_api.close_table();
return tmpval;