2023年4月19日水曜日

ホストログの分析2 : 出現回数のカウント

 前回csvを作成しましたので、それを取り込んで各要素でどんな出現があるかを確認していきます。データに含まれている要素は、以下になります。

'UserName', 'EventID', 'LogHost', 'LogonID', 'DomainName', 'ParentProcessName', 'ParentProcessID', 'ProcessName', 'Time', 'ProcessID', 'LogonTypeDescription', 'AuthenticationPackage', 'LogonType', 'Source', 'Status', 'ServiceName', 'Destination', 'SubjectUserName', 'SubjectLogonID', 'SubjectDomainName', 'FailureReason'

この中で、取得までに時間がかかる項目は、'LogonID'、'ProcessID'、'Time'で実際やってみると24時間以上かかります。(UserName(19314s) -> 5.3時間、ProcessName(4836s) -> 1.3時間, ParentProcessID(24928s) -> 6.9時間とかかりますが、24時間以内ですので、なんとかなりそうです。)
今回はこの'LogonID'、'ProcessID'、'Time'項目以外の項目を、各要素に出現する項目の出現回数を取得して、どのような内容になっているかを確認していきます。今回は単純計算なので並列計算は使いません。

ソースコード(HostEvents_Element_Count.py)

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import time
import sys
import json
if __name__ == '__main__':
target_list = ['UserName', 'EventID', 'LogHost', 'DomainName', 'ParentProcessName', 'ParentProcessID', 'ProcessName', 'LogonTypeDescription', 'AuthenticationPackage', 'LogonType', 'Source', 'Destination', 'SubjectUserName', 'SubjectLogonID', 'SubjectDomainName', 'Status', 'ServiceName', 'FailureReason'] #'18項目、LogonID', 'ProcessID', 'Time'は別途計算
#(1)csvファイルの取り込み
file = './wls_day-07_all.csv'
df = pd.read_csv(file)
#(2)各プロセスで各要素の計算
for target in target_list:
element_list = df[target].unique().tolist() #ユニークリスト作成
element_count = []
for i in element_list: #出現回数をカウント
element_count.append(df[target].tolist().count(i))
df_element_count = pd.DataFrame( #データフレーム化
data=element_count,
columns=['Count'],
index=element_list
)
df_element_count.to_csv('./wls_day-07_'+str(target)+'.csv', index=True)
#python3 HostEvents_Element_Count.py

これを実行すると、以下のようなデータが得られます。(wls_day-07_EventID.csv)

これを算出することで、どんなイベントがどのような頻度ででているかがわかります。まずは基本分析として、各要素のイベント出現回数を調査しました。

2023年4月18日火曜日

ホストログの分析1 : データの取り込みからcsv作成まで

Unified Host and Network Data Set (https://csr.lanl.gov/data/2017/)に2つデータセットがありますが、ここではHost Events Dataの分析を考えていきます。Host Events Dataは、下記のような要素があります(上記サイトから)。
この中でEventIDは以下のようなコード体系のようです(上記サイトから)
メールアドレスを入力すると、ダウンロードスクリプトが出てくるので、Host Events Dataをダウンロードします。ダウンロードすると1日分が約500MB程度のデータとなっています。全部のデータ90日分をダウンロードしようとすると3日程度かかってしまうので、1日分だけでもいいと思います。

(1) データの展開とファイル分割
例として「wls_day-07.bz2」331MBのデータを使ってみます。まずはbz2を展開していきます。僕はLinuxまたはMacのターミナルで実行しました。bunzip2 コマンドを使います。結構時間がかかります。僕の環境では3分程度です。

$ bunzip2 wls_day-07.bz2 

展開したファイル名は「wls_day-07」展開後の容量は10.1GBでした。このファイルの中身はjson形式となっています。このファイルを直接開こうとしても、通常のPCではメモリエラーになってしまい開くことができません。そこで500万行ずつ程度にこのファイルを分割します。

split -l 5000000 wls_day-07 wls_day-07_5000000

完了すると、今回は10個のファイルになり、末尾にaaなどがつきます。

(2) jsonデータからcsvに変換
jsonデータ形式は情報量も多く扱いやすいのですが、今回のようなデータではcsvに変換して、データを開きやすくした方が全体を扱えるのでいいと思います。一つずつファイルを取り込み、一つのcsvファイルにします。分割されたファイルが10個あるので、MPIで10プロセス発生させ、それぞれのプロセスで取り込んだものをrank0のプロセスが集約するようにします。一つのプロセスで時間かけてやってもよいと思います。
この処理には相当大きなメモリが必要となります。最低100GB程度あるサーバで実行して下さい。今回jsonで取り込んで、pandasでデータフレーム形式に変換して、そのあとcsvに保存するようにしました。
ソースコード(HostEvents_CSV_MPI.py)
from mpi4py import MPI
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import time
import sys
import json
if __name__ == '__main__':
comm = MPI.COMM_WORLD
rank = comm.Get_rank()
size = comm.Get_size()
file_list = ['wls_day-07_5000000aa', 'wls_day-07_5000000ab', 'wls_day-07_5000000ac', 'wls_day-07_5000000ad', 'wls_day-07_5000000ae', 'wls_day-07_5000000af', 'wls_day-07_5000000ag', 'wls_day-07_5000000ah', 'wls_day-07_5000000ai', 'wls_day-07_5000000aj'] #file_listの要素数だけプロセスを発生するようにする(今回は10)
#(1)各プロセスでrank数のfile_listを取り込み
json_file = open(file_list[rank])
df_jsonl = pd.read_json(json_file, orient='records', lines=True)
#(2)各プロセスから取り込んだ内容を集約して、一つのデータフレームにする
df_all = None
#データフレームの結合
if rank == 0:
df_all = df_jsonl #自分のデータフレームを代入
for i in range(1, size): #他プロセスのデータフレームを受け取り結合
df_rank = comm.recv(source=i, tag=11)
df_all = pd.concat([df_all, df_rank], ignore_index=True)
print('結合完了')
else :
comm.send(df_jsonl, dest=0, tag=11)
if rank == 0:
df_all.to_csv('./wls_day-07_all.csv', index=False)
#mpiexec -n 10 python3 HostEvents_CSV_MPI.py

集約ができると「wls_day-07_all.csv」が作成されます。僕の環境だと10分程度かかりました。容量は4.3GBとなり10.1GBから半減しています。これを試しに取り込んでみます。
少し時間はかかりますが、jupyterの環境でも無事取り込むことができました。今回の1日分は4500万行程度でした。
ここまでで1日分のHost Events Dataを取り込むことが出来ましたので、次はこれの基本分析を行なっていきます。