Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions collections/shedowe19/shieldpm.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
## ShieldPM collection

A collection to defend nginx against common attacks:
- [ShieldPM](https://github.com/shedowe19/ShieldPM) parser
- base http scenarios (crawl, 404 scan, bf)
- modsecurity support

## Acquisition template

Example acquisition for this collection:

```yaml
filenames:
- /data/shieldpm/nginx/*.log
labels:
type: shieldpm
---
filenames:
- /data/shieldpm/nginx/*.log
labels:
type: modsecurity
---
listen_addr: 0.0.0.0:7422
appsec_config: crowdsecurity/appsec-default
name: appsec
source: appsec
labels:
type: appsec
```

## Notes
- Depending on your configuration, paths to log files might change
- Please read more at [ShieldPM GitHub](https://github.com/shedowe19/ShieldPM)
21 changes: 21 additions & 0 deletions collections/shedowe19/shieldpm.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
parsers:
- shedowe19/shieldpm-logs
- crowdsecurity/cri-logs
- crowdsecurity/dateparse-enrich
collections:
- crowdsecurity/appsec-virtual-patching
- crowdsecurity/appsec-generic-rules
- crowdsecurity/base-http-scenarios
- crowdsecurity/http-cve
- crowdsecurity/modsecurity
scenarios:
- crowdsecurity/nginx-req-limit-exceeded
description: "ShieldPM support: parser and generic http scenarios"
author: shedowe19
tags:
- linux
- nginx
- nginx-proxy
- shieldpm
- crawl
- scan
107 changes: 107 additions & 0 deletions parsers/s01-parse/shedowe19/shieldpm-logs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
filter: "evt.Parsed.program startsWith 'shieldpm'"
onsuccess: next_stage
name: shedowe19/shieldpm-logs
description: "Parse ShieldPM JSON access logs and error logs"
# ShieldPM uses JSON log format for access logs
nodes:
# JSON Access Log Parser
- filter: "evt.Line contains '{' && evt.Line contains 'remote_addr'"
statics:
- meta: log_type
value: http_access-log
- parsed: time_iso8601
expression: JsonExtract(evt.Line, "time_iso8601")
- target: evt.StrTime
expression: evt.Parsed.time_iso8601
- parsed: remote_addr
expression: JsonExtract(evt.Line, "remote_addr")
- meta: source_ip
expression: evt.Parsed.remote_addr
- parsed: status
expression: JsonExtract(evt.Line, "status")
- meta: http_status
expression: evt.Parsed.status
- parsed: request_uri
expression: JsonExtract(evt.Line, "request_uri")
- meta: http_path
expression: evt.Parsed.request_uri
- parsed: request_method
expression: JsonExtract(evt.Line, "request_method")
- meta: http_verb
expression: evt.Parsed.request_method
- parsed: http_user_agent
expression: JsonExtract(evt.Line, "http_user_agent")
- meta: http_user_agent
expression: evt.Parsed.http_user_agent
- parsed: http_host
expression: JsonExtract(evt.Line, "http_host")
- meta: target_fqdn
expression: evt.Parsed.http_host
- meta: service
value: http
# Traditional Access Log (alog format fallback)
- grok:
pattern: '\[%{HTTPDATE:time_local}\] %{DATA:target_fqdn} %{IPORHOST:remote_addr} %{NUMBER:request_time} "%{WORD:verb} %{DATA:request} HTTP/%{NUMBER:http_version}" %{NUMBER:status} %{NUMBER:body_bytes_sent} %{NUMBER:bytes_sent} %{DATA:http_referer} %{GREEDYDATA:http_user_agent}'
apply_on: message
statics:
- meta: log_type
value: http_access-log
- target: evt.StrTime
expression: evt.Parsed.time_local
- meta: source_ip
expression: evt.Parsed.remote_addr
- meta: http_status
expression: evt.Parsed.status
- meta: http_path
expression: evt.Parsed.request
- meta: http_verb
expression: evt.Parsed.verb
- meta: http_user_agent
expression: evt.Parsed.http_user_agent
- meta: target_fqdn
expression: evt.Parsed.target_fqdn
- meta: service
value: http
# Error Log Parser
- grok:
pattern: '%{NGINXERRTIME:time} \[%{LOGLEVEL:loglevel}\] %{NONNEGINT:pid}#%{NONNEGINT:tid}: (\*%{NONNEGINT:cid} )?%{GREEDYDATA:message}, client: %{IPORHOST:remote_addr}, server: %{DATA:target_fqdn}, request: "%{WORD:verb} ([^/]+)?%{URIPATHPARAM:request}( HTTP/%{NUMBER:http_version})?", host: "%{IPORHOST}(:%{NONNEGINT})?"'
apply_on: message
statics:
- meta: log_type
value: http_error-log
- target: evt.StrTime
expression: evt.Parsed.time
- meta: source_ip
expression: evt.Parsed.remote_addr
- meta: service
value: http
pattern_syntax:
NO_DOUBLE_QUOTE: '[^"]+'
onsuccess: next_stage
nodes:
- filter: "evt.Parsed.message contains 'was not found in'"
pattern_syntax:
USER_NOT_FOUND: 'user "%{NO_DOUBLE_QUOTE:username}" was not found in "%{NO_DOUBLE_QUOTE}"'
grok:
pattern: '%{USER_NOT_FOUND}'
apply_on: message
statics:
- meta: sub_type
value: "auth_fail"
- meta: username
expression: evt.Parsed.username
- filter: "evt.Parsed.message contains 'password mismatch'"
pattern_syntax:
PASSWORD_MISMATCH: 'user "%{NO_DOUBLE_QUOTE:username}": password mismatch'
grok:
pattern: '%{PASSWORD_MISMATCH}'
apply_on: message
statics:
- meta: sub_type
value: "auth_fail"
- meta: username
expression: evt.Parsed.username
- filter: "evt.Parsed.message contains 'limiting requests, excess'"
statics:
- meta: sub_type
value: "req_limit_exceeded"