From: Cynthia Leonard (cyleonar) Date: Tue, 10 Nov 2020 06:31:07 +0000 (+0000) Subject: Merge pull request #2595 in SNORT/snort3 from ~KDEWANGA/snort3:ftp_test to master X-Git-Tag: 3.0.3-5~7 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6cc0d6cc74a83bd852fc64a299f66667917b8718;p=thirdparty%2Fsnort3.git Merge pull request #2595 in SNORT/snort3 from ~KDEWANGA/snort3:ftp_test to master Squashed commit of the following: commit 2cd7609ecc9008ca733be3cabb7ff3aacdb01fc1 Author: kdewanga Date: Wed Nov 4 04:48:06 2020 -0500 ftp: Handling FTP detection when ftp data segment size changes --- diff --git a/src/service_inspectors/ftp_telnet/ftp_data.cc b/src/service_inspectors/ftp_telnet/ftp_data.cc index f00f84c9a..52bc27c30 100644 --- a/src/service_inspectors/ftp_telnet/ftp_data.cc +++ b/src/service_inspectors/ftp_telnet/ftp_data.cc @@ -30,6 +30,7 @@ #include "packet_tracer/packet_tracer.h" #include "parser/parse_rule.h" #include "profiler/profiler.h" +#include "protocols/tcp.h" #include "pub_sub/opportunistic_tls_event.h" #include "stream/stream.h" #include "utils/util.h" @@ -238,16 +239,50 @@ void FtpDataFlowData::handle_expected(Packet* p) } } +void FtpDataFlowData::handle_retransmit(Packet* p) +{ + FTP_DATA_SESSION* data_ssn = &session; + + if ((data_ssn->eof_seq > 0) and (data_ssn->eof_seq == p->ptrs.tcph->seq() + p->dsize)) + { + // only process the final data segment + initFilePosition(&data_ssn->position, get_file_processed_size(p->flow)); + finalFilePosition(&data_ssn->position); + + FileFlows* file_flows = FileFlows::get_file_flows(p->flow); + if (file_flows) + { + file_flows->file_process(DetectionEngine::get_current_packet(), + p->data, 0, SNORT_FILE_END, data_ssn->direction, data_ssn->path_hash); + + eof_handled = true; + } + } +} + void FtpDataFlowData::handle_eof(Packet* p) { FTP_DATA_SESSION* data_ssn = &session; + data_ssn->eof_seq = 0; if (!PROTO_IS_FTP_DATA(data_ssn) || !FTPDataDirection(p, data_ssn)) return; - initFilePosition(&data_ssn->position, get_file_processed_size(p->flow)); - finalFilePosition(&data_ssn->position); - eof_handled = true; + if (p->dsize != 0) + { + initFilePosition(&data_ssn->position, get_file_processed_size(p->flow)); + finalFilePosition(&data_ssn->position); + eof_handled = true; + } + else + { + Active* act = p->active; + act->set_delayed_action(Active::ACT_RETRY, true); + data_ssn->eof_seq = p->ptrs.tcph->seq(); + } + + if (data_ssn->mss_changed) + ftstats.total_sessions_mss_changed++; } //------------------------------------------------------------------------- diff --git a/src/service_inspectors/ftp_telnet/ftp_module.cc b/src/service_inspectors/ftp_telnet/ftp_module.cc index 212a28fe1..8688f14ec 100644 --- a/src/service_inspectors/ftp_telnet/ftp_module.cc +++ b/src/service_inspectors/ftp_telnet/ftp_module.cc @@ -347,7 +347,8 @@ static const PegInfo ftp_pegs[] = { CountType::SUM, "start_tls", "total STARTTLS events generated" }, { CountType::SUM, "ssl_search_abandoned", "total SSL search abandoned" }, { 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::END, nullptr, nullptr } }; diff --git a/src/service_inspectors/ftp_telnet/ftpdata_splitter.cc b/src/service_inspectors/ftp_telnet/ftpdata_splitter.cc index 07e9c4e2b..8414d8fb4 100644 --- a/src/service_inspectors/ftp_telnet/ftpdata_splitter.cc +++ b/src/service_inspectors/ftp_telnet/ftpdata_splitter.cc @@ -26,6 +26,8 @@ #include "detection/detection_engine.h" #include "file_api/file_flows.h" #include "flow/session.h" +#include "packet_io/active.h" +#include "protocols/tcp.h" #include "stream/stream.h" #include "ftpp_si.h" @@ -49,7 +51,10 @@ StreamSplitter::Status FtpDataSplitter::scan(Packet* pkt, const uint8_t*, uint32 { Flow* flow = pkt->flow; assert(flow); + FtpDataFlowData* fdfd = (FtpDataFlowData*)flow->get_flow_data(FtpDataFlowData::inspector_id); + if (!fdfd) + return SEARCH; if ( len ) { if(expected_seg_size == 0) @@ -70,11 +75,24 @@ StreamSplitter::Status FtpDataSplitter::scan(Packet* pkt, const uint8_t*, uint32 if ( len != expected_seg_size ) { - // Treat this as the last packet of the FTP data transfer. - set_ftp_flush_flag(flow); + ftstats.total_packets_mss_changed++; + fdfd->session.mss_changed = true; + if (fdfd->session.bytes_seen == 0) + { + // Segmented pkt is smaller than expected_seg_size + set_ftp_flush_flag(flow); + } + else if (pkt->ptrs.tcph and !pkt->ptrs.tcph->is_fin()) + { + Active* act = pkt->active; + // add packet to retry queue to consider this is not end of ftp flow + if (!(pkt->flow->flags.trigger_detained_packet_event)) + act->set_delayed_action(Active::ACT_RETRY, true); + } expected_seg_size = len; restart_scan(); *fp = len; + fdfd->session.bytes_seen += len; return FLUSH; } else @@ -82,9 +100,11 @@ StreamSplitter::Status FtpDataSplitter::scan(Packet* pkt, const uint8_t*, uint32 segs++; bytes += len; } + fdfd->session.bytes_seen += len; - if ( segs >= 2 && bytes >= min ) + if ((segs >= 2 and bytes >= min) or (pkt->ptrs.tcph and pkt->ptrs.tcph->is_fin())) { + // Either FIN or smaller size do FLUSH to continue inspection restart_scan(); *fp = len; return FLUSH; diff --git a/src/service_inspectors/ftp_telnet/ftpp_si.h b/src/service_inspectors/ftp_telnet/ftpp_si.h index 0feeebaa7..ac1d77831 100644 --- a/src/service_inspectors/ftp_telnet/ftpp_si.h +++ b/src/service_inspectors/ftp_telnet/ftpp_si.h @@ -212,13 +212,16 @@ struct FTP_DATA_SESSION FTP_TELNET_SESSION ft_ssn; snort::FlowKey ftp_key; char* filename; + uint32_t eof_seq; size_t path_hash; int data_chan; int file_xfer_info; FilePosition position; - bool direction; + uint32_t bytes_seen; unsigned char mode; unsigned char packet_flags; + bool direction; + bool mss_changed; }; class FtpDataFlowData : public snort::FlowData @@ -232,7 +235,7 @@ public: void handle_expected(snort::Packet*) override; void handle_eof(snort::Packet*) override; - + void handle_retransmit(snort::Packet*) override; size_t size_of() override { return sizeof(*this); } @@ -293,6 +296,8 @@ struct FtpStats PegCount starttls; PegCount ssl_search_abandoned; PegCount ssl_search_abandoned_too_soon; + PegCount total_packets_mss_changed; + PegCount total_sessions_mss_changed; }; struct TelnetStats