Sections du handbook

Contrôler l'accès à cron et at

Revu le

Les tâches planifiées sont le moyen préféré d'un attaquant pour rester. Verrouillez qui peut utiliser cron et at avec une liste d'autorisation en interdiction par défaut pour qu'un pied dans la place ne se transforme pas en persistance silencieuse.

La menace : les tâches planifiées sont une persistance clé en main

Déposer du code sur une machine n'est que la première étape pour un attaquant ; y rester est le vrai but. Les tâches planifiées sont le mécanisme de persistance classique : présentes sur chaque machine Linux, elles survivent aux redémarrages et s'exécutent toutes seules, sans personne connecté. La technique MITRE ATT&CK T1053.003 (Scheduled Task/Job: Cron) décrit exactement cela : poser une entrée crontab ou un job at, et la charge utile se relance chaque minute, à chaque redémarrage, indéfiniment.

Le danger est amplifié par la permissivité des réglages par défaut. Sur beaucoup de systèmes, tout utilisateur peut écrire un crontab tant qu'une liste d'autorisation ne dit pas le contraire. Si l'accès à cron et at est grand ouvert, un compte peu privilégié compromis (un service web, un runner CI, un login développeur oublié) peut planifier un beacon ou un job de réinfection que personne ne surveille. Un modèle fondé sur cron.deny aggrave les choses : il ne bloque que les utilisateurs nommés, donc tout compte oublié est implicitement autorisé.

Pourquoi le durcir

La planification de tâches est un privilège qui doit être accordé, pas présumé. Inversez le défaut : passez de tout le monde peut planifier à seul un ensemble de comptes explicite et auditable peut planifier. Cela supprime un chemin de persistance clé en main de chaque compte de service compromis, réduit l'ensemble des identités capables d'exécuter du code sans surveillance, et transforme la planification en une décision explicite et révisable plutôt qu'en effet de bord du simple fait d'avoir un shell. La plupart des utilisateurs ordinaires n'en ont jamais besoin : la liste d'autorisation est donc en général courte, et un cron.allow présent mais vide est une posture parfaitement valide et très solide.

Comment fonctionne la logique allow/deny ?

La décision est allow d'abord, et la présence de cron.allow change tout :

État des fichiers Qui peut utiliser cron
cron.allow existe seuls les utilisateurs qui y sont listés (cron.deny est ignoré)
seul cron.deny existe tout le monde sauf les utilisateurs listés (fail-open)
aucun n'existe dépend de la distribution : root seul (Debian) ou tout le monde (autres)

La posture durcie est donc : créer cron.allow (avec root et les rares comptes qui en ont besoin) et supprimer cron.deny. at utilise la logique identique avec at.allow / at.deny. Notez qu'une liste d'autorisation contrôle les crontabs utilisateur (crontab -e) ; le crontab système (/etc/crontab, /etc/cron.d, /etc/cron.daily...) s'exécute quoi qu'il arrive, raison pour laquelle leurs permissions comptent tout autant.

Comment le mettre en place ?

# cron : liste d'autorisation explicite, suppression de la deny-list fail-open
echo root > /etc/cron.allow
chown root:root /etc/cron.allow && chmod 600 /etc/cron.allow
rm -f /etc/cron.deny

# at : même modèle
echo root > /etc/at.allow
chown root:root /etc/at.allow && chmod 600 /etc/at.allow
rm -f /etc/at.deny

# verrouiller la surface cron système (root uniquement)
chown root:root /etc/crontab /etc/cron.d /etc/cron.{hourly,daily,weekly,monthly}
chmod 600 /etc/crontab && chmod 700 /etc/cron.d /etc/cron.{hourly,daily,weekly,monthly}

Ce que Pavois audite : l'état réel du système de fichiers

Le domaine Contrôle d'accès cron/at de Pavois applique le modèle d'interdiction par défaut sur le système en fonctionnement :

  • file-cron-allow-exists : /etc/cron.allow doit exister (cron en mode liste d'autorisation, pas le défaut permissif).
  • file-at-allow-exists : /etc/at.allow doit exister, même modèle pour at/batch.
  • file-cron-deny-absent : /etc/cron.deny ne doit pas exister, pour supprimer la deny-list fail-open.
  • file-at-deny-absent : /etc/at.deny ne doit pas exister, même raison côté at.

Chaque contrôle inspecte l'état réel du système de fichiers avec file(...) { should exist / should_not exist } d'InSpec, de sorte que le verdict reflète ce que cron et at lisent réellement à l'exécution. Les vérifications complémentaires de propriété et de permissions sur /etc/cron.allow, les répertoires cron.{d,daily,hourly} et les fichiers crontab résident dans les domaines permissions et propriété de Pavois, garantissant que la politique d'accès ne peut pas être altérée par les utilisateurs qu'elle restreint.

Vérifier

ls -l /etc/cron.allow /etc/at.allow      # present, root:root, 0600
ls /etc/cron.deny /etc/at.deny 2>&1      # doit indiquer 'No such file'
stat -c '%a %U' /etc/crontab /etc/cron.d # 600/700, root
# en tant qu'utilisateur non liste, ceci doit etre refuse :
sudo -u nobody crontab -e

Pièges

  • Un cron.allow vide refuse tout le monde, administrateurs compris, pour les crontabs utilisateur. C'est voulu ; mettez-y root (et tout compte de planification réel). Le cron système (/etc/cron.d, /etc/crontab) tourne toujours.
  • cron.allow l'emporte sur cron.deny : lister un utilisateur dans les deux l'autorise. Ne comptez pas sur deny une fois allow présent.
  • Supprimer cron.deny sans créer cron.allow peut, sur certaines distributions, retomber sur tout le monde autorisé. Créez d'abord la liste d'autorisation.
  • La liste d'autorisation n'inspecte pas le contenu des jobs : elle contrôle qui peut planifier, pas quoi. Couplez-la à la surveillance des répertoires cron.

FAQ

cron.allow ou cron.deny ? cron.allow. C'est de l'interdiction par défaut (seuls les utilisateurs listés), alors que cron.deny est fail-open (tout compte non nommé est autorisé), donc un compte oublié passe au travers.

Un cron.allow vide arrête-t-il les tâches cron système ? Non. /etc/crontab et /etc/cron.d tournent quand même ; la liste d'autorisation ne contrôle que le crontab par utilisateur. Verrouillez les fichiers système par les permissions.

Pourquoi Pavois vérifie-t-il l'existence des fichiers, pas une valeur de config ? Parce que cron/at décident de l'accès uniquement selon l'existence de ces fichiers et qui ils listent ; le système de fichiers vivant est la politique.