From 6bc914458b4685521c7fb51f448502ffbd15cdd8 Mon Sep 17 00:00:00 2001 From: Bernhard Amann Date: Thu, 15 May 2014 09:57:01 -0700 Subject: [PATCH] Add smtp starttls support --- scripts/base/protocols/smtp/files.bro | 4 +- scripts/base/protocols/smtp/main.bro | 11 ++++- src/analyzer/protocol/smtp/SMTP.cc | 39 ++++++++++++++---- src/analyzer/protocol/smtp/SMTP.h | 6 +++ src/analyzer/protocol/smtp/events.bif | 8 ++++ .../smtp.log | 10 +++++ .../ssl.log | 10 +++++ .../x509.log | 12 ++++++ testing/btest/Traces/tls/smtp-starttls.pcap | Bin 0 -> 8693 bytes .../scripts/base/protocols/smtp/starttls.test | 6 +++ 10 files changed, 94 insertions(+), 12 deletions(-) create mode 100644 testing/btest/Baseline/scripts.base.protocols.smtp.starttls/smtp.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.smtp.starttls/ssl.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.smtp.starttls/x509.log create mode 100644 testing/btest/Traces/tls/smtp-starttls.pcap create mode 100644 testing/btest/scripts/base/protocols/smtp/starttls.test diff --git a/scripts/base/protocols/smtp/files.bro b/scripts/base/protocols/smtp/files.bro index f9ae2ab05f..352c2025a3 100644 --- a/scripts/base/protocols/smtp/files.bro +++ b/scripts/base/protocols/smtp/files.bro @@ -41,13 +41,13 @@ function describe_file(f: fa_file): string event bro_init() &priority=5 { - Files::register_protocol(Analyzer::ANALYZER_SMTP, + Files::register_protocol(Analyzer::ANALYZER_SMTP, [$get_file_handle = SMTP::get_file_handle, $describe = SMTP::describe_file]); } event file_over_new_connection(f: fa_file, c: connection, is_orig: bool) &priority=5 { - if ( c?$smtp ) + if ( c?$smtp && !c$smtp$tls ) c$smtp$fuids[|c$smtp$fuids|] = f$id; } diff --git a/scripts/base/protocols/smtp/main.bro b/scripts/base/protocols/smtp/main.bro index d3bd8a97b4..58583d035b 100644 --- a/scripts/base/protocols/smtp/main.bro +++ b/scripts/base/protocols/smtp/main.bro @@ -49,7 +49,10 @@ export { path: vector of addr &log &optional; ## Value of the User-Agent header from the client. user_agent: string &log &optional; - + + ## Indicates that the connection has switched to using TLS + tls: bool &default=F; + ## Indicates if the "Received: from" headers should still be ## processed. process_received_from: bool &default=T; @@ -276,6 +279,12 @@ event connection_state_remove(c: connection) &priority=-5 smtp_message(c); } +event smtp_starttls(c: connection) &priority=5 + { + if ( c?$smtp ) + c$smtp$tls = T; + } + function describe(rec: Info): string { if ( rec?$mailfrom && rec?$rcptto ) diff --git a/src/analyzer/protocol/smtp/SMTP.cc b/src/analyzer/protocol/smtp/SMTP.cc index c3fb21b6a4..e345d5368a 100644 --- a/src/analyzer/protocol/smtp/SMTP.cc +++ b/src/analyzer/protocol/smtp/SMTP.cc @@ -8,7 +8,7 @@ #include "SMTP.h" #include "Event.h" #include "Reporter.h" -#include "analyzer/protocol/tcp/ContentLine.h" +#include "analyzer/Manager.h" #include "events.bif.h" @@ -44,12 +44,12 @@ SMTP_Analyzer::SMTP_Analyzer(Connection* conn) line_after_gap = 0; mail = 0; UpdateState(first_cmd, 0); - tcp::ContentLine_Analyzer* cl_orig = new tcp::ContentLine_Analyzer(conn, true); + cl_orig = new tcp::ContentLine_Analyzer(conn, true); cl_orig->SetIsNULSensitive(true); cl_orig->SetSkipPartial(true); AddSupportAnalyzer(cl_orig); - tcp::ContentLine_Analyzer* cl_resp = new tcp::ContentLine_Analyzer(conn, false); + cl_resp = new tcp::ContentLine_Analyzer(conn, false); cl_resp->SetIsNULSensitive(true); cl_resp->SetSkipPartial(true); AddSupportAnalyzer(cl_resp); @@ -118,6 +118,13 @@ void SMTP_Analyzer::DeliverStream(int length, const u_char* line, bool orig) { tcp::TCP_ApplicationAnalyzer::DeliverStream(length, line, orig); + // If an TLS transaction has been initiated, forward to child and abort. + if ( state == SMTP_IN_TLS ) + { + ForwardStream(length, line, orig); + return; + } + // NOTE: do not use IsOrig() here, because of TURN command. int is_sender = orig_is_sender ? orig : ! orig; @@ -152,10 +159,6 @@ void SMTP_Analyzer::DeliverStream(int length, const u_char* line, bool orig) void SMTP_Analyzer::ProcessLine(int length, const char* line, bool orig) { const char* end_of_line = line + length; - if ( state == SMTP_IN_TLS ) - // Do not try to parse contents after STARTTLS/220. - return; - int cmd_len = 0; const char* cmd = ""; @@ -380,6 +383,25 @@ void SMTP_Analyzer::NewCmd(const int cmd_code) first_cmd = cmd_code; } +void SMTP_Analyzer::StartTLS() + { + // STARTTLS was succesful. Remove SMTP support analyzers, add SSL + // analyzer and throw event signifying the change. + state = SMTP_IN_TLS; + expect_sender = expect_recver = 1; + RemoveSupportAnalyzer(cl_orig); + RemoveSupportAnalyzer(cl_resp); + Analyzer* ssl = analyzer_mgr->InstantiateAnalyzer("SSL", Conn()); + if ( ssl ) + AddChildAnalyzer(ssl); + + val_list* vl = new val_list; + vl->append(BuildConnVal()); + + ConnectionEvent(smtp_starttls, vl); + } + + // Here we keep a SMTP state machine and update it on each reply. // However, the purpose is NOT to check correctness of SMTP commands @@ -740,8 +762,7 @@ void SMTP_Analyzer::UpdateState(const int cmd_code, const int reply_code) break; case 220: - state = SMTP_IN_TLS; - expect_sender = expect_recver = 1; + StartTLS(); break; case 454: diff --git a/src/analyzer/protocol/smtp/SMTP.h b/src/analyzer/protocol/smtp/SMTP.h index 8caaf846b8..30b14fed2f 100644 --- a/src/analyzer/protocol/smtp/SMTP.h +++ b/src/analyzer/protocol/smtp/SMTP.h @@ -7,6 +7,7 @@ using namespace std; #include "analyzer/protocol/tcp/TCP.h" +#include "analyzer/protocol/tcp/ContentLine.h" #include "analyzer/protocol/mime/MIME.h" #undef SMTP_CMD_DEF @@ -74,6 +75,7 @@ protected: int detail_len, const char* detail); void UnexpectedCommand(const int cmd_code, const int reply_code); void UnexpectedReply(const int cmd_code, const int reply_code); + void StartTLS(); bool orig_is_sender; int expect_sender, expect_recver; @@ -88,6 +90,10 @@ protected: // after a gap mime::MIME_Mail* mail; + +private: + tcp::ContentLine_Analyzer* cl_orig; + tcp::ContentLine_Analyzer* cl_resp; }; } } // namespace analyzer::* diff --git a/src/analyzer/protocol/smtp/events.bif b/src/analyzer/protocol/smtp/events.bif index 4a376bcbf8..33d4f683b1 100644 --- a/src/analyzer/protocol/smtp/events.bif +++ b/src/analyzer/protocol/smtp/events.bif @@ -98,3 +98,11 @@ event smtp_data%(c: connection, is_orig: bool, data: string%); ## ## .. bro:see:: smtp_data smtp_request smtp_reply event smtp_unexpected%(c: connection, is_orig: bool, msg: string, detail: string%); + +## Generated if a connection switched to using TLS using STARTTLS. After this event +## no more SMTP events will be raised for the connection. See the SSL analyzer for +## related SSL events. +## +## c: The connection +## +event smtp_starttls%(c: connection%); diff --git a/testing/btest/Baseline/scripts.base.protocols.smtp.starttls/smtp.log b/testing/btest/Baseline/scripts.base.protocols.smtp.starttls/smtp.log new file mode 100644 index 0000000000..91b305783b --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.smtp.starttls/smtp.log @@ -0,0 +1,10 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path smtp +#open 2014-05-15-16-56-36 +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p trans_depth helo mailfrom rcptto date from to reply_to msg_id in_reply_to subject x_originating_ip first_received second_received last_reply path user_agent fuids +#types time string addr port addr port count string string set[string] string string set[string] string string string string addr string string string vector[addr] string vector[string] +1400168396.898137 CXWv6p3arKYeMETxOg 192.168.4.149 54170 74.125.142.26 25 1 openssl.client.net - - - - - - - - - - - - 220 2.0.0 Ready to start TLS 74.125.142.26,192.168.4.149 - (empty) +#close 2014-05-15-16-56-36 diff --git a/testing/btest/Baseline/scripts.base.protocols.smtp.starttls/ssl.log b/testing/btest/Baseline/scripts.base.protocols.smtp.starttls/ssl.log new file mode 100644 index 0000000000..cec018c589 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.smtp.starttls/ssl.log @@ -0,0 +1,10 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path ssl +#open 2014-05-15-16-56-36 +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version cipher curve server_name session_id last_alert established cert_chain_fuids client_cert_chain_fuids subject issuer client_subject client_issuer +#types time string addr port addr port string string string string string string bool vector[string] vector[string] string string string string +1400168397.019290 CXWv6p3arKYeMETxOg 192.168.4.149 54170 74.125.142.26 25 TLSv12 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 secp256r1 - - - T FUE0dj3SWjQASC0bk3,FbPkr51wrSMIUT5Hib,FVW1o23Jjs8yenOhzb (empty) CN=mx.google.com,O=Google Inc,L=Mountain View,ST=California,C=US CN=Google Internet Authority G2,O=Google Inc,C=US - - +#close 2014-05-15-16-56-36 diff --git a/testing/btest/Baseline/scripts.base.protocols.smtp.starttls/x509.log b/testing/btest/Baseline/scripts.base.protocols.smtp.starttls/x509.log new file mode 100644 index 0000000000..304728aeaa --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.smtp.starttls/x509.log @@ -0,0 +1,12 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path x509 +#open 2014-05-15-16-56-36 +#fields ts id certificate.version certificate.serial certificate.subject certificate.issuer certificate.not_valid_before certificate.not_valid_after certificate.key_alg certificate.sig_alg certificate.key_type certificate.key_length certificate.exponent certificate.curve san.dns san.uri san.email san.ip basic_constraints.ca basic_constraints.path_len +#types time string count string string string time time string string string count string string vector[string] vector[string] vector[string] vector[addr] bool count +1400168397.069811 FUE0dj3SWjQASC0bk3 3 325D8297987D50B0 CN=mx.google.com,O=Google Inc,L=Mountain View,ST=California,C=US CN=Google Internet Authority G2,O=Google Inc,C=US 1378726355.000000 1410262355.000000 rsaEncryption sha1WithRSAEncryption rsa 2048 65537 - aspmx.l.google.com,alt1.aspmx.l.google.com,alt2.aspmx.l.google.com,alt3.aspmx.l.google.com,alt4.aspmx.l.google.com,gmail-smtp-in.l.google.com,alt1.gmail-smtp-in.l.google.com,alt2.gmail-smtp-in.l.google.com,alt3.gmail-smtp-in.l.google.com,alt4.gmail-smtp-in.l.google.com,gmr-smtp-in.l.google.com,alt1.gmr-smtp-in.l.google.com,alt2.gmr-smtp-in.l.google.com,alt3.gmr-smtp-in.l.google.com,alt4.gmr-smtp-in.l.google.com,mx.google.com,aspmx2.googlemail.com,aspmx3.googlemail.com,aspmx4.googlemail.com,aspmx5.googlemail.com - - - F - +1400168397.069811 FbPkr51wrSMIUT5Hib 3 023A69 CN=Google Internet Authority G2,O=Google Inc,C=US CN=GeoTrust Global CA,O=GeoTrust Inc.,C=US 1365174955.000000 1428160555.000000 rsaEncryption sha1WithRSAEncryption rsa 2048 65537 - - - - - T 0 +1400168397.069811 FVW1o23Jjs8yenOhzb 3 12BBE6 CN=GeoTrust Global CA,O=GeoTrust Inc.,C=US OU=Equifax Secure Certificate Authority,O=Equifax,C=US 1021953600.000000 1534824000.000000 rsaEncryption sha1WithRSAEncryption rsa 2048 65537 - - - - - T - +#close 2014-05-15-16-56-36 diff --git a/testing/btest/Traces/tls/smtp-starttls.pcap b/testing/btest/Traces/tls/smtp-starttls.pcap new file mode 100644 index 0000000000000000000000000000000000000000..d1d3812689aeeb3891a35c1b846e1f5a2c1aab98 GIT binary patch literal 8693 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 literal 0 HcmV?d00001 diff --git a/testing/btest/scripts/base/protocols/smtp/starttls.test b/testing/btest/scripts/base/protocols/smtp/starttls.test new file mode 100644 index 0000000000..e3a114f572 --- /dev/null +++ b/testing/btest/scripts/base/protocols/smtp/starttls.test @@ -0,0 +1,6 @@ +# @TEST-EXEC: bro -C -r $TRACES/tls/smtp-starttls.pcap %INPUT +# @TEST-EXEC: btest-diff smtp.log +# @TEST-EXEC: btest-diff ssl.log +# @TEST-EXEC: btest-diff x509.log + +@load base/protocols/smtp