Wie überprüfe ich mein Passwort unter Linux?

21

Ich möchte über die Linux-Befehlszeile prüfen, ob ein bestimmtes Klartext-Passwort mit einem verschlüsselten Passwort in einer / etc / shadow übereinstimmt

(Ich benötige dies, um Webbenutzer zu authentifizieren. Ich verwende ein eingebettetes Linux.)

Ich habe Zugriff auf die Datei / etc / shadow.

Michelemarcon
quelle
Als Benutzer mit dem Passwort anmelden?
Kusalananda
Der Test muss automatisch durchgeführt werden, ich kann das Passwort nicht manuell vom Webserver
eingeben

Antworten:

16

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 cryptdas 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 cryptFunktion 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 suoder 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 sues 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.

Gilles 'SO - hör auf böse zu sein'
quelle
Ich mag den suAnsatz.
Benjohn
6

Schauen Sie sich man 5 shadowund an man 3 crypt. Von letzterem können Sie lernen, dass Passwort-Hashes in /etc/shadowder folgenden Form vorliegen:

 $id$salt$encrypted

wo idund die Art der Verschlüsselung definiert, das Lesen weiter kann eines sein, von

          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)

Abhängig von der Art des Hash müssen Sie die entsprechende Funktion / das entsprechende Tool verwenden, um das Kennwort "von Hand" zu generieren und zu überprüfen. Wenn das System ein mkpasswdProgramm enthält , können Sie es wie hier vorgeschlagen verwenden . (Sie nehmen das Salz aus der Schattendatei, wenn das nicht offensichtlich war.) Zum Beispiel mit md5Passwörtern:

 mkpasswd -5 <the_salt> <the_password>

generiert den String, der mit dem /etc/shadowEintrag übereinstimmen soll .

rozcietrzewiacz
quelle
1
Auf meinem Debian-Wheezy hatte ich eine völlig andere Syntax für den Befehl mkpasswd, den ich mit installieren musste apt-get install whois. Die Befehlszeile für die Schattenzeile <user>:$6$<salt>$<pwd>:warmkpasswd -msha-512 <password> <salt>
Daniel Alder
1

Bei Stack Overflow wurde eine ähnliche Frage gestellt . cluelessCoder hat mit expect ein Skript bereitgestellt , das Sie möglicherweise auf Ihrem eingebetteten System installiert haben oder nicht.

#!/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
mr.Shu
quelle
0

Beachten Sie, dass das Programm unter der Annahme, dass das System ordnungsgemäß konfiguriert ist, als Root ausgeführt werden muss.

Eine bessere Lösung, als die Schattendatei direkt zu lesen und Ihren eigenen Code um die Krypta zu schreiben, wäre, einfach die Pam-Bindungen zu verwenden.

Der Squid- Tarball enthielt früher ein einfaches CLI-Tool zur Überprüfung von Benutzernamen / Passwörtern mit stdio - so einfach, dass es sich um Argumente handelt - obwohl die Version, die ich zuvor gehackt habe, kaum ein Pin-up-Poster für strukturierte Programmierung war. Ein kurzer Blick auf Google und es sieht so aus, als ob die neueren Versionen erheblich aufgeräumt wurden, aber immer noch ein paar 'goto's' drin sind.

symcbean
quelle
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 ${@}
Alberto Salvia Novella
quelle
Spews einen Fehlerline 61: :: syntax error: operand expected (error token is ":")
Hoefling
Der Terminal-Emulator sollte Bash 5 sein und Sie müssen sowohl Benutzername als auch Passwort als Argumente angeben. Ich habe getestet, dass es funktioniert.
Alberto Salvia Novella