From cc7c3776ccab7bae73b56b68c7ce0552c2f9ad45 Mon Sep 17 00:00:00 2001 From: Seth Hall Date: Wed, 27 Oct 2010 15:37:00 -0400 Subject: [PATCH] Added the initial syslog analyzer and policy script. --- policy/logging.syslog.bro | 38 ++++++++++++++++ policy/syslog.bro | 57 ++++++++++++++++++++++++ src/Analyzer.cc | 4 ++ src/AnalyzerTags.h | 2 +- src/Makefile.am | 13 ++++-- src/Syslog-binpac.cc | 92 +++++++++++++++++++++++++++++++++++++++ src/Syslog-binpac.h | 58 ++++++++++++++++++++++++ src/event.bif | 2 + src/syslog-analyzer.pac | 27 ++++++++++++ src/syslog-protocol.pac | 15 +++++++ src/syslog.pac | 10 +++++ 11 files changed, 313 insertions(+), 5 deletions(-) create mode 100644 policy/logging.syslog.bro create mode 100644 policy/syslog.bro create mode 100644 src/Syslog-binpac.cc create mode 100644 src/Syslog-binpac.h create mode 100644 src/syslog-analyzer.pac create mode 100644 src/syslog-protocol.pac create mode 100644 src/syslog.pac diff --git a/policy/logging.syslog.bro b/policy/logging.syslog.bro new file mode 100644 index 0000000000..606fd95071 --- /dev/null +++ b/policy/logging.syslog.bro @@ -0,0 +1,38 @@ +@load syslog + +module Syslog; + +export { + # If set to T, this will split inbound and outbound transactions + # into separate files. F merges everything into a single file. + const split_log_file = F &redef; + + # Which SSH logins to record. + # Choices are: Inbound, Outbound, Enabled, Disabled + const logging = Enabled &redef; + +} + +event bro_init() + { + LOG::create_logs("syslog", logging, split_log_file, T); + LOG::define_header("syslog", cat_sep("\t", "", + "ts", + "orig_h", "orig_p", + "resp_h", "resp_p", + "facility", "severity", + "msg")); + } + +event syslog_message(c: connection, facility: count, severity: count, msg: string) + { + local log = LOG::get_file_by_id("syslog", c$id, F); + local id = c$id; + + print log, cat_sep("\t", "\\N", + network_time(), + id$orig_h, port_to_count(id$orig_p), + id$resp_h, port_to_count(id$resp_p), + facility_codes[facility], severity_codes[severity], + msg); + } diff --git a/policy/syslog.bro b/policy/syslog.bro new file mode 100644 index 0000000000..988966f194 --- /dev/null +++ b/policy/syslog.bro @@ -0,0 +1,57 @@ +redef capture_filters += { ["syslog"] = "port 514" }; + +global syslog_ports = { 514/udp } &redef; +redef dpd_config += { [ANALYZER_SYSLOG_BINPAC] = [$ports = syslog_ports] }; + +module Syslog; + +export { + redef enum Notice += { + Syslog_New_Source, + Syslog_New_Destination, + }; + + const facility_codes: table[count] of string = { + [0] = "KERN", + [1] = "USER", + [2] = "MAIL", + [3] = "DAEMON", + [4] = "AUTH", + [5] = "SYSLOG", + [6] = "LPR", + [7] = "NEWS", + [8] = "UUCP", + [9] = "CRON", + [10] = "AUTHPRIV", + [11] = "FTP", + [12] = "NTP", + [13] = "AUDIT", + [14] = "ALERT", + [15] = "CLOCK", + [16] = "LOCAL0", + [17] = "LOCAL1", + [18] = "LOCAL2", + [19] = "LOCAL3", + [20] = "LOCAL4", + [21] = "LOCAL5", + [22] = "LOCAL6", + [23] = "LOCAL7", + }; + + const severity_codes: table[count] of string = { + [0] = "EMERG", + [1] = "ALERT", + [2] = "CRIT", + [3] = "ERR", + [4] = "WARNING", + [5] = "NOTICE", + [6] = "INFO", + [7] = "DEBUG", + }; + +} + +event syslog_message(c: connection, facility: count, severity: count, msg: string) + { + + } diff --git a/src/Analyzer.cc b/src/Analyzer.cc index 6ad1f7998f..14eaff20c1 100644 --- a/src/Analyzer.cc +++ b/src/Analyzer.cc @@ -36,6 +36,7 @@ #include "SSH.h" #include "SSLProxy.h" #include "SSL-binpac.h" +#include "Syslog-binpac.h" // Keep same order here as in AnalyzerTag definition! const Analyzer::Config Analyzer::analyzer_configs[] = { @@ -138,6 +139,9 @@ const Analyzer::Config Analyzer::analyzer_configs[] = { { AnalyzerTag::SSL_BINPAC, "SSL_BINPAC", SSL_Analyzer_binpac::InstantiateAnalyzer, SSL_Analyzer_binpac::Available, 0, false }, + { AnalyzerTag::SYSLOG_BINPAC, "SYSLOG_BINPAC", + Syslog_Analyzer_binpac::InstantiateAnalyzer, + Syslog_Analyzer_binpac::Available, 0, false }, { AnalyzerTag::File, "FILE", File_Analyzer::InstantiateAnalyzer, File_Analyzer::Available, 0, false }, diff --git a/src/AnalyzerTags.h b/src/AnalyzerTags.h index eafa5de300..06f5d636dc 100644 --- a/src/AnalyzerTags.h +++ b/src/AnalyzerTags.h @@ -36,7 +36,7 @@ namespace AnalyzerTag { // Application-layer analyzers, binpac-generated. DHCP_BINPAC, DNS_TCP_BINPAC, DNS_UDP_BINPAC, - HTTP_BINPAC, RPC_UDP_BINPAC, SSL_BINPAC, + HTTP_BINPAC, RPC_UDP_BINPAC, SSL_BINPAC, SYSLOG_BINPAC, // Other File, Backdoor, InterConn, SteppingStone, TCPStats, diff --git a/src/Makefile.am b/src/Makefile.am index 48aa6536a8..d620f02856 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -31,7 +31,7 @@ bifcl_SOURCES = bif_lex.cc bif_parse.cc bif_arg.cc BINPAC_SRC = binpac-lib.pac binpac_bro-lib.pac bittorrent.pac \ dce_rpc.pac dce_rpc_simple.pac dhcp.pac dns.pac \ dns_tcp.pac http.pac ncp.pac netflow.pac rpc.pac smb.pac \ - ssl.pac ssl-record-layer.pac + ssl.pac ssl-record-layer.pac syslog.pac BINPAC_H = $(BINPAC_SRC:.pac=_pac.h) BINPAC_CC = $(BINPAC_SRC:.pac=_pac.cc) @@ -49,7 +49,8 @@ BINPAC_RPC_AUXSRC = \ rpc-protocol.pac rpc-analyzer.pac \ smb-protocol.pac smb-mailslot.pac smb-pipe.pac \ ssl.pac ssl-analyzer.pac ssl-defs.pac \ - ssl-protocol.pac ssl-record-layer.pac + ssl-protocol.pac ssl-record-layer.pac \ + syslog.pac syslog-protocol.pac syslog-analyzer.pac BINPAC = @BINPAC@ BINPAC_FLAGS = -d $(top_builddir)/src -I $(srcdir) @@ -129,7 +130,7 @@ bro_SOURCES = \ Queue.cc RE.cc RPC.cc Reassem.cc RemoteSerializer.cc Rlogin.cc RSH.cc \ Rule.cc RuleAction.cc RuleCondition.cc RuleMatcher.cc \ ScriptAnaly.cc SmithWaterman.cc SMB.cc SMTP.cc \ - SSH.cc SSL-binpac.cc \ + SSH.cc SSL-binpac.cc Syslog-binpac.cc \ Scope.cc SerializationFormat.cc SerialObj.cc Serializer.cc \ Sessions.cc StateAccess.cc Stats.cc SteppingStone.cc Stmt.cc \ TCP.cc TCP_Endpoint.cc TCP_Reassembler.cc TCP_Rewriter.cc \ @@ -165,7 +166,7 @@ noinst_HEADERS = Active.h Analyzer.h AnalyzerTags.h Anon.h ARP.h Attr.h \ SSLInterpreter.h SSLProxy.h SSLv2.h SSLv3.h SSLv3Automaton.h Scope.h \ SerialInfo.h SerialObj.h SerialTypes.h \ SerializationFormat.h Serializer.h Sessions.h StateAccess.h \ - Stats.h SteppingStone.h Stmt.h StmtEnums.h \ + Stats.h SteppingStone.h Stmt.h StmtEnums.h Syslog-binpac.h \ TCP.h TCP_Endpoint.h TCP_Reassembler.h TCP_Rewriter.h Telnet.h Timer.h \ Traverse.h TraverseTypes.h Trigger.h TwoWise.h Type.h UDP.h \ Val.h Var.h X509.h XDR.h ZIP.h \ @@ -331,6 +332,10 @@ ssl_pac.h ssl_pac.cc: ssl.pac $(BINPAC) $(BINPAC_AUXSRC) $(BINPAC_AUXHDR) ssl-pr ssl-record-layer_pac.h ssl-record-layer_pac.cc: ssl-record-layer.pac $(BINPAC) $(BINPAC_AUXSRC) $(BINPAC_AUXHDR) $(BINPAC) $(BINPAC_FLAGS) $(srcdir)/ssl-record-layer.pac +syslog_pac.h syslog_pac.cc: syslog.pac $(BINPAC) $(BINPAC_AUXSRC) $(BINPAC_AUXHDR) syslog-protocol.pac syslog-analyzer.pac + $(BINPAC) $(BINPAC_FLAGS) $(srcdir)/syslog.pac + + patricia.o: patricia.c patricia.h $(CC) $(CFLAGS) -c $(srcdir)/patricia.c diff --git a/src/Syslog-binpac.cc b/src/Syslog-binpac.cc new file mode 100644 index 0000000000..28c0716aab --- /dev/null +++ b/src/Syslog-binpac.cc @@ -0,0 +1,92 @@ +// $Id:$ + +#include "Syslog-binpac.h" +#include "TCP_Reassembler.h" + +Syslog_Analyzer_binpac::Syslog_Analyzer_binpac(Connection* conn) +: Analyzer(AnalyzerTag::SYSLOG_BINPAC, conn) + { + interp = new binpac::Syslog::Syslog_Conn(this); + did_session_done = 0; + //ADD_ANALYZER_TIMER(&Syslog_Analyzer_binpac::ExpireTimer, + // network_time + Syslog_session_timeout, 1, TIMER_Syslog_EXPIRE); + } + +Syslog_Analyzer_binpac::~Syslog_Analyzer_binpac() + { + delete interp; + } + +void Syslog_Analyzer_binpac::Done() + { + Analyzer::Done(); + + if ( ! did_session_done ) + Event(udp_session_done); + } + +void Syslog_Analyzer_binpac::DeliverPacket(int len, const u_char* data, bool orig, int seq, const IP_Hdr* ip, int caplen) + { + Analyzer::DeliverPacket(len, data, orig, seq, ip, caplen); + interp->NewData(orig, data, data + len); + } + +//void Syslog_Analyzer_binpac::ExpireTimer(double t) +// { +// // The - 1.0 in the following is to allow 1 second for the +// // common case of a single request followed by a single reply, +// // so we don't needlessly set the timer twice in that case. +// if ( t - Conn()->LastTime() >= Syslog_session_timeout - 1.0 || terminating ) +// { +// Event(connection_timeout); +// sessions->Remove(Conn()); +// } +// else +// ADD_ANALYZER_TIMER(&Syslog_Analyzer_binpac::ExpireTimer, +// t + Syslog_session_timeout, 1, TIMER_Syslog_EXPIRE); +// } + +//Syslog_TCP_Analyzer_binpac::Syslog_TCP_Analyzer_binpac(Connection* conn) +//: TCP_ApplicationAnalyzer(AnalyzerTag::Syslog_TCP_BINPAC, conn) +// { +// interp = new binpac::Syslog_on_TCP::Syslog_TCP_Conn(this); +// } + +//Syslog_TCP_Analyzer_binpac::~Syslog_TCP_Analyzer_binpac() +// { +// delete interp; +// } + +//void Syslog_TCP_Analyzer_binpac::Done() +// { +// TCP_ApplicationAnalyzer::Done(); +// +// interp->FlowEOF(true); +// interp->FlowEOF(false); +// } + +//void Syslog_TCP_Analyzer_binpac::EndpointEOF(TCP_Reassembler* endp) +// { +// TCP_ApplicationAnalyzer::EndpointEOF(endp); +// interp->FlowEOF(endp->IsOrig()); +// } + +//void Syslog_TCP_Analyzer_binpac::DeliverStream(int len, const u_char* data, +// bool orig) +// { +// TCP_ApplicationAnalyzer::DeliverStream(len, data, orig); +// +// assert(TCP()); +// +// if ( TCP()->IsPartial() || TCP()->HadGap(orig) ) +// // punt-on-partial or stop-on-gap. +// return; +// +// interp->NewData(orig, data, data + len); +// } + +//void Syslog_TCP_Analyzer_binpac::Undelivered(int seq, int len, bool orig) +// { +// TCP_ApplicationAnalyzer::Undelivered(seq, len, orig); +// interp->NewGap(orig, len); +// } diff --git a/src/Syslog-binpac.h b/src/Syslog-binpac.h new file mode 100644 index 0000000000..c9a42ddbcf --- /dev/null +++ b/src/Syslog-binpac.h @@ -0,0 +1,58 @@ +// $Id:$ + +#ifndef Syslog_binpac_h +#define Syslog_binpac_h + +#include "UDP.h" +#include "TCP.h" + +#include "syslog_pac.h" + +class Syslog_Analyzer_binpac : public Analyzer { +public: + Syslog_Analyzer_binpac(Connection* conn); + virtual ~Syslog_Analyzer_binpac(); + + virtual void Done(); + virtual void DeliverPacket(int len, const u_char* data, bool orig, + int seq, const IP_Hdr* ip, int caplen); + + static Analyzer* InstantiateAnalyzer(Connection* conn) + { return new Syslog_Analyzer_binpac(conn); } + + static bool Available() + { return true; } + //{ return (Syslog_request || Syslog_full_request) && FLAGS_use_binpac; } + +protected: + friend class AnalyzerTimer; + void ExpireTimer(double t); + + int did_session_done; + + binpac::Syslog::Syslog_Conn* interp; +}; + +// #include "Syslog_tcp_pac.h" +// +//class Syslog_TCP_Analyzer_binpac : public TCP_ApplicationAnalyzer { +//public: +// Syslog_TCP_Analyzer_binpac(Connection* conn); +// virtual ~Syslog_TCP_Analyzer_binpac(); +// +// virtual void Done(); +// virtual void DeliverStream(int len, const u_char* data, bool orig); +// virtual void Undelivered(int seq, int len, bool orig); +// virtual void EndpointEOF(TCP_Reassembler* endp); +// +// static Analyzer* InstantiateAnalyzer(Connection* conn) +// { return new Syslog_TCP_Analyzer_binpac(conn); } +// +// static bool Available() +// { return (Syslog_request || Syslog_full_request) && FLAGS_use_binpac; } +// +//protected: +// binpac::Syslog_on_TCP::Syslog_TCP_Conn* interp; +//}; +// +#endif diff --git a/src/event.bif b/src/event.bif index 3171b02dde..ce5bd16c03 100644 --- a/src/event.bif +++ b/src/event.bif @@ -392,6 +392,8 @@ event irc_password_message%(c: connection, password: string%); event file_transferred%(c: connection, prefix: string, descr: string, mime_type: string%); event file_virus%(c: connection, virname: string%); +event syslog_message%(c: connection, facility: count, severity: count, msg: string%); + event signature_match%(state: signature_state, msg: string, data: string%); # Generated if a handler finds an identification of the software diff --git a/src/syslog-analyzer.pac b/src/syslog-analyzer.pac new file mode 100644 index 0000000000..5256b1d294 --- /dev/null +++ b/src/syslog-analyzer.pac @@ -0,0 +1,27 @@ + +connection Syslog_Conn(bro_analyzer: BroAnalyzer) +{ + upflow = Syslog_Flow; + downflow = Syslog_Flow; +}; + +flow Syslog_Flow +{ + datagram = Syslog_Message withcontext(connection, this); + + function process_syslog_message(m: Syslog_Message): bool + %{ + bro_event_syslog_message(connection()->bro_analyzer(), + connection()->bro_analyzer()->Conn(), + ${m.PRI.facility}, + ${m.PRI.severity}, + new StringVal(${m.msg}.length(), (const char*) ${m.msg}.begin()) + ); + return true; + %} + +}; + +refine typeattr Syslog_Message += &let { + proc_syslog_message = $context.flow.process_syslog_message(this); +}; diff --git a/src/syslog-protocol.pac b/src/syslog-protocol.pac new file mode 100644 index 0000000000..a2bf8a31da --- /dev/null +++ b/src/syslog-protocol.pac @@ -0,0 +1,15 @@ +type Syslog_Message = record { + PRI: Syslog_Priority; + msg: bytestring &restofdata; +} &byteorder = littleendian; + +type Syslog_Priority = record { + lt : uint8 &check(lt == "<"); + val : RE/[[:digit:]]+/; + gt : uint8 &check(gt == ">"); +} &let { + val_length: int = sizeof(val) - 1; + int_val: int = bytestring_to_int(val, 10); + severity: int = (int_val & 0x07); + facility: int = (int_val & 0x03f8) >> 3; +}; diff --git a/src/syslog.pac b/src/syslog.pac new file mode 100644 index 0000000000..3c0ecfb10d --- /dev/null +++ b/src/syslog.pac @@ -0,0 +1,10 @@ +%include binpac.pac +%include bro.pac + +analyzer Syslog withcontext { + connection: Syslog_Conn; + flow: Syslog_Flow; +}; + +%include syslog-protocol.pac +%include syslog-analyzer.pac