SSHブルートフォースアタックの対応



●DenyHostsとは

 最近、SSHサービスに対し、ユーザ名・パスワードデータベースを使ったログイン攻撃が盛んに行われています。このため、わかりやすいパスワードを使っているユーザがいると簡単に侵入されてしまいます。DenyHostsはこういった不正な攻撃を察知して防御するためのツールです。デフォルトでは、10回の不成功ログイン試行が繰り返されたIPアドレスを/etc/hosts.denyに記録し、接続を拒否します。rootの直接ログイン試行に対しては1回の失敗でも拒否します。
 また、怪しい活動をしているIPアドレスを集めている専用サーバからIPアドレスをダウンロードして予防したり、こちらからアップロードすることもできます。不成功ログイン回数の上限設定、一定時間後に制限解除したい場合はその時間設定(1秒~数年)、不正アクセスレポートメールなど、IPアドレスのアップロードダウンロードの有無、サーバからダウンロードしたIPアドレス細かい動作は設定ファイルで指定できます。

 システムログ(/var/log/messages、/var/log/auth.log、/var/log/secureなど)には様々なシステム上のアクティビティが記録されています。ここには、失敗したログインの記録も残されます。
 失敗したログの例は以下のとおりです。
# cat /var/log/messages | grep sshd
Mar 17 19:24:51 nezumi sshd[27340]: Invalid user user0 from 222.80.184.54
Mar 17 19:25:02 nezumi sshd[27406]: Invalid user zt from 222.80.184.54
Mar 17 19:27:03 nezumi sshd[27594]: Invalid user avouni from 222.80.184.54
Mar 17 19:29:03 nezumi sshd[27848]: Invalid user guest from 222.80.184.54
Mar 17 19:29:05 nezumi sshd[27853]: Invalid user oracle from 222.80.184.54
Mar 17 19:29:18 nezumi sshd[27979]: Invalid user oracle from 222.80.184.54
Mar 17 19:29:21 nezumi sshd[27981]: Invalid user nagios from 222.80.184.54
Mar 17 19:29:37 nezumi sshd[28008]: Invalid user sir from 222.80.184.54
Mar 17 19:31:21 nezumi sshd[28226]: Invalid user ss2701 from 222.80.184.54
Mar 17 19:31:45 nezumi sshd[28260]: Invalid user eggbreaker2 from 222.80.184.54
Mar 17 19:31:48 nezumi sshd[28263]: Invalid user network from 222.80.184.54
Mar 17 19:32:06 nezumi sshd[28282]: Invalid user oracle from 222.80.184.54
Mar 17 19:32:10 nezumi sshd[28287]: Invalid user msr from 222.80.184.54
 短時間のうちに様々なユーザ名でログインが試みられています。これがパスワード辞書攻撃(dictionary-based attack)もしくはブルートフォースアタック(Brute force attack)です。一度、ログインされてしまうと内部から様々なことができるようになります。最悪はシステム乗っ取りですが、他ホストへのDoS(Denial of Service)攻撃やSniffering(ネット上のパスワード盗聴)など、見えにくい形で周囲に大迷惑をかけることも多々あります。
 これを防ぐにはログインを阻止するしかありませんが、わかりやすいパスワードを使用しているユーザが一人でもいれば、辞書攻撃、つまりありそうなパスワード一覧表を片っ端から試すことによって、簡単に破られます。様々なシステムが「大文字、小文字、数字、記号の混じった」「○字以上」のパスワードを設定するよう求めたり、一定期間毎にパスワード変更を求めるのはそういう理由からです。とはいえ、全ユーザにこれを強制するのはあまり現実的でなく、実を言うとシステム側の手抜きです。
 システム側の防御方法としては、TCP_wrapperと呼ばれる方式が広く用いられています。SSHなどのサービスへの接続要求が来たときに、相手先のIPアドレスあるいはドメインを受け入れて良いかどうかを照合してから許可するという比較的単純な方式ですが、有効性が認められています。具体的には、/etc/hosts.allowあるいは/etc/hosts.denyに許可あるいは拒否するサービスとホストの組合わせを書いておくと、相手に応じて許可を出すという仕組みです。
 ここで問題なのが、相手先IPアドレスとして認めて良いかどうかの登録がめんどくさいということです。人手で行っていては、目の前のアタックには間に合わないということも起こります。一方で、特定ホストのみを認める厳しい設定にすれば陥落の心配は減りますが、出張先でアクセスしようとしたとき、事前に設定しておかない限り自分が拒否されてしまうということが起こりえます。出張先のアクセスがホテルからだったり、モバイルサービスからだったりすると、到着までIPアドレスがわからないことも多く、かといって到着するまで全アクセスを受け入れるようにするのは、ちょっと危険で避けたいものです。
 ひとつの解決方法は、頻用されるポートとは異なる番号をサービスに割り当てることで、相手が間抜けな攻撃者であれば、一応かわすことができます。が、現在はポートスキャンによって、目的のサービスがどのポートから供給されているかを調べることができるので、多少の知恵がある攻撃者は防げません。
 こういった背景から、DenyHostsはTCP_wrapperを利用しつつ、/etc/hosts.denyへの書き込みを自動化することで、いつでもリアルタイムに対応できるようにしたものです。具体的には、セキュリティログを監視し、何度も繰り返しログインに失敗しているIPアドレスがあると、それを/etc/hosts.denyに書き込んでその後のログインを許可しないようにするというものです。仕組みは単純ですが、辞書攻撃には絶大な効果があります。
 アクセスされた相手のみの拒否では、攻撃を防ぎきれないことがあります。そこで拒否アドレスデータベースサーバがあり、一定時間毎にダウンロード/アップロードできるような仕組みも提供されています。多くの攻撃者は、次々に様々なホストにアクセスを試みるので、こういったデータベースは防御に極めて有効です。
 最後に、自分自身がなんらかの事情でパスワードを忘れて拒否されてしまう場合にも、対策が用意されています。一定時間が過ぎると、拒否リストから自動的に取り除くようにする設定ができるようになっているのです。「一定時間」も自由に設定可能ですが、経験上、90分程度以上に設定するのが妥当なようです。攻撃に失敗した人が、少し時間をおいて戻ってきてしまうことがあるからです。

●SSHへのブルートフォースアタック(ID, PASS 総当たり攻撃)への対応

 SSHへのブルートフォースアタックは必ず経験する攻撃の一つです。ブルートフォースアタックへの対応策は必ずしておきましょう。
 ブルートフォースアタックを受けていることを確認するにはログファイルを確認します。まずログファイルの場所を確認し、そのログファイルを参照します。
# cat /etc/syslog.conf
Fedora や CentoOSの場合下記コマンドで確認できます。
cat /var/log/secure | grep "Invalid user"
cat /var/log/secure | grep "Failed password"
cat /var/log/messages | grep "failure"

 対応策1./etc/ssh/sshd_configを変更
#vi /etc/ssh/sshd_config
 以下の設定を追加する
# 最大同時認証数数を3にする
MaxAuthTries 3
# 2つを超える認証受付は90%の確率で遮断。4つを超えると全て遮断
MaxStartups 2:90:4
MaxAuthTries(最大認証試行回数)
1接続あたりの認証を最大で何回まで試みることができるかを指定します。ここで指定された半数以上の認証が失敗すると、それ以降の失敗はログに記録されます。デフォルトの値は 6 です。
MaxStartups(最大起動数)
認証されていない段階の接続を sshd デーモンが最大でどれだけ受けつけるかを指定します。この値を超えた (認証されていない段階の) 接続は捨てられます。この状態は (すでに接続したクライアントの) 認証が成功するか、その LoginGraceTime (ログイン猶予時間) が切れるまで続きます。デフォルトではこの数は 10 です。

もうひとつの方法は、早いうちからランダムに接続を拒否するよう指定することです。これはこのオプションにコロンで区切った 3つの値を与えることによりおこないます。この値は ``start:rate:full'' (``開始時:確率:最大数'') の形をとります (例: "10:30:60" など)。 sshd は認証されていない段階の接続が ``start'' (この例では 10) 個を超えると、これ以後の接続要求を ``rate/100'' (この例では 30%) の確率で拒否しはじめます。この確を拒否するようになります。

 対応策2./etc/hosts.denyに手動でアクセスしてほしくないホストを追加
/etc/hosts.deny
以下を追加
(IP:1.0.0.0からのssh接続を拒否する場合)
(IP:1.255.255.255からの全ての接続を拒否する場合)
sshd: 1.0.0.0
ALL : 1.255.255.255

 対応策3./etc/hosts.denyにアクセスしてほしくないホストを自動追加する

 http://denyhosts.sourceforge.net/からDenyHosts-2.6.tar.gzをダウンロード
# tar zxvf DenyHosts-2.6.tar.gz 
# cd DenyHosts-2.6
# python setup.py install
インストールが完了したらコンフィグファイルをコピーし所有者と権限を変更する
# cd /usr/share/denyhosts/
# cp denyhosts.cfg-dist denyhosts.cfg
# cp daemon-control-dist daemon-control
# chown root daemon-control
# chmod 700 daemon-control
 denyhosts.cfgを編集します。
# vi /usr/share/denyhosts/denyhosts.cfg
# RPM版の場合
EPELリポジトリを追加
# rpm -ivh http://ftp.riken.jp/Linux/fedora/epel/7/x86_64/e/epel-release-7-6.noarch.rpm
OSやバージョンによって異なるので注意
# vi /etc/denyhosts.conf
または
# vi /etc/denyhosts/denyhosts.cfg
設定例
# 4週間経過すると拒否対象から解除
PURGE_DENY = 4w
# 拒否解除を2回行うとそれ以降は解除しない
PURGE_THRESHOLD = 2
# 存在しないユーザでの認証の失敗5回で拒否ホストに認定
DENY_THRESHOLD_INVALID = 5
# 存在するユーザでの認証の失敗10回で拒否ホストに認定
DENY_THRESHOLD_VALID = 10
# rootでの認証の失敗1回で拒否ホストに認定
DENY_THRESHOLD_ROOT = 1
# メールにて通知
ADMIN_EMAIL = user1@hogehoge.com
# メールタイトルを指定する
SMTP_SUBJECT = DenyHosts Report Server( yourhost.server )
 自動起動の設定します。
# cd /etc/init.d
ln -s /usr/share/denyhosts/daemon-control denyhosts
# chkconfig denyhosts on
 denyhostsを起動します。 # service denyhosts start  間違って自分のホストが denyhosts によって拒否された場合は # vi /etc/hosts.allow として接続を許可したいIPアドレスを追加します
sshd: 10.10.10.10
 DENY_THRESHOLD_INVALID及びDENY_THRESHOLD_VALIDの数値は小さければ小さいほどアクセス拒否効果が上がります。
 しかし、アクセス拒否しているにも関わらず定期的に攻撃してくる”馬鹿野郎”がいます。ログ出力されるのが鬱陶しい。whoisコマンドで調査し、該当するネットワークまるごと拒否するように設定しました。これでログもすっきりしました。

●DenyHostsの設定項目

 CentoOS 6にdenyhostsをインストールします。

設定項目
  • PURGE_DENY
    自動的に拒否対象から解除するまでの時間
    ex 24h(m,h,d,w,yで指定します。)
  • PURGE_THRESHOLD
    拒否解除が有効な回数。この回数を超えてしまうと、二度と解除されません。設定しないと、自動的に解除されなくなる。0で解除の回数制限が無くなる。
  • BLOCK_SERVICE
    ブロックをするサービス。今回はsshdのみ指定しました。
    hosts.allow/denyで指定出来るサービスを記述します。全てならALL
  • DENY_THRESHOLD_INVALID
    サーバに登録されていないユーザでのログイン失敗時の閾値
  • DENY_THRESHOLD_VALID
    サーバに登録されてるユーザでのログイン失敗時の閾値
  • DENY_THRESHOLD_ROOT
    rootでのログイン失敗時の閾値今回は1回でBANに設定しました。
  • WORK_DIR
    YESに設定している場合、許可されたホストからの疑わしいログインを、疑わしいログインとしてレポートする。NOに設定している場合、レポートしない。許可されたホストでない疑わしいログインは、全てレポートする。
  • SUSPICIOUS_LOGIN_REPORT_ALLOWED_HOSTS = [Yes/No]
    怪しいログインを監視するか。
  • ADMIN_EMAIL
    イベントメールの送信先。『,』で複数指定可能です
  • SMTP_HOST
  • SMTP_PORT
    SMTPサーバの指定
  • SMTP_FROM
  • SMTP_SUBJECT
    メールの送信元と件名
  • SYNC_SERVER
    Denyhostsユーザから送信されたりして集められた、不正アクセス元のIPアドレスリストを同期させるサーバ
    コメント解除
  • SYNC_INTERVAL
    同期間隔
  • SYNC_UPLOAD
  • SYNC_DOWNLOAD
    同期する時に、自分のデータをUPするか、DownLoadするか。Yes、Noで指定。
  • SYNC_DOWNLOAD_THRESHOL
    ここで指定した数以上のサーバで拒否されたアドレスをDownloadリストの中から設定する。
 ログは標準では、/var/log/denyhostsに出力されます。

●常に許可するIPアドレスを設定

 常にアクセスを許可しておきたいIPアドレスは、/var/lib/denyhosts/allowed-hostsに設定しておきます。
# vi /var/lib/denyhosts/allowed-hosts
# We mustn't block localhost
127.0.0.1
192.168.1.*
 また、/etc/hosts.allowにも記載する必要があります。

●ブロックされない

 外部から攻撃されているにもかかわらず/etc/hosts.denyにIPアドレスが追加されない場合、「SECURE_LOG」を確認してください。対象となるログを変更することにより正常に動作するようになります。
SECURE_LOG = /var/log/secure
  ↓
SECURE_LOG = /var/log/messages
 変更したらdenyhostsを再起動してください。

●誤って拒否登録されてしまったものを取り消す方法

 denyhostsを停止させます。
# /etc/init.d/denyhosts stop
 denyhostsが停止したことを確認します。
# ps aux | grep denyhosts
以下のファイルを編集し, 拒否しないIPアドレスを削除します。
   /etc/hosts.deny
   /var/lib/denyhosts/hosts
   /var/lib/denyhosts/hosts-restricted
   /var/lib/denyhosts/hosts-root
   /var/lib/denyhosts/hosts-valid
   /var/lib/denyhosts/users-hosts
 /var/lib/denyhosts/allowed-hostsを編集し、拒否しないIPアドレスを追加します。
 denyhostsをスタートします。
   # /etc/init.d/denyhosts start
 denyhostsが動作したことを確認します。
# ps aux | grep denyhosts