crowdsecurity / crowdsec

CrowdSec - the open-source and participative security solution offering crowdsourced protection against malicious IPs and access to the most advanced real-world CTI.
https://crowdsec.net
MIT License
9.01k stars 467 forks source link

http-probing doesn't trigger #3164

Closed azertylr closed 3 months ago

azertylr commented 3 months ago

What happened?

Hello,

I've just installed crowdsec with Caddy 2.8.4 and I don't manage to make it works properly (I used to have nginx and it was fine)

When I generate several 403 error from a client, http-probing is not triggered.

What did you expect to happen?

http-probing triggered when I generate 10* 404 or 403 errors in 10s with the same device

How can we reproduce it (as minimally and precisely as possible)?

install caddy 2.8.4 + crowdsec with the config below that request a 403 error

Anything else we need to know?

Caddy 2.8.4 with https://github.com/hslatman/caddy-crowdsec-bouncer

I tried to trigger authelia-bf and it works. The ip is blocked.

Crowdsec version

```console $ cscli version version: v1.6.2-16bfab86 Codename: alphaga BuildDate: 2024-06-05_14:25:55 GoVersion: 1.22.3 Platform: docker libre2: C++ User-Agent: crowdsec/v1.6.2-16bfab86-docker Constraint_parser: >= 1.0, <= 3.0 Constraint_scenario: >= 1.0, <= 3.0 Constraint_api: v1 Constraint_acquis: >= 1.0, < 2.0 ```

OS version

```console NAME="Alpine Linux" ID=alpine VERSION_ID=3.20.0 PRETTY_NAME="Alpine Linux v3.20" HOME_URL="https://alpinelinux.org/" BUG_REPORT_URL="https://gitlab.alpinelinux.org/alpine/aports/-/issues"

Enabled collections and parsers

```console $ cscli hub list -o raw # paste output here ```

Acquisition config

```console # On Linux: $ cat /etc/crowdsec/acquis.yaml /etc/crowdsec/acquis.d/* filename: /var/log/access.log labels: type: apache2 --- filename: /var/log/authelia.log labels: type: authelia --- filename: /var/log/vaultwarden.log labels: type: vaultwarden

Config show

```console $ cscli config show Global: - Configuration Folder : /etc/crowdsec - Data Folder : /var/lib/crowdsec/data - Hub Folder : /etc/crowdsec/hub - Simulation File : /etc/crowdsec/simulation.yaml - Log Folder : /var/log - Log level : info - Log Media : stdout Crowdsec: - Acquisition File : /etc/crowdsec/acquis.yaml - Parsers routines : 1 - Acquisition Folder : /etc/crowdsec/acquis.d cscli: - Output : human - Hub Branch : API Client: - URL : http://0.0.0.0:8080/ - Login : vm - Credentials File : /etc/crowdsec/local_api_credentials.yaml Local API Server: - Listen URL : 0.0.0.0:8080 - Listen Socket : - Profile File : /etc/crowdsec/profiles.yaml - Trusted IPs: - 127.0.0.1 - ::1 - Database: - Type : sqlite - Path : /var/lib/crowdsec/data/crowdsec.db - Flush age : 7d - Flush size : 5000 ```

Prometheus metrics

```console $ cscli metrics # paste output here ```

Related custom configs versions (if applicable) : notification plugins, custom scenarios, parsers etc.

crowdsec log

``` time="2024-08-05T20:00:54Z" level=debug msg="dbg(result=true): evt.Meta.service == 'http' && evt.Meta.http_status in ['404', '403', '400'] && evt.Parsed.static_ressource == 'false'" cfg=purple-moon name=crowdsecurity/http-probing time="2024-08-05T20:00:54Z" level=debug msg=" [== 'http'] \"http\" == \"http\" -> [true]" cfg=purple-moon name=crowdsecurity/http-probing time="2024-08-05T20:00:54Z" level=debug msg=" [&&] AND -> true" cfg=purple-moon name=crowdsecurity/http-probing time="2024-08-05T20:00:54Z" level=debug msg=" [in ['404', '403', '400']] \"403\" in map[400:{} 403:{} 404:{}] -> [true]" cfg=purple-moon name=crowdsecurity/http-probing time="2024-08-05T20:00:54Z" level=debug msg=" [== 'false'] \"false\" == \"false\" -> true" cfg=purple-moon name=crowdsecurity/http-probing time="2024-08-05T20:00:54Z" level=debug msg="dbg(result=x.x.x.x/): evt.Meta.source_ip + '/' + evt.Parsed.target_fqdn" cfg=purple-moon name=crowdsecurity/http-probing time="2024-08-05T20:00:54Z" level=debug msg="Creating Live bucket" cfg=purple-moon name=crowdsecurity/http-probing time="2024-08-05T20:00:54Z" level=debug msg="Leaky routine starting, lifetime : 18m20s" bucket_id=dry-snow cfg=purple-moon name=crowdsecurity/http-probing partition=3671c134e830f40dab5b16ed453aa1a1fd52413c time="2024-08-05T20:00:54Z" level=debug msg="Created new bucket 3671c134e830f40dab5b16ed453aa1a1fd52413c" cfg=purple-moon name=crowdsecurity/http-probing time="2024-08-05T20:00:54Z" level=debug msg="bucket 'crowdsecurity/http-probing' is poured" cfg=purple-moon name=crowdsecurity/http-probing time="2024-08-05T20:00:54Z" level=debug msg="Uniq(/) : ok" bucket_id=dry-snow cfg=purple-moon name=crowdsecurity/http-probing partition=3671c134e830f40dab5b16ed453aa1a1fd52413c time="2024-08-05T20:00:54Z" level=debug msg="dbg(result=true): evt.Meta.service == 'http' && evt.Meta.http_status in ['404', '403', '400'] && evt.Parsed.static_ressource == 'false'" cfg=purple-moon name=crowdsecurity/http-probing time="2024-08-05T20:00:54Z" level=debug msg=" [== 'http'] \"http\" == \"http\" -> [true]" cfg=purple-moon name=crowdsecurity/http-probing time="2024-08-05T20:00:54Z" level=debug msg=" [&&] AND -> true" cfg=purple-moon name=crowdsecurity/http-probing time="2024-08-05T20:00:54Z" level=debug msg=" [in ['404', '403', '400']] \"403\" in map[400:{} 403:{} 404:{}] -> [true]" cfg=purple-moon name=crowdsecurity/http-probing time="2024-08-05T20:00:54Z" level=debug msg=" [== 'false'] \"false\" == \"false\" -> true" cfg=purple-moon name=crowdsecurity/http-probing time="2024-08-05T20:00:54Z" level=debug msg="dbg(result=x.x.x.x/): evt.Meta.source_ip + '/' + evt.Parsed.target_fqdn" cfg=purple-moon name=crowdsecurity/http-probing time="2024-08-05T20:00:54Z" level=debug msg="Creating Live bucket" cfg=purple-moon name=crowdsecurity/http-probing time="2024-08-05T20:00:54Z" level=debug msg="Leaky routine starting, lifetime : 18m20s" bucket_id=dry-snow cfg=purple-moon name=crowdsecurity/http-probing partition=3671c134e830f40dab5b16ed453aa1a1fd52413c time="2024-08-05T20:00:54Z" level=debug msg="Created new bucket 3671c134e830f40dab5b16ed453aa1a1fd52413c" cfg=purple-moon name=crowdsecurity/http-probing time="2024-08-05T20:00:54Z" level=debug msg="bucket 'crowdsecurity/http-probing' is poured" cfg=purple-moon name=crowdsecurity/http-probing time="2024-08-05T20:00:54Z" level=debug msg="Uniq(/) : ok" bucket_id=dry-snow cfg=purple-moon name=crowdsecurity/http-probing partition=3671c134e830f40dab5b16ed453aa1a1fd52413c time="2024-08-05T20:01:42Z" level=debug msg=" [== 'http'] \"http\" == \"http\" -> [true]" cfg=purple-moon name=crowdsecurity/http-probing time="2024-08-05T20:01:42Z" level=debug msg=" [&&] AND -> true" cfg=purple-moon name=crowdsecurity/http-probing time="2024-08-05T20:01:42Z" level=debug msg=" [in ['404', '403', '400']] \"403\" in map[400:{} 403:{} 404:{}] -> [true]" cfg=purple-moon name=crowdsecurity/http-probing time="2024-08-05T20:01:42Z" level=debug msg=" [== 'false'] \"false\" == \"false\" -> true" cfg=purple-moon name=crowdsecurity/http-probing time="2024-08-05T20:01:42Z" level=debug msg="dbg(result=x.x.x.x/): evt.Meta.source_ip + '/' + evt.Parsed.target_fqdn" cfg=purple-moon name=crowdsecurity/http-probing time="2024-08-05T20:01:42Z" level=debug msg="bucket 'crowdsecurity/http-probing' is poured" cfg=purple-moon name=crowdsecurity/http-probing time="2024-08-05T20:01:42Z" level=debug msg="Uniq(/) : ko, discard event" bucket_id=dry-snow cfg=purple-moon name=crowdsecurity/http-probing partition=3671c134e830f40dab5b16ed453aa1a1fd52413c ```
``` 4be1d10e0537:/# cscli metrics Acquisition Metrics: ╭──────────────────────────┬────────────┬──────────────┬────────────────┬────────────────────────┬───────────────────╮ │ Source │ Lines read │ Lines parsed │ Lines unparsed │ Lines poured to bucket │ Lines whitelisted │ ├──────────────────────────┼────────────┼──────────────┼────────────────┼────────────────────────┼───────────────────┤ │ file:/var/log/access.log │ 24 │ 24 │ - │ 17 │ - │ ╰──────────────────────────┴────────────┴──────────────┴────────────────┴────────────────────────┴───────────────────╯ Local API Alerts: ╭──────────────────────────┬───────╮ │ Reason │ Count │ ├──────────────────────────┼───────┤ │ LePresidente/authelia-bf │ 3 │ │ manual 'ban' from 'vm' │ 1 │ ╰──────────────────────────┴───────╯ Local API Decisions: ╭─────────────────────────────────┬────────┬────────┬───────╮ │ Reason │ Origin │ Action │ Count │ ├─────────────────────────────────┼────────┼────────┼───────┤ │ manual 'ban' from 'vm' │ cscli │ ban │ 1 │ │ LePresidente/authelia-bf │ CAPI │ ban │ 3 │ │ crowdsecurity/ssh-bf │ CAPI │ ban │ 6193 │ │ crowdsecurity/ssh-cve-2024-6387 │ CAPI │ ban │ 41 │ │ crowdsecurity/ssh-slow-bf │ CAPI │ ban │ 8763 │ ╰─────────────────────────────────┴────────┴────────┴───────╯ Local API Metrics: ╭──────────────────────┬────────┬──────╮ │ Route │ Method │ Hits │ ├──────────────────────┼────────┼──────┤ │ /v1/decisions/stream │ GET │ 32 │ │ /v1/heartbeat │ GET │ 7 │ │ /v1/watchers/login │ POST │ 1 │ ╰──────────────────────┴────────┴──────╯ Local API Bouncers Metrics: ╭─────────┬──────────────────────┬────────┬──────╮ │ Bouncer │ Route │ Method │ Hits │ ├─────────┼──────────────────────┼────────┼──────┤ │ caddy │ /v1/decisions/stream │ GET │ 32 │ ╰─────────┴──────────────────────┴────────┴──────╯ Local API Machines Metrics: ╭─────────┬───────────────┬────────┬──────╮ │ Machine │ Route │ Method │ Hits │ ├─────────┼───────────────┼────────┼──────┤ │ vm │ /v1/heartbeat │ GET │ 7 │ ╰─────────┴───────────────┴────────┴──────╯ Parser Metrics: ╭──────────────────────────────────┬──────┬────────┬──────────╮ │ Parsers │ Hits │ Parsed │ Unparsed │ ├──────────────────────────────────┼──────┼────────┼──────────┤ │ child-crowdsecurity/apache2-logs │ 24 │ 24 │ - │ │ child-crowdsecurity/http-logs │ 72 │ 48 │ 24 │ │ crowdsecurity/apache2-logs │ 24 │ 24 │ - │ │ crowdsecurity/dateparse-enrich │ 24 │ 24 │ - │ │ crowdsecurity/geoip-enrich │ 24 │ 24 │ - │ │ crowdsecurity/http-logs │ 24 │ 24 │ - │ │ crowdsecurity/non-syslog │ 24 │ 24 │ - │ │ crowdsecurity/whitelists │ 24 │ 24 │ - │ ╰──────────────────────────────────┴──────┴────────┴──────────╯ Scenario Metrics: ╭──────────────────────────────────────┬───────────────┬───────────┬──────────────┬────────┬─────────╮ │ Scenario │ Current Count │ Overflows │ Instantiated │ Poured │ Expired │ ├──────────────────────────────────────┼───────────────┼───────────┼──────────────┼────────┼─────────┤ │ crowdsecurity/http-crawl-non_statics │ 1 │ - │ 10 │ 10 │ 9 │ │ crowdsecurity/http-dos-swithcing-ua │ 1 │ - │ 5 │ 5 │ 4 │ │ crowdsecurity/http-probing │ 1 │ - │ 1 │ 1 │ - │ ╰──────────────────────────────────────┴───────────────┴───────────┴──────────────┴────────┴─────────╯ Whitelist Metrics: ╭──────────────────────────┬─────────────────────────────┬──────┬─────────────╮ │ Whitelist │ Reason │ Hits │ Whitelisted │ ├──────────────────────────┼─────────────────────────────┼──────┼─────────────┤ │ crowdsecurity/whitelists │ private ipv4/ipv6 ip/ranges │ 24 │ - │ ╰──────────────────────────┴─────────────────────────────┴──────┴─────────────╯ ```
github-actions[bot] commented 3 months ago

@azertylr: Thanks for opening an issue, it is currently awaiting triage.

In the meantime, you can:

  1. Check Crowdsec Documentation to see if your issue can be self resolved.
  2. You can also join our Discord.
  3. Check Releases to make sure your agent is on the latest version.
Details I am a bot created to help the [crowdsecurity](https://github.com/crowdsecurity) developers manage community feedback and contributions. You can check out my [manifest file](https://github.com/crowdsecurity/crowdsec/blob/master/.github/governance.yml) to understand my behavior and what I can do. If you want to use this for your project, you can check out the [BirthdayResearch/oss-governance-bot](https://github.com/BirthdayResearch/oss-governance-bot) repository.
LaurenceJJones commented 3 months ago

Where have you configured caddy to log?

Because it seems there is no acquisition configuration for caddy logs, the only webserver I see is apache2

azertylr commented 3 months ago

I'm using github.com/caddyserver/transform-encoder to transform Caddy log as apache2 log

I've tried crowdsec caddy parser but I have this problem https://github.com/crowdsecurity/crowdsec/issues/2921

LaurenceJJones commented 3 months ago

I'm using github.com/caddyserver/transform-encoder to transform Caddy log as apache2 log

I've tried crowdsec caddy parser but I have this problem #2921

Okay, it seems the bucket is pouring, however, the test seems to be using the same http path so it doesnt satisfy the distinct constraint

time="2024-08-05T20:01:42Z" level=debug msg="bucket 'crowdsecurity/http-probing' is poured" cfg=purple-moon name=crowdsecurity/http-probing
time="2024-08-05T20:01:42Z" level=debug msg="Uniq(/) : ko, discard event" bucket_id=dry-snow cfg=purple-moon name=crowdsecurity/http-probing partition=3671c134e830f40dab5b16ed453aa1a1fd52413c

https://app.crowdsec.net/hub/author/crowdsecurity/configurations/http-probing

distinct: "evt.Meta.http_path"

How are you testing it? each path needs to be unique for example

for i in {1..20}; do curl -s http://example.com/$i ;done
azertylr commented 3 months ago

oh ok, I was querying the same url.

I've tried with different url, but same problem.

it seems that caddy doesn't output the path in the log with 403 or 404 error:

caddy access log

0000 - - [06/Aug/2024:08:41:15 +0000] "GET / HTTP/3.0" 403 3 "-" "Mozilla/5.0 (Android 14; Mobile; rv:129.0) Gecko/129.0 Firefox/129.0"
0000 - - [06/Aug/2024:08:41:17 +0000] "GET / HTTP/3.0" 403 3 "-" "Mozilla/5.0 (Android 14; Mobile; rv:129.0) Gecko/129.0 Firefox/129.0"
0000 - - [06/Aug/2024:08:41:19 +0000] "GET / HTTP/3.0" 403 3 "-" "Mozilla/5.0 (Android 14; Mobile; rv:129.0) Gecko/129.0 Firefox/129.0"
0000 - - [06/Aug/2024:08:42:06 +0000] "GET /api/endpoints/2/docker/containers/4be1d10e0537bf4a43a571d92d8aeae39f93ce7d8596bb4c1a26f1e7a213bb8d/logs?since=0&stderr=1&stdout=1&tail=100&timestamps=0 HTTP/2.0" 200 17107 "https://www.mydomain/" "Mozilla/5.0 (Android 14; Mobile; rv:129.0) Gecko/129.0 Firefox/129.0

my Caddyfile:

{
    debug
    order crowdsec first
    crowdsec {
        api_url http://crowdsec:8080
        api_key 
        ticker_interval 15s
    }
}

*.{$MY_DOMAIN} {
    log {       
        level DEBUG
        format transform `{request>remote_ip} - {user_id} [{ts}] "{request>method} {request>uri} {request>proto}" {status} {size} "{request>headers>Referer>[0]}" "{request>headers>User-Agent>[0]}"` {
                time_format "02/Jan/2006:15:04:05 0000"
        }
        output file /var/log/caddy/access.log
    }
    tls {
        dns ovh {
        }
    }

    route {
        crowdsec

        @www host www.{$MY_DOMAIN}

        handle @www {
            reverse_proxy www:4533
        }

        @unknown host *.{$MY_DOMAIN}
        handle @unknown {
            respond * "403" 403
        }

        respond * "Access Deny" 403
    }
}
LaurenceJJones commented 3 months ago

it seems that caddy doesn't output the path in the log with 403 or 404 error:

Hmmm then the scenario will never trigger in that case as we rely on the http path being logged, for 403 it should trigger this scenario only for POST requests. For 404 as long as its a GET request it will trigger this scenario but has to be quite aggressive.

You can ultimately just remove the distinct restraint from the scenario locally but if it doesnt log the correct values there isnt much for us to go on from the log itself.

azertylr commented 3 months ago

thanks, I will see with Caddy team why the logs doesn't have the path of the requested file :)