¿Cómo verificar la contraseña con Linux?


22

Quiero verificar, desde la línea de comandos de Linux, si una contraseña de texto sin formato dada es la misma que una contraseña cifrada en / etc / shadow

(Necesito esto para autenticar a los usuarios web. Estoy ejecutando un Linux incrustado).

Tengo acceso al archivo / etc / shadow en sí.


¿Iniciar sesión como usuario con la contraseña?
Kusalananda

La prueba debe hacerse automáticamente, no puedo escribir manualmente la contraseña del servidor web
michelemarcon

Respuestas:


17

Puede extraer fácilmente la contraseña cifrada con awk. Luego, debe extraer el prefijo $algorithm$salt$(suponiendo que este sistema no esté utilizando el DES tradicional, que está en desuso porque puede ser forzado en estos días).

correct=$(</etc/shadow awk -v user=bob -F : 'user == $1 {print $2}')
prefix=${correct%"${correct#\$*\$*\$}"}

Para la verificación de contraseña, la función C subyacente es crypt, pero no hay un comando de shell estándar para acceder a ella.

En la línea de comando, puede usar una línea Perl para invocar cryptla contraseña.

supplied=$(echo "$password" |
           perl -e '$_ = <STDIN>; chomp; print crypt($_, $ARGV[0])' "$prefix")
if [ "$supplied" = "$correct" ]; then 

Dado que esto no se puede hacer en herramientas de shell puro, si tiene Perl disponible, también podría hacerlo todo en Perl. (O Python, Ruby, ... lo que tenga disponible que pueda llamar a la cryptfunción). Advertencia, código no probado.

#!/usr/bin/env perl
use warnings;
use strict;
my @pwent = getpwnam($ARGV[0]);
if (!@pwent) {die "Invalid username: $ARGV[0]\n";}
my $supplied = <STDIN>;
chomp($supplied);
if (crypt($supplied, $pwent[1]) eq $pwent[1]) {
    exit(0);
} else {
    print STDERR "Invalid password for $ARGV[0]\n";
    exit(1);
}

En un sistema embebido sin Perl, usaría un pequeño programa dedicado de C. Advertencia, escrita directamente en el navegador, ni siquiera he intentado compilar. ¡Esto está destinado a ilustrar los pasos necesarios, no como una implementación robusta!

/* Usage: echo password | check_password username */
#include <stdio.h>
#include <stdlib.h>
#include <pwd.h>
#include <shadow.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
    char password[100];
    struct spwd shadow_entry;
    char *p, *correct, *supplied, *salt;
    if (argc < 2) return 2;
    /* Read the password from stdin */
    p = fgets(password, sizeof(password), stdin);
    if (p == NULL) return 2;
    *p = 0;
    /* Read the correct hash from the shadow entry */
    shadow_entry = getspnam(username);
    if (shadow_entry == NULL) return 1;
    correct = shadow_entry->sp_pwdp;
    /* Extract the salt. Remember to free the memory. */
    salt = strdup(correct);
    if (salt == NULL) return 2;
    p = strchr(salt + 1, '$');
    if (p == NULL) return 2;
    p = strchr(p + 1, '$');
    if (p == NULL) return 2;
    p[1] = 0;
    /*Encrypt the supplied password with the salt and compare the results*/
    supplied = crypt(password, salt);
    if (supplied == NULL) return 2;
    return !!strcmp(supplied, correct);
}

Un enfoque diferente es utilizar un programa existente como suo login. De hecho, si puede, sería ideal organizar la aplicación web para que realice lo que necesite a través de su -c somecommand username. La dificultad aquí es alimentar la contraseña a su; Esto requiere una terminal. Se espera la herramienta habitual para emular un terminal , pero es una gran dependencia para un sistema embebido. Además, mientras suestá en BusyBox, a menudo se omite porque muchos de sus usos requieren que el binario de BusyBox sea la raíz setuid. Aún así, si puede hacerlo, este es el enfoque más sólido desde un punto de vista de seguridad.


1
Me gusta el suacercamiento.
Benjohn

6

Echa un vistazo a man 5 shadowy man 3 crypt. De este último, puede aprender que los hash de contraseña /etc/shadowtienen la siguiente forma:

 $id$salt$encrypted

donde iddefine el tipo de cifrado y, leyendo más, puede ser uno de

          ID  | Method
          ---------------------------------------------------------
          1   | MD5
          2a  | Blowfish (not in mainline glibc; added in some
              | Linux distributions)
          5   | SHA-256 (since glibc 2.7)
          6   | SHA-512 (since glibc 2.7)

Según el tipo de hash, debe usar la función / herramienta adecuada para generar y verificar la contraseña "a mano". Si el sistema contiene un mkpasswdprograma, puede usarlo como se sugiere aquí . (Si no era obvio, toma la sal del archivo sombra). Por ejemplo, con las md5contraseñas:

 mkpasswd -5 <the_salt> <the_password>

generará la cadena que debe coincidir con la /etc/shadowentrada.


1
En mi Debian wheezy tenía una sintaxis completamente diferente para el comando mkpasswd, que tuve que instalar usando apt-get install whois. La línea de comando para la línea de sombra <user>:$6$<salt>$<pwd>:eramkpasswd -msha-512 <password> <salt>
Daniel Alder,

1

Hubo una pregunta similar en Stack Overflow . cluelessCoder proporcionó una secuencia de comandos que utiliza el método wait , que puede o no tener en su sistema integrado.

#!/bin/bash
#
# login.sh $USERNAME $PASSWORD

#this script doesn't work if it is run as root, since then we don't have to specify a pw for 'su'
if [ $(id -u) -eq 0 ]; then
        echo "This script can't be run as root." 1>&2
        exit 1
fi

if [ ! $# -eq 2 ]; then
        echo "Wrong Number of Arguments (expected 2, got $#)" 1>&2
        exit 1
fi

USERNAME=$1
PASSWORD=$2

#since we use expect inside a bash-script, we have to escape tcl-$.
expect << EOF
spawn su $USERNAME -c "exit" 
expect "Password:"
send "$PASSWORD\r"
#expect eof

set wait_result  [wait]

# check if it is an OS error or a return code from our command
#   index 2 should be -1 for OS erro, 0 for command return code
if {[lindex \$wait_result 2] == 0} {
        exit [lindex \$wait_result 3]
} 
else {
        exit 1 
}
EOF

0

Tenga en cuenta que, suponiendo que el sistema esté configurado correctamente, el programa deberá ejecutarse como root.

Una mejor solución que leer el archivo de sombra directamente y escribir su propio código alrededor de la cripta sería usar los enlaces de pam.

El tarball de squid solía venir con una herramienta CLI simple para verificar nombres de usuario / contraseñas usando stdio, tan simple de adaptar para usar argumentos, aunque la versión que pirateé anteriormente no era un póster pin-up para la programación estructurada. Un google rápido y parece que las versiones más recientes se han limpiado significativamente, pero todavía hay algunos 'goto' allí.


0
#! /bin/bash
#  (GPL3+) Alberto Salvia Novella (es20490446e)


passwordHash () {
    password=${1}
    salt=${2}
    encryption=${3}

    hashes=$(echo ${password} | openssl passwd -${encryption} -salt ${salt} -stdin)
    echo $(substring ${hashes} "$" "3")
}


passwordIsValid () {
    user=${1}
    password=${2}

    encryption=$(secret "encryption" ${user})
    salt=$(secret "salt" ${user})
    salted=$(secret "salted" ${user})
    hash=$(passwordHash ${password} ${salt} ${encryption})

    [ ${salted} = ${hash} ] && echo "true" || echo "false"
}


secret () {
    secret=${1}
    user=${2}
    shadow=$(shadow ${user})

    if [ ${secret} = "encryption" ]; then
        position=1
    elif [ ${secret} = "salt" ]; then
        position=2
    elif [ ${secret} = "salted" ]; then
        position=3
    fi

    echo $(substring ${shadow} "$" ${position})
}


shadow () {
    user=${1}
    shadow=$(cat /etc/shadow | grep ${user})
    shadow=$(substring ${shadow} ":" "1")
    echo ${shadow}
}


substring () {
    string=${1}
    separator=${2}
    position=${3}

    substring=${string//"${separator}"/$'\2'}
    IFS=$'\2' read -a substring <<< "${substring}"
    echo ${substring[${position}]}
}


passwordIsValid ${@}

Lanza un errorline 61: :: syntax error: operand expected (error token is ":")
hoefling

El emulador de terminal debe ser Bash 5, y debe indicar tanto el nombre de usuario como la contraseña como argumentos. He probado que funciona.
Alberto Salvia Novella
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.