DenyHostsでSSHブルートフォースアタックに対抗 CentOS

たまたま/var/log/secureを除いたら怪しいログが!

sshd[4113]: Invalid user shashi from 114.141.167.190 port 57982
sshd[4113]: input_userauth_request: invalid user shashi [preauth]
sshd[4113]: pam_unix(sshd:auth): check pass; user unknown
sshd[4113]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=114.141.167.190
sshd[4113]: Failed password for invalid user shashi from 114.141.167.190 port 57982 ssh2
sshd[4113]: Received disconnect from 114.141.167.190 port 57982:11: Bye Bye [preauth]
sshd[4113]: Disconnected from 114.141.167.190 port 57982 [preauth]
sshd[5949]: Invalid user joerg from 181.49.246.20 port 33874
sshd[5949]: input_userauth_request: invalid user joerg [preauth]
sshd[5949]: pam_unix(sshd:auth): check pass; user unknown
sshd[5949]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=181.49.246.20
sshd[5949]: Failed password for invalid user joerg from 181.49.246.20 port 33874 ssh2
sshd[5949]: Received disconnect from 181.49.246.20 port 33874:11: Bye Bye [preauth]
sshd[5949]: Disconnected from 181.49.246.20 port 33874 [preauth]
sshd[18062]: Invalid user admin from 106.241.33.158 port 23663
sshd[18062]: input_userauth_request: invalid user admin [preauth]
sshd[18062]: pam_unix(sshd:auth): check pass; user unknown
sshd[18062]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=106.241.33.158
sshd[18062]: Failed password for invalid user admin from 106.241.33.158 port 23663 ssh2
sshd[18062]: Received disconnect from 106.241.33.158 port 23663:11: Bye Bye [preauth]
sshd[18062]: Disconnected from 106.241.33.158 port 23663 [preauth]

明らかな攻撃ですね。

何も対策してなかったので対策しないといけないですね。

調べると色々あるようです。
日本以外からのアクセスを拒否するとか、手動で拒否するIPを追加するとか。。。

まあエンジニアなので自動化します!

自動化するソフトとしてはDenyHosts, Fail2banといったところが有名なようです。

DenyHostsはSSH用で拒否するIPをhosts.deny(拒否IPリスト)に追加していくという単純なもの。

Fail2banはiptableベースでSSH以外にも対応しているらしい。

今回はDenyHostsで対応することに。

昔はepelのリポジトリにあったようですが、現在は削除されている模様。

というわけでgithubのリポジトリにrpmがあるのでgithubからインストールします。(2020-07現在の最新版は3.1.2)
https://github.com/denyhosts/denyhosts/releases

$ yum install https://github.com/denyhosts/denyhosts/releases/download/v3.1/DenyHosts-3.1.2-1.noarch.rpm
$ $ rpm -ql DenyHosts
/etc/denyhosts.conf
/usr/local/bin/daemon-control-dist
/usr/local/bin/denyhosts.py
/usr/local/lib/python2.7/dist-packages/DenyHosts-3.1.2.egg-info
/usr/local/lib/python2.7/dist-packages/DenyHosts/__init__.py
/usr/local/lib/python2.7/dist-packages/DenyHosts/__init__.pyc
/usr/local/lib/python2.7/dist-packages/DenyHosts/__init__.pyo
/usr/local/lib/python2.7/dist-packages/DenyHosts/allowedhosts.py
/usr/local/lib/python2.7/dist-packages/DenyHosts/allowedhosts.pyc
/usr/local/lib/python2.7/dist-packages/DenyHosts/allowedhosts.pyo
/usr/local/lib/python2.7/dist-packages/DenyHosts/constants.py
/usr/local/lib/python2.7/dist-packages/DenyHosts/constants.pyc
/usr/local/lib/python2.7/dist-packages/DenyHosts/constants.pyo
/usr/local/lib/python2.7/dist-packages/DenyHosts/counter.py
/usr/local/lib/python2.7/dist-packages/DenyHosts/counter.pyc
/usr/local/lib/python2.7/dist-packages/DenyHosts/counter.pyo
/usr/local/lib/python2.7/dist-packages/DenyHosts/daemon.py
/usr/local/lib/python2.7/dist-packages/DenyHosts/daemon.pyc
/usr/local/lib/python2.7/dist-packages/DenyHosts/daemon.pyo
/usr/local/lib/python2.7/dist-packages/DenyHosts/deny_hosts.py
/usr/local/lib/python2.7/dist-packages/DenyHosts/deny_hosts.pyc
/usr/local/lib/python2.7/dist-packages/DenyHosts/deny_hosts.pyo
/usr/local/lib/python2.7/dist-packages/DenyHosts/denyfileutil.py
/usr/local/lib/python2.7/dist-packages/DenyHosts/denyfileutil.pyc
/usr/local/lib/python2.7/dist-packages/DenyHosts/denyfileutil.pyo
/usr/local/lib/python2.7/dist-packages/DenyHosts/filetracker.py
/usr/local/lib/python2.7/dist-packages/DenyHosts/filetracker.pyc
/usr/local/lib/python2.7/dist-packages/DenyHosts/filetracker.pyo
/usr/local/lib/python2.7/dist-packages/DenyHosts/lockfile.py
/usr/local/lib/python2.7/dist-packages/DenyHosts/lockfile.pyc
/usr/local/lib/python2.7/dist-packages/DenyHosts/lockfile.pyo
/usr/local/lib/python2.7/dist-packages/DenyHosts/loginattempt.py
/usr/local/lib/python2.7/dist-packages/DenyHosts/loginattempt.pyc
/usr/local/lib/python2.7/dist-packages/DenyHosts/loginattempt.pyo
/usr/local/lib/python2.7/dist-packages/DenyHosts/plugin.py
/usr/local/lib/python2.7/dist-packages/DenyHosts/plugin.pyc
/usr/local/lib/python2.7/dist-packages/DenyHosts/plugin.pyo
/usr/local/lib/python2.7/dist-packages/DenyHosts/prefs.py
/usr/local/lib/python2.7/dist-packages/DenyHosts/prefs.pyc
/usr/local/lib/python2.7/dist-packages/DenyHosts/prefs.pyo
/usr/local/lib/python2.7/dist-packages/DenyHosts/purgecounter.py
/usr/local/lib/python2.7/dist-packages/DenyHosts/purgecounter.pyc
/usr/local/lib/python2.7/dist-packages/DenyHosts/purgecounter.pyo
/usr/local/lib/python2.7/dist-packages/DenyHosts/python_version.py
/usr/local/lib/python2.7/dist-packages/DenyHosts/python_version.pyc
/usr/local/lib/python2.7/dist-packages/DenyHosts/python_version.pyo
/usr/local/lib/python2.7/dist-packages/DenyHosts/regex.py
/usr/local/lib/python2.7/dist-packages/DenyHosts/regex.pyc
/usr/local/lib/python2.7/dist-packages/DenyHosts/regex.pyo
/usr/local/lib/python2.7/dist-packages/DenyHosts/report.py
/usr/local/lib/python2.7/dist-packages/DenyHosts/report.pyc
/usr/local/lib/python2.7/dist-packages/DenyHosts/report.pyo
/usr/local/lib/python2.7/dist-packages/DenyHosts/restricted.py
/usr/local/lib/python2.7/dist-packages/DenyHosts/restricted.pyc
/usr/local/lib/python2.7/dist-packages/DenyHosts/restricted.pyo
/usr/local/lib/python2.7/dist-packages/DenyHosts/sync.py
/usr/local/lib/python2.7/dist-packages/DenyHosts/sync.pyc
/usr/local/lib/python2.7/dist-packages/DenyHosts/sync.pyo
/usr/local/lib/python2.7/dist-packages/DenyHosts/util.py
/usr/local/lib/python2.7/dist-packages/DenyHosts/util.pyc
/usr/local/lib/python2.7/dist-packages/DenyHosts/util.pyo
/usr/local/lib/python2.7/dist-packages/DenyHosts/version.py
/usr/local/lib/python2.7/dist-packages/DenyHosts/version.pyc
/usr/local/lib/python2.7/dist-packages/DenyHosts/version.pyo
/usr/share/man/man8
/usr/share/man/man8/denyhosts.8.gz

これでインストール完了。

本体は/usr/local/bin/denyhosts.pyというpythonスクリプトです。

いちいち起動するのはアホなんでsystemdに登録します。

そこで使用するのが/usr/local/bin/daemon-control-dist

こちらを/etc/init.d以下にコピーします

$ cp /usr/local/bin/daemon-control-dist /etc/init.d/denyhosts

ちょこっと中身も編集します。

###############################################
# Edit these to suit your configuration #
###############################################
DENYHOSTS_BIN = "/usr/sbin/denyhosts.py"
DENYHOSTS_LOCK = "/run/denyhosts.pid"
DENYHOSTS_CFG = "/etc/denyhosts.conf"
PYTHON_BIN = "/usr/bin/python3"

ここのDENYHOSTS_BINが異なるので実際のパスに変更

python3はデフォでは入ってないのでPYTHON_BINをpythonに

編集した結果が以下

###############################################
#    Edit these to suit your configuration    #
###############################################
DENYHOSTS_BIN = "/usr/local/bin/denyhosts.py"
DENYHOSTS_LOCK = "/run/denyhosts.pid"
DENYHOSTS_CFG = "/etc/denyhosts.conf"
PYTHON_BIN = "/usr/bin/python"

これでOK.

余談ですが、実はこのコードの下にOS判定のコードがあるんですが、いけてなくてうまくCentOSだと認識してくれません。
しかも、判定されても/usr/bin/denyhosts.pyに設定されるので使えない。。。

これで使えると思いきや、実はさっきyumでインストールしたDenyHostsのライブラリにパスが通ってない。。。
pythonのモジュール検索パスに含まれていないところにインストールされています。。。

というわけで、検索パス上にリンクを作ります(もちろんパスを追加してもOK)

$ ln -s /usr/local/lib/python2.7/dist-packages/DenyHosts /usr/lib/python2.7/site-packages/DenyHosts


そして、DenyHostsで使用しているpythonライブラリをインストールします。
基本的にはipaddrだけだと思います。

$ pip install ipaddr




そして最後に肝心のdenyhostsの設定です。
/etc/denyhosts.confを編集します

デフォルトでは監視するログファイルが/var/log/auth.logになっているので/var/log/secureに変更します

SECURE_LOG = /var/log/secure

これでsystemdでdenyhostsを起動すれば動くはず。

$ sudo systemctl start denyhosts


ちゃんと動いていれば、しばらく攻撃を受け続けた後に/etc/hosts.denyにIPが追加されているはず。

我が家では1日で約300件追加されてました。。。(それでもまだ攻撃を受けている。。。)

ちなみに主な設定項目の意味はこちら

SECURE_LOG 監視するsshdのログファイル
HOST_DENY アクセス拒否リスト
PURGE_DENY アクセス拒否リストにから削除する経過時間 空の場合永遠
BLOCK_SERVICE アクセス拒否リストを使用して拒否するサービス
DENY_THRESHOLD_INVALID アクセス拒否リストに入れる存在しないユーザーでのログイン試行回数
DENY_THRESHOLD_VALID アクセス拒否リストに入れるログイン失敗回数
DENY_THRESHOLD_ROOT アクセス拒否リストに入れるrootでのログイン試行回数
IPTABLES iptablesのパス iptablesを使って拒否する場合
DAEMON_SLEEP
DAEMON_PURGE アクセス拒否の解除を判断する間隔 PURGE_DENYが空の場合は無意味
SYNC_SERVER アクセス拒否リストを同期するサーバー 同期機能を使用する場合
SYNC_INTERVAL アクセス拒否リストの同期間隔
SYNC_UPLOAD アクセス拒否リストをサーバーに送るかどうか
SYNC_DOWNLOAD アクセス拒否リストをサーバーから取ってくるかどうか

というわけでグッドラック!

コメントする