Como desea hacer esto en un script de shell, ¿hay un par de contribuciones en Cómo verificar la contraseña con Linux? (en Unix.SE , sugerido por AB ) son especialmente relevantes:
Para verificar manualmente si una cadena es realmente la contraseña de algún usuario, debe hacer un hash con el mismo algoritmo hash que en la entrada de sombra del usuario, con la misma sal que en la entrada de sombra del usuario. Luego se puede comparar con el hash de contraseña almacenado allí.
He escrito un guión completo y funcional que demuestra cómo hacer esto.
- Si lo nombra
chkpass
, puede ejecutarlo y leerá una línea de entrada estándar y comprobará si es la contraseña.chkpass user
user
- Instale el paquete whois para obtener la
mkpasswd
utilidad de la que depende este script.
- Este script debe ejecutarse como root para tener éxito.
- Antes de usar este script o cualquier parte del mismo para hacer un trabajo real, consulte las Notas de seguridad a continuación.
#!/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
Notas de seguridad
Puede que no sea el enfoque correcto.
El hecho de que un enfoque como este se considere seguro y apropiado depende de los detalles sobre su caso de uso que no haya proporcionado (a partir de este escrito).
No ha sido auditado.
Aunque he tratado de tener cuidado al escribir este script, no ha sido auditado adecuadamente por vulnerabilidades de seguridad . Se pretende que sea una demostración, y sería un software "alfa" si se lanza como parte de un proyecto. Además...
Otro usuario que está "mirando" puede descubrir la sal del usuario .
Debido a las limitaciones en la forma en que mkpasswd
acepta los datos de sal, este script contiene una falla de seguridad conocida , que puede considerar aceptable o no según el caso de uso. Por defecto, los usuarios de Ubuntu y la mayoría de los otros sistemas GNU / Linux pueden ver información sobre los procesos ejecutados por otros usuarios (incluida la raíz), incluidos sus argumentos de línea de comandos. Ni la entrada del usuario ni el hash de contraseña almacenado se pasan como argumento de línea de comandos a ninguna utilidad externa. Pero la sal , extraída de la shadow
base de datos, se proporciona como un argumento de línea de comandos mkpasswd
, ya que esta es la única forma en que la utilidad acepta una sal como entrada.
Si
- otro usuario en el sistema, o
- cualquier persona que tenga la capacidad de hacer cualquier cuenta de usuario (por ejemplo,
www-data
) ejecutar su código, o
- cualquiera que pueda ver información sobre procesos en ejecución (incluso mediante la inspección manual de entradas
/proc
)
es capaz de verificar los argumentos de la línea de comandos mkpasswd
según lo ejecuta este script, luego pueden obtener una copia de la sal del usuario de la shadow
base de datos. Es posible que tengan que ser capaces de adivinar cuándo se ejecuta ese comando, pero eso a veces es posible.
Un atacante con su sal no es tan malo como un atacante con su sal y hachís , pero no es lo ideal. La sal no proporciona suficiente información para que alguien descubra su contraseña. Pero sí permite que alguien genere tablas de arco iris o hash de diccionario precalculados específicos para ese usuario en ese sistema. Inicialmente, esto no tiene valor, pero si su seguridad se ve comprometida en una fecha posterior y se obtiene el hash completo, se podría descifrar más rápidamente para obtener la contraseña del usuario antes de que tenga la oportunidad de cambiarla.
Por lo tanto, esta falla de seguridad es un factor exacerbador en un escenario de ataque más complejo en lugar de una vulnerabilidad totalmente explotable. Y podría considerar la situación anterior exagerada. Pero soy reacio a recomendar cualquier método para uso general en el mundo real que filtre cualquier información no pública de /etc/shadow
un usuario no root.
Puede evitar este problema por completo:
- escribiendo parte de su script en Perl o algún otro lenguaje que le permite llamar a funciones de C, tal como se muestra en la respuesta de Gilles de la cuestión relacionada Unix.SE , o
- escribir todo su script / programa en dicho lenguaje, en lugar de usar bash. (Según la forma en que ha etiquetado la pregunta, parece que prefiere usar bash).
Ten cuidado con cómo llamas a este script.
Si permite que un usuario no confiable ejecute este script como root o ejecute algún proceso como root que llame a este script, tenga cuidado . Al cambiar el entorno, pueden hacer que este script, o cualquier script que se ejecute como root, haga cualquier cosa . A menos que pueda evitar que esto ocurra, no debe permitir a los usuarios privilegios elevados para ejecutar scripts de shell.
Ver 10.4. Lenguajes de secuencias de comandos de Shell (derivados de sh y csh) en la programación segura de David A. Wheeler para Linux y Unix HOWTO para obtener más información al respecto. Si bien su presentación se centra en los guiones setuid, otros mecanismos pueden ser víctimas de algunos de los mismos problemas si no desinfectan correctamente el medio ambiente.
Otras notas
Solo admite hashes de lectura de la shadow
base de datos.
Las contraseñas deben estar sombreadas para que este script funcione (es decir, sus hashes deben estar en un /etc/shadow
archivo separado que solo la raíz pueda leer, no en /etc/passwd
).
Este siempre debería ser el caso en Ubuntu. En cualquier caso, si es necesario, el script se puede extender trivialmente para leer hashes de contraseñas passwd
y también shadow
.
Tenga IFS
en cuenta al modificar este script.
Lo configuré IFS=$
al principio, ya que los tres datos en el campo hash de una entrada de sombra están separados por $
.
- También tienen un liderazgo
$
, por lo que el tipo de hash y la sal son "${ent[1]}"
y en "${ent[2]}"
lugar de "${ent[0]}"
y "${ent[1]}"
, respectivamente.
Los únicos lugares en este script donde $IFS
determina cómo el shell divide o combina palabras son
cuando estos datos se dividen en una matriz, inicializándolos desde la $(
)
sustitución del comando sin comillas en:
set -f; ent=($(getent shadow "$1" | awk -F: '{print $2}')); set +f
cuando la matriz se reconstituye en una cadena para compararla con el campo completo shadow
, la "${ent[*]}"
expresión en:
if [[ "${ent[*]}" = "$(mkpasswd -sm $hashtype -S "${ent[2]}" <<<"$pass")" ]]
Si modifica la secuencia de comandos y hace que divida las palabras (o la combinación de palabras) en otras situaciones, deberá establecer IFS
diferentes valores para diferentes comandos o diferentes partes de la secuencia de comandos.
Si no tiene esto en cuenta y asume que $IFS
está configurado en el espacio en blanco habitual ( $' \t\n'
), podría terminar haciendo que su script se comporte de maneras bastante extrañas.