2019年度版 : 不正アクセスの傾向分析 (クラウド上の汎用的サーバの例)

#はじめに
この記事はシスコの同志による <font color="DarkSlateBlue"><B>Cisco Systems Japan Advent Calendar 2018</B></font> の 23 日目として投稿しました。

<B>2017年版</B>: https://qiita.com/advent-calendar/2017/cisco
<B>2018年版</B>: https://qiita.com/advent-calendar/2018/cisco
<B>2019年版</B>: https://qiita.com/advent-calendar/2019/cisco

ネットワーク/インフラ/サーバ系エンジニアの方で自宅ラボを構築されている方も多いと思います。私も数年そのような形で自宅に実機を持っていましたが、約1年半前に自宅に機材を持つことをやめ、複数のクラウドサービスに移行しました。サーバの要塞化をするためのソフトウェアと管理系ツールをいくつか試し、設定変更を繰り返しながらようやく手放し運転をしてほぼ1年が経過しましたので、その一台のサーバへの直近一年間の不正アクセスの傾向をまとめてみたいと思います。

このエントリで取り上げるテーマは
「<B>2019年度版 : 不正アクセスの傾向分析 (クラウド上の汎用的サーバの例)</B>」です。この中では、

- <B><font color="DarkSlateBlue">年間不正アクセス統計</font></B>
- <B><font color="DarkSlateBlue">環境の前提とfail2banのチューニング例</font></B>
- <B><font color="DarkSlateBlue">不正アクセス接続元の悪性スコア調査Tips (Umbrella Investigate API)</font></B>

の主に3項目をまとめてみます。2018年度のAdvent Calender投稿から時間が経過するに連れ、いつかネタとしてまとめてみたいと思っていたテーマでした。

#<font color="DarkSlateBlue">年間不正アクセス統計</font>
- 期間
 - 2019/01/01 ~ 2019/11/31
- 項目
 - <B>月別 ssh 不正アクセス試行回数 (banned by ssh-sasl)</B>
 - <B>月別 ssh root ログイン試行回数 (root login fail)</B>
 - <B>月別 postfix 不正アクセス試行回数 (banned by postfix-sasl)</B>
 - <B>月別 Ban Table エントリ平均 (ssh, postfix)</B>
 - <B>時刻別 ssh 不正アクセス試行回数 (banned by ssh-sasl)</B>
 - <B>不正アクセス元カントリーコード Top26</B>
 - <B>月別不正アクセスソースIPアドレスドメイン逆引き可否</B>
 - <B>ssh アカウント Top20</B>
 - <B>dovecot アカウント Top14</B>
 - <B>不正アクセスソース RiskScore (全体)</B>
 - <B>不正アクセスソース RiskScore (日本)</B>
 - <B>postfix RBL アクセス違反統計</B>
- 統計元データ&Tool
 - <B>fail2ban</B> にて送信されるaction mail (ban時にactionで送信されるメール)
 - <B>logwatch</B> にて送信される統計レポート (`/vat/log/maillog`, `/var/log/secure`, `/var/log/messages`, `/var/log/dovecot/dovecot.log`)
 - <B>Cisco Umbrella Investigate</B> (不正アクセスソース悪性スコア(RiskScore)調査用)

###月別 ssh 不正アクセス試行回数 (banned by ssh-sasl), 月別 ssh root ログイン試行回数 (root login fail)
![1-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311200/b6803edd-0473-091b-b13b-b3a536f7c1ea.png)
![1-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311200/7d6c0d24-9ca4-e5c3-25ea-6a531573fa9d.png)
期間内12ヶ月における月別の ssh 不正アクセス試行回数と月別 ssh root アカウントの試行回数推移です。

fail2ban/iptablesの設定により、1800秒以内に3回失敗した接続元IPアドレスは少なくとも36000秒 (10日間) は再接続ができません。このグラフの不正アクセス試行回数はほぼ自動的に総当たり攻撃が実行される1回目, 2回目のアクセス数の記録です。通常このようなアクセス制御がされていないシステムにおいては、桁の異なる更に膨大なアクセスが行われていると考えられます。

2018年12月以前は、環境整備のため頻繁にpower offをしており、本格連続稼働は2018/11ころよりスタートしていました。その後にsshのアクセス試行回数が伸びていますが、2019年5月以降は一気にアクセス数が減ってきています。

###月別 postfix 不正アクセス試行回数 (banned by postfix-sasl), 月別 Ban Table エントリ平均 (ssh, postfix)
![2-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311200/1c65be56-d064-9e3e-c3f9-ac4b79ac69bd.png)
![2-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311200/80506de6-a913-1485-db6d-f08657bcde65.png)
期間内12ヶ月における月別の Postfix 認証不正アクセス試行回数と、月別のActive Ban Tableの平均値です。

今回の対象システムでは Postfix によるメール送信時に3rd Party リレー対策の一貫としてSMTP-AUTHを有効にしています。maillogよりこの SMTP-AUTH の試行が失敗した回数をカウントしています。ssh と同様に5400秒以内に2回失敗した接続元IPアドレスはiptablesにエントリされるため、初期接続時での認証失敗が対象になります。
sshに比べ総数はかなり少なくなっていますが、ssh へのアクセスが減る時期より徐々に増えていることが確認できます。

Ban Tableエントリは、logwatch にて報告される（午前3時）ssh と postfix の Active Banned Table エントリの合計数を定点観測した結果となります。ssh アクセス数に比例していることが確認できます。

###時刻別 ssh 不正アクセス試行回数 (banned by ssh-sasl)
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311200/426d7084-ff8f-d018-0f91-a69f81a450d2.png)
期間内12ヶ月における ssh 不正アクセスイベントの日本時刻別での発生比率です。メールサービスへの不正アクセスはカウントしていません。

日本時刻別でのアクセス数の偏りは全くありません。全世界のアクセス元からほぼ機械的に実行されていると考えられます。

###不正アクセス元カントリーコード Top26
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311200/ed5542bb-c842-19c3-3082-36b6ae12e5dd.png)
期間内12ヶ月における ssh 不正アクセスイベントの接続元の国別トップ26（日本がランクインするまで）です。メールサービスへの不正アクセスはカウントしていません。

圧倒的に<B><font color="red">中国</font></B>、<B><font color="red">アメリカ</font></B>の二カ国、次いで<B><font color="red">フランス</font></B>からのアクセスが多いことが確認できます。

###月別不正アクセスソースIPアドレスドメイン逆引き可否
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311200/9bdd9d6f-adc1-33d1-d573-fefea65cb1bf.png)
期間内12ヶ月における月別の ssh 不正アクセス試行回数（<font color="blue">青縦線</font>は前の '<B>月別 ssh 不正アクセス試行回数</B>' グラフと同じ）とその接続元IP アドレスからホストドメイン逆引きが可能だったIPアドレスとの比較です。

ssh 全不正アクセス試行回数 65507 回において、その接続元 IP アドレスが登録された FQDN を持っている比率は43%でした。月別での比率も大きく開きはありません。（39%~43%）

###ssh アカウント Top20, dovecot アカウント Top14
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311200/fd0d829e-5135-b792-8654-a965218a2718.png)
期間内12ヶ月における ssh, メールサービスへの不正アクセス施行に利用された root 以外のアカウントの利用率上位の表です。

ssh は簡易的に作成されてしまうと想像し得るアカウントが多く回数の偏りがあります。dovecot, postfix において偏りが少なくグラフ内にない利用回数がさらに少ない個別のアカウントにて多くのアクセスが確認できています。

###不正アクセスソース RiskScore (全体), 不正アクセスソース RiskScore (日本)
![7-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311200/a96d1f3c-6c4f-d0d5-4890-c90d5ef3f577.png)
![7-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311200/4acead96-8e08-52fd-915b-037e8e334d8c.png)
期間内12ヶ月における ssh 不正アクセス接続元 の <B>Cisco Umbrella Investigate</B> による<B>予測的な悪性度評価 (RiskScore)</B> の分布です。

不正アクティビティを行う接続元のレピュテーション情報としてUmbrella Investigateより抽出してみました。スコアは 0 - 100、100は最も悪性度が高いスコアとなります。大半が比較的良性なスコアを持つ接続元であることが確認できます。

###postfix RBL アクセス違反統計
![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311200/4a3b3404-c2ae-06cf-317b-1250537ab609.png)
期間内12ヶ月における RBLルールによる postfix 接続違反統計です。 

 - <B>RBL:1</B> : zen.spamhaus.org によるレピュテーションチェック
 - <B>RBL:2</B> : bl.spamcop.net によるレピュテーションチェック
 - <B>No Service</B> : Name or service not known
 - <B>No Address</B> : Address not listed for hostname

迷惑メール送信元レピュテーションブラックリスト RBL (Realtime Blackhole List) のとして zen.spamhaus.org , bl.spamcop.net を設定しており、これによりMTA接続時にこのリストをチェックしリストに該当した接続元を拒否します。zen.spamhaus.org のヒット数が 2019/6, 2019/10にそれぞれスパイクしています。

##<font color="DarkSlateBlue">環境の前提とfail2banのチューニング例</font>
年間不正アクセス統計の前提条件です。不正アクセス統計のグラフで表示されるカウントそのものがすべてのアクセス試行回数ではなく、利用しているツールにより十分にフィルタされた上での分析結果となっています。その条件をいくつか整理します。

今回の分析対象のシステム上ではsshの他にXRDP+GNOMEによるリモートデスクトップ環境、postfix+dovecotによるメールサービスを構築しています。その他Webサーバ等のサービスは利用していません。オープンポートは<B>22/tcp (ssh)</B>, <B>25/tcp (SMTP)</B>, <B>993/tcp (imaps)</B>, <B>995/tcp (pop3s)</B>, <B>3389/tcp (RDP)</B>です。

シンプルにリモートデスクトップサービスは接続元を固定する静的なiptablesで保護し、sshとメールサービスは<B>fail2ban</B>を用い、指定したルールに従ってダイナミックなiptablesエントリを登録し保護します。fail2banによるbanned tableエントリ時にその結果を都度メールに送信、24間置きのセキュリティイベント分析し結果を<B>logwatch</B>で送信しています。
各サービスは定期アップデートを実施することを前提で、脆弱性に対応するIPS/IDS等の高度なツールは利用していません。今回は主にこの伝統的な<B>fail2ban</B>で遮断された情報を元に不正アクセスの傾向を出力することを目的としています。

###fail2ban
fail2ban は新しいツールでは全くありません。リアルタイムに`/var/log/apache/error_log`等、サービスへの不正アクセスがレポートされる設定によって指定されたログファイルをリアルタイムでスキャンし、ログファイルの中の悪意あるサインを元に接続元IPアドレスを指定された時間においてBan (iptablesへの自動追加・アップデート) することで、ログインパスワードの失敗, Exploit利用からシステムを保護します。fail2banはbrutefoce攻撃のように繰り返し試行されるログインのレートを軽減することには有効に働きますが、脆弱な認証へのアクセスそのもを軽減するわけではありません。

###jail.local
sshの場合、なるべく同一のIPアドレスから連続した 'Failed password' が`/var/log/secure`に出力されないようにする、postfixの場合、なるべく同一のIPアドレスから連続した 'LOGIN authentication failed' が`/var/log/mail/maillog` から出力されないようにするための調整をしばらく続け、最終的にそれぞれ、`findtime=1800`/`maxentry=3`, `findtime=5400`/`maxentry=2`がベストであるという結論に行き着きました。つまりpostfixの場合、90分以内に3回同一接続元からログイン失敗があればBanするという設定です。多くの場合同一接続元から17~18分以内に再アクセスを試みていました。

```ini:jail.local
[DEFAULT]
ignoreip = x.x.x.0/24
backend = polling
bantime = 360000
maxretry= 3
usedns = yes

[ssh-iptables]
enabled = true
filter = sshd
action = iptables[name=SSH, port=ssh, protocol=tcp]
         sendmail-whois[name=ssh-sasl, dest=root, sender=fail2ban@sample.org]
logpath = /var/log/secure
findtime = 1800

[sasl-iptables]
enabled = true
filter = postfix-sasl
action = iptables-multiport[name=postfix-sasl, port="smtp,smtps", protocol=tcp]
         sendmail-whois[name=postfix-sasl, dest=root, sender=fail2ban@sample.org]
logpath = /var/log/mail/maillog
maxretry= 2
findtime = 5400
```


#<font color="DarkSlateBlue">不正アクセス接続元の悪性スコア調査Tips (Umbrella Investigate API)</font>

###Cisco Umbrella Investigate
<B>Umbrella</B> は Public Recursive DNS として1日辺り1800億以上のリクエストから自動解析された潜在的な悪性ドメイン, IPアドレスを予測的指標としてスコアリングしています。これらのDNS, IPアドレスに対するセキュリティ統計分析は <B>Umbrella Investigate</B> の機能として数多くの視点からスコア情報を取得できます。この特定のドメイン, IPアドレスに対して生成されたスコアは、主に予測分析を支援、疑わしいと見なされるネットワークアクティビティ情報を見つけるため、高度なセキュリティオペレーション担当者、セキュリティ研究者向けに利用することが可能です。

###Umbrella Investigate Risk Score
Umbrella Investigate Risk Score はドメイン名の字句特性 (構成文字列), とUmbrellaインフラへのドメインクエリ, リクエストパターン分析に基づき、0 - 100の範囲の予測的な潜在性スコアです。この数値は必ずしも調査対象の過去の不正活動による悪性度裁定に直結するわけでは無くあくまでも予測されるリスク値という位置づけです。この情報は調査対象に関する過去のBotnet、フィッシングドメイン、マルバタイジング、ランサムウェアとの関連性にもひも付きスコアリングされています。


###pyinvestigate (Umbrella Investigate API python モジュール)
不正アクセス情報統計のリスクスコア分布の情報として、Umbrella Investigate を利用しました。Umbrella Investigate は Web UI だけでなく REST API により Query することが可能です。65000 以上の取得された不正アクセス元IPアドレス, ホストFQDNから RiskScore をREST API から一括取得するため、Umbrella Investigate 用 python module である <B>pyinvestigate</B> を利用しました。


###1. pyinvestigate インストール
```bash
# pip3 install investigate
# pip3 install pytest
# pip3 install pytest-django
# pip3 install pytest-pythonpath
```
###2. investigate API キーの取得
- `https://dashboard.umbrella.com/` へログイン
- Investigate > Investigate API Access へナビゲート
- CREATE NEW TOKEN
![Token.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311200/47b7f69f-db3c-9c03-9d66-1dfff9a441b0.png)
![Token2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311200/e1a2b6dc-a598-3d70-2377-db80c13bf12b.png)
作成したTokenを参照し、コピー

###3. pyinvestigate 実行
pyinvestigate は pythonインタープリタから実行できます。
コピーしたAPI Keyを指定し、調査IPアドレス/ドメインをクエリします。
不正アクセス調査用には別途スクリプトを作成し、一括取得しています。

```bash
# python36
```
```python
Python 3.6.8 (default, Aug 10 2019, 06:52:10)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-23)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> import investigate

>>> import datetime
>>> api_key = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
>>> inv = investigate.Investigate(api_key)
>>>
>>> inv.risk_score('xxx.com')
{'features': [{'feature': 'Geo Popularity Score', 'normalizedScore': 50, 'score': 0}, {'feature': 'Keyword Score', 'normalizedScore': 26, 'score': 0.26108091120959626}, {'feature': 'Lexical', 'normalizedScore': 89, 'score': 0.898}, {'feature': 'Popularity 1 Day', 'normalizedScore': None, 'score': None}, {'feature': 'Popularity 30 Day', 'normalizedScore': None, 'score': None}, {'feature': 'Popularity 7 Day', 'normalizedScore': None, 'score': None}, {'feature': 'Popularity 90 Day', 'normalizedScore': None, 'score': None}, {'feature': 'TLD Rank Score', 'normalizedScore': 0, 'score': 0.007835250367488503}, {'feature': 'Umbrella Block Status', 'normalizedScore': 0, 'score': False}], 'riskScore': 71}
>>>
```

```python
{'features': [{'feature': 'Geo Popularity Score', 'normalizedScore': 3, 'score': -3.1797661699999997}, {'feature': 'Keyword Score', 'normalizedScore': 0, 'score': 0.005737760395203566}, {'feature': 'Lexical', 'normalizedScore': 50, 'score': 0.504}, {'feature': 'Popularity 1 Day', 'normalizedScore': 95, 'score': 95.59}, {'feature': 'Popularity 30 Day', 'normalizedScore': 96, 'score': 96.94}, {'feature': 'Popularity 7 Day', 'normalizedScore': 96, 'score': 96.26}, {'feature': 'Popularity 90 Day', 'normalizedScore': 96, 'score': 96.41}, {'feature': 'TLD Rank Score', 'normalizedScore': 0, 'score': 0.00562125007281412}, {'feature': 'Umbrella Block Status', 'normalizedScore': 0, 'score': False}], 'riskScore': 1}
{'features': [{'feature': 'Geo Popularity Score', 'normalizedScore': 84, 'score': 1.68891283}, {'feature': 'Keyword Score', 'normalizedScore': 50, 'score': 0.5030948281811238}, {'feature': 'Lexical', 'normalizedScore': 75, 'score': 0.751}, {'feature': 'Popularity 1 Day', 'normalizedScore': 11, 'score': 11.45}, {'feature': 'Popularity 30 Day', 'normalizedScore': 8, 'score': 8.72}, {'feature': 'Popularity 7 Day', 'normalizedScore': 9, 'score': 9.59}, {'feature': 'Popularity 90 Day', 'normalizedScore': 10, 'score': 10.8}, {'feature': 'TLD Rank Score', 'normalizedScore': 28, 'score': 0.28834641075042694}, {'feature': 'Umbrella Block Status', 'normalizedScore': 0, 'score': False}], 'riskScore': 29}
{'features': [{'feature': 'Geo Popularity Score', 'normalizedScore': 86, 'score': 1.8171738299999998}, {'feature': 'Keyword Score', 'normalizedScore': 50, 'score': 0.5030948281811238}, {'feature': 'Lexical', 'normalizedScore': 99, 'score': 0.991}, {'feature': 'Popularity 1 Day', 'normalizedScore': None, 'score': None}, {'feature': 'Popularity 30 Day', 'normalizedScore': None, 'score': None}, {'feature': 'Popularity 7 Day', 'normalizedScore': None, 'score': None}, {'feature': 'Popularity 90 Day', 'normalizedScore': None, 'score': None}, {'feature': 'TLD Rank Score', 'normalizedScore': 28, 'score': 0.28834641075042694}, {'feature': 'Umbrella Block Status', 'normalizedScore': 0, 'score': False}], 'riskScore': 94}
```

# 参照
[1] fail2ban
https://www.fail2ban.org/wiki/index.php/Main_Page
[2] Umbrella Investigate REST API - Security Information for a Domain
https://docs.umbrella.com/investigate-api/docs/security-information-for-a-domain-1#section-risk-score-for-a-domain
[3] pyinvestigate
https://github.com/opendns/pyinvestigate