「SIP-Fail2ban」の版間の差分

提供: VoIP-Info.jp
移動先: 案内検索
(起動の確認)
(5人の利用者による、間の13版が非表示)
1行目: 1行目:
IAXでのFail2banは'''IAX-Fail2ban'''を参照してください。
+
IAXでのFail2banは'''[[IAX-Fail2ban]]'''を参照してください。
 
==fail2ban==
 
==fail2ban==
 
ログファイルとiptablesを利用したファイアウォールの一種。Brute Forceアタックの対策に使いやすい。<br>
 
ログファイルとiptablesを利用したファイアウォールの一種。Brute Forceアタックの対策に使いやすい。<br>
 
:http://www.fail2ban.org/
 
:http://www.fail2ban.org/
 
:http://sourceforge.net/projects/fail2ban/
 
:http://sourceforge.net/projects/fail2ban/
==動作条件==
+
iptablesおよびpythonを必要とします。最新のFail2banではAsteriskにも対応しています。
pythonとiptablesが必要。yum install python iptablesなどで入れておいて下さい。
 
==インストール==
 
まずSFからfail2banをダウンロードし、展開します。
 
tar jxvf fail2ban-0.8.4.tar.bz2
 
展開したディレクトリでインストールを実行します。
 
cd fail2ban-0.8.4
 
python ./setup.py
 
スタートアップ・スクリプトをコピーしておきます(CentOSなどRedHat系の場合の例)。
 
cp files/redhat-initd /etc/init.d/fail2ban install
 
  
==設定==
+
==CentOS==
===Asteriskのログフォーマットを変更する===
+
CentOSではeaplからyumでインストールすることが可能です。
Fail2banはそのままではAsteriskのログの日付を認識できないため、Asteriskのログフォーマットを変更します。<br>
+
yum install -y epel-release
/etc/asterisk/logger.confを編集し、日付のフォーマット変更を行います。<br>
+
yum --enablerepo=epel -y install fail2ban
[general]セクションにある
+
yumでインストールした最新のFail2BanはAsteriskのログフォーマットを変更し、ローカル設定ファイルを作成するだけで使用することができます。<BR>
 +
まずAsteriskのlogger.confを修正し
 +
[general]
 +
; Customize the display of debug message time stamps
 +
; this example is the ISO 8601 date format (yyyy-mm-dd HH:MM:SS)
 +
; see strftime(3) Linux manual for format specifiers
 
  dateformat=%F %T
 
  dateformat=%F %T
のコメントを外すか、もしこのエントリがなければ記述します。設定を変更したら、Asteriskを再起動するか、loggerモジュールのリロードを行って、変更を有効にします。これによりAsteriskのログの日付形式が以下のように変わりますので、確認してください。
+
dateformatの箇所のコメント(;)を外して有効にし、Asteriskを再起動します。<br>
[2010-12-30 09:25:25] NOTICE[17537] chan_sip.c:.....
+
/etc/fail2ban/に以下の内容のjail.localというファイルを作成します。ファイルがある場合には修正します。
===Asterisk用の定義ファイルを作る===
+
[DEFAULT]
/etc/fail2ban/filter.d ディレクトリに asterisk.conf という名前で以下のようなファイルを作ります。ここで指定したメッセージがBAN基準として使われるメッセージとなります。<br>
+
ignoreip =
<br>
+
  backend = polling
Asterisk 1.8系の場合
+
  bantime = 3600 ; 1hour
  # Fail2Ban configuration file
+
  maxretry= 5
  #
+
  usedns = no
  #
 
  # $Revision: 250 $
 
  #
 
 
   
 
   
  [INCLUDES]
+
  [asterisk]
 +
enabled = true
 +
fail2banを起動すると監視が始まります。
 +
 
 +
 
 +
===起動の確認===
 +
iptables -Lでiptablesの状態を確認するとfail2banでbanされたIPアドレス等が確認できます。
 +
Chain f2b-asterisk-tcp (1 references)
 +
target    prot opt source              destination
 +
REJECT    all  --  46.17.42.180        anywhere            reject-with icmp-port-unreachable
 +
RETURN    all  --  anywhere            anywhere
 
   
 
   
  # Read common prefixes. If any customizations available -- read them from
+
  Chain f2b-asterisk-udp (1 references)
  # common.local
+
target    prot opt source              destination
  #before = common.conf
+
REJECT    all  --  46.17.42.180        anywhere            reject-with icmp-port-unreachable
 +
RETURN    all  -- anywhere            anywhere
 +
デフォルトではban時間は1時間です。
 +
 
 +
==INVITEによるBrute force攻撃への対策==
 +
REGISTERメッセージによる攻撃以外に、INVITEによるBrute force攻撃も確認されています。
 +
 
 +
この攻撃時に出力されるログメッセージは以下のようなものになります。
 +
 
 +
  Failed to authenticate user "Anonymous" <sip:anonymous@192.168.1.2>;tag=as105e401c
 +
 
 +
このログメッセージの攻撃元IPアドレスが、FROMヘッダに記載されているIPアドレスになっています。
 +
 
 +
このままでは、NAT配下のサーバーからの攻撃や、FROMヘッダが偽装された場合にfail2banで対応することができません。
 +
 
 +
そこで、Asteriskへパッチを当てて、実際の攻撃元IPアドレスを表示するように修正します。
 +
 
 +
===Asteriskへパッチを当てる===
 +
 
 +
次のようなパッチをAsteriskに適用します。
 +
 
 +
このパッチはAsterisk-1.4.40を対象にしていますが、1.6系、1.8系にも同様の修正で対応できます。
 +
 
 +
--- asterisk-1.4.40.orig/channels/chan_sip.c    2011-01-05 02:11:48.000000000 +0900
 +
  +++ asterisk-1.4.40/channels/chan_sip.c 2011-03-10 17:59:26.000000000 +0900
 +
@@ -15456,7 +15456,7 @@
 +
                                ast_log(LOG_NOTICE, "Sending fake auth rejection for user %s\n", get_header(req, "From"));
 +
                                transmit_fake_auth_response(p, SIP_INVITE, req, XMIT_RELIABLE);
 +
                        } else {
 +
-                              ast_log(LOG_NOTICE, "Failed to authenticate user %s\n", get_header(req, "From"));
 +
+                              ast_log(LOG_NOTICE, "Failed to authenticate user %s (%s:%d)\n", get_header(req, "From"), ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
 +
                                transmit_response_reliable(p, "403 Forbidden", req);
 +
                        }
 +
                        p->invitestate = INV_COMPLETED;
 
   
 
   
 +
こちらは Asterisk-1.8.23.0 用です。Asterisk-11.5.1 でもほぼ同じコードが使えます。
 +
 +
--- asterisk-1.8.23.0/channels/chan_sip.c.orig  2013-08-02 11:41:03.233638321 +0900
 +
+++ asterisk-1.8.23.0/channels/chan_sip.c      2013-12-06 14:51:08.698990909 +0900
 +
@@ -22673,7 +22673,7 @@
 +
                        return 0;
 +
                }
 +
                if (res < 0) { /* Something failed in authentication */
 +
-                      ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", get_header(req, "From"));
 +
+                      ast_log(LOG_NOTICE, "Failed to authenticate device %s (%s)\n", get_header(req, "From"), ast_sockaddr_stringify(addr));
 +
                        transmit_response(p, "403 Forbidden", req);
 +
                        sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
 +
                        return 0;
 +
@@ -23334,7 +23334,7 @@
 +
                        goto request_invite_cleanup;
 +
                }
 +
                if (res < 0) { /* Something failed in authentication */
 +
-                      ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", get_header(req, "From"));
 +
+                      ast_log(LOG_NOTICE, "Failed to authenticate device %s (%s)\n", get_header(req, "From"), ast_sockaddr_stringify(addr));
 +
                        transmit_response_reliable(p, "403 Forbidden", req);
 +
                        p->invitestate = INV_COMPLETED;
 +
                        sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
 +
@@ -25164,7 +25164,7 @@
 +
                p->lastinvite = seqno;
 +
                return 0;
 +
        } else if (auth_result < 0) {
 +
-              ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", get_header(req, "From"));
 +
+              ast_log(LOG_NOTICE, "Failed to authenticate device %s (%s)\n", get_header(req, "From"), ast_sockaddr_stringify(addr));
 +
                transmit_response(p, "403 Forbidden", req);
 +
                sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
 +
                ast_string_field_set(p, theirtag, NULL);
 +
@@ -25384,7 +25384,7 @@
 +
                if (res == AUTH_CHALLENGE_SENT) /* authpeer = NULL here */
 +
                        return 0;
 +
                if (res != AUTH_SUCCESSFUL) {
 +
-                      ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", get_header(req, "From"));
 +
+                      ast_log(LOG_NOTICE, "Failed to authenticate device %s (%s)\n", get_header(req, "From"), ast_sockaddr_stringify(addr));
 +
                        transmit_response(p, "403 Forbidden", req);
 
   
 
   
  [Definition]
+
                        pvt_set_needdestroy(p, "authentication failed");
 +
 
 +
Asterisk 11.23.1用パッチです。
 +
 
 +
  --- channels/chan_sip.c.orig    2016-09-09 01:28:35.000000000 +0900
 +
+++ channels/chan_sip.c 2016-10-28 23:26:38.985774935 +0900
 +
@@ -18751,7 +18751,7 @@ static void receive_message(struct sip_p
 +
                        return;
 +
                }
 +
                if (res < 0) { /* Something failed in authentication */
 +
-                      ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", sip_get_header(req, "From"));
 +
+                      ast_log(LOG_NOTICE, "Failed to authenticate device %s (%s)\n", sip_get_header(req, "From"), ast_sockaddr_stringify(addr));
 +
                        transmit_response(p, "403 Forbidden", req);
 +
                        sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
 +
                        return;
 +
@@ -24963,7 +24963,7 @@ static int handle_request_options(struct
 +
                        return 0;
 +
                }
 +
                if (res < 0) { /* Something failed in authentication */
 +
-                      ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", sip_get_header(req, "From"));
 +
+                      ast_log(LOG_NOTICE, "Failed to authenticate device %s (%s)\n", sip_get_header(req, "From"), ast_sockaddr_stringify(addr));
 +
                        transmit_response(p, "403 Forbidden", req);
 +
                        sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
 +
                        return 0;
 +
@@ -25798,7 +25798,7 @@ static int handle_request_invite(struct
 +
                        goto request_invite_cleanup;
 +
                }
 +
                if (res < 0) { /* Something failed in authentication */
 +
-                      ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", sip_get_header(req, "From"));
 +
+                      ast_log(LOG_NOTICE, "Failed to authenticate device %s (%s)\n", sip_get_header(req, "From"), ast_sockaddr_stringify(addr));
 +
                        transmit_response_reliable(p, "403 Forbidden", req);
 +
                        p->invitestate = INV_COMPLETED;
 +
                        sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
 +
@@ -27788,7 +27788,7 @@ static int handle_request_publish(struct
 +
                p->lastinvite = seqno;
 +
                return 0;
 +
        } else if (auth_result < 0) {
 +
-              ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", sip_get_header(req, "From"));
 +
+              ast_log(LOG_NOTICE, "Failed to authenticate device %s (%s)\n", sip_get_header(req, "From"), ast_sockaddr_stringify(addr));
 +
                transmit_response(p, "403 Forbidden", req);
 +
                sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
 +
                ast_string_field_set(p, theirtag, NULL);
 +
@@ -28003,7 +28003,7 @@ static int handle_request_subscribe(stru
 +
                if (res == AUTH_CHALLENGE_SENT) /* authpeer = NULL here */
 +
                        return 0;
 +
                if (res != AUTH_SUCCESSFUL) {
 +
-                      ast_log(LOG_NOTICE, "Failed to authenticate device %s for SUBSCRIBE\n", sip_get_header(req, "From"));
 +
+                      ast_log(LOG_NOTICE, "Failed to authenticate device %s (%s) for SUBSCRIBE\n", sip_get_header(req, "From"), ast_sockaddr_stringify(addr));
 +
                        transmit_response(p, "403 Forbidden", req);
 
   
 
   
#_daemon = asterisk
+
                        pvt_set_needdestroy(p, "authentication failed");
+
 
# Option:  failregex
+
 
# Notes.:  regex to match the password failures messages in the logfile. The
+
 
#          host must be matched by a group named "host". The tag "<HOST>" can
+
パッチを当てて、Asteriskをコンパイルし直し、再起動します。
#          be used for standard IP/hostname matching and is only an alias for
+
 
#          (?:::f{4,6}:)?(?P<host>\S+)
+
すると、先ほどの攻撃時のログは以下のように出力されるようになります。
# Values:  TEXT
+
 
#
+
  Failed to authenticate user "Anonymous" <sip:anonymous@192.168.1.2>;tag=as105e401c (123.45.67.89:5060)
   
+
 
failregex = Registration from '.*' failed for '<HOST>(:[0-9]{1,5})?' - Wrong password
+
ログの( )内に攻撃元の実IPアドレスが表示されるようになり、これを元にfail2banで攻撃を検知することができます。
            Registration from '.*' failed for '<HOST>(:[0-9]{1,5})?' - No matching peer found
+
 
            Registration from '.*' failed for '<HOST>(:[0-9]{1,5})?' - Username/auth name mismatch
+
===fail2banへ設定を追加===
            Registration from '.*' failed for '<HOST>(:[0-9]{1,5})?' - Device does not match ACL
+
 
            Registration from '.*' failed for '<HOST>(:[0-9]{1,5})?' - Peer is not supposed to register
+
修正したログに合わせたフィルタ設定をfail2banに追加します。
            Registration from '.*' failed for '<HOST>(:[0-9]{1,5})?' - Not a local domain
+
 
+
/etc/fail2ban/filter.d/asterisk.conf の failregex の項目に以下を追加します。
# Option:  ignoreregex
 
# Notes.:  regex to ignore. If this regex matches, the line is ignored.
 
# Values:  TEXT
 
#
 
ignoreregex =
 
Asterisk 1.6とそれ以前の場合
 
# Fail2Ban configuration file
 
#
 
#
 
# $Revision: 250 $
 
#
 
 
[INCLUDES]
 
 
# Read common prefixes. If any customizations available -- read them from
 
# common.local
 
#before = common.conf
 
 
 
[Definition]
 
 
#_daemon = asterisk
 
 
# Option:  failregex
 
# Notes.:  regex to match the password failures messages in the logfile. The
 
#          host must be matched by a group named "host". The tag "<HOST>" can
 
#          be used for standard IP/hostname matching and is only an alias for
 
#          (?:::f{4,6}:)?(?P<host>\S+)
 
# Values:  TEXT
 
#
 
 
failregex = Registration from '.*' failed for '<HOST>' - Wrong password
 
            Registration from '.*' failed for '<HOST>' - No matching peer found
 
            Registration from '.*' failed for '<HOST>' - Username/auth name mismatch
 
            Registration from '.*' failed for '<HOST>' - Device does not match ACL
 
            Registration from '.*' failed for '<HOST>' - Peer is not supposed to register
 
            Registration from '.*' failed for '<HOST>' - Not a local domain
 
 
# Option:  ignoreregex
 
# Notes.:  regex to ignore. If this regex matches, the line is ignored.
 
# Values:  TEXT
 
#
 
ignoreregex =
 
Asterisk 1.8とそれ以前ではログのホスト部分にポート番号を含む、含まないの違いがあるためfailregexの記述を変える必要がありますので注意してください。この部分に合致するメッセージが、ログファイルに現れたならばBAN基準になりますので注意して記述します。これ意外にも、引っかけたいメッセージがある場合にはそれも記述するとよいでしょう。<br>
 
  
===BANのアクションを作成する===
+
  NOTICE.* .*: Failed to authenticate user .* \(<HOST>:.*\)
ここではUDPの5060ポート、つまりSIPだけをBAN対象としたいためアクションをSIP用に作成します。 /etc/fail2ban/action.d で以下のようにしてアクションを作成します。<br>
 
まず
 
  cp iptables-allports.conf iptables-sip.conf
 
を行って、全ポート用のアクションをコピーします。次に iptables-sip.conf を編集し、以下のようにBANとUNBANのエントリを修正します。
 
# Option:  actionban
 
# Notes.: command executed when banning an IP. Take care that the
 
#          command is executed with Fail2Ban user rights.
 
# Tags:    <ip>  IP address
 
#          <failures>  number of failures
 
#          <time>  unix timestamp of the ban time
 
# Values:  CMD
 
#
 
actionban = iptables -I fail2ban-<name> 1 -s <ip> -p udp --dport 5060 -j DROP
 
 
# Option:  actionunban
 
# Notes.: command executed when unbanning an IP. Take care that the
 
#          command is executed with Fail2Ban user rights.
 
# Tags:    <ip>  IP address
 
#          <failures>  number of failures
 
#          <time>  unix timestamp of the ban time
 
# Values:  CMD
 
#
 
actionunban = iptables -D fail2ban-<name> -s <ip> -p udp --dport 5060 -j DROP
 
-p udp と --dport 5073 を actionban と actionunban に追記します。
 
  
===fail2banの設定ファイルを修正===
+
フィルタ追加後、fail2banを再起動し設定完了です。
/etc/fail2ban にある jail.conf ファイルの最後に以下を追加します。
 
[asterisk-iptables]
 
 
enabled  = true
 
filter  = asterisk
 
action  = iptables-sip[name=ASTERISK, protocol=all]
 
            sendmail-whois[name=ASTERISK, dest=root, sender=fail2ban@example.net]
 
logpath  = /var/log/asterisk/messages
 
maxretry = 5
 
findtime = 600
 
bantime = 604800
 
*action
 
BAN処理のアクションを定義します。この例ではiptables-sipを実行します。その後、sendmail-whois で BANしたIPアドレスのwhois情報を dest= で指定された宛先に送ります。このとき使用されるメールのFrom:はfail2ban@exampleになりますので、適切なものに書き換えます。<br>
 
アクションの所で iptables-allports を指定するとSIPだけでなく、すべてのポートからの接続を蹴るように iptables に設定されます。『怪しい攻撃元』をブロックするという意味では、こちらのアクションの方がより安全と言えます。
 
*logpath
 
Asteriskのログファイルへのパスを記述します。
 
*maxretry
 
何回以上失敗したらBANするかの指定です。
 
*findtime
 
この時間内にmaxretryで指定した回数以上失敗するとBANします。上の例では600秒(10分)の間に、5回以上の失敗があった場合にはBANされます。
 
*bantime
 
ここで指定された期間がBAN期間になります。指定は秒数です。上の例では 60x60x24x7=604800、つまり1週間になります。
 
  
==fail2banを起動する==
 
/etc/init.d/fail2ban start
 
起動したら期待の動作をするかどうかを、よく確認してください。試しに故意に間違えたパスワードで5回以上ログインをしてみるなどです。<br>
 
起動に問題がなければ、fail2banが自動起動されるように登録しておけば良いでしょう。
 
chkconfig --add fail2ban
 
===起動の確認===
 
iptables -L -v で確認すると
 
61638 8222K fail2ban-ASTERISK  all  --  any    any    anywhere            anywhere
 
 
Chain fail2ban-ASTERISK (1 references)
 
  pkts bytes target    prot opt in    out    source              destination
 
  61627 8216K RETURN    all  --  any    any    anywhere            anywhere
 
のようなエントリがあるはずです。<br>
 
BANされるとメールが送られ
 
  11  6424 DROP      udp  --  any    any    xxx.xxx.xxx.xx      anywhere            udp dpt:5060
 
のようなDROPのエントリが追加されているはずです。
 
 
[[Category:セキュリティ]]
 
[[Category:セキュリティ]]

2018年6月17日 (日) 16:53時点における版

IAXでのFail2banはIAX-Fail2banを参照してください。

fail2ban

ログファイルとiptablesを利用したファイアウォールの一種。Brute Forceアタックの対策に使いやすい。

http://www.fail2ban.org/
http://sourceforge.net/projects/fail2ban/

iptablesおよびpythonを必要とします。最新のFail2banではAsteriskにも対応しています。

CentOS

CentOSではeaplからyumでインストールすることが可能です。

yum install -y epel-release
yum --enablerepo=epel -y install fail2ban

yumでインストールした最新のFail2BanはAsteriskのログフォーマットを変更し、ローカル設定ファイルを作成するだけで使用することができます。
まずAsteriskのlogger.confを修正し

[general]
; Customize the display of debug message time stamps
; this example is the ISO 8601 date format (yyyy-mm-dd HH:MM:SS)
; see strftime(3) Linux manual for format specifiers
dateformat=%F %T

dateformatの箇所のコメント(;)を外して有効にし、Asteriskを再起動します。
/etc/fail2ban/に以下の内容のjail.localというファイルを作成します。ファイルがある場合には修正します。

[DEFAULT]
ignoreip =
backend = polling
bantime = 3600  ; 1hour
maxretry= 5
usedns = no

[asterisk]
enabled = true

fail2banを起動すると監視が始まります。


起動の確認

iptables -Lでiptablesの状態を確認するとfail2banでbanされたIPアドレス等が確認できます。

Chain f2b-asterisk-tcp (1 references)
target     prot opt source               destination
REJECT     all  --  46.17.42.180         anywhere            reject-with icmp-port-unreachable
RETURN     all  --  anywhere             anywhere

Chain f2b-asterisk-udp (1 references)
target     prot opt source               destination
REJECT     all  --  46.17.42.180         anywhere            reject-with icmp-port-unreachable
RETURN     all  --  anywhere             anywhere

デフォルトではban時間は1時間です。

INVITEによるBrute force攻撃への対策

REGISTERメッセージによる攻撃以外に、INVITEによるBrute force攻撃も確認されています。

この攻撃時に出力されるログメッセージは以下のようなものになります。

Failed to authenticate user "Anonymous" <sip:anonymous@192.168.1.2>;tag=as105e401c 

このログメッセージの攻撃元IPアドレスが、FROMヘッダに記載されているIPアドレスになっています。

このままでは、NAT配下のサーバーからの攻撃や、FROMヘッダが偽装された場合にfail2banで対応することができません。

そこで、Asteriskへパッチを当てて、実際の攻撃元IPアドレスを表示するように修正します。

Asteriskへパッチを当てる

次のようなパッチをAsteriskに適用します。

このパッチはAsterisk-1.4.40を対象にしていますが、1.6系、1.8系にも同様の修正で対応できます。

--- asterisk-1.4.40.orig/channels/chan_sip.c    2011-01-05 02:11:48.000000000 +0900
+++ asterisk-1.4.40/channels/chan_sip.c 2011-03-10 17:59:26.000000000 +0900
@@ -15456,7 +15456,7 @@
                                ast_log(LOG_NOTICE, "Sending fake auth rejection for user %s\n", get_header(req, "From"));
                                transmit_fake_auth_response(p, SIP_INVITE, req, XMIT_RELIABLE);
                        } else {
-                               ast_log(LOG_NOTICE, "Failed to authenticate user %s\n", get_header(req, "From"));
+                               ast_log(LOG_NOTICE, "Failed to authenticate user %s (%s:%d)\n", get_header(req, "From"), ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
                                transmit_response_reliable(p, "403 Forbidden", req);
                        }
                        p->invitestate = INV_COMPLETED;

こちらは Asterisk-1.8.23.0 用です。Asterisk-11.5.1 でもほぼ同じコードが使えます。

--- asterisk-1.8.23.0/channels/chan_sip.c.orig  2013-08-02 11:41:03.233638321 +0900
+++ asterisk-1.8.23.0/channels/chan_sip.c       2013-12-06 14:51:08.698990909 +0900
@@ -22673,7 +22673,7 @@
                        return 0;
                }
                if (res < 0) { /* Something failed in authentication */
-                       ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", get_header(req, "From"));
+                       ast_log(LOG_NOTICE, "Failed to authenticate device %s (%s)\n", get_header(req, "From"), ast_sockaddr_stringify(addr));
                        transmit_response(p, "403 Forbidden", req);
                        sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
                        return 0;
@@ -23334,7 +23334,7 @@
                        goto request_invite_cleanup;
                }
                if (res < 0) { /* Something failed in authentication */
-                       ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", get_header(req, "From"));
+                       ast_log(LOG_NOTICE, "Failed to authenticate device %s (%s)\n", get_header(req, "From"), ast_sockaddr_stringify(addr));
                        transmit_response_reliable(p, "403 Forbidden", req);
                        p->invitestate = INV_COMPLETED;
                        sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
@@ -25164,7 +25164,7 @@
                p->lastinvite = seqno;
                return 0;
        } else if (auth_result < 0) {
-               ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", get_header(req, "From"));
+               ast_log(LOG_NOTICE, "Failed to authenticate device %s (%s)\n", get_header(req, "From"), ast_sockaddr_stringify(addr));
                transmit_response(p, "403 Forbidden", req);
                sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
                ast_string_field_set(p, theirtag, NULL);
@@ -25384,7 +25384,7 @@
                if (res == AUTH_CHALLENGE_SENT) /* authpeer = NULL here */
                        return 0;
                if (res != AUTH_SUCCESSFUL) {
-                       ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", get_header(req, "From"));
+                       ast_log(LOG_NOTICE, "Failed to authenticate device %s (%s)\n", get_header(req, "From"), ast_sockaddr_stringify(addr));
                        transmit_response(p, "403 Forbidden", req);

                        pvt_set_needdestroy(p, "authentication failed");

Asterisk 11.23.1用パッチです。

--- channels/chan_sip.c.orig    2016-09-09 01:28:35.000000000 +0900
+++ channels/chan_sip.c 2016-10-28 23:26:38.985774935 +0900
@@ -18751,7 +18751,7 @@ static void receive_message(struct sip_p
                        return;
                }
                if (res < 0) { /* Something failed in authentication */
-                       ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", sip_get_header(req, "From"));
+                       ast_log(LOG_NOTICE, "Failed to authenticate device %s (%s)\n", sip_get_header(req, "From"), ast_sockaddr_stringify(addr));
                        transmit_response(p, "403 Forbidden", req);
                        sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
                        return;
@@ -24963,7 +24963,7 @@ static int handle_request_options(struct
                        return 0;
                }
                if (res < 0) { /* Something failed in authentication */
-                       ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", sip_get_header(req, "From"));
+                       ast_log(LOG_NOTICE, "Failed to authenticate device %s (%s)\n", sip_get_header(req, "From"), ast_sockaddr_stringify(addr));
                        transmit_response(p, "403 Forbidden", req);
                        sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
                        return 0;
@@ -25798,7 +25798,7 @@ static int handle_request_invite(struct
                        goto request_invite_cleanup;
                }
                if (res < 0) { /* Something failed in authentication */
-                       ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", sip_get_header(req, "From"));
+                       ast_log(LOG_NOTICE, "Failed to authenticate device %s (%s)\n", sip_get_header(req, "From"), ast_sockaddr_stringify(addr));
                        transmit_response_reliable(p, "403 Forbidden", req);
                        p->invitestate = INV_COMPLETED;
                        sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
@@ -27788,7 +27788,7 @@ static int handle_request_publish(struct
                p->lastinvite = seqno;
                return 0;
        } else if (auth_result < 0) {
-               ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", sip_get_header(req, "From"));
+               ast_log(LOG_NOTICE, "Failed to authenticate device %s (%s)\n", sip_get_header(req, "From"), ast_sockaddr_stringify(addr));
                transmit_response(p, "403 Forbidden", req);
                sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
                ast_string_field_set(p, theirtag, NULL);
@@ -28003,7 +28003,7 @@ static int handle_request_subscribe(stru
                if (res == AUTH_CHALLENGE_SENT) /* authpeer = NULL here */
                        return 0;
                if (res != AUTH_SUCCESSFUL) {
-                       ast_log(LOG_NOTICE, "Failed to authenticate device %s for SUBSCRIBE\n", sip_get_header(req, "From"));
+                       ast_log(LOG_NOTICE, "Failed to authenticate device %s (%s) for SUBSCRIBE\n", sip_get_header(req, "From"), ast_sockaddr_stringify(addr));
                        transmit_response(p, "403 Forbidden", req);

                        pvt_set_needdestroy(p, "authentication failed");


パッチを当てて、Asteriskをコンパイルし直し、再起動します。

すると、先ほどの攻撃時のログは以下のように出力されるようになります。

Failed to authenticate user "Anonymous" <sip:anonymous@192.168.1.2>;tag=as105e401c (123.45.67.89:5060)

ログの( )内に攻撃元の実IPアドレスが表示されるようになり、これを元にfail2banで攻撃を検知することができます。

fail2banへ設定を追加

修正したログに合わせたフィルタ設定をfail2banに追加します。

/etc/fail2ban/filter.d/asterisk.conf の failregex の項目に以下を追加します。

NOTICE.* .*: Failed to authenticate user .* \(<HOST>:.*\)

フィルタ追加後、fail2banを再起動し設定完了です。