From: Lokesh Bevinamarad (lbevinam) Date: Wed, 14 Apr 2021 15:07:29 +0000 (+0000) Subject: Merge pull request #2821 in SNORT/snort3 from ~BJANDHYA/snort3:feature/dcerpc to... X-Git-Tag: 3.1.4.0~10 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fa52d7b184aa7425bfb14426a5436f8a208e4e50;p=thirdparty%2Fsnort3.git Merge pull request #2821 in SNORT/snort3 from ~BJANDHYA/snort3:feature/dcerpc to master Squashed commit of the following: commit bddb8e4ce8aac8e8d78f3f62bf973228ac56994c Author: Bhargava Jandhyala Date: Wed Mar 31 12:21:44 2021 -0400 dce_rpc: DCERPC Support over SMBv2 --- diff --git a/src/service_inspectors/dce_rpc/dce_co.cc b/src/service_inspectors/dce_rpc/dce_co.cc index 106f787bb..5cf0e1cf1 100644 --- a/src/service_inspectors/dce_rpc/dce_co.cc +++ b/src/service_inspectors/dce_rpc/dce_co.cc @@ -29,6 +29,7 @@ #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" @@ -230,6 +231,14 @@ void DCE2_CoInitTracker(DCE2_CoTracker* cot) 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; } /******************************************************************** @@ -1350,8 +1359,7 @@ static Packet* dce_co_reassemble(DCE2_SsnData* sd, DCE2_CoTracker* cot, { 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) { @@ -2209,7 +2217,7 @@ static Packet* DCE2_CoGetSegRpkt(DCE2_SsnData* sd, if ( !rpkt ) return nullptr; - DCE2_SmbSetRdata((DCE2_SmbSsnData*)sd, const_cast(rpkt->data), + set_smb_reassembled_data(const_cast(rpkt->data), (uint16_t)(rpkt->dsize - smb_hdr_len)); break; diff --git a/src/service_inspectors/dce_rpc/dce_smb1.cc b/src/service_inspectors/dce_rpc/dce_smb1.cc index f4396e3a3..71b9a304c 100644 --- a/src/service_inspectors/dce_rpc/dce_smb1.cc +++ b/src/service_inspectors/dce_rpc/dce_smb1.cc @@ -24,6 +24,8 @@ #include "dce_smb1.h" +#include "dce_smb_utils.h" + using namespace snort; //------------------------------------------------------------------------- @@ -319,3 +321,8 @@ void Dce2Smb1SessionData::process() DCE2_Smb1Process(&ssd); } +void Dce2Smb1SessionData::set_reassembled_data(uint8_t* nb_ptr,uint16_t co_len) +{ + DCE2_SmbSetRdata(&ssd, nb_ptr, co_len); +} + diff --git a/src/service_inspectors/dce_rpc/dce_smb1.h b/src/service_inspectors/dce_rpc/dce_smb1.h index 716923e38..88bc18d92 100644 --- a/src/service_inspectors/dce_rpc/dce_smb1.h +++ b/src/service_inspectors/dce_rpc/dce_smb1.h @@ -277,6 +277,7 @@ public: { 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; diff --git a/src/service_inspectors/dce_rpc/dce_smb2.cc b/src/service_inspectors/dce_rpc/dce_smb2.cc index 553f17122..33262cb55 100644 --- a/src/service_inspectors/dce_rpc/dce_smb2.cc +++ b/src/service_inspectors/dce_rpc/dce_smb2.cc @@ -398,7 +398,23 @@ void Dce2Smb2SessionData::process_command(const Smb2Hdr* smb_hdr, 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; @@ -468,9 +484,51 @@ void Dce2Smb2SessionData::process() { 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); + } +} + diff --git a/src/service_inspectors/dce_rpc/dce_smb2.h b/src/service_inspectors/dce_rpc/dce_smb2.h index 498adf3ad..32c940934 100644 --- a/src/service_inspectors/dce_rpc/dce_smb2.h +++ b/src/service_inspectors/dce_rpc/dce_smb2.h @@ -265,6 +265,9 @@ struct Smb2TreeConnectResponseHdr #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; @@ -419,6 +422,7 @@ public: 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*); diff --git a/src/service_inspectors/dce_rpc/dce_smb2_file.cc b/src/service_inspectors/dce_rpc/dce_smb2_file.cc index 9e18e32e8..106d94cea 100644 --- a/src/service_inspectors/dce_rpc/dce_smb2_file.cc +++ b/src/service_inspectors/dce_rpc/dce_smb2_file.cc @@ -27,6 +27,7 @@ #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" @@ -100,6 +101,18 @@ bool Dce2Smb2FileTracker::process_data(const uint8_t* file_data, 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; @@ -153,8 +166,8 @@ bool Dce2Smb2FileTracker::process_data(const uint8_t* file_data, 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); diff --git a/src/service_inspectors/dce_rpc/dce_smb2_tree.cc b/src/service_inspectors/dce_rpc/dce_smb2_tree.cc index 76b3c9539..f16f41e98 100644 --- a/src/service_inspectors/dce_rpc/dce_smb2_tree.cc +++ b/src/service_inspectors/dce_rpc/dce_smb2_tree.cc @@ -188,9 +188,12 @@ void Dce2Smb2TreeTracker::process_create_response(uint64_t message_id, 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 { @@ -241,8 +244,11 @@ void Dce2Smb2TreeTracker::process_create_request(uint64_t message_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(); + 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)); } } @@ -345,6 +351,24 @@ void Dce2Smb2TreeTracker::process_write_request(uint64_t message_id, } } +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) { @@ -356,7 +380,7 @@ void Dce2Smb2TreeTracker::process(uint16_t command, uint8_t command_type, "%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); @@ -375,9 +399,8 @@ void Dce2Smb2TreeTracker::process(uint16_t command, uint8_t 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]); + "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); } @@ -418,6 +441,17 @@ void Dce2Smb2TreeTracker::process(uint16_t command, uint8_t command_type, 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); @@ -427,6 +461,13 @@ Dce2Smb2TreeTracker::~Dce2Smb2TreeTracker(void) { 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, diff --git a/src/service_inspectors/dce_rpc/dce_smb2_tree.h b/src/service_inspectors/dce_rpc/dce_smb2_tree.h index 84dfba4ee..67ff167c3 100644 --- a/src/service_inspectors/dce_rpc/dce_smb2_tree.h +++ b/src/service_inspectors/dce_rpc/dce_smb2_tree.h @@ -24,6 +24,7 @@ // 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" @@ -45,6 +46,15 @@ public: 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(); @@ -55,6 +65,9 @@ public: 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*); @@ -66,11 +79,13 @@ private: 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; diff --git a/src/service_inspectors/dce_rpc/dce_smb_common.cc b/src/service_inspectors/dce_rpc/dce_smb_common.cc index 034fbdb5d..52c49b6e4 100644 --- a/src/service_inspectors/dce_rpc/dce_smb_common.cc +++ b/src/service_inspectors/dce_rpc/dce_smb_common.cc @@ -99,8 +99,7 @@ Dce2SmbSessionData::Dce2SmbSessionData(const Packet* p, 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); @@ -196,3 +195,18 @@ char* get_smb_file_name(const uint8_t* data, uint32_t data_len, bool unicode, 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); + } + } +} + diff --git a/src/service_inspectors/dce_rpc/dce_smb_common.h b/src/service_inspectors/dce_rpc/dce_smb_common.h index 19c33384c..63484d7be 100644 --- a/src/service_inspectors/dce_rpc/dce_smb_common.h +++ b/src/service_inspectors/dce_rpc/dce_smb_common.h @@ -191,6 +191,11 @@ struct dce2SmbStats 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; }; @@ -220,6 +225,7 @@ public: 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; } @@ -244,7 +250,7 @@ public: 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: @@ -285,6 +291,7 @@ 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*); +void set_smb_reassembled_data(uint8_t*, uint16_t); #endif diff --git a/src/service_inspectors/dce_rpc/dce_smb_module.cc b/src/service_inspectors/dce_rpc/dce_smb_module.cc index b1fc1cbec..33cc952ba 100644 --- a/src/service_inspectors/dce_rpc/dce_smb_module.cc +++ b/src/service_inspectors/dce_rpc/dce_smb_module.cc @@ -178,6 +178,16 @@ static const PegInfo dce2_smb_pegs[] = "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 }