Anda dapat dengan mudah mengekstrak kata sandi terenkripsi dengan awk. Anda kemudian perlu mengekstrak awalan $algorithm$salt$
(dengan asumsi bahwa sistem ini tidak menggunakan DES tradisional, yang sudah sangat tidak digunakan lagi karena dapat dipaksakan dengan kasar saat ini).
correct=$(</etc/shadow awk -v user=bob -F : 'user == $1 {print $2}')
prefix=${correct%"${correct#\$*\$*\$}"}
Untuk pemeriksaan kata sandi, fungsi C yang mendasarinya adalah crypt
, tetapi tidak ada perintah shell standar untuk mengaksesnya.
Pada baris perintah, Anda dapat menggunakan Perl one-liner untuk menjalankan crypt
pada kata sandi.
supplied=$(echo "$password" |
perl -e '$_ = <STDIN>; chomp; print crypt($_, $ARGV[0])' "$prefix")
if [ "$supplied" = "$correct" ]; then …
Karena ini tidak dapat dilakukan di alat shell murni, jika Anda memiliki Perl, Anda sebaiknya melakukan semuanya di Perl. (Atau Python, Ruby, … apa pun yang Anda miliki yang dapat memanggil crypt
function.) Peringatan, kode belum teruji.
#!/usr/bin/env perl
use warnings;
use strict;
my @pwent = getpwnam($ARGV[0]);
if ([email protected]) {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);
}
Pada sistem tersemat tanpa Perl, saya akan menggunakan program C kecil khusus. Peringatan, diketik langsung ke browser, saya bahkan belum mencoba mengkompilasi. Ini dimaksudkan untuk mengilustrasikan langkah-langkah yang diperlukan, bukan sebagai penerapan yang kuat!
/* 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);
}
Pendekatan yang berbeda adalah dengan menggunakan program yang sudah ada seperti su
atau login
. Bahkan, jika Anda bisa, akan ideal untuk mengatur agar aplikasi web menjalankan apa pun yang diperlukan melalui su -c somecommand username
. Kesulitannya di sini adalah memasukkan kata sandi ke su
; ini membutuhkan terminal. Alat biasa untuk meniru terminal diharapkan, tetapi ini merupakan ketergantungan besar untuk sistem tertanam. Juga, sementara su
ada di BusyBox, sering diabaikan karena banyak kegunaannya membutuhkan biner BusyBox menjadi setuid root. Namun, jika Anda bisa melakukannya, ini adalah pendekatan yang paling kuat dari sudut pandang keamanan.
Lihat man 5 shadow
dan man 3 crypt
. Dari yang terakhir, Anda dapat mempelajari hash kata sandi di /etc/shadow
memiliki bentuk berikut:
$id$salt$encrypted
di mana id
menentukan jenis enkripsi dan, membaca lebih lanjut, dapat menjadi salah satu dari
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)
Bergantung pada jenis hash, Anda perlu menggunakan fungsi/alat yang sesuai untuk membuat dan memverifikasi kata sandi "dengan tangan". Jika sistem berisi mkpasswd
program, Anda dapat menggunakannya seperti yang disarankan di sini. (Anda mengambil garam dari file shadow, jika itu tidak jelas.) Misalnya, dengan md5
kata sandi :
mkpasswd -5 <the_salt> <the_password>
akan menghasilkan string yang cocok dengan /etc/shadow
masuk.
Ada pertanyaan serupa yang diajukan di Stack Overflow. cluelessCoder menyediakan skrip menggunakan ekspektasi, yang mungkin atau mungkin tidak Anda miliki di sistem tertanam Anda.
#!/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