From 8aa0536eed05701dfeea4211b8c5fc97feb0d10f Mon Sep 17 00:00:00 2001 From: Plague Doctor Date: Thu, 12 Feb 2026 13:11:04 +1100 Subject: [PATCH 1/4] feat(sharry): add Sharry collection with parser and bruteforce detection - Add sharry-logs parser for authentication failures - Add sharry-bf scenario (5 failures in 20s -> 1m ban) - Add collection, parser, and scenario documentation - Add test log samples - Detects: Authentication attempt failure for username X from ip Y --- .tests/sharry-logs/sharry.log | 3 +++ collections/plague-doctor/sharry.md | 19 ++++++++++++++ collections/plague-doctor/sharry.yaml | 10 +++++++ .../s01-parse/plague-doctor/sharry-logs.md | 15 +++++++++++ .../s01-parse/plague-doctor/sharry-logs.yaml | 26 +++++++++++++++++++ scenarios/plague-doctor/sharry-bf.md | 5 ++++ scenarios/plague-doctor/sharry-bf.yaml | 20 ++++++++++++++ 7 files changed, 98 insertions(+) create mode 100644 .tests/sharry-logs/sharry.log create mode 100644 collections/plague-doctor/sharry.md create mode 100644 collections/plague-doctor/sharry.yaml create mode 100644 parsers/s01-parse/plague-doctor/sharry-logs.md create mode 100644 parsers/s01-parse/plague-doctor/sharry-logs.yaml create mode 100644 scenarios/plague-doctor/sharry-bf.md create mode 100644 scenarios/plague-doctor/sharry-bf.yaml diff --git a/.tests/sharry-logs/sharry.log b/.tests/sharry-logs/sharry.log new file mode 100644 index 00000000000..0255fca0dfd --- /dev/null +++ b/.tests/sharry-logs/sharry.log @@ -0,0 +1,3 @@ +2026.02.12 12:50:22:0000 [io-comp...] [INFO ] sharry.restserver.routes.LoginRoutes.makeResponse:232 - Authentication attempt failure for username Thgg from ip 1.136.110.240 +2026.02.12 12:50:25:0000 [io-comp...] [INFO ] sharry.restserver.routes.LoginRoutes.makeResponse:232 - Authentication attempt failure for username Thgg from ip 1.136.110.240 +2026.02.12 12:45:23:0001 [io-comp...] [INFO ] org.http4s.server.middleware.Logger - HTTP/1.1 200 OK diff --git a/collections/plague-doctor/sharry.md b/collections/plague-doctor/sharry.md new file mode 100644 index 00000000000..9871cf9f996 --- /dev/null +++ b/collections/plague-doctor/sharry.md @@ -0,0 +1,19 @@ +# Description + +A collection to defend [Sharry](https://github.com/eikek/sharry) +deployments against common attacks: + +- Sharry parser +- Sharry bruteforce detection + +## Acquisition template + +Example acquisition for this collection: + +```yaml +--- +filenames: + - /var/log/sharry/*.log +labels: + type: sharry +``` diff --git a/collections/plague-doctor/sharry.yaml b/collections/plague-doctor/sharry.yaml new file mode 100644 index 00000000000..681b30292e5 --- /dev/null +++ b/collections/plague-doctor/sharry.yaml @@ -0,0 +1,10 @@ +parsers: + - plague-doctor/sharry-logs +scenarios: + - plague-doctor/sharry-bf +description: "Sharry: parser and brute-force detection" +author: plague-doctor +tags: + - linux + - brute-force + - sharry diff --git a/parsers/s01-parse/plague-doctor/sharry-logs.md b/parsers/s01-parse/plague-doctor/sharry-logs.md new file mode 100644 index 00000000000..361dd914bea --- /dev/null +++ b/parsers/s01-parse/plague-doctor/sharry-logs.md @@ -0,0 +1,15 @@ +# Description + +A parser that will search for unauthorized access to Sharry. + +## Acquisition template + +Example acquisition for this collection: + +```yaml +--- +filenames: + - /var/log/sharry/*.log +labels: + type: sharry +``` diff --git a/parsers/s01-parse/plague-doctor/sharry-logs.yaml b/parsers/s01-parse/plague-doctor/sharry-logs.yaml new file mode 100644 index 00000000000..00f1a4e206c --- /dev/null +++ b/parsers/s01-parse/plague-doctor/sharry-logs.yaml @@ -0,0 +1,26 @@ +onsuccess: next_stage +#debug: true +filter: "Upper(evt.Parsed.program) == 'SHARRY'" +name: plague-doctor/sharry-logs +description: "Parse Sharry logs" +pattern_syntax: + SHARRY_DATE: "%{YEAR}\\.%{MONTHNUM2}\\.%{MONTHDAY} %{TIME}:%{INT}" + SHARRY_THREAD: "\\[%{DATA:thread}\\]" + SHARRY_LEVEL: "\\[%{LOGLEVEL:level}\\s*\\]" + SHARRY_CLASS: "%{JAVACLASS:class}:%{INT:line}" +nodes: + - grok: + pattern: "^%{SHARRY_DATE:timestamp} %{SHARRY_THREAD} %{SHARRY_LEVEL} %{SHARRY_CLASS} - Authentication attempt failure for username %{USERNAME:username} from ip %{IP:source_ip}" + apply_on: message + statics: + - meta: log_type + value: sharry_failed_auth +statics: + - meta: service + value: sharry + - meta: source_ip + expression: "evt.Parsed.source_ip" + - target: evt.StrTime + expression: evt.Parsed.timestamp + - meta: username + expression: "evt.Parsed.username" diff --git a/scenarios/plague-doctor/sharry-bf.md b/scenarios/plague-doctor/sharry-bf.md new file mode 100644 index 00000000000..220546eb217 --- /dev/null +++ b/scenarios/plague-doctor/sharry-bf.md @@ -0,0 +1,5 @@ +# Description + +Detect failed Sharry authentications: + +- 5 failed authentication attempts within 20 second leakspeed diff --git a/scenarios/plague-doctor/sharry-bf.yaml b/scenarios/plague-doctor/sharry-bf.yaml new file mode 100644 index 00000000000..cc7214a1302 --- /dev/null +++ b/scenarios/plague-doctor/sharry-bf.yaml @@ -0,0 +1,20 @@ +# Sharry bruteforce +type: leaky +name: plague-doctor/sharry-bf +description: "Detect Sharry bruteforce attacks" +filter: "evt.Meta.service == 'sharry' && evt.Meta.log_type == 'sharry_failed_auth'" +leakspeed: 20s +capacity: 5 +groupby: evt.Meta.source_ip +blackhole: 1m +reprocess: true +labels: + service: sharry + type: bruteforce + classification: + - attack.T1110 + remediation: true + behavior: http:bruteforce + spoofable: 0 + confidence: 3 + From 105ea9b28724e8ffc1edf2828369dde50bd61896 Mon Sep 17 00:00:00 2001 From: Plague Doctor Date: Thu, 12 Feb 2026 13:18:21 +1100 Subject: [PATCH 2/4] test(sharry): add parser and scenario tests - Add sharry-logs parser tests with assertions - Add sharry-bf scenario tests with 5 authentication failures - Tests verify correct field extraction and scenario triggering --- .tests/sharry-bf/config.yaml | 11 +++++ .tests/sharry-bf/parser.assert | 0 .tests/sharry-bf/scenario.assert | 44 +++++++++++++++++ .tests/sharry-bf/sharry.log | 5 ++ .tests/sharry-logs/config.yaml | 10 ++++ .tests/sharry-logs/parser.assert | 81 ++++++++++++++++++++++++++++++++ 6 files changed, 151 insertions(+) create mode 100644 .tests/sharry-bf/config.yaml create mode 100644 .tests/sharry-bf/parser.assert create mode 100644 .tests/sharry-bf/scenario.assert create mode 100644 .tests/sharry-bf/sharry.log create mode 100644 .tests/sharry-logs/config.yaml create mode 100644 .tests/sharry-logs/parser.assert diff --git a/.tests/sharry-bf/config.yaml b/.tests/sharry-bf/config.yaml new file mode 100644 index 00000000000..fa36d02e88c --- /dev/null +++ b/.tests/sharry-bf/config.yaml @@ -0,0 +1,11 @@ +parsers: + - crowdsecurity/syslog-logs + - crowdsecurity/dateparse-enrich + - ./parsers/s01-parse/plague-doctor/sharry-logs.yaml +scenarios: + - ./scenarios/plague-doctor/sharry-bf.yaml +postoverflows: + - "" +log_file: sharry.log +log_type: sharry +ignore_parsers: true diff --git a/.tests/sharry-bf/parser.assert b/.tests/sharry-bf/parser.assert new file mode 100644 index 00000000000..e69de29bb2d diff --git a/.tests/sharry-bf/scenario.assert b/.tests/sharry-bf/scenario.assert new file mode 100644 index 00000000000..d590ce33c34 --- /dev/null +++ b/.tests/sharry-bf/scenario.assert @@ -0,0 +1,44 @@ +len(results) == 1 +"1.136.110.240" in results[0].Overflow.GetSources() +results[0].Overflow.Sources["1.136.110.240"].IP == "1.136.110.240" +results[0].Overflow.Sources["1.136.110.240"].Range == "" +results[0].Overflow.Sources["1.136.110.240"].GetScope() == "Ip" +results[0].Overflow.Sources["1.136.110.240"].GetValue() == "1.136.110.240" +results[0].Overflow.Alert.Events[0].GetMeta("datasource_path") == "sharry.log" +results[0].Overflow.Alert.Events[0].GetMeta("datasource_type") == "file" +results[0].Overflow.Alert.Events[0].GetMeta("log_type") == "sharry_failed_auth" +results[0].Overflow.Alert.Events[0].GetMeta("service") == "sharry" +results[0].Overflow.Alert.Events[0].GetMeta("source_ip") == "1.136.110.240" +results[0].Overflow.Alert.Events[0].GetMeta("timestamp") == "2026-02-12T01:50:22Z" +results[0].Overflow.Alert.Events[0].GetMeta("username") == "Thgg" +results[0].Overflow.Alert.Events[1].GetMeta("datasource_path") == "sharry.log" +results[0].Overflow.Alert.Events[1].GetMeta("datasource_type") == "file" +results[0].Overflow.Alert.Events[1].GetMeta("log_type") == "sharry_failed_auth" +results[0].Overflow.Alert.Events[1].GetMeta("service") == "sharry" +results[0].Overflow.Alert.Events[1].GetMeta("source_ip") == "1.136.110.240" +results[0].Overflow.Alert.Events[1].GetMeta("timestamp") == "2026-02-12T01:50:25Z" +results[0].Overflow.Alert.Events[1].GetMeta("username") == "Thgg" +results[0].Overflow.Alert.Events[2].GetMeta("datasource_path") == "sharry.log" +results[0].Overflow.Alert.Events[2].GetMeta("datasource_type") == "file" +results[0].Overflow.Alert.Events[2].GetMeta("log_type") == "sharry_failed_auth" +results[0].Overflow.Alert.Events[2].GetMeta("service") == "sharry" +results[0].Overflow.Alert.Events[2].GetMeta("source_ip") == "1.136.110.240" +results[0].Overflow.Alert.Events[2].GetMeta("timestamp") == "2026-02-12T01:50:27Z" +results[0].Overflow.Alert.Events[2].GetMeta("username") == "Thgg" +results[0].Overflow.Alert.Events[3].GetMeta("datasource_path") == "sharry.log" +results[0].Overflow.Alert.Events[3].GetMeta("datasource_type") == "file" +results[0].Overflow.Alert.Events[3].GetMeta("log_type") == "sharry_failed_auth" +results[0].Overflow.Alert.Events[3].GetMeta("service") == "sharry" +results[0].Overflow.Alert.Events[3].GetMeta("source_ip") == "1.136.110.240" +results[0].Overflow.Alert.Events[3].GetMeta("timestamp") == "2026-02-12T01:50:29Z" +results[0].Overflow.Alert.Events[3].GetMeta("username") == "Thgg" +results[0].Overflow.Alert.Events[4].GetMeta("datasource_path") == "sharry.log" +results[0].Overflow.Alert.Events[4].GetMeta("datasource_type") == "file" +results[0].Overflow.Alert.Events[4].GetMeta("log_type") == "sharry_failed_auth" +results[0].Overflow.Alert.Events[4].GetMeta("service") == "sharry" +results[0].Overflow.Alert.Events[4].GetMeta("source_ip") == "1.136.110.240" +results[0].Overflow.Alert.Events[4].GetMeta("timestamp") == "2026-02-12T01:50:31Z" +results[0].Overflow.Alert.Events[4].GetMeta("username") == "Thgg" +results[0].Overflow.Alert.GetScenario() == "plague-doctor/sharry-bf" +results[0].Overflow.Alert.Remediation == true +results[0].Overflow.Alert.GetEventsCount() == 5 diff --git a/.tests/sharry-bf/sharry.log b/.tests/sharry-bf/sharry.log new file mode 100644 index 00000000000..fe8d40ffec1 --- /dev/null +++ b/.tests/sharry-bf/sharry.log @@ -0,0 +1,5 @@ +2026.02.12 12:50:22:0000 [io-comp...] [INFO ] sharry.restserver.routes.LoginRoutes.makeResponse:232 - Authentication attempt failure for username Thgg from ip 1.136.110.240 +2026.02.12 12:50:25:0000 [io-comp...] [INFO ] sharry.restserver.routes.LoginRoutes.makeResponse:232 - Authentication attempt failure for username Thgg from ip 1.136.110.240 +2026.02.12 12:50:27:0000 [io-comp...] [INFO ] sharry.restserver.routes.LoginRoutes.makeResponse:232 - Authentication attempt failure for username Thgg from ip 1.136.110.240 +2026.02.12 12:50:29:0000 [io-comp...] [INFO ] sharry.restserver.routes.LoginRoutes.makeResponse:232 - Authentication attempt failure for username Thgg from ip 1.136.110.240 +2026.02.12 12:50:31:0000 [io-comp...] [INFO ] sharry.restserver.routes.LoginRoutes.makeResponse:232 - Authentication attempt failure for username Thgg from ip 1.136.110.240 diff --git a/.tests/sharry-logs/config.yaml b/.tests/sharry-logs/config.yaml new file mode 100644 index 00000000000..39c76d56f1e --- /dev/null +++ b/.tests/sharry-logs/config.yaml @@ -0,0 +1,10 @@ +parsers: + - crowdsecurity/syslog-logs + - crowdsecurity/dateparse-enrich + - ./parsers/s01-parse/plague-doctor/sharry-logs.yaml +scenarios: + - "" +postoverflows: + - "" +log_file: sharry.log +log_type: sharry diff --git a/.tests/sharry-logs/parser.assert b/.tests/sharry-logs/parser.assert new file mode 100644 index 00000000000..b5d37e0fcab --- /dev/null +++ b/.tests/sharry-logs/parser.assert @@ -0,0 +1,81 @@ +len(results) == 4 +len(results["s00-raw"]["crowdsecurity/non-syslog"]) == 3 +results["s00-raw"]["crowdsecurity/non-syslog"][0].Success == true +results["s00-raw"]["crowdsecurity/non-syslog"][0].Evt.Parsed["message"] == "2026.02.12 12:50:22:0000 [io-comp...] [INFO ] sharry.restserver.routes.LoginRoutes.makeResponse:232 - Authentication attempt failure for username Thgg from ip 1.136.110.240" +results["s00-raw"]["crowdsecurity/non-syslog"][0].Evt.Parsed["program"] == "sharry" +results["s00-raw"]["crowdsecurity/non-syslog"][0].Evt.Meta["datasource_path"] == "sharry.log" +results["s00-raw"]["crowdsecurity/non-syslog"][0].Evt.Meta["datasource_type"] == "file" +results["s00-raw"]["crowdsecurity/non-syslog"][0].Evt.Whitelisted == false +results["s00-raw"]["crowdsecurity/non-syslog"][1].Success == true +results["s00-raw"]["crowdsecurity/non-syslog"][1].Evt.Parsed["message"] == "2026.02.12 12:50:25:0000 [io-comp...] [INFO ] sharry.restserver.routes.LoginRoutes.makeResponse:232 - Authentication attempt failure for username Thgg from ip 1.136.110.240" +results["s00-raw"]["crowdsecurity/non-syslog"][1].Evt.Parsed["program"] == "sharry" +results["s00-raw"]["crowdsecurity/non-syslog"][1].Evt.Meta["datasource_path"] == "sharry.log" +results["s00-raw"]["crowdsecurity/non-syslog"][1].Evt.Meta["datasource_type"] == "file" +results["s00-raw"]["crowdsecurity/non-syslog"][1].Evt.Whitelisted == false +results["s00-raw"]["crowdsecurity/non-syslog"][2].Success == true +results["s00-raw"]["crowdsecurity/non-syslog"][2].Evt.Parsed["message"] == "2026.02.12 12:45:23:0001 [io-comp...] [INFO ] org.http4s.server.middleware.Logger - HTTP/1.1 200 OK" +results["s00-raw"]["crowdsecurity/non-syslog"][2].Evt.Parsed["program"] == "sharry" +results["s00-raw"]["crowdsecurity/non-syslog"][2].Evt.Meta["datasource_path"] == "sharry.log" +results["s00-raw"]["crowdsecurity/non-syslog"][2].Evt.Meta["datasource_type"] == "file" +results["s00-raw"]["crowdsecurity/non-syslog"][2].Evt.Whitelisted == false +len(results["s00-raw"]["crowdsecurity/syslog-logs"]) == 3 +results["s00-raw"]["crowdsecurity/syslog-logs"][0].Success == false +results["s00-raw"]["crowdsecurity/syslog-logs"][1].Success == false +results["s00-raw"]["crowdsecurity/syslog-logs"][2].Success == false +len(results["s01-parse"]["plague-doctor/sharry-logs"]) == 3 +results["s01-parse"]["plague-doctor/sharry-logs"][0].Success == true +results["s01-parse"]["plague-doctor/sharry-logs"][0].Evt.Parsed["message"] == "2026.02.12 12:50:22:0000 [io-comp...] [INFO ] sharry.restserver.routes.LoginRoutes.makeResponse:232 - Authentication attempt failure for username Thgg from ip 1.136.110.240" +results["s01-parse"]["plague-doctor/sharry-logs"][0].Evt.Parsed["program"] == "sharry" +results["s01-parse"]["plague-doctor/sharry-logs"][0].Evt.Parsed["source_ip"] == "1.136.110.240" +results["s01-parse"]["plague-doctor/sharry-logs"][0].Evt.Parsed["timestamp"] == "2026.02.12 12:50:22:0000" +results["s01-parse"]["plague-doctor/sharry-logs"][0].Evt.Parsed["username"] == "Thgg" +results["s01-parse"]["plague-doctor/sharry-logs"][0].Evt.Meta["datasource_path"] == "sharry.log" +results["s01-parse"]["plague-doctor/sharry-logs"][0].Evt.Meta["datasource_type"] == "file" +results["s01-parse"]["plague-doctor/sharry-logs"][0].Evt.Meta["log_type"] == "sharry_failed_auth" +results["s01-parse"]["plague-doctor/sharry-logs"][0].Evt.Meta["service"] == "sharry" +results["s01-parse"]["plague-doctor/sharry-logs"][0].Evt.Meta["source_ip"] == "1.136.110.240" +results["s01-parse"]["plague-doctor/sharry-logs"][0].Evt.Meta["username"] == "Thgg" +results["s01-parse"]["plague-doctor/sharry-logs"][0].Evt.Whitelisted == false +results["s01-parse"]["plague-doctor/sharry-logs"][1].Success == true +results["s01-parse"]["plague-doctor/sharry-logs"][1].Evt.Parsed["message"] == "2026.02.12 12:50:25:0000 [io-comp...] [INFO ] sharry.restserver.routes.LoginRoutes.makeResponse:232 - Authentication attempt failure for username Thgg from ip 1.136.110.240" +results["s01-parse"]["plague-doctor/sharry-logs"][1].Evt.Parsed["program"] == "sharry" +results["s01-parse"]["plague-doctor/sharry-logs"][1].Evt.Parsed["source_ip"] == "1.136.110.240" +results["s01-parse"]["plague-doctor/sharry-logs"][1].Evt.Parsed["timestamp"] == "2026.02.12 12:50:25:0000" +results["s01-parse"]["plague-doctor/sharry-logs"][1].Evt.Parsed["username"] == "Thgg" +results["s01-parse"]["plague-doctor/sharry-logs"][1].Evt.Meta["datasource_path"] == "sharry.log" +results["s01-parse"]["plague-doctor/sharry-logs"][1].Evt.Meta["datasource_type"] == "file" +results["s01-parse"]["plague-doctor/sharry-logs"][1].Evt.Meta["log_type"] == "sharry_failed_auth" +results["s01-parse"]["plague-doctor/sharry-logs"][1].Evt.Meta["service"] == "sharry" +results["s01-parse"]["plague-doctor/sharry-logs"][1].Evt.Meta["source_ip"] == "1.136.110.240" +results["s01-parse"]["plague-doctor/sharry-logs"][1].Evt.Meta["username"] == "Thgg" +results["s01-parse"]["plague-doctor/sharry-logs"][1].Evt.Whitelisted == false +results["s01-parse"]["plague-doctor/sharry-logs"][2].Success == false +len(results["s02-enrich"]["crowdsecurity/dateparse-enrich"]) == 2 +results["s02-enrich"]["crowdsecurity/dateparse-enrich"][0].Success == true +results["s02-enrich"]["crowdsecurity/dateparse-enrich"][0].Evt.Parsed["message"] == "2026.02.12 12:50:22:0000 [io-comp...] [INFO ] sharry.restserver.routes.LoginRoutes.makeResponse:232 - Authentication attempt failure for username Thgg from ip 1.136.110.240" +results["s02-enrich"]["crowdsecurity/dateparse-enrich"][0].Evt.Parsed["program"] == "sharry" +results["s02-enrich"]["crowdsecurity/dateparse-enrich"][0].Evt.Parsed["source_ip"] == "1.136.110.240" +results["s02-enrich"]["crowdsecurity/dateparse-enrich"][0].Evt.Parsed["timestamp"] == "2026.02.12 12:50:22:0000" +results["s02-enrich"]["crowdsecurity/dateparse-enrich"][0].Evt.Parsed["username"] == "Thgg" +results["s02-enrich"]["crowdsecurity/dateparse-enrich"][0].Evt.Meta["datasource_path"] == "sharry.log" +results["s02-enrich"]["crowdsecurity/dateparse-enrich"][0].Evt.Meta["datasource_type"] == "file" +results["s02-enrich"]["crowdsecurity/dateparse-enrich"][0].Evt.Meta["log_type"] == "sharry_failed_auth" +results["s02-enrich"]["crowdsecurity/dateparse-enrich"][0].Evt.Meta["service"] == "sharry" +results["s02-enrich"]["crowdsecurity/dateparse-enrich"][0].Evt.Meta["source_ip"] == "1.136.110.240" +results["s02-enrich"]["crowdsecurity/dateparse-enrich"][0].Evt.Meta["timestamp"] == "2026-02-12T01:50:22Z" +results["s02-enrich"]["crowdsecurity/dateparse-enrich"][0].Evt.Meta["username"] == "Thgg" +results["s02-enrich"]["crowdsecurity/dateparse-enrich"][0].Evt.Whitelisted == false +results["s02-enrich"]["crowdsecurity/dateparse-enrich"][1].Success == true +results["s02-enrich"]["crowdsecurity/dateparse-enrich"][1].Evt.Parsed["message"] == "2026.02.12 12:50:25:0000 [io-comp...] [INFO ] sharry.restserver.routes.LoginRoutes.makeResponse:232 - Authentication attempt failure for username Thgg from ip 1.136.110.240" +results["s02-enrich"]["crowdsecurity/dateparse-enrich"][1].Evt.Parsed["program"] == "sharry" +results["s02-enrich"]["crowdsecurity/dateparse-enrich"][1].Evt.Parsed["source_ip"] == "1.136.110.240" +results["s02-enrich"]["crowdsecurity/dateparse-enrich"][1].Evt.Parsed["timestamp"] == "2026.02.12 12:50:25:0000" +results["s02-enrich"]["crowdsecurity/dateparse-enrich"][1].Evt.Parsed["username"] == "Thgg" +results["s02-enrich"]["crowdsecurity/dateparse-enrich"][1].Evt.Meta["datasource_path"] == "sharry.log" +results["s02-enrich"]["crowdsecurity/dateparse-enrich"][1].Evt.Meta["datasource_type"] == "file" +results["s02-enrich"]["crowdsecurity/dateparse-enrich"][1].Evt.Meta["log_type"] == "sharry_failed_auth" +results["s02-enrich"]["crowdsecurity/dateparse-enrich"][1].Evt.Meta["service"] == "sharry" +results["s02-enrich"]["crowdsecurity/dateparse-enrich"][1].Evt.Meta["source_ip"] == "1.136.110.240" +results["s02-enrich"]["crowdsecurity/dateparse-enrich"][1].Evt.Meta["timestamp"] == "2026-02-12T01:50:25Z" +results["s02-enrich"]["crowdsecurity/dateparse-enrich"][1].Evt.Meta["username"] == "Thgg" +results["s02-enrich"]["crowdsecurity/dateparse-enrich"][1].Evt.Whitelisted == false From f2a5b368d37bde22aa0e27bc33ffe062bf1c1530 Mon Sep 17 00:00:00 2001 From: Plague Doctor Date: Thu, 19 Feb 2026 08:09:18 +1100 Subject: [PATCH 3/4] fix(sharry): fix timestamp parsing and scenario capacity - Add timezone support to parser (UTC+11 for Sharry logs) - Add StrTimeFormat with timezone offset handling - Reduce scenario capacity from 5 to 4 (5 events need capacity 4 to overflow) - Update test assertions to expect +11:00 timezone format Fixes test failures where: 1. Timestamps weren't being parsed correctly (was defaulting to 1970) 2. Scenario wasn't triggering (needed 6 events with capacity 5, only had 5) --- .tests/sharry-bf/scenario.assert | 10 +++++----- .tests/sharry-logs/parser.assert | 4 ++-- parsers/s01-parse/plague-doctor/sharry-logs.yaml | 4 +++- scenarios/plague-doctor/sharry-bf.yaml | 2 +- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/.tests/sharry-bf/scenario.assert b/.tests/sharry-bf/scenario.assert index d590ce33c34..8f68827cbec 100644 --- a/.tests/sharry-bf/scenario.assert +++ b/.tests/sharry-bf/scenario.assert @@ -9,35 +9,35 @@ results[0].Overflow.Alert.Events[0].GetMeta("datasource_type") == "file" results[0].Overflow.Alert.Events[0].GetMeta("log_type") == "sharry_failed_auth" results[0].Overflow.Alert.Events[0].GetMeta("service") == "sharry" results[0].Overflow.Alert.Events[0].GetMeta("source_ip") == "1.136.110.240" -results[0].Overflow.Alert.Events[0].GetMeta("timestamp") == "2026-02-12T01:50:22Z" +results[0].Overflow.Alert.Events[0].GetMeta("timestamp") == "2026-02-12T12:50:22+11:00" results[0].Overflow.Alert.Events[0].GetMeta("username") == "Thgg" results[0].Overflow.Alert.Events[1].GetMeta("datasource_path") == "sharry.log" results[0].Overflow.Alert.Events[1].GetMeta("datasource_type") == "file" results[0].Overflow.Alert.Events[1].GetMeta("log_type") == "sharry_failed_auth" results[0].Overflow.Alert.Events[1].GetMeta("service") == "sharry" results[0].Overflow.Alert.Events[1].GetMeta("source_ip") == "1.136.110.240" -results[0].Overflow.Alert.Events[1].GetMeta("timestamp") == "2026-02-12T01:50:25Z" +results[0].Overflow.Alert.Events[1].GetMeta("timestamp") == "2026-02-12T12:50:25+11:00" results[0].Overflow.Alert.Events[1].GetMeta("username") == "Thgg" results[0].Overflow.Alert.Events[2].GetMeta("datasource_path") == "sharry.log" results[0].Overflow.Alert.Events[2].GetMeta("datasource_type") == "file" results[0].Overflow.Alert.Events[2].GetMeta("log_type") == "sharry_failed_auth" results[0].Overflow.Alert.Events[2].GetMeta("service") == "sharry" results[0].Overflow.Alert.Events[2].GetMeta("source_ip") == "1.136.110.240" -results[0].Overflow.Alert.Events[2].GetMeta("timestamp") == "2026-02-12T01:50:27Z" +results[0].Overflow.Alert.Events[2].GetMeta("timestamp") == "2026-02-12T12:50:27+11:00" results[0].Overflow.Alert.Events[2].GetMeta("username") == "Thgg" results[0].Overflow.Alert.Events[3].GetMeta("datasource_path") == "sharry.log" results[0].Overflow.Alert.Events[3].GetMeta("datasource_type") == "file" results[0].Overflow.Alert.Events[3].GetMeta("log_type") == "sharry_failed_auth" results[0].Overflow.Alert.Events[3].GetMeta("service") == "sharry" results[0].Overflow.Alert.Events[3].GetMeta("source_ip") == "1.136.110.240" -results[0].Overflow.Alert.Events[3].GetMeta("timestamp") == "2026-02-12T01:50:29Z" +results[0].Overflow.Alert.Events[3].GetMeta("timestamp") == "2026-02-12T12:50:29+11:00" results[0].Overflow.Alert.Events[3].GetMeta("username") == "Thgg" results[0].Overflow.Alert.Events[4].GetMeta("datasource_path") == "sharry.log" results[0].Overflow.Alert.Events[4].GetMeta("datasource_type") == "file" results[0].Overflow.Alert.Events[4].GetMeta("log_type") == "sharry_failed_auth" results[0].Overflow.Alert.Events[4].GetMeta("service") == "sharry" results[0].Overflow.Alert.Events[4].GetMeta("source_ip") == "1.136.110.240" -results[0].Overflow.Alert.Events[4].GetMeta("timestamp") == "2026-02-12T01:50:31Z" +results[0].Overflow.Alert.Events[4].GetMeta("timestamp") == "2026-02-12T12:50:31+11:00" results[0].Overflow.Alert.Events[4].GetMeta("username") == "Thgg" results[0].Overflow.Alert.GetScenario() == "plague-doctor/sharry-bf" results[0].Overflow.Alert.Remediation == true diff --git a/.tests/sharry-logs/parser.assert b/.tests/sharry-logs/parser.assert index b5d37e0fcab..2b5e6b59a8e 100644 --- a/.tests/sharry-logs/parser.assert +++ b/.tests/sharry-logs/parser.assert @@ -62,7 +62,7 @@ results["s02-enrich"]["crowdsecurity/dateparse-enrich"][0].Evt.Meta["datasource_ results["s02-enrich"]["crowdsecurity/dateparse-enrich"][0].Evt.Meta["log_type"] == "sharry_failed_auth" results["s02-enrich"]["crowdsecurity/dateparse-enrich"][0].Evt.Meta["service"] == "sharry" results["s02-enrich"]["crowdsecurity/dateparse-enrich"][0].Evt.Meta["source_ip"] == "1.136.110.240" -results["s02-enrich"]["crowdsecurity/dateparse-enrich"][0].Evt.Meta["timestamp"] == "2026-02-12T01:50:22Z" +results["s02-enrich"]["crowdsecurity/dateparse-enrich"][0].Evt.Meta["timestamp"] == "2026-02-12T12:50:22+11:00" results["s02-enrich"]["crowdsecurity/dateparse-enrich"][0].Evt.Meta["username"] == "Thgg" results["s02-enrich"]["crowdsecurity/dateparse-enrich"][0].Evt.Whitelisted == false results["s02-enrich"]["crowdsecurity/dateparse-enrich"][1].Success == true @@ -76,6 +76,6 @@ results["s02-enrich"]["crowdsecurity/dateparse-enrich"][1].Evt.Meta["datasource_ results["s02-enrich"]["crowdsecurity/dateparse-enrich"][1].Evt.Meta["log_type"] == "sharry_failed_auth" results["s02-enrich"]["crowdsecurity/dateparse-enrich"][1].Evt.Meta["service"] == "sharry" results["s02-enrich"]["crowdsecurity/dateparse-enrich"][1].Evt.Meta["source_ip"] == "1.136.110.240" -results["s02-enrich"]["crowdsecurity/dateparse-enrich"][1].Evt.Meta["timestamp"] == "2026-02-12T01:50:25Z" +results["s02-enrich"]["crowdsecurity/dateparse-enrich"][1].Evt.Meta["timestamp"] == "2026-02-12T12:50:25+11:00" results["s02-enrich"]["crowdsecurity/dateparse-enrich"][1].Evt.Meta["username"] == "Thgg" results["s02-enrich"]["crowdsecurity/dateparse-enrich"][1].Evt.Whitelisted == false diff --git a/parsers/s01-parse/plague-doctor/sharry-logs.yaml b/parsers/s01-parse/plague-doctor/sharry-logs.yaml index 00f1a4e206c..796b2bd3fca 100644 --- a/parsers/s01-parse/plague-doctor/sharry-logs.yaml +++ b/parsers/s01-parse/plague-doctor/sharry-logs.yaml @@ -20,7 +20,9 @@ statics: value: sharry - meta: source_ip expression: "evt.Parsed.source_ip" + - target: evt.StrTimeFormat + value: "2006.01.02 15:04:05:0000 -0700" - target: evt.StrTime - expression: evt.Parsed.timestamp + expression: evt.Parsed.timestamp + " +1100" - meta: username expression: "evt.Parsed.username" diff --git a/scenarios/plague-doctor/sharry-bf.yaml b/scenarios/plague-doctor/sharry-bf.yaml index cc7214a1302..0cc8056dd58 100644 --- a/scenarios/plague-doctor/sharry-bf.yaml +++ b/scenarios/plague-doctor/sharry-bf.yaml @@ -4,7 +4,7 @@ name: plague-doctor/sharry-bf description: "Detect Sharry bruteforce attacks" filter: "evt.Meta.service == 'sharry' && evt.Meta.log_type == 'sharry_failed_auth'" leakspeed: 20s -capacity: 5 +capacity: 4 groupby: evt.Meta.source_ip blackhole: 1m reprocess: true From 57a3bed95411b7de097f0a5c06fd15329b3c6f4b Mon Sep 17 00:00:00 2001 From: Plague Doctor Date: Tue, 17 Mar 2026 08:45:59 +1100 Subject: [PATCH 4/4] fix(sharry): use UTC timezone instead of hardcoded +1100 Replace hardcoded +1100 timezone offset with +0000 (UTC) since Sharry logs don't include timezone information. This follows the standard approach for logs without explicit timezone data. --- parsers/s01-parse/plague-doctor/sharry-logs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parsers/s01-parse/plague-doctor/sharry-logs.yaml b/parsers/s01-parse/plague-doctor/sharry-logs.yaml index 796b2bd3fca..b7af53750a3 100644 --- a/parsers/s01-parse/plague-doctor/sharry-logs.yaml +++ b/parsers/s01-parse/plague-doctor/sharry-logs.yaml @@ -23,6 +23,6 @@ statics: - target: evt.StrTimeFormat value: "2006.01.02 15:04:05:0000 -0700" - target: evt.StrTime - expression: evt.Parsed.timestamp + " +1100" + expression: evt.Parsed.timestamp + " +0000" - meta: username expression: "evt.Parsed.username"