주어진 일반 텍스트 비밀번호가 / etc / shadow의 암호화 된 비밀번호와 동일한 지 Linux 명령 행에서 확인하고 싶습니다.
(웹 사용자를 인증하려면 이것이 필요합니다. 임베디드 리눅스를 실행하고 있습니다.)
/ etc / shadow 파일 자체에 액세스 할 수 있습니다.
주어진 일반 텍스트 비밀번호가 / etc / shadow의 암호화 된 비밀번호와 동일한 지 Linux 명령 행에서 확인하고 싶습니다.
(웹 사용자를 인증하려면 이것이 필요합니다. 임베디드 리눅스를 실행하고 있습니다.)
/ etc / shadow 파일 자체에 액세스 할 수 있습니다.
답변:
awk를 사용하여 암호화 된 비밀번호를 쉽게 추출 할 수 있습니다. 그런 다음 접두사를 추출해야합니다 $algorithm$salt$
(이 시스템은 기존의 DES를 사용하지 않는 것으로 가정합니다. 요즘은 무차별적일 수 있기 때문에 더 이상 사용되지 않습니다).
correct=$(</etc/shadow awk -v user=bob -F : 'user == $1 {print $2}')
prefix=${correct%"${correct#\$*\$*\$}"}
비밀번호 검사의 경우 기본 C 함수는입니다 crypt
만 액세스 할 수있는 표준 쉘 명령은 없습니다.
명령 행에서 Perl one-liner를 사용 crypt
하여 비밀번호 를 호출 할 수 있습니다 .
supplied=$(echo "$password" |
perl -e '$_ = <STDIN>; chomp; print crypt($_, $ARGV[0])' "$prefix")
if [ "$supplied" = "$correct" ]; then …
순수한 쉘 도구로는이 작업을 수행 할 수 없기 때문에 Perl을 사용할 수 있다면 Perl에서도 모든 작업을 수행 할 수 있습니다. (또는 Python, Ruby, ... crypt
함수를 호출 할 수있는 모든 것 ) 경고, 테스트되지 않은 코드
#!/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);
}
Perl이없는 임베디드 시스템에서는 작은 전용 C 프로그램을 사용합니다. 경고는 브라우저에 직접 입력했지만 컴파일조차 시도하지 않았습니다. 이는 강력한 구현이 아니라 필요한 단계를 설명하기위한 것입니다!
/* 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);
}
다른 방법은 su
또는 과 같은 기존 프로그램을 사용하는 것 login
입니다. 실제로 가능하다면 웹 애플리케이션이 필요한 모든 것을 수행하도록 구성하는 것이 이상적입니다 su -c somecommand username
. 여기서 어려운 점은 암호를 제공하는 것입니다 su
. 이것은 터미널이 필요합니다. 터미널을 에뮬레이트하는 일반적인 도구는 expect 이지만 임베디드 시스템의 경우 큰 의존성입니다. 또한 su
BusyBox에 있지만 BusyBox 바이너리를 setuid 루트로 사용하려면 많은 용도로 사용되기 때문에 종종 생략됩니다. 여전히 가능하다면 보안 관점에서 가장 강력한 접근 방법입니다.
su
접근법을 좋아한다 .
한 번 봐 가지고 man 5 shadow
와 man 3 crypt
. 후자에서 암호 해시의 /etc/shadow
형식은 다음과 같습니다.
$id$salt$encrypted
여기서 id
암호화 유형을 정의하고 자세히 읽으면 다음 중 하나 일 수 있습니다.
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)
해시 유형에 따라 "손으로"암호를 생성하고 확인하기 위해 적절한 기능 / 도구를 사용해야합니다. 시스템에 mkpasswd
프로그램이 포함 된 경우 여기에 제안 된대로 사용할 수 있습니다 . ( 분명하지 않은 경우 섀도 파일에서 솔트 를 가져옵니다 .) 예를 들어, md5
passwords :
mkpasswd -5 <the_salt> <the_password>
/etc/shadow
항목 과 일치하는 문자열을 생성합니다 .
mkpasswd
사용했다 apt-get install whois
. 섀도우 라인의 명령 줄 <user>:$6$<salt>$<pwd>:
은 다음과 같습니다mkpasswd -msha-512 <password> <salt>
Stack Overflow 에서 비슷한 질문 이있었습니다 . cluelessCoder는 임베디드 시스템에있을 수도 있고 없을 수도있는 expect를 사용하여 스크립트를 제공했습니다 .
#!/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
시스템이 올바르게 구성되었다고 가정하면 프로그램을 루트로 실행해야합니다.
섀도 파일을 직접 읽고 crypt 주위에 자신의 코드를 작성하는 것보다 낫는 해결책은 pam 바인딩을 사용하는 것입니다.
오징어 인수를 사용에 적응하기 위해 너무 간단 - - 타르는 표준 입출력을 사용하여 사용자 이름 / 암호를 확인하기위한 간단한 CLI 도구를 제공하는 데 사용 나는 해킹 버전이 이전에 거의 구조화 프로그래밍을위한 핀 - 업 포스터 없었다하지만. 빠른 Google과 최신 버전 이 크게 정리되었지만 여전히 몇 가지 '고토'가 있는 것처럼 보입니다 .
#! /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 ${@}
line 61: :: syntax error: operand expected (error token is ":")