2021.09.18  

【CentOS】パスワードの確認とハッシュ化されたパスワードの解析

Linux,  Security    

この記事ではCentOS(Linux)の下記について紹介します。

  1. パスワードの保存場所の確認
  2. パスワードを忘れた場合の対応策
  3. ハッシュ化されたパスワードから平文パスワードを特定する
  4. パスワードのハッシュ化に利用されるアルゴリズムの設定箇所

パスワードの保存場所

CentOS(Linux)のパスワードは/etc/shadowの第2フィールドにハッシュ化された状態で保存されています。

かつては/etc/passwdに保存されていましたが、誰でも中身を確認できるファイルであるため、セキュリティ面を考慮して/etc/shadowに保存されることになりました。shadowファイルはrootユーザーでしか読み取ることができません。

/etc/shadowの中身
[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部分に、かつてはハッシュ化されたパスワードが記述されていました。

/etc/passwdの中身
[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にパスワードを設定してみます。

下記例ではhoge01hoge02ユーザーを作成し、パスワードをそれぞれ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:::

確認すると、hoge01hoge02ユーザーはそれぞれ同じパスワードhogehoge123を設定しているにも関わらず、パスワードのハッシュ値が異なります。

これは設定したパスワードを単純にハッシュ化している訳ではなくperlpythonで使用できる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について)

コメント
現在コメントはありません。
コメントする
コメント入力

名前 (※ 必須)

メールアドレス (※ 必須 画面には表示されません)

送信