技術者になりたい何か

技術者になりたい何かの覚書的な何かです

てきすとすとりーむ2

テキスト処理系2回目。
テキストデータを加工するための色々。
組み合わせて使うとなんだか色々できる。

■uniq

重複している行をまとめて出力する。
入力するテキストストリームは予めソートしておく必要がある。
ので、多くの場合sortと併用される。

ログの集計とかに便利。nginxとかapacheアクセスログから簡易アクセス解析とかもできます。

というわけでsshdのFailedを集計してみます。先日やったけども。

こういうログから存在しているユーザ名でのログイン失敗ログからIPを抜き出して集計。
(対象ログ→/var/log/auth.log)

Dec 3 00:01:10 tminserver sshd[29952]: Failed password for root from 58.242.83.26 port 41788 ssh2
Dec 3 00:01:13 tminserver sshd[29952]: Failed password for root from 58.242.83.26 port 41788 ssh2
Dec 3 00:01:15 tminserver sshd[29952]: Failed password for root from 58.242.83.26 port 41788 ssh2
Dec 3 00:01:17 tminserver sshd[29952]: Failed password for root from 58.242.83.26 port 41788 ssh2
Dec 3 00:12:15 tminserver sshd[30090]: Failed password for invalid user admin from 103.207.37.155 port 507
05 ssh2
Dec 3 00:12:23 tminserver sshd[30092]: Failed password for invalid user support from 103.207.37.155 port 6
3144 ssh2
Dec 3 00:12:32 tminserver sshd[30099]: Failed password for invalid user admin from 103.207.37.155 port 620
87 ssh2

パターン①rootでログイン失敗しているアクセス元IPの集計

集計期間は12/3-6 →grep 'Dec [3-6]'
失敗してるのを抜き出す →grep 'Failed'
存在しないユーザ名での失敗ははじく→grep -v 'invalid'
IPのカラム(フィールド)を抜き出す→ cut -d ' ' -f 12
抜き出したIPをソート → sort
ソートしたIPの重複分削除するけどそれぞれの件数(行数?)はカウントする → uniq -c
カウントした結果が1カラム目に出るので、多い方から順にソート → sort -nr

$ sudo grep 'Dec [3-6]' /var/log/auth.log | grep 'Failed' | grep -v 'invalid' | cut -d ' ' -f 12 | sort | uniq -c | sort -nr
54381 58.242.83.26
15564 42.7.26.91
156 193.201.224.218
21 103.207.37.155
14 103.99.1.187
14 103.207.37.154
12 92.247.83.86
12 42.62.51.53
12 103.99.0.199
10 181.214.87.4
6 91.126.205.238
6 90.226.61.158
6 87.123.137.84
6 84.135.151.34
6 83.233.45.72
6 69.165.46.170
6 69.131.92.126
6 61.153.20.84
6 60.179.11.32
6 60.173.82.156
6 60.165.208.28
6 59.15.210.188
6 59.120.249.139
6 46.72.18.89
6 41.82.138.10
6 39.71.158.158
6 38.108.61.214


~~~以下略~~~~

 

パターン②存在しないユーザで入力されているユーザ名を集計。

集計期間は12/3-6 →grep 'Dec [3-6]'
失敗してるのを抜き出す →grep 'Failed'
存在しないユーザ名での失敗を抜き出す →grep 'invalid user'
入力されたユーザ名のカラム(フィールド)を抜き出す→ cut -d ' ' -f 12
抜き出したユーザ名をソート → sort
ソートしたユーザ名の重複分削除するけどそれぞれの件数(行数?)はカウントする → uniq -c
カウントした結果が1カラム目に出るので、多い方から順にソート → sort -nr

$ sudo grep 'Dec [3-6]' /var/log/auth.log | grep 'Failed' | grep 'invalid user' | cut -d ' ' -f 12 | sort | uniq -c | sort -nr
446 admin
52 user
36 ubnt
33 test
32 pi
31 support
27
25 ftp
22 guest
22 ftpuser
21 service
20 1234
20 0
14 user1
14 adm
14 111111
13 super
13 operator
13 default
10 manager
10 22
9 sysadmin
9 nagios
9 a
8 webmaster
8 tomcat
8 scan
8 postgres
8 monitor
8 git
8 fax
8 apache
8 123321
7 www
7 usuario
7 report
7 mother
7 matsumoto
7 auction
7 administrator
7 123
~~~以下省略~~~~

 
つかpiって誰だよ

■wc

ファイルの行数、単語数、文字数を表示。
数えるのがめんどい時に便利。

オプション
-c 文字数(バイト数)を表示
-l 行数を表示
-w 単語数を表示

単純に大きいファイルの時に行数見たりとか、
grepの検索結果をwc -l に渡して件数カウントしたりする時とかに使える。

上記sshアタックのログの場合で、rootでログインしようとして失敗しているログの件数(12/3~12/6)


$ sudo grep 'Dec [3-6]' /var/log/auth.log.1 | grep 'Failed' | grep 'root' |wc -l
70539

■pr

印刷前の整形によく使うらしい。
コマンドラインから印刷・・・?

-l でヘッダ・フッタを含むページの行数を指定。+1:2で1ページ目から2ページ目まで。

$ pr -l 25 +1:2 dpkg.log


2017-12-13 18:16 dpkg.log 1 ページ


2017-12-02 08:56:42 startup archives unpack
2017-12-02 08:57:16 upgrade curl:amd64 7.38.0-4+deb8u7 7.38.0-4+deb8u8
2017-12-02 08:57:16 status half-configured curl:amd64 7.38.0-4+deb8u7
2017-12-02 08:57:17 status unpacked curl:amd64 7.38.0-4+deb8u7
2017-12-02 08:57:17 status half-installed curl:amd64 7.38.0-4+deb8u7
2017-12-02 08:57:17 status triggers-pending man-db:amd64 2.7.0.2-5
2017-12-02 08:57:17 status half-installed curl:amd64 7.38.0-4+deb8u7
2017-12-02 08:57:17 status unpacked curl:amd64 7.38.0-4+deb8u8
2017-12-02 08:57:17 status unpacked curl:amd64 7.38.0-4+deb8u8
2017-12-02 08:57:18 upgrade libcurl3:amd64 7.38.0-4+deb8u7 7.38.0-4+deb8u8
2017-12-02 08:57:18 status half-configured libcurl3:amd64 7.38.0-4+deb8u7
2017-12-02 08:57:18 status unpacked libcurl3:amd64 7.38.0-4+deb8u7
2017-12-02 08:57:18 status half-installed libcurl3:amd64 7.38.0-4+deb8u7
2017-12-02 08:57:18 status half-installed libcurl3:amd64 7.38.0-4+deb8u7
2017-12-02 08:57:18 status unpacked libcurl3:amd64 7.38.0-4+deb8u8

 

 

 

2017-12-13 18:16 dpkg.log 2 ページ


2017-12-02 08:57:18 status unpacked libcurl3:amd64 7.38.0-4+deb8u8
2017-12-02 08:57:19 upgrade libcurl3-gnutls:amd64 7.38.0-4+deb8u7 7.38.0-4+deb8u8
2017-12-02 08:57:19 status half-configured libcurl3-gnutls:amd64 7.38.0-4+deb8u7
2017-12-02 08:57:19 status unpacked libcurl3-gnutls:amd64 7.38.0-4+deb8u7
2017-12-02 08:57:19 status half-installed libcurl3-gnutls:amd64 7.38.0-4+deb8u7
2017-12-02 08:57:19 status half-installed libcurl3-gnutls:amd64 7.38.0-4+deb8u7
2017-12-02 08:57:20 status unpacked libcurl3-gnutls:amd64 7.38.0-4+deb8u8
2017-12-02 08:57:20 status unpacked libcurl3-gnutls:amd64 7.38.0-4+deb8u8
2017-12-02 08:57:20 upgrade bzr:all 2.6.0+bzr6595-6 2.6.0+bzr6595-6+deb8u1
2017-12-02 08:57:20 status half-configured bzr:all 2.6.0+bzr6595-6
2017-12-02 08:57:20 status unpacked bzr:all 2.6.0+bzr6595-6
2017-12-02 08:57:20 status half-installed bzr:all 2.6.0+bzr6595-6
2017-12-02 08:57:20 status half-installed bzr:all 2.6.0+bzr6595-6
2017-12-02 08:57:20 status unpacked bzr:all 2.6.0+bzr6595-6+deb8u1
2017-12-02 08:57:21 status unpacked bzr:all 2.6.0+bzr6595-6+deb8u1

 

これリダイレクトかなんかで新しいファイルに出力すると印刷時にきれいになるという事かな?
ぶっちゃけ使う場面がいまいち・・・

■fmt

テキストを決められた桁に整形する。

オプション
-w 一行の幅を設定

$ head -5 /var/log/dpkg.log
2017-12-02 08:56:42 startup archives unpack
2017-12-02 08:57:16 upgrade curl:amd64 7.38.0-4+deb8u7 7.38.0-4+deb8u8
2017-12-02 08:57:16 status half-configured curl:amd64 7.38.0-4+deb8u7
2017-12-02 08:57:17 status unpacked curl:amd64 7.38.0-4+deb8u7
2017-12-02 08:57:17 status half-installed curl:amd64 7.38.0-4+deb8u7


↑のようなのを最大幅40で整形すると・・・

$ head -5 /var/log/dpkg.log | fmt -w 40
2017-12-02 08:56:42 startup archives
unpack 2017-12-02 08:57:16 upgrade
curl:amd64 7.38.0-4+deb8u7
7.38.0-4+deb8u8 2017-12-02
08:57:16 status half-configured
curl:amd64 7.38.0-4+deb8u7 2017-12-02
08:57:17 status unpacked curl:amd64
7.38.0-4+deb8u7 2017-12-02 08:57:17
status half-installed curl:amd64
7.38.0-4+deb8u7

とはいえなかなかうまいとこで切れてくれないです。行が変に結合して余計読みにくい。
こういう時は-sオプション付けて行結合しないように指定してやると・・・

$ head -5 /var/log/dpkg.log | fmt -s -w 40
2017-12-02 08:56:42 startup archives
unpack
2017-12-02 08:57:16 upgrade curl:amd64
7.38.0-4+deb8u7 7.38.0-4+deb8u8
2017-12-02 08:57:16 status
half-configured curl:amd64
7.38.0-4+deb8u7
2017-12-02 08:57:17 status unpacked
curl:amd64 7.38.0-4+deb8u7
2017-12-02 08:57:17 status
half-installed curl:amd64
7.38.0-4+deb8u7

さっきよりましになりましたね。

■expand

テキストファイル内のタブをスペースに変換

オプション 
-i 行頭のタブのみ変換
-t タブ幅 タブ幅を設定する

■unexpand

行頭にある連続した空白をタブに変換

オプション
-a 行頭以外の空白も変換
-t タブ幅 タブ幅指定(デフォルトでは8ケタ)

インデント付けるときの変換とかには便利かもしれない
あと空白→タブに一括返還しといてエクセル貼り付けとか?

■xargs

これはテキストストリームに入れていいのかよくわからないけども。
標準入力から受け取った文字列を引数に指定して、与えられたコマンドを実行。
引数の数が多すぎた場合でも良きに計らってくれる気が利くやつ。
大量のログ調査とかでうまい事やってくれてるのがこいつの仕業である。

$ find -type f -name "*log*"

logがファイル名に含まれるファイルをカレントディレクトリから検索。

これをxargs でcatにつなぐと、cat の引数として上記ファイルが全てうまい事引き渡される。
ので、順次catで展開されていく。後ろに| grep 'hoge' をつければその結果からhogeが含まれる行を抽出してくれる。

$ find -type f -name "*log*" | xargs cat | grep "hoge"

引き渡すコマンド次第では引数となるファイルが多すぎるとエラーを吐いたりすることがある。
その辺上手くやってくれるのがxargs。
xargs [コマンド] のコマンド部分の引数として前の結果を渡すので、コマンド次第ではうまくいかないときもなきにしもあらず。


$ sudo find /var/log -type f -name 'mail.log.?.gz'
/var/log/mail.log.2.gz
/var/log/mail.log.4.gz
/var/log/mail.log.3.gz

この出力されたmail.log[2-4].gz をxargsでzcatに渡してgrepをかけると

$ sudo find /var/log -type f -name 'mail.log.?.gz' | xargs sudo zcat | grep 'status=sent'
Jul 7 17:33:15 tminserver postfix/local[6448]: 0E4B540D99: to=<tmin@tminserver.localdomain>, orig_to=<root>, relay=local, delay=0.56, delays=0.33/0.09/0/0.15, dsn=2.0.0, status=sent (delivered to mailbox)

3つのファイルが順次に後ろのzcatに渡される→grep status=sentで。
ちなみに下記のコマンドと一緒になる。(最初のカラムにファイルフルパスが出るかどうか)

$ sudo zgrep 'status=sent' /var/log/mail.log.?.gz
/var/log/mail.log.3.gz:Jul 7 17:33:15 tminserver postfix/local[6448]: 0E4B540D99: to=<tmin@tminserver.localdomain>, orig_to=<root>, relay=local, delay=0.56, delays=0.33/0.09/0/0.15, dsn=2.0.0, status=sent (delivered to mailbox) 


上手く使えば○○日以上たったファイルを前部圧縮とか全部退避、とかもできる。

mariadbが終わらない

今更ですがDebianをjessieからstretchにUpgradeしました。

Upgrade自体はいつもどおり /etc/apy/sources.list のjessieをstretchに置き換えて、

$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt-get dist-upgrade

でほぼ通ったのですが、この際にmaeiadb-serverが依存関係でエラーはいてちょっとハマりました。

症状:

mariadb-serverがupgradeできない
・たぶんmariadb-clientとの依存関係
・でもmariadb-serverをremoveもできない
・メッセージは「mariadb-serverが走ってるから手動で止めてよ」みたいなこと言ってるけど、systemctlとかserviceでは止まってる(というかFialedになってる)

原因:

どうやらmariadb-serverがsafe modeで走ってて、これを強制的に止めてやればよかった

対処:

ps でプロセス番号調べてkill -9
止まったの確認してからautoremoveなりremoveなりupgradeなりすればおk

1.発端

jessieからstretchへのUpgrade作業にてdist-upgrade時にエラーが出ていたので、まずは普通に修復を試みる。

$ sudo apt-get autoremove
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています
状態情報を読み取っています... 完了
これらを直すためには 'apt --fix-broken install' を実行する必要があるかもしれません。
提案パッケージ:
mariadb-test netcat-openbsd tinyca
以下のパッケージは「削除」されます:
mariadb-server-10.0 mariadb-server-core-10.0
以下のパッケージが新たにインストールされます:
libjemalloc1 mariadb-client-10.1 mariadb-client-core-10.1 mariadb-server-10.1 mariadb-server-core-10.1 socat
アップグレード: 0 個、新規インストール: 6 個、削除: 2 個、保留: 266 個。
693 個のパッケージが完全にインストールまたは削除されていません。
21.8 MB 中 0 B のアーカイブを取得する必要があります。
この操作後に追加で 78.2 MB のディスク容量が消費されます。
続行しますか? [Y/n] y
パッケージを事前設定しています ...
apt (1.4.8) を設定しています ...
新バージョンの設定ファイル /etc/apt/apt.conf.d/01autoremove をインストールしています ...
新バージョンの設定ファイル /etc/kernel/postinst.d/apt-auto-removal をインストールしています ...
usermod: 変更はありません
Created symlink /etc/systemd/system/timers.target.wants/apt-daily-upgrade.timer → /lib/systemd/system/apt-daily-upgrade
.timer.
Created symlink /etc/systemd/system/timers.target.wants/apt-daily.timer → /lib/systemd/system/apt-daily.timer.
Removing obsolete conffile /etc/cron.daily/apt ...
(データベースを読み込んでいます ... 現在 194534 個のファイルとディレクトリがインストールされています。)
mariadb-server-10.0 (10.0.32-0+deb8u1) を削除しています ...
1500
There is a MySQL server running, but we failed in our attempts to stop it.
Stop it yourself and try again!
dpkg: パッケージ mariadb-server-10.0 の処理中にエラーが発生しました (--remove):
サブプロセス インストール済みの pre-removal スクリプト はエラー終了ステータス 1 を返しました
Job for mysql.service failed because the control process exited with error code.
See "systemctl status mysql.service" and "journalctl -xe" for details.
invoke-rc.d: initscript mysql, action "start" failed.
mysql.service - LSB: Start and stop the mysql database server daemon
Loaded: loaded (/etc/init.d/mysql)
Active: failed (Result: exit-code) since Fri 2017-12-08 11:21:13 JST; 19ms ago
Docs: man:systemd-sysv-generator(8)
Process: 3153 ExecStart=/etc/init.d/mysql start (code=exited, status=1/FAILURE)

12月 08 11:20:42 tminserver /etc/init.d/mysql[3180]: 171208 11:20:42 mysqld_safe A mysqld process already exists
12月 08 11:20:42 tminserver mysqld_safe[3227]: A mysqld process already exists
12月 08 11:21:13 tminserver mysql[3153]: Starting MariaDB database server: mysqld . . . . . . . . . . . . . . .…failed!
12月 08 11:21:13 tminserver systemd[1]: mysql.service: control process exited, code=exited status=1
12月 08 11:21:13 tminserver systemd[1]: Failed to start LSB: Start and stop the mysql database server daemon.
12月 08 11:21:13 tminserver systemd[1]: Unit mysql.service entered failed state.
Hint: Some lines were ellipsized, use -l to show in full.
dpkg: error while cleaning up:
サブプロセス インストール済みの post-installation スクリプト はエラー終了ステータス 1 を返しました
処理中にエラーが発生しました:
mariadb-server-10.0
W: システムにサンドボックスユーザ '_apt' がありません。権限を削除できません
E: Sub-process /usr/bin/dpkg returned an error code (1)

 

ダメです。
ちなみに apt --fix-broken install しても、apt-get remove mariadb-serverしても dpkg --configure -a してもだめです。

 

ポイントはここだった模様。

There is a MySQL server running, but we failed in our attempts to stop it.
Stop it yourself and try again!

2.対処1(失敗)

なんかMySQLが走ってるとか言ってるので、systemctlで状態確認。

$ systemctl status mysql
mysql.service - LSB: Start and stop the mysql database server daemon
Loaded: loaded (/etc/init.d/mysql)
Active: failed (Result: exit-code) since Fri 2017-12-08 11:21:13 JST; 2min 0s ago
Docs: man:systemd-sysv-generator(8)
Process: 3153 ExecStart=/etc/init.d/mysql start (code=exited, status=1/FAILURE)

Failしてます。
手動で止めようとしてみます。

$ sudo systemctl stop mysql

$ systemctl status mysql
mysql.service - LSB: Start and stop the mysql database server daemon
Loaded: loaded (/etc/init.d/mysql)
Active: failed (Result: exit-code) since Fri 2017-12-08 11:21:13 JST; 2min 17s ago
Docs: man:systemd-sysv-generator(8)
Process: 3153 ExecStart=/etc/init.d/mysql start (code=exited, status=1/FAILURE)

$ journalctl -xe
Hint: You are currently not seeing messages from other users and the system.
Users in the 'systemd-journal' group can see all messages. Pass -q to
turn off this notice.
No journal files were opened due to insufficient permissions.

変わってません。ここでautoremoveとかしてもやはり同じ。
つかFailしてるのに起動してるとは何事?

3.対処2(成功)

実はsafemodeでmariadbが起動していた模様です。
psで確認。

$ ps aux | grep sql
root 672 0.0 0.1 19524 3484 ? S 11:32 0:00 /bin/bash /usr/bin/mysqld_safe
mysql 753 0.1 4.4 735512 85424 ? Sl 11:32 0:02 /usr/sbin/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib/mysql/plugin --user=mysql --skip-log-error --pid-file=tminserver.pid
root 754 0.0 0.0 26444 1284 ? S 11:32 0:00 logger -t mysqld -p daemon error
tmin 14764 0.0 0.0 12264 992 pts/0 S+ 12:05 0:00 grep sql

プロセスがわかったので、kill -9 で強制終了

$ sudo kill -9 672
$ sudo kill -9 753
$ sudo kill -9 754

ちゃんと終了したか確認。

$ ps aux | grep sql
tmin 14764 0.0 0.0 12264 992 pts/0 S+ 12:05 0:00 grep sql

apt 再実行

$ sudo apt --fix-broken install

mariadb-server-10.0 (10.0.32-0+deb8u1) を削除しています ...
以前に未選択のパッケージ mariadb-client-core-10.1 を選択しています。
(データベースを読み込んでいます ... 現在 194442 個のファイルとディレクトリがインストールされています。)
.../mariadb-client-core-10.1_10.1.26-0+deb9u1_amd64.deb を展開する準備をしています ...
mariadb-client-core-10.1 (10.1.26-0+deb9u1) を展開しています...
以前に未選択のパッケージ libjemalloc1 を選択しています。
.../libjemalloc1_3.6.0-9.1_amd64.deb を展開する準備をしています ...
libjemalloc1 (3.6.0-9.1) を展開しています...
以前に未選択のパッケージ mariadb-client-10.1 を選択しています。
.../mariadb-client-10.1_10.1.26-0+deb9u1_amd64.deb を展開する準備をしています ...
mariadb-client-10.1 (10.1.26-0+deb9u1) を展開しています...
(データベースを読み込んでいます ... 現在 194499 個のファイルとディレクトリがインストールされています。)
mariadb-server-core-10.0 (10.0.32-0+deb8u1) を削除しています ...
以前に未選択のパッケージ mariadb-server-core-10.1 を選択しています。
以前に未選択のパッケージ mariadb-server-core-10.1 を選択しています。
(データベースを読み込んでいます ... 現在 194419 個のファイルとディレクトリがインストールされています。)
.../mariadb-server-core-10.1_10.1.26-0+deb9u1_amd64.deb を展開する準備をしています ...
.../mariadb-server-core-10.1_10.1.26-0+deb9u1_amd64.deb を展開する準備をしています ...
mariadb-server-core-10.1 (10.1.26-0+deb9u1) を展開しています...
mariadb-server-core-10.1 (10.1.26-0+deb9u1) を展開しています...
以前に未選択のパッケージ socat を選択しています。
.../socat_1.7.3.1-2+deb9u1_amd64.deb を展開する準備をしています ...
socat (1.7.3.1-2+deb9u1) を展開しています...
以前に未選択のパッケージ mariadb-server-10.1 を選択しています。
.../mariadb-server-10.1_10.1.26-0+deb9u1_amd64.deb を展開する準備をしています ...
/var/lib/mysql: found previous version 10.0
mariadb-server-10.1 (10.1.26-0+deb9u1) を展開しています...
libjemalloc1 (3.6.0-9.1) を設定しています ...
socat (1.7.3.1-2+deb9u1) を設定しています ...
mariadb-client-core-10.1 (10.1.26-0+deb9u1) を設定しています ...
libc-bin (2.24-11+deb9u1) のトリガを処理しています ...
systemd (232-25+deb9u1) のトリガを処理しています ...
man-db (2.7.6.1-2) のトリガを処理しています ...
mariadb-client-10.1 (10.1.26-0+deb9u1) を設定しています ...
mariadb-server-core-10.1 (10.1.26-0+deb9u1) を設定しています ...
mariadb-server-10.1 (10.1.26-0+deb9u1) を設定しています ...
新バージョンの設定ファイル /etc/init.d/mysql をインストールしています ...
新バージョンの設定ファイル /etc/logrotate.d/mysql-server をインストールしています ...
新バージョンの設定ファイル /etc/mysql/debian-start をインストールしています ...
Created symlink /etc/systemd/system/mysql.service → /lib/systemd/system/mariadb.service.
Created symlink /etc/systemd/system/mysqld.service → /lib/systemd/system/mariadb.service.
Created symlink /etc/systemd/system/multi-user.target.wants/mariadb.service → /lib/systemd/system/mariadb.service.
insserv: warning: current start runlevel(s) (empty) of script `mysql' overrides LSB defaults (2 3 4 5).
insserv: warning: current stop runlevel(s) (0 1 2 3 4 5 6) of script `mysql' overrides LSB defaults (0 1 6).
mariadb-server (10.1.26-0+deb9u1) を設定しています ...
systemd (232-25+deb9u1) のトリガを処理しています ...

 

通りましたね。

状態確認。

$ ps aux | grep sql
mysql 17785 0.2 4.1 677900 79808 ? Ssl 12:09 0:00 /usr/sbin/mysqld
tmin 18694 0.0 0.0 12264 936 pts/0 S+ 12:15 0:00 grep sql


このあと再度dist -upgradeすると、止まってた更新たちもちゃんと入ります。

しかし、普通mysqlのsafemodeってsystemctlとかserviceで起動・停止ができたと思うんだけど・・・

sshdへのアタックログをみてみよう&対策しよう

ちょっと外出先からssh自宅サーバに繋いで色々したいときとか多くて、
ルータのport転送とか使って外からssh接続できるようにしました。
したら毎日のsshへのブルートフォースがすごいことになってた。

■教訓


外部からアクセスできるsshサーバで、rootログイン許可は即刻やめるべき。
外部からアクセスできるsshサーバで、パスワード認証はできるだけやめるべき。
外部からアクセスできるsshサーバで、デフォルトポート(22)での運用はできるだけやめるべき。
外部からアクセスできるsshサーバでは、fail2banとかiptablesでアクセス制限かけたほうがいい。

sshへの攻撃者はどのようにアクセスしてくるのか。


Debianなので、ログは/var/log/auth.logに出ます。(CentOSなら/var/log/secure)
というわけでログから調べますよっと。

ログイン失敗のログの一部


Dec 6 18:45:41 tminserver sshd[5876]: Failed password for root from 42.7.26.91 port 22754 ssh2
Dec 6 18:45:44 tminserver sshd[5876]: Failed password for root from 42.7.26.91 port 22754 ssh2
Dec 6 18:45:46 tminserver sshd[5876]: Failed password for root from 42.7.26.91 port 22754 ssh2
Dec 6 18:45:49 tminserver sshd[5876]: Failed password for root from 42.7.26.91 port 22754 ssh2
Dec 6 18:45:58 tminserver sshd[5878]: Failed password for root from 42.7.26.91 port 49250 ssh2
Dec 6 18:46:00 tminserver sshd[5878]: Failed password for root from 42.7.26.91 port 49250 ssh2
Dec 6 18:46:03 tminserver sshd[5878]: Failed password for root from 42.7.26.91 port 49250 ssh2
Dec 6 18:46:06 tminserver sshd[5878]: Failed password for root from 42.7.26.91 port 49250 ssh2
Dec 6 18:46:09 tminserver sshd[5878]: Failed password for root from 42.7.26.91 port 49250 ssh2
Dec 6 18:46:11 tminserver sshd[5878]: Failed password for root from 42.7.26.91 port 49250 ssh2

ちなみに件数

$ sudo grep 'Failed password' /var/log/auth.log | grep 'Dec 1' | wc -l
0
$ sudo grep 'Failed password' /var/log/auth.log | grep 'Dec 2' | wc -l
6572
$ sudo grep 'Failed password' /var/log/auth.log | grep 'Dec 3' | wc -l
14007
$ sudo grep 'Failed password' /var/log/auth.log | grep 'Dec 4' | wc -l
21951
$ sudo grep 'Failed password' /var/log/auth.log | grep 'Dec 5' | wc -l
12345
$ sudo grep 'Failed password' /var/log/auth.log | grep 'Dec 6' | wc -l
23431
tmin@tminserver:~$ sudo grep 'Failed password' /var/log/auth.log | grep 'Dec 7' | wc -l
5261

20000超とか来てますね。

圧倒的に多いのはrootで入ろうとしてFailed password(パスワード認証失敗)

root以外は何が多いかなっということで、Failed password forで出てるエラーログからユーザーのカラム抜き出して集計。

$ sudo grep 'Failed password' /var/log/auth.log | grep 'Dec' | cut -d ' ' -f 10 | sort -n | uniq -c | sort -nr
82233 root
1266 invalid
19
11 mysql
9 sync
9 postfix
9 man
5 uucp
4 sshd
4 nobody
2 backup
1 sys


圧倒的にroot多し。他にはプロセス名とかでありそうなのを打ち込んでるのが少々。

invalid は存在しないユーザ名打ち込んでエラーになってるので別途集計。

該当ログはこんな感じ

$ sudo grep 'Failed password' /var/log/auth.log | grep 'Dec' | grep 'invalid' | more
Dec 2 20:10:03 tminserver sshd[17682]: Failed password for invalid user 0101 from 5.188.10.156 port 46964 ssh2
Dec 2 20:10:18 tminserver sshd[17687]: Failed password for invalid user 0 from 5.188.10.156 port 49623 ssh2
Dec 2 20:10:29 tminserver sshd[17689]: Failed password for invalid user 1234 from 5.188.10.156 port 47647 ssh2
Dec 2 20:10:59 tminserver sshd[17697]: Failed password for invalid user admin from 5.188.10.156 port 50191 ssh2
Dec 2 20:11:02 tminserver sshd[17697]: Failed password for invalid user admin from 5.188.10.156 port 50191 ssh2
Dec 2 20:11:06 tminserver sshd[17697]: Failed password for invalid user admin from 5.188.10.156 port 50191 ssh2
Dec 2 20:11:09 tminserver sshd[17697]: Failed password for invalid user admin from 5.188.10.156 port 50191 ssh2
Dec 2 20:11:11 tminserver sshd[17697]: Failed password for invalid user admin from 5.188.10.156 port 50191 ssh2

ユーザ名のカラム抜き出して集計。


$ sudo grep 'Failed password' /var/log/auth.log | grep 'Dec' | grep 'invalid' | cut -d ' ' -f 12 | sort -n | uniq -c | sort -nr
489 admin
53 user
44 ubnt
36 test
36 pi
32 support
26 service
26 ftp
26
24 ftpuser
23 guest
20 1234
14 user1
13 super
13 adm
13 111111
12 operator
12 default
11 sysadmin
10 webmaster
10 tomcat
10 scan
10 postgres
10 manager
10 git
10 fax
10 apache
10 a
10 22
9 www
9 report
9 nagios
9 matsumoto
9 auction
8 0
7 usuario
7 mother
7 monitor
7 123321
6 api
6 administrator
6 123
5 testuser
4 plcmspip
4 client
4 anonymous
4 PlcmSpIp
3 master
3 cisco
3 Management
2 telecomadmin
2 sysadm
2 supervisor
2 raspberry
2 osmc
2 agent
2 Operator
1 zabbix
1 webadmin
1 vyatta
1 vt100
1 volition
1 vcr
1 username
1 ubuntu
1 ubadmin
1 ts3
1 telecom
1 telco
1 tech
1 target
1 system
1 svn
1 svin
1 superman
1 student
1 storwatch
1 steve
1 steam
1 shop
1 setup
1 security
1 sales
1 router
1 rcust
1 rapport
1 radware
1 public
1 print2000
1 poll
1 pizza
1 patrol
1 oracle
1 nt
1 naadmin
1 mtcl
1 mtch
1 mike
1 media
1 mark
1 mailman
1 library
1 jenkins
1 installer
1 init
1 info
1 hscroot
1 helpdesk
1 halt
1 ftptest
1 enrique
1 engineer
1 echo
1 e250
1 dvs
1 draytek
1 disttech
1 demo
1 david
1 daniel
1 bob
1 bill
1 am
1 adfexc
1 adam
1 acc
1 aaa
1 VTech
1 VNC
1 User
1 USERID
1 Sweex
1 SYSDBA
1 SYSADM
1 RSBCMON
1 Polycom
1 PSEAdmin
1 PRODDTA
1 NAU
1 Manager
1 MANAGER
1 HELLO
1 D-Link
1 Cisco
1 Administrator
1 Admin
1 ADMN
1 ;ccrusr
1 3comcso
1 266344
1 1502
1 12345
1 1111
1 0000

adminが頭一つ抜けてて、あとはuserとかありそうなユーザ名orプロセス名だったり。


ここまでの傾向から対策。

rootログイン禁止するだけで9割方防げる。
ユーザ名adminは次にやばい。(俺のサーバでは使ってない)
どうせport22への総当りなので、sshdを動かすport変更すればこれまたほとんど無くなる。
ここまでやっても0にはならないと思われるので、セキュリティ重視しなきゃな環境ならば、
パスワード認証やめて鍵認証とかにすれば、ユーザ名とポートがバレててもパスワード破られることがない。


■対策1 rootログインの禁止


簡単。効果はそこそこ。上記ログでダントツだったrootのログインが不可なので。
デメリットは自分もrootログインできなくなることくらいだが、そもそもいきなりrootで入って作業するとかリテラシーどうなの?ってかんじなので。
これで困る人は自分のやり方を考え直したほうがいいです。

/etc/ssh/sshd_configの設定でrootログインを禁止する。

$ sudo emacs /etc/ssh/sshd_config
PermitRootLogin yes →PermitRootLogin no

保存したらsshd再起動

$ sudo systemctl restart sshd

これでユーザrootで接続してみてログインできなければおk。


■対策2 ポート変更


簡単。効果は高め。これだけで多分普通のサーバならほとんど攻撃がなくなると思われ。
待受ポートがバレたらあれだけど、多分攻撃者は自動攻撃スクリプトかなんかを踏み台PCで実行してることがほとんどなため、
圧倒的に22番ポートへの攻撃が多い。無差別爆撃はまず22番への攻撃でしょう。

/etc/ssh/sshd_configの設定で待受ポートを変更

下の例では20022にしてるけど、ウェルノウンポート以外ならなんでもよい。
ウェルノウンポートでも使ってなくて使う予定もないならいいと思いますが。

$ sudo emacs /etc/ssh/sshd_config

Port 22 →Port 20022

 保存したらsshd再起動

$ sudo systemctl restart sshd

これで22番ポートに接続して繋がらず、かつ20022でつながればおk。

■対策3 パスワード認証切って公開鍵認証のみにする


難易度普通。少しめんどい。
パスワード認証切るので、パスワード総当たり攻撃は全て防げる。
デメリットは鍵持ってない端末から入れなくなること。

めんどいから今回はやってない。
とはいえVPSの方はこれにしてます。

設定はこんな感じ

mypace75.blog92.fc2.com

■対策4 fail2ban で攻撃回数に達したIPをbanする


結構難しいかも。設定も結構めんどい。
数回攻撃でアクセス自体拒否できるので、効果は大きい。
ないと思うけど一発目でアクセス成功、っていう攻撃には対処不可。
あと自分も間違えたら弾かれるので、自分が使う可能性があるIPは除外IPに入れとくのが良い。

設定した回数失敗したら攻撃とみなして該当IPをiptablesと連動してアクセス制限かける。
このあたりの説明がわかりやすいです。

さくらの VPS で CentOS fail2ban の設定 – TACKY.BIZ

ちなみにfail2banは設定によってssh不正アクセス以外の監視にも使えるので、
wordpressのログイン画面へのアクセスの監視とか、apache.htaccessへのアクセス監視とか、色々応用が効きます。
近いうちにちゃんと試す( ・`ω・´)

■対策5 firewallで海外からのアクセス弾く


攻撃元IPは中国がダントツ。
iptablesとかで日本IP以外のアクセス弾けばほとんど防げると思われ。
ただこれだと日本のIPからの攻撃の場合はどうしようもない。


■まとめ


外部からssh接続できるってだけのサーバでもこれだけの攻撃にさらされるので、
ローカル以外で使うsshサーバは何らかの対策はしときましょう。
(数日間なんの対策もしてませんでしたすみません)

あと怪しいなってときはlastとかwで見たことないとこからのアクセスがないかチェックした方がいいと思われ。