Fail2Ban ist eine auf Python basierte Skriptsammlung für Linux Server und Systeme, die es Administratoren ermöglicht, die Sicherheit ihres Systems zu erhöhen und sich vor Angriffen zu schützen, die auf wiederholte Anmeldeversuche abzielen, indem es fehlgeschlagene Anmeldeversuche überwacht und temporäre Sperrmaßnahmen auf IP-Adressen anwendet, die verdächtige oder bösartige Aktivitäten zeigen. Da zu zählen:
-
- Schutz vor Brute-Force-Angriffen: Fail2ban ist besonders nützlich, um sich gegen Brute-Force-Angriffe zu verteidigen, bei denen Angreifer wiederholt versuchen, sich mit verschiedenen Benutzernamen und Kennwörtern anzumelden, um unbefugten Zugriff zu erlangen.
- Konfigurierbare Regeln: Sie können Fail2ban so konfigurieren, dass es spezifische Dienste wie SSH, Apache, FTP und mehr überwacht. Es ermöglicht die Definition von Regeln, die auf Log-Dateien basieren, um verdächtige Aktivitäten zu erkennen.
- Zeitlich begrenzte Sperren: Wenn ein Benutzer oder eine IP-Adresse gegen eine Regel verstößt, wird er/sie temporär gesperrt. Die Dauer der Sperre ist konfigurierbar und kann je nach Bedarf angepasst werden.
- Zentrale Protokollierung: Fail2ban protokolliert alle Aktivitäten, einschließlich Sperrungen und Freigaben, um die Überwachung und Fehlersuche zu erleichtern.
- Benutzerdefinierte Aktionen: Sie können benutzerdefinierte Aktionen festlegen, die bei einer Sperre ausgeführt werden sollen, z.B. Benachrichtigungen per E-Mail oder das Hinzufügen von IP-Adressen zu einer Blockliste.
- Erweiterbarkeit: Es gibt viele Erweiterungen und Plugins für Fail2ban, die zusätzliche Funktionalitäten bieten, um den Schutz zu verbessern.
Technisch versierte Nutzer können eigene Muster in Error- bzw. Access-Logs erkennen und so weitere Firewall-Regeln definieren.
Grundlagen | Jails / Filter | Sonstiges |
Installation | SSH (mit Erklärung / BSP) | Fail2Ban E-Mail Support |
Konfiguration | WordPress | Manuelle IP-Sperre via Blacklist |
Die einzelnen Jails | Nextcloud | |
Fail2ban Steuern |
Installation
Fail2Ban ist in den Standardrepositories gängiger Distributionen bereits enthalten und kann auf Debian basierten Systemen wie gewohnt einfach installiert werden :
1 |
sudo apt-get install fail2ban |
Konfiguration
Nach erfolgreicher Installation befinden sich die Konfigurationsdateien im Verzeichnis /etc/fail2ban. In der fail2ban.conf werden die grundlegenden Parameter für Fail2Ban festgelegt. Die allgemeine Konfiguration der Jails wird in der Datei jail.local realisiert, nicht in der jail.conf, da diese bei Updates überschrieben wird.
1 2 |
# To avoid merges during upgrades DO NOT MODIFY THIS FILE # and rather provide your changes in /etc/fail2ban/jail.local |
Die jail.conf sollte daher zu jail.local kopiert oder einfach auf jail.conf verlinkt werden
1 |
cd /etc/fail2ban && sudo mv jail.conf jail.local && sudo ln -s jail.local jail.conf |
In der [DEFAULT] Sektion am Anfang der jail.local werden die globalen Parameter, wie beispielsweise Loglevel oder E-Mail-Adresse für Statusmeldungen, aller Jails gesetzt. Die Parameter können dabei für jeden Jail weiterhin separat konfiguriert werden, sofern diese in der betreffenden Jail Sektion oder Datei /etc/fail2ban/jail.d/<jailname>.conf angeben werden. Die jail.local ist damit eine Art „Fallback Konfigurtion“ der Jails. Globale Parameter sind beispielsweise folgende:
1 2 3 |
ignoreip = 127.0.0.1 bantime = 3600 maxretry = 3 |
Die einzelnen Jails
Die einzelnen Jails können in der Datei /etc/fail2ban/jail.d/defaults-debian.conf oder einzeln in /etc/fail2ban/jail.d/<jailname>.conf aktiviert und konfiguriert werden. Aktionen wie das Sperren der IP, Emailversand oder sonstige Aktionen werden hier definiert. Der Filter, der auf die unter dem Parameter logpath zugewiesenen Logdatei angewandt wird, ist in dem Verzeichnis /etc/fail2ban/filter.d/*.conf unter der entsprechen *.conf Datei definiert und wird mit dem Parameter „filter = <Filter Name> zugewiesen. Nachfolgend sind einige Filter und deren Konfigurationen aufgelistet.
/etc/fail2ban/sshd.conf :
1 2 3 4 5 6 7 8 9 |
[ssh] enabled = true filter = sshd port = ssh logpath = /var/log/auth.log # banaction = iptables-multiport # per default gesetzt maxretry = 6 findtime = 86400 bantime = 3600 |
/etc/fail2ban/filter.d/sshd.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# Fail2Ban filter for openssh # # If you want to protect OpenSSH from being bruteforced by password # authentication then get public key authentication working before disabling # PasswordAuthentication in sshd_config. # # # "Connection from <HOST> port \d+" requires LogLevel VERBOSE in sshd_config # [INCLUDES] # Read common prefixes. If any customizations available -- read them from # common.local before = common.conf [DEFAULT] _daemon = sshd # optional prefix (logged from several ssh versions) like "error: ", "error: PAM: " or "fatal: " __pref = (?:(?:error|fatal): (?:PAM: )?)? # optional suffix (logged from several ssh versions) like " [preauth]" __suff = (?: \[preauth\])?\s* __on_port_opt = (?: port \d+)?(?: on \S+(?: port \d+)?)? # for all possible (also future) forms of "no matching (cipher|mac|MAC|compression method|key exchange method|host key type) found", # see ssherr.c for all possible SSH_ERR_..._ALG_MATCH errors. __alg_match = (?:(?:\w+ (?!found\b)){0,2}\w+) [Definition] prefregex = ^<F-MLFID>%(__prefix_line)s</F-MLFID>%(__pref)s<F-CONTENT>.+</F-CONTENT>$ cmnfailre = ^[aA]uthentication (?:failure|error|failed) for <F-USER>.*</F-USER> from <HOST>( via \S+)?\s*%(__suff)s$ ^User not known to the underlying authentication module for <F-USER>.*</F-USER> from <HOST>\s*%(__suff)s$ ^Failed \S+ for invalid user <F-USER>(?P<cond_user>\S+)|(?:(?! from ).)*?</F-USER> from <HOST>%(__on_port_opt)s(?: ssh\d*)?(?(cond_user): |(?:(?:(?! from ).)*)$) ^Failed \b(?!publickey)\S+ for (?P<cond_inv>invalid user )?<F-USER>(?P<cond_user>\S+)|(?(cond_inv)(?:(?! from ).)*?|[^:]+)</F-USER> from <HOST>%(__on_port_opt)s(?: ssh\d*)?(?(cond_user): |(?:(?:(?! from ).)*)$) ^<F-USER>ROOT</F-USER> LOGIN REFUSED.* FROM <HOST>\s*%(__suff)s$ ^[iI](?:llegal|nvalid) user <F-USER>.*?</F-USER> from <HOST>%(__on_port_opt)s\s*$ ^User <F-USER>.+</F-USER> from <HOST> not allowed because not listed in AllowUsers\s*%(__suff)s$ ^User <F-USER>.+</F-USER> from <HOST> not allowed because listed in DenyUsers\s*%(__suff)s$ ^User <F-USER>.+</F-USER> from <HOST> not allowed because not in any group\s*%(__suff)s$ ^refused connect from \S+ \(<HOST>\)\s*%(__suff)s$ ^Received <F-MLFFORGET>disconnect</F-MLFFORGET> from <HOST>%(__on_port_opt)s:\s*3: .*: Auth fail%(__suff)s$ ^User <F-USER>.+</F-USER> from <HOST> not allowed because a group is listed in DenyGroups\s*%(__suff)s$ ^User <F-USER>.+</F-USER> from <HOST> not allowed because none of user's groups are listed in AllowGroups\s*%(__suff)s$ ^pam_unix\(sshd:auth\):\s+authentication failure;\s*logname=\S*\s*uid=\d*\s*euid=\d*\s*tty=\S*\s*ruser=<F-USER>\S*</F-USER>\s*rhost=<HOST>\s.*%(__suff)s$ ^(error: )?maximum authentication attempts exceeded for <F-USER>.*</F-USER> from <HOST>%(__on_port_opt)s(?: ssh\d*)?%(__suff)s$ ^User <F-USER>.+</F-USER> not allowed because account is locked%(__suff)s ^<F-MLFFORGET>Disconnecting</F-MLFFORGET>: Too many authentication failures(?: for <F-USER>.+?</F-USER>)?%(__suff)s ^<F-NOFAIL>Received <F-MLFFORGET>disconnect</F-MLFFORGET></F-NOFAIL> from <HOST>: 11: ^<F-NOFAIL>Connection <F-MLFFORGET>closed</F-MLFFORGET></F-NOFAIL> by <HOST>%(__suff)s$ ^<F-MLFFORGET><F-NOFAIL>Accepted publickey</F-NOFAIL></F-MLFFORGET> for \S+ from <HOST>(?:\s|$) mdre-normal = mdre-ddos = ^Did not receive identification string from <HOST>%(__suff)s$ ^Connection <F-MLFFORGET>reset</F-MLFFORGET> by <HOST>%(__on_port_opt)s%(__suff)s ^<F-NOFAIL>SSH: Server;Ltype:</F-NOFAIL> (?:Authname|Version|Kex);Remote: <HOST>-\d+;[A-Z]\w+: ^Read from socket failed: Connection <F-MLFFORGET>reset</F-MLFFORGET> by peer%(__suff)s mdre-extra = ^Received <F-MLFFORGET>disconnect</F-MLFFORGET> from <HOST>%(__on_port_opt)s:\s*14: No supported authentication methods available%(__suff)s$ ^Unable to negotiate with <HOST>%(__on_port_opt)s: no matching <__alg_match> found. ^Unable to negotiate a <__alg_match>%(__suff)s$ ^no matching <__alg_match> found: mdre-aggressive = %(mdre-ddos)s %(mdre-extra)s cfooterre = ^<F-NOFAIL>Connection from</F-NOFAIL> <HOST> failregex = %(cmnfailre)s <mdre-<mode>> %(cfooterre)s # Parameter "mode": normal (default), ddos, extra or aggressive (combines all) # Usage example (for jail.local): # [sshd] # mode = extra # # or another jail (rewrite filter parameters of jail): # [sshd-aggressive] # filter = sshd[mode=aggressive] # mode = normal #filter = sshd[mode=aggressive] ignoreregex = maxlines = 1 journalmatch = _SYSTEMD_UNIT=sshd.service + _COMM=sshd datepattern = {^LN-BEG} # DEV Notes: # # "Failed \S+ for .*? from <HOST>..." failregex uses non-greedy catch-all because # it is coming before use of <HOST> which is not hard-anchored at the end as well, # and later catch-all's could contain user-provided input, which need to be greedily # matched away first. # # Author: Cyril Jaquier, Yaroslav Halchenko, Petr Voralek, Daniel Black and Sergey Brester aka sebres # Rewritten using prefregex (and introduced "mode" parameter) by Serg G. Brester. |
/etc/fail2ban/jail.d/wordpress.conf
1 2 3 4 5 6 7 8 |
[wordpress] enabled = true port = http,https filter = wordpress logpath = /var/log/apache2/access.log maxretry = 6 findtime = 86400 bantime = 3600 |
/etc/fail2ban/filter.d/wordpress.conf
1 2 3 4 5 6 |
# Filter for WordPress login [INCLUDES] before = common.conf [Definition] failregex = <HOST>.*POST.*(wp-login\.php|xmlrpc\.php).* 200 datepattern = %%d/%%b/%%Y:%%H:%%M:%%S %%z |
/etc/fail2ban/jail.d/nextcloud.conf
1 2 3 4 5 6 7 8 |
[nextcloud] enabled = true port = https,http filter = nextcloud logpath = /var/www/nextcloud/data/nextcloud.log maxretry = 6 findtime = 86400 bantime = 1800 |
/etc/fail2ban/filter.d/nextcloud.conf :
1 2 3 |
[Definition] failregex={"reqId":".*","remoteAddr":".*","app":"core","message":"Login failed: '.*' \(Remote IP: '<HOST>'\)","level":2,"time":".*"} ignoreregex = |
Fail2Ban setzt allerdings nicht irgendwelche IP-Adressen auf die interne Blacklist, sondern ausschließlich die, die dem regulären Ausdruck aus dem Jail-Filter entsprechen. Daher sollte man sehr vorsichtig mit Filter-Definitionen hantieren und diese mit fail2ban-regex umgehend testen. Die Funktion der Filter kann mit dem folgenden Befehl überprüft werden (in diesem Fall SSH):
1 |
fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf |
Manuelle IP-Sperre via Blacklist
Je nach Anwendungsfall kann es notwendig sein, bestimmte IP-Adressen in Fail2Ban manuell zu sperren. Um die Übersicht zu erhalten und die Pflege der Einträge so einfach wie möglich zu halten, empfiehlt sich eine Blacklist Datei.
Eine eigens für diesen Zweck erstellte Lösung kommt an der Stelle zum Einsatz: IP-Datensätze werden aus der angelegten Datei ip.blacklist extrahiert und in der Firewall eingetragen. Einrichten einer Firewall-Blacklist mit Fail2Ban.
Fail2Ban E-Mail Support
Voraussetzung für das automatische Versenden von E-Mails ist ein installierter und konfigurierter Mailtransportagent (MTA) wie z.B. Postfix.
Fail2Ban E-Mail Funktion
Fail2ban kann mit einigen Parametern eigenständig E-Mails versenden ( IP-Adresse gesperrt, Fail2ban start/stop etc. ). Dazu wird die Datei /etc/fail2ban/jail.local angepasst. Der Parametereintrag „destemail = <youremail.address>“ sollte auf eine gültige/n E-Mail-Adresse oder einen Systembenutzer verweisen:
1 |
destemail = root@localhost |
Der Parametereintrag „action = %(action_XXX)s“ legt fest in welchem Umfang fail2ban Mails versendet.
1 |
action = %(action_mw)s |
ggf. muss der Systemmailadresse „fail2ban@<hostname>“ noch eine gültige Absenderadresse zugewiesen werden. Entweder direkt in der /etc/postfix/sender_canonical (Fail2ban@<hostname> <address>@<provider>.<tld>) oder in der /etc/postfix/generic (Fail2ban@<hostname> <address>@<provider>.<tld>). Hierbei das Neuerstellen der Postfixdatenbanken nicht vergessen.
1 |
cd /etc/postfix && sudo postmap generic && sudo postmap sender_canonical |
Fail2Ban E-Mail Filter Script
Die o.g. Lösung veranlasst Fail2Ban nach jeder Aktion eine E-Mail Benachrichtigung zu versenden. Dies kann u.U. einen sehr hohen E-Mailverkehr verursachen und / oder das E-Mail-Postfach überfluten. Eleganter ist es, die Fail2Ban Logs nach Einträgen zu durchsuchen, zu filtern und täglich eine Zusammenfassung per E-Mail zu versenden. Folgendes Script durchsucht die Fail2Ban Logs der letzten 24 Stunden nach SSH und FTP Bans, sortiert diese und versendet das Ergebnis per E-Mail. Über einen Cronjob kann festgelegt werden, wann und wie oft das Script gestartet wird.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 |
#!/bin/bash # name : mail_log_report.sh # desciption : send logfile summaries via mail # autor : speefak ( itoss@gmx.de ) # licence : (CC) BY-NC-SA # version : 2.6 # notice : requires iptables-blacklist version 2.0 or later #------------------------------------------------------------------------------------------------------------ ############################################################################################################ ########################################### define variables ########################################### ############################################################################################################ #------------------------------------------------------------------------------------------------------------ ScriptName=$(basename $0) Version=$(cat $0 | grep "# version" | head -n1 | awk -F ":" '{print $2}' | sed 's/ //g') MailAddress=root # mail address or systemuser ( requires active MTA ) #------------------------------------------------------------------------------------------------------------ ############################################################################################################ ######################################### adjustable functions ######################################### ############################################################################################################ #------------------------------------------------------------------------------------------------------------------------------------------------ service.ssh () { # add any charater (e.g. space) at beginning line to deactivate service # filter successfull ssh logins from /var/log/auth.log and send daily summary via mail to root ServiceName=SSH # sevicename ServiceFilter="sshd" # daemonname SectionFilter="publickey password" # section expression filter LogfileSource=$(journalctl --since "24 hour ago" -u ssh.service) # journald and timeframe ( 24 hour ago ) #LogfileSource="/var/log/auth.log /var/log/auth.log.1" # rsyslog path to log file(s) - ( /var/log/auth.log* for long check periods ) MailSubjectLine="Daily report from $(hostname) ( $(date '+%F %H:%M') ) => Accepted SSH Logins <=" # Email Subject line SummaryMessage=" Accepted SSH Logins" # Email content summary line FilterPeriod=86400 # filter past period in seconds (86400 = 1 Day) SummaryFirstLastEntryOnTop=last # show <first|last> log entry on summary top #TODO RecapColumn => sortierungs spalte für doppelte einträge CountDuplicateLines=false # count duplicate entries RecapDuplicateLines=false # sammurize duplicate entries MailSubjectLineSubstitutions="password;PW publickey;PK" # set substitutions for mail subject line # filter logfile for output expressions ( date string required ) # start line using date format : e.g. "Jan 18 07:00:00 " or "2018 01-01 07:00:00 " or "2019-01-18 21:34:34 " ; date divider: third space character logfile_filter_service () { echo "$LogfileSource" | grep Accepted | awk -F ": RSA" '{printf $1 "\n"}' # journald logging # zgrep -ahwEi "$ServiceFilter" $LogfileSource | grep Accepted | awk -F ": RSA" '{printf $1 "\n"}' # rsyslog logging } } #------------------------------------------------------------------------------------------------------------------------------------------------ service.fail2ban () { # filter via fail2ban banned IPs from /var/log ServiceName=Fail2Ban # sevicename ServiceFilter=" Ban" # daemonname / logfile entry SectionFilter="ssh wordpress nextcloud ftp http" # section expression filter #LogfileSource=$(journalctl --since "24 hour ago" -u fail2ban.service) # journald unit and timeframe ( 24 hour ago ), f2ban does not write bans to journald LogfileSource="/var/log/fail2ban.log*" #TODO set filter for last gz file # path to log file(s) - ( also gz compressed files) MailSubjectLine="Daily report from $(hostname) ( $(date '+%F %H:%M') ) => Fail2Ban log <=" # Email Subject line SummaryMessage=" Baned IPs / Attempts" # Email content summary line FilterPeriod=86400 # filter past period in seconds (86400 = 1 Day) SummaryFirstLastEntryOnTop=last # show <first|last> log entry on summary top #TODO RecapColumn => sortierungs spalte für doppelte einträge CountDuplicateLines=true # count duplicate entries RecapDuplicateLines=true # sammurize duplicate entries MailSubjectLineSubstitutions="" # set substitutions for mail subject line # filter logfile for output expressions ( date string required ) # start line using date format : e.g. "Jan 18 07:00:00 " or "2018 01-01 07:00:00 " or "2019-01-18 21:34:34 " ; date divider: third space character logfile_filter_service () { # if [[ $(cat /etc/*release* | grep VERSION_ID | cut -d '"' -f2) -ge 12 ]]; then # debian 12 or newer / journald does not save bans to journald # echo "$LogfileSource" | cut -d " " -f1,2,14,15,16 | sed 's/,.../ /' # el if [[ $(cat /etc/*release* | grep VERSION_ID | cut -d '"' -f2) -ge 9 ]]; then # debian 9 or newer zgrep -ahwEi "$ServiceFilter" $LogfileSource | cut -d " " -f1,2,14,15,16 | sed 's/,.../ /' elif [[ $(cat /etc/*release* | grep VERSION_ID | cut -d '"' -f2) == 8 ]]; then # debian 8 zgrep -ahwEi "$ServiceFilter" $LogfileSource | cut -d " " -f1,2,5,6,7 | sed 's/,.../ /' fi } } #------------------------------------------------------------------------------------------------------------------------------------------------ execute_post_report_command () { if [[ $ServiceName == "Fail2Ban" ]]; then # add multible bans to permanent blacklist using ipb command MaxEntries=2 BlacklistedIPs=$(grep -w "\[sshd\] Ban" <<< $ReportContent | awk '{ if ($1 >= '$MaxEntries') print $0 }' | grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}') # check for non empty BlacklistedIPs var if [[ -n "$BlacklistedIPs" ]]; then printf "\r adding blacklisted IPs to blacklist ( ipb -a $BlacklistedIPs ) \n" ipb -a $(echo "$BlacklistedIPs" | tr "\n" " ") else printf "\r no new blacklisted IPs detected \n" fi fi } #------------------------------------------------------------------------------------------------------------------------------------------------ ############################################################################################################ ######################################## set vars from options ########################################## ############################################################################################################ #------------------------------------------------------------------------------------------------------------ OptionVarList=" MailReport;-mr PrintReport;-pr ExecutePostReportCommands;-eprc Monochrome;-m ScriptInformation;-si " # set entered vars from optionvarlist for InputOption in $(echo " $@" | tr " " "\n" ) ; do for VarNameVarValue in $OptionVarList ; do VarName=$(echo "$VarNameVarValue" | cut -d ";" -f1) VarValue=$(echo "$VarNameVarValue" | cut -d ";" -f2) if [[ $InputOption == $VarValue ]]; then eval $(echo "$VarName"="$InputOption") fi done done #------------------------------------------------------------------------------------------------------------------------------------------------ ############################################################################################################ ########################################### fixed functions ############################################ ############################################################################################################ #------------------------------------------------------------------------------------------------------------ load_color_codes () { Black='\033[0;30m' && DGray='\033[1;30m' LRed='\033[0;31m' && Red='\033[1;31m' LGreen='\033[0;32m' && Green='\033[1;32m' LYellow='\033[0;33m' && Yellow='\033[1;33m' LBlue='\033[0;34m' && Blue='\033[1;34m' LPurple='\033[0;35m' && Purple='\033[1;35m' LCyan='\033[0;36m' && Cyan='\033[1;36m' LLGrey='\033[0;37m' && White='\033[1;37m' Reset='\033[0m' # Use them to print in your required colours: # printf "%s\n" "Text in ${Red}red${Reset}, white and ${Blue}blue${Reset}." BG='\033[47m' FG='\033[0;30m' # reloard colored global vars for i in $(cat $0 | sed '/load_color_codes/q' | grep '${Reset}'); do eval "$i" done } #------------------------------------------------------------------------------------------------------------------------------------------------ usage() { printf " iptables-blacklist version: $Version | script location $basename $0\n" clear printf "\n" printf " Usage: $(basename $0) <options> " printf "\n" printf " -h => help dialog \n" printf " -stm => send test mail\n" printf " -mr => mail report \n" printf " -pr => print report \n" printf " -eprc => execute post report commands \n" printf " -m => monochrome output \n" printf " -si => show script information \n" printf "\n${Red} $1 ${Reset}\n" printf "\n" exit } #------------------------------------------------------------------------------------------------------------ script_information () { printf "\n" printf " Scriptname: $ScriptName\n" printf " Version: $Version \n" printf " Location: $(pwd)/$ScriptName\n" printf " Filesize: $(ls -lh $0 | cut -d " " -f5)\n" printf "\n" exit 0 } #------------------------------------------------------------------------------------------------------------------------------------------------ logfile_entry_filter () { # set unixtime beginn past period UnixtimePastValue=$(($(date +%s)-$FilterPeriod)) LogfileEntries=$(logfile_filter_service) LogfileEntriesCount=$( wc -l <<< $LogfileEntries) Counter=1 # ab Debian 10 => counter=1 # compare timestamp and print matched logfile line SAVEIFS=$IFS IFS=$(echo -en "\n\b") for LogEntry in $LogfileEntries ;do # skip counter for cron execution if [[ ! $CronExecution == true ]]; then printf "\r processing entry $Counter/$LogfileEntriesCount" >&2 Counter=$((Counter+1)) fi # skip Dec entries for turn of the year if [[ $TurOfTheYear == true ]] || [[ -n $( grep "^Jan " <<< $LogEntry ) ]]; then TurOfTheYear=true if [[ $( grep "^Dec " <<< $LogEntry ) ]]; then continue fi fi if [[ $UnixtimePastValue -lt $(date -d "$(echo $LogEntry | cut -d " " -f1-3)" +"%s") ]]; then # divider : third space to get time string,faster #if [[ $UnixtimePastValue -lt $(date -d "$(echo $LogEntry | sed 's/\([0-9]\{2\}:\)\{2\}[0-9]\{2\}.*$//')" +"%s") ]]; then # divider : "01:00:00" to get time string LogfileFilteredDateContent=$(echo -e "$LogfileFilteredDateContent \n $LogEntry") fi done IFS=$SAVEIFS # print logfile content for each filter string for SectionFilterLine in $SectionFilter ;do # filter log entries and write to proccessing var FinalLogfileContent=$(printf "$(echo "$LogfileFilteredDateContent" | grep $SectionFilterLine | sort -rnk1)") FinalLogfileContentRecaped=$(printf "$(echo "$LogfileFilteredDateContent" | grep $SectionFilterLine | sort -k4 | uniq -f3 -c | sort -rnk1)") # TODO uniq -f3 -c => uniq -f$VAR -c # set counter FinalLogfileContentCounter=$(echo "$FinalLogfileContent" | grep $SectionFilterLine | sed '/^ $/d' | grep -c .) FinalLogfileContentRecapedCounter=$(echo "$FinalLogfileContentRecaped" | grep $SectionFilterLine | sed '/^ $/d' | grep -c .) # set output sequence SummaryFirstLastEntryOnTop=$(echo $SummaryFirstLastEntryOnTop | sed 's/last/tee/' | sed 's/first/tac/') # print counter and logentries for each section expression filter if [[ $CountDuplicateLines == true ]] && [[ $RecapDuplicateLines == true ]]; then printf "$SummaryMessage [$SectionFilterLine] => $FinalLogfileContentRecapedCounter / $FinalLogfileContentCounter \n\n" printf "$FinalLogfileContentRecaped\n" | $SummaryFirstLastEntryOnTop | sed '/^$/d' elif [[ $CountDuplicateLines == true ]] && [[ $RecapDuplicateLines == false ]]; then printf "$SummaryMessage [$SectionFilterLine] => $FinalLogfileContentRecapedCounter / $FinalLogfileContentCounter \n\n" printf "$FinalLogfileContent\n" | $SummaryFirstLastEntryOnTop | sed '/^$/d' elif [[ $CountDuplicateLines == false ]] && [[ $RecapDuplicateLines == true ]]; then printf "$SummaryMessage [$SectionFilterLine] => $FinalLogfileContentRecapedCounter \n\n" printf "$FinalLogfileContentRecaped\n" | $SummaryFirstLastEntryOnTop | sed '/^$/d' elif [[ $CountDuplicateLines == false ]] && [[ $RecapDuplicateLines == false ]]; then printf "$SummaryMessage [$SectionFilterLine] => $FinalLogfileContentRecapedCounter \n\n" printf "$FinalLogfileContent\n" | $SummaryFirstLastEntryOnTop | sed '/^$/d' fi if [[ -n $FinalLogfileContent ]]; then printf "\n" fi done printf "End of Report \n\n " } #------------------------------------------------------------------------------------------------------------------------------------------------ ############################################################################################################ ############################################# start script ############################################# ############################################################################################################ #------------------------------------------------------------------------------------------------------------------------------------------------ # check for cronjob execution and cronjob options CronExecution= if [ -z $(grep "/" <<< "$(tty)") ]; then CronExecution=true Monochrome=true TERM=xterm-256color # TERM=linux export TERM fi #------------------------------------------------------------------------------------------------------------------------------------------------ # check for help dialog if [[ -z $1 ]] || [[ $1 == -h ]]; then usage ;fi #------------------------------------------------------------------------------------------------------------------------------------------------ # check for monochrome output if [[ -z $Monochrome ]]; then load_color_codes fi #------------------------------------------------------------------------------------------------------------------------------------------------ # check for script information if [[ -n $ScriptInformation ]]; then script_information ; fi #------------------------------------------------------------------------------------------------------------------------------------------------ # check for root permission if [ "$(whoami)" = "root" ]; then echo "";else echo "Are You Root ?";exit 1;fi #------------------------------------------------------------------------------------------------------------------------------------------------ # check input options if [[ -z $@ ]] || [[ $@ == -[hH] ]]; then usage "help dialog" ; fi if [[ -n $(grep stm <<< $@) ]]; then printf "execute: printf \"mail_log_report testmail on $(date) from $(hostname)\" | mail -s \"testmail\" $MailAddress \n" printf "mail_log_report testmail on $(date) from $(hostname)" | mail -s "testmail" $MailAddress exit fi if [[ $(grep -c . <<< $MailReport$PrintReport$ExecutePostReportCommands) == 0 ]]; then usage " missing options " fi #------------------------------------------------------------------------------------------------------------------------------------------------ # processing services ( service.<name> functions ) for service in $(cat $0 | grep "() {" | grep "^service\." | cut -d " " -f1 ); do # execute service section to set service vars $service printf "\n analyzing log files: $LogfileSource ($ServiceName) ... \n" # create ReportContent from filtered log entries and calculate counter ReportContent=$(logfile_entry_filter) # set summary counter CounterSummary=$(for SectionFilterLine in $SectionFilter ;do Counter=$(echo "$ReportContent" | grep -w "\[$SectionFilterLine\]" | awk -F "=>" '{printf $2}' | sed 's/ //g') printf "$SectionFilterLine $Counter, " done printf "\n\n" ) if [[ -n $MailReport ]]; then # set subject line MailSubjectLine="$MailSubjectLine $CounterSummary" # set mail summary header MailContentHeaderLine="$MailSubjectLine $(date -d "$FilterPeriod seconds ago" "+%F|%H:%M:%H") - $(date "+%F|%H:%M:%H")" # parse mail subject for shortnames for i in $MailSubjectLineSubstitutions ;do BaseExpression=$(echo $i | cut -d ";" -f1) OverwriteExpression=$(echo $i | cut -d ";" -f2) MailSubjectLine=$(echo "$MailSubjectLine" | sed 's/'$BaseExpression'/'$OverwriteExpression'/' ) done # send report via mail printf "$MailContentHeaderLine \n\n$ReportContent" | mail -a "Content-Type: text/plain" -s "$MailSubjectLine" $MailAddress fi if [[ -n $PrintReport ]]; then # print report only printf "\n\n$ReportContent" fi if [[ -n $ExecutePostReportCommands ]]; then # execute post report functions execute_post_report_command fi done #------------------------------------------------------------------------------------------------------------------------------------------------ exit 0 ------------------------------------------------------------------------------------------------------------ ############################################################################################################ ############################################## changelog ############################################### ############################################################################################################ #------------------------------------------------------------------------------------------------------------ #changelog 2.5 => 2.6 : add journald logfile analyzing for ssh deamon |
Fail2ban steuern
Fail2Ban nutzt eine eigene Logdatei ( /var/log/fail2ban.log ) in der alle relevanten Aktionen protokliert werden.
Der Status der verschiedenen Jails kann wie filgt abgerufen werden:
1 |
fail2ban-client status <jailname> |
IP-Adresse manuell entsperren:
Aufgrund welchen Jails die Adresse gesperrt wurde kann über die Fail2ban Logfiles auslesen werden :
1 |
cat /var/log/fail2ban.log | grep xxx.xxx.xxx.xxx |
Mit der Jail Information wird dann die IP Adresse mit dem Fail2ban Client entsperrt :
1 |
fail2ban-client set ssh unbanip xxx.xxx.xxx.xxx |
Alternativ kann die IP auch direkt über iptables wieder freigeben werden. Dazu wird die Iptables Chain und die Nummer der IP in der Chain benötigt :
1 |
iptables -L -n --line-numbers |
Hat man die betreffenden Informationen zu der IP gefunden wir die IP direkt über Iptables freigeben :
1 |
iptables -D fail2ban-ssh 1 |
by Speefak | www.my-it-brain.de | the-art-of-web.com | the-art-of-web.com | the-art-of-web.com | the-art-of-web.com | www.w2k.ch