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 crypt
la 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 crypt
funció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 su
o 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 su
está 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.