SSHGuard のインストール
〜 Bye Bye [preauth] 〜
2024-04-24 作成 福島
TOP > tips > sshguard
[ TIPS | TOYS | OTAKU | LINK | MOVIE | CGI | AvTitle | ConfuTerm | HIST | AnSt | Asob ]

前置き

サーバへの余計なトラフィックを遮断します。
/var/log/secure に sshd へ BruteForce/DoS の痕跡が記録されていて、今年に入ってその数がかなり多くなってきました。
手法が分散型の上に間隔が短いため、結果的に DDoS になることもあります。
Mar 10 07:26:57 MyHost sshd[710923]: Received disconnect from 192.168.232.226 port 43292:11: Bye Bye [preauth]
Mar 10 07:26:58 MyHost sshd[712577]: Received disconnect from 192.168.232.226 port 42130:11: Bye Bye [preauth]
 …
「ssh サーバが IP 192.168.232.226 からの接続のためにポート 22 を開いたが、認証する前に切断された」という意味を持つ複数の記録。
普通にブルートフォースを受けています。
サーバへの攻撃が予測・検出される場合、「sshd のポートを非標準の番号へ変更して防御する」
という記述がよそ様のサイトに散見されますが、敵も然る者引っ掻くもの。
ポートを変更した程度では一時しのぎにしかなりません。

SSHGuard という優れたプログラムが公開されているので、これを利用します。
SSHGuard の動作は以下で、しつこく不正接続されるほど強固に (1 → 4) 接続元をブロックします。
  1. sshd に対して認証失敗があると、接続元を一定期間の監視対象にするとともに攻撃スコアを蓄積する。
    → 監視期間中にアクセスが無ければ、接続元を監視対象から外す。

  2. 監視期間が終了する前に加えて認証失敗があれば、監視期間を延長して攻撃スコアを蓄積する。
    → 攻撃スコアがしきい値に達したら接続元を一時ブロックする。
    (一時ブロック: 監視時間が経過したり SSHGuard が再起動されるとブロックが解除される)

  3. それでも接続試行が止まらなければ、接続元を一時ブロックしたまま監視期間をさらに延長して攻撃スコアを蓄積する。

  4. それでも接続試行・認証失敗が止まらなければ、接続元を永久ブロックする。(BLACKLIST_FILE が有効の場合)
    (永久ブロック: SSHGuard が再起動されてもブロックを継続する)
なお、下記 4-1 にある通り永久ブロックするのは sshd ポートだけでなく、攻撃元 IP アドレスからの接続がすべて遮断されます。
(冗談でも攻撃しないこと。メールや http/https 等も遮断されるので絶縁状態となります)


0. インストール要件

OSAlmaLinux 9.3 (Shamrock Pampas Cat)本稿記述時の最新版
防御ソフトSSHGuard 2.4.2
firewalld 1.2.5AlmaLinux に付属のもの
ipset 7.11


1. firewalld の確認

$ LANG=C dnf info firewalld | egrep 'Name|Version|Release'
Name         : firewalld
Version      : 1.2.5
Release      : 2.el9_3
$ LANG=C dnf info ipset | egrep 'Name|Version|Release'
Name         : ipset
Version      : 7.11
Release      : 8.el9


2. EPEL のインストール

$ su
# dnf install epel-release    #*1

*1が使用不能の場合はこちらを実行↓
# dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm

# LANG=C dnf info epel-release | egrep 'Name|Version|Release'
Name         : epel-release
Version      : 9
Release      : 7.el9
# exit
$


3. SSHGuard のインストールと起動

3-1. SSHGuard をインストールする。
$ su
# dnf install sshguard

# LANG=C dnf info sshguard | egrep 'Name|Version|Release'
Name         : sshguard
Version      : 2.4.2
Release      : 7.el9
3-2. 設定ファイルを用意する。
# cat /etc/sshguard.conf | grep -v '^#' | grep -v '^$'
BACKEND="/usr/libexec/sshguard/sshg-fw-firewalld"
LOGREADER="LANG=C /usr/bin/journalctl -afb -p info -n1 -o cat -t sshd"
journalctl のオプションスイッチ
-a : すべてのフィールドを出力する。
-f : 最新のログを追跡して出力する。
-b : 指定ブートからのログを出力する。(指定を省略しているので現在のブートが対象)
-p info : SYSLOG と同じ指定レベルのログを出力する。(info を指定している)
-n 1 : 指定行数を出力する。(1 行を指定している)
-o cat : ログの内容だけを出力する。(タイムスタンプ等を出力しない)
-t sshd : 絞り込む SYSLOG の ID を指定する。(sshd を指定している。-t sshd -t unix_chkpwd のように複数指定可能)
# vim /etc/sshguard.conf
BLACKLIST_FILE=, WHITELIST_FILE= を明記する。

# Colon-separated blacklist threshold and full path to blacklist file. # Uncomment to add attackers hitting the threshold to the permanent blacklist # (default: disabled) BLACKLIST_FILE=90:/var/lib/sshguard/blacklist
# Full path to whitelist file. # Uncomment to consider IP addresses, address blocks or hostnames listed in this # file as friendlies that will never be blocked. # (default: disabled) WHITELIST_FILE=/etc/sshguard.whitelist
90: 攻撃スコアの累積が 90 に達するとブラックリストに追加する (永久ブロック) という意味。
30 分間の連続した接続失敗を攻撃スコアとして累積する (DETECTION_TIME=1800)。累積はリセットされない。
攻撃スコアは、受けた攻撃の重要度によって決まっている。

blacklist は sshguard の再起動時に読まれるが、読み込みが速くない。
すべての永久ブロックが読み込まれるまで時間を必要とする。
(約 4 アドレス/秒。10,000 アドレスだと約 40 分程度)
# cat /etc/sshguard.conf | grep -v '^#' | grep -v '^$'
BACKEND="/usr/libexec/sshguard/sshg-fw-firewalld"
LOGREADER="LANG=C /usr/bin/journalctl -afb -p info -n1 -o cat -t sshd"
BLACKLIST_FILE=90:/var/lib/sshguard/blacklist
WHITELIST_FILE=/etc/sshguard.whitelist
# touch /var/lib/sshguard/blacklist   # このファイルに永久ブロックする IP アドレスが追記される。
# cat /etc/sshguard.whitelist | grep -v '^#' | grep -v '^$' | wc -l
0
# vim /etc/sshguard.whitelist
自分の環境に合わせて、ブロックしない IP アドレスやホスト名を記述する。
(ホスト名は SSHGuard の起動時に一回だけ解決されるので、起動後に IP アドレスを変更すると認識されない)
127.0.0.0/8
192.168.0.0/24
192.168.56.0/24
192.168.122.0/24

client.example.jp
3-3. SSHGuard を起動する。
# systemctl enable sshguard
# systemctl status sshguard | grep 'Loaded:'
Loaded: loaded (/usr/lib/systemd/system/sshguard.service; enabled; preset: disabled)
enabled になっていること。(自動起動になっていないと disabled になる)
# systemctl start sshguard
# systemctl status sshguard | grep 'Active:'
Active: active (running) since Mon 2024-03-04 15:44:51 JST; 3s ago
active になっていること。(起動していないと inactive になる)
# exit
$


4. 動作確認

4-1. firewalld の設定状況を確認する。
$ su
# firewall-cmd --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: enp4s0f0
  sources:
  services: cockpit ssh
  ports:
  protocols:
  forward: yes
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:
        rule family="ipv6" source ipset="sshguard6" drop
        rule family="ipv4" source ipset="sshguard4" drop  
ipset の登録タイミングは /usr/libexec/sshguard/sshg-fw-firewalld を参照。
4-2. 永久ブロック対象の増加を確認する。
# firewall-cmd --ipset=sshguard4 --get-entries | tail
(IPv6 の場合は --ipset=sshguard6 とする)
192.168.16.117/32
192.168.1.36/32
10.2.0.39/32
192.168.224.167/32
192.168.223.124/32
10.2.1.11/32
192.168.149.150/32
起動して少し放っておくとブロックリストに IP アドレスが追加されていく。
(これはサンプル。実際はグローバルアドレスになる)
# exit
$


5. 間違えて永久ブロック登録された IP アドレスの解除

5-1. firewalld の「実行時」から IP アドレスを解除。
$ su
# firewall-cmd --ipset=sshguard4 --remove-entry=10.2.1.99/32
(10.2.1.99/32 は間違えて登録された IP アドレスの例)
(IPv6 の場合は --ipset=sshguard6 とする)
5-2. sshguard のブラックリストから IP アドレスを解除。(firewalld の「永続」に相当)
# systemctl stop sshguard

# vim /var/lib/sshguard/blacklist
(間違えて登録された IP アドレスを削除する)
# systemctl start sshguard
# exit
$


6. 実証

疑似攻撃してみる。
攻/防ホスト名IP アドレス
攻撃側Villain10.2.1.99
防御側MyHost10.2.1.10

6-1. 攻撃の様子
6-1-1. MyHost の sshd ポートに接続可能か確認する。
Villain$ telnet 10.2.1.10 22

Trying 10.2.1.10...
Connected to 10.2.1.10.
Escape character is '^]'.                                 
SSH-2.0-OpenSSH_8.7
^C

← 接続できている。
6-1-2. MyHost の sshd にブルートフォースをかけてみる。
存在しないユーザ・パスワード違いの攻撃スコアは 10 + 10 + 2 = 22 となっている。
しきい値 30 に達するように攻撃を 2 回繰り返す。

Villain$ for i in {1..2} ; do sshpass -p password ssh -l admin 10.2.1.10 ; done

Permission denied, please try again.                      
Permission denied, please try again.
接続不許可の応答。これは当然。
6-1-3. MyHost の sshd ポートに接続可能か確認する。
Villain$ telnet 10.2.1.10 22

Trying 10.2.1.10...
telnet: connect to address 10.2.1.10: Connection timed out

← 接続できなくなった。

6-2. 防御の様子
MyHost$ cat /var/log/messages | grep sshguard | tail
Mar 4 20:20:56 MyHost sshguard[6157]: Attack from "10.2.1.99" on service SSH with danger 10.
Mar 4 20:20:58 MyHost sshguard[6157]: Attack from "10.2.1.99" on service SSH with danger 10.
Mar 4 20:21:00 MyHost sshguard[6157]: Attack from "10.2.1.99" on service SSH with danger 2.

Mar 4 20:21:00 MyHost sshguard[6157]: Attack from "10.2.1.99" on service SSH with danger 10.

Mar 4 20:21:00 MyHost sshguard[6157]: Blocking "10.2.1.99/32" for 120 secs (4 attacks in 4 secs, after 1 abuses over 4 secs.)
2 回目の攻撃の最初で攻撃スコアの累積が 30 に達して 10.2.1.99 が 120 秒間のブロック対象になった。
ここでは可読性を上げるため行間に線を表示している。実際は存在しない。


7. おまけ

7-1. sshguard の動作ログを確認。
MyHost$ tail -f /var/log/messages | grep sshguard

Mar 4 22:49:34 MyHost sshguard[1109]: Attack from "10.2.1.99" on service SSH with danger 10.
Mar 4 22:49:36 MyHost sshguard[1109]: Attack from "10.2.1.99" on service SSH with danger 10.
Mar 4 22:49:36 MyHost sshguard[1109]: Attack from "10.2.1.99" on service SSH with danger 2.
Mar 4 22:50:18 MyHost sshguard[1109]: Attack from "10.2.1.99" on service SSH with danger 10.
Mar 4 22:50:18 MyHost sshguard[1109]: Blocking "10.2.1.99/32" for 120 secs*2 (4 attacks in 44 secs, after 1 abuses over 44 secs.)

Mar 4 22:53:05 MyHost sshguard[1109]: 10.2.1.99: unblocking after 167 secs*3

Mar 4 22:53:10 MyHost sshguard[1109]: Attack from "10.2.1.99" on service SSH with danger 10.
Mar 4 22:53:13 MyHost sshguard[1109]: Attack from "10.2.1.99" on service SSH with danger 10.
Mar 4 22:53:15 MyHost sshguard[1109]: Attack from "10.2.1.99" on service SSH with danger 2.
Mar 4 22:53:56 MyHost sshguard[1109]: Attack from "10.2.1.99" on service SSH with danger 10.
Mar 4 22:53:56 MyHost sshguard[1109]: Blocking "10.2.1.99/32" for 240 secs*4 (4 attacks in 46 secs, after 2 abuses over 262 secs.*5)

Mar 4 22:57:58 MyHost sshguard[1109]: 10.2.1.99: unblocking after 242 secs

Mar 4 22:58:12 MyHost sshguard[1109]: Attack from "10.2.1.99" on service SSH with danger 10.
Mar 4 22:58:14 MyHost sshguard[1109]: Attack from "10.2.1.99" on service SSH with danger 10.
Mar 4 22:58:14 MyHost sshguard[1109]: Attack from "10.2.1.99" on service SSH with danger 2.
Mar 4 22:58:25 MyHost sshguard[1109]: Attack from "10.2.1.99" on service SSH with danger 10.
Mar 4 22:58:25 MyHost sshguard[1109]: Blocking "10.2.1.99/32" forever*6 (4 attacks in 13 secs, after 3 abuses over 531 secs.)
*210.2.1.99 を 120 秒間のブロック対象とする。(攻撃スコアがしきい値 THRESHOLD=30 に達した)
*310.2.1.99 をブロック対象から除外した。(除外までの時間はちょうど 120 秒ではなく、ランダムに秒数が加算される)
*410.2.1.99 を 240 秒間のブロック対象とする。(← 監視期間を延長した) *5(46 秒間に 4 回の攻撃動作、最初の認証失敗から 262 秒間に 2 回の不正接続)
*610.2.1.99 の攻撃スコアがしきい値 90 に達して、永久ブロック対象となった。
7-2. GNOME では firewall-config から永久ブロック対象を確認可能。
firewall-config をインストールする。

 ⇓
firewall-config を起動する。

 ⇓
firewall-config 画面
*7永久ブロックする IP アドレス (上図の「エントリー」) は SSHGuard が起動するたび firewalld の に登録されるため に登録されなくて良い。