]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #2226 in SNORT/snort3 from ~EBURMAI/snort3:dce_tcp_pinhole to...
authorShravan Rangarajuvenkata (shrarang) <shrarang@cisco.com>
Wed, 3 Jun 2020 19:43:12 +0000 (19:43 +0000)
committerShravan Rangarajuvenkata (shrarang) <shrarang@cisco.com>
Wed, 3 Jun 2020 19:43:12 +0000 (19:43 +0000)
Squashed commit of the following:

commit fe674926599fc7ff9b42dd8cbe624e23eb747e63
Author: Eduard Burmai <eburmai@cisco.com>
Date:   Wed May 13 16:00:18 2020 -0400

    dce_rpc: suppport for DCE/RPC future session

30 files changed:
src/network_inspectors/appid/appid_dcerpc_event_handler.h [new file with mode: 0644]
src/network_inspectors/appid/appid_inspector.cc
src/network_inspectors/appid/appid_session.cc
src/network_inspectors/appid/appid_session.h
src/network_inspectors/appid/detector_plugins/detector_sip.cc
src/network_inspectors/appid/lua_detector_api.cc
src/network_inspectors/appid/lua_detector_flow_api.cc
src/network_inspectors/appid/service_plugins/service_detector.cc
src/network_inspectors/appid/service_plugins/service_detector.h
src/network_inspectors/appid/service_plugins/service_ftp.cc
src/network_inspectors/appid/service_plugins/service_ftp.h
src/network_inspectors/appid/service_plugins/service_rexec.cc
src/network_inspectors/appid/service_plugins/service_rpc.cc
src/network_inspectors/appid/service_plugins/service_rshell.cc
src/network_inspectors/appid/service_plugins/service_snmp.cc
src/network_inspectors/appid/service_plugins/service_ssl.cc
src/network_inspectors/appid/service_plugins/service_tftp.cc
src/network_inspectors/appid/test/CMakeLists.txt
src/network_inspectors/appid/test/appid_expected_flags_test.cc [deleted file]
src/pub_sub/CMakeLists.txt
src/pub_sub/dcerpc_events.h [new file with mode: 0644]
src/service_inspectors/dce_rpc/CMakeLists.txt
src/service_inspectors/dce_rpc/dce_co.cc
src/service_inspectors/dce_rpc/dce_co.h
src/service_inspectors/dce_rpc/dce_expected_session.cc [new file with mode: 0644]
src/service_inspectors/dce_rpc/dce_expected_session.h [new file with mode: 0644]
src/service_inspectors/dce_rpc/dce_tcp.cc
src/service_inspectors/dce_rpc/dce_tcp.h
src/service_inspectors/dce_rpc/dce_tcp_module.cc
src/service_inspectors/dce_rpc/dce_utils.h

diff --git a/src/network_inspectors/appid/appid_dcerpc_event_handler.h b/src/network_inspectors/appid/appid_dcerpc_event_handler.h
new file mode 100644 (file)
index 0000000..3e2aed7
--- /dev/null
@@ -0,0 +1,64 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 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.
+//--------------------------------------------------------------------------
+
+// appid_dcerpc_event_handler.h author Eduard Burmai <eburmai@cisco.com>
+
+#ifndef APPID_DCERPC_EVENT_HANDLER_H
+#define APPID_DCERPC_EVENT_HANDLER_H
+
+#include "pub_sub/dcerpc_events.h"
+
+#include "appid_session.h"
+#include "service_plugins/service_detector.h"
+
+class DceExpSsnEventHandler : public snort::DataHandler
+{
+public:
+    DceExpSsnEventHandler() : DataHandler(MOD_NAME) { }
+
+    void handle(snort::DataEvent& event, snort::Flow* flow) override
+    {
+        assert(flow);
+
+        AppIdSession* asd = snort::appid_api.get_appid_session(*flow);
+        if (!asd)
+            return; // appid disabled
+
+        DceExpectedSessionEvent& map_resp_event = static_cast<DceExpectedSessionEvent&>(event);
+
+        const snort::Packet* pkt = map_resp_event.get_packet();
+        const snort::SfIp* src_ip = map_resp_event.get_src_ip();
+        const snort::SfIp* dst_ip = map_resp_event.get_dst_ip();
+        uint16_t src_port = map_resp_event.get_src_port();
+        uint16_t dst_port = map_resp_event.get_dst_port();
+        IpProtocol proto = map_resp_event.get_ip_proto();
+        SnortProtocolId protocol_id = map_resp_event.get_proto_id();
+
+        AppIdSession* fp = AppIdSession::create_future_session(pkt, src_ip, src_port,
+            dst_ip, dst_port, proto, protocol_id);
+
+        if (fp) // initialize data session
+        {
+            fp->service.set_id(APP_ID_DCE_RPC, asd->ctxt.get_odp_ctxt());
+            asd->initialize_future_session(*fp, APPID_SESSION_IGNORE_ID_FLAGS,
+                APP_ID_FROM_RESPONDER);
+        }
+    }
+};
+
+#endif // APPID_DCERPC_EVENT_HANDLER_H
index 71df6fc1106b06e61bb0ba5e55735b303f964afa..9aad875a759fd54e852719124d42b4ae5870e35c 100644 (file)
@@ -35,6 +35,7 @@
 
 #include "app_forecast.h"
 #include "appid_data_decrypt_event_handler.h"
+#include "appid_dcerpc_event_handler.h"
 #include "appid_debug.h"
 #include "appid_discovery.h"
 #include "appid_http_event_handler.h"
@@ -124,6 +125,8 @@ bool AppIdInspector::configure(SnortConfig* sc)
 
     DataBus::subscribe_global(DATA_DECRYPT_EVENT, new DataDecryptEventHandler(), sc);
 
+    DataBus::subscribe_global(DCERPC_EXP_SESSION_EVENT_KEY, new DceExpSsnEventHandler(), sc);
+
     return true;
 }
 
index 39c78c35c0adbca1286818f282755d6526c53b29..afe857ca41914576a697fc9672351d68a0977b78 100644 (file)
@@ -170,7 +170,7 @@ static inline PktType get_pkt_type_from_ip_proto(IpProtocol proto)
 
 AppIdSession* AppIdSession::create_future_session(const Packet* ctrlPkt, const SfIp* cliIp,
     uint16_t cliPort, const SfIp* srvIp, uint16_t srvPort, IpProtocol proto,
-    SnortProtocolId snort_protocol_id, int /*flags*/)
+    SnortProtocolId snort_protocol_id)
 {
     char src_ip[INET6_ADDRSTRLEN];
     char dst_ip[INET6_ADDRSTRLEN];
@@ -216,6 +216,42 @@ AppIdSession* AppIdSession::create_future_session(const Packet* ctrlPkt, const S
     return asd;
 }
 
+void AppIdSession::initialize_future_session(AppIdSession& expected, uint64_t flags,
+    AppidSessionDirection dir)
+{
+    if (dir == APP_ID_FROM_INITIATOR)
+    {
+        expected.set_session_flags(flags |
+            get_session_flags(
+            APPID_SESSION_INITIATOR_CHECKED |
+            APPID_SESSION_INITIATOR_MONITORED |
+            APPID_SESSION_RESPONDER_CHECKED |
+            APPID_SESSION_RESPONDER_MONITORED));
+    }
+    else if (dir == APP_ID_FROM_RESPONDER)
+    {
+        if (get_session_flags(APPID_SESSION_INITIATOR_CHECKED))
+            flags |= APPID_SESSION_RESPONDER_CHECKED;
+
+        if (get_session_flags(APPID_SESSION_INITIATOR_MONITORED))
+            flags |= APPID_SESSION_RESPONDER_MONITORED;
+
+        if (get_session_flags(APPID_SESSION_RESPONDER_CHECKED))
+            flags |= APPID_SESSION_INITIATOR_CHECKED;
+
+        if (get_session_flags(APPID_SESSION_RESPONDER_MONITORED))
+            flags |= APPID_SESSION_INITIATOR_MONITORED;
+    }
+
+    expected.set_session_flags(flags |
+        get_session_flags(
+        APPID_SESSION_SPECIAL_MONITORED |
+        APPID_SESSION_DISCOVER_APP |
+        APPID_SESSION_DISCOVER_USER));
+
+    expected.service_disco_state = APPID_DISCO_STATE_FINISHED;
+    expected.client_disco_state = APPID_DISCO_STATE_FINISHED;
+}
 void AppIdSession::reinit_session_data(AppidChangeBits& change_bits)
 {
     misc_app_id = APP_ID_NONE;
index 276d3728ff5ccff480e189c51b8258bc31cfe078..f836d5604bd24bf656b3768f1b3045bf8d152ac1 100644 (file)
@@ -209,8 +209,8 @@ public:
     static AppIdSession* allocate_session(const snort::Packet*, IpProtocol,
         AppidSessionDirection, AppIdInspector*);
     static AppIdSession* create_future_session(const snort::Packet*, const snort::SfIp*, uint16_t,
-        const snort::SfIp*,
-        uint16_t, IpProtocol, SnortProtocolId, int);
+        const snort::SfIp*, uint16_t, IpProtocol, SnortProtocolId);
+    void initialize_future_session(AppIdSession&, uint64_t, AppidSessionDirection);
 
     size_t size_of() override
     { return sizeof(*this); }
index 3cf16fe3826737f62dc411e9f6e018f663d66fb7..56960e38d7141b53786d9348c9c008f769983661 100644 (file)
@@ -184,8 +184,7 @@ void SipServiceDetector::createRtpFlow(AppIdSession& asd, const Packet* pkt, con
     // snort_protocol_id.
 
     AppIdSession* fp = AppIdSession::create_future_session(
-        pkt, cliIp, cliPort, srvIp, srvPort, protocol, app_id,
-        APPID_EARLY_SESSION_FLAG_FW_RULE);
+        pkt, cliIp, cliPort, srvIp, srvPort, protocol, app_id);
 
     if ( fp )
     {
@@ -195,17 +194,16 @@ void SipServiceDetector::createRtpFlow(AppIdSession& asd, const Packet* pkt, con
 
         // FIXIT-M : snort 2.9.x updated the flag to APPID_SESSION_EXPECTED_EVALUATE.
         // Check if it is needed here as well.
-        //initialize_expected_session(asd, fp, APPID_SESSION_EXPECTED_EVALUATE);
+        // asd.initialize_future_session(*fp, APPID_SESSION_EXPECTED_EVALUATE, APP_ID_APPID_SESSION_DIRECTION_MAX);
 
-        initialize_expected_session(
-            asd, *fp, APPID_SESSION_IGNORE_ID_FLAGS, APP_ID_APPID_SESSION_DIRECTION_MAX);
+        asd.initialize_future_session(*fp, APPID_SESSION_IGNORE_ID_FLAGS,
+            APP_ID_APPID_SESSION_DIRECTION_MAX);
     }
 
     // create an RTCP flow as well
 
     AppIdSession* fp2 = AppIdSession::create_future_session(
-        pkt, cliIp, cliPort + 1, srvIp, srvPort + 1, protocol, app_id,
-        APPID_EARLY_SESSION_FLAG_FW_RULE);
+        pkt, cliIp, cliPort + 1, srvIp, srvPort + 1, protocol, app_id);
 
     if ( fp2 )
     {
@@ -214,10 +212,10 @@ void SipServiceDetector::createRtpFlow(AppIdSession& asd, const Packet* pkt, con
         fp2->service.set_id(APP_ID_RTCP, asd.ctxt.get_odp_ctxt());
 
         // FIXIT-M : same comment as above
-        //initialize_expected_session(asd, fp2, APPID_SESSION_EXPECTED_EVALUATE);
+        // asd.initialize_future_session(*fp2, APPID_SESSION_EXPECTED_EVALUATE, APP_ID_APPID_SESSION_DIRECTION_MAX);
 
-        initialize_expected_session(
-            asd, *fp2, APPID_SESSION_IGNORE_ID_FLAGS, APP_ID_APPID_SESSION_DIRECTION_MAX);
+        asd.initialize_future_session(*fp2, APPID_SESSION_IGNORE_ID_FLAGS,
+            APP_ID_APPID_SESSION_DIRECTION_MAX);
     }
 }
 
index 4b131c548448e9e2e23f2e7d87a634554bf5cbc5..10b1a13d0fb6a9483c1ae2290d2437a917319b29 100644 (file)
@@ -2415,8 +2415,7 @@ static int create_future_flow(lua_State* L)
     }
 
     AppIdSession* fp = AppIdSession::create_future_session(lsd->ldp.pkt,  &client_addr,
-        client_port, &server_addr, server_port, proto, snort_protocol_id,
-        APPID_EARLY_SESSION_FLAG_FW_RULE);
+        client_port, &server_addr, server_port, proto, snort_protocol_id);
     if (fp)
     {
         fp->service.set_id(service_id, ud->get_odp_ctxt());
index 3d045b2609d3d5ac126f1c713b38b8b1a0f5c7f5..4ed4d359b37199eb8b3cf9290f34ae2147924f79 100644 (file)
@@ -213,7 +213,7 @@ static int create_detector_flow(lua_State* L)
     LuaDetectorManager::add_detector_flow(detector_flow);
 
     detector_flow->asd = AppIdSession::create_future_session(lsd->ldp.pkt, &saddr, sport,
-        &daddr, dport, proto, 0, 0);
+        &daddr, dport, proto, 0);
 
     if (!detector_flow->asd)
     {
index c09ba3effb77aa2c5cdef8fa6dbf534e729a4247..20837389fda4ccb7a4513adffc36a5bbb0c49762 100644 (file)
@@ -175,40 +175,3 @@ int ServiceDetector::fail_service(AppIdSession& asd, const Packet* pkt, AppidSes
 {
     return static_cast<ServiceDiscovery*>(handler)->fail_service(asd, pkt, dir, this);
 }
-
-void ServiceDetector::initialize_expected_session(const AppIdSession& parent, AppIdSession& expected,
-    uint64_t flags, AppidSessionDirection dir)
-{
-    if (dir == APP_ID_FROM_INITIATOR)
-    {
-        expected.set_session_flags(flags |
-            parent.get_session_flags(
-            APPID_SESSION_INITIATOR_CHECKED |
-            APPID_SESSION_INITIATOR_MONITORED |
-            APPID_SESSION_RESPONDER_CHECKED |
-            APPID_SESSION_RESPONDER_MONITORED));
-    }
-    else if (dir == APP_ID_FROM_RESPONDER)
-    {
-        if (parent.get_session_flags(APPID_SESSION_INITIATOR_CHECKED))
-            flags |= APPID_SESSION_RESPONDER_CHECKED;
-
-        if (parent.get_session_flags(APPID_SESSION_INITIATOR_MONITORED))
-            flags |= APPID_SESSION_RESPONDER_MONITORED;
-
-        if (parent.get_session_flags(APPID_SESSION_RESPONDER_CHECKED))
-            flags |= APPID_SESSION_INITIATOR_CHECKED;
-
-        if (parent.get_session_flags(APPID_SESSION_RESPONDER_MONITORED))
-            flags |= APPID_SESSION_INITIATOR_MONITORED;
-    }
-
-    expected.set_session_flags(flags |
-        parent.get_session_flags(
-        APPID_SESSION_SPECIAL_MONITORED |
-        APPID_SESSION_DISCOVER_APP |
-        APPID_SESSION_DISCOVER_USER));
-
-    expected.service_disco_state = APPID_DISCO_STATE_FINISHED;
-    expected.client_disco_state = APPID_DISCO_STATE_FINISHED;
-}
index 489467d8a7595b72248dbf1d587939940d3f9c02..4683e3f1a115a13b049945cdaa4e0c7f534c1ee7 100644 (file)
@@ -25,8 +25,6 @@
 #include "appid_detector.h"
 #include "service_discovery.h"
 
-#define APPID_EARLY_SESSION_FLAG_FW_RULE    1
-
 class ServiceDetector : public AppIdDetector
 {
 public:
@@ -58,8 +56,6 @@ public:
         asd.misc_app_id = miscId;
     }
 
-    void initialize_expected_session(const AppIdSession&, AppIdSession&, uint64_t flags, AppidSessionDirection dir);
-
 private:
     int update_service_data(AppIdSession&, const snort::Packet*, AppidSessionDirection dir, AppId,
         const char* vendor, const char* version, AppidChangeBits& change_bits);
index 357359e7f9d03d2c85b50831cdbba73288d4bcd6..44b67309141c9eea6cb4bbbf1d98318bb0e95822 100644 (file)
@@ -879,8 +879,7 @@ static inline void WatchForCommandResult(ServiceFTPData* fd, AppIdSession& asd,
 }
 
 void FtpServiceDetector::create_expected_session(AppIdSession& asd, const Packet* pkt, const SfIp* cliIp,
-    uint16_t cliPort, const SfIp* srvIp, uint16_t srvPort, IpProtocol protocol,
-    int flags, AppidSessionDirection dir)
+    uint16_t cliPort, const SfIp* srvIp, uint16_t srvPort, IpProtocol protocol, AppidSessionDirection dir)
 {
     // FIXIT-M - Avoid thread locals
     static THREAD_LOCAL SnortProtocolId ftp_data_snort_protocol_id = UNKNOWN_PROTOCOL_ID;
@@ -888,7 +887,7 @@ void FtpServiceDetector::create_expected_session(AppIdSession& asd, const Packet
         ftp_data_snort_protocol_id = pkt->context->conf->proto_ref->find("ftp-data");
 
     AppIdSession* fp = AppIdSession::create_future_session(pkt, cliIp, cliPort, srvIp, srvPort,
-        protocol, ftp_data_snort_protocol_id, flags);
+        protocol, ftp_data_snort_protocol_id);
 
     if (fp) // initialize data session
     {
@@ -903,7 +902,7 @@ void FtpServiceDetector::create_expected_session(AppIdSession& asd, const Packet
             fp->service.set_id(APP_ID_FTP_DATA, asd.ctxt.get_odp_ctxt());
         }
 
-        initialize_expected_session(asd, *fp, APPID_SESSION_IGNORE_ID_FLAGS | encrypted_flags, dir);
+        asd.initialize_future_session(*fp, APPID_SESSION_IGNORE_ID_FLAGS | encrypted_flags, dir);
     }
 }
 
@@ -962,8 +961,8 @@ int FtpServiceDetector::validate(AppIdDiscoveryArgs& args)
                 &fd->address, &fd->port) == 0)
             {
                 const SfIp* dip = args.pkt->ptrs.ip_api.get_dst();
-                create_expected_session(args.asd, args.pkt, dip, 0, &fd->address, fd->port, args.asd.protocol,
-                    APPID_EARLY_SESSION_FLAG_FW_RULE, APP_ID_FROM_RESPONDER);
+                create_expected_session(args.asd, args.pkt, dip, 0, &fd->address, fd->port,
+                    args.asd.protocol, APP_ID_FROM_RESPONDER);
                 WatchForCommandResult(fd, args.asd, FTP_CMD_PORT_EPRT);
             }
         }
@@ -975,8 +974,8 @@ int FtpServiceDetector::validate(AppIdDiscoveryArgs& args)
                 &fd->address, &fd->port) == 0)
             {
                 const SfIp* dip = args.pkt->ptrs.ip_api.get_dst();
-                create_expected_session(args.asd, args.pkt, dip, 0, &fd->address, fd->port, args.asd.protocol,
-                    APPID_EARLY_SESSION_FLAG_FW_RULE, APP_ID_FROM_RESPONDER);
+                create_expected_session(args.asd, args.pkt, dip, 0, &fd->address, fd->port,
+                    args.asd.protocol, APP_ID_FROM_RESPONDER);
                 WatchForCommandResult(fd, args.asd, FTP_CMD_PORT_EPRT);
             }
         }
@@ -1244,14 +1243,12 @@ int FtpServiceDetector::validate(AppIdDiscoveryArgs& args)
                     addr = htonl(address);
                     ip.set(&addr, AF_INET);
                     create_expected_session(args.asd, args.pkt, dip, 0, &ip, port,
-                        args.asd.protocol, APPID_EARLY_SESSION_FLAG_FW_RULE,
-                        APP_ID_FROM_INITIATOR);
+                        args.asd.protocol, APP_ID_FROM_INITIATOR);
 
                     if (!ip.fast_eq6(*sip))
                     {
                         create_expected_session(args.asd, args.pkt, dip, 0, sip, port,
-                            args.asd.protocol, APPID_EARLY_SESSION_FLAG_FW_RULE,
-                            APP_ID_FROM_INITIATOR);
+                            args.asd.protocol, APP_ID_FROM_INITIATOR);
                     }
                     add_payload(args.asd, APP_ID_FTP_PASSIVE);
                 }
@@ -1268,8 +1265,8 @@ int FtpServiceDetector::validate(AppIdDiscoveryArgs& args)
                 {
                     const SfIp* dip = args.pkt->ptrs.ip_api.get_dst();
                     const SfIp* sip = args.pkt->ptrs.ip_api.get_src();
-                    create_expected_session(args.asd, args.pkt, dip, 0, sip, port, args.asd.protocol,
-                        APPID_EARLY_SESSION_FLAG_FW_RULE, APP_ID_FROM_INITIATOR);
+                    create_expected_session(args.asd, args.pkt, dip, 0, sip, port,
+                        args.asd.protocol, APP_ID_FROM_INITIATOR);
 
                     add_payload(args.asd, APP_ID_FTP_PASSIVE);
                 }
index dccb2928d93293be2f5d141be850d05e9d23917a..ee26742a17c330d76f99a5cbc9d4029e1de2f695 100644 (file)
@@ -36,7 +36,7 @@ public:
 private:
     void create_expected_session(AppIdSession&, const snort::Packet*,
         const snort::SfIp* cliIp, uint16_t cliPort, const snort::SfIp* srvIp,
-        uint16_t srvPort, IpProtocol, int flags, AppidSessionDirection);
+        uint16_t srvPort, IpProtocol, AppidSessionDirection);
 };
 #endif
 
index e301ba252d061bfda8485f8ce6a7dbc5b1bf9e8e..c3ed30e015e3baeb749095af3be18d1d999ac620 100644 (file)
@@ -168,7 +168,7 @@ int RexecServiceDetector::validate(AppIdDiscoveryArgs& args)
             dip = args.pkt->ptrs.ip_api.get_dst();
             sip = args.pkt->ptrs.ip_api.get_src();
             AppIdSession* pf = AppIdSession::create_future_session(args.pkt, dip, 0, sip, (uint16_t)port,
-                IpProtocol::TCP, rexec_snort_protocol_id, APPID_EARLY_SESSION_FLAG_FW_RULE);
+                IpProtocol::TCP, rexec_snort_protocol_id);
             if (pf)
             {
                 ServiceREXECData* tmp_rd = (ServiceREXECData*)snort_calloc(
@@ -186,7 +186,7 @@ int RexecServiceDetector::validate(AppIdDiscoveryArgs& args)
                 }
                 pf->service_disco_state = APPID_DISCO_STATE_STATEFUL;
                 pf->scan_flags |= SCAN_HOST_PORT_FLAG;
-                initialize_expected_session(args.asd, *pf, REXEC_EXPECTED_SESSION_FLAGS, APP_ID_FROM_RESPONDER);
+                args.asd.initialize_future_session(*pf, REXEC_EXPECTED_SESSION_FLAGS, APP_ID_FROM_RESPONDER);
                 pf->service_disco_state = APPID_DISCO_STATE_STATEFUL;
                 rd->child = tmp_rd;
                 rd->state = REXEC_STATE_SERVER_CONNECT;
index 8be459026776dc27b0f1936c7c2fd718c0eb9518..ffbeb96d3e10c4f3519bf70eecd14284a6013b32 100644 (file)
@@ -413,7 +413,7 @@ int RpcServiceDetector::validate_packet(const uint8_t* data, uint16_t size, Appi
 
                         AppIdSession* pf = AppIdSession::create_future_session(
                             pkt, dip, 0, sip, (uint16_t)tmp,
-                            (IpProtocol)ntohl((uint32_t)rd->proto), sunrpc_snort_protocol_id, 0);
+                            (IpProtocol)ntohl((uint32_t)rd->proto), sunrpc_snort_protocol_id);
                         if (pf)
                         {
                             pf->add_flow_data_id((uint16_t)tmp, this);
index b261b2e2186803f6f39b5d554f22c500ae1cff10..0f14d8798b7a81439f6528e6fd721ca0f81063a5 100644 (file)
@@ -161,7 +161,7 @@ int RshellServiceDetector::validate(AppIdDiscoveryArgs& args)
             const SfIp* dip = args.pkt->ptrs.ip_api.get_dst();
             const SfIp* sip = args.pkt->ptrs.ip_api.get_src();
             AppIdSession* pf = AppIdSession::create_future_session(args.pkt, dip, 0, sip,
-                (uint16_t)port, IpProtocol::TCP, rsh_error_snort_protocol_id, APPID_EARLY_SESSION_FLAG_FW_RULE);
+                (uint16_t)port, IpProtocol::TCP, rsh_error_snort_protocol_id);
             if (pf)
             {
                 ServiceRSHELLData* tmp_rd = (ServiceRSHELLData*)snort_calloc(
@@ -178,10 +178,10 @@ int RshellServiceDetector::validate(AppIdDiscoveryArgs& args)
                     return APPID_ENOMEM;
                 }
                 pf->scan_flags |= SCAN_HOST_PORT_FLAG;
-                initialize_expected_session(args.asd, *pf,
-                    APPID_SESSION_CONTINUE | APPID_SESSION_REXEC_STDERR | APPID_SESSION_NO_TPI |
+                args.asd.initialize_future_session(*pf, APPID_SESSION_CONTINUE | APPID_SESSION_REXEC_STDERR | APPID_SESSION_NO_TPI |
                     APPID_SESSION_NOT_A_SERVICE | APPID_SESSION_PORT_SERVICE_DONE,
                     APP_ID_FROM_RESPONDER);
+
                 pf->service_disco_state = APPID_DISCO_STATE_STATEFUL;
                 rd->child = tmp_rd;
                 rd->state = RSHELL_STATE_SERVER_CONNECT;
index b6c15f7975c2c42af7cb0871f31fd76433a3294b..4bd8d1f0983b566764d93760e1e513533413c510 100644 (file)
@@ -471,7 +471,7 @@ int SnmpServiceDetector::validate(AppIdDiscoveryArgs& args)
         const SfIp* dip = args.pkt->ptrs.ip_api.get_dst();
         const SfIp* sip = args.pkt->ptrs.ip_api.get_src();
         AppIdSession* pf = AppIdSession::create_future_session(args.pkt, dip, 0, sip,
-            args.pkt->ptrs.sp, args.asd.protocol, snmp_snort_protocol_id, 0);
+            args.pkt->ptrs.sp, args.asd.protocol, snmp_snort_protocol_id);
         if (pf)
         {
             tmp_sd = (ServiceSNMPData*)snort_calloc(sizeof(ServiceSNMPData));
@@ -484,7 +484,7 @@ int SnmpServiceDetector::validate(AppIdDiscoveryArgs& args)
                 tmp_sd->state = SNMP_STATE_ERROR;
                 return APPID_ENULL;
             }
-            initialize_expected_session(args.asd, *pf, APPID_SESSION_EXPECTED_EVALUATE, APP_ID_APPID_SESSION_DIRECTION_MAX);
+            args.asd.initialize_future_session(*pf, APPID_SESSION_EXPECTED_EVALUATE, APP_ID_APPID_SESSION_DIRECTION_MAX);
             pf->service_disco_state = APPID_DISCO_STATE_STATEFUL;
             pf->scan_flags |= SCAN_HOST_PORT_FLAG;
             pf->common.initiator_ip = *sip;
index 0dfe0ee9a59d0d2a375a6ef846c5fe18fd2e9bb2..6e2b97dcad1611795c3715e9783672565808394a 100644 (file)
@@ -809,4 +809,3 @@ bool is_service_over_ssl(AppId appId)
 
     return false;
 }
-
index 8abfd2db47d3aa4fce9f2dda8781ff938c5d0a9e..2dbe4c762e09025649f10a80c63b424946ade2c9 100644 (file)
@@ -192,7 +192,7 @@ int TftpServiceDetector::validate(AppIdDiscoveryArgs& args)
         dip = args.pkt->ptrs.ip_api.get_dst();
         sip = args.pkt->ptrs.ip_api.get_src();
         pf = AppIdSession::create_future_session(args.pkt, dip, 0, sip,
-            args.pkt->ptrs.sp, args.asd.protocol, tftp_snort_protocol_id, APPID_EARLY_SESSION_FLAG_FW_RULE);
+            args.pkt->ptrs.sp, args.asd.protocol, tftp_snort_protocol_id);
         if (pf)
         {
             data_add(*pf, tmp_td, &snort_free);
@@ -203,7 +203,7 @@ int TftpServiceDetector::validate(AppIdDiscoveryArgs& args)
                 tmp_td->state = TFTP_STATE_ERROR;
                 return APPID_ENOMEM;
             }
-            initialize_expected_session(args.asd, *pf, APPID_SESSION_EXPECTED_EVALUATE, APP_ID_FROM_RESPONDER);
+            args.asd.initialize_future_session(*pf, APPID_SESSION_EXPECTED_EVALUATE, APP_ID_FROM_RESPONDER);
             pf->common.initiator_ip = *sip;
             pf->service_disco_state = APPID_DISCO_STATE_STATEFUL;
             pf->scan_flags |= SCAN_HOST_PORT_FLAG;
index dbe83887888769dcfe002d97210af32a7d8ee493..e7b7d63c7def1cb328c647122bc6a9110da5a134 100644 (file)
@@ -25,10 +25,6 @@ add_cpputest( appid_discovery_test
     SOURCES $<TARGET_OBJECTS:appid_cpputest_deps>
 )
 
-add_cpputest( appid_expected_flags_test
-    SOURCES $<TARGET_OBJECTS:appid_cpputest_deps>
-)
-
 add_cpputest( appid_http_event_test
     SOURCES $<TARGET_OBJECTS:appid_cpputest_deps>
 )
diff --git a/src/network_inspectors/appid/test/appid_expected_flags_test.cc b/src/network_inspectors/appid/test/appid_expected_flags_test.cc
deleted file mode 100644 (file)
index 5cfcfed..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-//--------------------------------------------------------------------------
-// Copyright (C) 2017-2020 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.
-//--------------------------------------------------------------------------
-
-// appid_expected_flags_test.cc author maya dagon <mdagon@cisco.com>
-
-#include "network_inspectors/appid/appid_detector.cc"
-#include "network_inspectors/appid/service_plugins/service_detector.cc"
-
-#include "appid_mock_definitions.h"
-#include "appid_mock_inspector.h"
-#include "appid_mock_session.h"
-
-#include <CppUTest/CommandLineTestRunner.h>
-#include <CppUTest/TestHarness.h>
-
-snort::Inspector* snort::InspectorManager::get_inspector(
-    char const*, bool, const snort::SnortConfig*) { return nullptr; }
-
-void ApplicationDescriptor::set_id(
-    const Packet&, AppIdSession&, AppidSessionDirection, AppId, AppidChangeBits&) { }
-
-void AppIdHttpSession::set_http_change_bits(AppidChangeBits&, HttpFieldIds) {}
-
-class MockServiceDetector : public ServiceDetector
-{
-public:
-    int validate(AppIdDiscoveryArgs&) override { return 0; }
-};
-
-AppIdSession* parent = nullptr;
-AppIdSession* expected = nullptr;
-MockServiceDetector test_detector;
-
-uint64_t allFlags = APPID_SESSION_RESPONDER_MONITORED |  APPID_SESSION_INITIATOR_MONITORED |
-    APPID_SESSION_SPECIAL_MONITORED | APPID_SESSION_RESPONDER_CHECKED |
-    APPID_SESSION_INITIATOR_CHECKED | APPID_SESSION_DISCOVER_APP |
-    APPID_SESSION_DISCOVER_USER;
-
-static inline void cleanup()
-{
-    parent->clear_session_flags(allFlags);
-    expected->clear_session_flags(allFlags);
-}
-
-TEST_GROUP(appid_expected_flags)
-{
-    void setup() override
-    {
-        MemoryLeakWarningPlugin::turnOffNewDeleteOverloads();
-        parent = new AppIdSession(IpProtocol::TCP, nullptr, 1492, dummy_appid_inspector);
-        expected = new AppIdSession(IpProtocol::TCP, nullptr, 1492, dummy_appid_inspector);
-    }
-
-    void teardown() override
-    {
-        delete parent;
-        delete expected;
-        MemoryLeakWarningPlugin::turnOnNewDeleteOverloads();
-    }
-};
-
-TEST(appid_expected_flags, test1)
-{
-    // Test 1 - expected flow same direction as parent, initiator monitored
-    parent->set_session_flags(APPID_SESSION_INITIATOR_CHECKED | APPID_SESSION_INITIATOR_MONITORED);
-    test_detector.initialize_expected_session(*parent, *expected, 0, APP_ID_FROM_INITIATOR);
-
-    CHECK(expected->get_session_flags(allFlags) ==
-        (APPID_SESSION_INITIATOR_CHECKED | APPID_SESSION_INITIATOR_MONITORED));
-
-    cleanup();
-}
-
-TEST(appid_expected_flags, test2)
-{
-    // Test 2 - expected flow same direction as parent, responder monitored
-    parent->set_session_flags(APPID_SESSION_RESPONDER_CHECKED | APPID_SESSION_RESPONDER_MONITORED);
-    test_detector.initialize_expected_session(*parent, *expected, 0, APP_ID_FROM_INITIATOR);
-
-    CHECK(expected->get_session_flags(allFlags) ==
-        (APPID_SESSION_RESPONDER_CHECKED | APPID_SESSION_RESPONDER_MONITORED));
-
-    cleanup();
-}
-
-TEST(appid_expected_flags, test3)
-{
-    // Test 3 - expected flow same direction as parent, all flags set
-    parent->set_session_flags(allFlags);
-    test_detector.initialize_expected_session(*parent, *expected, 0, APP_ID_FROM_INITIATOR);
-
-    CHECK(expected->get_session_flags(allFlags) == allFlags);
-
-    cleanup();
-}
-
-TEST(appid_expected_flags, test4)
-{
-    // Test 4 - expected flow opposite direction as parent, initiator monitored
-    parent->set_session_flags(APPID_SESSION_INITIATOR_CHECKED | APPID_SESSION_INITIATOR_MONITORED);
-    test_detector.initialize_expected_session(*parent, *expected, 0, APP_ID_FROM_RESPONDER);
-
-    CHECK(expected->get_session_flags(allFlags) ==
-        (APPID_SESSION_RESPONDER_CHECKED | APPID_SESSION_RESPONDER_MONITORED));
-
-    cleanup();
-}
-
-TEST(appid_expected_flags, test5)
-{
-    // Test 5 - expected flow opposite direction as parent, responder monitored
-    parent->set_session_flags(APPID_SESSION_RESPONDER_CHECKED | APPID_SESSION_RESPONDER_MONITORED);
-    test_detector.initialize_expected_session(*parent, *expected, 0, APP_ID_FROM_RESPONDER);
-
-    CHECK(expected->get_session_flags(allFlags) ==
-        (APPID_SESSION_INITIATOR_CHECKED | APPID_SESSION_INITIATOR_MONITORED));
-
-    cleanup();
-}
-
-TEST(appid_expected_flags, test6)
-{
-    // Test 6 - expected flow opposite direction as parent, all flags set
-    parent->set_session_flags(allFlags);
-    test_detector.initialize_expected_session(*parent, *expected, 0, APP_ID_FROM_RESPONDER);
-
-    CHECK(expected->get_session_flags(allFlags) == allFlags);
-
-    cleanup();
-}
-
-int main(int argc, char** argv)
-{
-    mock_init_appid_pegs();
-    int rc = CommandLineTestRunner::RunAllTests(argc, argv);
-    mock_cleanup_appid_pegs();
-    return rc;
-}
-
index fc79d75686aaa0c64b0ae2a1d1a853a1be13e3a1..5c62a56817af0237525e2ea7adb3604d93bdaf6e 100644 (file)
@@ -3,6 +3,7 @@ set (PUB_SUB_INCLUDES
     cip_events.h
     data_decrypt_event.h
     daq_message_event.h
+    dcerpc_events.h
     expect_events.h
     finalize_packet_event.h
     http_events.h
diff --git a/src/pub_sub/dcerpc_events.h b/src/pub_sub/dcerpc_events.h
new file mode 100644 (file)
index 0000000..3b28ff8
--- /dev/null
@@ -0,0 +1,63 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 Cisco and/or its affiliates. All rights reserved.
+//--------------------------------------------------------------------------
+
+#ifndef DCERPC_EVENTS_H
+#define DCERPC_EVENTS_H
+
+#include "framework/data_bus.h"
+
+#define DCERPC_EXP_SESSION_EVENT_KEY "dcerpc_expected_session_event"
+
+namespace snort
+{
+struct SfIp;
+}
+
+class DceExpectedSessionEvent : public snort::DataEvent
+{
+public:
+
+    DceExpectedSessionEvent(snort::Packet* p,
+        const snort::SfIp* src_ip, const uint16_t src_port,
+        const snort::SfIp* dst_ip, const uint16_t dst_port,
+        IpProtocol proto, SnortProtocolId protocol_id) :
+            p(p), src_ip(src_ip), src_port(src_port),
+            dst_ip(dst_ip), dst_port(dst_port),
+            proto(proto), protocol_id(protocol_id) { }
+
+    const snort::Packet* get_packet() override
+    { return p; }
+
+    const snort::SfIp* get_src_ip() const 
+    { return src_ip; }
+    
+    const snort::SfIp* get_dst_ip() const 
+    { return dst_ip; }
+    
+    uint16_t get_src_port() const 
+    { return src_port; }
+    
+    uint16_t get_dst_port() const 
+    { return dst_port; }
+
+    SnortProtocolId get_proto_id() const 
+    { return protocol_id; }
+
+    IpProtocol get_ip_proto() const 
+    { return proto; }
+
+private:
+    const snort::Packet* p;
+
+    const snort::SfIp* src_ip;
+    uint16_t src_port;
+
+    const snort::SfIp* dst_ip;
+    uint16_t dst_port;
+
+    IpProtocol proto;
+    SnortProtocolId protocol_id;
+};
+
+#endif // DCERPC_EVENTS_H
index aa055282e024e006f47af8eb4f01281ab2399fbe..c94c51bab9ecb728cda6a4829c7c404581677772 100644 (file)
@@ -6,6 +6,8 @@ set( FILE_LIST
     dce_common.h
     dce_context_data.cc
     dce_context_data.h
+    dce_expected_session.cc
+    dce_expected_session.h
     dce_http_proxy.cc
     dce_http_proxy_module.cc
     dce_http_proxy_module.h
index 066867da1ddd8fc8dc01da486e6cc7f0b6e3e6c1..ac88475f373a95444da9286147f4a68d1e14bd04 100644 (file)
 
 #include "utils/util.h"
 
+#include "dce_expected_session.h"
 #include "dce_smb.h"
 #include "dce_smb_module.h"
 #include "dce_smb_utils.h"
 #include "dce_tcp.h"
-#include "dce_tcp_module.h"
 
 using namespace snort;
 
 static THREAD_LOCAL int co_reassembled = 0;
 
+/* [MS-RPCE] 2.2.5 - 64-Bit Network Data Representation */
+static const Uuid uuid_ndr64 = { 0x71710533, 0xbeba, 0x4937, 0x83, 0x19,
+    { 0xb5, 0xdb, 0xef, 0x9c, 0xcc, 0x36 } };
+
+/********************************************************************
+ * Function: DCE2_CoEptMapResponse()
+ *
+ * Handles the processing of EPT_MAP response.
+ * The response consists of a tower array that embeds tower pointers.
+ * Pointers, in turn, consist of floors. Our target is 4 & 5 floors,
+ * which contain info about future sessions.
+ *
+ ********************************************************************/
+static void DCE2_CoEptMapResponse(const DCE2_CoTracker* cot, const DceRpcCoHdr* co_hdr,
+    const uint8_t* stub_data, uint16_t dlen)
+{
+    DCE2_CoCtxIdNode* ctx_id_node;
+    uint64_t actual_count;
+    uint64_t tptr_length; /* Tower pointer length */
+    unsigned int i;
+    int ndr_flen = 4; /* 4-bytes fields in default NDR */
+    int offset = 0;
+    int floor3_start;
+    int proto_offset;
+    int port_offset;
+    int ip_addr_offset;
+    uint16_t ept_port;
+    SfIp ept_ip_addr;
+    DceRpcBoFlag byte_order;
+
+    if (stub_data == nullptr || dlen == 0)
+        return;
+
+    ctx_id_node = (DCE2_CoCtxIdNode*)DCE2_ListFind(cot->ctx_ids,
+        (void*)(uintptr_t)cot->ctx_id);
+
+    if (ctx_id_node == nullptr)
+        return;
+
+    if (ctx_id_node->transport == DCE2_CO_CTX_TRANS_SYNTAX_NDR64)
+        ndr_flen = 8; /* 8-bytes fields in NDR64 */
+
+    /*                     20                       4
+     * +---------------------------------------+--------+
+     * |                  Handle               | N Twrs |
+     * +---------------------------------------+--------+
+     * Length of the next fields depends on transport
+     * (NDR/NDR64, 4/8 bytes). Conformant & Varying Arr hdrs.
+     * +---------------+---------------+----------------+
+     * |   Max Count   |    Offset     |  Actual Count  |
+     * +---------------+---------------+----------------+ */
+    offset += DCE2_CO_MAP_HANDLE_OFS + DCE2_CO_MAP_NUM_TOWERS_OFS + 2 * ndr_flen;
+
+    /* Get the actual count of pointers in tower array */
+    byte_order = DceRpcCoByteOrder(co_hdr);
+    offset += DCE2_GetNdrUint3264(stub_data + offset, actual_count,
+        offset, byte_order, ctx_id_node->transport);
+
+    /* Skipping Referent IDs and moving to deferred pointers representation */
+    offset += actual_count * ndr_flen;
+    dce2_move(stub_data, dlen, offset);
+
+    for (i = 0; i < actual_count; i++)
+    {
+        int fc_offset;
+        uint16_t floor_count;
+        /*        4/8          4
+         * +---------------+--------+
+         * |     Length    | Length |
+         * +---------------+--------+
+         * The first len field seems to be a conformant array header,
+         * the second one tower length field.
+         *        2
+         * +-------------+---------+---------+---------+---------+
+         * | floor count | floor 1 | floor 2 |   ...   | floor n |
+         * +-------------+---------+---------+---------+---------+ 
+         * The target is 4th & 5th floors */
+
+        /* Get tower length and determine the floor count offset */
+        fc_offset = DCE2_GetNdrUint3264(stub_data, tptr_length,
+            offset, byte_order, ctx_id_node->transport) + DCE2_CO_MAP_TWR_LEN_OFS;
+        if (dlen < tptr_length)
+            return;
+
+        floor_count = DceRpcNtohs((const uint16_t*)(stub_data + fc_offset),
+            DceRpcCoByteOrder(co_hdr));
+
+        offset += fc_offset;
+        dce2_move(stub_data, dlen, fc_offset);
+
+        /* No needed data for the pinhole creation */
+        if (floor_count < 5) 
+            continue;
+
+        floor3_start =  2 * DCE2_CO_MAP_TWR_FLOOR12_OFS +
+            DCE2_CO_MAP_FLR_COUNT_OFS;
+        
+        /* Skipping 1st & 2nd floors up to 3rd floor protocol id */
+        proto_offset = floor3_start +
+            DCE2_CO_MAP_FLR_LHS_RHS_OFS;
+
+        /* Check protocol, expected to be connection-oriented */
+        if (*(stub_data + proto_offset) != DCE2_CO_PROTO_ID_CO)
+            return;
+
+        port_offset = floor3_start + DCE2_CO_MAP_TWR_FLOOR34_OFS +
+            2 * DCE2_CO_MAP_FLR_LHS_RHS_OFS + DCE2_CO_MAP_FLR_PROTO_ID_OFS;
+
+        ip_addr_offset = port_offset +
+            DCE2_CO_MAP_TWR_FLOOR34_OFS;
+
+        ept_port = DceRpcNtohs((const uint16_t*)(stub_data + port_offset),
+            DCERPC_BO_FLAG__BIG_ENDIAN);
+
+        /* According to DCE RPC 1.1, host address is 4 octets, big-endian order */
+        ept_ip_addr.set(stub_data + ip_addr_offset, AF_INET);
+
+        DceExpSsnManager::create_expected_session(&ept_ip_addr, ept_port, DCE2_TCP_NAME);
+
+        offset += tptr_length;
+        dce2_move(stub_data, dlen, tptr_length);
+    }
+}
+
 /********************************************************************
  * Function: DCE2_CoInitTracker()
  *
@@ -585,6 +709,7 @@ static DCE2_CoCtxIdNode* dce_co_process_ctx_id(DCE2_SsnData* sd,DCE2_CoTracker*
     ctx_node->iface_vers_maj = if_vers_maj;
     ctx_node->iface_vers_min = if_vers_min;
     ctx_node->state = DCE2_CO_CTX_STATE__PENDING;
+    ctx_node->transport = DCE2_CO_CTX_TRANS_SYNTAX_NDR_DEF;
     return ctx_node;
 }
 
@@ -639,7 +764,8 @@ static void DCE2_CoCtxReq(DCE2_SsnData* sd, DCE2_CoTracker* cot, const DceRpcCoH
 }
 
 static void dce_co_process_ctx_result(DCE2_SsnData*, DCE2_CoTracker* cot,
-    const DceRpcCoHdr* co_hdr,DCE2_Policy policy, uint16_t result)
+    const DceRpcCoHdr* co_hdr, DCE2_Policy policy, uint16_t result,
+    const Uuid* transport)
 {
     DCE2_CoCtxIdNode* ctx_node, * existing_ctx_node;
     DCE2_Ret status;
@@ -657,6 +783,13 @@ static void dce_co_process_ctx_result(DCE2_SsnData*, DCE2_CoTracker* cot,
         ctx_node->state = DCE2_CO_CTX_STATE__ACCEPTED;
         if (DceRpcCoPduType(co_hdr) == DCERPC_PDU_TYPE__BIND_ACK)
             cot->got_bind = 1;
+
+        /* Need to check accepted transfer syntax 
+         * for further EPT_MAP response parsing */
+        if (!DCE2_UuidCompare(transport, &uuid_ndr64))
+        {
+            ctx_node->transport = DCE2_CO_CTX_TRANS_SYNTAX_NDR64;
+        }
     }
     else
     {
@@ -804,6 +937,7 @@ static void DCE2_CoBindAck(DCE2_SsnData* sd, DCE2_CoTracker* cot,
     for (i = 0; i < num_ctx_results; i++)
     {
         const DceRpcCoContResult* ctx_result;
+        const Uuid* transport;
         uint16_t result;
 
         if (ctx_len < sizeof(DceRpcCoContResult))
@@ -812,6 +946,7 @@ static void DCE2_CoBindAck(DCE2_SsnData* sd, DCE2_CoTracker* cot,
             return;
         }
         ctx_result = (const DceRpcCoContResult*)ctx_data;
+        transport = DceRpcCoContResTransport(ctx_result);
         result = DceRpcCoContRes(co_hdr, ctx_result);
 
         dce2_move(ctx_data, ctx_len, sizeof(DceRpcCoContResult));
@@ -819,7 +954,7 @@ static void DCE2_CoBindAck(DCE2_SsnData* sd, DCE2_CoTracker* cot,
         if (DCE2_QueueIsEmpty(cot->pending_ctx_ids))
             return;
 
-        dce_co_process_ctx_result(sd,cot,co_hdr,policy,result);
+        dce_co_process_ctx_result(sd,cot,co_hdr,policy,result,transport);
     }
 }
 
@@ -1706,6 +1841,30 @@ static void DCE2_CoResponse(DCE2_SsnData* sd, DCE2_CoTracker* cot,
                 (uint16_t)(frag_len - (uint16_t)auth_len));
         }
     }
+    
+    /* If this is the last fragment, we can proceed with stub data processing */
+    if (DceRpcCoLastFrag(co_hdr))
+    {
+        const uint8_t* stub_data; 
+        uint16_t stub_data_len;
+        if (DCE2_BufferIsEmpty(cot->frag_tracker.srv_stub_buf))
+        {
+            /* Data reassembled from multiple TSDUs */
+            stub_data = frag_ptr;
+            stub_data_len = frag_len;
+        }
+        else
+        {
+            /* Data received from single TSDU */
+            stub_data = cot->frag_tracker.srv_stub_buf->data;
+            stub_data_len = cot->frag_tracker.srv_stub_buf->len;
+        }
+
+        if (cot->opnum == DCE2_CO_EPT_MAP)
+        {
+            DCE2_CoEptMapResponse(cot, co_hdr, stub_data, stub_data_len);
+        }
+    }
 }
 
 /********************************************************************
index 5a26a62dacbc5387ebbf69add06cb6ea4f0aeb52..78671c632a2d033587342f3ce8254b5b3e2a8e29 100644 (file)
 #define DCE2_CO_FRAG_DIFF_OPNUM             38
 #define DCE2_CO_FRAG_DIFF_CTX_ID            39
 
+/* Map response fields offsets */
+#define DCE2_CO_MAP_HANDLE_OFS              20
+#define DCE2_CO_MAP_NUM_TOWERS_OFS          4
+#define DCE2_CO_MAP_TWR_FLOOR12_OFS         25
+#define DCE2_CO_MAP_TWR_FLOOR34_OFS         7
+#define DCE2_CO_MAP_TWR_LEN_OFS             4
+#define DCE2_CO_MAP_FLR_COUNT_OFS           2
+#define DCE2_CO_MAP_FLR_LHS_RHS_OFS         2
+#define DCE2_CO_MAP_FLR_PROTO_ID_OFS        1
+
+/* Protocol IDs. Not a full list.
+ * Refer to DCE RPC 1.1 Appendix I */
+#define DCE2_CO_PROTO_DOD_TCP               0x07
+#define DCE2_CO_PROTO_ID_CO                 0x0b
+
 #define DCE2_CO_BAD_MAJOR_VERSION_STR  "connection oriented DCE/RPC - invalid major version"
 #define DCE2_CO_BAD_MINOR_VERSION_STR  "connection oriented DCE/RPC - invalid minor version"
 #define DCE2_CO_BAD_PDU_TYPE_STR       "connection-oriented DCE/RPC - invalid PDU type"
@@ -242,6 +257,25 @@ enum DCE2_CoCtxState
     DCE2_CO_CTX_STATE__PENDING
 };
 
+enum DCE2_CoCtxTransport
+{
+    /* Default 32-Bit NDR defined in DCE RPC 1.1 */
+    DCE2_CO_CTX_TRANS_SYNTAX_NDR_DEF,
+    /* 64-Bit NDR defined in [MS-RPCE] */
+    DCE2_CO_CTX_TRANS_SYNTAX_NDR64
+};
+
+enum DCE2_CoEpmOpnum {
+    DCE2_CO_EPT_NONE = -1,
+    DCE2_CO_EPT_INSERT = 0,
+    DCE2_CO_EPT_DELETE,
+    DCE2_CO_EPT_LOOKUP,
+    DCE2_CO_EPT_MAP,
+    DCE2_CO_EPT_LKUP_HANDLE_FREE,
+    DCE2_CO_EPT_INQ_OBJECT,
+    DCE2_CO_EPT_MGMT_DELETE
+};
+
 struct DCE2_CoCtxIdNode
 {
     uint16_t ctx_id;           /* The context id */
@@ -252,6 +286,7 @@ struct DCE2_CoCtxIdNode
     /* Whether or not the server accepted or rejected the client bind/alter context
      * request.  Initially set to pending until server response */
     DCE2_CoCtxState state;
+    DCE2_CoCtxTransport transport; 
 };
 
 enum DceRpcCoAuthLevelType
@@ -349,6 +384,11 @@ inline uint16_t DceRpcCoContRes(const DceRpcCoHdr* co, const DceRpcCoContResult*
     return DceRpcNtohs(&cocr->result, DceRpcCoByteOrder(co));
 }
 
+inline const Uuid* DceRpcCoContResTransport(const DceRpcCoContResult* cocr)
+{
+    return &cocr->transfer_syntax.if_uuid;
+}
+
 inline int DceRpcCoObjectFlag(const DceRpcCoHdr* co)
 {
     return co->pfc_flags & DCERPC_CO_PFC_FLAGS__OBJECT_UUID;
@@ -409,6 +449,54 @@ inline uint16_t DceRpcCoCtxId(const DceRpcCoHdr* co, const DceRpcCoRequest* cor)
     return DceRpcNtohs(&cor->context_id, DceRpcCoByteOrder(co));
 }
 
+inline int DCE2_GetNdrUint32(const uint8_t* data_ptr, uint32_t& data,
+    int offset, DceRpcBoFlag bo_flag)
+{
+    const uint32_t* ptr;
+    int align_offset = 0;
+
+    /* Alignment */
+    if (offset % 4) 
+    {
+        align_offset = 4 - (offset % 4);
+    }
+
+    ptr = (const uint32_t*)(data_ptr + align_offset);
+    data = DceRpcNtohl(ptr, bo_flag);
+
+    return align_offset + 4;
+}
+
+inline int DCE2_GetNdrUint64(const uint8_t* data_ptr, uint64_t& data,
+    int offset, DceRpcBoFlag bo_flag)
+{
+    const uint64_t* ptr;
+    int align_offset = 0;
+
+    /* Alignment */
+    if (offset % 8) 
+    {
+        align_offset = 8 - (offset % 8);
+    }
+
+    ptr = (const uint64_t*)(data_ptr + align_offset);
+    data = DceRpcNtohl64(ptr, bo_flag);
+
+    return align_offset + 8;
+}
+
+inline int DCE2_GetNdrUint3264(const uint8_t* data_ptr, uint64_t& data,
+    int offset, DceRpcBoFlag bo_flag, DCE2_CoCtxTransport transport)
+{
+    if (transport == DCE2_CO_CTX_TRANS_SYNTAX_NDR64)
+        return DCE2_GetNdrUint64(data_ptr, data, offset, bo_flag);
+
+    uint32_t val = 0;
+    offset = DCE2_GetNdrUint32(data_ptr, val, offset, bo_flag);
+    data = val;
+    return offset;
+}
+
 void DCE2_CoInitTracker(DCE2_CoTracker*);
 void DCE2_CoProcess(DCE2_SsnData*, DCE2_CoTracker*,
     const uint8_t*, uint16_t);
diff --git a/src/service_inspectors/dce_rpc/dce_expected_session.cc b/src/service_inspectors/dce_rpc/dce_expected_session.cc
new file mode 100644 (file)
index 0000000..e6a58fe
--- /dev/null
@@ -0,0 +1,93 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 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_expected_session.cc author Eduard Burmai <eburmai@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "dce_expected_session.h"
+
+#include "managers/inspector_manager.h"
+#include "pub_sub/dcerpc_events.h"
+#include "stream/stream.h"
+
+#include "dce_tcp.h"
+
+using namespace snort;
+
+DceExpSsnManager::DceExpSsnManager(const char* protocol,
+    IpProtocol proto, PktType type): proto(proto), type(type) 
+{
+    protocol_id = SnortConfig::get_conf()->proto_ref->add(protocol);
+}
+
+void DceExpSsnManager::create_expected_session(const SfIp* ept_ip,
+    uint16_t ept_port, const char* mod_name)
+{
+    Packet* pkt = DetectionEngine::get_current_packet();
+    Dce2Tcp* inspector = (Dce2Tcp*)InspectorManager::get_inspector(mod_name, true);
+    DceExpSsnManager& esm = inspector->get_esm();
+
+    const SfIp* src_ip = pkt->ptrs.ip_api.get_dst();
+    PktType type = esm.get_pkt_type();
+    IpProtocol proto = esm.get_ip_proto();
+    SnortProtocolId protocol_id = esm.get_proto_id();
+
+    if (esm.create_expected_session_impl(pkt, src_ip, 0,
+        ept_ip, ept_port, type, proto, protocol_id))
+        return;
+
+    dce2_tcp_stats.tcp_expected_sessions++;
+
+    DceExpectedSessionEvent map_resp_event(pkt, src_ip, 0,
+        ept_ip, ept_port, proto, protocol_id);
+    DataBus::publish(DCERPC_EXP_SESSION_EVENT_KEY, map_resp_event, pkt->flow);
+}
+
+DceTcpExpSsnManager::DceTcpExpSsnManager(dce2TcpProtoConf& config) :
+    DceExpSsnManager("dce-tcp", IpProtocol::TCP, PktType::TCP),
+    pc(config) { }
+
+int DceTcpExpSsnManager::create_expected_session_impl(Packet* pkt,
+    const snort::SfIp* src_ip, uint16_t src_port,
+    const snort::SfIp* dst_ip, uint16_t dst_port,
+    PktType type, IpProtocol proto, SnortProtocolId protocol_id)
+{
+    Dce2TcpFlowData* fd = new Dce2TcpFlowData;
+
+    fd->state = DCE2_TCP_FLOW__EXPECTED;
+    memset(&fd->dce2_tcp_session, 0, sizeof(DCE2_TcpSsnData));
+    DCE2_CoInitTracker(&fd->dce2_tcp_session.co_tracker);
+    DCE2_ResetRopts(&fd->dce2_tcp_session.sd, pkt);
+
+    fd->dce2_tcp_session.sd.trans = DCE2_TRANS_TYPE__TCP;
+    fd->dce2_tcp_session.sd.server_policy = pc.common.policy;
+    fd->dce2_tcp_session.sd.client_policy = DCE2_POLICY__WINXP;
+    fd->dce2_tcp_session.sd.config = (void*)&pc;
+
+    if (Stream::set_snort_protocol_id_expected(pkt, type,
+        proto, src_ip, src_port, dst_ip, dst_port, protocol_id, fd))
+    {
+        delete fd;
+        return -1;
+    }
+
+    return 0;
+}
diff --git a/src/service_inspectors/dce_rpc/dce_expected_session.h b/src/service_inspectors/dce_rpc/dce_expected_session.h
new file mode 100644 (file)
index 0000000..0db9bd2
--- /dev/null
@@ -0,0 +1,81 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 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_expected_session.h author Eduard Burmai <eburmai@cisco.com>
+
+#ifndef DCE_EXPECTED_SESSION_H
+#define DCE_EXPECTED_SESSION_H
+
+#include "framework/decode_data.h"
+#include "target_based/snort_protocols.h"
+
+namespace snort
+{
+struct Packet;
+struct SfIp;
+}
+
+struct dce2TcpProtoConf;
+
+// Expected Session Manager
+class DceExpSsnManager
+{
+public:
+    DceExpSsnManager(const char*, IpProtocol, PktType);
+    virtual ~DceExpSsnManager() = default;
+
+    SnortProtocolId get_proto_id() const
+    { return protocol_id; }
+
+    IpProtocol get_ip_proto() const
+    { return proto; }
+
+    PktType get_pkt_type() const
+    { return type; }
+
+    static void create_expected_session(const snort::SfIp*, uint16_t, const char*);
+
+private:
+    virtual int create_expected_session_impl(snort::Packet*,
+        const snort::SfIp*, uint16_t, const snort::SfIp*, uint16_t,
+        PktType, IpProtocol, SnortProtocolId) = 0;
+
+private:
+    SnortProtocolId protocol_id;
+    IpProtocol proto;
+    PktType type;
+};
+
+class DceTcpExpSsnManager : public DceExpSsnManager
+{
+public:
+    DceTcpExpSsnManager() = delete;
+    DceTcpExpSsnManager(dce2TcpProtoConf&);
+    DceTcpExpSsnManager(const DceTcpExpSsnManager&) = delete;
+    DceTcpExpSsnManager& operator=(const DceTcpExpSsnManager&) =delete;
+
+private:
+    int create_expected_session_impl(snort::Packet*,
+        const snort::SfIp*, uint16_t, const snort::SfIp*, uint16_t,
+        PktType, IpProtocol, SnortProtocolId) override;
+
+private:
+    const dce2TcpProtoConf& pc;
+};
+
+#endif // DCE_EXPECTED_SESSION_H
index 88c8877f085d11a534d54ee5c1e9efea5e78971b..31e28a28cb42067552b780f59962227cb38750c6 100644 (file)
@@ -30,8 +30,6 @@
 
 #include "dce_context_data.h"
 #include "dce_common.h"
-#include "dce_tcp_module.h"
-#include "dce_tcp_paf.h"
 
 using namespace snort;
 
@@ -57,6 +55,13 @@ unsigned Dce2TcpFlowData::inspector_id = 0;
 DCE2_TcpSsnData* get_dce2_tcp_session_data(Flow* flow)
 {
     Dce2TcpFlowData* fd = (Dce2TcpFlowData*)flow->get_flow_data(Dce2TcpFlowData::inspector_id);
+
+    // check whether this session was expected and mark it as realized
+    if (fd && fd->state == DCE2_TCP_FLOW__EXPECTED)
+    {
+        fd->state = DCE2_TCP_FLOW__REALIZED;
+        dce2_tcp_stats.tcp_expected_realized_sessions++;
+    }
     return fd ? &fd->dce2_tcp_session : nullptr;
 }
 
@@ -64,6 +69,7 @@ static DCE2_TcpSsnData* set_new_dce2_tcp_session(Packet* p)
 {
     Dce2TcpFlowData* fd = new Dce2TcpFlowData;
 
+    fd->state = DCE2_TCP_FLOW__COMMON;
     memset(&fd->dce2_tcp_session,0,sizeof(DCE2_TcpSsnData));
     p->flow->set_flow_data(fd);
     return(&fd->dce2_tcp_session);
@@ -104,28 +110,8 @@ static DCE2_TcpSsnData* dce2_handle_tcp_session(Packet* p, dce2TcpProtoConf* con
 //-------------------------------------------------------------------------
 // class stuff
 //-------------------------------------------------------------------------
-
-class Dce2Tcp : public Inspector
-{
-public:
-    Dce2Tcp(const dce2TcpProtoConf&);
-
-    void show(const SnortConfig*) const override;
-    void eval(Packet*) override;
-    void clear(Packet*) override;
-    StreamSplitter* get_splitter(bool c2s) override
-    {
-        return new Dce2TcpSplitter(c2s);
-    }
-
-private:
-    dce2TcpProtoConf config;
-};
-
-Dce2Tcp::Dce2Tcp(const dce2TcpProtoConf& pc)
-{
-    config = pc;
-}
+Dce2Tcp::Dce2Tcp(const dce2TcpProtoConf& pc) :
+    config(pc), esm(config) { }
 
 void Dce2Tcp::show(const SnortConfig*) const
 {
index df3f15092b8f6c4b40c67c7266ab06403663e5e6..3a3380cf038ca3ac9e4e6c1d7f98027030bd9d7e 100644 (file)
 #ifndef DCE_TCP_H
 #define DCE_TCP_H
 
+#include "framework/inspector.h"
 #include "profiler/profiler_defs.h"
 
 #include "dce_co.h"
+#include "dce_expected_session.h"
+#include "dce_tcp_module.h"
+#include "dce_tcp_paf.h"
 
 #define DCE2_TCP_NAME "dce_tcp"
 #define DCE2_TCP_HELP "dce over tcp inspection"
@@ -64,6 +68,8 @@ struct dce2TcpStats
 
     /*DCE TCP specific*/
     PegCount tcp_sessions;
+    PegCount tcp_expected_sessions;
+    PegCount tcp_expected_realized_sessions;
     PegCount tcp_pkts;
     PegCount concurrent_sessions;
     PegCount max_concurrent_sessions;
@@ -103,6 +109,13 @@ struct DCE2_TcpSsnData
     DCE2_CoTracker co_tracker;
 };
 
+enum DCE2_TcpFlowState
+{
+    DCE2_TCP_FLOW__COMMON,
+    DCE2_TCP_FLOW__EXPECTED,
+    DCE2_TCP_FLOW__REALIZED
+};
+
 class Dce2TcpFlowData : public snort::FlowData
 {
 public:
@@ -118,6 +131,27 @@ public:
 public:
     static unsigned inspector_id;
     DCE2_TcpSsnData dce2_tcp_session;
+    DCE2_TcpFlowState state;
+};
+
+class Dce2Tcp : public snort::Inspector
+{
+public:
+    Dce2Tcp(const dce2TcpProtoConf&);
+
+    void show(const snort::SnortConfig*) const override;
+    void eval(snort::Packet*) override;
+    void clear(snort::Packet*) override;
+
+    DceTcpExpSsnManager& get_esm()
+    { return esm; }
+
+    snort::StreamSplitter* get_splitter(bool c2s) override
+    { return new Dce2TcpSplitter(c2s); }
+
+private:
+    dce2TcpProtoConf config;
+    DceTcpExpSsnManager esm;
 };
 
 DCE2_TcpSsnData* get_dce2_tcp_session_data(snort::Flow*);
index 1dfc2f3a25896feb29cee85acfac8755aea89f5a..b1e4d5fa122e6390756a600235258ebb5d59e351 100644 (file)
@@ -112,6 +112,8 @@ static const PegInfo dce2_tcp_pegs[] =
     { CountType::SUM, "server_frags_reassembled",
         "total connection-oriented server fragments reassembled" },
     { CountType::SUM, "tcp_sessions", "total tcp sessions" },
+    { CountType::SUM, "tcp_expected_sessions", "total tcp dynamic endpoint expected sessions" },
+    { CountType::SUM, "tcp_expected_realized", "total tcp dynamic endpoint expected realized sessions" },
     { CountType::SUM, "tcp_packets", "total tcp packets" },
     { CountType::NOW, "concurrent_sessions", "total concurrent sessions" },
     { CountType::MAX, "max_concurrent_sessions", "maximum concurrent sessions" },
index d48e20f9f329c9c902df3d25e000dfb53c3bce47..2379297daf3e9e38a570d692751d002f3ca7756f 100644 (file)
@@ -344,6 +344,36 @@ inline uint32_t DceRpcHtonl(const uint32_t* ptr, const DceRpcBoFlag bo_flag)
     return DceRpcNtohl(ptr, bo_flag);
 }
 
+inline uint64_t DceRpcNtohl64(const uint64_t* ptr, const DceRpcBoFlag bo_flag)
+{
+    uint64_t value;
+
+    if (ptr == nullptr)
+        return 0;
+
+    value = *ptr;
+
+    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 & 0xff00000000000000) >> 56) | ((value & 0x00ff000000000000) >> 40) |
+           ((value & 0x0000ff0000000000) >> 24) | ((value & 0x000000ff00000000) >> 8) |
+           ((value & 0x00000000000000ff) << 56) | ((value & 0x000000000000ff00) << 40) |
+           ((value & 0x0000000000ff0000) << 24) | ((value & 0x00000000ff000000) << 8);
+}
+
+inline uint64_t DceRpcHtonl64(const uint64_t* ptr, const DceRpcBoFlag bo_flag)
+{
+    return DceRpcNtohl64(ptr, bo_flag);
+}
+
 inline void DCE2_CopyUuid(Uuid* dst_uuid, const Uuid* pkt_uuid, const DceRpcBoFlag byte_order)
 {
     dst_uuid->time_low = DceRpcNtohl(&pkt_uuid->time_low, byte_order);
@@ -410,4 +440,3 @@ inline void dce2_move(const uint8_t*& data_ptr, int64_t& data_len, int amount)
 }
 
 #endif
-