#include "dce_expected_session.h"
#include "dce_smb1.h"
+#include "dce_smb_common.h"
#include "dce_smb_module.h"
#include "dce_smb_utils.h"
#include "dce_tcp.h"
cot->frag_tracker.expected_call_id = DCE2_SENTINEL;
cot->frag_tracker.expected_opnum = DCE2_SENTINEL;
cot->frag_tracker.expected_ctx_id = DCE2_SENTINEL;
+ cot->ctx_ids = nullptr;
+ cot->pending_ctx_ids = nullptr;
+ cot->frag_tracker.cli_stub_buf = nullptr;
+ cot->frag_tracker.srv_stub_buf = nullptr;
+ cot->cli_seg.buf = nullptr;
+ cot->cli_seg.frag_len = 0;
+ cot->srv_seg.buf = nullptr;
+ cot->srv_seg.frag_len = 0;
}
/********************************************************************
{
case DCE2_RPKT_TYPE__SMB_CO_FRAG:
case DCE2_RPKT_TYPE__SMB_CO_SEG:
- DCE2_SmbSetRdata((DCE2_SmbSsnData*)sd, wrdata,
- (uint16_t)(rpkt->dsize - smb_hdr_len));
+ set_smb_reassembled_data(wrdata, (uint16_t)(rpkt->dsize - smb_hdr_len));
if (rpkt_type == DCE2_RPKT_TYPE__SMB_CO_FRAG)
{
if ( !rpkt )
return nullptr;
- DCE2_SmbSetRdata((DCE2_SmbSsnData*)sd, const_cast<uint8_t*>(rpkt->data),
+ set_smb_reassembled_data(const_cast<uint8_t*>(rpkt->data),
(uint16_t)(rpkt->dsize - smb_hdr_len));
break;
#include "dce_smb1.h"
+#include "dce_smb_utils.h"
+
using namespace snort;
//-------------------------------------------------------------------------
DCE2_Smb1Process(&ssd);
}
+void Dce2Smb1SessionData::set_reassembled_data(uint8_t* nb_ptr,uint16_t co_len)
+{
+ DCE2_SmbSetRdata(&ssd, nb_ptr, co_len);
+}
+
{ DCE2_SmbDataFree(&ssd); }
void process() override;
void handle_retransmit(FilePosition, FileVerdict) override { }
+ void set_reassembled_data(uint8_t*, uint16_t) override;
private:
DCE2_SmbSsnData ssd;
else
dce2_smb_stats.v2_session_ignored++;
break;
-
+ case SMB2_COM_IOCTL:
+ if (session)
+ {
+ if (SMB2_COMMAND_TYPE(IOCTL, REQUEST))
+ {
+ SMB2_HANDLE_HEADER_ERROR(IOCTL, REQUEST, ioctl_req)
+ session->process(command, SMB2_CMD_TYPE_REQUEST, smb_hdr, end);
+ }
+ else if ( SMB2_COMMAND_TYPE(IOCTL, RESPONSE))
+ {
+ SMB2_HANDLE_HEADER_ERROR(IOCTL, RESPONSE, ioctl_resp)
+ session->process(command, SMB2_CMD_TYPE_RESPONSE, smb_hdr, end);
+ }
+ else
+ SMB2_HANDLE_INVALID_STRUC_SIZE(ioctl)
+ }
+ break;
default:
dce2_smb_stats.v2_msgs_uninspected++;
break;
{
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());
}
}
+void Dce2Smb2SessionData::set_reassembled_data(uint8_t* nb_ptr, uint16_t co_len)
+{
+ NbssHdr* nb_hdr = (NbssHdr*)nb_ptr;
+ SmbNtHdr* smb_hdr = (SmbNtHdr*)((uint8_t*)nb_hdr + sizeof(NbssHdr));
+
+ uint32_t tid = (tcp_file_tracker) ? tcp_file_tracker->get_parent()->get_tree_id() : 0;
+ smb_hdr->smb_tid = alignedNtohl((const uint32_t*)&tid);
+
+ if (DetectionEngine::get_current_packet()->is_from_client())
+ {
+ Smb2WriteRequestHdr* write = (Smb2WriteRequestHdr*)((uint8_t*)smb_hdr + sizeof(SmbNtHdr));
+ uint32_t nb_len = sizeof(SmbNtHdr) + sizeof(Smb2WriteRequestHdr) + co_len;
+
+ if (nb_len > UINT16_MAX)
+ nb_len = UINT16_MAX;
+ write->structure_size = SMB2_WRITE_REQUEST_STRUC_SIZE;
+ nb_hdr->length = htons((uint16_t)nb_len);
+ if (tcp_file_tracker)
+ {
+ uint64_t fid = tcp_file_tracker->get_file_id();
+ write->fileId_persistent = alignedNtohq(&fid);
+ write->fileId_volatile = alignedNtohq(&fid);
+ }
+ else
+ write->fileId_persistent = write->fileId_volatile = 0;
+
+ write->length = alignedNtohs(&co_len);
+ }
+ else
+ {
+ Smb2ReadResponseHdr* read = (Smb2ReadResponseHdr*)((uint8_t*)smb_hdr + sizeof(SmbNtHdr));
+ uint32_t nb_len = sizeof(SmbNtHdr) + sizeof(Smb2ReadResponseHdr) + co_len;
+
+ if (nb_len > UINT16_MAX)
+ nb_len = UINT16_MAX;
+
+ nb_hdr->length = htons((uint16_t)nb_len);
+ read->structure_size = SMB2_READ_RESPONSE_STRUC_SIZE;
+ read->length = alignedNtohs(&co_len);
+ }
+}
+
#define SMB2_LOGOFF_REQUEST_STRUC_SIZE 4
#define SMB2_LOGOFF_RESPONSE_STRUC_SIZE 4
+#define SMB2_IOCTL_REQUEST_STRUC_SIZE 57
+#define SMB2_IOCTL_RESPONSE_STRUC_SIZE 49
+
#define GET_CURRENT_PACKET snort::DetectionEngine::get_current_packet()
class Dce2Smb2FileTracker;
void reset_matching_tcp_file_tracker(Dce2Smb2FileTracker*);
void set_tcp_file_tracker(Dce2Smb2FileTracker* file_tracker)
{ tcp_file_tracker = file_tracker; }
+ void set_reassembled_data(uint8_t*, uint16_t) override;
private:
void process_command(const Smb2Hdr*, const uint8_t*);
#include "file_api/file_flows.h"
#include "hash/hash_key_operations.h"
+#include "dce_co.h"
#include "dce_smb2_session.h"
#include "dce_smb2_tree.h"
uint32_t data_size)
{
Dce2Smb2SessionData* current_flow = parent_tree->get_parent()->get_current_flow();
+
+ if (parent_tree->get_share_type() != SMB2_SHARE_TYPE_DISK)
+ {
+ if (data_size > UINT16_MAX)
+ {
+ data_size = UINT16_MAX;
+ }
+ DCE2_CoProcess(current_flow->get_dce2_session_data(), get_parent()->get_cotracker(),
+ file_data, data_size);
+ return true;
+ }
+
int64_t file_detection_depth = current_flow->get_smb_file_depth();
int64_t detection_size = 0;
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);
+ 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);
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();
+ if (share_type == SMB2_SHARE_TYPE_DISK)
+ {
+ file_tracker->set_info(create_request->get_file_name(),
+ create_request->get_file_name_size(), file_size, true);
+ create_request->reset_file_name();
+ }
}
else
{
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();
+ if (share_type == SMB2_SHARE_TYPE_DISK)
+ {
+ 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_ioctl_command(uint8_t command_type, const Smb2Hdr* smb_header,
+ const uint8_t* end)
+{
+ const uint8_t* smb_data = (const uint8_t*)smb_header + SMB2_HEADER_LENGTH;
+ const uint8_t structure_size = (command_type == SMB2_CMD_TYPE_REQUEST) ?
+ SMB2_IOCTL_REQUEST_STRUC_SIZE : SMB2_IOCTL_RESPONSE_STRUC_SIZE;
+
+ const uint8_t* file_data = (const uint8_t*)smb_data + structure_size - 1;
+ int data_size = end - file_data;
+ Dce2Smb2SessionData* current_flow = parent_session->get_current_flow();
+ if (data_size > UINT16_MAX)
+ {
+ data_size = UINT16_MAX;
+ }
+
+ DCE2_CoProcess(current_flow->get_dce2_session_data(), co_tracker, file_data, data_size);
+}
+
void Dce2Smb2TreeTracker::process(uint16_t command, uint8_t command_type,
const Smb2Hdr* smb_header, const uint8_t* end)
{
"%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);
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]);
+ "processed 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_REQUEST == command_type)
process_write_request(message_id, smb_header, end);
break;
+ case SMB2_COM_IOCTL:
+ if (SMB2_CMD_TYPE_ERROR_RESPONSE == command_type)
+ {
+ debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
+ "%s_RESP: error\n", smb2_command_string[command]);
+ }
+ else if (SMB2_SHARE_TYPE_DISK != share_type)
+ {
+ process_ioctl_command(command_type, smb_header, end);
+ }
+ break;
}
if (SMB2_CMD_TYPE_RESPONSE == command_type or SMB2_CMD_TYPE_ERROR_RESPONSE == command_type)
remove_request(message_id);
{
debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
"tree tracker %" PRIu32 " terminating\n", tree_id);
+
+ if (co_tracker != nullptr)
+ {
+ DCE2_CoCleanTracker(co_tracker);
+ snort_free((void*)co_tracker);
+ co_tracker = nullptr;
+ }
if (active_requests.size())
{
debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
// This provides tree trackers for SMBv2.
// Tree trackers are used to identify and track an opened share
+#include "dce_co.h"
#include "dce_smb2.h"
#include "dce_smb2_file.h"
#include "dce_smb2_request.h"
debug_logf(dce_smb_trace, GET_CURRENT_PACKET,
"tree tracker %" PRIu32 " created\n", tree_id);
memory::MemoryCap::update_allocations(sizeof(*this));
+ if (share_type != SMB2_SHARE_TYPE_DISK)
+ {
+ co_tracker = (DCE2_CoTracker*)snort_calloc(sizeof(DCE2_CoTracker));
+ DCE2_CoInitTracker(co_tracker);
+ }
+ else
+ {
+ co_tracker = nullptr;
+ }
}
~Dce2Smb2TreeTracker();
Dce2Smb2RequestTracker* find_request(uint64_t);
void process(uint16_t, uint8_t, const Smb2Hdr*, const uint8_t*);
Dce2Smb2SessionTracker* get_parent() { return parent_session; }
+ DCE2_CoTracker* get_cotracker() { return co_tracker; }
+ uint32_t get_tree_id() { return tree_id; }
+ uint8_t get_share_type() { return share_type; }
private:
void process_set_info_request(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 process_ioctl_command(uint8_t, const Smb2Hdr*, const uint8_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;
+ DCE2_CoTracker* co_tracker; // Connection-oriented DCE/RPC tracker
Dce2Smb2FileTrackerMap opened_files;
Dce2Smb2RequestTrackerMap active_requests;
Dce2Smb2SessionTracker* parent_session;
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))
+ 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);
return fname;
}
+void set_smb_reassembled_data(uint8_t* nb_ptr, uint16_t co_len)
+{
+ snort::Flow* flow = DetectionEngine::get_current_packet()->flow;
+ if (flow)
+ {
+ Dce2SmbFlowData* fd = (Dce2SmbFlowData*)flow->get_flow_data(
+ Dce2SmbFlowData::inspector_id);
+ if (fd)
+ {
+ Dce2SmbSessionData* smb_ssn_data = fd->get_smb_session_data();
+ smb_ssn_data->set_reassembled_data(nb_ptr, co_len);
+ }
+ }
+}
+
PegCount v2_cmpnd_req_lt_crossed;
PegCount v2_tree_ignored;
PegCount v2_session_ignored;
+ PegCount v2_ioctl;
+ PegCount v2_ioctl_err_resp;
+ PegCount v2_ioctl_inv_str_sz;
+ PegCount v2_ioctl_req_hdr_err;
+ PegCount v2_ioctl_resp_hdr_err;
PegCount concurrent_sessions;
PegCount max_concurrent_sessions;
};
virtual void process() = 0;
virtual void handle_retransmit(FilePosition, FileVerdict) = 0;
+ virtual void set_reassembled_data(uint8_t*, uint16_t) = 0;
DCE2_SsnData* get_dce2_session_data()
{ return &sd; }
uint16_t get_smb_max_compound()
{
return sd.config ? ((dce2SmbProtoConf*)sd.config)->smb_max_compound :
- SMB_DEFAULT_MAX_COMPOUND_REQ;
+ SMB_DEFAULT_MAX_COMPOUND_REQ;
}
protected:
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*);
+void set_smb_reassembled_data(uint8_t*, uint16_t);
#endif
"total number of packets ignored due to missing tree tracker" },
{ CountType::SUM, "v2_session_ignored",
"total number of packets ignored due to missing session tracker" },
+ { CountType::SUM, "v2_ioctl",
+ "total number of ioctl calls" },
+ { CountType::SUM, "v2_ioctl_err_resp",
+ "total number of ioctl errors responses" },
+ { CountType::SUM, "v2_ioctl_inv_str_sz",
+ "total number of ioctl invalid structure size" },
+ { CountType::SUM, "v2_ioctl_req_hdr_err",
+ "total number of ioctl request header errors" },
+ { CountType::SUM, "v2_ioctl_resp_hdr_err",
+ "total number of ioctl response header errors" },
{ CountType::NOW, "concurrent_sessions", "total concurrent sessions" },
{ CountType::MAX, "max_concurrent_sessions", "maximum concurrent sessions" },
{ CountType::END, nullptr, nullptr }