Skip to content

Conversation

Azlaroc
Copy link

@Azlaroc Azlaroc commented Sep 8, 2025

Adds a CrowdSec collection for SFTPGo to detect bruteforce attacks on FTP (port 2121) and SFTP (port 2022). Includes:

  • Parser: Azlaroc/sftpgo-logs (parses JSON logs for failed/successful logins)
  • Scenario: Azlaroc/sftpgo-bf (bans after 3 failed logins in 30 seconds)
    Tested in production with 4 bans triggered. Log file: /opt/sftpgo/logs/sftpgo.log

@Azlaroc
Copy link
Author

Azlaroc commented Sep 8, 2025

I will work on these things tonight and have an update! Thanks for the feedback and consideration!

@Azlaroc
Copy link
Author

Azlaroc commented Sep 9, 2025

I made the suggested changes but want to generate test logs and ran out of time for the evening so I will complete testing tomorrow

Azlaroc added a commit to Azlaroc/hub that referenced this pull request Sep 14, 2025
Azlaroc added a commit to Azlaroc/hub that referenced this pull request Sep 14, 2025
Azlaroc added a commit to Azlaroc/hub that referenced this pull request Sep 14, 2025
Azlaroc added a commit to Azlaroc/hub that referenced this pull request Sep 14, 2025
Azlaroc added a commit to Azlaroc/hub that referenced this pull request Sep 14, 2025
@Azlaroc
Copy link
Author

Azlaroc commented Sep 14, 2025

I have attached my latest explain to show the parser can handle a bigger log file with several different types of logins and bans after 3 attempts

sudo cscli explain --file ~/hub/.tests/sftpgo-logs/sftpgo-logs-25.log --type sftpgo
line: {"level":"debug","time":"2025-09-14T16:57:09.434","sender":"common","connection_id":"34e4ab426f1522416ac2d92815e2041f2e5d4f0af631d6edcd712afbac2ccf61","message":"ssh connection removed, num open ssh connections: 0"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"info","time":"2025-09-14T16:57:36.616","sender":"SSH","connection_id":"b6e3b2dca7eec7e1672472f83466853e1589f1991d0fac2b962c2b714fc984ba","message":"User "bob" logged in with "keyboard-interactive", from ip "1.2.3.4", client version "SSH-2.0-FileZilla_3.69.3", negotiated algorithms: {KeyExchange:curve25519-sha256 HostKey:ssh-ed25519 Read:{Cipher:aes256-ctr MAC:hmac-sha2-256 compression:none} Write:{Cipher:aes256-ctr MAC:hmac-sha2-256 compression:none}}"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"debug","time":"2025-09-14T16:57:36.616","sender":"common","connection_id":"b6e3b2dca7eec7e1672472f83466853e1589f1991d0fac2b962c2b714fc984ba","message":"ssh connection added, num open connections: 1"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"debug","time":"2025-09-14T16:58:01.904","sender":"ftpserverlib","server_id":"FTP_0","clientId":"14","clientIp":"1.2.3.4:49713","message":"Client disconnected"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"debug","time":"2025-09-14T16:58:17.593","sender":"FTP","connection_id":"FTP_0_15","message":"connection removed, local address "172.21.0.30:2121", remote address "1.2.3.4:49770" close fs error: , num open connections: 0"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"debug","time":"2025-09-14T16:59:50.520","sender":"connection_failed","client_ip":"5.6.7.8","username":"","login_type":"no_auth_tried","protocol":"SSH","error":"ssh: disconnect, reason 11: "}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🟢 (+14 ~2)
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
├ s02-enrich
| ├ 🟢 crowdsecurity/dateparse-enrich (+2 ~2)
| ├ 🟢 crowdsecurity/geoip-enrich (+13)
| ├ 🔴 crowdsecurity/http-logs
| ├ 🔴 crowdsecurity/plex-allowlist
| ├ 🟢 crowdsecurity/public-dns-allowlist (unchanged)
| └ 🟢 crowdsecurity/whitelists (unchanged)
├-------- parser success 🟢
├ Scenarios
└ 🟢 Azlaroc/sftpgo-bf

line: {"level":"debug","time":"2025-09-14T17:00:12.574","sender":"FTP","connection_id":"FTP_0_16","message":"connection removed, local address "172.21.0.30:2121", remote address "5.6.7.8:7843" close fs error: , num open connections: 0"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"debug","time":"2025-09-14T16:57:35.709","sender":"FTP","connection_id":"FTP_0_13","message":"connection removed, local address "172.21.0.30:2121", remote address "1.2.3.4:62099" close fs error: , num open connections: 0"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"debug","time":"2025-09-14T16:57:44.524","sender":"common","connection_id":"b6e3b2dca7eec7e1672472f83466853e1589f1991d0fac2b962c2b714fc984ba","message":"ssh connection removed, num open ssh connections: 0"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"debug","time":"2025-09-14T16:57:44.524","sender":"SFTP","connection_id":"SFTP_b6e3b2dca7eec7e1672472f83466853e1589f1991d0fac2b962c2b714fc984ba_1","message":"connection removed, local address "172.21.0.30:2022", remote address "1.2.3.4:62151" close fs error: , num open connections: 0"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"info","time":"2025-09-14T16:58:02.799","sender":"SSH","connection_id":"55f35cafbc585ec9ec97e08785cc43a90310fb89c9b6ef150f46f07b9ae9802a","message":"User "bob" logged in with "keyboard-interactive", from ip "1.2.3.4", client version "SSH-2.0-FileZilla_3.69.3", negotiated algorithms: {KeyExchange:curve25519-sha256 HostKey:ssh-ed25519 Read:{Cipher:aes256-ctr MAC:hmac-sha2-256 compression:none} Write:{Cipher:aes256-ctr MAC:hmac-sha2-256 compression:none}}"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"debug","time":"2025-09-14T16:58:17.593","sender":"ftpserverlib","server_id":"FTP_0","clientId":"15","clientIp":"1.2.3.4:49770","message":"Client disconnected"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"debug","time":"2025-09-14T16:59:50.520","sender":"sftpd","message":"failed to accept an incoming connection from ip "5.6.7.8": ssh: disconnect, reason 11: "}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"debug","time":"2025-09-14T17:00:12.274","sender":"FTP","connection_id":"FTP_0_16","message":"connection added, local address "172.21.0.30:2121", remote address "5.6.7.8:7843", num open connections: 1"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"debug","time":"2025-09-14T16:56:57.984","sender":"SFTP","connection_id":"SFTP_34e4ab426f1522416ac2d92815e2041f2e5d4f0af631d6edcd712afbac2ccf61_1","message":"connection added, local address "172.21.0.30:2022", remote address "1.2.3.4:62078", num open connections: 1"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"debug","time":"2025-09-14T16:57:45.270","sender":"common","connection_id":"FTP_0_14","message":"connection swapped, close fs error: "}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"debug","time":"2025-09-14T16:58:13.269","sender":"common","connection_id":"FTP_0_15","message":"connection swapped, close fs error: "}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"debug","time":"2025-09-14T17:00:12.273","sender":"ftpserverlib","server_id":"FTP_0","clientId":"16","clientIp":"5.6.7.8:7843","message":"Client connected"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"debug","time":"2025-09-14T16:56:57.729","sender":"dataprovider_sqlite","message":"last login updated for user "bob""}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"debug","time":"2025-09-14T16:57:09.591","sender":"FTP","connection_id":"FTP_0_13","message":"connection added, local address "172.21.0.30:2121", remote address "1.2.3.4:62099", num open connections: 1"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"info","time":"2025-09-14T16:57:44.524","sender":"SFTP","connection_id":"SFTP_b6e3b2dca7eec7e1672472f83466853e1589f1991d0fac2b962c2b714fc984ba_1","message":"connection closed, sent exit status {Status:0} error: EOF"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"debug","time":"2025-09-14T16:58:12.546","sender":"common","connection_id":"55f35cafbc585ec9ec97e08785cc43a90310fb89c9b6ef150f46f07b9ae9802a","message":"ssh connection removed, num open ssh connections: 0"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"debug","time":"2025-09-14T17:00:12.574","sender":"ftpserverlib","server_id":"FTP_0","clientId":"16","err":"close tcp 172.21.0.30:2121->5.6.7.8:7843: use of closed network connection","message":"Problem closing control connection"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"debug","time":"2025-09-14T16:56:57.729","sender":"common","connection_id":"34e4ab426f1522416ac2d92815e2041f2e5d4f0af631d6edcd712afbac2ccf61","message":"ssh connection added, num open connections: 1"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"debug","time":"2025-09-14T16:57:19.173","sender":"common","connection_id":"FTP_0_13","message":"connection swapped, close fs error: "}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"debug","time":"2025-09-14T16:57:35.709","sender":"ftpserverlib","server_id":"FTP_0","clientId":"13","clientIp":"1.2.3.4:62099","message":"Client disconnected"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"debug","time":"2025-09-14T16:58:12.707","sender":"FTP","connection_id":"FTP_0_15","message":"connection added, local address "172.21.0.30:2121", remote address "1.2.3.4:49770", num open connections: 1"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line:
├ s00-enrich
| └ 🟢 crowdsecurity/rdns (+155 ~6)
├ s01-whitelist
| ├ 🟢 crowdsecurity/cdn-whitelist (unchanged)
| └ 🟢 crowdsecurity/seo-bots-whitelist (unchanged)
└-------- parser failure 🔴

line: {"level":"debug","time":"2025-09-14T16:57:09.591","sender":"ftpserverlib","server_id":"FTP_0","clientId":"13","clientIp":"1.2.3.4:62099","message":"Client connected"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"debug","time":"2025-09-14T16:58:01.904","sender":"FTP","connection_id":"FTP_0_14","message":"connection removed, local address "172.21.0.30:2121", remote address "1.2.3.4:49713" close fs error: , num open connections: 0"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"debug","time":"2025-09-14T16:58:02.799","sender":"common","connection_id":"55f35cafbc585ec9ec97e08785cc43a90310fb89c9b6ef150f46f07b9ae9802a","message":"ssh connection added, num open connections: 1"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"debug","time":"2025-09-14T16:58:03.096","sender":"SFTP","connection_id":"SFTP_55f35cafbc585ec9ec97e08785cc43a90310fb89c9b6ef150f46f07b9ae9802a_1","message":"connection added, local address "172.21.0.30:2022", remote address "1.2.3.4:49753", num open connections: 1"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"info","time":"2025-09-14T16:58:12.546","sender":"SFTP","connection_id":"SFTP_55f35cafbc585ec9ec97e08785cc43a90310fb89c9b6ef150f46f07b9ae9802a_1","message":"connection closed, sent exit status {Status:0} error: EOF"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"info","time":"2025-09-14T16:58:13.269","sender":"FTP","connection_id":"FTP_0_15","message":"User "bob" logged in with "password" from ip "1.2.3.4", TLS enabled? false"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"debug","time":"2025-09-14T16:59:44.796","sender":"connection_failed","client_ip":"5.6.7.8","username":"bob","login_type":"keyboard-interactive","protocol":"SSH","error":"invalid credentials"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🟢 (+15 ~2)
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
├ s02-enrich
| ├ 🟢 crowdsecurity/dateparse-enrich (+2 ~2)
| ├ 🟢 crowdsecurity/geoip-enrich (+13)
| ├ 🔴 crowdsecurity/http-logs
| ├ 🔴 crowdsecurity/plex-allowlist
| ├ 🟢 crowdsecurity/public-dns-allowlist (unchanged)
| └ 🟢 crowdsecurity/whitelists (unchanged)
├-------- parser success 🟢
├ Scenarios
└ 🟢 Azlaroc/sftpgo-bf

line: {"level":"info","time":"2025-09-14T16:57:09.434","sender":"SFTP","connection_id":"SFTP_34e4ab426f1522416ac2d92815e2041f2e5d4f0af631d6edcd712afbac2ccf61_1","message":"connection closed, sent exit status {Status:0} error: EOF"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"info","time":"2025-09-14T16:57:19.173","sender":"FTP","connection_id":"FTP_0_13","message":"User "bob" logged in with "password" from ip "1.2.3.4", TLS enabled? false"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"debug","time":"2025-09-14T16:57:36.899","sender":"SFTP","connection_id":"SFTP_b6e3b2dca7eec7e1672472f83466853e1589f1991d0fac2b962c2b714fc984ba_1","message":"connection added, local address "172.21.0.30:2022", remote address "1.2.3.4:62151", num open connections: 1"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"debug","time":"2025-09-14T16:57:44.689","sender":"ftpserverlib","server_id":"FTP_0","clientId":"14","clientIp":"1.2.3.4:49713","message":"Client connected"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"info","time":"2025-09-14T16:57:45.270","sender":"FTP","connection_id":"FTP_0_14","message":"User "bob" logged in with "password" from ip "1.2.3.4", TLS enabled? false"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"debug","time":"2025-09-14T16:58:12.546","sender":"SFTP","connection_id":"SFTP_55f35cafbc585ec9ec97e08785cc43a90310fb89c9b6ef150f46f07b9ae9802a_1","message":"connection removed, local address "172.21.0.30:2022", remote address "1.2.3.4:49753" close fs error: , num open connections: 0"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"debug","time":"2025-09-14T17:00:12.574","sender":"connection_failed","client_ip":"5.6.7.8","username":"bob","login_type":"password","protocol":"FTP","error":"invalid credentials"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🟢 (+15 ~2)
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
├ s02-enrich
| ├ 🟢 crowdsecurity/dateparse-enrich (+2 ~2)
| ├ 🟢 crowdsecurity/geoip-enrich (+13)
| ├ 🔴 crowdsecurity/http-logs
| ├ 🔴 crowdsecurity/plex-allowlist
| ├ 🟢 crowdsecurity/public-dns-allowlist (unchanged)
| └ 🟢 crowdsecurity/whitelists (unchanged)
├-------- parser success 🟢
├ Scenarios
└ 🟢 Azlaroc/sftpgo-bf

line: {"level":"error","time":"2025-09-14T17:00:12.574","sender":"ftpserverlib","server_id":"FTP_0","clientId":"16","err":"read tcp 172.21.0.30:2121->5.6.7.8:7843: use of closed network connection","message":"Network error"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"info","time":"2025-09-14T16:56:57.706","sender":"SSH","connection_id":"34e4ab426f1522416ac2d92815e2041f2e5d4f0af631d6edcd712afbac2ccf61","message":"User "bob" logged in with "keyboard-interactive", from ip "1.2.3.4", client version "SSH-2.0-FileZilla_3.69.3", negotiated algorithms: {KeyExchange:curve25519-sha256 HostKey:ssh-ed25519 Read:{Cipher:aes256-ctr MAC:hmac-sha2-256 compression:none} Write:{Cipher:aes256-ctr MAC:hmac-sha2-256 compression:none}}"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"debug","time":"2025-09-14T16:57:09.434","sender":"SFTP","connection_id":"SFTP_34e4ab426f1522416ac2d92815e2041f2e5d4f0af631d6edcd712afbac2ccf61_1","message":"connection removed, local address "172.21.0.30:2022", remote address "1.2.3.4:62078" close fs error: , num open connections: 0"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"debug","time":"2025-09-14T16:57:44.689","sender":"FTP","connection_id":"FTP_0_14","message":"connection added, local address "172.21.0.30:2121", remote address "1.2.3.4:49713", num open connections: 1"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"debug","time":"2025-09-14T16:58:12.707","sender":"ftpserverlib","server_id":"FTP_0","clientId":"15","clientIp":"1.2.3.4:49770","message":"Client connected"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

line: {"level":"debug","time":"2025-09-14T16:59:44.443","sender":"connection_failed","client_ip":"5.6.7.8","username":"bob","login_type":"password","protocol":"SSH","error":"invalid credentials"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🟢 (+15 ~2)
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
├ s02-enrich
| ├ 🟢 crowdsecurity/dateparse-enrich (+2 ~2)
| ├ 🟢 crowdsecurity/geoip-enrich (+13)
| ├ 🔴 crowdsecurity/http-logs
| ├ 🔴 crowdsecurity/plex-allowlist
| ├ 🟢 crowdsecurity/public-dns-allowlist (unchanged)
| └ 🟢 crowdsecurity/whitelists (unchanged)
├-------- parser success 🟢
├ Scenarios
└ 🟢 Azlaroc/sftpgo-bf

line: {"level":"debug","time":"2025-09-14T17:00:12.574","sender":"ftpserverlib","server_id":"FTP_0","clientId":"16","clientIp":"5.6.7.8:7843","message":"Client disconnected"}
├ s00-raw
| ├ 🔴 crowdsecurity/syslog-logs
| └ 🟢 crowdsecurity/non-syslog (+5 ~8)
├ s01-parse
| ├ 🔴
| ├ 🔴 crowdsecurity/iptables-logs
| ├ 🔴 crowdsecurity/nginx-logs
| ├ 🔴 crowdsecurity/sshd-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴

@Azlaroc
Copy link
Author

Azlaroc commented Sep 14, 2025

PR Update: Expanded Testing with Larger Log File

Thanks for the feedback on the SFTPGo bruteforce detection collection! I’ve conducted additional testing with a much larger log file (sftpgo-logs-25.log) to demonstrate the parser’s ability to handle high-volume, mixed-protocol logs (FTP on port 2121, SFTP on port 2022) in a production-like environment.

Test Summary

  1. Ran sudo cscli --debug hubtest run sftpgo-logs with a larger log containing diverse entries (successful/failed logins, connection events, debug/info/error messages).
  2. Result: All tests passed, confirming the parser (Azlaroc/sftpgo-logs) and scenario (Azlaroc/sftpgo-bf) work reliably with complex logs.
  3. Key findings from sudo cscli explain --file ~/hub/.tests/sftpgo-logs/sftpgo-logs-25.log --type sftpgo:
    1. Failed login attempts (e.g., "invalid credentials", "no_auth_tried") are correctly parsed, enriched (e.g., timestamps, GeoIP), and trigger the bruteforce scenario (Azlaroc/sftpgo-bf).
    2. Non-relevant lines (e.g., successful logins, connection events) fail parsing as expected, avoiding false positives.
    3. No crashes or unexpected behavior with varied log entries (SSH, SFTP, FTP protocols).
  4. The test log included anonymized data (usernames as "bob", IPs as 1.2.3.4 or 5.6.7.8, internal IPs in 172.21.0.0/16 range) to ensure no sensitive information is exposed.

Commands Used

sudo cscli --debug hubtest run sftpgo-logs
sudo cscli explain --file ~/hub/.tests/sftpgo-logs/sftpgo-logs-25.log --type sftpgo

Notes

  • The GeoIP enrichment warning (unable to open GeoLite2-City.mmdb) in the test output is due to a missing database in the test environment and doesn’t affect the parser’s core functionality.
  • This complements the original test (smaller log, 4 bans triggered in production) by showing scalability with larger datasets.

I’ve attached the cscli explain output (anonymized) for reference. Let me know if you’d like additional details or changes before merging!

@Azlaroc
Copy link
Author

Azlaroc commented Sep 17, 2025

@LaurenceJJones Hey, just checking in on the PR! Updated the test results with a larger log (sftpgo-logs-25.log), confirmed files match prod (/etc/crowdsec), and fixed the README in my repo to reflect the correct ban threshold (3 failed logins in 30s) and parser scope (failed logins only). Everything’s tested and ready—any feedback or tweaks needed to get this merged? Excited to see it in the hub! 😎

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are missing the name key to define it as Azlaroc/sftpgo-logs

pattern_syntax:
SFTPGO_TIME: '%{YEAR}-%{MONTHNUM}-%{MONTHDAY}T%{HOUR}:%{MINUTE}:%{SECOND}\.%{NUMBER}'
SFTPGO_FAILED: '\{"level":"%{WORD:log_level}","time":"%{SFTPGO_TIME:evt_time}","sender":"connection_failed","client_ip":"%{IPV4:client_ip}","username":"%{DATA:username}","login_type":"%{DATA:login_type}","protocol":"%{WORD:protocol}","error":"%{GREEDYDATA:error}"\}'
filter: evt.Parsed.program == 'sftpgo'
Copy link
Contributor

@LaurenceJJones LaurenceJJones Sep 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can most likely make this filter and the pattern easier to parse

filter: "evt.Parsed.program == 'sftpgo' && UnmarshalJSON(evt.Parsed.message, evt.Unmarshaled, 'sftpgo') in [nil, '']"

this will parse the incoming log line as json and within the statics you can reference them easier via

statics:
  - meta: source_ip
    expression: evt.Unmarshaled.sftpgo["client_ip"]

groupby: evt.Meta.source_ip
capacity: 3
leakspeed: "30s"
blackhole: 4h
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make this like 5m instead blackhole doesnt control the ban duration just the supression on repeated buckets if enforce happens at later time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants