From 7b77c7e523f9855a73b1e6a494dd7fe45ad5f431 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Fri, 9 Oct 2020 12:41:15 -0700 Subject: [PATCH 1/3] Rename signature parser tokens to not be TCP-specific --- src/rule-parse.y | 14 +++++++------- src/rule-scan.l | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/rule-parse.y b/src/rule-parse.y index eb79250bf5..c99104e0e3 100644 --- a/src/rule-parse.y +++ b/src/rule-parse.y @@ -59,14 +59,14 @@ static uint8_t ip4_mask_to_len(uint32_t mask) %token TOK_SRC_PORT %token TOK_TCP_STATE %token TOK_STRING -%token TOK_TCP_STATE_SYM +%token TOK_STATE_SYM %token TOK_ACTIVE %token TOK_BOOL %token TOK_POLICY_SYMBOL %type TOK_STRING TOK_IDENT TOK_POLICY_SYMBOL TOK_PATTERN pattern string -%type TOK_INT TOK_TCP_STATE_SYM TOK_IP_OPTION_SYM TOK_COMP -%type integer ipoption_list tcpstate_list opt_strength +%type TOK_INT TOK_STATE_SYM TOK_IP_OPTION_SYM TOK_COMP +%type integer ipoption_list state_list opt_strength %type rule %type TOK_BOOL opt_negate %type hdr_expr @@ -246,7 +246,7 @@ rule_attr: (zeek::detail::RuleHdrTest::Comp) $2, $3)); } - | TOK_TCP_STATE tcpstate_list + | TOK_TCP_STATE state_list { current_rule->AddCondition(new zeek::detail::RuleConditionTCPState($2)); } @@ -382,10 +382,10 @@ ipoption_list: { $$ = $1; } ; -tcpstate_list: - tcpstate_list ',' TOK_TCP_STATE_SYM +state_list: + state_list ',' TOK_STATE_SYM { $$ = $1 | $3; } - | TOK_TCP_STATE_SYM + | TOK_STATE_SYM { $$ = $1; } ; diff --git a/src/rule-scan.l b/src/rule-scan.l index ff4c6b0dfa..c7ccb90009 100644 --- a/src/rule-scan.l +++ b/src/rule-scan.l @@ -76,22 +76,22 @@ false { rules_lval.val = false; return TOK_BOOL; } established { rules_lval.val = zeek::detail::RuleConditionTCPState::STATE_ESTABLISHED; - return TOK_TCP_STATE_SYM; + return TOK_STATE_SYM; } originator { rules_lval.val = zeek::detail::RuleConditionTCPState::STATE_ORIG; - return TOK_TCP_STATE_SYM; + return TOK_STATE_SYM; } responder { rules_lval.val = zeek::detail::RuleConditionTCPState::STATE_RESP; - return TOK_TCP_STATE_SYM; + return TOK_STATE_SYM; } stateless { rules_lval.val = zeek::detail::RuleConditionTCPState::STATE_STATELESS; - return TOK_TCP_STATE_SYM; + return TOK_STATE_SYM; } lsrr { From 7556beac20ae4798f85e20e872d7262026f7b0af Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Fri, 9 Oct 2020 12:56:23 -0700 Subject: [PATCH 2/3] Rename RuleConditionTCPState::TCPState enum values --- src/RuleCondition.cc | 8 ++++---- src/RuleCondition.h | 14 +++++++------- src/rule-scan.l | 8 ++++---- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/RuleCondition.cc b/src/RuleCondition.cc index 977eb9f8e2..0650ea309b 100644 --- a/src/RuleCondition.cc +++ b/src/RuleCondition.cc @@ -32,16 +32,16 @@ bool RuleConditionTCPState::DoMatch(Rule* rule, RuleEndpointState* state, auto* ta = static_cast(root); - if ( tcpstates & STATE_STATELESS ) + if ( tcpstates & RULE_STATE_STATELESS ) return true; - if ( (tcpstates & STATE_ORIG) && ! state->IsOrig() ) + if ( (tcpstates & RULE_STATE_ORIG) && ! state->IsOrig() ) return false; - if ( (tcpstates & STATE_RESP) && state->IsOrig() ) + if ( (tcpstates & RULE_STATE_RESP) && state->IsOrig() ) return false; - if ( (tcpstates & STATE_ESTABLISHED ) && + if ( (tcpstates & RULE_STATE_ESTABLISHED ) && ! (is_established(ta->Orig()) && is_established(ta->Resp()))) return false; diff --git a/src/RuleCondition.h b/src/RuleCondition.h index aa735cf854..5951b86eaf 100644 --- a/src/RuleCondition.h +++ b/src/RuleCondition.h @@ -22,16 +22,16 @@ public: virtual void PrintDebug() = 0; }; +enum RuleStateKind { + RULE_STATE_ESTABLISHED = 1, + RULE_STATE_ORIG = 2, + RULE_STATE_RESP = 4, + RULE_STATE_STATELESS = 8 +}; + // Implements the "tcp-state" keyword. class RuleConditionTCPState : public RuleCondition { public: - enum TCPState { - STATE_ESTABLISHED = 1, - STATE_ORIG = 2, - STATE_RESP = 4, - STATE_STATELESS = 8 - }; - explicit RuleConditionTCPState(int arg_tcpstates) { tcpstates = arg_tcpstates; } diff --git a/src/rule-scan.l b/src/rule-scan.l index c7ccb90009..0660105513 100644 --- a/src/rule-scan.l +++ b/src/rule-scan.l @@ -75,22 +75,22 @@ true { rules_lval.val = true; return TOK_BOOL; } false { rules_lval.val = false; return TOK_BOOL; } established { - rules_lval.val = zeek::detail::RuleConditionTCPState::STATE_ESTABLISHED; + rules_lval.val = zeek::detail::RULE_STATE_ESTABLISHED; return TOK_STATE_SYM; } originator { - rules_lval.val = zeek::detail::RuleConditionTCPState::STATE_ORIG; + rules_lval.val = zeek::detail::RULE_STATE_ORIG; return TOK_STATE_SYM; } responder { - rules_lval.val = zeek::detail::RuleConditionTCPState::STATE_RESP; + rules_lval.val = zeek::detail::RULE_STATE_RESP; return TOK_STATE_SYM; } stateless { - rules_lval.val = zeek::detail::RuleConditionTCPState::STATE_STATELESS; + rules_lval.val = zeek::detail::RULE_STATE_STATELESS; return TOK_STATE_SYM; } From 5904d0708f7c350ffd92eeac34165fdd5aebdd39 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Fri, 9 Oct 2020 13:43:17 -0700 Subject: [PATCH 3/3] GH-779: Add "udp-state" signature condition It accepts "originator" or "responder" states as a way to enforce that the signature only matches packets in the associated direction. The "established" state is rejected as an error since it doesn't have a useful meaning like it does for the "tcp-state" condition. --- src/RuleCondition.cc | 25 +++++++++++++ src/RuleCondition.h | 14 ++++++++ src/rule-parse.y | 9 +++++ src/rule-scan.l | 1 + .../btest/Baseline/signatures.udp-state/out | 10 ++++++ .../Baseline/signatures.udp-state/reject | 2 ++ testing/btest/signatures/udp-state.zeek | 36 +++++++++++++++++++ 7 files changed, 97 insertions(+) create mode 100644 testing/btest/Baseline/signatures.udp-state/out create mode 100644 testing/btest/Baseline/signatures.udp-state/reject create mode 100644 testing/btest/signatures/udp-state.zeek diff --git a/src/RuleCondition.cc b/src/RuleCondition.cc index 0650ea309b..789c94cd88 100644 --- a/src/RuleCondition.cc +++ b/src/RuleCondition.cc @@ -54,6 +54,31 @@ void RuleConditionTCPState::PrintDebug() fprintf(stderr, " RuleConditionTCPState: 0x%x\n", tcpstates); } +bool RuleConditionUDPState::DoMatch(Rule* rule, RuleEndpointState* state, + const u_char* data, int len) + { + analyzer::Analyzer* root = state->GetAnalyzer()->Conn()->GetRootAnalyzer(); + + if ( ! root || ! root->IsAnalyzer("UDP") ) + return false; + + if ( states & RULE_STATE_STATELESS ) + return true; + + if ( (states & RULE_STATE_ORIG) && ! state->IsOrig() ) + return false; + + if ( (states & RULE_STATE_RESP) && state->IsOrig() ) + return false; + + return true; + } + +void RuleConditionUDPState::PrintDebug() + { + fprintf(stderr, " RuleConditionUDPState: 0x%x\n", states); + } + void RuleConditionIPOptions::PrintDebug() { fprintf(stderr, " RuleConditionIPOptions: 0x%x\n", options); diff --git a/src/RuleCondition.h b/src/RuleCondition.h index 5951b86eaf..6e73da4d1d 100644 --- a/src/RuleCondition.h +++ b/src/RuleCondition.h @@ -46,6 +46,20 @@ private: int tcpstates; }; +// Implements the "udp-state" keyword. +class RuleConditionUDPState : public RuleCondition { +public: + explicit RuleConditionUDPState(int arg_states) + { states = arg_states; } + + bool DoMatch(Rule* rule, RuleEndpointState* state, const u_char* data, + int len) override; + + void PrintDebug() override; + +private: + int states; +}; // Implements "ip-options". class RuleConditionIPOptions : public RuleCondition { diff --git a/src/rule-parse.y b/src/rule-parse.y index c99104e0e3..cb555c0c6d 100644 --- a/src/rule-parse.y +++ b/src/rule-parse.y @@ -58,6 +58,7 @@ static uint8_t ip4_mask_to_len(uint32_t mask) %token TOK_SRC_IP %token TOK_SRC_PORT %token TOK_TCP_STATE +%token TOK_UDP_STATE %token TOK_STRING %token TOK_STATE_SYM %token TOK_ACTIVE @@ -251,6 +252,14 @@ rule_attr: current_rule->AddCondition(new zeek::detail::RuleConditionTCPState($2)); } + | TOK_UDP_STATE state_list + { + if ( $2 & zeek::detail::RULE_STATE_ESTABLISHED ) + rules_error("'established' is not a valid 'udp-state'"); + + current_rule->AddCondition(new zeek::detail::RuleConditionUDPState($2)); + } + | TOK_ACTIVE TOK_BOOL { current_rule->SetActiveStatus($2); } ; diff --git a/src/rule-scan.l b/src/rule-scan.l index 0660105513..8cf698563e 100644 --- a/src/rule-scan.l +++ b/src/rule-scan.l @@ -132,6 +132,7 @@ same-ip return TOK_SAME_IP; src-ip return TOK_SRC_IP; src-port return TOK_SRC_PORT; tcp-state return TOK_TCP_STATE; +udp-state return TOK_UDP_STATE; active return TOK_ACTIVE; file-magic { rules_lval.val = zeek::detail::Rule::FILE_MAGIC; return TOK_PATTERN_TYPE; } diff --git a/testing/btest/Baseline/signatures.udp-state/out b/testing/btest/Baseline/signatures.udp-state/out new file mode 100644 index 0000000000..eb4d4bc78a --- /dev/null +++ b/testing/btest/Baseline/signatures.udp-state/out @@ -0,0 +1,10 @@ +signature_match [orig_h=192.168.17.58, orig_p=58755/udp, resp_h=8.8.8.8, resp_p=53/udp] - my_sig_udp_orig +0000 35 5e 01 00 00 01 00 00 00 00 00 00 06 67 6f 6f 5^...... .....goo +0010 67 6c 65 03 63 6f 6d 00 01 01 00 01 gle.com. .... + +signature_match [orig_h=192.168.17.58, orig_p=58755/udp, resp_h=8.8.8.8, resp_p=53/udp] - my_sig_udp_resp +0000 35 5e 81 80 00 01 00 01 00 00 00 00 06 67 6f 6f 5^...... .....goo +0010 67 6c 65 03 63 6f 6d 00 01 01 00 01 c0 0c 01 01 gle.com. ........ +0020 00 01 00 00 54 49 00 13 00 05 69 73 73 75 65 73 ....TI.. ..issues +0030 79 6d 61 6e 74 65 63 2e 63 6f 6d ymantec. com + diff --git a/testing/btest/Baseline/signatures.udp-state/reject b/testing/btest/Baseline/signatures.udp-state/reject new file mode 100644 index 0000000000..b495e79aa4 --- /dev/null +++ b/testing/btest/Baseline/signatures.udp-state/reject @@ -0,0 +1,2 @@ +error: Error in signature (udp-established.sig:5): 'established' is not a valid 'udp-state' + diff --git a/testing/btest/signatures/udp-state.zeek b/testing/btest/signatures/udp-state.zeek new file mode 100644 index 0000000000..13cb3d1b8a --- /dev/null +++ b/testing/btest/signatures/udp-state.zeek @@ -0,0 +1,36 @@ +# @TEST-EXEC: zeek -b -s udp-states.sig -r $TRACES/dns-caa.pcap %INPUT >out +# @TEST-EXEC-FAIL: zeek -b -s udp-established.sig -r $TRACES/dns-caa.pcap %INPUT >reject 2>&1 +# @TEST-EXEC: btest-diff out +# @TEST-EXEC: btest-diff reject + +@TEST-START-FILE udp-states.sig +signature my_sig_udp_orig { + ip-proto == udp + payload /.+/ + udp-state originator + event "my_sig_udp_orig" +} + +signature my_sig_udp_resp { + ip-proto == udp + payload /.+/ + udp-state responder + event "my_sig_udp_resp" +} +@TEST-END-FILE + +@TEST-START-FILE udp-established.sig +signature my_sig_udp_est { + ip-proto == udp + payload /.+/ + udp-state established + event "my_sig_udp_est" +} +@TEST-END-FILE + +event signature_match(state: signature_state, msg: string, data: string) + { + print fmt("signature_match %s - %s", state$conn$id, msg); + local s = split_string(hexdump(data), /\n/); + for ( i in s ) print s[i]; + }