Puisque vous voulez le faire dans un script shell, quelques contributions dans Comment vérifier le mot de passe avec Linux? (sur Unix.SE , suggéré par AB ) sont particulièrement pertinents:
Pour vérifier manuellement si une chaîne est vraiment le mot de passe d'un utilisateur, vous devez la hacher avec le même algorithme de hachage que dans l'entrée reflet de l'utilisateur, avec le même sel que dans l'entrée reflet de l'utilisateur. Ensuite, il peut être comparé au hachage de mot de passe qui y est stocké.
J'ai écrit un script complet et fonctionnel montrant comment procéder.
- Si vous le nommez
chkpass
, vous pouvez l'exécuter et il lira une ligne à partir de l'entrée standard et vérifiera s'il s'agit du mot de passe.chkpass user
user
- Installez le package whois pour obtenir l'
mkpasswd
utilitaire dont dépend ce script.
- Ce script doit être exécuté en tant que root pour réussir.
- Avant d'utiliser ce script ou une partie de celui-ci pour effectuer un travail réel, veuillez consulter les notes de sécurité ci-dessous.
#!/usr/bin/env bash
xcorrect=0 xwrong=1 enouser=2 enodata=3 esyntax=4 ehash=5 IFS=$
die() {
printf '%s: %s\n' "$0" "$2" >&2
exit $1
}
report() {
if (($1 == xcorrect))
then echo 'Correct password.'
else echo 'Wrong password.'
fi
exit $1
}
(($# == 1)) || die $esyntax "Usage: $(basename "$0") <username>"
case "$(getent passwd "$1" | awk -F: '{print $2}')" in
x) ;;
'') die $enouser "error: user '$1' not found";;
*) die $enodata "error: $1's password appears unshadowed!";;
esac
if [ -t 0 ]; then
IFS= read -rsp "[$(basename "$0")] password for $1: " pass
printf '\n'
else
IFS= read -r pass
fi
set -f; ent=($(getent shadow "$1" | awk -F: '{print $2}')); set +f
case "${ent[1]}" in
1) hashtype=md5;; 5) hashtype=sha-256;; 6) hashtype=sha-512;;
'') case "${ent[0]}" in
\*|!) report $xwrong;;
'') die $enodata "error: no shadow entry (are you root?)";;
*) die $enodata 'error: failure parsing shadow entry';;
esac;;
*) die $ehash "error: password hash type is unsupported";;
esac
if [[ "${ent[*]}" = "$(mkpasswd -sm $hashtype -S "${ent[2]}" <<<"$pass")" ]]
then report $xcorrect
else report $xwrong
fi
Notes de sécurité
Ce n'est peut-être pas la bonne approche.
La question de savoir si une approche comme celle-ci doit être considérée comme sûre et appropriée dépend des détails de votre cas d'utilisation que vous n'avez pas fournis (au moment de la rédaction de ce document).
Il n'a pas été vérifié.
Bien que j'aie essayé d'être prudent lors de l'écriture de ce script, il n'a pas été correctement audité pour les failles de sécurité . Il est conçu comme une démonstration et serait un logiciel "alpha" s'il était publié dans le cadre d'un projet. En outre...
Un autre utilisateur qui "regarde" peut découvrir le sel de l'utilisateur .
En raison des limites dans la façon dont les mkpasswd
données de sel sont acceptées , ce script contient une faille de sécurité connue , que vous pouvez ou non considérer comme acceptable selon le cas d'utilisation. Par défaut, les utilisateurs d'Ubuntu et de la plupart des autres systèmes GNU / Linux peuvent afficher des informations sur les processus exécutés par d'autres utilisateurs (y compris root), y compris leurs arguments de ligne de commande. Ni l'entrée de l'utilisateur ni le hachage de mot de passe stocké ne sont transmis en tant qu'argument de ligne de commande à un utilitaire externe. Mais le sel , extrait de la shadow
base de données, est donné comme argument de ligne de commande mkpasswd
, car c'est la seule façon dont l'utilitaire accepte un sel en entrée.
Si
- un autre utilisateur du système, ou
- toute personne ayant la capacité de faire
www-data
exécuter un code à n'importe quel compte d'utilisateur (par exemple, ), ou
- toute personne qui autrement peut afficher des informations sur les processus en cours (y compris en inspectant manuellement les entrées dans
/proc
)
est en mesure de vérifier les arguments de la ligne de commande mkpasswd
lorsqu'il est exécuté par ce script, puis ils peuvent obtenir une copie du sel de l'utilisateur à partir de la shadow
base de données. Ils peuvent devoir deviner quand cette commande est exécutée, mais c'est parfois réalisable.
Un attaquant avec votre sel n'est pas aussi mauvais qu'un attaquant avec votre sel et votre haschisch , mais ce n'est pas idéal. Le sel ne fournit pas suffisamment d'informations pour que quelqu'un découvre votre mot de passe. Mais cela permet à quelqu'un de générer des tables arc-en-ciel ou des hachages de dictionnaire pré-calculés spécifiques à cet utilisateur sur ce système. Cela ne vaut initialement rien, mais si votre sécurité est compromise à une date ultérieure et que le hachage complet est obtenu, il pourrait ensuite être craqué plus rapidement pour obtenir le mot de passe de l'utilisateur avant qu'il ne puisse le changer.
Ainsi, cette faille de sécurité est un facteur aggravant dans un scénario d'attaque plus complexe plutôt qu'une vulnérabilité pleinement exploitable. Et vous pourriez considérer la situation ci-dessus comme tirée par les cheveux. Mais je suis réticent à recommander une méthode pour une utilisation générale dans le monde réel qui fuit toutes les données non publiques d' /etc/shadow
un utilisateur non root.
Vous pouvez éviter complètement ce problème en:
- écrire une partie de votre script en Perl ou dans un autre langage qui vous permet d'appeler des fonctions C, comme indiqué dans la réponse de Gilles à la question Unix.SE connexe , ou
- écrire tout votre script / programme dans un tel langage, plutôt que d'utiliser bash. (Selon la façon dont vous avez marqué la question, il semble que vous préfériez utiliser bash.)
Faites attention à la façon dont vous appelez ce script.
Si vous autorisez un utilisateur non fiable à exécuter ce script en tant que root ou à exécuter un processus en tant que root qui appelle ce script, soyez prudent . En modifiant l'environnement, ils peuvent faire en sorte que ce script - ou tout script qui s'exécute en tant que root - fasse n'importe quoi . À moins que vous ne puissiez empêcher cela, vous ne devez pas accorder aux utilisateurs des privilèges élevés pour exécuter des scripts shell.
Voir 10.4. Langages de script Shell (dérivés sh et csh) dans le guide de programmation sécurisée de David A. Wheeler pour Linux et Unix pour plus d'informations à ce sujet. Bien que sa présentation se concentre sur les scripts setuid, d'autres mécanismes peuvent être la proie de certains des mêmes problèmes s'ils ne désinfectent pas correctement l'environnement.
Autres notes
Il prend en charge la lecture des hachages à partir de la shadow
base de données uniquement.
Les mots de passe doivent être masqués pour que ce script fonctionne (c'est-à-dire que leurs hachages doivent être dans un /etc/shadow
fichier séparé que seul root peut lire, pas dans /etc/passwd
).
Cela devrait toujours être le cas dans Ubuntu. Dans tous les cas, si nécessaire, le script peut être étendu de manière triviale pour lire les hachages de mot de passe passwd
ainsi que shadow
.
Gardez IFS
à l'esprit lorsque vous modifiez ce script.
J'ai défini IFS=$
au début, car les trois données du champ de hachage d'une entrée fantôme sont séparées par $
.
- Ils ont également un leader
$
, c'est pourquoi le type de hachage et le sel sont "${ent[1]}"
et "${ent[2]}"
plutôt que "${ent[0]}"
et "${ent[1]}"
, respectivement.
Les seuls endroits dans ce script où $IFS
détermine la façon dont le shell divise ou combine les mots sont
lorsque ces données sont divisées en un tableau, en l'initialisant à partir de la $(
)
substitution de commande non citée dans:
set -f; ent=($(getent shadow "$1" | awk -F: '{print $2}')); set +f
lorsque le tableau est reconstitué en une chaîne à comparer au champ complet de shadow
, l' "${ent[*]}"
expression dans:
if [[ "${ent[*]}" = "$(mkpasswd -sm $hashtype -S "${ent[2]}" <<<"$pass")" ]]
Si vous modifiez le script et faites-le effectuer la division (ou la jonction de mots) dans d'autres situations, vous devrez définir IFS
des valeurs différentes pour différentes commandes ou différentes parties du script.
Si vous ne gardez pas cela à l'esprit et supposez qu'il $IFS
est défini sur l'espace blanc habituel ( $' \t\n'
), vous pourriez finir par faire en sorte que votre script se comporte de manière assez étrange.