From: Michael Altizer (mialtize) Date: Thu, 29 Sep 2016 18:31:53 +0000 (-0400) Subject: Merge pull request #643 in SNORT/snort3 from dce_udp_autodetect to master X-Git-Tag: 3.0.0-233~251 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ac77266298694c8e8eb82250654e69347c2a0e67;p=thirdparty%2Fsnort3.git Merge pull request #643 in SNORT/snort3 from dce_udp_autodetect to master Squashed commit of the following: commit 75280120e229d16a4137908587d900b34ff14c15 Author: mdagon Date: Thu Sep 29 13:17:45 2016 -0400 Code review commit 378da827dc3aa45f2367b47b61fd9f176370d260 Author: mdagon Date: Tue Sep 27 15:25:47 2016 -0400 dce_udp autodetect and session creation --- diff --git a/src/main/snort_debug.h b/src/main/snort_debug.h index 540add35a..4f9ebf288 100644 --- a/src/main/snort_debug.h +++ b/src/main/snort_debug.h @@ -94,6 +94,7 @@ #define DEBUG_PIGLET 0x0800000000000000LL #endif +#define DEBUG_DCE_UDP 0x1000000000000000LL #ifdef DEBUG_MSGS @@ -102,7 +103,8 @@ class SO_PUBLIC Debug public: static bool enabled(uint64_t flag); - static void print(const char* file, int line, uint64_t dbg, const char* fmt, ...) __attribute__((format (printf, 4, 5))); + static void print(const char* file, int line, uint64_t dbg, const char* fmt, + ...) __attribute__((format (printf, 4, 5))); private: static bool init; @@ -127,3 +129,4 @@ private: #endif #endif + diff --git a/src/service_inspectors/dce_rpc/dce_udp.cc b/src/service_inspectors/dce_rpc/dce_udp.cc index 4e499716d..984561e04 100644 --- a/src/service_inspectors/dce_rpc/dce_udp.cc +++ b/src/service_inspectors/dce_rpc/dce_udp.cc @@ -40,6 +40,40 @@ THREAD_LOCAL ProfileStats dce2_udp_pstat_cl_acts; THREAD_LOCAL ProfileStats dce2_udp_pstat_cl_frag; THREAD_LOCAL ProfileStats dce2_udp_pstat_cl_reass; +void DCE2_ClCleanTracker(DCE2_ClTracker* clt) +{ + if (clt == nullptr) + return; + + /* Destroy activity trackers list - this will have the + * effect of freeing everything inside of it */ + DCE2_ListDestroy(clt->act_trackers); + clt->act_trackers = nullptr; +} + +// Tries to determine if a packet is likely to be DCE/RPC over UDP +static DCE2_TransType DCE2_UdpAutodetect(const Packet* p) +{ + if (p->dsize >= sizeof(DceRpcClHdr)) + { + const DceRpcClHdr* cl_hdr = (DceRpcClHdr*)p->data; + + if ((DceRpcClRpcVers(cl_hdr) == DCERPC_PROTO_MAJOR_VERS__4) && + ((DceRpcClPduType(cl_hdr) == DCERPC_PDU_TYPE__REQUEST) || + (DceRpcClPduType(cl_hdr) == DCERPC_PDU_TYPE__RESPONSE) || + (DceRpcClPduType(cl_hdr) == DCERPC_PDU_TYPE__FAULT) || + (DceRpcClPduType(cl_hdr) == DCERPC_PDU_TYPE__REJECT) || + (DceRpcClPduType(cl_hdr) == DCERPC_PDU_TYPE__FACK)) && + ((DceRpcClLen(cl_hdr) != 0) && + (DceRpcClLen(cl_hdr) + sizeof(DceRpcClHdr)) <= p->dsize)) + { + return DCE2_TRANS_TYPE__UDP; + } + } + + return DCE2_TRANS_TYPE__NONE; +} + //------------------------------------------------------------------------- // class stuff //------------------------------------------------------------------------- @@ -49,11 +83,91 @@ Dce2UdpFlowData::Dce2UdpFlowData() : FlowData(flow_id) Dce2UdpFlowData::~Dce2UdpFlowData() { - // FIXIT-M add cl_tracker cleanup + DCE2_ClCleanTracker(&dce2_udp_session.cl_tracker); } unsigned Dce2UdpFlowData::flow_id = 0; +DCE2_UdpSsnData* get_dce2_udp_session_data(Flow* flow) +{ + Dce2UdpFlowData* fd = (Dce2UdpFlowData*)flow->get_flow_data(Dce2UdpFlowData::flow_id); + return fd ? &fd->dce2_udp_session : nullptr; +} + +static DCE2_UdpSsnData* set_new_dce2_udp_session(Packet* p) +{ + Dce2UdpFlowData* fd = new Dce2UdpFlowData; + + memset(&fd->dce2_udp_session,0,sizeof(DCE2_UdpSsnData)); + p->flow->set_flow_data(fd); + return(&fd->dce2_udp_session); +} + +static DCE2_UdpSsnData* dce2_create_new_udp_session(Packet* p, dce2UdpProtoConf* config) +{ + DCE2_UdpSsnData* dce2_udp_sess = nullptr; + Profile profile(dce2_udp_pstat_new_session); + + // FIXIT-M re-evaluate after infrastructure/binder support if autodetect here + // is necessary + if (DCE2_UdpAutodetect(p)) + { + DebugMessage(DEBUG_DCE_UDP, "DCE over UDP packet detected\n"); + DebugMessage(DEBUG_DCE_UDP, "Creating new session\n"); + + dce2_udp_sess = set_new_dce2_udp_session(p); + + DCE2_ResetRopts(&dce2_udp_sess->sd.ropts); + + dce2_udp_stats.udp_sessions++; + DebugFormat(DEBUG_DCE_UDP,"Created (%p)\n", (void*)dce2_udp_sess); + + dce2_udp_sess->sd.trans = DCE2_TRANS_TYPE__UDP; + dce2_udp_sess->sd.wire_pkt = p; + dce2_udp_sess->sd.config = (void*)config; + + DCE2_SsnSetAutodetected(&dce2_udp_sess->sd, p); + } + + return dce2_udp_sess; +} + +static DCE2_UdpSsnData* dce2_handle_udp_session(Packet* p, dce2UdpProtoConf* config) +{ + Profile profile(dce2_udp_pstat_session); + + DCE2_UdpSsnData* dce2_udp_sess = get_dce2_udp_session_data(p->flow); + + if (dce2_udp_sess == nullptr) + { + dce2_udp_sess = dce2_create_new_udp_session(p, config); + } + else + { + DCE2_SsnData* sd = (DCE2_SsnData*)dce2_udp_sess; + sd->wire_pkt = p; + + if (DCE2_SsnAutodetected(sd) && !(p->packet_flags & sd->autodetect_dir)) + { + /* Try to autodetect in opposite direction */ + if (!DCE2_UdpAutodetect(p)) + { + DebugMessage(DEBUG_DCE_UDP, "Bad autodetect.\n"); + DCE2_SsnNoInspect(sd); + dce2_udp_stats.sessions_aborted++; + dce2_udp_stats.bad_autodetects++; + return nullptr; + } + + DCE2_SsnClearAutodetected(sd); + } + } + + DebugFormat(DEBUG_DCE_UDP, "Session pointer: %p\n", (void*)dce2_udp_sess); + + return dce2_udp_sess; +} + class Dce2Udp : public Inspector { public: @@ -75,8 +189,30 @@ void Dce2Udp::show(SnortConfig*) print_dce2_udp_conf(config); } -void Dce2Udp::eval(Packet*) +void Dce2Udp::eval(Packet* p) { + DCE2_UdpSsnData* dce2_udp_sess; + Profile profile(dce2_udp_pstat_main); + if (DCE2_SsnFromServer(p)) + { + DebugMessage(DEBUG_DCE_UDP, "Packet from Server.\n"); + } + else + { + DebugMessage(DEBUG_DCE_UDP, "Packet from Client.\n"); + } + + assert(p->flow); + + dce2_udp_sess = dce2_handle_udp_session(p, &config); + + if (dce2_udp_sess) + { + dce2_udp_stats.udp_pkts++; + + if (!DCE2_SsnAutodetected(&dce2_udp_sess->sd)) + DisableInspection(); + } } //------------------------------------------------------------------------- diff --git a/src/service_inspectors/dce_rpc/dce_udp.h b/src/service_inspectors/dce_rpc/dce_udp.h index ccf38cdc2..c084c16dd 100644 --- a/src/service_inspectors/dce_rpc/dce_udp.h +++ b/src/service_inspectors/dce_rpc/dce_udp.h @@ -75,6 +75,50 @@ extern THREAD_LOCAL ProfileStats dce2_udp_pstat_cl_acts; extern THREAD_LOCAL ProfileStats dce2_udp_pstat_cl_frag; extern THREAD_LOCAL ProfileStats dce2_udp_pstat_cl_reass; +struct DceRpcClHdr /* Connectionless header */ +{ + uint8_t rpc_vers; + uint8_t ptype; + uint8_t flags1; + uint8_t flags2; + uint8_t drep[3]; + uint8_t serial_hi; + Uuid object; + Uuid if_id; + Uuid act_id; + uint32_t server_boot; + uint32_t if_vers; + uint32_t seqnum; + uint16_t opnum; + uint16_t ihint; + uint16_t ahint; + uint16_t len; + uint16_t fragnum; + uint8_t auth_proto; + uint8_t serial_lo; + +}; + +inline uint8_t DceRpcClRpcVers(const DceRpcClHdr *cl) +{ + return cl->rpc_vers; +} + +inline uint8_t DceRpcClPduType(const DceRpcClHdr *cl) +{ + return cl->ptype; +} + +inline DceRpcBoFlag DceRpcClByteOrder(const DceRpcClHdr *cl) +{ + return DceRpcByteOrder(cl->drep[0]); +} + +inline uint16_t DceRpcClLen(const DceRpcClHdr *cl) +{ + return DceRpcNtohs(&cl->len, DceRpcClByteOrder(cl)); +} + struct DCE2_ClTracker { DCE2_List* act_trackers; /* List of activity trackers */ @@ -102,5 +146,7 @@ public: DCE2_UdpSsnData dce2_udp_session; }; +DCE2_UdpSsnData* get_dce2_udp_session_data(Flow*); + #endif diff --git a/src/service_inspectors/dce_rpc/dce_utils.h b/src/service_inspectors/dce_rpc/dce_utils.h index e821c23f5..92d0bc374 100644 --- a/src/service_inspectors/dce_rpc/dce_utils.h +++ b/src/service_inspectors/dce_rpc/dce_utils.h @@ -54,6 +54,7 @@ enum DCE2_TransType DCE2_TRANS_TYPE__NONE = 0, DCE2_TRANS_TYPE__SMB, DCE2_TRANS_TYPE__TCP, + DCE2_TRANS_TYPE__UDP, DCE2_TRANS_TYPE__MAX };