この記事ではCentOS(Linux)の下記について紹介します。
- パスワードの保存場所の確認
- パスワードを忘れた場合の対応策
- ハッシュ化されたパスワードから平文パスワードを特定する
- パスワードのハッシュ化に利用されるアルゴリズムの設定箇所
パスワードの保存場所
CentOS(Linux)のパスワードは/etc/shadow
の第2フィールドにハッシュ化された状態で保存されています。
かつては/etc/passwd
に保存されていましたが、誰でも中身を確認できるファイルであるため、セキュリティ面を考慮して/etc/shadow
に保存されることになりました。shadowファイルはrootユーザーでしか読み取ることができません。
[root@centos8 ~]# cat /etc/shadow | grep hoge
hoge1:$6$X9plwZHrxbldTwnA$F3PgQY8KtBBMf7UjL
2FfZfM7ahel846f6iG/pclv3OxMh81Sc61J.rRiv6UIBBd
AZ3XQui3RCT2dYRgtZ8g5W.:
18875:0:99999:7:::
hoge1
がユーザー名で、その後ろの$6$X9plw ~ gtZ8g5W.
がハッシュ化されたパスワードです。
また、以下は/etc/passwd
の中身です。第2フィールドのx
部分に、かつてはハッシュ化されたパスワードが記述されていました。
[root@centos8 ~]# cat /etc/passwd | grep hoge
hoge:x:1002:1002::/home/hoge1:/bin/bash
パスワードを忘れた場合
/etc/shadow
では、ハッシュ化されたパスワードは確認できますが、平文のパスワード(元のパスワード)は確認することはできません。
また、ハッシュ化されたパスワードは平文に戻すことができません。
ハッシュ化とは、ある計算ルール(アルゴリズム)に基づいて、与えられた値(ここではパスワード)を誰にも元に戻すことができない不可逆的な置き換えを行うことだからです。
ちなみに、計算ルールとパスワードが同じ場合、常に同じ文字列が計算結果として出力されます。
一般ユーザーのパスワードを忘れてしまった場合は、rootユーザーでのパスワード変更を行うのが一番簡単な対応方法です。
パスワードを変更するには次のコマンドを実行します。
[root@centos8 ~]# passwd [パスワードを変更するユーザー名]
rootユーザーのパスワードを忘れてしまった場合は、次のような対応をします。
- 一般ユーザーからsudo suコマンドを実行できるのであれば、それでrootユーザーにスイッチしてパスワードを再設定する
- CentOS 6であればシングルユーザーモードでログインしてパスワードを再設定する (デフォルトのログインユーザーがrootであり、パスワードなしでログインできる)
- CentOS 7, 8であればGRUB2起動画面の編集モードでパスワードを再設定する 参考(CentOS7) 参考(CentOS8)
平文のパスワードをなんとなく覚えていれば/etc/shadow
のハッシュ値と平文パスワードをハッシュ化した値からパスワードを特定できます。
ただ、この方法は/etc/shadow
はrootユーザーでしか確認できませんし、rootユーザーにログインできるのならパスワードを変更すれば済む話なので、実用性はあまりありません。(ハッカーを目指しているなら話は変わりますが)
Linuxのパスワードの仕組み、セキュリティなどに興味がある方は次章以降をお読みください。
ハッシュ化パスワード生成の仕組みと解析
実際にユーザーを作成して/etc/shadow
にパスワードを設定してみます。
下記例ではhoge01
、hoge02
ユーザーを作成し、パスワードをそれぞれhogehoge123
と設定しています。
[root@centos8 ~]# useradd hoge01 && passwd hoge01
Changing password for user hoge01.
New password:
Retype new password:
[root@centos8 ~]# useradd hoge02 && passwd hoge02
Changing password for user hoge02.
New password:
Retype new password:
次に/etc/shadow
でそれぞれのユーザーのパスワードを確認します。
パスワード部分は:
で区切られた2つ目のフィールドです。
[root@centos8 ~]# cat /etc/shadow | grep hoge0
hoge01:$6$fojOWGVpwP6uyzUU$V84ts77ogpplT2hobFjnfGT9h0NBVJVkLN5STZDkulY4S6Iakb4fRSnDNUpsFWpLwxVl8evtGl1hKVyzvXEhs/:18888:0:99999:7:::
hoge02:$6$TD4FtYq.e04Xt8ff$Ggi5Izf1ckalhbEwJ0NB3MhGqzsgvjJtdOTn9GRT24brlydSLfFbcxJTyXXtO5Dln44hsV9iUxtcDQL03kf6V1:18888:0:99999:7:::
確認すると、hoge01
、hoge02
ユーザーはそれぞれ同じパスワードhogehoge123
を設定しているにも関わらず、パスワードのハッシュ値が異なります。
これは設定したパスワードを単純にハッシュ化している訳ではなくperl
やpython
で使用できるcrypt
という関数を使用してハッシュ化を行っているからです。
(余談ですが、perlのマニュアルにはC言語の crypt(3) 関数と全く同じであるという記述があります。つまり、crypt
はC言語に関連する関数ということです。)
crypt
関数にはユーザーが指定した平文のパスワードの他にsalt
という引数を使用します。
crypt
関数の書式は次のようになります。参考: perlマニュアル
perl -e 'print crypt("平文のパスワード", "salt");'
それではsalt
に何を指定すれば良いかというと話になります。
先ほどcat /etc/shadow | grep hoge0
コマンドで出力したhoge01
ユーザーのハッシュ化パスワードの前半部分を確認するとsalt
の値を確認できます。下記が前半部分を抜き出した記述です。
$6$fojOWGVpwP6uyzUU$
最初の$
で囲まれた部分$6$
はハッシュ化に利用されたアルゴリズムを表しています。
対応するアルゴリズムのデジット(数字)は次の表の通りです。
$デジット$ | アルゴリズム名 |
---|---|
$1$ | md5 |
$2$ | Blowfish |
$5$ | SHA256 |
$6$ | SHA512 |
後半の$fojOWGVpwP6uyzUU$
についてはCentOS側でランダムな値を生成したものです。
このsalt
と平文のパスワードをcrypt
関数を利用してハッシュ化すると次のように、/etc/shadow
ファイルと全く同じ文字列が出力されます。
[root@centos8 ~]# perl -e 'print crypt("hogehoge123", "\$6\$fojOWGVpwP6uyzUU");'
$6$fojOWGVpwP6uyzUU$V84ts77ogpplT2hobFjnfGT9h0NBVJVkLN5STZDkulY4S6Iakb4fRSnDNUpsFWpLwxVl8evtGl1hKVyzvXEhs/
つまり、パスワードのハッシュ値とsalt
の値は/etc/shadow
から読み取ることができます。
あとは正しいと思われる平文パスワードとsalt
の値をcrypt
関数に順次設定、実行していき、/etc/shadow
のパスワードのハッシュ値と突き合わせ、差分がなければ、それが正しいパスワードとなります。
下記コマンドを使用すると/etc/shadow
のハッシュ値と、crypt
関数の出力結果の差分をチェックできます。
実行結果が表示されなければ、差分なしです。
[root@centos8 ~]# diff -w \
<(cat /etc/shadow | grep hoge01 | awk -F ':' '{print $2}' ) \
<(perl -e 'print crypt("hogehoge123", "\$6\$fojOWGVpwP6uyzUU");')
diff
コマンドの-w
オプションはすべての空白を無視して差分比較を行うオプションです。
<(実行コマンド)
と記述するとコマンドの実行結果をdiff
コマンドで比較できるようになります。
awk
の-F
オプションで区切り文字を指定して、'{print $2}'
と記述すると、crypt
関数の出力結果の二番目のフィールド、つまりハッシュ化されたパスワードの部分のみを出力できます。
\
を記述するとコマンドを実行することなく改行することができます。
パスワードのハッシュ化に使用するアルゴリズムはどこで決まる?
こちらについてはPAM
で設定されます。
PAM(Pluggable Authentication Modules)とは、Linuxの認証を管理するモジュールのことです。
PAM
は各アプリケーション(telnet、ssh、sambaなど)をどの情報(/etc/shadow など)で認証するかを管理しています。
パスワードのハッシュ値を決定する設定は次のファイルで行われています。
/etc/pam.d/system-auth
中身を確認すると次のような行が見つかります。
ここの3番目のフィールドを見るとshadow
ファイルで使用されているハッシュ値(sha512
)が確認できます。
password ・・・
password sufficient pam_unix.so sha512 shadow nullok try_first_pass use_authtok
password ・・・
この行の設定値の意味は何?
上記password sufficient pam_unix.so sha512 shadow nullok try_first_pass use_authtok
の設定値について簡単に解説します。
password
pam_unix.so モジュールの password インターフェースを使用して、プログラムがユーザーのパスワードを変更するかどうかを指定しています。
sufficient
この行の適用条件。詳細については本記事の話題から大分ずれてしまうので割愛します。
pam_unix.so
PAM実行モジュールを指定しています。
sha512
暗号化アルゴリズムの種類を指定しています。md5
なども設定することが可能です。
shadow
ユーザーのパスワード更新の際にシャドウパスワードを作成するようモジュールに指示します。
nullok
ユーザーが空のパスワードからパスワードを変更できるようにするようにモジュールに指示します。
それ以外の場合は、null パスワードはアカウントロックとして扱われます。
try_first_pass
pam_unix.soは/etc/passwd, /etc/shadowの内容を基に認証を行います。
try_first_passはあるサービスに対するPAM認証が2行存在する場合に使用します。
1つめ(1行目)の認証モジュールで入力したパスワードを後続のモジュールで再利用します。
あるサービスに対するPAM認証が2行存在する場合に try_first_passを用いれば、
その2行から呼び出される認証サービスはパスワードを2回必要とします。
しかし、この設定をすると入力を1回で済ますことができます。
use_authtok
use_authtok は、ユーザーに新しいパスワードを要求しないようにモジュールに指示します。
代わりに、以前のパスワードモジュールで記録されたパスワードを受け入れます。
これにより、新しいパスワードはすべて、受け入れられる前に安全なパスワードの pam_cracklib.so のテスト通過が必要となります。
余談ですが、行末にremember=5
を設定すると過去5世代のパスワードの再利用を禁止する設定が行えます。
password sufficient pam_unix.so sha512 shadow nullok try_first_pass use_authtok remember=5
参考サイト
【CentOS】/etc/shadowのハッシュ化パスワードについて
Red Hatマニュアル(PAMの設定値について)
Linuxサーバのパスワードポリシー設定手順(remember=5について)
PAMによる認証の仕組みを調べてみた(rtry_first_passについて)