Sie können das verschlüsselte Passwort einfach mit awk extrahieren. Anschließend müssen Sie das Präfix extrahieren $algorithm$salt$
(vorausgesetzt, dieses System verwendet nicht das traditionelle DES, das derzeit stark veraltet ist, weil es brachial erzwungen werden kann).
correct=$(</etc/shadow awk -v user=bob -F : 'user == $1 {print $2}')
prefix=${correct%"${correct#\$*\$*\$}"}
Für die Kennwortprüfung ist die zugrunde liegende C-Funktion crypt
, es gibt jedoch keinen Standard-Shell-Befehl, um darauf zuzugreifen.
In der Befehlszeile können Sie einen Perl-Einzeiler verwenden, um crypt
das Kennwort aufzurufen .
supplied=$(echo "$password" |
perl -e '$_ = <STDIN>; chomp; print crypt($_, $ARGV[0])' "$prefix")
if [ "$supplied" = "$correct" ]; then …
Da dies in reinen Shell-Tools nicht möglich ist, können Sie dies auch in Perl tun, wenn Perl verfügbar ist. (Oder Python, Ruby, ... was immer Sie zur Verfügung haben, um die crypt
Funktion aufzurufen .) Warnung, ungetesteter Code.
#!/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);
}
Auf einem Embedded-System ohne Perl würde ich ein kleines, dediziertes C-Programm verwenden. Warnung, direkt in den Browser eingegeben, habe ich noch nicht einmal versucht zu kompilieren. Dies soll die notwendigen Schritte veranschaulichen, nicht als robuste Implementierung!
/* 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);
}
Ein anderer Ansatz besteht darin, ein vorhandenes Programm wie su
oder zu verwenden login
. In der Tat ist es ideal, wenn Sie dafür sorgen, dass die Webanwendung das ausführt, was sie benötigt su -c somecommand username
. Die Schwierigkeit besteht darin, das Passwort einzugeben su
. Dies erfordert ein Terminal. Das übliche Tool zum Emulieren eines Terminals ist zu erwarten , es ist jedoch eine große Abhängigkeit für ein eingebettetes System. Während su
es sich in BusyBox befindet, wird es häufig weggelassen, da für viele seiner Verwendungen die BusyBox-Binärdatei als root festgelegt werden muss. Wenn Sie dies dennoch tun können, ist dies aus Sicherheitsgründen der robusteste Ansatz.