From: Manav Soneja (msoneja) Date: Thu, 19 Sep 2024 07:47:46 +0000 (+0000) Subject: Pull request #4432: ftp_telnet: adding fallback functionality X-Git-Tag: 3.3.7.0~6 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a3d7f31dff6148056c3c6674f33be99d8a5048aa;p=thirdparty%2Fsnort3.git Pull request #4432: ftp_telnet: adding fallback functionality Merge in SNORT/snort3 from ~MSONEJA/snort3:ftp_telnet_fallback to master Squashed commit of the following: commit b64420ab2fa645d2c38aa874d26a2a3525c8a6a8 Author: msoneja Date: Mon Aug 26 06:56:49 2024 +0000 ftp_telnet: adding fallback functionality for ftp --- diff --git a/src/service_inspectors/ftp_telnet/ftp_module.cc b/src/service_inspectors/ftp_telnet/ftp_module.cc index 7d79eb5c1..12deefdaa 100644 --- a/src/service_inspectors/ftp_telnet/ftp_module.cc +++ b/src/service_inspectors/ftp_telnet/ftp_module.cc @@ -216,6 +216,9 @@ FtpCmd::FtpCmd(const std::string& key, const std::string& fmt, int num) "FTP bounce attempt" #define FTP_EVASIVE_TELNET_CMD_STR \ "evasive (incomplete) TELNET cmd on FTP command channel" +#define FTP_ABORTED_SESSION_STR \ + "FTP session aborted as server response invalid" + //------------------------------------------------------------------------- @@ -316,6 +319,7 @@ static const RuleMap ftp_server_rules[] = { FTP_ENCRYPTED, FTP_ENCRYPTED_STR }, { FTP_BOUNCE, FTP_BOUNCE_STR }, { FTP_EVASIVE_TELNET_CMD, FTP_EVASIVE_TELNET_CMD_STR }, + { FTP_ABORTED_SESSION, FTP_ABORTED_SESSION_STR }, { 0, nullptr } }; @@ -331,6 +335,8 @@ static const PegInfo ftp_pegs[] = { CountType::SUM, "ssl_srch_abandoned_early", "total SSL search abandoned too soon" }, { CountType::SUM, "pkt_segment_size_changed", "total number of FTP data packets with segment size change" }, { CountType::SUM, "flow_segment_size_changed", "total number of FTP sessions with segment size change" }, + { CountType::SUM, "total_aborted_sessions", "total aborted sessions" }, + { CountType::END, nullptr, nullptr } }; diff --git a/src/service_inspectors/ftp_telnet/ftp_module.h b/src/service_inspectors/ftp_telnet/ftp_module.h index 9186eb84a..3124db52f 100644 --- a/src/service_inspectors/ftp_telnet/ftp_module.h +++ b/src/service_inspectors/ftp_telnet/ftp_module.h @@ -35,6 +35,7 @@ #define FTP_ENCRYPTED 7 #define FTP_BOUNCE 8 #define FTP_EVASIVE_TELNET_CMD 9 +#define FTP_ABORTED_SESSION 10 namespace snort { diff --git a/src/service_inspectors/ftp_telnet/ftpp_si.h b/src/service_inspectors/ftp_telnet/ftpp_si.h index 730fd428b..f5b400e5b 100644 --- a/src/service_inspectors/ftp_telnet/ftpp_si.h +++ b/src/service_inspectors/ftp_telnet/ftpp_si.h @@ -75,6 +75,7 @@ typedef struct s_FTP_TELNET_SESSION { int proto; + bool fallback; } FTP_TELNET_SESSION; /* @@ -287,6 +288,7 @@ struct FtpStats PegCount ssl_search_abandoned_too_soon; PegCount total_packets_mss_changed; PegCount total_sessions_mss_changed; + PegCount aborted_sessions; }; struct TelnetStats diff --git a/src/service_inspectors/ftp_telnet/pp_ftp.cc b/src/service_inspectors/ftp_telnet/pp_ftp.cc index f7018eab2..01468c5bb 100644 --- a/src/service_inspectors/ftp_telnet/pp_ftp.cc +++ b/src/service_inspectors/ftp_telnet/pp_ftp.cc @@ -1586,15 +1586,20 @@ int check_ftp(FTP_SESSION* ftpssn, Packet* p, int iMode) state = FTP_RESPONSE_ENDCONT; ftpssn->server.response.state = 0; } - else + else if (req->cmd_size == 3) { /* Single line response */ state = FTP_RESPONSE; } + else + { + ftpssn->server.response.state = FTP_RESPONSE_INV; + } + } } - if (ftpssn->server.response.state != 0) + if (ftpssn->server.response.state > FTP_RESPONSE_INV) { req->cmd_begin = nullptr; req->cmd_end = nullptr; @@ -1618,13 +1623,17 @@ int check_ftp(FTP_SESSION* ftpssn, Packet* p, int iMode) /* Continuation of previous response */ state = FTP_RESPONSE_CONT; } - else + else if (req->cmd_size == 3) { /* Start of response, state stays as -2 */ state = FTP_RESPONSE_2BCONT; ftpssn->server.response.state = resp_code; rsp_code = resp_code; } + else + { + ftpssn->server.response.state = FTP_RESPONSE_INV; + } } else { @@ -1692,6 +1701,15 @@ int check_ftp(FTP_SESSION* ftpssn, Packet* p, int iMode) req->pipeline_req = (const char*)read_ptr; else req->pipeline_req = nullptr; + + + if (ftpssn->server.response.state == FTP_RESPONSE_INV) + { + ftpssn->ft_ssn.fallback = true; + DetectionEngine::queue_event(GID_FTP, FTP_ABORTED_SESSION); + ++ftstats.aborted_sessions; + return FTPP_ALERT; + } switch (state) { diff --git a/src/service_inspectors/ftp_telnet/telnet_splitter.cc b/src/service_inspectors/ftp_telnet/telnet_splitter.cc index 2ee5abe69..b042a3673 100644 --- a/src/service_inspectors/ftp_telnet/telnet_splitter.cc +++ b/src/service_inspectors/ftp_telnet/telnet_splitter.cc @@ -25,6 +25,7 @@ #include +#include "ftpp_si.h" #include "protocols/ssl.h" #include "protocols/packet.h" #include "utils/util.h" @@ -40,6 +41,17 @@ StreamSplitter::Status TelnetSplitter::scan( Packet* p, const uint8_t* data, uint32_t len, uint32_t, uint32_t* fp) { + if (p->flow) + { + FTP_TELNET_SESSION* ft_ssn = nullptr; + + FtpFlowData* fd = (FtpFlowData*)p->flow->get_flow_data(FtpFlowData::inspector_id); + ft_ssn = fd ? &fd->session.ft_ssn : nullptr; + + if (ft_ssn && ft_ssn->fallback) + return ABORT; + } + if ( IsSSL(data, len, p->packet_flags) ) { *fp = len;