Merge remote-tracking branch 'origin/topic/jsiwek/gh-779-udp-state-sig'

* origin/topic/jsiwek/gh-779-udp-state-sig:
  GH-779: Add "udp-state" signature condition
  Rename RuleConditionTCPState::TCPState enum values
  Rename signature parser tokens to not be TCP-specific
This commit is contained in:
Jon Siwek 2020-10-12 11:15:29 -07:00
commit b73cc816e9
11 changed files with 141 additions and 28 deletions

13
CHANGES
View file

@ -1,4 +1,17 @@
3.3.0-dev.381 | 2020-10-12 11:15:29 -0700
* GH-779: Add "udp-state" signature condition (Jon Siwek, Corelight)
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.
* Rename RuleConditionTCPState::TCPState enum values (Jon Siwek, Corelight)
* Rename "tcp-state" signature parser tokens to not be TCP-specific (Jon Siwek, Corelight)
3.3.0-dev.377 | 2020-10-08 12:07:42 -0700 3.3.0-dev.377 | 2020-10-08 12:07:42 -0700
* GH-1200: ignore a maybe-uninitialized warning (Jon Siwek, Corelight) * GH-1200: ignore a maybe-uninitialized warning (Jon Siwek, Corelight)

3
NEWS
View file

@ -34,6 +34,9 @@ New Functionality
See https://docs.zeek.org/en/master/frameworks/logging.html#filter-log-records See https://docs.zeek.org/en/master/frameworks/logging.html#filter-log-records
for more details. for more details.
- Added a ``udp-state`` signature condition to enforce matching against
either "originator" or "responder" flow direction of UDP packets.
Changed Functionality Changed Functionality
--------------------- ---------------------

View file

@ -1 +1 @@
3.3.0-dev.377 3.3.0-dev.381

2
doc

@ -1 +1 @@
Subproject commit 2960bd2ee131e1c565da3e02983bbe4b719bc607 Subproject commit fd3e22bf5efc42a572e83346031aec4493b3c803

View file

@ -32,16 +32,16 @@ bool RuleConditionTCPState::DoMatch(Rule* rule, RuleEndpointState* state,
auto* ta = static_cast<analyzer::tcp::TCP_Analyzer*>(root); auto* ta = static_cast<analyzer::tcp::TCP_Analyzer*>(root);
if ( tcpstates & STATE_STATELESS ) if ( tcpstates & RULE_STATE_STATELESS )
return true; return true;
if ( (tcpstates & STATE_ORIG) && ! state->IsOrig() ) if ( (tcpstates & RULE_STATE_ORIG) && ! state->IsOrig() )
return false; return false;
if ( (tcpstates & STATE_RESP) && state->IsOrig() ) if ( (tcpstates & RULE_STATE_RESP) && state->IsOrig() )
return false; return false;
if ( (tcpstates & STATE_ESTABLISHED ) && if ( (tcpstates & RULE_STATE_ESTABLISHED ) &&
! (is_established(ta->Orig()) && ! (is_established(ta->Orig()) &&
is_established(ta->Resp()))) is_established(ta->Resp())))
return false; return false;
@ -54,6 +54,31 @@ void RuleConditionTCPState::PrintDebug()
fprintf(stderr, " RuleConditionTCPState: 0x%x\n", tcpstates); 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() void RuleConditionIPOptions::PrintDebug()
{ {
fprintf(stderr, " RuleConditionIPOptions: 0x%x\n", options); fprintf(stderr, " RuleConditionIPOptions: 0x%x\n", options);

View file

@ -22,16 +22,16 @@ public:
virtual void PrintDebug() = 0; 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. // Implements the "tcp-state" keyword.
class RuleConditionTCPState : public RuleCondition { class RuleConditionTCPState : public RuleCondition {
public: public:
enum TCPState {
STATE_ESTABLISHED = 1,
STATE_ORIG = 2,
STATE_RESP = 4,
STATE_STATELESS = 8
};
explicit RuleConditionTCPState(int arg_tcpstates) explicit RuleConditionTCPState(int arg_tcpstates)
{ tcpstates = arg_tcpstates; } { tcpstates = arg_tcpstates; }
@ -46,6 +46,20 @@ private:
int tcpstates; 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". // Implements "ip-options".
class RuleConditionIPOptions : public RuleCondition { class RuleConditionIPOptions : public RuleCondition {

View file

@ -58,15 +58,16 @@ static uint8_t ip4_mask_to_len(uint32_t mask)
%token TOK_SRC_IP %token TOK_SRC_IP
%token TOK_SRC_PORT %token TOK_SRC_PORT
%token TOK_TCP_STATE %token TOK_TCP_STATE
%token TOK_UDP_STATE
%token TOK_STRING %token TOK_STRING
%token TOK_TCP_STATE_SYM %token TOK_STATE_SYM
%token TOK_ACTIVE %token TOK_ACTIVE
%token TOK_BOOL %token TOK_BOOL
%token TOK_POLICY_SYMBOL %token TOK_POLICY_SYMBOL
%type <str> TOK_STRING TOK_IDENT TOK_POLICY_SYMBOL TOK_PATTERN pattern string %type <str> TOK_STRING TOK_IDENT TOK_POLICY_SYMBOL TOK_PATTERN pattern string
%type <val> TOK_INT TOK_TCP_STATE_SYM TOK_IP_OPTION_SYM TOK_COMP %type <val> TOK_INT TOK_STATE_SYM TOK_IP_OPTION_SYM TOK_COMP
%type <val> integer ipoption_list tcpstate_list opt_strength %type <val> integer ipoption_list state_list opt_strength
%type <rule> rule %type <rule> rule
%type <bl> TOK_BOOL opt_negate %type <bl> TOK_BOOL opt_negate
%type <hdr_test> hdr_expr %type <hdr_test> hdr_expr
@ -246,11 +247,19 @@ rule_attr:
(zeek::detail::RuleHdrTest::Comp) $2, $3)); (zeek::detail::RuleHdrTest::Comp) $2, $3));
} }
| TOK_TCP_STATE tcpstate_list | TOK_TCP_STATE state_list
{ {
current_rule->AddCondition(new zeek::detail::RuleConditionTCPState($2)); 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 | TOK_ACTIVE TOK_BOOL
{ current_rule->SetActiveStatus($2); } { current_rule->SetActiveStatus($2); }
; ;
@ -382,10 +391,10 @@ ipoption_list:
{ $$ = $1; } { $$ = $1; }
; ;
tcpstate_list: state_list:
tcpstate_list ',' TOK_TCP_STATE_SYM state_list ',' TOK_STATE_SYM
{ $$ = $1 | $3; } { $$ = $1 | $3; }
| TOK_TCP_STATE_SYM | TOK_STATE_SYM
{ $$ = $1; } { $$ = $1; }
; ;

View file

@ -75,23 +75,23 @@ true { rules_lval.val = true; return TOK_BOOL; }
false { rules_lval.val = false; return TOK_BOOL; } false { rules_lval.val = false; return TOK_BOOL; }
established { established {
rules_lval.val = zeek::detail::RuleConditionTCPState::STATE_ESTABLISHED; rules_lval.val = zeek::detail::RULE_STATE_ESTABLISHED;
return TOK_TCP_STATE_SYM; return TOK_STATE_SYM;
} }
originator { originator {
rules_lval.val = zeek::detail::RuleConditionTCPState::STATE_ORIG; rules_lval.val = zeek::detail::RULE_STATE_ORIG;
return TOK_TCP_STATE_SYM; return TOK_STATE_SYM;
} }
responder { responder {
rules_lval.val = zeek::detail::RuleConditionTCPState::STATE_RESP; rules_lval.val = zeek::detail::RULE_STATE_RESP;
return TOK_TCP_STATE_SYM; return TOK_STATE_SYM;
} }
stateless { stateless {
rules_lval.val = zeek::detail::RuleConditionTCPState::STATE_STATELESS; rules_lval.val = zeek::detail::RULE_STATE_STATELESS;
return TOK_TCP_STATE_SYM; return TOK_STATE_SYM;
} }
lsrr { lsrr {
@ -132,6 +132,7 @@ same-ip return TOK_SAME_IP;
src-ip return TOK_SRC_IP; src-ip return TOK_SRC_IP;
src-port return TOK_SRC_PORT; src-port return TOK_SRC_PORT;
tcp-state return TOK_TCP_STATE; tcp-state return TOK_TCP_STATE;
udp-state return TOK_UDP_STATE;
active return TOK_ACTIVE; active return TOK_ACTIVE;
file-magic { rules_lval.val = zeek::detail::Rule::FILE_MAGIC; return TOK_PATTERN_TYPE; } file-magic { rules_lval.val = zeek::detail::Rule::FILE_MAGIC; return TOK_PATTERN_TYPE; }

View file

@ -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

View file

@ -0,0 +1,2 @@
error: Error in signature (udp-established.sig:5): 'established' is not a valid 'udp-state'

View file

@ -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];
}