Làm thế nào để kiểm tra mật khẩu với Linux?


22

Tôi muốn kiểm tra, từ dòng lệnh linux, nếu mật khẩu Cleartext đã cho giống với mật khẩu được mã hóa trên / etc / bóng

(Tôi cần điều này để xác thực người dùng web. Tôi đang chạy một linux nhúng.)

Tôi có quyền truy cập vào tập tin / etc / bóng.


Đăng nhập với tư cách người dùng bằng mật khẩu?
Kusalananda

Việc kiểm tra phải được thực hiện tự động, tôi không thể nhập mật khẩu thủ công từ máy chủ web
michelemarcon

Câu trả lời:


17

Bạn có thể dễ dàng trích xuất mật khẩu được mã hóa bằng awk. Sau đó, bạn cần trích xuất tiền tố $algorithm$salt$(giả sử rằng hệ thống này không sử dụng DES truyền thống, vốn không được dùng nữa vì nó có thể bị ép buộc trong những ngày này).

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

Để kiểm tra mật khẩu, hàm C bên dưới là crypt, nhưng không có lệnh shell tiêu chuẩn để truy cập nó.

Trên dòng lệnh, bạn có thể sử dụng Perl one-liner để gọi cryptmật khẩu.

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

Vì điều này không thể được thực hiện trong các công cụ shell thuần túy, nếu bạn có sẵn Perl, bạn cũng có thể làm tất cả trong Perl. (Hoặc Python, Ruby, xông bất cứ thứ gì bạn có sẵn có thể gọi crypthàm.) Cảnh báo, mã chưa được kiểm tra.

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

Trên một hệ thống nhúng không có Perl, tôi sẽ sử dụng một chương trình C nhỏ, chuyên dụng. Cảnh báo, được gõ trực tiếp vào trình duyệt, tôi thậm chí chưa thử biên dịch. Điều này có nghĩa là để minh họa các bước cần thiết, không phải là một triển khai mạnh mẽ!

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

Một cách tiếp cận khác là sử dụng một chương trình hiện có như suhoặc login. Trong thực tế, nếu bạn có thể, sẽ rất lý tưởng khi sắp xếp cho ứng dụng web thực hiện bất cứ điều gì nó cần thông qua su -c somecommand username. Khó khăn ở đây là cung cấp mật khẩu cho su; điều này đòi hỏi một thiết bị đầu cuối. Công cụ thông thường để mô phỏng thiết bị đầu cuối là mong đợi , nhưng đó là một sự phụ thuộc lớn cho một hệ thống nhúng. Ngoài ra, trong khi suở BusyBox, nó thường bị bỏ qua vì nhiều cách sử dụng của nó yêu cầu nhị phân BusyBox phải là root setuid. Tuy nhiên, nếu bạn có thể làm điều đó, đây là cách tiếp cận mạnh mẽ nhất từ ​​quan điểm bảo mật.


1
Tôi thích sucách tiếp cận.
Stewohn

6

Có một cái nhìn man 5 shadowman 3 crypt. Từ cái sau, bạn có thể biết rằng băm mật khẩu /etc/shadowcó dạng sau:

 $id$salt$encrypted

trong đó idxác định loại mã hóa và, đọc thêm, có thể là một trong

          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)

Tùy thuộc vào loại băm, bạn cần sử dụng chức năng / công cụ thích hợp để tạo và xác minh mật khẩu "bằng tay". Nếu hệ thống chứa mkpasswdchương trình, bạn có thể sử dụng nó như được đề xuất ở đây . (Bạn lấy muối từ tệp bóng, nếu điều đó không rõ ràng.) Ví dụ: với md5mật khẩu:

 mkpasswd -5 <the_salt> <the_password>

sẽ tạo ra chuỗi phù hợp với /etc/shadowmục nhập.


1
Trên Debian của tôi, tôi có một cú pháp hoàn toàn khác cho lệnh mkpasswdmà tôi phải cài đặt bằng cách sử dụng apt-get install whois. Dòng lệnh cho dòng bóng <user>:$6$<salt>$<pwd>:mkpasswd -msha-512 <password> <salt>
Daniel Alder

1

Có một câu hỏi tương tự được hỏi trên Stack Overflow . clulessCoder đã cung cấp một tập lệnh sử dụng kỳ vọng mà bạn có thể có hoặc không có trên hệ thống nhúng của mình.

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

Hãy nhớ rằng, giả sử hệ thống được cấu hình đúng, chương trình sẽ cần được chạy dưới quyền root.

Một giải pháp tốt hơn là đọc tệp bóng trực tiếp và viết mã của riêng bạn xung quanh tiền điện tử sẽ chỉ là sử dụng các ràng buộc pam.

Các mực tarball sử dụng để đi kèm với một công cụ CLI đơn giản cho việc xác minh tên người dùng / mật khẩu sử dụng stdio - đơn giản như vậy để thích ứng với sử dụng đối số - mặc dù các phiên bản hack tôi trước đây là hầu như không một poster pin-up cho lập trình có cấu trúc. Google nhanh chóng và có vẻ như các phiên bản gần đây đã được dọn sạch đáng kể nhưng vẫn còn một vài 'goto trong đó.


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

Phát sinh lỗiline 61: :: syntax error: operand expected (error token is ":")
cuốc

Trình giả lập thiết bị đầu cuối phải là Bash 5 và bạn phải chỉ ra cả tên người dùng và mật khẩu làm đối số. Tôi đã thử nó hoạt động.
Alberto Salvia Novella
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.