Overview
Windows EventLogをElasticSearchにimportする
という記事をちょっと前に書きました
EvtxtoElkはとても素晴らしいライブラリなのですが,
Windowsの巨大なイベントログをインデックスしようとするとアホみたいに時間がかかって死にそうなので高速化を図ります。(僕のケースでは30分ほどかかっていました)
結論からいうと, EvtxtoElkの高速化は(コスト的に)無理なので偉い人が作ったパーサを利用して自分で書きました。
2020/06/12 追記:
機能追加しました
Windows EventLogをjson形式に変換する
Usage
pipでインスコします。
pip install evtx2es
コンソールからも使えます。
$ evtx2es /path/to/your/file.evtx
Python製なのでスクリプトからも呼べて安心!
100ファイル読みたいときとかも楽チンですね!
from evtx2es import evtx2es
if __name__ == '__main__':
filepath = '/path/to/your/file.evtx'
evtx2es(filepath)
Evaluation
評価にはJPCERT/CCが提供しているLogonTracerというツールのsampleを使いました。
だいたい30MBくらいのSecurityログです。
速度の計測にはtimeコマンドを用いました。
もっと厳密な図り方もできますが, どうせ計測環境によって変わるしいいよね。
EvtxtoElk
$ time python elk.py
321.95 user 0.11 system 5:30.77 elapsed 97%CPU
Evtx2es
$ time python es.py
4.94 user 0.06 system 0:11.84 elapsed 42%CPU
約320秒から5秒になりました。
大体64倍の高速化ができました!100倍は嘘です!!ごめんなさい!!!
CPU使用率も下がってるのも嬉しいです
Optimize
最初はWindowsのクソデカいファイルだからこんなもんかな〜と思ってたんですけど, ElasticSearchのインデックスってそんなに遅くないハズなんですよね。
なのに遅いってことは, どこかで足を引っ張っている存在がいるということです。
ならそこを高速化してあげれば早くなるはず!と思って取り掛かりました。
アプローチとしては
-
Python部分を書き直す
- numbaで実行時コンパイルを行う
- Cythonを使ってC言語のライブラリをコンパイルする
-
それ以外の言語を使う
- 遅い部分だけ別の言語で書く
- 速い言語でPythonライブラリを作る
などいくつかあります。下に行くほど黒魔術感が増します。
以下に高速化の手順を書いていきます...といっても僕がしたことはほとんどなくて,
卍最強Evtxパースライブラリ卍 を使っただけです。
Profiling
Pythonみたいな速度の遅い言語を使う人はよくやると思うんですが,
むやみやたらに高速化するよりボトルネックを探して重点的に高速化したほうが効果が高いことが多いです。
そのために, line_profilerというものを使います。
詳しい説明を書いてくれている方がいらっしゃるのでおまかせします。(助かりました!ありがとうございます!)
line_profilerで行単位でEvtxtoElkのコードを分析した結果, EvtxtoElkは無実だということがわかりました
じゃあ何が悪かったかというと, 依存ライブラリのpython-evtxのようです。
(※ このライブラリは非常に有用ですが, 今回のユースケースでは間違った選択だった. ということです.)
Development
ならpython-evtxをCythonで高速化しようと思ったのですが, ソースコードをひと目見てやめました。作業量にリターンが見合いません。
しかたないからRustあたりでパーサを書くか〜とも思ったのですが, ふとこんな考えが頭をよぎりました。
(もう誰かつくってるのでは?)
https://github.com/omerbenamram/pyevtx-rs
じゃあelasticsearchとの接続部分だけ書けばいいじゃん!と思ってつくってついでにパッケージ化しました。
修士の研究で使うから作ったけどせっかくなら使ってもらえるとうれしいです!
お わ り
ちなみに
$ evtx2es hoge.evtx --size=10000
とかしましたがあんまりはやくなりませんでしたざんねん
ElasticSearchはバッファサイズで劇的に早くなるわけではないのでそこそこの値にしておくのが良いと思います。
どっちかというとMappingTypeを最適化したほうがパフォーマンス良かったりします(_allを無効にする, not_analyzedなフィールドを設定するなど...)