ログインまたはアカウント作成でアカウントを作成すると、編集することができます。

DenyHosts で ssh ブルートフォースアタック対策

出典: maruko2 Note.

sshd のログファイル(/var/log/secure など)を定期的に読み込み、sshd の認証に失敗した回数がしきい値(設定した回数)をこえると、/etc/hosts.deny にアクセス拒否の設定を書き込み、接続できないようにする Python のスクリプトです。

Web Site
http://denyhosts.sourceforge.net/

目次


Mac OS X 10.3/10.4 にインストールする

  • python 2.3 以上が必要(インストール済み)
  • ソースコード

http://jaist.dl.sourceforge.net/sourceforge/denyhosts/DenyHosts-2.6.tar.gz

1. 解凍・展開しインストール

$ tar xzf DenyHosts-2.6.tar.gz
$ cd DenyHosts-2.6
$ sudo python setup.py install

2. /usr/share/denyhosts/ に設定ファイル denyhosts.cfg と、DenyHosts をデーモンとして動作させるスクリプト daemon-control がインストールされる。ファイル名の末尾が -dist になっているので、コピーして使用する。((ディストリビューションや OS の違いで、ログファイルの場所が違ったりするため。))

$ cd /usr/share/denyhosts
$ sudo cp daemon-control-dist daemon-control
$ sudo cp denyhosts.cfg-dist denyhosts.cfg

3. Mac OS X には、デフォルトで /etc/host.deny /etc/hosts.allow ファイルがないので作っておく。

$ sudo touch /etc/{hosts.deny,hosts.allow}

4. 設定ファイル denyhosts.cfg を Mac OS X 用に修正 ((denyhosts.cfg に Mac OS X の設定例が書かれているが、それとは違う設定にする。))

SECURE_LOG = /var/log/system.log      ← Mac OS X 10.3 の場合
SECURE_LOG = /var/log/secure.log      ← Mac OS X 10.4 の場合
LOCK_FILE = /var/run/denyhosts.pid    ← Mac OS X 10.3/10.4 共通
DAEMON_LOG = /var/log/denyhosts.log   ← Mac OS X 10.3/10.4 共通

5. daemon-control を Mac OS X 用に修正

DENYHOSTS_BIN = "/System/Library/Frameworks/Python.framework/Versions/2.3/bin/denyhosts.py"
DENYHOSTS_LOCK = "/var/run/denyhosts.pid"

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


デーモンとして起動

$ sudo /usr/share/denyhosts/daemon-control start

ログが大きいと少し時間がかかるかもしれない。

ログの読み込みが完了すると、デーモンとして起動したままになる。

読み込まれ、解析されたデータは、/usr/share/denyhosts/data/ ディレクトリ内に保存される。


/var/log/denyhosts.log で動作確認

denyhosts.log の内容はこんな感じ。

2007-06-02 14:46:53,749 - denyhosts   : INFO     DenyHosts launched with the following args:
2007-06-02 14:46:53,751 - denyhosts   : INFO        /System/Library/Frameworks/Python.framework/Versions/2.3/bin/denyhosts.py --daemon --config=/usr/share/denyhosts/denyhosts.cfg
2007-06-02 14:46:53,752 - prefs       : INFO     DenyHosts configuration settings:
省略

すでに、ブルートフォースアタックがあった場合は、次のように記録される。

2007-06-04 18:09:52,474 - denyhosts   : INFO     new denied hosts: ['219.232.237.39']

そして、/etc/hosts.deny に次のような記述が追加され、sshd への接続を拒否するようになる。

sshd: 219.232.237.39


logrotate している場合どうなるのか

ログを読み込み終わると、data/offset にログの読み込み済みの位置を書き込んで、次回はその位置以降から読み込むようにしている。 ローテートされるログでも問題なく動作する。

2007-06-04 03:15:12,442 - denyhosts   : INFO     /var/log/system.log has been rotated


denyhosts.cfg の設定

SECURE_LOG = /var/log/secure.log
denyhosts の読み込むログファイルの場所
HOSTS_DENY = /etc/hosts.deny
hosts.deny の場所
PURGE_DENY =
拒否するホストを /etc/hosts.deny に登録しておく時間を設定する(この設定時間を過ぎると、拒否するホストから削除される。)
空白の場合は、ずっと登録したままにになる。
--purge オプションを付けてスクリプトを起動しないと実行しない。
#PURGE_THRESHOLD
拒否するホストを /etc/hosts.deny から削除する最大回数を定義する。この回数を超えると、/etc/hosts.deny に登録されたままになる。default 0 (disable)
BLOCK_SERVICE = sshd
/etc/hosts.deny に追加するときのサービス名。
DENY_THRESHOLD_INVALID = 5
この回数より多くログインに失敗したホストをブロックする。存在しないユーザに適用。
DENY_THRESHOLD_VALID = 10
この回数より多くログインに失敗したホストをブロックする。存在するユーザに適用。root は除く。
DENY_THRESHOLD_ROOT = 1
この回数より多くログインに失敗したホストをブロックする。root のみ。
DENY_THRESHOLD_RESTRICTED = 1
この回数より多くログインに失敗したホストをブロックする。WORK_DIR/restricted-usernames ファイルに書かれている username のみ。
WORK_DIR = /usr/share/denyhosts/data
WORK_DIR のパス。
SUSPICIOUS_LOGIN_REPORT_ALLOWED_HOSTS=YES
YES に設定している場合、許可されたホストからの疑わしいログインを、疑わしいログインとしてレポートする。
NOに設定している場合、レポートしない。許可されたホストでない疑わしいログインは、全てレポートする。
HOSTNAME_LOOKUP=YES
YES なら、IP アドレスからホスト名をルックアップする。
LOCK_FILE = /var/run/denyhosts.pid
LOCK_FILE を指定する。

optional setting

ADMIN_EMAIL =
新しい拒否するホストと疑わしいログインについてメールする。
SMTP_HOST = localhost
SMTP サーバのアドレス。
SMTP_PORT = 25
SMTP サーバのポート。
#SMTP_USERNAME=foo
SMTP 認証で使用するユーザ名。
#SMTP_PASSWORD=bar
SMTP 認証のパスワード。
SMTP_FROM = DenyHosts <nobody@localhost>
メールの From: アドレス。
SMTP_SUBJECT = DenyHosts Report
メールの件名。
#SMTP_DATE_FORMAT = %a, %d %b %Y %H:%M:%S %z
メールの Date: の書式。
#SYSLOG_REPORT=NO
syslog へデータを送るかどうか。
#ALLOWED_HOSTS_HOSTNAME_LOOKUP=NO
AGE_RESET_VALID=5d
AGE_RESET_ROOT=25d
AGE_RESET_RESTRICTED=25d
AGE_RESET_INVALID=10d
#RESET_ON_SUCCESS = yes
#PLUGIN_DENY=/usr/bin/true
#PLUGIN_PURGE=/usr/bin/true
#USERDEF_FAILED_ENTRY_REGEX=

daemonmode setting

DAEMON_LOG = /var/log/denyhosts.log
#DAEMON_LOG_TIME_FORMAT = %b %d %H:%M:%S
DAEMON_LOG_MESSAGE_FORMAT = %(asctime)s - %(name)-12s: %(levelname)-8s %(message)s
DAEMON_SLEEP = 30s
デーモンモードで実行中、SECURE_LOG を読みにいくまでのスリープしている時間。
DAEMON_PURGE = 1h
/etc/host.deny の中の過ぎたエントリーをパージする間隔。PURGE_DENY が空のときはなにもしない。

daemon sync setting

#SYNC_SERVER = http://xmlrpc.denyhosts.net:9911
#SYNC_INTERVAL = 1h
#SYNC_UPLOAD = no
#SYNC_DOWNLOAD = no
#SYNC_DOWNLOAD_THRESHOLD = 10
#SYNC_DOWNLOAD_RESILIENCY = 2d

起動スクリプト

/Library/StartupItems/DenyHosts/DenyHosts

#!/bin/sh
 
. /etc/rc.common
 
StartService ()
{
if [ "${DenyHosts:=-NO-}" = "-YES-" ] ; then
  ConsoleMessage "Starting DenyHosts"
  /usr/share/denyhosts/daemon-control start >/dev/null 2>&1
fi
}
 
StopService ()
{
if [ "${DenyHosts:=-NO-}" = "-YES-" ] ; then
  ConsoleMessage "Stopping DenyHosts"
  /usr/share/denyhosts/daemon-control stop >/dev/null 2>&1
fi
}
 
RestartService ()
{
if [ "${DenyHosts:=-NO-}" = "-YES-" ] ; then
  ConsoleMessage "Starting DenyHosts"
  /usr/share/denyhosts/daemon-control restart >/dev/null 2>&1
fi
}
 
RunService "$1"

/Library/StartupItems/DenyHosts/StartupParameters.plist

{
  Description     = "DenyHosts";
  OrderPreference = "Last";
  Messages =
  {
    start = "Starting DenyHosts";
    stop  = "Stopping DenyHosts";
  };
}

/etc/hostconfig に DenyHosts=-YES- を追加


ホワイトリスト (Whitelist)

常に許可するホストのリスト。

/etc/hosts.allow に許可するアドレスを書いておく。hosts.allow にリストされたアドレスは、hosts.deny に追加されても許可される。

  • /etc/hosts.allow の例

IPアドレス 192.168.1.0〜192.168.1.254 のホストからの sshd への接続を常に許可する。

sshd: 192.168.1.
  • denyhosts.py --help [#xc1c15e6]
$ denyhosts.py --help
Usage:
/System/Library/Frameworks/Python.framework/Versions/2.3/bin/denyhosts.py [-f logfile | --file=logfile] [ -c configfile | --config=configfile] [-i | --ignore] [-n | --noemail] [--purge] [--migrate] [--daemon] [--sync] [--version]
 
 
 --file:   The name of log file to parse
 --ignore: Ignore last processed offset (start processing from beginning)
 --noemail: Do not send an email report
 --unlock: if lockfile exists, remove it and run as normal
 --migrate: migrate your HOSTS_DENY file so that it is suitable for --purge
 --purge: expire entries older than your PURGE_DENY setting
 --daemon: run DenyHosts in daemon mode
 --sync: run DenyHosts synchronization mode
 --version: Prints the version of DenyHosts and exits
 
Note: multiple --file args can be processed.  If multiple files are provided, --ignore is implied
 
When run in --daemon mode the following flags are ignored:
     --file, --purge, --migrate, --sync, --verbose


その他

Mac OS X にインストールされている Python

  • PYTHONHOME

/System/Library/Framework/Python.framework/Versions/2.3/

  • PYTHONPATH

/System/Library/Frameworks/Python.framework/Versions/2.3/bin/python /usr/bin/python シンボリックリンク

  • site-packages

/Library/Python/2.3/site-packages

インストールされるファイル

- lib
site-packages/DenyHosts/
	__init__.py
	__init__.pyc
	allowedhosts.py
	allowedhosts.pyc
	constants.py
	constants.pyc
	counter.py
	counter.pyc
	daemon.py
	daemon.pyc
	deny_hosts.py
	deny_hosts.pyc
	denyfileutil.py
	denyfileutil.pyc
	filetracker.py
	filetracker.pyc
	lockfile.py
	lockfile.pyc
	loginattempt.py
	loginattempt.pyc
	old-daemon.py
	old-daemon.pyc
	plugin.py
	plugin.pyc
	prefs.py
	prefs.pyc
	purgecounter.py
	purgecounter.pyc
	python_version.py
	python_version.pyc
	regex.py
	regex.pyc
	report.py
	report.pyc
	restricted.py
	restricted.pyc
	sync.py
	sync.pyc
	util.py
	util.pyc
	version.py
	version.pyc

- script
bin/denyhosts.py

- data
/usr/share/denyhosts
	denyhosts.cfg-dist
	setup.py
	daemon-control-dist
	CHANGELOG.txt
	README.txt
	LICENSE.txt
/usr/share/denyhosts/scripts
	restricted_from_invalid.py
	restricted_from_passwd.py
/usr/share/denyhosts/plugins
	README.contrib
	shorewall_allow.sh
	shorewall_deny.sh
	test_deny.py

ログの読み込みパターン

regex.py に書かれている。

regex.py の一部
 
SSHD_FORMAT_REGEX = re.compile(r""".* (sshd.*:|\[sshd\]) (?P<message>.*)""")
 
FAILED_ENTRY_REGEX = re.compile(r"""Failed (?P<method>.*) for (?P<invalid>invalid user |illegal user )?(?P<user>.*?) .*from (::ffff:)?(?P<host>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})""")
 
FAILED_ENTRY_REGEX2 = re.compile(r"""(?P<invalid>(Illegal|Invalid)) user (?P<user>.*?) .*from (::ffff:)?(?P<host>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})""")
 
FAILED_ENTRY_REGEX3 = re.compile(r"""Authentication failure for (?P<user>.*) .*from (::ffff:)?(?P<host>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})""")
 
FAILED_ENTRY_REGEX4 = re.compile(r"""Authentication failure for (?P<user>.*) .*from (?P<host>.*)""")
 
FAILED_ENTRY_REGEX5 = re.compile(r"""User (?P<user>.*) .*from (?P<host>.*) not allowed because none of user's groups are listed in AllowGroups""")
 
FAILED_ENTRY_REGEX6 = re.compile(r"""Did not receive identification string .*from (::ffff:)?(?P<host>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})""")
 
FAILED_ENTRY_REGEX7 = re.compile(r"""User (?P<user>.*) not allowed because not listed in AllowUsers""")

追加するときは、denyhosts.cfg に SSHD_FORMAT_REGEX = で追加することもできる。


参考ページ

表示