From 68aead024ab4a93ac83dc83f5ba61427bd1401e4 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Mon, 1 Oct 2012 12:32:24 -0500 Subject: [PATCH 1/4] Add an example of a GridFTP data channel detection script. It relies on the heuristics of GridFTP data channels commonly default to SSL mutual authentication with a NULL bulk cipher and that they usually transfer large datasets (default threshold of script is 1 GB). The script also defaults to skip_further_processing() after detection to try to save cycles analyzing the large, benign connection. Also added a script in base/protocols/conn/polling that generalizes the process of polling a connection for interesting features. The GridFTP data channel detection script depends on it to monitor bytes transferred. --- scripts/base/protocols/conn/__load__.bro | 1 + scripts/base/protocols/conn/polling.bro | 51 +++++++++++ .../protocols/ftp/gridftp-data-detection.bro | 83 ++++++++++++++++++ .../scripts.base.protocols.conn.polling/out1 | 7 ++ .../scripts.base.protocols.conn.polling/out2 | 4 + .../notice.log | 10 +++ testing/btest/Traces/globus-url-copy.trace | Bin 0 -> 21556 bytes .../scripts/base/protocols/conn/polling.test | 20 +++++ .../protocols/ftp/gridftp-data-dection.test | 6 ++ 9 files changed, 182 insertions(+) create mode 100644 scripts/base/protocols/conn/polling.bro create mode 100644 scripts/policy/protocols/ftp/gridftp-data-detection.bro create mode 100644 testing/btest/Baseline/scripts.base.protocols.conn.polling/out1 create mode 100644 testing/btest/Baseline/scripts.base.protocols.conn.polling/out2 create mode 100644 testing/btest/Baseline/scripts.policy.protocols.ftp.gridftp-data-dection/notice.log create mode 100644 testing/btest/Traces/globus-url-copy.trace create mode 100644 testing/btest/scripts/base/protocols/conn/polling.test create mode 100644 testing/btest/scripts/policy/protocols/ftp/gridftp-data-dection.test diff --git a/scripts/base/protocols/conn/__load__.bro b/scripts/base/protocols/conn/__load__.bro index 8c673eca85..719486d885 100644 --- a/scripts/base/protocols/conn/__load__.bro +++ b/scripts/base/protocols/conn/__load__.bro @@ -1,3 +1,4 @@ @load ./main @load ./contents @load ./inactivity +@load ./polling diff --git a/scripts/base/protocols/conn/polling.bro b/scripts/base/protocols/conn/polling.bro new file mode 100644 index 0000000000..7b9bd8d6af --- /dev/null +++ b/scripts/base/protocols/conn/polling.bro @@ -0,0 +1,51 @@ +##! Implements a generic way to poll connections looking for certain features +##! (e.g. monitor bytes transferred). The specific feature of a connection +##! to look for, the polling interval, and the code to execute if the feature +##! is found are all controlled by user-defined callback functions. + +module ConnPolling; + +export { + ## Starts monitoring a given connection. + ## + ## c: The connection to watch. + ## + ## callback: A callback function that takes as arguments the monitored + ## *connection*, and counter *cnt* that increments each time the + ## callback is called. It returns an interval indicating how long + ## in the future to schedule an event which will call the + ## callback. A negative return interval causes polling to stop. + ## + ## cnt: The initial value of a counter which gets passed to *callback*. + ## + ## i: The initial interval at which to schedule the next callback. + ## May be ``0secs`` to poll right away. + global watch: function( + c: connection, + callback: function(c: connection, cnt: count): interval, + cnt: count, + i: interval); +} + +event ConnPolling::check( + c: connection, + callback: function(c: connection, cnt: count): interval, + cnt: count) + { + if ( ! connection_exists(c$id) ) return; + + lookup_connection(c$id); # updates the conn val + + local next_interval = callback(c, cnt); + if ( next_interval < 0secs ) return; + watch(c, callback, cnt + 1, next_interval); + } + +function watch( + c: connection, + callback: function(c: connection, cnt: count): interval, + cnt: count, + i: interval) + { + schedule i { ConnPolling::check(c, callback, cnt) }; + } diff --git a/scripts/policy/protocols/ftp/gridftp-data-detection.bro b/scripts/policy/protocols/ftp/gridftp-data-detection.bro new file mode 100644 index 0000000000..15acfba65b --- /dev/null +++ b/scripts/policy/protocols/ftp/gridftp-data-detection.bro @@ -0,0 +1,83 @@ +##! A detection script for GridFTP data channels. The heuristic used to +##! identify a GridFTP data channel relies on the fact that default +##! setting for GridFTP clients typically mutually authenticate the data +##! channel with SSL and negotiate a NULL bulk cipher (no encryption). +##! Connections with those attributes are then polled for two minutes +##! with decreasing frequency to check if the transfer sizes are large +##! enough to indicate a GridFTP data channel that would be undesireable +##! to analyze further (e.g. TCP reassembly no longer occurs). A side +##! effect is that true connection sizes are not logged, but at the +##! benefit of saving CPU cycles that otherwise go to analyzing such +##! large (and hopefully benign) connections. + +module GridFTP; + +@load base/protocols/conn +@load base/protocols/ssl +@load base/frameworks/notice + +export { + ## Number of bytes transferred before guessing a connection is a + ## GridFTP data channel. + const size_threshold = 1073741824 &redef; + + ## Max number of times to check whether a connection's size exceeds the + ## :bro:see:`GridFTP::size_threshold`. + const max_poll_count = 15 &redef; + + ## Whether to skip further processing of the GridFTP data channel once + ## detected, which may help performance. + const skip_data = T &redef; + + ## Base amount of time between checking whether a GridFTP connection + ## has transferred more than :bro:see:`GridFTP::size_threshold` bytes. + const poll_interval = 1sec &redef; + + ## The amount of time the base :bro:see:`GridFTP::poll_interval` is + ## increased by each poll interval. Can be used to make more frequent + ## checks at the start of a connection and gradually slow down. + const poll_interval_increase = 1sec &redef; +} + +redef enum Notice::Type += { + Data_Channel +}; + +redef record SSL::Info += { + ## Indicates a client certificate was sent in the SSL handshake. + saw_client_cert: bool &optional; +}; + +event x509_certificate(c: connection, is_orig: bool, cert: X509, chain_idx: count, chain_len: count, der_cert: string) + { + if ( is_orig && c?$ssl ) + c$ssl$saw_client_cert = T; + } + +function size_callback(c: connection, cnt: count): interval + { + if ( c$orig$size > size_threshold || c$resp$size > size_threshold ) + { + local msg = fmt("GridFTP data channel over threshold %d bytes", + size_threshold); + NOTICE([$note=Data_Channel, $msg=msg, $conn=c]); + if ( skip_data ) + skip_further_processing(c$id); + return -1sec; + } + + if ( cnt >= max_poll_count ) return -1sec; + + return poll_interval + poll_interval_increase * cnt; + } + +event ssl_established(c: connection) + { + # By default GridFTP data channels do mutual authentication and + # negotiate a cipher suite with a NULL bulk cipher. + if ( c?$ssl && c$ssl?$saw_client_cert && c$ssl?$subject && + c$ssl?$cipher && /WITH_NULL/ in c$ssl$cipher ) + { + ConnPolling::watch(c, size_callback, 0, 0secs); + } + } diff --git a/testing/btest/Baseline/scripts.base.protocols.conn.polling/out1 b/testing/btest/Baseline/scripts.base.protocols.conn.polling/out1 new file mode 100644 index 0000000000..9cba678461 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.conn.polling/out1 @@ -0,0 +1,7 @@ +new_connection, [orig_h=192.168.3.103, orig_p=54102/tcp, resp_h=128.146.216.51, resp_p=80/tcp] +callback, [orig_h=192.168.3.103, orig_p=54102/tcp, resp_h=128.146.216.51, resp_p=80/tcp], 0 +callback, [orig_h=192.168.3.103, orig_p=54102/tcp, resp_h=128.146.216.51, resp_p=80/tcp], 1 +callback, [orig_h=192.168.3.103, orig_p=54102/tcp, resp_h=128.146.216.51, resp_p=80/tcp], 2 +callback, [orig_h=192.168.3.103, orig_p=54102/tcp, resp_h=128.146.216.51, resp_p=80/tcp], 3 +callback, [orig_h=192.168.3.103, orig_p=54102/tcp, resp_h=128.146.216.51, resp_p=80/tcp], 4 +callback, [orig_h=192.168.3.103, orig_p=54102/tcp, resp_h=128.146.216.51, resp_p=80/tcp], 5 diff --git a/testing/btest/Baseline/scripts.base.protocols.conn.polling/out2 b/testing/btest/Baseline/scripts.base.protocols.conn.polling/out2 new file mode 100644 index 0000000000..8476915d0a --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.conn.polling/out2 @@ -0,0 +1,4 @@ +new_connection, [orig_h=192.168.3.103, orig_p=54102/tcp, resp_h=128.146.216.51, resp_p=80/tcp] +callback, [orig_h=192.168.3.103, orig_p=54102/tcp, resp_h=128.146.216.51, resp_p=80/tcp], 0 +callback, [orig_h=192.168.3.103, orig_p=54102/tcp, resp_h=128.146.216.51, resp_p=80/tcp], 1 +callback, [orig_h=192.168.3.103, orig_p=54102/tcp, resp_h=128.146.216.51, resp_p=80/tcp], 2 diff --git a/testing/btest/Baseline/scripts.policy.protocols.ftp.gridftp-data-dection/notice.log b/testing/btest/Baseline/scripts.policy.protocols.ftp.gridftp-data-dection/notice.log new file mode 100644 index 0000000000..dc007e4e24 --- /dev/null +++ b/testing/btest/Baseline/scripts.policy.protocols.ftp.gridftp-data-dection/notice.log @@ -0,0 +1,10 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path notice +#open 2012-10-01-17-11-05 +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto note msg sub src dst p n peer_descr actions policy_items suppress_for dropped remote_location.country_code remote_location.region remote_location.city remote_location.latitude remote_location.longitude metric_index.host metric_index.str metric_index.network +#types time string addr port addr port enum enum string string addr addr port count string table[enum] table[count] interval bool string string string double double addr string subnet +1348168976.558309 arKYeMETxOg 192.168.57.103 35391 192.168.57.101 55968 tcp GridFTP::Data_Channel GridFTP data channel over threshold 2 bytes - 192.168.57.103 192.168.57.101 55968 - bro Notice::ACTION_LOG 6 3600.000000 F - - - - - - - - +#close 2012-10-01-17-11-05 diff --git a/testing/btest/Traces/globus-url-copy.trace b/testing/btest/Traces/globus-url-copy.trace new file mode 100644 index 0000000000000000000000000000000000000000..b42ce25bca7414edde499a36af32130444a0ee85 GIT binary patch literal 21556 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 +# @TEST-EXEC: btest-diff out1 +# @TEST-EXEC: bro -b -r $TRACES/http-100-continue.trace %INPUT stop_cnt=2 >out2 +# @TEST-EXEC: btest-diff out2 + +@load base/protocols/conn + +const stop_cnt = 10 &redef; + +function callback(c: connection, cnt: count): interval + { + print "callback", c$id, cnt; + return cnt >= stop_cnt ? -1 sec : .2 sec; + } + +event new_connection(c: connection) + { + print "new_connection", c$id; + ConnPolling::watch(c, callback, 0, 0secs); + } diff --git a/testing/btest/scripts/policy/protocols/ftp/gridftp-data-dection.test b/testing/btest/scripts/policy/protocols/ftp/gridftp-data-dection.test new file mode 100644 index 0000000000..bb7b9b510d --- /dev/null +++ b/testing/btest/scripts/policy/protocols/ftp/gridftp-data-dection.test @@ -0,0 +1,6 @@ +# @TEST-EXEC: bro -r $TRACES/globus-url-copy.trace %INPUT +# @TEST-EXEC: btest-diff notice.log + +@load protocols/ftp/gridftp-data-detection + +redef GridFTP::size_threshold = 2; From 49b8c7e3909ba0b57019285eaa07022c44f45270 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Fri, 5 Oct 2012 10:43:23 -0500 Subject: [PATCH 2/4] Add analyzer for GSI mechanism of GSSAPI FTP AUTH method. GSI authentication involves an encoded TLS/SSL handshake over the FTP control session. Decoding the exchanged tokens and passing them to an SSL analyzer instance allows use of all the familiar script-layer events in inspecting the handshake (e.g. client/server certificats are available). For FTP sessions that attempt GSI authentication, the service field of the connection record will have both "ftp" and "ssl". One additional change is an FTP server's acceptance of an AUTH request no longer causes analysis of the connection to cease (because further analysis likely wasn't possible). This decision can be made more dynamically at the script-layer (plus there's now the fact that further analysis can be done at least on the GSSAPI AUTH method). --- doc/scripts/DocSourcesList.cmake | 2 + scripts/base/protocols/ftp/main.bro | 6 +- .../protocols/ftp/gridftp-data-detection.bro | 4 +- scripts/test-all-policy.bro | 1 + src/Analyzer.cc | 1 + src/AnalyzerTags.h | 1 + src/FTP.cc | 173 ++++++++++++++++-- src/FTP.h | 22 +++ .../Baseline/core.print-bpf-filters/output | 2 +- .../canonified_loaded_scripts.log | 1 + 10 files changed, 188 insertions(+), 25 deletions(-) diff --git a/doc/scripts/DocSourcesList.cmake b/doc/scripts/DocSourcesList.cmake index 1abe6b9305..077e103dca 100644 --- a/doc/scripts/DocSourcesList.cmake +++ b/doc/scripts/DocSourcesList.cmake @@ -65,6 +65,7 @@ rest_target(${psd} base/frameworks/tunnels/main.bro) rest_target(${psd} base/protocols/conn/contents.bro) rest_target(${psd} base/protocols/conn/inactivity.bro) rest_target(${psd} base/protocols/conn/main.bro) +rest_target(${psd} base/protocols/conn/polling.bro) rest_target(${psd} base/protocols/dns/consts.bro) rest_target(${psd} base/protocols/dns/main.bro) rest_target(${psd} base/protocols/ftp/file-extract.bro) @@ -122,6 +123,7 @@ rest_target(${psd} policy/protocols/conn/weirds.bro) rest_target(${psd} policy/protocols/dns/auth-addl.bro) rest_target(${psd} policy/protocols/dns/detect-external-names.bro) rest_target(${psd} policy/protocols/ftp/detect.bro) +rest_target(${psd} policy/protocols/ftp/gridftp-data-detection.bro) rest_target(${psd} policy/protocols/ftp/software.bro) rest_target(${psd} policy/protocols/http/detect-MHR.bro) rest_target(${psd} policy/protocols/http/detect-intel.bro) diff --git a/scripts/base/protocols/ftp/main.bro b/scripts/base/protocols/ftp/main.bro index d20bc92d8a..0a4bfc07cc 100644 --- a/scripts/base/protocols/ftp/main.bro +++ b/scripts/base/protocols/ftp/main.bro @@ -96,11 +96,11 @@ redef record connection += { }; # Configure DPD -const ports = { 21/tcp } &redef; -redef capture_filters += { ["ftp"] = "port 21" }; +const ports = { 21/tcp, 2811/tcp } &redef; +redef capture_filters += { ["ftp"] = "port 21 and port 2811" }; redef dpd_config += { [ANALYZER_FTP] = [$ports = ports] }; -redef likely_server_ports += { 21/tcp }; +redef likely_server_ports += { 21/tcp, 2811/tcp }; # Establish the variable for tracking expected connections. global ftp_data_expected: table[addr, port] of Info &create_expire=5mins; diff --git a/scripts/policy/protocols/ftp/gridftp-data-detection.bro b/scripts/policy/protocols/ftp/gridftp-data-detection.bro index 15acfba65b..ffa2fa5816 100644 --- a/scripts/policy/protocols/ftp/gridftp-data-detection.bro +++ b/scripts/policy/protocols/ftp/gridftp-data-detection.bro @@ -10,12 +10,12 @@ ##! benefit of saving CPU cycles that otherwise go to analyzing such ##! large (and hopefully benign) connections. -module GridFTP; - @load base/protocols/conn @load base/protocols/ssl @load base/frameworks/notice +module GridFTP; + export { ## Number of bytes transferred before guessing a connection is a ## GridFTP data channel. diff --git a/scripts/test-all-policy.bro b/scripts/test-all-policy.bro index a7c43b14b3..f535d88cd5 100644 --- a/scripts/test-all-policy.bro +++ b/scripts/test-all-policy.bro @@ -34,6 +34,7 @@ @load protocols/dns/auth-addl.bro @load protocols/dns/detect-external-names.bro @load protocols/ftp/detect.bro +@load protocols/ftp/gridftp-data-detection.bro @load protocols/ftp/software.bro @load protocols/http/detect-intel.bro @load protocols/http/detect-MHR.bro diff --git a/src/Analyzer.cc b/src/Analyzer.cc index 9e30da0066..8c5573f96b 100644 --- a/src/Analyzer.cc +++ b/src/Analyzer.cc @@ -171,6 +171,7 @@ const Analyzer::Config Analyzer::analyzer_configs[] = { { AnalyzerTag::Contents_SMB, "CONTENTS_SMB", 0, 0, 0, false }, { AnalyzerTag::Contents_RPC, "CONTENTS_RPC", 0, 0, 0, false }, { AnalyzerTag::Contents_NFS, "CONTENTS_NFS", 0, 0, 0, false }, + { AnalyzerTag::FTP_ADAT, "FTP_ADAT", 0, 0, 0, false }, }; AnalyzerTimer::~AnalyzerTimer() diff --git a/src/AnalyzerTags.h b/src/AnalyzerTags.h index 7fad4d35bb..4301de8f71 100644 --- a/src/AnalyzerTags.h +++ b/src/AnalyzerTags.h @@ -46,6 +46,7 @@ namespace AnalyzerTag { Contents, ContentLine, NVT, Zip, Contents_DNS, Contents_NCP, Contents_NetbiosSSN, Contents_Rlogin, Contents_Rsh, Contents_DCE_RPC, Contents_SMB, Contents_RPC, Contents_NFS, + FTP_ADAT, // End-marker. LastAnalyzer }; diff --git a/src/FTP.cc b/src/FTP.cc index 588348ea8d..fba6b3eea6 100644 --- a/src/FTP.cc +++ b/src/FTP.cc @@ -8,6 +8,8 @@ #include "FTP.h" #include "NVT.h" #include "Event.h" +#include "SSL.h" +#include "Base64.h" FTP_Analyzer::FTP_Analyzer(Connection* conn) : TCP_ApplicationAnalyzer(AnalyzerTag::FTP, conn) @@ -44,6 +46,14 @@ void FTP_Analyzer::Done() Weird("partial_ftp_request"); } +static uint32 get_reply_code(int len, const char* line) + { + if ( len >= 3 && isdigit(line[0]) && isdigit(line[1]) && isdigit(line[2]) ) + return (line[0] - '0') * 100 + (line[1] - '0') * 10 + (line[2] - '0'); + else + return 0; + } + void FTP_Analyzer::DeliverStream(int length, const u_char* data, bool orig) { TCP_ApplicationAnalyzer::DeliverStream(length, data, orig); @@ -93,16 +103,7 @@ void FTP_Analyzer::DeliverStream(int length, const u_char* data, bool orig) } else { - uint32 reply_code; - if ( length >= 3 && - isdigit(line[0]) && isdigit(line[1]) && isdigit(line[2]) ) - { - reply_code = (line[0] - '0') * 100 + - (line[1] - '0') * 10 + - (line[2] - '0'); - } - else - reply_code = 0; + uint32 reply_code = get_reply_code(length, line); int cont_resp; @@ -143,19 +144,22 @@ void FTP_Analyzer::DeliverStream(int length, const u_char* data, bool orig) else line = end_of_line; - if ( auth_requested.size() > 0 && - (reply_code == 234 || reply_code == 335) ) - // Server accepted AUTH requested, - // which means that very likely we - // won't be able to parse the rest - // of the session, and thus we stop - // here. - SetSkip(true); - cont_resp = 0; } } + 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 + // to look for that. + SSL_Analyzer* ssl = new SSL_Analyzer(Conn()); + ssl->AddSupportAnalyzer(new FTP_ADAT_Analyzer(Conn(), true)); + ssl->AddSupportAnalyzer(new FTP_ADAT_Analyzer(Conn(), false)); + AddChildAnalyzer(ssl); + } + vl->append(new Val(reply_code, TYPE_COUNT)); vl->append(new StringVal(end_of_line - line, line)); vl->append(new Val(cont_resp, TYPE_BOOL)); @@ -164,5 +168,136 @@ void FTP_Analyzer::DeliverStream(int length, const u_char* data, bool orig) } ConnectionEvent(f, vl); + + ForwardStream(length, data, orig); } +void FTP_ADAT_Analyzer::DeliverStream(int len, const u_char* data, bool orig) + { + // Don't know how to parse anything but the ADAT exchanges of GSI GSSAPI, + // which is basically just TLS/SSL. + if ( ! Parent()->GetTag() == AnalyzerTag::SSL ) + { + Parent()->Remove(); + return; + } + + bool done = false; + const char* line = (const char*) data; + const char* end_of_line = line + len; + + BroString* decoded_adat = 0; + + if ( orig ) + { + int cmd_len; + const char* cmd; + line = skip_whitespace(line, end_of_line); + get_word(len, line, cmd_len, cmd); + + if ( strncmp(cmd, "ADAT", cmd_len) == 0 ) + { + line = skip_whitespace(line + cmd_len, end_of_line); + StringVal* encoded = new StringVal(end_of_line - line, line); + decoded_adat = decode_base64(encoded->AsString()); + delete encoded; + + if ( first_token ) + { + // RFC 2743 section 3.1 specifies a framing format for tokens + // that includes an identifier for the mechanism type. The + // framing is supposed to be required for the initial context + // token, but GSI doesn't do that and starts right in on a + // TLS/SSL handshake, so look for that to identify it. + const u_char* msg = decoded_adat->Bytes(); + int msg_len = decoded_adat->Len(); + + // Just check that it looks like a viable TLS/SSL handshake + // record from the first byte (content type of 0x16) and + // that the fourth and fifth bytes indicating the length of + // the record match the length of the decoded data. + if ( msg_len < 5 || msg[0] != 0x16 || + msg_len - 5 != ntohs(*((uint16*)(msg + 3))) ) + { + // Doesn't look like TLS/SSL, so done analyzing. + done = true; + delete decoded_adat; + decoded_adat = 0; + } + } + + first_token = false; + } + else if ( strncmp(cmd, "AUTH", cmd_len) == 0 ) + { + // Security state will be reset by a reissued AUTH + done = true; + } + } + else + { + uint32 reply_code = get_reply_code(len, line); + + switch ( reply_code ) { + case 232: + case 234: + // Indicates security data exchange is complete, but nothing + // more to decode in replies. + done = true; + break; + + case 235: + // Security data exchange complete, but may have more to decode + // in the reply (same format at 334 and 335). + done = true; + case 334: + case 335: + // Security data exchange still in progress, and there could be data + // to decode in the reply. + line += 3; + if ( len > 3 && line[0] == '-' ) line++; + line = skip_whitespace(line, end_of_line); + + if ( end_of_line - line >= 5 && strncmp(line, "ADAT=", 5) == 0 ) + { + line += 5; + StringVal* encoded = new StringVal(end_of_line - line, line); + decoded_adat = decode_base64(encoded->AsString()); + delete encoded; + } + break; + + case 421: + case 431: + case 500: + case 501: + case 503: + case 535: + // Server isn't going to accept named security mechanism. + // Client has to restart back at the AUTH. + done = true; + break; + + case 631: + case 632: + case 633: + // If the server is sending protected replies, the security + // data exchange must have already succeeded. It does have + // encoded data in the reply, but 632 and 633 are also encrypted. + done = true; + break; + + default: + break; + } + } + + if ( decoded_adat ) + { + ForwardStream(decoded_adat->Len(), decoded_adat->Bytes(), orig); + delete decoded_adat; + } + + if ( done ) + Parent()->Remove(); + } diff --git a/src/FTP.h b/src/FTP.h index 4ef6c44d83..f8d7644808 100644 --- a/src/FTP.h +++ b/src/FTP.h @@ -30,4 +30,26 @@ protected: string auth_requested; // AUTH method requested }; +/** + * Analyzes security data of ADAT exchanges over FTP control session (RFC 2228). + * Currently only the GSI mechanism of GSSAPI AUTH method is understood. + * The ADAT exchange for GSI is base64 encoded TLS/SSL handshake tokens. This + * analyzer just decodes the tokens and passes them on to the parent, which must + * be an SSL analyzer instance. + */ +class FTP_ADAT_Analyzer : public SupportAnalyzer { +public: + FTP_ADAT_Analyzer(Connection* conn, bool arg_orig) + : SupportAnalyzer(AnalyzerTag::FTP_ADAT, conn, arg_orig), + first_token(true) { } + + void DeliverStream(int len, const u_char* data, bool orig); + +protected: + // Used by the client-side analyzer to tell if it needs to peek at the + // initial context token and do sanity checking (i.e. does it look like + // a TLS/SSL handshake token). + bool first_token; +}; + #endif diff --git a/testing/btest/Baseline/core.print-bpf-filters/output b/testing/btest/Baseline/core.print-bpf-filters/output index c55952ffed..55473b8991 100644 --- a/testing/btest/Baseline/core.print-bpf-filters/output +++ b/testing/btest/Baseline/core.print-bpf-filters/output @@ -16,7 +16,7 @@ #open 2012-07-27-19-14-29 #fields ts node filter init success #types time string string bool bool -1343416469.888870 - (((((((((((((((((((((((((port 53) or (tcp port 989)) or (tcp port 443)) or (port 6669)) or (udp and port 5353)) or (port 6668)) or (tcp port 1080)) or (udp and port 5355)) or (tcp port 22)) or (tcp port 995)) or (port 21)) or (tcp port 25 or tcp port 587)) or (port 6667)) or (tcp port 614)) or (tcp port 990)) or (udp port 137)) or (tcp port 993)) or (tcp port 5223)) or (port 514)) or (tcp port 585)) or (tcp port 992)) or (tcp port 563)) or (tcp port 994)) or (tcp port 636)) or (tcp and port (80 or 81 or 631 or 1080 or 3138 or 8000 or 8080 or 8888))) or (port 6666) T T +1343416469.888870 - (((((((((((((((((((((((((port 53) or (tcp port 989)) or (tcp port 443)) or (port 6669)) or (udp and port 5353)) or (port 6668)) or (tcp port 1080)) or (udp and port 5355)) or (tcp port 22)) or (tcp port 995)) or (port 21 and port 2811)) or (tcp port 25 or tcp port 587)) or (port 6667)) or (tcp port 614)) or (tcp port 990)) or (udp port 137)) or (tcp port 993)) or (tcp port 5223)) or (port 514)) or (tcp port 585)) or (tcp port 992)) or (tcp port 563)) or (tcp port 994)) or (tcp port 636)) or (tcp and port (80 or 81 or 631 or 1080 or 3138 or 8000 or 8080 or 8888))) or (port 6666) T T #close 2012-07-27-19-14-29 #separator \x09 #set_separator , diff --git a/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log b/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log index b2afadc0fe..755260351b 100644 --- a/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log +++ b/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log @@ -77,6 +77,7 @@ scripts/base/init-default.bro scripts/base/protocols/conn/./main.bro scripts/base/protocols/conn/./contents.bro scripts/base/protocols/conn/./inactivity.bro + scripts/base/protocols/conn/./polling.bro scripts/base/protocols/dns/__load__.bro scripts/base/protocols/dns/./consts.bro scripts/base/protocols/dns/./main.bro From e34f6d9e3b1475828e11b590211311581dd05955 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Mon, 8 Oct 2012 11:38:29 -0500 Subject: [PATCH 3/4] Enable GridFTP detection by default. Track/log SSL client certs. In the *service* field of connection records, GridFTP control channels are labeled as "gridftp" and data channels as "gridftp-data". Added *client_subject* and *client_issuer_subject* as &log'd fields to SSL::Info record. Also added *client_cert* and *client_cert_chain* fields to track client cert chain. --- doc/scripts/DocSourcesList.cmake | 2 +- scripts/base/protocols/ftp/__load__.bro | 3 +- scripts/base/protocols/ftp/gridftp.bro | 106 ++++++++++++++++++ scripts/base/protocols/ssl/main.bro | 61 +++++++--- .../protocols/ftp/gridftp-data-detection.bro | 83 -------------- scripts/test-all-policy.bro | 1 - .../Baseline/core.print-bpf-filters/output | 24 ++-- .../canonified_loaded_scripts.log | 9 +- .../conn.log | 11 ++ .../notice.log | 4 +- .../ssl.log | 11 ++ .../scripts.base.protocols.ssl.basic/ssl.log | 10 +- .../scripts/base/protocols/ftp/gridftp.test | 21 ++++ .../protocols/ftp/gridftp-data-dection.test | 6 - testing/scripts/diff-remove-x509-names | 18 ++- 15 files changed, 238 insertions(+), 132 deletions(-) create mode 100644 scripts/base/protocols/ftp/gridftp.bro delete mode 100644 scripts/policy/protocols/ftp/gridftp-data-detection.bro create mode 100644 testing/btest/Baseline/scripts.base.protocols.ftp.gridftp/conn.log rename testing/btest/Baseline/{scripts.policy.protocols.ftp.gridftp-data-dection => scripts.base.protocols.ftp.gridftp}/notice.log (93%) create mode 100644 testing/btest/Baseline/scripts.base.protocols.ftp.gridftp/ssl.log create mode 100644 testing/btest/scripts/base/protocols/ftp/gridftp.test delete mode 100644 testing/btest/scripts/policy/protocols/ftp/gridftp-data-dection.test diff --git a/doc/scripts/DocSourcesList.cmake b/doc/scripts/DocSourcesList.cmake index 077e103dca..b127e1526d 100644 --- a/doc/scripts/DocSourcesList.cmake +++ b/doc/scripts/DocSourcesList.cmake @@ -69,6 +69,7 @@ rest_target(${psd} base/protocols/conn/polling.bro) rest_target(${psd} base/protocols/dns/consts.bro) rest_target(${psd} base/protocols/dns/main.bro) rest_target(${psd} base/protocols/ftp/file-extract.bro) +rest_target(${psd} base/protocols/ftp/gridftp.bro) rest_target(${psd} base/protocols/ftp/main.bro) rest_target(${psd} base/protocols/ftp/utils-commands.bro) rest_target(${psd} base/protocols/http/file-extract.bro) @@ -123,7 +124,6 @@ rest_target(${psd} policy/protocols/conn/weirds.bro) rest_target(${psd} policy/protocols/dns/auth-addl.bro) rest_target(${psd} policy/protocols/dns/detect-external-names.bro) rest_target(${psd} policy/protocols/ftp/detect.bro) -rest_target(${psd} policy/protocols/ftp/gridftp-data-detection.bro) rest_target(${psd} policy/protocols/ftp/software.bro) rest_target(${psd} policy/protocols/http/detect-MHR.bro) rest_target(${psd} policy/protocols/http/detect-intel.bro) diff --git a/scripts/base/protocols/ftp/__load__.bro b/scripts/base/protocols/ftp/__load__.bro index 0a399aef36..15c61be614 100644 --- a/scripts/base/protocols/ftp/__load__.bro +++ b/scripts/base/protocols/ftp/__load__.bro @@ -1,3 +1,4 @@ @load ./utils-commands @load ./main -@load ./file-extract \ No newline at end of file +@load ./file-extract +@load ./gridftp diff --git a/scripts/base/protocols/ftp/gridftp.bro b/scripts/base/protocols/ftp/gridftp.bro new file mode 100644 index 0000000000..e94836cceb --- /dev/null +++ b/scripts/base/protocols/ftp/gridftp.bro @@ -0,0 +1,106 @@ +##! A detection script for GridFTP data and control channels. +##! +##! GridFTP control channels are identified by FTP control channels +##! that successfully negotiate the GSSAPI method of an AUTH request +##! and for which the exchange involved an encoded TLS/SSL handshake, +##! indicating the GSI mechanism for GSSAPI was used. This analysis +##! is all supported internally, this script simple adds the "gridftp" +##! label to the *service* field of the control channel's +##! :bro:type:`connection` record. +##! +##! GridFTP data channels are identified by a heuristic that relies on +##! the fact that default settings for GridFTP clients typically +##! mutally authenticate the data channel with TLS/SSL and negotiate a +##! NULL bulk cipher (no encryption). Connections with those +##! attributes are then polled for two minutes with decreasing frequency +##! to check if the transfer sizes are large enough to indicate a +##! GridFTP ata channel that would be undesireable to analyze further +##! (e.g. stop TCP reassembly). A side effect is that true connection +##! sizes are not logged, but at the benefit of saving CPU cycles that +##! otherwise go to analyzing the large (and likely benign) connections. + +@load ./main +@load base/protocols/conn +@load base/protocols/ssl +@load base/frameworks/notice + +module GridFTP; + +export { + ## Number of bytes transferred before guessing a connection is a + ## GridFTP data channel. + const size_threshold = 1073741824 &redef; + + ## Max number of times to check whether a connection's size exceeds the + ## :bro:see:`GridFTP::size_threshold`. + const max_poll_count = 15 &redef; + + ## Whether to skip further processing of the GridFTP data channel once + ## detected, which may help performance. + const skip_data = T &redef; + + ## Base amount of time between checking whether a GridFTP data connection + ## has transferred more than :bro:see:`GridFTP::size_threshold` bytes. + const poll_interval = 1sec &redef; + + ## The amount of time the base :bro:see:`GridFTP::poll_interval` is + ## increased by each poll interval. Can be used to make more frequent + ## checks at the start of a connection and gradually slow down. + const poll_interval_increase = 1sec &redef; + + ## Raised when a GridFTP data channel is detected. + ## + ## c: The connection pertaining to the GridFTP data channel. + global data_channel_detected: event(c: connection); + + ## The initial criteria used to determine whether to start polling + ## the connection for the :bro:see:`GridFTP::size_threshold` to have + ## been exceeded. This is called in a :bro:see:`ssl_established` event + ## handler and by default looks for both a client and server certificate + ## and for a NULL bulk cipher. One way in which this function could be + ## redefined is to make it also consider client/server certificate issuer + ## subjects. + ## + ## c: The connection which may possibly be a GridFTP data channel. + ## + ## Returns: true if the connection should be further polled for an + ## exceeded :bro:see:`GridFTP::size_threshold`, else false. + const data_channel_initial_criteria: function(c: connection): bool &redef; +} + +function size_callback(c: connection, cnt: count): interval + { + if ( c$orig$size > size_threshold || c$resp$size > size_threshold ) + { + add c$service["gridftp-data"]; + event GridFTP::data_channel_detected(c); + if ( skip_data ) + skip_further_processing(c$id); + return -1sec; + } + + if ( cnt >= max_poll_count ) return -1sec; + + return poll_interval + poll_interval_increase * cnt; + } + +event ssl_established(c: connection) &priority=5 + { + # Add service label to control channels. + if ( "FTP" in c$service ) + add c$service["gridftp"]; + } + +function data_channel_initial_criteria(c: connection): bool + { + return ( c?$ssl && c$ssl?$client_subject && c$ssl?$subject && + c$ssl?$cipher && /WITH_NULL/ in c$ssl$cipher ); + } + +event ssl_established(c: connection) &priority=-3 + { + # By default GridFTP data channels do mutual authentication and + # negotiate a cipher suite with a NULL bulk cipher. + if ( data_channel_initial_criteria(c) ) + ConnPolling::watch(c, size_callback, 0, 0secs); + } diff --git a/scripts/base/protocols/ssl/main.bro b/scripts/base/protocols/ssl/main.bro index f61e0d68ab..788336e0a6 100644 --- a/scripts/base/protocols/ssl/main.bro +++ b/scripts/base/protocols/ssl/main.bro @@ -30,17 +30,28 @@ export { issuer_subject: string &log &optional; ## NotValidBefore field value from the server certificate. not_valid_before: time &log &optional; - ## NotValidAfter field value from the serve certificate. + ## NotValidAfter field value from the server certificate. not_valid_after: time &log &optional; ## Last alert that was seen during the connection. last_alert: string &log &optional; - + + ## Subject of the X.509 certificate offered by the client. + client_subject: string &log &optional; + ## Subject of the signer of the X.509 certificate offered by the client. + client_issuer_subject: string &log &optional; + ## Full binary server certificate stored in DER format. cert: string &optional; - ## Chain of certificates offered by the server to validate its + ## Chain of certificates offered by the server to validate its ## complete signing chain. cert_chain: vector of string &optional; + ## Full binary client certificate stored in DER format. + client_cert: string &optional; + ## Chain of certificates offered by the client to validate its + ## complete signing chain. + client_cert_chain: vector of string &optional; + ## The analyzer ID used for the analyzer instance attached ## to each connection. It is not used for logging since it's a ## meaningless arbitrary number. @@ -107,7 +118,8 @@ redef likely_server_ports += { function set_session(c: connection) { if ( ! c?$ssl ) - c$ssl = [$ts=network_time(), $uid=c$uid, $id=c$id, $cert_chain=vector()]; + c$ssl = [$ts=network_time(), $uid=c$uid, $id=c$id, $cert_chain=vector(), + $client_cert_chain=vector()]; } function finish(c: connection) @@ -141,23 +153,40 @@ event x509_certificate(c: connection, is_orig: bool, cert: X509, chain_idx: coun # We aren't doing anything with client certificates yet. if ( is_orig ) - return; - - if ( chain_idx == 0 ) { - # Save the primary cert. - c$ssl$cert = der_cert; + if ( chain_idx == 0 ) + { + # Save the primary cert. + c$ssl$client_cert = der_cert; - # Also save other certificate information about the primary cert. - c$ssl$subject = cert$subject; - c$ssl$issuer_subject = cert$issuer; - c$ssl$not_valid_before = cert$not_valid_before; - c$ssl$not_valid_after = cert$not_valid_after; + # Also save other certificate information about the primary cert. + c$ssl$client_subject = cert$subject; + c$ssl$client_issuer_subject = cert$issuer; + } + else + { + # Otherwise, add it to the cert validation chain. + c$ssl$client_cert_chain[|c$ssl$client_cert_chain|] = der_cert; + } } else { - # Otherwise, add it to the cert validation chain. - c$ssl$cert_chain[|c$ssl$cert_chain|] = der_cert; + if ( chain_idx == 0 ) + { + # Save the primary cert. + c$ssl$cert = der_cert; + + # Also save other certificate information about the primary cert. + c$ssl$subject = cert$subject; + c$ssl$issuer_subject = cert$issuer; + c$ssl$not_valid_before = cert$not_valid_before; + c$ssl$not_valid_after = cert$not_valid_after; + } + else + { + # Otherwise, add it to the cert validation chain. + c$ssl$cert_chain[|c$ssl$cert_chain|] = der_cert; + } } } diff --git a/scripts/policy/protocols/ftp/gridftp-data-detection.bro b/scripts/policy/protocols/ftp/gridftp-data-detection.bro deleted file mode 100644 index ffa2fa5816..0000000000 --- a/scripts/policy/protocols/ftp/gridftp-data-detection.bro +++ /dev/null @@ -1,83 +0,0 @@ -##! A detection script for GridFTP data channels. The heuristic used to -##! identify a GridFTP data channel relies on the fact that default -##! setting for GridFTP clients typically mutually authenticate the data -##! channel with SSL and negotiate a NULL bulk cipher (no encryption). -##! Connections with those attributes are then polled for two minutes -##! with decreasing frequency to check if the transfer sizes are large -##! enough to indicate a GridFTP data channel that would be undesireable -##! to analyze further (e.g. TCP reassembly no longer occurs). A side -##! effect is that true connection sizes are not logged, but at the -##! benefit of saving CPU cycles that otherwise go to analyzing such -##! large (and hopefully benign) connections. - -@load base/protocols/conn -@load base/protocols/ssl -@load base/frameworks/notice - -module GridFTP; - -export { - ## Number of bytes transferred before guessing a connection is a - ## GridFTP data channel. - const size_threshold = 1073741824 &redef; - - ## Max number of times to check whether a connection's size exceeds the - ## :bro:see:`GridFTP::size_threshold`. - const max_poll_count = 15 &redef; - - ## Whether to skip further processing of the GridFTP data channel once - ## detected, which may help performance. - const skip_data = T &redef; - - ## Base amount of time between checking whether a GridFTP connection - ## has transferred more than :bro:see:`GridFTP::size_threshold` bytes. - const poll_interval = 1sec &redef; - - ## The amount of time the base :bro:see:`GridFTP::poll_interval` is - ## increased by each poll interval. Can be used to make more frequent - ## checks at the start of a connection and gradually slow down. - const poll_interval_increase = 1sec &redef; -} - -redef enum Notice::Type += { - Data_Channel -}; - -redef record SSL::Info += { - ## Indicates a client certificate was sent in the SSL handshake. - saw_client_cert: bool &optional; -}; - -event x509_certificate(c: connection, is_orig: bool, cert: X509, chain_idx: count, chain_len: count, der_cert: string) - { - if ( is_orig && c?$ssl ) - c$ssl$saw_client_cert = T; - } - -function size_callback(c: connection, cnt: count): interval - { - if ( c$orig$size > size_threshold || c$resp$size > size_threshold ) - { - local msg = fmt("GridFTP data channel over threshold %d bytes", - size_threshold); - NOTICE([$note=Data_Channel, $msg=msg, $conn=c]); - if ( skip_data ) - skip_further_processing(c$id); - return -1sec; - } - - if ( cnt >= max_poll_count ) return -1sec; - - return poll_interval + poll_interval_increase * cnt; - } - -event ssl_established(c: connection) - { - # By default GridFTP data channels do mutual authentication and - # negotiate a cipher suite with a NULL bulk cipher. - if ( c?$ssl && c$ssl?$saw_client_cert && c$ssl?$subject && - c$ssl?$cipher && /WITH_NULL/ in c$ssl$cipher ) - { - ConnPolling::watch(c, size_callback, 0, 0secs); - } - } diff --git a/scripts/test-all-policy.bro b/scripts/test-all-policy.bro index f535d88cd5..a7c43b14b3 100644 --- a/scripts/test-all-policy.bro +++ b/scripts/test-all-policy.bro @@ -34,7 +34,6 @@ @load protocols/dns/auth-addl.bro @load protocols/dns/detect-external-names.bro @load protocols/ftp/detect.bro -@load protocols/ftp/gridftp-data-detection.bro @load protocols/ftp/software.bro @load protocols/http/detect-intel.bro @load protocols/http/detect-MHR.bro diff --git a/testing/btest/Baseline/core.print-bpf-filters/output b/testing/btest/Baseline/core.print-bpf-filters/output index 55473b8991..cd6e77dfcc 100644 --- a/testing/btest/Baseline/core.print-bpf-filters/output +++ b/testing/btest/Baseline/core.print-bpf-filters/output @@ -3,38 +3,38 @@ #empty_field (empty) #unset_field - #path packet_filter -#open 2012-07-27-19-14-29 +#open 2012-10-08-16-16-08 #fields ts node filter init success #types time string string bool bool -1343416469.508262 - ip or not ip T T -#close 2012-07-27-19-14-29 +1349712968.812610 - ip or not ip T T +#close 2012-10-08-16-16-08 #separator \x09 #set_separator , #empty_field (empty) #unset_field - #path packet_filter -#open 2012-07-27-19-14-29 +#open 2012-10-08-16-16-09 #fields ts node filter init success #types time string string bool bool -1343416469.888870 - (((((((((((((((((((((((((port 53) or (tcp port 989)) or (tcp port 443)) or (port 6669)) or (udp and port 5353)) or (port 6668)) or (tcp port 1080)) or (udp and port 5355)) or (tcp port 22)) or (tcp port 995)) or (port 21 and port 2811)) or (tcp port 25 or tcp port 587)) or (port 6667)) or (tcp port 614)) or (tcp port 990)) or (udp port 137)) or (tcp port 993)) or (tcp port 5223)) or (port 514)) or (tcp port 585)) or (tcp port 992)) or (tcp port 563)) or (tcp port 994)) or (tcp port 636)) or (tcp and port (80 or 81 or 631 or 1080 or 3138 or 8000 or 8080 or 8888))) or (port 6666) T T -#close 2012-07-27-19-14-29 +1349712969.042094 - (((((((((((((((((((((((((port 53) or (tcp port 989)) or (tcp port 443)) or (port 6669)) or (udp and port 5353)) or (port 6668)) or (tcp port 1080)) or (udp and port 5355)) or (tcp port 995)) or (tcp port 22)) or (port 21 and port 2811)) or (tcp port 25 or tcp port 587)) or (tcp port 614)) or (tcp port 990)) or (port 6667)) or (udp port 137)) or (tcp port 993)) or (tcp port 5223)) or (port 514)) or (tcp port 585)) or (tcp port 992)) or (tcp port 563)) or (tcp port 994)) or (tcp port 636)) or (tcp and port (80 or 81 or 631 or 1080 or 3138 or 8000 or 8080 or 8888))) or (port 6666) T T +#close 2012-10-08-16-16-09 #separator \x09 #set_separator , #empty_field (empty) #unset_field - #path packet_filter -#open 2012-07-27-19-14-30 +#open 2012-10-08-16-16-09 #fields ts node filter init success #types time string string bool bool -1343416470.252918 - port 42 T T -#close 2012-07-27-19-14-30 +1349712969.270826 - port 42 T T +#close 2012-10-08-16-16-09 #separator \x09 #set_separator , #empty_field (empty) #unset_field - #path packet_filter -#open 2012-07-27-19-14-30 +#open 2012-10-08-16-16-09 #fields ts node filter init success #types time string string bool bool -1343416470.614962 - port 56730 T T -#close 2012-07-27-19-14-30 +1349712969.499878 - port 56730 T T +#close 2012-10-08-16-16-09 diff --git a/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log b/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log index 755260351b..c3ee64cffe 100644 --- a/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log +++ b/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log @@ -85,6 +85,11 @@ scripts/base/init-default.bro scripts/base/protocols/ftp/./utils-commands.bro scripts/base/protocols/ftp/./main.bro scripts/base/protocols/ftp/./file-extract.bro + scripts/base/protocols/ftp/./gridftp.bro + scripts/base/protocols/ssl/__load__.bro + scripts/base/protocols/ssl/./consts.bro + scripts/base/protocols/ssl/./main.bro + scripts/base/protocols/ssl/./mozilla-ca-list.bro scripts/base/protocols/http/__load__.bro scripts/base/protocols/http/./main.bro scripts/base/protocols/http/./utils.bro @@ -103,10 +108,6 @@ scripts/base/init-default.bro scripts/base/protocols/socks/./main.bro scripts/base/protocols/ssh/__load__.bro scripts/base/protocols/ssh/./main.bro - scripts/base/protocols/ssl/__load__.bro - scripts/base/protocols/ssl/./consts.bro - scripts/base/protocols/ssl/./main.bro - scripts/base/protocols/ssl/./mozilla-ca-list.bro scripts/base/protocols/syslog/__load__.bro scripts/base/protocols/syslog/./consts.bro scripts/base/protocols/syslog/./main.bro diff --git a/testing/btest/Baseline/scripts.base.protocols.ftp.gridftp/conn.log b/testing/btest/Baseline/scripts.base.protocols.ftp.gridftp/conn.log new file mode 100644 index 0000000000..f3ac10b5b0 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ftp.gridftp/conn.log @@ -0,0 +1,11 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path conn +#open 2012-10-05-21-45-15 +#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 missed_bytes history orig_pkts orig_ip_bytes resp_pkts resp_ip_bytes tunnel_parents +#types time string addr port addr port enum string interval count count string bool count string count count count count table[string] +1348168976.274919 UWkUyAuUGXf 192.168.57.103 60108 192.168.57.101 2811 tcp ssl,ftp,gridftp 0.294743 4491 6659 SF - 0 ShAdDaFf 22 5643 21 7759 (empty) +1348168976.546371 arKYeMETxOg 192.168.57.103 35391 192.168.57.101 55968 tcp ssl,gridftp-data 0.011938 2135 3196 S1 - 0 ShADad 8 2559 6 3516 (empty) +#close 2012-10-05-21-45-15 diff --git a/testing/btest/Baseline/scripts.policy.protocols.ftp.gridftp-data-dection/notice.log b/testing/btest/Baseline/scripts.base.protocols.ftp.gridftp/notice.log similarity index 93% rename from testing/btest/Baseline/scripts.policy.protocols.ftp.gridftp-data-dection/notice.log rename to testing/btest/Baseline/scripts.base.protocols.ftp.gridftp/notice.log index dc007e4e24..f9292344a8 100644 --- a/testing/btest/Baseline/scripts.policy.protocols.ftp.gridftp-data-dection/notice.log +++ b/testing/btest/Baseline/scripts.base.protocols.ftp.gridftp/notice.log @@ -3,8 +3,8 @@ #empty_field (empty) #unset_field - #path notice -#open 2012-10-01-17-11-05 +#open 2012-10-05-21-45-15 #fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto note msg sub src dst p n peer_descr actions policy_items suppress_for dropped remote_location.country_code remote_location.region remote_location.city remote_location.latitude remote_location.longitude metric_index.host metric_index.str metric_index.network #types time string addr port addr port enum enum string string addr addr port count string table[enum] table[count] interval bool string string string double double addr string subnet 1348168976.558309 arKYeMETxOg 192.168.57.103 35391 192.168.57.101 55968 tcp GridFTP::Data_Channel GridFTP data channel over threshold 2 bytes - 192.168.57.103 192.168.57.101 55968 - bro Notice::ACTION_LOG 6 3600.000000 F - - - - - - - - -#close 2012-10-01-17-11-05 +#close 2012-10-05-21-45-15 diff --git a/testing/btest/Baseline/scripts.base.protocols.ftp.gridftp/ssl.log b/testing/btest/Baseline/scripts.base.protocols.ftp.gridftp/ssl.log new file mode 100644 index 0000000000..512676bbb6 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.ftp.gridftp/ssl.log @@ -0,0 +1,11 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path ssl +#open 2012-10-05-21-45-15 +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version cipher server_name session_id subject issuer_subject not_valid_before not_valid_after last_alert client_subject client_issuer_subject +#types time string addr port addr port string string string string string string time time string string string +1348168976.508038 UWkUyAuUGXf 192.168.57.103 60108 192.168.57.101 2811 TLSv10 TLS_RSA_WITH_AES_256_CBC_SHA - - CN=host/alpha,OU=simpleCA-alpha,OU=GlobusTest,O=Grid CN=Globus Simple CA,OU=simpleCA-alpha,OU=GlobusTest,O=Grid 1348161979.000000 1379697979.000000 - CN=917532944,CN=Jon Siwek,OU=local,OU=simpleCA-alpha,OU=GlobusTest,O=Grid CN=Jon Siwek,OU=local,OU=simpleCA-alpha,OU=GlobusTest,O=Grid +1348168976.551422 arKYeMETxOg 192.168.57.103 35391 192.168.57.101 55968 TLSv10 TLS_RSA_WITH_NULL_SHA - - CN=932373381,CN=917532944,CN=Jon Siwek,OU=local,OU=simpleCA-alpha,OU=GlobusTest,O=Grid CN=917532944,CN=Jon Siwek,OU=local,OU=simpleCA-alpha,OU=GlobusTest,O=Grid 1348168676.000000 1348206441.000000 - CN=917532944,CN=Jon Siwek,OU=local,OU=simpleCA-alpha,OU=GlobusTest,O=Grid CN=Jon Siwek,OU=local,OU=simpleCA-alpha,OU=GlobusTest,O=Grid +#close 2012-10-05-21-45-15 diff --git a/testing/btest/Baseline/scripts.base.protocols.ssl.basic/ssl.log b/testing/btest/Baseline/scripts.base.protocols.ssl.basic/ssl.log index 5bf3feddc5..872da052ea 100644 --- a/testing/btest/Baseline/scripts.base.protocols.ssl.basic/ssl.log +++ b/testing/btest/Baseline/scripts.base.protocols.ssl.basic/ssl.log @@ -3,8 +3,8 @@ #empty_field (empty) #unset_field - #path ssl -#open 2012-04-27-14-53-12 -#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version cipher server_name session_id subject issuer_subject not_valid_before not_valid_after last_alert -#types time string addr port addr port string string string string string string time time string -1335538392.319381 UWkUyAuUGXf 192.168.1.105 62045 74.125.224.79 443 TLSv10 TLS_ECDHE_RSA_WITH_RC4_128_SHA ssl.gstatic.com - CN=*.gstatic.com,O=Google Inc,L=Mountain View,ST=California,C=US CN=Google Internet Authority,O=Google Inc,C=US 1334102677.000000 1365639277.000000 - -#close 2012-04-27-14-53-16 +#open 2012-10-08-16-18-56 +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version cipher server_name session_id subject issuer_subject not_valid_before not_valid_after last_alert client_subject client_issuer_subject +#types time string addr port addr port string string string string string string time time string string string +1335538392.319381 UWkUyAuUGXf 192.168.1.105 62045 74.125.224.79 443 TLSv10 TLS_ECDHE_RSA_WITH_RC4_128_SHA ssl.gstatic.com - CN=*.gstatic.com,O=Google Inc,L=Mountain View,ST=California,C=US CN=Google Internet Authority,O=Google Inc,C=US 1334102677.000000 1365639277.000000 - - - +#close 2012-10-08-16-18-56 diff --git a/testing/btest/scripts/base/protocols/ftp/gridftp.test b/testing/btest/scripts/base/protocols/ftp/gridftp.test new file mode 100644 index 0000000000..494729cf5f --- /dev/null +++ b/testing/btest/scripts/base/protocols/ftp/gridftp.test @@ -0,0 +1,21 @@ +# @TEST-EXEC: bro -r $TRACES/globus-url-copy.trace %INPUT +# @TEST-EXEC: btest-diff notice.log +# @TEST-EXEC: btest-diff conn.log +# @TEST-EXEC: btest-diff ssl.log + +@load base/protocols/ftp/gridftp + +module GridFTP; + +redef size_threshold = 2; + +redef enum Notice::Type += { + Data_Channel +}; + +event GridFTP::data_channel_detected(c: connection) + { + local msg = fmt("GridFTP data channel over threshold %d bytes", + size_threshold); + NOTICE([$note=Data_Channel, $msg=msg, $conn=c]); + } diff --git a/testing/btest/scripts/policy/protocols/ftp/gridftp-data-dection.test b/testing/btest/scripts/policy/protocols/ftp/gridftp-data-dection.test deleted file mode 100644 index bb7b9b510d..0000000000 --- a/testing/btest/scripts/policy/protocols/ftp/gridftp-data-dection.test +++ /dev/null @@ -1,6 +0,0 @@ -# @TEST-EXEC: bro -r $TRACES/globus-url-copy.trace %INPUT -# @TEST-EXEC: btest-diff notice.log - -@load protocols/ftp/gridftp-data-detection - -redef GridFTP::size_threshold = 2; diff --git a/testing/scripts/diff-remove-x509-names b/testing/scripts/diff-remove-x509-names index 6209edfc65..4863efc990 100755 --- a/testing/scripts/diff-remove-x509-names +++ b/testing/scripts/diff-remove-x509-names @@ -3,7 +3,7 @@ # A diff canonifier that removes all X.509 Distinguished Name subject fields # because that output can differ depending on installed OpenSSL version. -BEGIN { FS="\t"; OFS="\t"; s_col = -1; i_col = -1 } +BEGIN { FS="\t"; OFS="\t"; s_col = -1; i_col = -1; cs_col = -1; ci_col = -1 } /^#fields/ { for ( i = 2; i < NF; ++i ) @@ -12,6 +12,10 @@ BEGIN { FS="\t"; OFS="\t"; s_col = -1; i_col = -1 } s_col = i-1; if ( $i == "issuer_subject" ) i_col = i-1; + if ( $i == "client_subject" ) + cs_col = i-1; + if ( $i == "client_issuer_subject" ) + ci_col = i-1; } } @@ -27,6 +31,18 @@ i_col >= 0 { $i_col = "+"; } +cs_col >= 0 { + if ( $cs_col != "-" ) + # Mark that it's set, but ignore content. + $cs_col = "+"; +} + +ci_col >= 0 { + if ( $ci_col != "-" ) + # Mark that it's set, but ignore content. + $ci_col = "+"; +} + { print; } From dedfdf7e11e5f653a5d54c582353214f8ac65f4c Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Mon, 8 Oct 2012 13:15:47 -0500 Subject: [PATCH 4/4] Add memory leak unit test for GridFTP. --- testing/btest/core/leaks/gridftp.test | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 testing/btest/core/leaks/gridftp.test diff --git a/testing/btest/core/leaks/gridftp.test b/testing/btest/core/leaks/gridftp.test new file mode 100644 index 0000000000..6364000b0d --- /dev/null +++ b/testing/btest/core/leaks/gridftp.test @@ -0,0 +1,24 @@ +# Needs perftools support. +# +# @TEST-REQUIRES: bro --help 2>&1 | grep -q mem-leaks +# +# @TEST-GROUP: leaks +# +# @TEST-EXEC: HEAP_CHECK_DUMP_DIRECTORY=. HEAPCHECK=local bro -m -r $TRACES/globus-url-copy.trace %INPUT + +@load base/protocols/ftp/gridftp + +module GridFTP; + +redef size_threshold = 2; + +redef enum Notice::Type += { + Data_Channel +}; + +event GridFTP::data_channel_detected(c: connection) + { + local msg = fmt("GridFTP data channel over threshold %d bytes", + size_threshold); + NOTICE([$note=Data_Channel, $msg=msg, $conn=c]); + }