From: Russ Combs (rucombs) Date: Tue, 9 Feb 2016 04:22:21 +0000 (-0500) Subject: Merge pull request #240 in SNORT/snort3 from dcerpc to master X-Git-Tag: 3.0.0-233~627 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7dada18967d3340be86171cde70bfa459a2dc701;p=thirdparty%2Fsnort3.git Merge pull request #240 in SNORT/snort3 from dcerpc to master Squashed commit of the following: commit 4f51d158cf3c8f7c2b430476c43ea446bae82c3d Author: rrp Date: Mon Feb 8 16:21:35 2016 -0500 Changes from more CR comments commit e3bf17154e79721bfc54a1b6a0e7782eb196ad7b Author: rrp Date: Mon Feb 8 09:34:27 2016 -0500 Changes based on CR feedback commit 0fa0a226f2bf45e9a006dbbbfcffd40da3cd1460 Author: rrp Date: Fri Jan 29 15:02:26 2016 -0500 DCE2 PAF and autodetect for TCP and SMB. Testing done with basic non-fragmented TCP and SMB traffic and verified with debugs that PAF and the preprocessor autodetect the packet correctly and that PAF determines the flush point correctly. Coverage between 85 and 90 %. --- diff --git a/src/main/snort_debug.h b/src/main/snort_debug.h index 7682d6b96..4365c7df2 100644 --- a/src/main/snort_debug.h +++ b/src/main/snort_debug.h @@ -79,11 +79,14 @@ #define DEBUG_MPSE 0x0010000000000000LL #define DEBUG_SO_RULE 0x0020000000000000LL #define DEBUG_LOGGER 0x0040000000000000LL +#define DEBUG_DCE_TCP 0x0080000000000000LL +#define DEBUG_DCE_SMB 0x0100000000000000LL #ifdef PIGLET -#define DEBUG_PIGLET 0x0080000000000000LL +#define DEBUG_PIGLET 0x0200000000000000LL #endif + #ifdef DEBUG_MSGS class SO_PUBLIC Debug diff --git a/src/service_inspectors/dce_rpc/CMakeLists.txt b/src/service_inspectors/dce_rpc/CMakeLists.txt index 144a9142d..d64aad138 100644 --- a/src/service_inspectors/dce_rpc/CMakeLists.txt +++ b/src/service_inspectors/dce_rpc/CMakeLists.txt @@ -1,23 +1,27 @@ set( FILE_LIST - dce2_co.h - dce2_common.cc - dce2_common.h - dce2_list.h - dce2_list.cc - dce2_smb.cc - dce2_smb.h - dce2_smb_module.cc - dce2_smb_module.h - dce2_tcp.cc - dce2_tcp.h - dce2_tcp_module.cc - dce2_tcp_module.h - dce2_utils.cc - dce2_utils.h - ips_dce2_iface.cc - ips_dce2_opnum.cc - ips_dce2_stub_data.cc + dce_co.h + dce_common.cc + dce_common.h + dce_list.h + dce_list.cc + dce_smb.cc + dce_smb.h + dce_smb_module.cc + dce_smb_module.h + dce_smb_paf.cc + dce_smb_paf.h + dce_tcp.cc + dce_tcp.h + dce_tcp_module.cc + dce_tcp_module.h + dce_tcp_paf.cc + dce_tcp_paf.h + dce_utils.cc + dce_utils.h + ips_dce_iface.cc + ips_dce_opnum.cc + ips_dce_stub_data.cc ) diff --git a/src/service_inspectors/dce_rpc/Makefile.am b/src/service_inspectors/dce_rpc/Makefile.am index f4e149883..7db794e99 100644 --- a/src/service_inspectors/dce_rpc/Makefile.am +++ b/src/service_inspectors/dce_rpc/Makefile.am @@ -1,22 +1,26 @@ file_list = \ -dce2_co.h \ -dce2_common.cc \ -dce2_common.h \ -dce2_list.cc \ -dce2_list.h \ -dce2_smb.cc \ -dce2_smb.h \ -dce2_smb_module.cc \ -dce2_smb_module.h \ -dce2_tcp.cc\ -dce2_tcp.h \ -dce2_tcp_module.cc \ -dce2_tcp_module.h \ -dce2_utils.cc \ -dce2_utils.h \ -ips_dce2_iface.cc \ -ips_dce2_opnum.cc \ -ips_dce2_stub_data.cc +dce_co.h \ +dce_common.cc \ +dce_common.h \ +dce_list.cc \ +dce_list.h \ +dce_smb.cc \ +dce_smb.h \ +dce_smb_module.cc \ +dce_smb_module.h \ +dce_smb_paf.cc \ +dce_smb_paf.h \ +dce_tcp.cc\ +dce_tcp.h \ +dce_tcp_module.cc \ +dce_tcp_module.h \ +dce_tcp_paf.cc \ +dce_tcp_paf.h \ +dce_utils.cc \ +dce_utils.h \ +ips_dce_iface.cc \ +ips_dce_opnum.cc \ +ips_dce_stub_data.cc if STATIC_INSPECTORS diff --git a/src/service_inspectors/dce_rpc/dce2_common.h b/src/service_inspectors/dce_rpc/dce2_common.h deleted file mode 100644 index 552b955a8..000000000 --- a/src/service_inspectors/dce_rpc/dce2_common.h +++ /dev/null @@ -1,69 +0,0 @@ -//-------------------------------------------------------------------------- -// Copyright (C) 2016-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. -//------------------------------------------------------------------------- - -//dce2_common.h author Rashmi Pitre - -#ifndef DCE2_COMMON_H -#define DCE2_COMMON_H - -#include "main/snort_types.h" -#include "framework/module.h" -#include "framework/inspector.h" - -extern const InspectApi dce2_smb_api; -extern const InspectApi dce2_tcp_api; - -#define GID_DCE2 145 - -enum DCE2_POLICY -{ - DCE2_POLICY__WIN2000 = 0, - DCE2_POLICY__WINXP, - DCE2_POLICY__WINVISTA, - DCE2_POLICY__WIN2003, - DCE2_POLICY__WIN2008, - DCE2_POLICY__WIN7, - DCE2_POLICY__SAMBA, - DCE2_POLICY__SAMBA_3_0_37, - DCE2_POLICY__SAMBA_3_0_22, - DCE2_POLICY__SAMBA_3_0_20, -}; - -#define DCE2_SARG__POLICY_WIN2000 "Win2000" -#define DCE2_SARG__POLICY_WINXP "WinXP" -#define DCE2_SARG__POLICY_WINVISTA "WinVista" -#define DCE2_SARG__POLICY_WIN2003 "Win2003" -#define DCE2_SARG__POLICY_WIN2008 "Win2008" -#define DCE2_SARG__POLICY_WIN7 "Win7" -#define DCE2_SARG__POLICY_SAMBA "Samba" -#define DCE2_SARG__POLICY_SAMBA_3_0_37 "Samba-3.0.37" /* Samba version 3.0.37 and previous */ -#define DCE2_SARG__POLICY_SAMBA_3_0_22 "Samba-3.0.22" /* Samba version 3.0.22 and previous */ -#define DCE2_SARG__POLICY_SAMBA_3_0_20 "Samba-3.0.20" /* Samba version 3.0.20 and previous */ - -struct dce2CommonProtoConf -{ - bool disable_defrag; - uint16_t max_frag_len; - DCE2_POLICY policy; -}; - -bool dce2_set_common_config(Value&, dce2CommonProtoConf&); -void print_dce2_common_config(dce2CommonProtoConf&); - -#endif - diff --git a/src/service_inspectors/dce_rpc/dce2_co.h b/src/service_inspectors/dce_rpc/dce_co.h similarity index 77% rename from src/service_inspectors/dce_rpc/dce2_co.h rename to src/service_inspectors/dce_rpc/dce_co.h index c46152e3a..3bcab9489 100644 --- a/src/service_inspectors/dce_rpc/dce2_co.h +++ b/src/service_inspectors/dce_rpc/dce_co.h @@ -16,11 +16,13 @@ // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. //-------------------------------------------------------------------------- -// dce2_co.h author Rashmi Pitre +// dce_co.h author Rashmi Pitre // based on work by Todd Wease -#ifndef DCE2_CO_H -#define DCE2_CO_H +#ifndef DCE_CO_H +#define DCE_CO_H + +#include "dce_common.h" #define DCE2_CO_BAD_MAJOR_VERSION 27 #define DCE2_CO_BAD_MINOR_VERSION 28 @@ -65,5 +67,52 @@ from opnum established for fragmented request." "Connection-oriented DCE/RPC - Context id of non first/last fragment different \ from context id established for fragmented request." +#pragma pack(1) + +struct DceRpcCoVersion +{ + uint8_t major; + uint8_t minor; +}; + +/* Connection oriented common header */ +struct DceRpcCoHdr +{ + DceRpcCoVersion pversion; + uint8_t ptype; + uint8_t pfc_flags; + uint8_t packed_drep[4]; + uint16_t frag_length; + uint16_t auth_length; + uint32_t call_id; +}; + +#pragma pack() + +static inline uint8_t DceRpcCoVersMaj(const DceRpcCoHdr* co) +{ + return co->pversion.major; +} + +static inline uint8_t DceRpcCoVersMin(const DceRpcCoHdr* co) +{ + return co->pversion.minor; +} + +static inline DceRpcPduType DceRpcCoPduType(const DceRpcCoHdr* co) +{ + return (DceRpcPduType)co->ptype; +} + +static inline DceRpcBoFlag DceRpcCoByteOrder(const DceRpcCoHdr* co) +{ + return DceRpcByteOrder(co->packed_drep[0]); +} + +static inline uint16_t DceRpcCoFragLen(const DceRpcCoHdr* co) +{ + return DceRpcNtohs(&co->frag_length, DceRpcCoByteOrder(co)); +} + #endif diff --git a/src/service_inspectors/dce_rpc/dce2_common.cc b/src/service_inspectors/dce_rpc/dce_common.cc similarity index 84% rename from src/service_inspectors/dce_rpc/dce2_common.cc rename to src/service_inspectors/dce_rpc/dce_common.cc index 76781354d..09d237336 100644 --- a/src/service_inspectors/dce_rpc/dce2_common.cc +++ b/src/service_inspectors/dce_rpc/dce_common.cc @@ -16,12 +16,14 @@ // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. //-------------------------------------------------------------------------- -// dce2_common.cc author Rashmi Pitre +// dce_common.cc author Rashmi Pitre -#include "dce2_common.h" -#include "framework/module.h" +#include "dce_common.h" #include "framework/base_api.h" +#include "framework/module.h" +#include "flow/flow.h" #include "log/messages.h" +#include "main/snort_debug.h" const char* dce2_get_policy_name(DCE2_POLICY policy) { @@ -90,6 +92,25 @@ void print_dce2_common_config(dce2CommonProtoConf& common) dce2_get_policy_name(common.policy)); } +bool dce2_paf_abort(Flow* flow) +{ + if (flow->get_session_flags() & SSNFLAG_MIDSTREAM) + { + DebugMessage(DEBUG_DCE_TCP, + "Aborting PAF because of midstream pickup.\n"); + return true; + } + else if (!(flow->get_session_flags() & SSNFLAG_ESTABLISHED)) + { + DebugMessage(DEBUG_DCE_TCP, + "Aborting PAF because of unestablished session.\n"); + return true; + } + // FIXIT-M add the remaining checks + + return false; +} + #ifdef BUILDING_SO extern const BaseApi* ips_dce_iface; diff --git a/src/service_inspectors/dce_rpc/dce_common.h b/src/service_inspectors/dce_rpc/dce_common.h new file mode 100644 index 000000000..637162ca2 --- /dev/null +++ b/src/service_inspectors/dce_rpc/dce_common.h @@ -0,0 +1,194 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2016-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. +//------------------------------------------------------------------------- + +//dce_common.h author Rashmi Pitre + +#ifndef DCE_COMMON_H +#define DCE_COMMON_H + +#include "dce_utils.h" +#include "main/snort_types.h" +#include "framework/module.h" +#include "framework/inspector.h" + +extern const InspectApi dce2_smb_api; +extern const InspectApi dce2_tcp_api; + +#define GID_DCE2 145 + +enum DCE2_POLICY +{ + DCE2_POLICY__WIN2000 = 0, + DCE2_POLICY__WINXP, + DCE2_POLICY__WINVISTA, + DCE2_POLICY__WIN2003, + DCE2_POLICY__WIN2008, + DCE2_POLICY__WIN7, + DCE2_POLICY__SAMBA, + DCE2_POLICY__SAMBA_3_0_37, + DCE2_POLICY__SAMBA_3_0_22, + DCE2_POLICY__SAMBA_3_0_20, +}; + +#define DCE2_SARG__POLICY_WIN2000 "Win2000" +#define DCE2_SARG__POLICY_WINXP "WinXP" +#define DCE2_SARG__POLICY_WINVISTA "WinVista" +#define DCE2_SARG__POLICY_WIN2003 "Win2003" +#define DCE2_SARG__POLICY_WIN2008 "Win2008" +#define DCE2_SARG__POLICY_WIN7 "Win7" +#define DCE2_SARG__POLICY_SAMBA "Samba" +#define DCE2_SARG__POLICY_SAMBA_3_0_37 "Samba-3.0.37" /* Samba version 3.0.37 and previous */ +#define DCE2_SARG__POLICY_SAMBA_3_0_22 "Samba-3.0.22" /* Samba version 3.0.22 and previous */ +#define DCE2_SARG__POLICY_SAMBA_3_0_20 "Samba-3.0.20" /* Samba version 3.0.20 and previous */ + +struct dce2CommonProtoConf +{ + bool disable_defrag; + uint16_t max_frag_len; + DCE2_POLICY policy; +}; + +#define DCE2_DEBUG__PAF_END_MSG "==========================================================" + +/* DCE/RPC byte order flag */ +enum DceRpcBoFlag +{ + DCERPC_BO_FLAG__NONE, + DCERPC_BO_FLAG__BIG_ENDIAN, + DCERPC_BO_FLAG__LITTLE_ENDIAN +}; + +enum DceRpcPduType +{ + DCERPC_PDU_TYPE__REQUEST = 0, + DCERPC_PDU_TYPE__PING, + DCERPC_PDU_TYPE__RESPONSE, + DCERPC_PDU_TYPE__FAULT, + DCERPC_PDU_TYPE__WORKING, + DCERPC_PDU_TYPE__NOCALL, + DCERPC_PDU_TYPE__REJECT, + DCERPC_PDU_TYPE__ACK, + DCERPC_PDU_TYPE__CL_CANCEL, + DCERPC_PDU_TYPE__FACK, + DCERPC_PDU_TYPE__CANCEL_ACK, + DCERPC_PDU_TYPE__BIND, + DCERPC_PDU_TYPE__BIND_ACK, + DCERPC_PDU_TYPE__BIND_NACK, + DCERPC_PDU_TYPE__ALTER_CONTEXT, + DCERPC_PDU_TYPE__ALTER_CONTEXT_RESP, + DCERPC_PDU_TYPE__AUTH3, + DCERPC_PDU_TYPE__SHUTDOWN, + DCERPC_PDU_TYPE__CO_CANCEL, + DCERPC_PDU_TYPE__ORPHANED, + DCERPC_PDU_TYPE__MICROSOFT_PROPRIETARY_OUTLOOK2003_RPC_OVER_HTTP, + DCERPC_PDU_TYPE__MAX +}; + +/* Version 4 is for Connectionless + * Version 5 is for Connection oriented */ +enum DceRpcProtoMajorVers +{ + DCERPC_PROTO_MAJOR_VERS__4 = 4, + DCERPC_PROTO_MAJOR_VERS__5 = 5 +}; + +enum DceRpcProtoMinorVers +{ + DCERPC_PROTO_MINOR_VERS__0 = 0, + DCERPC_PROTO_MINOR_VERS__1 = 1 +}; + +struct DCE2_Roptions +{ + /* dce_iface */ + int first_frag; /* Set to sentinel if not applicable */ + Uuid iface; + /* For connectionless */ + uint32_t iface_vers; /* For connectionless */ + + /* For connection-oriented */ + uint16_t iface_vers_maj; + uint16_t iface_vers_min; + + /* dce_opnum */ + int opnum; /* Set to sentinel if not applicable */ + + /* dce_byte_test */ + int hdr_byte_order; /* Set to sentinel if not applicable */ + int data_byte_order; /* Set to sentinel if not applicable */ + + /* dce_stub_data */ + const uint8_t* stub_data; /* Set to NULL if not applicable */ +}; + +struct DCE2_SsnData +{ + DCE2_POLICY server_policy; + DCE2_POLICY client_policy; + int flags; + const Packet* wire_pkt; + uint64_t alert_mask; + DCE2_Roptions ropts; + int autodetect_dir; + + uint32_t cli_seq; + uint32_t cli_nseq; + uint32_t srv_seq; + uint32_t srv_nseq; +}; + +inline DceRpcBoFlag DceRpcByteOrder(const uint8_t value) +{ + if ((value & 0x10) >> 4) + return DCERPC_BO_FLAG__LITTLE_ENDIAN; + + return DCERPC_BO_FLAG__BIG_ENDIAN; +} + +inline uint16_t DceRpcNtohs(const uint16_t* ptr, const DceRpcBoFlag bo_flag) +{ + uint16_t value; + + if (ptr == NULL) + return 0; + +#ifdef WORDS_MUSTALIGN + value = *((uint8_t*)ptr) << 8 | *((uint8_t*)ptr + 1); +#else + value = *ptr; +#endif /* WORDS_MUSTALIGN */ + + if (bo_flag == DCERPC_BO_FLAG__NONE) + return value; + +#ifdef WORDS_BIGENDIAN + if (bo_flag == DCERPC_BO_FLAG__BIG_ENDIAN) +#else + if (bo_flag == DCERPC_BO_FLAG__LITTLE_ENDIAN) +#endif /* WORDS_BIGENDIAN */ + return value; + + return ((value & 0xff00) >> 8) | ((value & 0x00ff) << 8); +} + +bool dce2_set_common_config(Value&, dce2CommonProtoConf&); +void print_dce2_common_config(dce2CommonProtoConf&); +bool dce2_paf_abort(Flow*); + +#endif + diff --git a/src/service_inspectors/dce_rpc/dce2_list.cc b/src/service_inspectors/dce_rpc/dce_list.cc similarity index 99% rename from src/service_inspectors/dce_rpc/dce2_list.cc rename to src/service_inspectors/dce_rpc/dce_list.cc index b8114d499..bc484f331 100644 --- a/src/service_inspectors/dce_rpc/dce2_list.cc +++ b/src/service_inspectors/dce_rpc/dce_list.cc @@ -25,8 +25,8 @@ * ****************************************************************************/ -#include "dce2_list.h" -#include "dce2_utils.h" +#include "dce_list.h" +#include "dce_utils.h" #include "log/messages.h" #include "utils/util.h" diff --git a/src/service_inspectors/dce_rpc/dce2_list.h b/src/service_inspectors/dce_rpc/dce_list.h similarity index 98% rename from src/service_inspectors/dce_rpc/dce2_list.h rename to src/service_inspectors/dce_rpc/dce_list.h index cd55b35a5..e0be02d30 100644 --- a/src/service_inspectors/dce_rpc/dce2_list.h +++ b/src/service_inspectors/dce_rpc/dce_list.h @@ -25,10 +25,10 @@ * ****************************************************************************/ -#ifndef _DCE2_LIST_H_ -#define _DCE2_LIST_H_ +#ifndef _DCE_LIST_H_ +#define _DCE_LIST_H_ -#include "dce2_utils.h" +#include "dce_utils.h" #include "main/snort_types.h" diff --git a/src/service_inspectors/dce_rpc/dce2_smb.cc b/src/service_inspectors/dce_rpc/dce_smb.cc similarity index 83% rename from src/service_inspectors/dce_rpc/dce2_smb.cc rename to src/service_inspectors/dce_rpc/dce_smb.cc index 0bd9fc176..90fe7f531 100644 --- a/src/service_inspectors/dce_rpc/dce2_smb.cc +++ b/src/service_inspectors/dce_rpc/dce_smb.cc @@ -18,9 +18,11 @@ // dce_smb.cc author Rashmi Pitre -#include "dce2_smb.h" -#include "dce2_smb_module.h" -#include "dce2_list.h" +#include "dce_smb.h" +#include "dce_smb_paf.h" +#include "dce_smb_module.h" +#include "dce_list.h" +#include "main/snort_debug.h" THREAD_LOCAL dce2SmbStats dce2_smb_stats; @@ -45,6 +47,16 @@ THREAD_LOCAL ProfileStats dce2_smb_pstat_smb_file_api; THREAD_LOCAL ProfileStats dce2_smb_pstat_smb_fingerprint; THREAD_LOCAL ProfileStats dce2_smb_pstat_smb_negotiate; +unsigned Dce2SmbFlowData::flow_id = 0; + +DCE2_SmbSsnData* get_dce2_smb_session_data(Flow* flow) +{ + Dce2SmbFlowData* fd = (Dce2SmbFlowData*)flow->get_application_data( + Dce2SmbFlowData::flow_id); + + return fd ? &fd->dce2_smb_session : nullptr; +} + //------------------------------------------------------------------------- // class stuff //------------------------------------------------------------------------- @@ -57,6 +69,10 @@ public: void show(SnortConfig*) override; void eval(Packet*) override; + StreamSplitter* get_splitter(bool c2s) override + { + return new Dce2SmbSplitter(c2s); + } private: dce2SmbProtoConf config; @@ -82,7 +98,17 @@ void Dce2Smb::show(SnortConfig*) void Dce2Smb::eval(Packet* p) { - UNUSED(p); + DCE2_SmbSsnData* dce2_sess = get_dce2_smb_session_data(p->flow); + + if (dce2_sess == nullptr) + { + /*Check if it is a DCE2 over SMB packet*/ + + if (DCE2_SmbAutodetect(p)) + { + DebugMessage(DEBUG_DCE_SMB, "DCE over SMB packet detected\n"); + } + } } //------------------------------------------------------------------------- diff --git a/src/service_inspectors/dce_rpc/dce2_smb.h b/src/service_inspectors/dce_rpc/dce_smb.h similarity index 72% rename from src/service_inspectors/dce_rpc/dce2_smb.h rename to src/service_inspectors/dce_rpc/dce_smb.h index f162ce68f..1e42653f9 100644 --- a/src/service_inspectors/dce_rpc/dce2_smb.h +++ b/src/service_inspectors/dce_rpc/dce_smb.h @@ -16,12 +16,13 @@ // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. //-------------------------------------------------------------------------- -//dce2_smb.h author Rashmi Pitre +//dce_smb.h author Rashmi Pitre // based on work by Todd Wease -#ifndef DCE2_SMB_H -#define DCE2_SMB_H +#ifndef DCE_SMB_H +#define DCE_SMB_H +#include "dce_common.h" #include "protocols/packet.h" #include "profiler/profiler.h" #include "framework/counts.h" @@ -199,5 +200,128 @@ extern THREAD_LOCAL ProfileStats dce2_smb_pstat_smb_file_detect; extern THREAD_LOCAL ProfileStats dce2_smb_pstat_smb_file_api; extern THREAD_LOCAL ProfileStats dce2_smb_pstat_smb_fingerprint; extern THREAD_LOCAL ProfileStats dce2_smb_pstat_smb_negotiate; + +#define NBSS_SESSION_TYPE__MESSAGE 0x00 +#define NBSS_SESSION_TYPE__REQUEST 0x81 +#define NBSS_SESSION_TYPE__POS_RESPONSE 0x82 +#define NBSS_SESSION_TYPE__NEG_RESPONSE 0x83 +#define NBSS_SESSION_TYPE__RETARGET_RESPONSE 0x84 +#define NBSS_SESSION_TYPE__KEEP_ALIVE 0x85 + +#define DCE2_SMB_ID 0xff534d42 /* \xffSMB */ +#define DCE2_SMB2_ID 0xfe534d42 /* \xfeSMB */ + +#pragma pack(1) + +/******************************************************************** + * NetBIOS Session Service header + ********************************************************************/ +struct NbssHdr +{ + uint8_t type; + uint8_t flags; /* Treat flags as the upper byte to length */ + uint16_t length; +} ; + +struct SmbNtHdr +{ + uint8_t smb_idf[4]; /* contains 0xFF, 'SMB' */ + uint8_t smb_com; /* command code */ + union + { + struct + { + uint8_t smb_class; /* dos error class */ + uint8_t smb_res; /* reserved for future */ + uint16_t smb_code; /* dos error code */ + } smb_status; + uint32_t nt_status; /* nt status */ + } smb_status; + uint8_t smb_flg; /* flags */ + uint16_t smb_flg2; /* flags */ + uint16_t smb_pid_high; + uint64_t smb_signature; + uint16_t smb_res; /* reserved for future */ + uint16_t smb_tid; /* tree id */ + uint16_t smb_pid; /* caller's process id */ + uint16_t smb_uid; /* authenticated user id */ + uint16_t smb_mid; /* multiplex id */ +}; + +#pragma pack() + +struct DCE2_SmbSsnData +{ + DCE2_SsnData sd; // This member must be first + // FIXIT-M add all the remaining fields +}; + +static inline uint32_t NbssLen(const NbssHdr* nb) +{ + /* Treat first bit of flags as the upper byte to length */ + return ((nb->flags & 0x01) << 16) | ntohs(nb->length); +} + +static inline uint8_t NbssType(const NbssHdr* nb) +{ + return nb->type; +} + +static inline uint32_t SmbId(const SmbNtHdr* hdr) +{ +#ifdef WORDS_MUSTALIGN + uint8_t* idf = (uint8_t*)hdr->smb_idf; + return *idf << 24 | *(idf + 1) << 16 | *(idf + 2) << 8 | *(idf + 3); +#else + return ntohl(*((uint32_t*)hdr->smb_idf)); +#endif /* WORDS_MUSTALIGN */ +} + +static inline bool DCE2_SmbAutodetect(Packet* p) +{ + if (p->dsize > (sizeof(NbssHdr) + sizeof(SmbNtHdr))) + { + NbssHdr* nb_hdr = (NbssHdr*)p->data; + + switch (NbssType(nb_hdr)) + { + case NBSS_SESSION_TYPE__MESSAGE: + { + SmbNtHdr* smb_hdr = (SmbNtHdr*)(p->data + sizeof(NbssHdr)); + + if ((SmbId(smb_hdr) == DCE2_SMB_ID) + || (SmbId(smb_hdr) == DCE2_SMB2_ID)) + { + return true; + } + } + + break; + + default: + break; + } + } + + return false; +} + +class Dce2SmbFlowData : public FlowData +{ +public: + Dce2SmbFlowData(); + + static void init() + { + flow_id = FlowData::get_flow_id(); + } + +public: + static unsigned flow_id; + DCE2_SmbSsnData dce2_smb_session; +}; + +DCE2_SmbSsnData* get_dce2_smb_session_data(Flow*); + #endif diff --git a/src/service_inspectors/dce_rpc/dce2_smb_module.cc b/src/service_inspectors/dce_rpc/dce_smb_module.cc similarity index 99% rename from src/service_inspectors/dce_rpc/dce2_smb_module.cc rename to src/service_inspectors/dce_rpc/dce_smb_module.cc index c293cf06f..15034100e 100644 --- a/src/service_inspectors/dce_rpc/dce2_smb_module.cc +++ b/src/service_inspectors/dce_rpc/dce_smb_module.cc @@ -18,10 +18,10 @@ // dce_smb_module.cc author Rashmi Pitre -#include "dce2_smb_module.h" -#include "dce2_smb.h" -#include "dce2_common.h" -#include "dce2_co.h" +#include "dce_smb_module.h" +#include "dce_smb.h" +#include "dce_common.h" +#include "dce_co.h" #include "main/snort_config.h" diff --git a/src/service_inspectors/dce_rpc/dce2_smb_module.h b/src/service_inspectors/dce_rpc/dce_smb_module.h similarity index 94% rename from src/service_inspectors/dce_rpc/dce2_smb_module.h rename to src/service_inspectors/dce_rpc/dce_smb_module.h index eb9028497..327ddc47a 100644 --- a/src/service_inspectors/dce_rpc/dce2_smb_module.h +++ b/src/service_inspectors/dce_rpc/dce_smb_module.h @@ -16,14 +16,14 @@ // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. //-------------------------------------------------------------------------- // -// dce2_smb_module.h author Rashmi Pitre +// dce_smb_module.h author Rashmi Pitre -#ifndef DCE2_SMB_MODULE_H -#define DCE2_SMB_MODULE_H +#ifndef DCE_SMB_MODULE_H +#define DCE_SMB_MODULE_H -#include "dce2_common.h" +#include "dce_common.h" #include "framework/module.h" -#include "dce2_list.h" +#include "dce_list.h" struct SnortConfig; diff --git a/src/service_inspectors/dce_rpc/dce_smb_paf.cc b/src/service_inspectors/dce_rpc/dce_smb_paf.cc new file mode 100644 index 000000000..2159aedd0 --- /dev/null +++ b/src/service_inspectors/dce_rpc/dce_smb_paf.cc @@ -0,0 +1,184 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2016-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. +//-------------------------------------------------------------------------- + +// dce_smb_paf.cc author Rashmi Pitre +// based on work by Todd Wease + +#include "dce_smb_paf.h" +#include "dce_smb.h" +#include "dce_common.h" +#include "main/snort_debug.h" +#include "protocols/packet.h" + +/********************************************************************* + * Function: DCE2_PafSmbIsValidNetbiosHdr() + * + * Purpose: Validates that the NetBIOS header is valid. If in + * junk states, header type must be Session Message. + * + *********************************************************************/ +static inline bool DCE2_PafSmbIsValidNetbiosHdr(uint32_t nb_hdr, bool junk) +{ + uint8_t type = (uint8_t)(nb_hdr >> 24); + uint8_t bit = (uint8_t)((nb_hdr & 0x00ff0000) >> 16); + + if (junk) + { + if (type != NBSS_SESSION_TYPE__MESSAGE) + return false; + } + else + { + switch (type) + { + case NBSS_SESSION_TYPE__MESSAGE: + case NBSS_SESSION_TYPE__REQUEST: + case NBSS_SESSION_TYPE__POS_RESPONSE: + case NBSS_SESSION_TYPE__NEG_RESPONSE: + case NBSS_SESSION_TYPE__RETARGET_RESPONSE: + case NBSS_SESSION_TYPE__KEEP_ALIVE: + break; + default: + return false; + } + } + + if ((bit != 0x00) && (bit != 0x01)) + return false; + + return true; +} + +/********************************************************************* + * Function: DCE2_SmbPaf() + * + * Purpose: The DCE/RPC over SMB PAF callback. + * Inspects a byte at a time changing state and shifting + * bytes onto the 64bit nb_hdr member. At state 3 + * determines if NetBIOS header is valid and if so sets + * flush point. If not valid goes to states 4-7 where + * there is the possibility that junk data was inserted + * before request/response. Needs to validate SMB ID at + * this point. At state 7 determines if NetBIOS header + * is valid and that the SMB ID is present. Stays in + * state 7 until this is the case. + * + *********************************************************************/ +StreamSplitter::Status dce2_smb_paf(DCE2_PafSmbData* ss, Flow* flow, const uint8_t* data, + uint32_t len, uint32_t flags, uint32_t* fp) +{ + uint32_t n = 0; + StreamSplitter::Status ps = StreamSplitter::SEARCH; + uint32_t nb_hdr; + uint32_t nb_len; + + DebugFormat(DEBUG_DCE_SMB, "%s\n", DCE2_DEBUG__PAF_START_MSG_SMB); + DebugFormat(DEBUG_DCE_SMB, "SMB: %u bytes of data\n", len); + + if (flags & PKT_FROM_CLIENT) + DebugMessage(DEBUG_DCE_SMB, "Packet from Client\n"); + else + DebugMessage(DEBUG_DCE_SMB, "Packet from Server\n"); + + if (dce2_paf_abort(flow)) + { + DebugFormat(DEBUG_DCE_SMB, "%s\n", DCE2_DEBUG__PAF_END_MSG); + return StreamSplitter::ABORT; + } + + DebugFormat(DEBUG_DCE_SMB, "Start state: %u\n", ss->paf_state); + + while (n < len) + { + DebugFormat(DEBUG_DCE_SMB, " State %d : 0x%02x", ss->paf_state, data[n]); + + switch (ss->paf_state) + { + case DCE2_PAF_SMB_STATES__0: + ss->nb_hdr = (uint64_t)data[n]; + ss->paf_state = (DCE2_PafSmbStates)(((int)ss->paf_state) + 1); + break; + case DCE2_PAF_SMB_STATES__3: + DCE2_SMB_PAF_SHIFT(ss->nb_hdr, data[n]); + if (DCE2_PafSmbIsValidNetbiosHdr((uint32_t)ss->nb_hdr, false)) + { + nb_hdr = htonl((uint32_t)ss->nb_hdr); + nb_len = NbssLen((const NbssHdr*)&nb_hdr); + *fp = (nb_len + sizeof(NbssHdr) + n) - ss->paf_state; + ss->paf_state = DCE2_PAF_SMB_STATES__0; + DebugFormat(DEBUG_DCE_SMB, + "Setting flush point: %u\n", *fp); + DebugFormat(DEBUG_DCE_SMB, "%s\n", DCE2_DEBUG__PAF_END_MSG); + return StreamSplitter::FLUSH; + } + DebugMessage(DEBUG_DCE_SMB, "Invalid NetBIOS header - " + "entering junk data states.\n"); + ss->paf_state = (DCE2_PafSmbStates)(((int)ss->paf_state) + 1); + break; + case DCE2_PAF_SMB_STATES__7: + DCE2_SMB_PAF_SHIFT(ss->nb_hdr, data[n]); + + if (!DCE2_PafSmbIsValidNetbiosHdr((uint32_t)(ss->nb_hdr >> 32), true)) + { + DebugMessage(DEBUG_DCE_SMB, "Invalid NetBIOS header - " + "staying in State 7.\n"); + break; + } + if (((uint32_t)ss->nb_hdr != DCE2_SMB_ID) + && ((uint32_t)ss->nb_hdr != DCE2_SMB2_ID)) + { + DebugMessage(DEBUG_DCE_SMB, "Invalid SMB ID - " + "staying in State 7.\n"); + break; + } + + nb_hdr = htonl((uint32_t)(ss->nb_hdr >> 32)); + nb_len = NbssLen((const NbssHdr*)&nb_hdr); + *fp = (nb_len + sizeof(NbssHdr) + n) - ss->paf_state; + DebugFormat(DEBUG_DCE_SMB, + "Setting flush point: %u\n", *fp); + ss->paf_state = DCE2_PAF_SMB_STATES__0; + DebugFormat(DEBUG_DCE_SMB, "%s\n", DCE2_DEBUG__PAF_END_MSG); + return StreamSplitter::FLUSH; + default: + DCE2_SMB_PAF_SHIFT(ss->nb_hdr, data[n]); + ss->paf_state = (DCE2_PafSmbStates)(((int)ss->paf_state) + 1); + break; + } + + n++; + } + + DebugFormat(DEBUG_DCE_SMB, "%s\n", DCE2_DEBUG__PAF_END_MSG); + return ps; +} + +Dce2SmbSplitter::Dce2SmbSplitter(bool c2s) : StreamSplitter(c2s) +{ + state.paf_state = DCE2_PAF_SMB_STATES__0; + state.nb_hdr = 0; +} + +StreamSplitter::Status Dce2SmbSplitter::scan( + Flow* flow, const uint8_t* data, uint32_t len, + uint32_t flags, uint32_t* fp) +{ + DCE2_PafSmbData* pfdata = &state; + return dce2_smb_paf(pfdata, flow, data, len, flags, fp); +} + diff --git a/src/service_inspectors/dce_rpc/dce_smb_paf.h b/src/service_inspectors/dce_rpc/dce_smb_paf.h new file mode 100644 index 000000000..0f783ad75 --- /dev/null +++ b/src/service_inspectors/dce_rpc/dce_smb_paf.h @@ -0,0 +1,71 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2016-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. +//-------------------------------------------------------------------------- + +// dce_smb_paf.h author Rashmi Pitre +// based on work by Todd Wease + +#ifndef DCE_SMB_PAF_H +#define DCE_SMB_PAF_H + +#include "main/snort_types.h" +#include "stream/stream_api.h" +#include "stream/stream_splitter.h" + +#define DCE2_SMB_PAF_SHIFT(x64, x8) { x64 <<= 8; x64 |= (uint64_t)x8; } +#define DCE2_DEBUG__PAF_START_MSG_SMB "DCE/RPC over SMB PAF =====================================" + +// Enumerations for PAF states +enum DCE2_PafSmbStates +{ + DCE2_PAF_SMB_STATES__0 = 0, // NetBIOS type + DCE2_PAF_SMB_STATES__1, // Added bit of NetBIOS length + DCE2_PAF_SMB_STATES__2, // First byte of NetBIOS length + DCE2_PAF_SMB_STATES__3, // Second byte of NetBIOS length + // Junk states + DCE2_PAF_SMB_STATES__4, // 0xff + DCE2_PAF_SMB_STATES__5, // 'S' + DCE2_PAF_SMB_STATES__6, // 'M' + DCE2_PAF_SMB_STATES__7 // 'B' +}; + +// State tracker for DCE/RPC over SMB PAF +struct DCE2_PafSmbData +{ + DCE2_PafSmbStates paf_state; + uint64_t nb_hdr; // Enough for NetBIOS header and 4 bytes SMB header +}; + +class Dce2SmbSplitter : public StreamSplitter +{ +public: + Dce2SmbSplitter(bool c2s); + + Status scan(Flow*, const uint8_t* data, uint32_t len, + uint32_t flags, uint32_t* fp) override; + + bool is_paf() override + { + return true; + } + +public: + DCE2_PafSmbData state; +}; + +#endif + diff --git a/src/service_inspectors/dce_rpc/dce2_tcp.cc b/src/service_inspectors/dce_rpc/dce_tcp.cc similarity index 79% rename from src/service_inspectors/dce_rpc/dce2_tcp.cc rename to src/service_inspectors/dce_rpc/dce_tcp.cc index 45c003533..77e6fe830 100644 --- a/src/service_inspectors/dce_rpc/dce2_tcp.cc +++ b/src/service_inspectors/dce_rpc/dce_tcp.cc @@ -16,11 +16,13 @@ // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. //-------------------------------------------------------------------------- -// dce2_tcp.cc author Rashmi Pitre +// dce_tcp.cc author Rashmi Pitre // based on work by Todd Wease -#include "dce2_tcp.h" -#include "dce2_tcp_module.h" +#include "dce_tcp.h" +#include "dce_tcp_paf.h" +#include "dce_tcp_module.h" +#include "main/snort_debug.h" THREAD_LOCAL dce2TcpStats dce2_tcp_stats; @@ -35,6 +37,16 @@ THREAD_LOCAL ProfileStats dce2_tcp_pstat_co_frag; THREAD_LOCAL ProfileStats dce2_tcp_pstat_co_reass; THREAD_LOCAL ProfileStats dce2_tcp_pstat_co_ctx; +unsigned Dce2TcpFlowData::flow_id = 0; + +DCE2_TcpSsnData* get_dce2_tcp_session_data(Flow* flow) +{ + Dce2TcpFlowData* fd = (Dce2TcpFlowData*)flow->get_application_data( + Dce2TcpFlowData::flow_id); + + return fd ? &fd->dce2_tcp_session : nullptr; +} + //------------------------------------------------------------------------- // class stuff //------------------------------------------------------------------------- @@ -46,6 +58,10 @@ public: void show(SnortConfig*) override; void eval(Packet*) override; + StreamSplitter* get_splitter(bool c2s) override + { + return new Dce2TcpSplitter(c2s); + } private: dce2TcpProtoConf config; @@ -63,7 +79,18 @@ void Dce2Tcp::show(SnortConfig*) void Dce2Tcp::eval(Packet* p) { - UNUSED(p); + DCE2_TcpSsnData* dce2_sess = get_dce2_tcp_session_data(p->flow); + + if (dce2_sess == nullptr) + { + /*Check if it is a DCE2 over TCP packet*/ + + if (DCE2_TcpAutodetect(p)) + { + DebugMessage(DEBUG_DCE_TCP, "DCE over TCP packet detected\n"); + } + + } } //------------------------------------------------------------------------- diff --git a/src/service_inspectors/dce_rpc/dce2_tcp.h b/src/service_inspectors/dce_rpc/dce_tcp.h similarity index 69% rename from src/service_inspectors/dce_rpc/dce2_tcp.h rename to src/service_inspectors/dce_rpc/dce_tcp.h index 699cc385e..a24d13aee 100644 --- a/src/service_inspectors/dce_rpc/dce2_tcp.h +++ b/src/service_inspectors/dce_rpc/dce_tcp.h @@ -16,12 +16,13 @@ // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. //-------------------------------------------------------------------------- -//dce2_tcp.h author Rashmi Pitre +//dce_tcp.h author Rashmi Pitre // based on work by Todd Wease -#ifndef DCE2_TCP_H -#define DCE2_TCP_H +#ifndef DCE_TCP_H +#define DCE_TCP_H +#include "dce_co.h" #include "protocols/packet.h" #include "profiler/profiler.h" #include "framework/counts.h" @@ -85,5 +86,53 @@ extern THREAD_LOCAL ProfileStats dce2_tcp_pstat_co_frag; extern THREAD_LOCAL ProfileStats dce2_tcp_pstat_co_reass; extern THREAD_LOCAL ProfileStats dce2_tcp_pstat_co_ctx; +static inline bool DCE2_TcpAutodetect(Packet* p) +{ + if (p->dsize >= sizeof(DceRpcCoHdr)) + { + DceRpcCoHdr* co_hdr = (DceRpcCoHdr*)p->data; + + if ((DceRpcCoVersMaj(co_hdr) == DCERPC_PROTO_MAJOR_VERS__5) + && (DceRpcCoVersMin(co_hdr) == DCERPC_PROTO_MINOR_VERS__0) + && ((p->from_client() + && DceRpcCoPduType(co_hdr) == DCERPC_PDU_TYPE__BIND) + || (p->from_server() + && DceRpcCoPduType(co_hdr) == DCERPC_PDU_TYPE__BIND_ACK)) + && (DceRpcCoFragLen(co_hdr) >= sizeof(DceRpcCoHdr))) + { + return true; + } + } + else if ((*p->data == DCERPC_PROTO_MAJOR_VERS__5) && p->from_client()) + { + return true; + } + + return false; +} + +struct DCE2_TcpSsnData +{ + DCE2_SsnData sd; // This member must be first + // FIXIT-M add all the remaining fields +}; + +class Dce2TcpFlowData : public FlowData +{ +public: + Dce2TcpFlowData(); + + static void init() + { + flow_id = FlowData::get_flow_id(); + } + +public: + static unsigned flow_id; + DCE2_TcpSsnData dce2_tcp_session; +}; + +DCE2_TcpSsnData* get_dce2_tcp_session_data(Flow*); + #endif diff --git a/src/service_inspectors/dce_rpc/dce2_tcp_module.cc b/src/service_inspectors/dce_rpc/dce_tcp_module.cc similarity index 98% rename from src/service_inspectors/dce_rpc/dce2_tcp_module.cc rename to src/service_inspectors/dce_rpc/dce_tcp_module.cc index c2d7ea966..0bb1edc79 100644 --- a/src/service_inspectors/dce_rpc/dce2_tcp_module.cc +++ b/src/service_inspectors/dce_rpc/dce_tcp_module.cc @@ -18,11 +18,11 @@ // dce_tcp_module.cc author Rashmi Pitre -#include "dce2_tcp_module.h" -#include "dce2_tcp.h" -#include "dce2_common.h" +#include "dce_tcp_module.h" +#include "dce_tcp.h" +#include "dce_common.h" #include "main/snort_config.h" -#include "dce2_co.h" +#include "dce_co.h" using namespace std; diff --git a/src/service_inspectors/dce_rpc/dce2_tcp_module.h b/src/service_inspectors/dce_rpc/dce_tcp_module.h similarity index 95% rename from src/service_inspectors/dce_rpc/dce2_tcp_module.h rename to src/service_inspectors/dce_rpc/dce_tcp_module.h index 6205c7ef6..c7de6b9af 100644 --- a/src/service_inspectors/dce_rpc/dce2_tcp_module.h +++ b/src/service_inspectors/dce_rpc/dce_tcp_module.h @@ -16,12 +16,12 @@ // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. //-------------------------------------------------------------------------- // -// dce2_tcp_module.h author Rashmi Pitre +// dce_tcp_module.h author Rashmi Pitre #ifndef DCE2_TCP_MODULE_H #define DCE2_TCP_MODULE_H -#include "dce2_common.h" +#include "dce_common.h" #include "framework/module.h" struct SnortConfig; diff --git a/src/service_inspectors/dce_rpc/dce_tcp_paf.cc b/src/service_inspectors/dce_rpc/dce_tcp_paf.cc new file mode 100644 index 000000000..6d348d702 --- /dev/null +++ b/src/service_inspectors/dce_rpc/dce_tcp_paf.cc @@ -0,0 +1,187 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2016-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. +//-------------------------------------------------------------------------- + +// dce_tcp_paf.cc author Rashmi Pitre +// based on work by Todd Wease + +#include "dce_tcp_paf.h" +#include "dce_tcp.h" +#include "dce_common.h" +#include "main/snort_debug.h" + +/********************************************************************* + * Function: dce2_tcp_paf() + * + * Purpose: The DCE/RPC over TCP PAF callback. + * Inspects a byte at a time changing state. At state 4 + * gets byte order of PDU. At states 8 and 9 gets + * fragment length and sets flush point if no more data. + * Otherwise accumulates flush points because there can + * be multiple PDUs in a single TCP segment (evasion case). + * + *********************************************************************/ +static StreamSplitter::Status dce2_tcp_paf(DCE2_PafTcpData* ds, Flow* flow, const uint8_t* data, + uint32_t len, uint32_t flags, uint32_t* fp) +{ + uint32_t n = 0; + int start_state; + StreamSplitter::Status ps = StreamSplitter::SEARCH; + uint32_t tmp_fp = 0; + DCE2_TcpSsnData* sd = get_dce2_tcp_session_data(flow); + + int num_requests = 0; + + DebugFormat(DEBUG_DCE_TCP, "%s\n", DCE2_DEBUG__PAF_START_MSG_TCP); + DebugFormat(DEBUG_DCE_TCP, "TCP: %u bytes of data\n", len); + + if (flags & PKT_FROM_CLIENT) + DebugMessage(DEBUG_DCE_TCP, "Packet from Client\n"); + else + DebugMessage(DEBUG_DCE_TCP, "Packet from Server\n"); + + if (dce2_paf_abort(flow)) + { + DebugFormat(DEBUG_DCE_TCP, "%s\n", DCE2_DEBUG__PAF_END_MSG); + return StreamSplitter::ABORT; + } + + if (sd == NULL) + { + bool autodetected = false; + DebugMessage(DEBUG_DCE_TCP, "No session data - autodetecting\n"); + + if (len >= sizeof(DceRpcCoHdr)) + { + DceRpcCoHdr* co_hdr = (DceRpcCoHdr*)data; + + if ((DceRpcCoVersMaj(co_hdr) == DCERPC_PROTO_MAJOR_VERS__5) + && (DceRpcCoVersMin(co_hdr) == DCERPC_PROTO_MINOR_VERS__0) + && (((flags & PKT_FROM_CLIENT) + && DceRpcCoPduType(co_hdr) == DCERPC_PDU_TYPE__BIND) + || ((flags & PKT_FROM_SERVER) + && DceRpcCoPduType(co_hdr) == DCERPC_PDU_TYPE__BIND_ACK)) + && (DceRpcCoFragLen(co_hdr) >= sizeof(DceRpcCoHdr))) + { + autodetected = true; + DebugMessage(DEBUG_DCE_TCP, "Autodetected!\n"); + } + } + else if ((*data == DCERPC_PROTO_MAJOR_VERS__5) && (flags & PKT_FROM_CLIENT)) + { + autodetected = true; + DebugMessage(DEBUG_DCE_TCP, "Autodetected!\n"); + } + + if (!autodetected) + { + DebugMessage(DEBUG_DCE_TCP, "Couldn't autodetect - aborting\n"); + DebugFormat(DEBUG_DCE_TCP, "%s\n", DCE2_DEBUG__PAF_END_MSG); + return StreamSplitter::ABORT; + } + } + + DebugFormat(DEBUG_DCE_TCP, "Start state: %u\n", ds->paf_state); + start_state = (uint8_t)ds->paf_state; + + while (n < len) + { + DebugFormat(DEBUG_DCE_TCP, " State %d : 0x%02x", ds->paf_state, data[n]); + + switch (ds->paf_state) + { + case DCE2_PAF_TCP_STATES__4: // Get byte order + ds->byte_order = DceRpcByteOrder(data[n]); + ds->paf_state = (DCE2_PafTcpStates)(((int)ds->paf_state) + 1); + if (ds->byte_order == DCERPC_BO_FLAG__LITTLE_ENDIAN) + { + DebugMessage(DEBUG_DCE_TCP, "Byte order: Little endian\n"); + } + else + { + DebugMessage(DEBUG_DCE_TCP, "Byte order: Big endian\n"); + } + break; + case DCE2_PAF_TCP_STATES__8: + DebugMessage(DEBUG_DCE_TCP, "First byte of fragment length\n"); + if (ds->byte_order == DCERPC_BO_FLAG__LITTLE_ENDIAN) + ds->frag_len = data[n]; + else + ds->frag_len = data[n] << 8; + ds->paf_state = (DCE2_PafTcpStates)(((int)ds->paf_state) + 1); + break; + case DCE2_PAF_TCP_STATES__9: + DebugMessage(DEBUG_DCE_TCP, "Second byte of fragment length\n"); + if (ds->byte_order == DCERPC_BO_FLAG__LITTLE_ENDIAN) + ds->frag_len |= data[n] << 8; + else + ds->frag_len |= data[n]; + + /* If we get a bad frag length abort */ + if (ds->frag_len < sizeof(DceRpcCoHdr)) + { + DebugFormat(DEBUG_DCE_TCP, "%s\n", DCE2_DEBUG__PAF_END_MSG); + return StreamSplitter::ABORT; + } + + DebugFormat(DEBUG_DCE_TCP, "Fragment length: %u\n", ds->frag_len); + + /* Increment n here so we can continue */ + n += ds->frag_len - (uint8_t)ds->paf_state; + num_requests++; + /* Might have multiple PDUs in one segment. If the last PDU is partial, + * flush just before it */ + if ((num_requests == 1) || (n <= len)) + tmp_fp += ds->frag_len; + DebugFormat(DEBUG_DCE_TCP, "Requests: %u\n", num_requests); + ds->paf_state = DCE2_PAF_TCP_STATES__0; + continue; // we incremented n already + default: + ds->paf_state = (DCE2_PafTcpStates)(((int)ds->paf_state) + 1); + break; + } + + n++; + } + + if (tmp_fp != 0) + { + *fp = tmp_fp - start_state; + DebugFormat(DEBUG_DCE_TCP, "Setting flush point: %u\n", *fp); + DebugFormat(DEBUG_DCE_TCP, "%s\n", DCE2_DEBUG__PAF_END_MSG); + return StreamSplitter::FLUSH; + } + + DebugFormat(DEBUG_DCE_TCP, "%s\n", DCE2_DEBUG__PAF_END_MSG); + return ps; +} + +Dce2TcpSplitter::Dce2TcpSplitter(bool c2s) : StreamSplitter(c2s) +{ + state.paf_state = DCE2_PAF_TCP_STATES__0; + state.byte_order = DCERPC_BO_FLAG__NONE; + state.frag_len = 0; +} + +StreamSplitter::Status Dce2TcpSplitter::scan( + Flow* flow, const uint8_t* data, uint32_t len, + uint32_t flags, uint32_t* fp) +{ + DCE2_PafTcpData* pfdata = &state; + return dce2_tcp_paf(pfdata, flow, data, len, flags, fp); +} + diff --git a/src/service_inspectors/dce_rpc/dce_tcp_paf.h b/src/service_inspectors/dce_rpc/dce_tcp_paf.h new file mode 100644 index 000000000..8a10bfe4c --- /dev/null +++ b/src/service_inspectors/dce_rpc/dce_tcp_paf.h @@ -0,0 +1,72 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2016-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. +//-------------------------------------------------------------------------- + +// dce_tcp_paf.h author Rashmi Pitre +// based on work by Todd Wease + +#ifndef DCE_TCP_PAF_H +#define DCE_TCP_PAF_H + +#include "dce_common.h" +#include "main/snort_types.h" +#include "stream/stream_api.h" +#include "stream/stream_splitter.h" + +#define DCE2_DEBUG__PAF_START_MSG_TCP "DCE/RPC over TCP PAF =====================================" + +enum DCE2_PafTcpStates +{ + DCE2_PAF_TCP_STATES__0 = 0, + DCE2_PAF_TCP_STATES__1, + DCE2_PAF_TCP_STATES__2, + DCE2_PAF_TCP_STATES__3, + DCE2_PAF_TCP_STATES__4, // Byte order + DCE2_PAF_TCP_STATES__5, + DCE2_PAF_TCP_STATES__6, + DCE2_PAF_TCP_STATES__7, + DCE2_PAF_TCP_STATES__8, // First byte of fragment length + DCE2_PAF_TCP_STATES__9 // Second byte of fragment length +}; + +// State tracker for DCE/RPC over TCP PAF +struct DCE2_PafTcpData +{ + DCE2_PafTcpStates paf_state; + DceRpcBoFlag byte_order; + uint16_t frag_len; +}; + +class Dce2TcpSplitter : public StreamSplitter +{ +public: + Dce2TcpSplitter(bool c2s); + + Status scan(Flow*, const uint8_t* data, uint32_t len, + uint32_t flags, uint32_t* fp) override; + + bool is_paf() override + { + return true; + } + +public: + DCE2_PafTcpData state; +}; + +#endif + diff --git a/src/service_inspectors/dce_rpc/dce2_utils.cc b/src/service_inspectors/dce_rpc/dce_utils.cc similarity index 99% rename from src/service_inspectors/dce_rpc/dce2_utils.cc rename to src/service_inspectors/dce_rpc/dce_utils.cc index 8428467f1..dca58f59e 100644 --- a/src/service_inspectors/dce_rpc/dce2_utils.cc +++ b/src/service_inspectors/dce_rpc/dce_utils.cc @@ -17,7 +17,7 @@ // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. //-------------------------------------------------------------------------- -#include "dce2_utils.h" +#include "dce_utils.h" /******************************************************************** diff --git a/src/service_inspectors/dce_rpc/dce2_utils.h b/src/service_inspectors/dce_rpc/dce_utils.h similarity index 99% rename from src/service_inspectors/dce_rpc/dce2_utils.h rename to src/service_inspectors/dce_rpc/dce_utils.h index 862f7e10c..deffe804b 100644 --- a/src/service_inspectors/dce_rpc/dce2_utils.h +++ b/src/service_inspectors/dce_rpc/dce_utils.h @@ -17,8 +17,8 @@ // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. //-------------------------------------------------------------------------- -#ifndef _DCE2_UTILS_H_ -#define _DCE2_UTILS_H_ +#ifndef _DCE_UTILS_H_ +#define _DCE_UTILS_H_ #include #include diff --git a/src/service_inspectors/dce_rpc/ips_dce2_iface.cc b/src/service_inspectors/dce_rpc/ips_dce_iface.cc similarity index 99% rename from src/service_inspectors/dce_rpc/ips_dce2_iface.cc rename to src/service_inspectors/dce_rpc/ips_dce_iface.cc index 6d0d00511..e3e68f55c 100644 --- a/src/service_inspectors/dce_rpc/ips_dce2_iface.cc +++ b/src/service_inspectors/dce_rpc/ips_dce_iface.cc @@ -16,10 +16,10 @@ // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. //-------------------------------------------------------------------------- -// ips_dce2_iface.cc author Maya Dagon +// ips_dce_iface.cc author Maya Dagon // based on work by Todd Wease -#include "dce2_utils.h" +#include "dce_utils.h" #include "framework/ips_option.h" #include "framework/module.h" diff --git a/src/service_inspectors/dce_rpc/ips_dce2_opnum.cc b/src/service_inspectors/dce_rpc/ips_dce_opnum.cc similarity index 99% rename from src/service_inspectors/dce_rpc/ips_dce2_opnum.cc rename to src/service_inspectors/dce_rpc/ips_dce_opnum.cc index fd809bb12..8a50740bf 100644 --- a/src/service_inspectors/dce_rpc/ips_dce2_opnum.cc +++ b/src/service_inspectors/dce_rpc/ips_dce_opnum.cc @@ -16,10 +16,10 @@ // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. //-------------------------------------------------------------------------- -// ips_dce2_opnum.cc author Maya Dagon +// ips_dce_opnum.cc author Maya Dagon // based on work by Todd Wease -#include "dce2_utils.h" +#include "dce_utils.h" #include "framework/ips_option.h" #include "framework/module.h" diff --git a/src/service_inspectors/dce_rpc/ips_dce2_stub_data.cc b/src/service_inspectors/dce_rpc/ips_dce_stub_data.cc similarity index 98% rename from src/service_inspectors/dce_rpc/ips_dce2_stub_data.cc rename to src/service_inspectors/dce_rpc/ips_dce_stub_data.cc index feda11c3e..7251102b4 100644 --- a/src/service_inspectors/dce_rpc/ips_dce2_stub_data.cc +++ b/src/service_inspectors/dce_rpc/ips_dce_stub_data.cc @@ -16,7 +16,7 @@ // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. //-------------------------------------------------------------------------- -// ips_dce2_stub_data.cc author Maya Dagon +// ips_dce_stub_data.cc author Maya Dagon // based on work by Todd Wease #include "detection/detection_defines.h"