SSH bannissement

De EjnTricks
Révision de 16 mars 2018 à 13:26 par Etienne (discussion | contributions)

(diff) ← Version précédente | Voir la version courante (diff) | Version suivante → (diff)

Lors de l'ouverture d'une machine sur internet avec le protocole SSH, les attaques sont nombreuses. Cet article présente une règle personnalisée sous <code<Fail2ban</code> pour banir rapidement les tentatives d'intrusions sur des essais de connexions avec des comptes inexistants.


Hand-icon.png Votre avis

Nobody voted on this yet

 You need to enable JavaScript to vote


Study icon.png Etude

Par défaut, Fail2ban fournit une configuration sur les tentatives d'attaque sur ce protocole.

Dans le fichier jail.conf, dans le répertoire /etc/fail2ban pour une installation sous Ubuntu, les sections suivantes sont disponibles pour une installation en version 0.9.7.

[sshd]

# To use more aggressive sshd filter (inclusive sshd-ddos failregex):
#filter = sshd-aggressive
port    = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s


[sshd-ddos]
# This jail corresponds to the standard configuration in Fail2ban.
# The mail-whois action send a notification e-mail with a whois request
# in the body.
port    = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s

Par défaut, les configurations de bannissement sont dans le sous répertoire filter.d avec des fichiers portant le nom de la section. Pour la configuration sshd, la configuration est la suivante.

# 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+)?)?

# single line prefix:
__prefix_line_sl = %(__prefix_line)s%(__pref)s
# multi line prefixes (for first and second lines):
__prefix_line_ml1 = (?P<__prefix>%(__prefix_line)s)%(__pref)s
__prefix_line_ml2 = %(__suff)s$<SKIPLINES>^(?P=__prefix)%(__pref)s

mode = %(normal)s

normal = ^%(__prefix_line_sl)s[aA]uthentication (?:failure|error|failed) for .* from <HOST>( via \S+)?\s*%(__suff)s$
         ^%(__prefix_line_sl)sUser not known to the underlying authentication module for .* from <HOST>\s*%(__suff)s$
         ^%(__prefix_line_sl)sFailed \S+ for (?P<cond_inv>invalid user )?(?P<user>(?P<cond_user>\S+)|(?(cond_inv)(?:(?! from ).)*?|[^:]+)) from <HOST>%(__on_port_opt)s(?: ssh\d*)?(?(cond_user): |(?:(?:(?! from ).)*)$)
         ^%(__prefix_line_sl)sROOT LOGIN REFUSED.* FROM <HOST>\s*%(__suff)s$
         ^%(__prefix_line_sl)s[iI](?:llegal|nvalid) user .*? from <HOST>%(__on_port_opt)s\s*$
         ^%(__prefix_line_sl)sUser .+ from <HOST> not allowed because not listed in AllowUsers\s*%(__suff)s$
         ^%(__prefix_line_sl)sUser .+ from <HOST> not allowed because listed in DenyUsers\s*%(__suff)s$
         ^%(__prefix_line_sl)sUser .+ from <HOST> not allowed because not in any group\s*%(__suff)s$
         ^%(__prefix_line_sl)srefused connect from \S+ \(<HOST>\)\s*%(__suff)s$
         ^%(__prefix_line_sl)sReceived disconnect from <HOST>%(__on_port_opt)s:\s*3: .*: Auth fail%(__suff)s$
         ^%(__prefix_line_sl)sUser .+ from <HOST> not allowed because a group is listed in DenyGroups\s*%(__suff)s$
         ^%(__prefix_line_sl)sUser .+ from <HOST> not allowed because none of user's groups are listed in AllowGroups\s*%(__suff)s$
         ^%(__prefix_line_sl)spam_unix\(sshd:auth\):\s+authentication failure;\s*logname=\S*\s*uid=\d*\s*euid=\d*\s*tty=\S*\s*ruser=\S*\s*rhost=<HOST>\s.*%(__suff)s$
         ^%(__prefix_line_sl)s(error: )?maximum authentication attempts exceeded for .* from <HOST>%(__on_port_opt)s(?: ssh\d*)? \[preauth\]$
         ^%(__prefix_line_ml1)sUser .+ not allowed because account is locked%(__prefix_line_ml2)sReceived disconnect from <HOST>: 11: .+%(__suff)s$
         ^%(__prefix_line_ml1)sDisconnecting: Too many authentication failures for .+?%(__prefix_line_ml2)sConnection closed by <HOST>%(__suff)s$
         ^%(__prefix_line_ml1)sConnection from <HOST>%(__on_port_opt)s%(__prefix_line_ml2)sDisconnecting: Too many authentication failures for .+%(__suff)s$

ddos =   ^%(__prefix_line_sl)sDid not receive identification string from <HOST>%(__suff)s$
         ^%(__prefix_line_sl)sReceived disconnect from <HOST>%(__on_port_opt)s:\s*14: No supported authentication methods available%(__suff)s$
         ^%(__prefix_line_sl)sUnable to negotiate with <HOST>%(__on_port_opt)s: no matching (?:cipher|key exchange method) found.
         ^%(__prefix_line_ml1)sConnection from <HOST>%(__on_port_opt)s%(__prefix_line_ml2)sUnable to negotiate a (?:cipher|key exchange method)%(__suff)s$
         ^%(__prefix_line_ml1)sSSH: Server;Ltype: (?:Authname|Version|Kex);Remote: <HOST>-\d+;[A-Z]\w+:.*%(__prefix_line_ml2)sRead from socket failed: Connection reset by peer%(__suff)s$

aggressive = %(normal)s
             %(ddos)s

[Definition]

failregex = %(mode)s

ignoreregex =

[Init]

# "maxlines" is number of log lines to buffer for multi-line regex searches
maxlines = 10

journalmatch = _SYSTEMD_UNIT=sshd.service + _COMM=sshd

# 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

Pour la configuration sshd-ddos, celle-ci est une extension de la précédente afin d'activer le mode ddos.

# Fail2Ban ssh filter for at attempted exploit
#
# The regex here also relates to a exploit:
#
#  http://www.securityfocus.com/bid/17958/exploit
#  The example code here shows the pushing of the exploit straight after
#  reading the server version. This is where the client version string normally
#  pushed. As such the server will read this unparsible information as
#  "Did not receive identification string".

[INCLUDES]

before = sshd.conf

[Definition]

mode = %(ddos)s

Il suffit de s'inspirer de cette organisation pour créer une règle spécifique.


Icon-Configuration-Settings.png Configuration

Add-icon.png Ajout bannissement

La première étape consiste à référencer le nouveau bannissement. Pour cette règle, il n'est pas souhaité de laisser beaucoup de chance aux attaques et dès la première tentative elle doit se déclencher.

Un nouveau fichier sshd-invalid-user.local est créé dans le sous répertoire jail.d avec le contenu suivant.

[sshd-invalid-user]
enabled  = true
bantime  = 21600
maxretry = 1
port     = ssh
logpath  = %(sshd_log)s
backend  = %(sshd_backend)s

La durée de bannissement est configurée à 6 heures, valeur 21600 dans bantime, et la variable sshd_log est utilisée pour référencer l'emplacement des fichier traces à vérifier comme dans les configurations fournies.

Process-icon.png Définition règle

La seconde étape consiste à définir les règles de déclenchement du bannissement. Un fichier est le nom sshd-invalid-user.conf, contenant le nom du bannissement, est ajouté dans le sous répertoire filter.d.

Afin d'identifier les tentatives d'intrusion avec des comptes "génériques", il suffit de regarder les message du type Failed password for USER_TEST ... ou Invalid user USER_TEST. La syntax de ces règles sont déjà disponibles dans les configurations standards et il suffit de les recopier.

La possibilité d'extension est utilisée pour limiter les configurations à mettre en place. Ainsi, seul un nouveau mode invalid-user est configuré puis activé dans la configuration fournie par sshd.conf en spécifiant la valeur de mode. Le contenu du fichier est le suivant.

# Fail2Ban ssh filter for invalid user.
#

[INCLUDES]

before = sshd.conf

[DEFAULT]

invalid-user = ^%(__prefix_line_sl)sFailed \S+ for (?P<cond_inv>invalid user )?(?P<user>(?P<cond_user>\S+)|(?(cond_inv)(?:(?! from ).)*?|[^:]+)) from <HOST>%(__on_port_opt)s(?: ssh\d*)?(?(cond_user): |(?:(?:(?! from ).)*)$)
               ^%(__prefix_line_sl)s[iI](?:llegal|nvalid) user .*? from <HOST>%(__on_port_opt)s\s*$

[Definition]

mode = %(invalid-user)s


Run-icon.png Test

Avant d'activer la nouvelle règle, il est possible de la tester à l'aide de la commande fail2ban-regex.

#sudo fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd-invalid-user.conf

Running tests
=============

Use   failregex filter file : sshd-invalid-user, basedir: /etc/fail2ban
Use         maxlines : 10
Use         log file : /var/log/auth.log
Use         encoding : UTF-8


Results
=======

Failregex: 2043 total
|-  #) [# of hits] regular expression
|   1) [1666] ^(?:\[\])?\s*(?:<[^.]+\.[^.]+>\s+)?(?:\S+\s+)?(?:kernel: \[ *\d+\.\d+\]\s+)?(?:@vserver_\S+\s+)?(?:(?:(?:\[\d+\])?:\s+[\[\(]?sshd(?:\(\S+\))?[\]\)]?:?|[\[\(]?sshd(?:\
(\S+\))?[\]\)]?:?(?:\[\d+\])?:?)\s+)?(?:\[ID \d+ \S+\]\s+)?(?:(?:error|fatal): (?:PAM: )?)?Failed \S+ for (?P<cond_inv>invalid user )?(?P<user>(?P<cond_user>\S+)|(?(cond_inv)(?:(?! from 
).)*?|[^:]+)) from <HOST>(?: port \d+)?(?: on \S+(?: port \d+)?)?(?: ssh\d*)?(?(cond_user): |(?:(?:(?! from ).)*)$)
|   2) [377] ^(?:\[\])?\s*(?:<[^.]+\.[^.]+>\s+)?(?:\S+\s+)?(?:kernel: \[ *\d+\.\d+\]\s+)?(?:@vserver_\S+\s+)?(?:(?:(?:\[\d+\])?:\s+[\[\(]?sshd(?:\(\S+\))?[\]\)]?:?|[\[\(]?sshd(?:\(\S+\))?
[\]\)]?:?(?:\[\d+\])?:?)\s+)?(?:\[ID \d+ \S+\]\s+)?(?:(?:error|fatal): (?:PAM: )?)?[iI](?:llegal|nvalid) user .*? from <HOST>(?: port \d+)?(?: on \S+(?: port \d+)?)?\s*$
`-

Ignoreregex: 0 total

Date template hits:
|- [# of hits] date format
|  [9603] (?:DAY )?MON Day 24hour:Minute:Second(?:\.Microseconds)?(?: Year)?
`-

Lines: 9603 lines, 0 ignored, 2043 matched, 7560 missed
[processed in 3.09 sec]

Missed line(s): too many to print.  Use --print-all-missed to print all 7560 lines


Update icon.png Activation

Une fois validée, il suffit d'activer la règle à l'aide de la commande fail2ban-client avec l'argument reload.

#sudo fail2ban-client reload