1. はじめに
Linux では /etc/ssh/ssh_config
ファイルに、「HashKnownHosts yes」と記述してある場合、known_hosts
ファイル内のホスト名(IPアドレス)部分がハッシュ化されます。
/etc/ssh/ssh_config
ファイルの例
(省略)
Host *
(省略)
HashKnownHosts yes
(省略)
known_hosts
ファイル内の行の例(ハッシュされていない場合)
192.30.253.113 ssh-rsa {公開鍵を表す文字列}
この行がハッシュ化されると以下に変化します。
|1|8V1J9OVTw6LucO4ldA8vUzfBJaE=|kmv/2pGp40XQR7CCuvxqKb3IgnM= ssh-rsa {公開鍵を表す文字列}
- IPアドレスだった部分が、別の文字列になっています。それ以降の部分に変化はありません。
本記事では、この文字列を自分で算出する方法を紹介します。
2. 実験
とある ~/.ssh/known_hosts
ファイルの内容をハッシュ化してみます。
ハッシュ化する前は、以下の行が存在していました。
github.com,192.30.253.113 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
以下のコマンドを実行することによって、known_hosts
ファイル(のホスト名部分)をハッシュ化することができます。
$ ssh-keygen -H -f ~/.ssh/known_hosts
先程の行は以下のようになりました。
|1|R0yjBY6jpUzgTmJU82oSOUjIBLQ=|HCaWOPa5tIlXcNV5Ja99BEd53RA= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
- 「
github.com,192.30.253.113
」だった部分が「|1|R0yjBY6jpUzgTmJU82oSOUjIBLQ=|HCaWOPa5tIlXcNV5Ja99BEd53RA=
」に変化しています。 - この部分は「|」で区切られており、最初の「
1
」はハッシュ化されていることを表します。 - 次の「
R0yjBY6jpUzgTmJU82oSOUjIBLQ=
」はハッシュを算出する際に使うキーで、ソルトとして使われているようです。 - 最後の「
HCaWOPa5tIlXcNV5Ja99BEd53RA=
」がハッシュ化された文字列です。
では、ホスト名(IPアドレス)である「github.com,192.30.253.113
」と「R0yjBY6jpUzgTmJU82oSOUjIBLQ=
」から、「HCaWOPa5tIlXcNV5Ja99BEd53RA=
」を求めてみます。
いろいろ調べた結果、SSH HashKnownHosts File Format や A guide and tool for cracking ssh known_hosts files with hashcat に必要なコマンドが記載されていました。
これらの情報を元にして、以下の内容を記述したファイルを作成し、実行権限を与えて実行しました。
#!/usr/bin/sh
set -eu
hexkey=$(echo 'R0yjBY6jpUzgTmJU82oSOUjIBLQ=' | base64 --decode | xxd -p)
echo -n 'github.com' | openssl sha1 -binary -mac HMAC -macopt hexkey:$hexkey | base64
- ハッシュのアルゴリズムとして HMAC-SHA-1 が利用されているようなので、
openssl sha1
コマンドに、-mac HMAC
と-macopt
オプションを指定して実行しています。 - まず、ハッシュ化する際のキーである文字列を Base64 でデコードし、それを16進数表現にした文字列を変数 hexkey にセットしています。
- 次の行では、その hexkey をキーとして HMAC-SHA-1 アルゴリズムを利用し、’github.com’ のハッシュを算出して、それを Base64 でエンコードしています。
- 元の行には、github.com というホスト名だけでなく IPアドレスもありましたが(‘github.com,192.30.253.113’ の部分) 、ここではホスト名しか利用していません。実は IPアドレスをハッシュ化した行は別に生成されています。つまり、
ssh-keygen -H
コマンドによって、1行が2行になっています。上記の「echo -n ‘github.com’」の部分を「echo -n ‘192.30.253.113’」にすると、生成されるハッシュ値が元の文字列と一致しないので、その行は ‘github.com’ の行だと分かりました(キーも違います)。 - 元の行のホスト名(IPアドレス)の部分が、「[IPアドレス]:ポート番号」となっている場合は、上記の「echo -n ‘github.com’」の部分を「echo -n ‘[IPアドレス]:ポート番号’」とします。
-binary
,-mac
,-macopt
,プションについては /docs/manmaster/man1/openssl-dgst.html で説明されています。
ここでは calc_hash.sh
というファイル名にして実行してみました。
$ ./calc_hash.sh
HCaWOPa5tIlXcNV5Ja99BEd53RA=
想定通りの文字列が出力されました。
3. メモ
- この仕様はかなり古いために、脆弱な HMAC-SHA-1 というハッシュアルゴリズムが採用されているようです。
- 本文でもリンクを貼った chris408/known_hosts-hashcat: A guide and tool for cracking ssh known_hosts files with hashcat には、hashcat を使って known_hosts ファイルのハッシュ文字列からIPアドレスを割り出す方法が紹介されています。
known_hosts
ファイルのホスト名(IPアドレス)がハッシュ化されていると、シェル上でホスト名の補完が効かないために HashKnownHosts を no と設定している環境もあるようです。