特定のクリアテキストパスワードが/ etc / shadow上の暗号化されたパスワードと同じかどうかを、Linuxコマンドラインから確認したい
(Webユーザーを認証するためにこれが必要です。組み込みLinuxを実行しています。)
/ etc / shadowファイル自体にアクセスできます。
特定のクリアテキストパスワードが/ etc / shadow上の暗号化されたパスワードと同じかどうかを、Linuxコマンドラインから確認したい
(Webユーザーを認証するためにこれが必要です。組み込み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のワンライナーを使用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
です。実際、可能であれば、Webアプリケーションがを介して必要なものを実行できるように調整することが理想的su -c somecommand username
です。ここでの難しさは、パスワードを提供することsu
です。これには端末が必要です。端末をエミュレートする通常のツールはexpectですが、組み込みシステムにとっては大きな依存関係です。また、su
BusyBoxにありますが、その使用の多くはBusyBoxバイナリをsetuid rootにする必要があるため、しばしば省略されます。それでも、できれば、これはセキュリティの観点から最も堅牢なアプローチです。
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
パスワードを使用する場合:
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バインディングを使用することです。
イカ、私は以前にハッキングバージョンは構造化プログラミングのためのほとんどのピンアップポスターだったが-引数を使用してに適応するために、単純なので- tarボールは標準入出力を使用して、ユーザー名/パスワードを検証するためのシンプルなCLIツールが付属していました。簡単なグーグルで、最近のバージョンはかなりクリーンアップされているように見えますが、まだいくつかの「goto」があります。
#! /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 ":")