Quellenhinweis

Dieser Beitrag fasst eine Anleitung von Merijn Schering (Group-Office / Intermesh BV) in eigenen Worten zusammen. Den vollständigen Original-Artikel findest du direkt bei Group-Office: group-office.com/blog – Protect your GroupOffice server.

Wenn Scanner an die Tür klopfen

Apache-Access-Log mit Scanner-Anfragen und fail2ban-Sperre

Wer Group-Office selbst betreibt, sollte ab und zu einen Blick ins Apache-Access-Log werfen. Sehr wahrscheinlich finden sich dort ganze Salven von Anfragen dieser Art:

groupoffice.example.com 203.0.113.45 - - [08/Oct/2026:09:03:06 +0200] "GET /.env HTTP/1.1" 404 236
groupoffice.example.com 203.0.113.45 - - [08/Oct/2026:09:03:06 +0200] "GET /.git/config HTTP/1.1" 404 236
groupoffice.example.com 203.0.113.45 - - [08/Oct/2026:09:03:06 +0200] "GET /.aws/credentials HTTP/1.1" 404 236
groupoffice.example.com 203.0.113.45 - - [08/Oct/2026:09:03:07 +0200] "GET /api/uploads/%2e%2e%2f%2e%2e%2f.env HTTP/1.1" 404 236
groupoffice.example.com 203.0.113.45 - - [08/Oct/2026:09:03:13 +0200] "GET /phpinfo.php HTTP/1.1" 404 236

Dahinter stecken automatisierte Schwachstellen-Scanner. Sie klappern jeden erreichbaren Server nach versehentlich veröffentlichten Konfigurationsdateien, Cloud-Zugangsdaten, Git-Repositories, Debug-Endpunkten und Path-Traversal-Lücken ab. Intermesh berichtet von einem Scanner, der in weniger als zehn Sekunden rund 250 Anfragen abgesetzt hat.

Gegen Group-Office laufen diese Anfragen zwar ins Leere – die schiere Menge kann trotzdem schaden. Jede Anfrage belegt einen Apache-Worker, und wenn mehrere Scanner gleichzeitig zuschlagen, wird der Server für die eigentlichen Nutzerinnen und Nutzer spürbar langsam oder reagiert gar nicht mehr. Die Lösung: fail2ban erkennt die Scanner in den Apache-Logs und sperrt sie binnen Sekunden an der Firewall aus.

Der Ansatz: zwei Jails

  • apache-badpaths überwacht das Access-Log und sperrt eine IP bereits nach drei Anfragen auf Pfade, die kein regulärer Group-Office-Nutzer je aufruft – etwa .env-Dateien, /proc/self/environ, .git, Credential-Dateien oder ../-Traversal.
  • apache-phpnotfound überwacht das Error-Log und sperrt IPs, die gehäuft nicht existierende PHP-Skripte anfragen. Damit erwischt man auch Scanner, deren Pfade nicht auf der Liste stehen.

Warum nicht einfach jeden 404 im Access-Log zählen? Weil Group-Office-Clients ganz legitim 404-Antworten erzeugen: CalDAV-, CardDAV- und WebDAV-Clients bekommen sie beim normalen Synchronisieren regelmäßig, und Group-Office selbst liefert über index.php einen 404, wenn etwa ein temporärer Download abgelaufen ist. Wer das mitzählt, sperrt früher oder später die eigenen Anwender aus.

Das Error-Log löst dieses Problem elegant. Fragt jemand ein PHP-Skript an, das auf der Platte gar nicht existiert, schreibt Apache eine Zeile wie diese:

[client 203.0.113.45:51046] script '/var/www/groupoffice/info.php' not found or unable to stat

Die eigenen 404-Antworten von Group-Office und der DAV-Verkehr erzeugen diese Zeile nie – sie lässt sich also ohne jede Ausnahmeliste zählen.

fail2ban installieren

sudo apt install fail2ban

Format des Access-Logs prüfen

Der Filter für verdächtige Pfade geht davon aus, dass der Name des virtuellen Hosts vor der Client-IP steht – so wie im Debian-Format vhost_combined, das für /var/log/apache2/other_vhosts_access.log verwendet wird:

groupoffice.example.com:443 203.0.113.45 - - [08/Oct/2026:09:03:06 +0200] "GET /.env HTTP/1.1" 404 236

Nutzt das eigene Access-Log dagegen das einfache combined-Format mit der IP am Zeilenanfang, entfernt man in der failregex-Zeile das \S+ direkt hinter dem ^.

Filter 1: eindeutige Exploit-Versuche

Datei /etc/fail2ban/filter.d/apache-badpaths.conf anlegen:

[Definition]
# Anfragen nach Geheimnissen, Debug-Tools und Path Traversal (ohne Groß-/Kleinschreibung).
# Hinweis: Ein wörtliches % muss in fail2ban-Konfigurationsdateien als %% geschrieben werden.
failregex = ^\S+ <HOST> \S+ \S+ .*"[A-Z]+ [^"]*(?i:/\.env|\.env\.|/\.git|/\.aws|/\.ssh|/\.npmrc|/\.dockerenv|id_rsa|id_ed25519|proc/self|\.\./|\.\.%%2f|%%2e%%2e|%%2eenv|/@fs/|__vite|terraform\.tfstate|serviceaccount|credentials\.json|service-account\.json|firebase-admin|/actuator|phpinfo|/pi\.php|/info\.php|/test\.php|app_dev\.php|_profiler|_ignition|_debugbar|telescope/|elmah\.axd|trace\.axd|wp-login|wp-admin|xmlrpc\.php|cgi-bin/)[^"]*"

ignoreregex =

Die Liste lässt sich jederzeit um Muster erweitern, die im eigenen Log auftauchen.

Filter 2: nicht vorhandene PHP-Skripte

Datei /etc/fail2ban/filter.d/apache-phpnotfound.conf anlegen:

[Definition]
# Apache protokolliert dies nur, wenn das angefragte PHP-Skript nicht auf der Platte existiert.
failregex = \[client <HOST>(?::\d+)?\] .*script '[^']*' not found or unable to stat

ignoreregex =

Die Jails

Datei /etc/fail2ban/jail.d/apache-scanners.conf anlegen:

[DEFAULT]
# Eigene Büro- und Monitoring-IPs ergänzen, damit man sich nie selbst aussperrt
ignoreip = 127.0.0.1/8 ::1

# Wiederholungstäter werden immer länger gesperrt
bantime.increment = true
bantime.maxtime   = 4w

[apache-badpaths]
enabled  = true
backend  = auto
port     = http,https
filter   = apache-badpaths
logpath  = /var/log/apache2/*access*.log
maxretry = 3
findtime = 10m
bantime  = 1d

[apache-phpnotfound]
enabled  = true
backend  = auto
port     = http,https
filter   = apache-phpnotfound
logpath  = /var/log/apache2/*error*.log
maxretry = 10
findtime = 1m
bantime  = 6h

Standardmäßig sperrt ein Ban nur die Ports 80 und 443. Wer gesperrte Scanner komplett vom Server fernhalten möchte, ergänzt in beiden Jails banaction = nftables-allports.

Erst testen, dann scharf schalten

Mit fail2ban-regex lässt sich ein Filter gegen eine bestehende Logdatei prüfen, ohne dass dabei jemand gesperrt wird:

sudo fail2ban-regex /var/log/apache2/other_vhosts_access.log /etc/fail2ban/filter.d/apache-badpaths.conf
sudo fail2ban-regex /var/log/apache2/error.log /etc/fail2ban/filter.d/apache-phpnotfound.conf

Mit dem Zusatz --print-all-matched sieht man genau, welche Zeilen getroffen werden. Wichtig: Normaler Group-Office-Verkehr der eigenen Nutzer darf in dieser Ausgabe nicht auftauchen.

Aktivieren

sudo systemctl reload fail2ban
sudo fail2ban-client status apache-badpaths
sudo fail2ban-client status apache-phpnotfound

Die Statusausgabe zeigt, wie viele Treffer bereits gezählt wurden und welche IPs aktuell gesperrt sind.

Sperren verwalten

fail2ban speichert seine Sperren in einer Datenbank, verknüpft mit dem Namen des Jails. Ändert man später einen Filter und lädt neu, bleiben aktive Sperren bestehen und werden für ihre Restlaufzeit wiederhergestellt. Ein kompletter Neustart ist nicht nötig – es reicht, ein einzelnes Jail neu zu laden:

sudo fail2ban-client reload apache-phpnotfound

Erwischt es doch einmal einen legitimen Nutzer, lässt sich die Sperre sofort aufheben:

sudo fail2ban-client set apache-phpnotfound unbanip 203.0.113.45

Um etwa während eines Angriffs zu sehen, welche IPs gerade die meisten Verbindungen zum Server halten, hilft dieser Einzeiler:

ss -tn state established | awk 'NR>1 {sub(/:[0-9]+$/,"",$4); print $4}' | sort | uniq -c | sort -rn | head -20

Fazit

Mit diesen beiden Jails ist ein Scanner in der Regel nach ein bis zwei Sekunden gesperrt – lange bevor er die Apache-Worker blockieren kann. In den ersten Tagen lohnt sich ein regelmäßiger Blick auf fail2ban-client status; außerdem sollten die eigenen IPs in ignoreip eingetragen und die Liste verdächtiger Pfade erweitert werden, sobald neue Scan-Muster in den Logs auftauchen.

Du betreibst Group-Office selbst und möchtest deine Installation absichern? Wir unterstützen dich gern bei Einrichtung und Feinschliff – oder übernehmen das Hosting gleich ganz.