From 0b897c70da1ddcfd867101a7331ac45cd003d457 Mon Sep 17 00:00:00 2001 From: Johanna Amann Date: Tue, 21 Jul 2015 13:20:35 -0700 Subject: [PATCH] Add xmpp dpd sig and fix a few parsing problems for connections that do not upgrade to TLS. --- scripts/base/protocols/xmpp/__load__.bro | 2 ++ scripts/base/protocols/xmpp/dpd.sig | 5 +++++ src/analyzer/protocol/xmpp/XMPP.cc | 1 - src/analyzer/protocol/xmpp/xmpp-analyzer.pac | 7 ++++--- src/analyzer/protocol/xmpp/xmpp-protocol.pac | 3 ++- .../ssl.log | 10 ++++++++++ .../ssl.log | 10 ++++++++++ .../Traces/tls/xmpp-dialback-starttls.pcap | Bin 0 -> 14673 bytes .../scripts/base/protocols/xmpp/client-dpd.test | 8 ++++++++ .../protocols/xmpp/server-dialback-dpd.test | 8 ++++++++ 10 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 scripts/base/protocols/xmpp/dpd.sig create mode 100644 testing/btest/Baseline/scripts.base.protocols.xmpp.client-dpd/ssl.log create mode 100644 testing/btest/Baseline/scripts.base.protocols.xmpp.server-dialback-dpd/ssl.log create mode 100644 testing/btest/Traces/tls/xmpp-dialback-starttls.pcap create mode 100644 testing/btest/scripts/base/protocols/xmpp/client-dpd.test create mode 100644 testing/btest/scripts/base/protocols/xmpp/server-dialback-dpd.test diff --git a/scripts/base/protocols/xmpp/__load__.bro b/scripts/base/protocols/xmpp/__load__.bro index a10fe855df..0f41578f8a 100644 --- a/scripts/base/protocols/xmpp/__load__.bro +++ b/scripts/base/protocols/xmpp/__load__.bro @@ -1 +1,3 @@ @load ./main + +@load-sigs ./dpd.sig diff --git a/scripts/base/protocols/xmpp/dpd.sig b/scripts/base/protocols/xmpp/dpd.sig new file mode 100644 index 0000000000..50ae57a669 --- /dev/null +++ b/scripts/base/protocols/xmpp/dpd.sig @@ -0,0 +1,5 @@ +signature dpd_xmpp { + ip-proto == tcp + payload /^(<\?xml[^?>]*\?>)?[\n\r ]*]*xmlns='jabber:/ + enable "xmpp" +} diff --git a/src/analyzer/protocol/xmpp/XMPP.cc b/src/analyzer/protocol/xmpp/XMPP.cc index c84c372c4d..ee2667a276 100644 --- a/src/analyzer/protocol/xmpp/XMPP.cc +++ b/src/analyzer/protocol/xmpp/XMPP.cc @@ -61,7 +61,6 @@ void XMPP_Analyzer::DeliverStream(int len, const u_char* data, bool orig) } catch ( const binpac::Exception& e ) { - printf("BinPAC Exception: %s\n", e.c_msg()); ProtocolViolation(fmt("Binpac exception: %s", e.c_msg())); } } diff --git a/src/analyzer/protocol/xmpp/xmpp-analyzer.pac b/src/analyzer/protocol/xmpp/xmpp-analyzer.pac index a4417e1601..90b51ec183 100644 --- a/src/analyzer/protocol/xmpp/xmpp-analyzer.pac +++ b/src/analyzer/protocol/xmpp/xmpp-analyzer.pac @@ -16,7 +16,8 @@ refine connection XMPP_Conn += { // Yup, looks like xmpp... bro_analyzer()->ProtocolConfirmation(); - if ( token == "success" || token == "message" ) + if ( token == "success" || token == "message" || token == "db:result" + || token == "db:verify" || token == "presence" ) // Handshake has passed the phase where we should see StartTLS. Simply skip from hereon... bro_analyzer()->SetSkip(true); @@ -24,9 +25,9 @@ refine connection XMPP_Conn += { client_starttls = true; if ( !is_orig && token == "proceed" && client_starttls ) - { bro_analyzer()->StartTLS(); - } + else if ( !is_orig && token == "proceed" ) + reporter->Weird(bro_analyzer()->Conn(), "XMPP: proceed without starttls"); //printf("Processed: %d %s %s \n", is_orig, c_str(name), c_str(rest)); diff --git a/src/analyzer/protocol/xmpp/xmpp-protocol.pac b/src/analyzer/protocol/xmpp/xmpp-protocol.pac index e05268fe32..9b21679c30 100644 --- a/src/analyzer/protocol/xmpp/xmpp-protocol.pac +++ b/src/analyzer/protocol/xmpp/xmpp-protocol.pac @@ -3,6 +3,7 @@ type XML_END = RE/>/; type XML_NAME = RE/\/?[?:[:alnum:]]+/; type XML_REST = RE/[^<>]*/; type SPACING = RE/[ \r\n]*/; +type CONTENT = RE/[^<>]*/; type XMPP_PDU(is_orig: bool) = XMPP_TOKEN(is_orig)[] &until($input.length() == 0); @@ -12,6 +13,6 @@ type XMPP_TOKEN(is_orig: bool) = record { name: XML_NAME; rest: XML_REST; : XML_END; - : SPACING; + tagcontent: CONTENT; }; diff --git a/testing/btest/Baseline/scripts.base.protocols.xmpp.client-dpd/ssl.log b/testing/btest/Baseline/scripts.base.protocols.xmpp.client-dpd/ssl.log new file mode 100644 index 0000000000..0ce11b2e6f --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.xmpp.client-dpd/ssl.log @@ -0,0 +1,10 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path ssl +#open 2015-07-21-20-08-11 +#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 cert_chain_fuids client_cert_chain_fuids subject issuer client_subject client_issuer +#types time string addr port addr port string string string string bool string string bool vector[string] vector[string] string string string string +1437091702.232293 CXWv6p3arKYeMETxOg 198.128.203.95 56048 146.255.57.229 5222 TLSv12 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 secp256r1 - F - - T F5Nz2G1vSZQ0QXM2s8,FUw8omi2keRxShDUa (empty) CN=jabber.ccc.de,O=Chaos Computer Club e.V.,L=Hamburg,ST=Hamburg,C=DE emailAddress=support@cacert.org,CN=CA Cert Signing Authority,OU=http://www.cacert.org,O=Root CA - - +#close 2015-07-21-20-08-11 diff --git a/testing/btest/Baseline/scripts.base.protocols.xmpp.server-dialback-dpd/ssl.log b/testing/btest/Baseline/scripts.base.protocols.xmpp.server-dialback-dpd/ssl.log new file mode 100644 index 0000000000..15641ba5b0 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.xmpp.server-dialback-dpd/ssl.log @@ -0,0 +1,10 @@ +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path ssl +#open 2015-07-21-20-18-36 +#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 cert_chain_fuids client_cert_chain_fuids subject issuer client_subject client_issuer +#types time string addr port addr port string string string string bool string string bool vector[string] vector[string] string string string string +1437506779.381295 CXWv6p3arKYeMETxOg 184.73.173.246 1193 104.236.167.107 5269 TLSv12 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 secp384r1 - F - - T FLFr7Z1TXmFDv9FwC2,FydVem3ToAkEIAHD29,FK07OA1VxtQi69Irde F3D2e62Vxl7iTnwbA4,FUCD5w4ABMG5N0YvSi,FxWUEd3mgvThYO2uod,FGOrVE2laVCPsCLMF6 CN=www.0xxon.net,OU=Free SSL,OU=Domain Control Validated CN=COMODO RSA Domain Validation Secure Server CA,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB CN=*.hosted.im,OU=Domain Control Validated CN=Go Daddy Secure Certificate Authority - G2,OU=http://certs.godaddy.com/repository/,O=GoDaddy.com\\, Inc.,L=Scottsdale,ST=Arizona,C=US +#close 2015-07-21-20-18-36 diff --git a/testing/btest/Traces/tls/xmpp-dialback-starttls.pcap b/testing/btest/Traces/tls/xmpp-dialback-starttls.pcap new file mode 100644 index 0000000000000000000000000000000000000000..ad55c6eceba70f34ebabaf3f8aa8f25f83fa0fe8 GIT binary patch literal 14673 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