Le scénario:
Dans un script bash, je dois vérifier si un mot de passe donné par un utilisateur est un mot de passe utilisateur valide.
Je suppose que j'ai un utilisateur A avec le mot de passe PA .. Dans le script, j'ai demandé à l'utilisateur A d'entrer son mot de passe, alors comment vérifier si la chaîne saisie est vraiment son mot de passe? ...
expect
au stackoverflow.com/a/1503831/320594 .Réponses:
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:
/etc/shadow
donne une partie de la solution.mkpasswd
commande présente dans Debian (et Ubuntu).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.
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
mkpasswd
utilitaire dont dépend ce script.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 lashadow
base de données, est donné comme argument de ligne de commandemkpasswd
, car c'est la seule façon dont l'utilitaire accepte un sel en entrée.Si
www-data
exécuter un code à n'importe quel compte d'utilisateur (par exemple, ), ou/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 lashadow
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:
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 queshadow
.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$
.$
, 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 sontlorsque ces données sont divisées en un tableau, en l'initialisant à partir de la
$(
)
substitution de commande non citée dans:lorsque le tableau est reconstitué en une chaîne à comparer au champ complet de
shadow
, l'"${ent[*]}"
expression dans: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.la source
Vous pouvez abuser
sudo
de cela.sudo
a la-l
possibilité de tester les privilèges sudo de l'utilisateur et-S
de lire le mot de passe depuis stdin. Cependant, quel que soit le niveau de privilège de l'utilisateur, s'il est authentifié avec succès,sudo
retourne avec l'état de sortie 0. Ainsi, vous pouvez prendre tout autre état de sortie comme indication que l'authentification n'a pas fonctionné (en supposantsudo
qu'il n'y ait pas de problèmes, comme erreurs d'autorisation ousudoers
configuration invalide ).Quelque chose comme:
Ce script dépend un peu de la
sudoers
configuration. J'ai supposé la configuration par défaut. Choses qui peuvent provoquer son échec:targetpw
ourunaspw
est définilistpw
estnever
D'autres problèmes incluent (merci Eliah):
/var/log/auth.log
sudo
doit être exécuté en tant qu'utilisateur pour lequel vous vous authentifiez. À moins que vous nesudo
disposiez de privilèges pour pouvoir exécutersudo -u foo sudo -lS
, cela signifie que vous devrez exécuter le script en tant qu'utilisateur cible.Maintenant, la raison pour laquelle j'ai utilisé here-docs est d'entraver l'écoute. Une variable utilisée dans le cadre de la ligne de commande est plus facilement révélée en utilisant
top
oups
ou d'autres outils pour inspecter les processus.la source
sudo
configurations inhabituelles (comme vous le dites) et des encombrements/var/log/auth.log
avec des enregistrements de chaque tentative, cela est rapide, simple et utilise un utilitaire existant, plutôt que de réinventer la roue (pour ainsi dire). Je suggère de définirIFS=
pourread
éviter les faux succès pour les entrées utilisateur remplies d'espaces blancs et les mots de passe non remplis, ainsi que les faux échecs pour les entrées utilisateur remplies d'espaces blancs et les mots de passe remplis. (Ma solution avait un bogue similaire.) Vous pouvez également expliquer comment il doit être exécuté en tant qu'utilisateur dont le mot de passe est vérifié.sudo -l
entraîne l'écriture d'une entrée avec "COMMAND=list
". Btw (sans rapport), bien qu'il ne soit pas objectivement préférable de le faire, l'utilisation d'une chaîne ici à la place d'un document ici atteint le même objectif de sécurité et est plus compacte. Puisque le script utilise déjà les bashismesread -s
et&>
, l'utilisationif sudo -lS &>/dev/null <<<"$PASSWD"; then
n'est pas moins portable. Je ne suggère pas que vous devriez changer ce que vous avez (c'est très bien). Je le mentionne plutôt pour que les lecteurs sachent qu'ils ont aussi cette option.sudo -l
quelque chose avait été désactivé - il s'agissait peut-être d'un rapport lorsqu'un utilisateur essayait d'exécuter une commande à laquelle il n'était pas autorisé.Une autre méthode (probablement plus intéressante pour son contenu théorique que pour ses applications pratiques).
Les mots de passe des utilisateurs sont stockés dans
/etc/shadow
.Les mots de passe stockés ici sont cryptés, dans les dernières versions d'Ubuntu utilisant
SHA-512
.Plus précisément, lors de la création du mot de passe, le mot de passe en texte clair est salé et chiffré
SHA-512
.Une solution serait alors de saler / chiffrer le mot de passe donné et de le faire correspondre avec le mot de passe de l'utilisateur chiffré stocké dans l'
/etc/shadow
entrée de l'utilisateur donné .Pour donner une ventilation rapide de la façon dont les mots de passe sont stockés dans chaque
/etc/shadow
entrée d' utilisateur , voici un exemple d'/etc/shadow
entrée pour un utilisateurfoo
avec mot de passebar
:foo
: Nom d'utilisateur6
: type de cryptage du mot de passelWS1oJnmDlaXrx1F
: sel de cryptage du mot de passeh4vuzZVBwIE1Z6vT7N.spwbxYig9e/OHOIH.VDv9JPaC3.OtTusPFzma7g.R/oSZFW5QOI7IDdDY01G0zTGQE/
:SHA-512
mot de passe salé / cryptéAfin de faire correspondre le mot
bar
de passe donné pour l'utilisateur donnéfoo
, la première chose à faire est d'obtenir le sel:Ensuite, on devrait obtenir le mot de passe complet salé / crypté:
Ensuite, le mot de passe donné peut être salé / chiffré et comparé au mot de passe de l'utilisateur salé / chiffré stocké dans
/etc/shadow
:Ils correspondent! Tout est mis dans un
bash
script:Production:
la source
sudo getent shadow
>>sudo grep ...
. Sinon, c'est bien. C'est ce à quoi je pensais à l'origine, puis je suis devenu trop paresseux.getent
+grep
+cut
>grep
+cut
getent
peut faire la recherche pour vous. J'ai pris la liberté d'éditer.mkpasswd
de générer un hachage à partir des entrées utilisateur et du sel existant (et inclus des fonctionnalités et des diagnostics supplémentaires), vous avez plutôt codé un simple programme Python implémentantmkpasswd
les fonctionnalités les plus importantes et utilisé cela. Je vous recommande de définirIFS=
lors de la lecture de l'entrée de mot de passe et de citer${password}
avec"
, afin que les tentatives de mot de passe avec des espaces ne cassent pas le script.