mirror of
https://github.com/zeek/zeek.git
synced 2025-10-06 08:38:20 +00:00
Add simple XMPP StartTLS analyzer.
This is a very simple XMPP analyzer that basically only can parse the protocol until the client and server start negotiating a TLS session. At that point, the TLS analyzer is attached. While the basic case seems to be working, I fully expect that I missed something and that this might break in a lot of cases.
This commit is contained in:
parent
748450c61f
commit
574bcb0a51
17 changed files with 314 additions and 0 deletions
|
@ -59,6 +59,7 @@
|
|||
@load base/protocols/ssl
|
||||
@load base/protocols/syslog
|
||||
@load base/protocols/tunnels
|
||||
@load base/protocols/xmpp
|
||||
|
||||
@load base/files/pe
|
||||
@load base/files/hash
|
||||
|
|
5
scripts/base/protocols/xmpp/README
Normal file
5
scripts/base/protocols/xmpp/README
Normal file
|
@ -0,0 +1,5 @@
|
|||
Support for the Extensible Messaging and Presence Protocol (XMPP).
|
||||
|
||||
Note that currently the XMPP analyzer only supports analyzing XMPP sessions
|
||||
until they do or do not switch to TLS using StartTLS. Hence, we do not get
|
||||
actual chat information from XMPP sessions, only X509 certificates.
|
1
scripts/base/protocols/xmpp/__load__.bro
Normal file
1
scripts/base/protocols/xmpp/__load__.bro
Normal file
|
@ -0,0 +1 @@
|
|||
@load ./main
|
11
scripts/base/protocols/xmpp/main.bro
Normal file
11
scripts/base/protocols/xmpp/main.bro
Normal file
|
@ -0,0 +1,11 @@
|
|||
|
||||
module XMPP;
|
||||
|
||||
const ports = { 5222/tcp, 5269/tcp };
|
||||
redef likely_server_ports += { ports };
|
||||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Analyzer::register_for_ports(Analyzer::ANALYZER_XMPP, ports);
|
||||
}
|
||||
|
|
@ -43,4 +43,5 @@ add_subdirectory(syslog)
|
|||
add_subdirectory(tcp)
|
||||
add_subdirectory(teredo)
|
||||
add_subdirectory(udp)
|
||||
add_subdirectory(xmpp)
|
||||
add_subdirectory(zip)
|
||||
|
|
11
src/analyzer/protocol/xmpp/CMakeLists.txt
Normal file
11
src/analyzer/protocol/xmpp/CMakeLists.txt
Normal file
|
@ -0,0 +1,11 @@
|
|||
|
||||
include(BroPlugin)
|
||||
|
||||
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
bro_plugin_begin(Bro XMPP)
|
||||
bro_plugin_cc(Plugin.cc)
|
||||
bro_plugin_cc(XMPP.cc)
|
||||
bro_plugin_pac(xmpp.pac xmpp-analyzer.pac xmpp-protocol.pac)
|
||||
bro_plugin_end()
|
||||
|
26
src/analyzer/protocol/xmpp/Plugin.cc
Normal file
26
src/analyzer/protocol/xmpp/Plugin.cc
Normal file
|
@ -0,0 +1,26 @@
|
|||
// See the file in the main distribution directory for copyright.
|
||||
|
||||
|
||||
#include "plugin/Plugin.h"
|
||||
|
||||
#include "XMPP.h"
|
||||
|
||||
namespace plugin {
|
||||
namespace Bro_XMPP {
|
||||
|
||||
class Plugin : public plugin::Plugin {
|
||||
public:
|
||||
plugin::Configuration Configure()
|
||||
{
|
||||
AddComponent(new ::analyzer::Component("XMPP", ::analyzer::xmpp::XMPP_Analyzer::Instantiate));
|
||||
|
||||
|
||||
plugin::Configuration config;
|
||||
config.name = "Bro::XMPP";
|
||||
config.description = "XMPP analyzer StartTLS only";
|
||||
return config;
|
||||
}
|
||||
} plugin;
|
||||
|
||||
}
|
||||
}
|
87
src/analyzer/protocol/xmpp/XMPP.cc
Normal file
87
src/analyzer/protocol/xmpp/XMPP.cc
Normal file
|
@ -0,0 +1,87 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "XMPP.h"
|
||||
#include "analyzer/protocol/tcp/TCP_Reassembler.h"
|
||||
#include "analyzer/Manager.h"
|
||||
|
||||
using namespace analyzer::xmpp;
|
||||
|
||||
XMPP_Analyzer::XMPP_Analyzer(Connection* conn)
|
||||
: tcp::TCP_ApplicationAnalyzer("XMPP", conn)
|
||||
{
|
||||
interp = new binpac::XMPP::XMPP_Conn(this);
|
||||
had_gap = false;
|
||||
tls_active = false;
|
||||
}
|
||||
|
||||
XMPP_Analyzer::~XMPP_Analyzer()
|
||||
{
|
||||
delete interp;
|
||||
}
|
||||
|
||||
void XMPP_Analyzer::Done()
|
||||
{
|
||||
tcp::TCP_ApplicationAnalyzer::Done();
|
||||
|
||||
interp->FlowEOF(true);
|
||||
interp->FlowEOF(false);
|
||||
}
|
||||
|
||||
void XMPP_Analyzer::EndpointEOF(bool is_orig)
|
||||
{
|
||||
tcp::TCP_ApplicationAnalyzer::EndpointEOF(is_orig);
|
||||
interp->FlowEOF(is_orig);
|
||||
}
|
||||
|
||||
void XMPP_Analyzer::DeliverStream(int len, const u_char* data, bool orig)
|
||||
{
|
||||
tcp::TCP_ApplicationAnalyzer::DeliverStream(len, data, orig);
|
||||
|
||||
if ( tls_active )
|
||||
{
|
||||
// If TLS has been initiated, forward to child and abort further
|
||||
// processing
|
||||
ForwardStream(len, data, orig);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(TCP());
|
||||
if ( TCP()->IsPartial() )
|
||||
return;
|
||||
|
||||
if ( had_gap )
|
||||
// If only one side had a content gap, we could still try to
|
||||
// deliver data to the other side if the script layer can
|
||||
// handle this.
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
interp->NewData(orig, data, data + len);
|
||||
}
|
||||
catch ( const binpac::Exception& e )
|
||||
{
|
||||
printf("BinPAC Exception: %s\n", e.c_msg());
|
||||
ProtocolViolation(fmt("Binpac exception: %s", e.c_msg()));
|
||||
}
|
||||
}
|
||||
|
||||
void XMPP_Analyzer::Undelivered(uint64 seq, int len, bool orig)
|
||||
{
|
||||
tcp::TCP_ApplicationAnalyzer::Undelivered(seq, len, orig);
|
||||
had_gap = true;
|
||||
interp->NewGap(orig, len);
|
||||
}
|
||||
|
||||
void XMPP_Analyzer::StartTLS()
|
||||
{
|
||||
// StartTLS was called. This means we saw a client starttls followed
|
||||
// by a server proceed. From here on, everything should be a binary
|
||||
// TLS datastream.
|
||||
|
||||
tls_active = true;
|
||||
|
||||
Analyzer* ssl = analyzer_mgr->InstantiateAnalyzer("SSL", Conn());
|
||||
if ( ssl )
|
||||
AddChildAnalyzer(ssl);
|
||||
}
|
38
src/analyzer/protocol/xmpp/XMPP.h
Normal file
38
src/analyzer/protocol/xmpp/XMPP.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#ifndef ANALYZER_PROTOCOL_XMPP_XMPP_H
|
||||
#define ANALYZER_PROTOCOL_XMPP_XMPP_H
|
||||
|
||||
#include "analyzer/protocol/tcp/TCP.h"
|
||||
|
||||
#include "xmpp_pac.h"
|
||||
|
||||
namespace analyzer { namespace xmpp {
|
||||
|
||||
class XMPP_Analyzer : public tcp::TCP_ApplicationAnalyzer {
|
||||
public:
|
||||
XMPP_Analyzer(Connection* conn);
|
||||
virtual ~XMPP_Analyzer();
|
||||
|
||||
virtual void Done();
|
||||
virtual void DeliverStream(int len, const u_char* data, bool orig);
|
||||
virtual void Undelivered(uint64 seq, int len, bool orig);
|
||||
|
||||
// Overriden from tcp::TCP_ApplicationAnalyzer.
|
||||
virtual void EndpointEOF(bool is_orig);
|
||||
|
||||
void StartTLS();
|
||||
|
||||
static analyzer::Analyzer* Instantiate(Connection* conn)
|
||||
{ return new XMPP_Analyzer(conn); }
|
||||
|
||||
protected:
|
||||
binpac::XMPP::XMPP_Conn* interp;
|
||||
bool had_gap;
|
||||
|
||||
bool tls_active;
|
||||
};
|
||||
|
||||
} } // namespace analyzer::*
|
||||
|
||||
#endif /* ANALYZER_PROTOCOL_XMPP_XMPP_H */
|
41
src/analyzer/protocol/xmpp/xmpp-analyzer.pac
Normal file
41
src/analyzer/protocol/xmpp/xmpp-analyzer.pac
Normal file
|
@ -0,0 +1,41 @@
|
|||
refine connection XMPP_Conn += {
|
||||
|
||||
%member{
|
||||
bool client_starttls;
|
||||
%}
|
||||
|
||||
%init{
|
||||
client_starttls = false;
|
||||
%}
|
||||
|
||||
function proc_xmpp_token(is_orig: bool, name: bytestring, rest: bytestring): bool
|
||||
%{
|
||||
string token = std_str(name);
|
||||
|
||||
if ( is_orig && token == "stream:stream" )
|
||||
// Yup, looks like xmpp...
|
||||
bro_analyzer()->ProtocolConfirmation();
|
||||
|
||||
if ( token == "success" || token == "message" )
|
||||
// Handshake has passed the phase where we should see StartTLS. Simply skip from hereon...
|
||||
bro_analyzer()->SetSkip(true);
|
||||
|
||||
if ( is_orig && token == "starttls" )
|
||||
client_starttls = true;
|
||||
|
||||
if ( !is_orig && token == "proceed" && client_starttls )
|
||||
{
|
||||
bro_analyzer()->StartTLS();
|
||||
}
|
||||
|
||||
//printf("Processed: %d %s %s \n", is_orig, c_str(name), c_str(rest));
|
||||
|
||||
return true;
|
||||
%}
|
||||
|
||||
};
|
||||
|
||||
refine typeattr XMPP_TOKEN += &let {
|
||||
proc: bool = $context.connection.proc_xmpp_token(is_orig, name, rest);
|
||||
};
|
||||
|
17
src/analyzer/protocol/xmpp/xmpp-protocol.pac
Normal file
17
src/analyzer/protocol/xmpp/xmpp-protocol.pac
Normal file
|
@ -0,0 +1,17 @@
|
|||
type XML_START = RE/</;
|
||||
type XML_END = RE/>/;
|
||||
type XML_NAME = RE/\/?[?:[:alnum:]]+/;
|
||||
type XML_REST = RE/[^<>]*/;
|
||||
type SPACING = RE/[ \r\n]*/;
|
||||
|
||||
type XMPP_PDU(is_orig: bool) = XMPP_TOKEN(is_orig)[] &until($input.length() == 0);
|
||||
|
||||
type XMPP_TOKEN(is_orig: bool) = record {
|
||||
: SPACING;
|
||||
: XML_START;
|
||||
name: XML_NAME;
|
||||
rest: XML_REST;
|
||||
: XML_END;
|
||||
: SPACING;
|
||||
};
|
||||
|
35
src/analyzer/protocol/xmpp/xmpp.pac
Normal file
35
src/analyzer/protocol/xmpp/xmpp.pac
Normal file
|
@ -0,0 +1,35 @@
|
|||
# binpac file for the XMPP analyzer.
|
||||
# Note that we currently do not even try to parse the protocol
|
||||
# completely -- this is only supposed to be able to parse xmpp
|
||||
# till StartTLS does (or does not) kick in.
|
||||
|
||||
%include binpac.pac
|
||||
%include bro.pac
|
||||
|
||||
%extern{
|
||||
namespace analyzer { namespace xmpp { class XMPP_Analyzer; } }
|
||||
namespace binpac { namespace XMPP { class XMPP_Conn; } }
|
||||
typedef analyzer::xmpp::XMPP_Analyzer* XMPPAnalyzer;
|
||||
|
||||
#include "XMPP.h"
|
||||
%}
|
||||
|
||||
extern type XMPPAnalyzer;
|
||||
|
||||
analyzer XMPP withcontext {
|
||||
connection: XMPP_Conn;
|
||||
flow: XMPP_Flow;
|
||||
};
|
||||
|
||||
connection XMPP_Conn(bro_analyzer: XMPPAnalyzer) {
|
||||
upflow = XMPP_Flow(true);
|
||||
downflow = XMPP_Flow(false);
|
||||
};
|
||||
|
||||
%include xmpp-protocol.pac
|
||||
|
||||
flow XMPP_Flow(is_orig: bool) {
|
||||
datagram = XMPP_PDU(is_orig) withcontext(connection, this);
|
||||
};
|
||||
|
||||
%include xmpp-analyzer.pac
|
|
@ -0,0 +1,10 @@
|
|||
#separator \x09
|
||||
#set_separator ,
|
||||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path conn
|
||||
#open 2015-07-21-18-55-16
|
||||
#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
|
||||
#types time string addr port addr port enum string interval count count string bool bool count string count count count count set[string]
|
||||
1437091701.732171 CXWv6p3arKYeMETxOg 198.128.203.95 56048 146.255.57.229 5222 tcp ssl,xmpp 2.213218 676 4678 SF - - 0 ShADadfFr 19 1676 15 5442 (empty)
|
||||
#close 2015-07-21-18-55-16
|
|
@ -0,0 +1,10 @@
|
|||
#separator \x09
|
||||
#set_separator ,
|
||||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path ssl
|
||||
#open 2015-07-21-18-55-16
|
||||
#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-18-55-16
|
|
@ -0,0 +1,11 @@
|
|||
#separator \x09
|
||||
#set_separator ,
|
||||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path x509
|
||||
#open 2015-07-21-18-55-16
|
||||
#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
|
||||
1437091702.407347 F5Nz2G1vSZQ0QXM2s8 3 0DF4F2 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 1382043019.000000 1445115019.000000 rsaEncryption sha1WithRSAEncryption rsa 2048 65537 - jabber.ccc.de,conference.jabber.ccc.de,jabberd.jabber.ccc.de,pubsub.jabber.ccc.de,vjud.jabber.ccc.de - - - F -
|
||||
1437091702.407347 FUw8omi2keRxShDUa 3 00 emailAddress=support@cacert.org,CN=CA Cert Signing Authority,OU=http://www.cacert.org,O=Root CA emailAddress=support@cacert.org,CN=CA Cert Signing Authority,OU=http://www.cacert.org,O=Root CA 1049027389.000000 1995712189.000000 rsaEncryption md5WithRSAEncryption rsa 4096 65537 - - - - - T -
|
||||
#close 2015-07-21-18-55-16
|
BIN
testing/btest/Traces/tls/xmpp-starttls.pcap
Normal file
BIN
testing/btest/Traces/tls/xmpp-starttls.pcap
Normal file
Binary file not shown.
9
testing/btest/scripts/base/protocols/xmpp/starttls.test
Normal file
9
testing/btest/scripts/base/protocols/xmpp/starttls.test
Normal file
|
@ -0,0 +1,9 @@
|
|||
# @TEST-EXEC: bro -C -b -r $TRACES/tls/xmpp-starttls.pcap %INPUT
|
||||
# @TEST-EXEC: btest-diff conn.log
|
||||
# @TEST-EXEC: btest-diff ssl.log
|
||||
# @TEST-EXEC: btest-diff x509.log
|
||||
|
||||
@load base/protocols/conn
|
||||
@load base/frameworks/dpd
|
||||
@load base/protocols/ssl
|
||||
@load base/protocols/xmpp
|
Loading…
Add table
Add a link
Reference in a new issue