はじめに
最近とりわけサイバー攻撃が増えていますね。クライアントに設置しているFortigateから毎日かなりの数のアラートが届きます。社内から「毎回報告書を作るのが大変」との声が出たので,GASを使ってアラートメールをスクレイピングして「何件あるか」「どこからの攻撃か」がわかるようにしました。
使ったもの
- Gmail
- Google スプレッドシート
- Google Apps Script
- GeoLite2(IPから国情報を取得)
- LINE Notify(分析完了時の通知)
取得する内容
来るアラートはこんな感じです。
Message meets Alert condition
The following critical firewall event was detected: SSL VPN login fail.
date=2022-**-** time=00:00:01 devname=<<DEVNAME>> devid=<<DEVID>> logid=<<LOGID>> type=event subtype=vpn level=alert vd=root logdesc="SSL VPN login fail" action="ssl-login-fail" tunneltype="ssl-web" tunnelid=0 remip=<<攻撃元IPアドレス>> user="<<USER>>" group="N/A" dst_host="N/A" reason="sslvpn_login_unknown_user" msg="SSL user failed to logged in"
上記アラートから
- 日付:受信日時
- メールタイトル
- メッセージ:msg=
- 攻撃元IPアドレス:remip=
- 国情報
を取得し,最終的には以下のようなシートを作るようにします。グラフは後から手動で付けてます。(ここもそのうち自動化する予定)
ロシア多いな…
IPアドレスと国情報の取得
メールの受信日時はgetDate()
を,タイトルはgetSubject()
を,メールの文面はgetPlainBody()
を使えばいいので特に苦労しませんでした。
IPアドレスは正規表現で取得できます。
// リモートIPアドレス取得
const Regex = /(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])/;
const IPAddr = PlainBody.match(Regex);
配列で返ってくるので,文字列を取得するにはIPAddr[0]
としてあげる必要があります。
今回は「どこからの攻撃か」を知りたいので,GeoLite2を使ってIPアドレスから国情報を取得します。事前にサインアップしてIDとトークンを取得しておく必要があります。GeoLite2 サインアップページ
// GeoLite2 Options
const ID = "<<GeoLite2のID>>";
const PW = "<<GeoLite2のトークン>>";
const option = {
'method': 'GET',
'contentType': 'application/json; charset=utf-8',
headers: {"Authorization" : " Basic " + Utilities.base64Encode(ID + ":" + PW)}
}
// IPアドレスから国を取得(GeoLite2使用)
const url = 'https://geolite.info/geoip/v2.1/country/' + IPAddr[0] + '?pretty';
let res = UrlFetchApp.fetch(url, option);
let conData = JSON.parse(res);
let txtCountry = conData["country"]["names"]['ja'];
あとGeoLite2は無料なので 1日あたり1000件までしかリクエストできない ことに注意してください。(超える場合は有償を考慮)
今回は1ヶ月分まとめてリクエストするとすぐ上限に行きそうだったので,毎日定時でスクリプトを動かすことにしました。
定時実行
GAS にはトリガーが設定できるので,毎日朝7~8時に前日のアラートメールを収集するよう設定します。
せっかくなのでLINE通知
LINE Notifyを使えば難しいことなく自分のLINEに通知できるので活用することにします。日付を引数で渡していつの分析が済んだかわかるようにします。
function sendLINENotify(RunDate) {
const Mes = RunDate + "分のFortigateのアラート分析が完了しました!";
// LINE Notify Token
const Token = "<<取得したトークン>>";
const options = {
"method": "post",
"headers": {
"Authorization" : "Bearer "+ Token
},
"payload": {
"message": Mes
}
}
const url = "https://notify-api.line.me/api/notify"
UrlFetchApp.fetch(url, options)
}
感想
GASでのメールスクレイピングは初めてやりましたがすごく便利ですね。受注メールから在庫管理システムへデータ渡したり,売り上げ出したり…できること多くて面白いです。
「かゆいところに手が届く」身近なシステム屋さんを目指してますので是非お仕事・ご相談お待ちしております😄
謝辞
以下のサイトを参考にさせていただきました。ありがとうございます。
https://tetsuooo.net/gas/746/
https://note.com/skipla/n/nefdfa2abd350