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.
This commit is contained in:
Jon Siwek 2020-10-09 13:43:17 -07:00
parent 7556beac20
commit 5904d0708f
7 changed files with 97 additions and 0 deletions

View file

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

View file

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

View file

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

View file

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

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