From 718307214e598adfdd1ebd6ea768b0801b21b138 Mon Sep 17 00:00:00 2001 From: Johanna Amann Date: Tue, 27 May 2025 13:45:23 +0100 Subject: [PATCH] Add explicit TLS support for FTP This is defined in RFC 4217; TLS initialized by the client sending an `AUTH TLS` command. Fixes GH-4463 --- src/analyzer/protocol/ftp/FTP.cc | 19 +++++++++++++++++- src/analyzer/protocol/ftp/FTP.h | 1 + src/analyzer/protocol/ftp/events.bif | 6 ++++++ .../.stdout | 2 ++ .../conn.log | 11 ++++++++++ .../ftp.log | 12 +++++++++++ .../ssl.log | 11 ++++++++++ testing/btest/Traces/ftp/ftp-auth-tls.pcap | Bin 0 -> 11363 bytes .../base/protocols/ftp/ftp-auth-tls.zeek | 13 ++++++++++++ 9 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 testing/btest/Baseline/scripts.base.protocols.ftp.ftp-auth-tls/.stdout create mode 100644 testing/btest/Baseline/scripts.base.protocols.ftp.ftp-auth-tls/conn.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.ftp.ftp-auth-tls/ftp.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.ftp.ftp-auth-tls/ssl.log create mode 100644 testing/btest/Traces/ftp/ftp-auth-tls.pcap create mode 100644 testing/btest/scripts/base/protocols/ftp/ftp-auth-tls.zeek diff --git a/src/analyzer/protocol/ftp/FTP.cc b/src/analyzer/protocol/ftp/FTP.cc index eda45c2148..368162005b 100644 --- a/src/analyzer/protocol/ftp/FTP.cc +++ b/src/analyzer/protocol/ftp/FTP.cc @@ -65,6 +65,11 @@ static bool is_ftp_cmd(int len, const char* s) { void FTP_Analyzer::DeliverStream(int length, const u_char* data, bool orig) { analyzer::tcp::TCP_ApplicationAnalyzer::DeliverStream(length, data, orig); + if ( tls_active ) { + ForwardStream(length, data, orig); + return; + } + if ( (orig && ! ftp_request) || (! orig && ! ftp_reply) ) return; @@ -172,6 +177,17 @@ void FTP_Analyzer::DeliverStream(int length, const u_char* data, bool orig) { } } + if ( reply_code == 234 && auth_requested.size() > 0 && auth_requested == "TLS" ) { + EnqueueConnEvent(ftp_starttls, ConnVal()); + Analyzer* ssl = analyzer_mgr->InstantiateAnalyzer("SSL", Conn()); + if ( ssl ) { + AddChildAnalyzer(ssl); + RemoveSupportAnalyzer(nvt_orig); + RemoveSupportAnalyzer(nvt_resp); + tls_active = true; + } + } + if ( reply_code == 334 && auth_requested.size() > 0 && auth_requested == "GSSAPI" ) { // Server wants to proceed with an ADAT exchange and we // know how to analyze the GSI mechanism, so attach analyzer @@ -192,7 +208,8 @@ void FTP_Analyzer::DeliverStream(int length, const u_char* data, bool orig) { EnqueueConnEvent(f, std::move(vl)); - ForwardStream(length, data, orig); + if ( ! tls_active ) + ForwardStream(length, data, orig); } void FTP_ADAT_Analyzer::DeliverStream(int len, const u_char* data, bool orig) { diff --git a/src/analyzer/protocol/ftp/FTP.h b/src/analyzer/protocol/ftp/FTP.h index f8bae5788b..c0bae38dde 100644 --- a/src/analyzer/protocol/ftp/FTP.h +++ b/src/analyzer/protocol/ftp/FTP.h @@ -24,6 +24,7 @@ protected: analyzer::login::NVT_Analyzer* nvt_resp; uint32_t pending_reply; // code associated with multi-line reply, or 0 std::string auth_requested; // AUTH method requested + bool tls_active = false; // starttls active }; /** diff --git a/src/analyzer/protocol/ftp/events.bif b/src/analyzer/protocol/ftp/events.bif index 6cc2317936..cf102dc582 100644 --- a/src/analyzer/protocol/ftp/events.bif +++ b/src/analyzer/protocol/ftp/events.bif @@ -33,3 +33,9 @@ event ftp_request%(c: connection, command: string, arg: string%); ## parse_ftp_epsv parse_ftp_pasv parse_ftp_port event ftp_reply%(c: connection, code: count, msg: string, cont_resp: bool%); +## Generated if an FTP connection switched to TLS using AUTH TLS. After this +## event no more FTP events will be raised for the connection. See the SSL +## analyzer for related SSL events, which will now be generated. +## +## c: The connection. +event ftp_starttls%(c: connection%); diff --git a/testing/btest/Baseline/scripts.base.protocols.ftp.ftp-auth-tls/.stdout b/testing/btest/Baseline/scripts.base.protocols.ftp.ftp-auth-tls/.stdout new file mode 100644 index 0000000000..ea35dc336b --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ftp.ftp-auth-tls/.stdout @@ -0,0 +1,2 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +starttls, [orig_h=127.0.0.1, orig_p=40284/tcp, resp_h=127.0.0.1, resp_p=21/tcp, proto=6] diff --git a/testing/btest/Baseline/scripts.base.protocols.ftp.ftp-auth-tls/conn.log b/testing/btest/Baseline/scripts.base.protocols.ftp.ftp-auth-tls/conn.log new file mode 100644 index 0000000000..e3d1c23666 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ftp.ftp-auth-tls/conn.log @@ -0,0 +1,11 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path conn +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes conn_state local_orig local_resp missed_bytes history orig_pkts orig_ip_bytes resp_pkts resp_ip_bytes tunnel_parents ip_proto +#types time string addr port addr port enum string interval count count string bool bool count string count count count count set[string] count +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 40284 127.0.0.1 21 tcp ftp,ssl 23.881319 1133 3314 RSTR T T 0 ShAdDafr 40 3221 44 5598 - 6 +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ftp.ftp-auth-tls/ftp.log b/testing/btest/Baseline/scripts.base.protocols.ftp.ftp-auth-tls/ftp.log new file mode 100644 index 0000000000..c3ff41ddf8 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ftp.ftp-auth-tls/ftp.log @@ -0,0 +1,12 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path ftp +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p user password command arg mime_type file_size reply_code reply_msg data_channel.passive data_channel.orig_h data_channel.resp_h data_channel.resp_p fuid +#types time string addr port addr port string string string string string count count string bool addr addr port string +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 40284 127.0.0.1 21 - - - - 220 (vsFTPd 3.0.5) - - - - - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 40284 127.0.0.1 21 - AUTH TLS - - 234 Proceed with negotiation. - - - - - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.ftp.ftp-auth-tls/ssl.log b/testing/btest/Baseline/scripts.base.protocols.ftp.ftp-auth-tls/ssl.log new file mode 100644 index 0000000000..fef021bdc1 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ftp.ftp-auth-tls/ssl.log @@ -0,0 +1,11 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path ssl +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version cipher curve server_name resumed last_alert next_protocol established ssl_history cert_chain_fps client_cert_chain_fps sni_matches_cert +#types time string addr port addr port string string string string bool string string bool string vector[string] vector[string] bool +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 40284 127.0.0.1 21 TLSv13 TLS_AES_256_GCM_SHA384 secp256r1 127.0.0.1 F - - T CsiI - - - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Traces/ftp/ftp-auth-tls.pcap b/testing/btest/Traces/ftp/ftp-auth-tls.pcap new file mode 100644 index 0000000000000000000000000000000000000000..cc93e042b240946101c297b73191f246cc7c0e52 GIT binary patch literal 11363 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", "AUTH" }; + +event ftp_starttls(c: connection) { + print "starttls", c$id; +}