blog/pages/network-security.html Pelicanux

Débusquons les mythes cybersécurité !

De nombreux responsables sécurité interdisent la connexion SSH à partir du login root. Nous allons voir dans cet article en quoi cette mesure de sécurité reste en réalité trop souvent incomprise, et en profiter pour initier la catégories cargo cult security, inspirée de l’expression Cargo Cult Programming en l’adaptant à la cyber-sécurité.

Interdire la connexion SSH à partir de l’utilisateur root

La variable permitRootLogin accepte les valeurs suivantes :

PermitRootLogin 
   no (interdiction) ou yes (autorisation)
   without-password (obsolète) ou prohibit-password
   forced-commands-only (c'est la meilleure option en fait)

À noter la valeur without-password trompeuse, puisqu’elle interdit en réalité la connexion à partir d’un mot de passe. La valeur prohibit-password, plus claire, la déprécie désormais.

Les justifications apportées se résument généralement aux arguments suivants :

  • Le login root étant prédictible, l’attaquant peut tenter de deviner son mot de passe et passe ainsi d’une complexité n2 à n,
  • L’attaquant disposerait directement des pleins pouvoir,
  • Perte de traçabilité, puisqu’il n’est plus évident de faire correspondre root à l’utilisateur se connectant.

Et donc, nos ‘‘experts en sécurité’’ choisissent de durcir la configuration SSH de la façon suivante :

PermitRootLogin no

À noter à titre d’exemple le man oscap-ssh :

Note that the openscap scanner is best run by the root user as in the first example above. To do this, the PermitRootLogin directive must be enabled in /etc/ssh/sshd_config, which is itself a security violation. A safer approach is to enable a non-privileged user (oscap-user in the second example above) to run only the oscap binary as root (with the --sudo flag) by updating the remote machine’s sudoers file or adding a file like /etc/sudoers.d/99-oscap-user:

Defaults!/usr/bin/oscap !requiretty oscap-user ALL=(root) NOPASSWD: /usr/bin/oscap

Parfait ! Qu’on m’explique en quoi une règle sudo potentiellement dangeureuse reste mieux qu’un PermitRootLogin=forced-commands-only

Mais nos ‘‘experts en sécurité’’ vivent heureux.

Et nous, on va quand même avoir des problèmes.

Pourquoi ça ne marche pas

Techniquement, cela permet pourtant de respecter le cahier des charges : Plus de connexion directe à partir de l’utilisateur root, donc :

  • Plus difficile à bruteforcer, il faut désormais déterminer un utilisateur valide en plus du mot de passe,
  • L’attaquant ayant néanmoins réussi à déterminer un couple {utilisateur} ↔ {mot de passe} valide ne dispose donc que d’un compte sans privilège,
  • La configuration permet la traçabilité.

Cependant, ces arguments sont déjà fragiles :

  • Un mot de passe de 6 caractères alphanumériques aléatoires (pas non plus la politique la plus robuste) nécessite quand même, à supposer un bruteforce de 10 essais par secondes (donc une bonne latence pour l’attaquant) (26 + 26 + 10)6 / 10 secondes pour atteindre l’ensemble de l’espace, soit environ 180 ans…
  • Si l’attaquant découvre le mot de passe associé au login nominatif de l’administrateur, ben… il est administrateur ! Il lui suffira de backdoorer son bashrc pour récupérer le mot de passe sudo ou su !

À noter : L’authentification par mot de passe reste intrinsèquement fragile !

Les scripts, robots, et administrateurs peu sensibilisés ne vérifient jamais ces empreintes. Pensez notamment aux scripts et tâches planifiées lancées avec StrictHostKeyChecking=no ou KnownHostsFile=/dev/null.

Un attaquant présent sur le réseau pouvant réaliser un man-in-the-middle obtiendra ce mot de passe.

Voir le très bon article gremwell - MITM SSH qui démontre d’ailleurs que l’authentification par clef interdit complètement le MITM.

Mais à l’extrême, si interdir le SSH pour l’utilisateur root permet de faire plaisir à nos ‘‘experts sécurité’’ et de passer à autre chose, cela pourrait constituer un compromis acceptable. En réalité, les effets de bords sont pires que le mal.

Des effets de bords imprévus

J’ai dû m’attacher à la configuration rsync pour permettre de réaliser un plan de restauration. J'en ai profité pour rédiger cet article : rsync magic command. L’idée consiste à utiliser une clef SSH tagguée pour imposer l’ouverture du démon rsync dans un tunnel SSH et à réaliser le transfert via SSH, bénéficiant ainsi du chiffrement des données transférées et d’une authentification solide par clef SSH. Cependant, pour respecter l’interdiction de connexion en root, j’ai dû utiliser un utilisateur sans privilèges.

La configuration ressemblait alors à ceci :

uid = youruser
gid = youruser
use chroot = no
read only = no
max connections = 2
log file = /tmp/rsyncd.log
pid file = /tmp/rsyncd.pid

[module1]
    path = /home/youruser/upload_target
    comment = Restricted upload area
    auth users = fakeuser

J’obtenais le message d’erreur suivant dans le fichier /tmp/rsyncd.log :

rsync: [Receiver] setgroups failed: Operation not permitted (1)

Cette erreur survient parce que :

  • Le processus rsync tente de droper ses privilèges,
  • Mais il n’a pas le droit pour cela ; puisque la capability associée n’est permise qu’à l’utilisateur root.

La solution consiste alors à exécuter rsync en sudo !

# clef SSH tagguée
command="sudo /usr/bin/rsync --server --daemon --config=/home/myuser/rsyncd.conf" ssh-rsa ...

# Configuration sudo
myuser ALL=(ALL) NOPASSWD: /usr/bin/rsync

Super ! Maintenant, au lieu d’avoir un transfert de fichiers protégé par clef, j’ai un utilisateur jusque là non-privilégié mais pouvant désormais utiliser rsync à loisir sur la machine ; L’élévation de privilège s’obtient rapidement (cf. Cette réponse très complête sur stackoverflow.).

% sudo rsync --perms --chmod u+s /bin/dash /bin/rootdash
% rootdash
# whoami
root

À retenir : À chaque fois que vous devez renseigner sudo pour une tâche automatique ou périodique, vous faites une erreur !

Comment travailler proprement

De très nombreux outils, scripts de sauvegarde / restauration, tâches planifiées de transfert de fichiers, supervision, etc. nécessitent parfois de se connecter à partir de l’utilisateur root.

Et c’est normal !

Plutôt que l’interdire de manière dogmatique, et ouvrir par effet de bord des brêches critiques dans la configuration sudo, il est préférable de paramétrer pour chaque besoin une clef SSH tagguée et déclencher l’action sur cette clef :

PermitRootLogin forced-commands-only

La clef tagguée permet de restreindre à des jeux atomiques d’actions unitaires dont l’administrateur doit pouvoir déterminer si elles présentent un danger ou non.

La pratique d’interdire la connexion à root implique de configurer un utilisateur sans privilège, de lui associer des scripts de post-exécution, pour déplacer les fichiers synchronisés par exemple dans un autre répertoire, de changer les permissions et les ownerships, etc. in fine de réaliser un grand nombre de tâches toutes plus à risques puisqu’impliquant une élévation et la transmission de données potentiellement sensibles à des utilisateurs non-privilégiés.