ネットワークログは様々なものがありますが、オープンデータで入手できるものを使って、分析をしてみようと思います。ここでは以下の点に注目して実施していきます。プログラム言語はPythonでやっていきます。
(1)大量なログを分析できる形に整えることができる
(2)ネットワーク管理者が設計図で確認できる内容ではなく、実際のネットワークデータから、コンピュータ間の同値類(セグメントみたいなもの)を確認し、可視化する
(3)コンピュータ間の通信をマルコフ連鎖でモデル化する(推移確率を求める)
1. 利用データの準備
今回は「Unified Host and Network Data Set」を使わせてもらいます。ここには「Network Event Data」と「Host Event Data」の2つがあり、今回は「Network Event Data」を使います。このデータは、サイトから引用すると下記のような項目があり、シンプルでわかりやすいです。
利用するためには、メールアドレスの登録をすると、データをダウンロードするためのスクリプトが出てくるので、Linux等の環境で行い、ダウンロードを行なって下さい。ただし、データが巨大なので十分な領域を確保してやりましょう。解凍後のcsvの1ファイルは7~10Gbyte位あります。あと謝辞にこのサイトを入れるのを忘れないようにしましょう。M. Turcotte, A. Kent and C. Hash, “Unified Host and Network Data Set”, in Data Science for Cyber-Security. November 2018, 1-22
無事データの取り込みができると、このファイルでは、115,949,436件のデータがあることがわかります。
ダウンロードしたら、展開しておき、csvファイルを確認します。今回は最初の日のデータで、「netflow_day-02.bz2」(1.08GB)を展開した「netflow_day-02.csv」(7.15GB)を使っていきます。
bz2の展開には「bunzip2 netflow_day-XX.bz2」のようにbunzip2を使うといいでしょう。
2. データの取り込み
必要なモジュール(numpy, pandas, matplotlib.pyplot)をインストールして、ファイルを取り込みます。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#https://csr.lanl.gov/data/2017/ | |
file = './netflow_day-02.csv' | |
df = pd.read_csv(file, header=None) | |
df.columns = ['Time','Duration','SrcDevice','DstDevice','Protocol','SrcPort','DstPort','SrcPackets','DstPackets','SrcBytes','DstBytes'] | |
df |
基本統計情報を見てみると、特にバイト数が桁数が大きいところがあるので、他の項目もまとめて10^6で割り、バイトはメガバイト(MB)に変換しておきます。maxの項目をみると、桁数が減っていることがわかります。
変更前のdf.describe()
10^6で割った後のdf.describe()
3. デバイス集合を作成
「SrcDevice」と「DstDevice」を使って、デバイス集合を作成します。このデバイス集合を使って、どこからどこへの通信があるかを集計していきます。SrcDeviceにしかないデバイス、DstDeviceにしかないデバイス、両方にあるデバイスがあるので、それぞれ集合として抽出して、その和集合を取ります。SrcDeviceには25,847件、DstDeviceには25,308件ありました。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
SrcDevice_list = df['SrcDevice'].unique().tolist() | |
print(len(SrcDevice_list)) | |
SrcDevice_df = pd.DataFrame({'SrcDevice': SrcDevice_list}) | |
SrcDevice_df.to_csv('netflow_day-02_srcdevice.csv', index=False) | |
DstDevice_list = df['DstDevice'].unique().tolist() | |
print(len(DstDevice_list)) | |
DstDevice_df = pd.DataFrame({'DstDevice': DstDevice_list}) | |
DstDevice_df.to_csv('netflow_day-02_dstdevice.csv', index=False) | |
#和集合を求める | |
SrcDevice_set = set(SrcDevice_list) | |
DstDevice_set = set(DstDevice_list) | |
Device_set = SrcDevice_set | DstDevice_set | |
Device_list = list(Device_set) | |
Device_df = pd.DataFrame({'Device': Device_list}) | |
Device_df.to_csv('netflow_day-02_device.csv', index=False) | |
#積集合を求める(追加 2023/05/02) | |
Device_set_intersection = SrcDevice_set & DstDevice_set | |
Device_list_intersection = list(Device_set_intersection) | |
Device_df_intersection = pd.DataFrame({'Device': Device_list_intersection}) | |
Device_df_intersection.to_csv(file + '_device_intersection.csv', index=False) |
[2023/05/02]修正
ここで書いてあるように、最初はデバイスの和集合でやっていました。取りこぼしが無いように、全てのデバイスで集計して、通信が無いデバイスを後から削除しようと思いましたが、実際やってみると、集計ファイルが100GBになり、とても無理でした。ですので、和集合ではなく、積集合をとり、From <--> To の通信が両方ともあるデバイスのみ対象に変更しました。
4. 推移表の作成
3で作成したデバイス集合を使って、どのデバイスからどのデバイスへ通信があったかを集計します。今回はデータフレームの抽出は使わず、groupbyを使うことで高速に処理できます。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ファイルを分割せずに、集約して出力する | |
#PC間の通信回数を抽出 | |
device_weight = [] | |
from_device = [] | |
to_device = [] | |
from_packets = [] | |
to_packets = [] | |
from_bytes = [] | |
to_bytes = [] | |
duration = [] | |
start = time.time() | |
index = 1 | |
for src, sub_df in df.groupby('SrcDevice'): | |
for dst, subsub_df in sub_df.groupby('DstDevice'): | |
from_device.append(src) | |
to_device.append(dst) | |
cnt = len(subsub_df) | |
device_weight.append(cnt) | |
from_packets.append(subsub_df['SrcPackets'].sum()) | |
to_packets.append(subsub_df['DstPackets'].sum()) | |
from_bytes.append(subsub_df['SrcBytes'].sum()) | |
to_bytes.append(subsub_df['DstBytes'].sum()) | |
duration.append(subsub_df['Duration'].sum()) | |
print('{0} %完了'.format(index / len(SrcDevice_list) * 100)) | |
index += 1 | |
# if index > 30: | |
# break | |
df_sum = pd.DataFrame({'from': from_device, 'to': to_device, 'count' : device_weight, 'duration': duration, 'from_packets': from_packets, 'to_packets': to_packets, 'from_bytes': from_bytes, 'to_bytes': to_bytes}) | |
df_sum.to_csv('netflow_day-02_sum.csv') | |
elapsed_time = time.time() - start | |
print ("calclation_time:{0}".format(elapsed_time) + "[sec]") | |
df_sum |
0 件のコメント:
コメントを投稿