Come controllare la password con Linux?


22

Voglio controllare, dalla riga di comando di Linux, se una determinata password in chiaro è la stessa di una password crittografata su un / etc / shadow

(Ho bisogno di questo per autenticare gli utenti Web. Sto eseguendo un Linux incorporato.)

Ho accesso al file / etc / shadow stesso.


Accedi come utente con la password?
Kusalananda

Il test deve essere eseguito automaticamente, non riesco a digitare manualmente la password dal server web
michelemarcon,

Risposte:


17

È possibile estrarre facilmente la password crittografata con awk. È quindi necessario estrarre il prefisso $algorithm$salt$(supponendo che questo sistema non stia utilizzando il tradizionale DES, che è fortemente deprecato perché al giorno d'oggi può essere forzato).

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

Per il controllo della password, la funzione C sottostante è crypt, ma non esiste un comando shell standard per accedervi.

Sulla riga di comando, è possibile utilizzare un one-liner Perl per richiamare cryptla password.

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

Dato che questo non può essere fatto con strumenti shell puri, se hai Perl disponibile, potresti anche fare tutto in Perl. (O Python, Ruby, ... qualunque cosa tu abbia a disposizione che può chiamare la cryptfunzione.) Avviso, codice non testato.

#!/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);
}

Su un sistema embedded senza Perl, utilizzerei un piccolo programma C dedicato. Attenzione, digitato direttamente nel browser, non ho nemmeno provato a compilare. Questo ha lo scopo di illustrare i passaggi necessari, non come un'implementazione 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 approccio diverso consiste nell'utilizzare un programma esistente come suo login. In effetti, se puoi, sarebbe l'ideale organizzare l'applicazione web per eseguire tutto ciò di cui ha bisogno su -c somecommand username. La difficoltà qui è di fornire la password a su; questo richiede un terminale. Si prevede il solito strumento per emulare un terminale , ma è una grande dipendenza per un sistema incorporato. Inoltre, mentre suè in BusyBox, viene spesso omesso perché molti dei suoi usi richiedono che il binario BusyBox sia setuid root. Tuttavia, se riesci a farlo, questo è l'approccio più solido dal punto di vista della sicurezza.


1
Mi piace l' suapproccio.
Benjohn,

6

Dai un'occhiata a man 5 shadowe man 3 crypt. Da quest'ultimo, puoi imparare che gli hash delle password /etc/shadowhanno la seguente forma:

 $id$salt$encrypted

dove iddefinisce il tipo di crittografia e, leggendo oltre, può essere uno dei

          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)

A seconda del tipo di hash, è necessario utilizzare la funzione / strumento appropriato per generare e verificare la password "a mano". Se il sistema contiene un mkpasswdprogramma, è possibile utilizzarlo come suggerito qui . (Prendi il sale dal file shadow, se non fosse ovvio.) Ad esempio, con le md5password:

 mkpasswd -5 <the_salt> <the_password>

genererà la stringa che dovrebbe corrispondere alla /etc/shadowvoce.


1
Sul mio wheezy Debian avevo una sintassi completamente diversa per il comando mkpasswd, che dovevo installare usando apt-get install whois. La linea di comando per la linea d'ombra <user>:$6$<salt>$<pwd>:eramkpasswd -msha-512 <password> <salt>
Daniel Alder,

1

È stata posta una domanda simile su Stack Overflow . cluelessCoder ha fornito uno script usando wait , che potresti avere o meno sul tuo sistema embedded.

#!/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

Tieni presente che, supponendo che il sistema sia configurato correttamente, il programma dovrà essere eseguito come root.

Una soluzione migliore rispetto alla lettura diretta del file shadow e alla scrittura del proprio codice su crypt sarebbe quella di utilizzare solo i collegamenti pam.

Il tarball di calamari veniva con un semplice strumento CLI per verificare nomi utente / password usando stdio - così semplice da adattare usando argomenti - anche se la versione che ho hackerato in precedenza non era certo un poster pin-up per la programmazione strutturata. Un rapido google e sembra che le versioni più recenti siano state ripulite in modo significativo ma ci sono ancora alcuni "goto".


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 ${@}

Sputa un erroreline 61: :: syntax error: operand expected (error token is ":")
hoefling

L'emulatore di terminale dovrebbe essere Bash 5 e devi indicare sia nome utente che password come argomenti. Ho provato che funziona.
Alberto Salvia Novella,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.