From 3b3c35c866fdacdaefd73a2381398878af12944c Mon Sep 17 00:00:00 2001 From: Anil Mahtani <929854+Anilm3@users.noreply.github.com> Date: Mon, 20 Nov 2023 17:46:25 +0000 Subject: [PATCH] [PoC] Suspicious attacker blocking --- src/collection.cpp | 18 ++++++++------- src/event.cpp | 9 +++++++- src/event.hpp | 1 + src/exclusion/common.hpp | 2 +- src/parser/parser_v2.cpp | 5 ++++- ...1_rule11_rule_blocking_through_filter.yaml | 22 +++++++++++++++++++ .../012_rule11_rule_not_blocking.yaml | 11 ++++++++++ .../rule_filter/unconditional/ruleset.yaml | 15 +++++++++++++ 8 files changed, 72 insertions(+), 11 deletions(-) create mode 100644 validator/tests/exclusions/rule_filter/unconditional/011_rule11_rule_blocking_through_filter.yaml create mode 100644 validator/tests/exclusions/rule_filter/unconditional/012_rule11_rule_not_blocking.yaml diff --git a/src/collection.cpp b/src/collection.cpp index e8c5b9a16..2ff189df6 100644 --- a/src/collection.cpp +++ b/src/collection.cpp @@ -29,16 +29,14 @@ std::optional match_rule(rule *rule, const object_store &store, return std::nullopt; } - bool skip_actions = false; auto exclusion = policy.find(rule); - if (exclusion.mode == exclusion::filter_mode::bypass) { + if (exclusion.mode == exclusion::filter_mode::block) { + DDWAF_DEBUG("Potentially blocking rule '{}'", id); + } else if (exclusion.mode == exclusion::filter_mode::bypass) { DDWAF_DEBUG("Bypassing rule '{}'", id); return std::nullopt; - } - - if (exclusion.mode == exclusion::filter_mode::monitor) { + } else if (exclusion.mode == exclusion::filter_mode::monitor) { DDWAF_DEBUG("Monitoring rule '{}'", id); - skip_actions = true; } DDWAF_DEBUG("Evaluating rule '{}'", id); @@ -54,8 +52,12 @@ std::optional match_rule(rule *rule, const object_store &store, std::optional event; event = rule->match(store, rule_cache, exclusion.objects, dynamic_matchers, deadline); - if (event.has_value() && skip_actions) { - event->skip_actions = true; + if (event.has_value()) { + if (exclusion.mode == exclusion::filter_mode::block) { + event->override_action = "block"; + } else if (exclusion.mode == exclusion::filter_mode::monitor) { + event->skip_actions = true; + } } return event; diff --git a/src/event.cpp b/src/event.cpp index afe8e5cb7..729fcd669 100644 --- a/src/event.cpp +++ b/src/event.cpp @@ -99,7 +99,14 @@ void event_serializer::serialize(const std::vector &events, ddwaf_result ddwaf_object_map_add(&rule_map, "name", to_object(tmp, event.rule->get_name())); const auto &actions = event.rule->get_actions(); - if (!actions.empty()) { + if (!event.override_action.empty()) { + all_actions.emplace(event.override_action); + + ddwaf_object actions_array; + ddwaf_object_array(&actions_array); + ddwaf_object_array_add(&actions_array, to_object(tmp, event.override_action)); + ddwaf_object_map_add(&rule_map, "on_match", &actions_array); + } else if (!actions.empty()) { ddwaf_object actions_array; ddwaf_object_array(&actions_array); if (!event.skip_actions) { diff --git a/src/event.hpp b/src/event.hpp index 4da1a4441..ba190bad2 100644 --- a/src/event.hpp +++ b/src/event.hpp @@ -34,6 +34,7 @@ struct event { std::vector matches; bool ephemeral{false}; bool skip_actions{false}; + std::string override_action{}; }; using optional_event = std::optional; diff --git a/src/exclusion/common.hpp b/src/exclusion/common.hpp index cf76d7701..85656add6 100644 --- a/src/exclusion/common.hpp +++ b/src/exclusion/common.hpp @@ -19,7 +19,7 @@ class rule; namespace exclusion { -enum class filter_mode : uint8_t { none = 0, monitor = 1, bypass = 2 }; +enum class filter_mode : uint8_t { none = 0, monitor = 1, bypass = 2, block = 3 }; struct object_set { std::unordered_set persistent; diff --git a/src/parser/parser_v2.cpp b/src/parser/parser_v2.cpp index d8752e1cc..8b609bfed 100644 --- a/src/parser/parser_v2.cpp +++ b/src/parser/parser_v2.cpp @@ -11,6 +11,7 @@ #include #include "exception.hpp" +#include "exclusion/common.hpp" #include "exclusion/object_filter.hpp" #include "generator/extract_schema.hpp" #include "indexer.hpp" @@ -433,7 +434,9 @@ rule_filter_spec parse_rule_filter( on_match = exclusion::filter_mode::bypass; } else if (on_match_str == "monitor") { on_match = exclusion::filter_mode::monitor; - } else { + } else if (on_match_str == "block") { + on_match = exclusion::filter_mode::block; + }else { throw ddwaf::parsing_error("unsupported on_match value: " + std::string(on_match_str)); } diff --git a/validator/tests/exclusions/rule_filter/unconditional/011_rule11_rule_blocking_through_filter.yaml b/validator/tests/exclusions/rule_filter/unconditional/011_rule11_rule_blocking_through_filter.yaml new file mode 100644 index 000000000..556f33197 --- /dev/null +++ b/validator/tests/exclusions/rule_filter/unconditional/011_rule11_rule_blocking_through_filter.yaml @@ -0,0 +1,22 @@ +{ + name: "Rule blocking through exclusion filter", + runs: [ + { + persistent-input: { + rule11-input: "rule11" + }, + rules: [ + { + 11: [ + { + address: rule11-input, + value: rule11 + } + ] + } + ], + code: match, + actions: ["block"] + } + ] +} diff --git a/validator/tests/exclusions/rule_filter/unconditional/012_rule11_rule_not_blocking.yaml b/validator/tests/exclusions/rule_filter/unconditional/012_rule11_rule_not_blocking.yaml new file mode 100644 index 000000000..3fe811d75 --- /dev/null +++ b/validator/tests/exclusions/rule_filter/unconditional/012_rule11_rule_not_blocking.yaml @@ -0,0 +1,11 @@ +{ + name: "Rule doesn't block due to no match", + runs: [ + { + persistent-input: { + rule11-input: "rule12" + }, + code: ok, + } + ] +} diff --git a/validator/tests/exclusions/rule_filter/unconditional/ruleset.yaml b/validator/tests/exclusions/rule_filter/unconditional/ruleset.yaml index edeaad643..e71f80049 100644 --- a/validator/tests/exclusions/rule_filter/unconditional/ruleset.yaml +++ b/validator/tests/exclusions/rule_filter/unconditional/ruleset.yaml @@ -40,6 +40,10 @@ exclusions: rules_target: - rule_id: "1" on_match: monitor + - id: "9" + rules_target: + - rule_id: "11" + on_match: block rules: - id: "1" @@ -154,3 +158,14 @@ rules: - address: rule10-input regex: rule10 on_match: [ block ] + - id: "11" + name: rule11-block-through-filter + tags: + type: flow11 + category: category11 + conditions: + - operator: match_regex + parameters: + inputs: + - address: rule11-input + regex: rule11