Phòng ngừa SIP Scanner với Fail2Ban trong Asterisk

1. Tổng quan

Trong môi trường VoIP sử dụng Asterisk, việc bị quét tài khoản SIP (REGISTER, INVITE) là điều rất phổ biến. Những kẻ tấn công (SIP scanner) cố gắng dò tìm username/password bằng brute-force. May mắn thay, Fail2Ban là công cụ tuyệt vời giúp tự động chặn IP khi phát hiện các hành vi bất thường.

Tuy nhiên, log chuẩn từ Asterisk thường khó xử lý bằng regex, đặc biệt là với res_pjsip. Vì thế, trong bài viết này, mình sẽ chia sẻ cách:

  • Tùy biến log Asterisk để dễ bắt lỗi
  • Dùng Fail2Ban phân tích log đó
  • Tự động chặn IP độc hại

2. Sơ đồ hoạt động

┌────────────────────────┐
│ /var/log/asterisk/full │
└─────────┬──────────────┘
          │ tail -F
          ▼
     Fail2Ban phân tích
          │
          ▼
      🔒 IP bị chặn!

3. Cài đặt Fail2Ban

Sử dụng 2 command đơn giản này để cài đặt Fail2ban

apt update
apt install fail2ban -y

Sau khi cài xong, kiểm tra phiên bản:

fail2ban-client -V

Ví dụ đầu ra:

0.11.2

4. Biến log khó đọc → log dễ đọc (đây là tùy chọn, bạn có thể bỏ qua)

Vấn đề gặp phải, bạn có log gốc như sau:

[Jun 28 10:06:32] NOTICE[...] res_pjsip/pjsip_distributor.c: Request 'INVITE' ... failed for '5.196.115.163:56732' - Failed to authenticate

Cú pháp log phức tạp, regex khó khớp. Fail2Ban yêu cầu dòng log phải có định dạng rõ ràng và có IP ở đúng vị trí.

Lúc này sơ đồ sẽ đi theo luồng sau.

┌────────────────────────┐
│ /var/log/asterisk/full │
└─────────┬──────────────┘
          │ tail -F
          ▼
┌──────────────────────────────┐
│ log_failed_ip.sh (lọc & ghi) │
└─────────┬────────────────────┘
          ▼
  /var/log/asterisk/pjsip_auth.log
          │
          ▼
     Fail2Ban phân tích
          │
          ▼
      🔒 IP bị chặn!

Viết script lọc log Asterisk

cat > /usr/local/bin/log_failed_ip.sh <<'EOF'
#!/bin/bash
while read line; do
    echo "$line" | grep -q "Failed to authenticate" || continue
    ip=$(echo "$line" | grep -oP "failed for '\K[^']+")
    [[ $ip ]] && echo "$(date '+%Y-%m-%d %H:%M:%S') REGISTER_FAIL ${ip%:*}" >> /var/log/asterisk/pjsip_auth.log
done
EOF

chmod +x /usr/local/bin/log_failed_ip.sh

Sau đó chạy nền bằng:

tail -F /var/log/asterisk/full | /usr/local/bin/log_failed_ip.sh &

File /var/log/asterisk/pjsip_auth.log giờ sẽ có log dạng:

2025-06-28 10:01:16 REGISTER_FAIL 5.196.115.163

Đây là option gợi ý, mình không sử dụng nó nhé.

5. Quy trình cấu hình

Cấu hình Fail2Ban filter bằng cách tạo file /etc/fail2ban/filter.d/asterisk-pjsip.conf.

[Definition]
failregex = failed for '<HOST>:\d+' .* - (Failed to authenticate|No matching endpoint found)
            Call \(UDP:<HOST>:\d+\) to extension '.*' rejected because extension not found in context 'from-zenhub'
ignoreregex =

Bạn có thể kiểm tra regex bằng lệnh dưới và nhớ thay đường dẫn log và filter tương ứng với hệ thống của bạn.

shell> fail2ban-regex /var/log/asterisk/full /etc/fail2ban/filter.d/asterisk-pjsip.conf

Running tests
=============

Use   failregex filter file : asterisk-pjsip, basedir: /etc/fail2ban
Use         log file : /var/log/asterisk/full
Use         encoding : UTF-8


Results
=======

Failregex: 71320 total
|-  #) [# of hits] regular expression
|   1) [64735] failed for '<HOST>:\d+' .* - (Failed to authenticate|No matching endpoint found)
|   2) [6585] Call \(UDP:<HOST>:\d+\) to extension '.*' rejected because extension not found in context 'from-internal-zenhub'
`-

Ignoreregex: 0 total

Date template hits:
|- [# of hits] date format
|  [74316] {^LN-BEG}ExYear(?P<_sep>[-/.])Month(?P=_sep)Day(?:T|  ?)24hour:Minute:Second(?:[.,]Microseconds)?(?:\s*Zone offset)?
`-

Lines: 74316 lines, 0 ignored, 71320 matched, 2996 missed
[processed in 4.64 sec]

Missed line(s): too many to print.  Use --print-all-missed to print all 2996 lines

Cấu hình Fail2Ban jail bằng cách tạo file jail riêng:

cat > /etc/fail2ban/jail.d/asterisk-pjsip.local << 'EOF'
[asterisk-pjsip]
enabled  = true
port     = 5060,5061
protocol = udp
filter   = asterisk-pjsip
logpath  = /var/log/asterisk/full
maxretry = 3
bantime  = 3600
findtime = 300
EOF

Nếu cần bạn có thể tối ưu log Asterisk bằng cách kiểm tra file /etc/asterisk/logger.conf. Dưới đây là cách tối ưu của mình.

cat > /etc/asterisk/logger.conf << 'OEF'
[general]
dateformat=%F %T

[logfiles]
console => notice,warning,error
messages.log => notice,warning,error
full => notice,warning,error,debug,verbose
OEF

Reload lại logger:

asterisk -rx "logger reload"

Khởi động lại Fail2Ban

systemctl restart fail2ban

Check status Fail2ban.

shell> systemctl status fail2ban
● fail2ban.service - Fail2Ban Service
     Loaded: loaded (/lib/systemd/system/fail2ban.service; disabled; vendor preset: enabled)
     Active: active (running) since Sat 2025-06-28 15:37:46 UTC; 1s ago
       Docs: man:fail2ban(1)
   Main PID: 569147 (fail2ban-server)
      Tasks: 7 (limit: 9474)
     Memory: 14.1M
        CPU: 1.140s
     CGroup: /system.slice/fail2ban.service
             └─569147 /usr/bin/python3 /usr/bin/fail2ban-server -xf start

Jun 28 15:37:46 VPNServer1-100-151 systemd[1]: Started Fail2Ban Service.
Jun 28 15:37:47 VPNServer1-100-151 fail2ban-server[569147]: Server ready

Hãy xem kết quả log trong /var/log/asterisk/full nhé.

shell> tail -f /var/log/asterisk/full
[2025-06-28 15:37:46] NOTICE[65016] res_pjsip/pjsip_distributor.c: Request 'REGISTER' from '"866" <sip:866@113.161.201.128>' failed for '51.89.162.163:5369' (callid: 3625520650) - Failed to authenticate
[2025-06-28 15:37:46] NOTICE[65016] res_pjsip/pjsip_distributor.c: Request 'REGISTER' from '"866" <sip:866@113.161.201.128>' failed for '51.89.162.163:5369' (callid: 2525337673) - No matching endpoint found
[2025-06-28 15:37:46] NOTICE[65016] res_pjsip/pjsip_distributor.c: Request 'REGISTER' from '"866" <sip:866@113.161.201.128>' failed for '51.89.162.163:5369' (callid: 2525337673) - Failed to authenticate
[2025-06-28 15:37:46] NOTICE[65016] res_pjsip/pjsip_distributor.c: Request 'REGISTER' from '"866" <sip:866@113.161.201.128>' failed for '51.89.162.163:5369' (callid: 1976627641) - No matching endpoint found
[2025-06-28 15:37:46] NOTICE[65016] res_pjsip/pjsip_distributor.c: Request 'REGISTER' from '"866" <sip:866@113.161.201.128>' failed for '51.89.162.163:5369' (callid: 1976627641) - Failed to authenticate
[2025-06-28 15:37:46] NOTICE[65016] res_pjsip/pjsip_distributor.c: Request 'REGISTER' from '"866" <sip:866@113.161.201.128>' failed for '51.89.162.163:5369' (callid: 3426223023) - No matching endpoint found
[2025-06-28 15:37:46] NOTICE[65016] res_pjsip/pjsip_distributor.c: Request 'REGISTER' from '"866" <sip:866@113.161.201.128>' failed for '51.89.162.163:5369' (callid: 3426223023) - Failed to authenticate
[2025-06-28 15:37:46] NOTICE[65016] res_pjsip/pjsip_distributor.c: Request 'REGISTER' from '"866" <sip:866@113.161.201.128>' failed for '51.89.162.163:5369' (callid: 91974241) - No matching endpoint found
[2025-06-28 15:37:46] NOTICE[65016] res_pjsip/pjsip_distributor.c: Request 'REGISTER' from '"866" <sip:866@113.161.201.128>' failed for '51.89.162.163:5369' (callid: 91974241) - Failed to authenticate
[2025-06-28 15:39:24] NOTICE[569508] res_pjsip/pjsip_distributor.c: Request 'INVITE' from '<sip:a'or'3=3--@92.205.110.66>' failed for '92.205.110.66:5060' (callid: 8521572-154458-1712632-182936198814@92.205.110.66) - No matching endpoint found

Khi xem trạng thái bạn thấy regex Fail2Ban sẽ khớp dòng này có IP 5.196.115.163 và đã chặn nó vì sai nhiều lần.

shell> fail2ban-client status asterisk-pjsip
Status for the jail: asterisk-pjsip
|- Filter
|  |- Currently failed: 0
|  |- Total failed:     0
|  `- File list:        /var/log/asterisk/full
`- Actions
   |- Currently banned: 16
   |- Total banned:     16
   `- Banned IP list:   103.176.90.16 103.176.90.92 123.21.229.201 135.237.126.250 154.212.141.147 154.212.141.253 173.231.185.164 185.38.148.119 207.167.64.28 207.167.67.22 23.175.48.211 5.196.115.163 5.39.61.118 69.175.4.222 77.110.126.104 77.221.140.149

6. Unban một IP.

Giả sử ví dụ 123.21.229.201 là IP của mình và mình muốn gỡ chặn nó. Hiện tại IP này của mình đã bị chặn, xem kết quả của IPTables bạn cũng thấy nó đã bị chặn bởi Fail2ban.

shell> iptables -L --line-number -n -v
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination
1        0     0 f2b-asterisk-pjsip  udp  --  *      *       0.0.0.0/0            0.0.0.0/0            multiport dports 5060,5061

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination

Chain f2b-asterisk-pjsip (1 references)
num   pkts bytes target     prot opt in     out     source               destination
1        0     0 REJECT     all  --  *      *       77.221.140.149       0.0.0.0/0            reject-with icmp-port-unreachable
2        0     0 REJECT     all  --  *      *       77.110.126.104       0.0.0.0/0            reject-with icmp-port-unreachable
3        0     0 REJECT     all  --  *      *       69.175.4.222         0.0.0.0/0            reject-with icmp-port-unreachable
4        0     0 REJECT     all  --  *      *       5.39.61.118          0.0.0.0/0            reject-with icmp-port-unreachable
5        0     0 REJECT     all  --  *      *       5.196.115.163        0.0.0.0/0            reject-with icmp-port-unreachable
6        0     0 REJECT     all  --  *      *       23.175.48.211        0.0.0.0/0            reject-with icmp-port-unreachable
7        0     0 REJECT     all  --  *      *       207.167.67.22        0.0.0.0/0            reject-with icmp-port-unreachable
8        0     0 REJECT     all  --  *      *       207.167.64.28        0.0.0.0/0            reject-with icmp-port-unreachable
9        0     0 REJECT     all  --  *      *       185.38.148.119       0.0.0.0/0            reject-with icmp-port-unreachable
10       0     0 REJECT     all  --  *      *       173.231.185.164      0.0.0.0/0            reject-with icmp-port-unreachable
11       0     0 REJECT     all  --  *      *       154.212.141.253      0.0.0.0/0            reject-with icmp-port-unreachable
12       0     0 REJECT     all  --  *      *       154.212.141.147      0.0.0.0/0            reject-with icmp-port-unreachable
13       0     0 REJECT     all  --  *      *       135.237.126.250      0.0.0.0/0            reject-with icmp-port-unreachable
14       0     0 REJECT     all  --  *      *       123.21.229.201       0.0.0.0/0            reject-with icmp-port-unreachable
15       0     0 REJECT     all  --  *      *       103.176.90.92        0.0.0.0/0            reject-with icmp-port-unreachable
16       0     0 REJECT     all  --  *      *       103.176.90.16        0.0.0.0/0            reject-with icmp-port-unreachable
17       0     0 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0

Nếu bạn gỡ iptables -D f2b-asterisk-pjsip 14 cũng không xi nhê gì vì lát cũng bị fail2ban đưa vào danh sách chặn. Cùng xem lại danh sách IP bị chặn là 16 IP.

shell> fail2ban-client status asterisk-pjsip
Status for the jail: asterisk-pjsip
|- Filter
|  |- Currently failed: 0
|  |- Total failed:     0
|  `- File list:        /var/log/asterisk/full
`- Actions
   |- Currently banned: 16
   |- Total banned:     16
   `- Banned IP list:   103.176.90.16 103.176.90.92 123.21.229.201 135.237.126.250 154.212.141.147 154.212.141.253 173.231.185.164 185.38.148.119 207.167.64.28 207.167.67.22 23.175.48.211 5.196.115.163 5.39.61.118 69.175.4.222 77.110.126.104 77.221.140.149

Bạn phải chạy lệnh sau để gỡ cấm IP, ví dụ 123.21.229.201.

shell> fail2ban-client set asterisk-pjsip unbanip 123.21.229.201
1

Bây giờ số lượng IP bị chặn chỉ còn 15 IP.

shell> fail2ban-client status asterisk-pjsip
Status for the jail: asterisk-pjsip
|- Filter
|  |- Currently failed: 0
|  |- Total failed:     0
|  `- File list:        /var/log/asterisk/full
`- Actions
   |- Currently banned: 15
   |- Total banned:     15
   `- Banned IP list:   103.176.90.16 103.176.90.92 135.237.126.250 154.212.141.147 154.212.141.253 173.231.185.164 185.38.148.119 207.167.64.28 207.167.67.22 23.175.48.211 5.196.115.163 5.39.61.118 69.175.4.222 77.110.126.104 77.221.140.149

Trên IPTables cũng đã gỡ 123.21.229.201 ra khỏi danh sách chặn.

shell> iptables -L --line-number -n -v
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination
1        1   744 f2b-asterisk-pjsip  udp  --  *      *       0.0.0.0/0            0.0.0.0/0            multiport dports 5060,5061

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination

Chain f2b-asterisk-pjsip (1 references)
num   pkts bytes target     prot opt in     out     source               destination
1        0     0 REJECT     all  --  *      *       77.221.140.149       0.0.0.0/0            reject-with icmp-port-unreachable
2        0     0 REJECT     all  --  *      *       77.110.126.104       0.0.0.0/0            reject-with icmp-port-unreachable
3        0     0 REJECT     all  --  *      *       69.175.4.222         0.0.0.0/0            reject-with icmp-port-unreachable
4        0     0 REJECT     all  --  *      *       5.39.61.118          0.0.0.0/0            reject-with icmp-port-unreachable
5        0     0 REJECT     all  --  *      *       5.196.115.163        0.0.0.0/0            reject-with icmp-port-unreachable
6        0     0 REJECT     all  --  *      *       23.175.48.211        0.0.0.0/0            reject-with icmp-port-unreachable
7        0     0 REJECT     all  --  *      *       207.167.67.22        0.0.0.0/0            reject-with icmp-port-unreachable
8        1   744 REJECT     all  --  *      *       207.167.64.28        0.0.0.0/0            reject-with icmp-port-unreachable
9        0     0 REJECT     all  --  *      *       185.38.148.119       0.0.0.0/0            reject-with icmp-port-unreachable
10       0     0 REJECT     all  --  *      *       173.231.185.164      0.0.0.0/0            reject-with icmp-port-unreachable
11       0     0 REJECT     all  --  *      *       154.212.141.253      0.0.0.0/0            reject-with icmp-port-unreachable
12       0     0 REJECT     all  --  *      *       154.212.141.147      0.0.0.0/0            reject-with icmp-port-unreachable
13       0     0 REJECT     all  --  *      *       135.237.126.250      0.0.0.0/0            reject-with icmp-port-unreachable
14       0     0 REJECT     all  --  *      *       103.176.90.92        0.0.0.0/0            reject-with icmp-port-unreachable
15       0     0 REJECT     all  --  *      *       103.176.90.16        0.0.0.0/0            reject-with icmp-port-unreachable
16       0     0 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0

Bạn có thể fix cứng bằng cách thêm IP vào danh sách “ignoreip”.

Mở file cấu hình của jail asterisk-pjsip (có thể là một trong các file sau), ví dụ trường hợp của mình /etc/fail2ban/jail.d/asterisk-pjsip.local và thêm dòng sau.

[asterisk-pjsip]
ignoreip = 127.0.0.1/8 ::1 123.21.229.201

Khởi động lại Fail2Ban để áp dụng.

systemctl restart fail2ban

Sau đó, xác minh lại bạn sẽ không thấy IP 123.21.229.201 không còn trong danh sách bị cấm và sẽ không bị cấm lại trong tương lai.

fail2ban-client status asterisk-pjsip

6. Fail2Ban chặn IP bằng gì?

IPTables/NFTables (phổ biến nhất trên Linux)

  • Đây là backend mặc định của Fail2Ban trên hầu hết hệ thống Linux (Debian, Ubuntu, CentOS).
  • Nó thêm các rules tạm thời vào iptables hoặc nftables để DROP hoặc REJECT các IP bị coi là tấn công.

Bạn có thể thấy các rules bằng lệnh:

iptables -L --line-number -n -v

Ví dụ ở phần demo trên, iptables đã chặn 2 IP đó là 77.110.126.10451.89.162.163.

shell> iptables -L --line-number -n -v
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination
1       28 20237 f2b-asterisk-pjsip  udp  --  *      *       0.0.0.0/0            0.0.0.0/0            multiport dports 5060,5061

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination

Chain f2b-asterisk-pjsip (1 references)
num   pkts bytes target     prot opt in     out     source               destination
1       20 15062 REJECT     all  --  *      *       77.110.126.104       0.0.0.0/0            reject-with icmp-port-unreachable
2        3  1416 REJECT     all  --  *      *       51.89.162.163        0.0.0.0/0            reject-with icmp-port-unreachable
3        5  3759 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0

Hoàn toàn khớp với kết quả của lệnh fail2ban-client status asterisk-pjsip.

fail2ban-client status asterisk-pjsip
Status for the jail: asterisk-pjsip
|- Filter
|  |- Currently failed: 3
|  |- Total failed:     17184
|  `- File list:        /var/log/asterisk/full
`- Actions
   |- Currently banned: 2
   |- Total banned:     2
   `- Banned IP list:   51.89.162.163 77.110.126.104

Hoặc nếu bạn dùng nftables:

nft list ruleset

Firewalld (CentOS/RHEL/Fedora)

Nếu hệ thống bạn dùng firewalld, Fail2Ban có thể sử dụng backend firewalld để thêm/zones rich rules.

Các backend khác (hiếm)

Fail2Ban cũng hỗ trợ các backend khác như:

BackendMô tả
iptablesMặc định truyền thống
nftablesFirewall hiện đại (Debian 10+, Ubuntu 20+)
firewalldCho CentOS/RHEL sử dụng firewalld
ipsetKết hợp với iptables để chặn theo tập hợp IP
routeChặn IP bằng cách thay route
hostsdenyGhi vào /etc/hosts.deny (cũ)
dummyKhông thực hiện gì (chỉ log)

Cấu hình backend trong Fail2Ban.

Mặc định nằm ở:

/etc/fail2ban/jail.conf  hoặc  /etc/fail2ban/jail.local

Dòng cấu hình:

banaction = iptables-multiport

Hoặc:

banaction = nftables-multiport

✅ Kiểm tra Fail2Ban đang dùng gì:

Chạy:

fail2ban-client status

hoặc:

fail2ban-client status asterisk-pjsip

Coi mục Actions → sẽ hiển thị như:

Actions:   iptables-multiport[...]

7. Ưu và nhược điểm của phương án này.

✅ Ưu điểm

  • Regex cực kỳ đơn giản
  • Hoạt động với mọi định dạng log Asterisk (miễn có Failed to authenticate)
  • Không cần sửa mã nguồn Asterisk

❌ Nhược điểm

  • Tốn thêm tài nguyên do phải tail -F
  • Cần script trung gian (nhưng dễ kiểm soát)

💬 Lời khuyên

  • Nên chạy log_failed_ip.sh bằng systemd hoặc tmux để không bị mất khi reboot.
  • Có thể mở rộng script để xử lý No matching endpoint hoặc Wrong password
  • Nếu log full không có Failed to authenticate, kiểm tra lại cấu hình logger.conf

8. Kết luận

Việc bảo vệ Asterisk khỏi tấn công SIP là vô cùng quan trọng. Sử dụng Fail2Ban kết hợp với log tùy biến là giải pháp hiệu quả, linh hoạt và cực kỳ dễ mở rộng.

Với cách tiếp cận “biến log khó thành dễ”, bạn không cần vật lộn với regex dài dòng nữa. Tập trung vào chặn IP và bảo mật hệ thống một cách nhẹ nhàng.

Hãy thử ngay hôm nay để thấy hiệu quả! 🎯

Nếu bạn thấy bài viết hữu ích, hãy chia sẻ với cộng đồng. Hoặc nếu bạn có cách tối ưu hơn, đừng ngại để lại bình luận nhé!

Bài viết gần đây

spot_img

Related Stories

Leave A Reply

Please enter your comment!
Please enter your name here

Đăng ký nhận thông tin bài viết qua email