
Beagleは、セキュリティログやデータをグラフに変換するインシデント対応およびデジタルフォレンジックツールです。
Beagleは、データソースとログをグラフに変換するインシデント対応およびデジタルフォレンジックツールです。対応データソースには、FireEye HX Triage、Windows EVTXファイル、SysMonログ、WindowsメモリのRawイメージが含まれます。生成されたグラフは、Neo4JやDGraphなどのグラフデータベースに送信するか、PythonのNetworkXオブジェクトとしてローカルに保持できます。
Beagleは、Pythonライブラリとして直接使用することも、提供されるWebインターフェースを介して使用することもできます。
ライブラリは、単一のデータソースからの一連の関数呼び出しとして使用できます。
>>> from beagle.datasources import SysmonEVTX
>>> graph = SysmonEVTX("malicious.evtx").to_graph()
>>> graph
<networkx.classes.multidigraph.MultiDiGraph at 0x12700ee10>
複数のアーティファクトから生成されたグラフとしても使用できます。
>>> from beagle.datasources import SysmonEVTX, HXTriage, PCAP
>>> from beagle.backends import NetworkX
>>> nx = NetworkX.from_datasources(
datasources=[
SysmonEVTX("malicious.evtx"),
HXTriage("alert.mans"),
PCAP("traffic.pcap"),
]
)
>>> G = nx.graph()
<networkx.classes.multidigraph.MultiDiGraph at 0x12700ee10>
または、データソースからグラフへの各中間ステップを明示的に呼び出すこともできます。
>>> from beagle.backends import NetworkX
>>> from beagle.datasources import SysmonEVTX
>>> from beagle.transformers import SysmonTransformer
>>> datasource = SysmonEVTX("malicious.evtx")
# Transformerはデータソースを受け取り、各イベントを
# 1つ以上のノードのタプルに変換します。
>>> transformer = SysmonTransformer(datasource=datasource)
>>> nodes = transformer.run()
# Transformerはノードの配列を出力します。
[
(<SysMonProc> process_guid="{0ad3e319-0c16-59c8-0000-0010d47d0000}"),
(<File> host="DESKTOP-2C3IQHO" full_path="C:\Windows\System32\services.exe"),
...
]
# Backendはノードを受け取り、グラフに変換します。
>>> backend = NetworkX(nodes=nodes)
>>> G = backend.graph()
<networkx.classes.multidigraph.MultiDiGraph at 0x126b887f0>
グラフは個々のプロセスのアクティビティを中心に構成されており、主にアナリストがホスト上のアクティビティを調査するためのものであり、ホスト間のアクティビティを対象としたものではありません。
BeagleはDockerファイルとして利用可能です。
docker pull yampelo/beagle
mkdir -p data/beagle
docker run -v "$PWD/data/beagle":"/data/beagle" -p 8000:8000 yampelo/beagle
ライブラリとしても利用可能です。完全なAPIドキュメントはhttps://beagle-graphs.readthedocs.ioで入手できます。
pip install pybeagle
注:現在サポートされているのはPython 3.6以上のみです。
Rekallは自動的にはインストールされません。Rekallをインストールするには、代わりに以下のコマンドを実行してください。
pip install pybeagle[rekall]
設定ファイル内の任意のエントリは、BEAGLE__{SECTION}__{KEY}の形式に従った環境変数を使用して変更できます。例えば、Dockerイメージ使用時のVirusTotal APIキーを変更するには、-eパラメータを使用してBEAGLE__VIRUSTOTAL__API_KEY変数を設定します。
docker run -v "data/beagle":"/data/beagle" -p 8000:8000 -e "BEAGLE__VIRUSTOTAL__API_KEY=$API_KEY" beagle
環境変数とディレクトリは、docker composeを使用して簡単に定義できます。
version: "3"
services:
beagle:
image: yampelo/beagle
volumes:
- /data/beagle:/data/beagle
ports:
- "8000:8000"
environment:
- BEAGLE__VIRUSTOTAL__API_KEY=$key$
BeagleのDockerイメージには、データをグラフに変換するプロセスと、それらを使用してデータを調査するプロセスをラップしたWebインターフェースが付属しています。
アップロードフォームはグラフ作成プロセスをラップし、自動的にNetworkXをバックエンドとして使用します。データソースが必要とするパラメータに応じて、フォームはファイルのアップロードまたはテキスト入力を促します。例えば:
作成されたグラフは、設定のstorageセクションのdirキーで定義されたフォルダ内にローカルに保存されます。これはBEAGLE__STORAGE__DIR環境変数を設定することで変更できます。
必要に応じて、任意のグラフにコメントを追加して、より適切に説明することができます。
各データソースは、提供されたパラメータから自動的にメタデータを抽出します。メタデータとコメントは、後でそのデータソースの既存のグラフを表示する際に表示されます。
サイドバーのデータソースをクリックすると、そのデータソースで解析されたすべてのグラフのテーブルが表示されます。
Beagleでグラフを表示すると、アナリストがインシデントを迅速に分析できるWebインターフェースが提供されます。
インターフェースは主に2つの部分に分かれています。左側の部分はグラフのさまざまな視点(グラフ、ツリー、テーブルなど)を含み、右側の部分はノードとエッジをタイプでフィルタリング、ノードの検索、ノードのプロパティの展開を可能にします。また、グラフに対して実行した操作を元に戻したりやり直したりすることもできます。
グラフ内で上に仕切りがある要素はすべて折りたたみ可能です。
グラフ内のノードは、特定のフィールドの最初の15文字を表示します。たとえば、プロセスノードの場合はプロセス名が表示されます。
エッジはエッジタイプを単に表示します。
ノードまたはエッジを1回クリックすると、そのノードにフォーカスし、右側のサイドバーの「ノード情報」パネルにその情報が表示されます。
ノードをダブルクリックすると、近隣のノードが取り込まれます。近隣ノードとは、クリックされたノードにエッジで接続されている任意のノードです。取り込む近隣ノードがない場合、グラフに変化は見られません。
ノードを長押しクリックすると、そのノードとそれに依存するすべてのエッジがグラフから非表示になります。
ノードを右クリックすると、グラフミューテーターを実行できるコンテキストメニューが表示されます。ミューテーターは、グラフの状態を受け取り、新しい状態を返す関数です。
非常に便利なミューテーターを2つ紹介します。
ノードのバックトラックは非常に便利で、ログファイルで感染の根本原因を特定するのと似ています。
ノードの子孫を展開すると、このノードが原因で発生したすべてのものを即座に表示できます。このアクションは、選択されたノードをルートとするサブグラフを明らかにします。
ノードまたはエッジが現在のインシデントに関連しない場合があります。その場合、エッジとノードの種類をオン/オフに切り替えることができます。種類を切り替えると、その種類のノードまたはエッジが表示されているグラフから削除されます。
ノードの種類をオフにすると、そのノードの種類はミューテーターの使用時や近隣ノードの取り込み時に使用されなくなります。
グラフ内のアクションはすべて即座に元に戻せます。元に戻す/やり直しボタンを使用して、実行したアクションを元に戻すことができます。リセットボタンはグラフの状態を読み込み時の状態に戻し、リフレッシュの手間を省きます。
上記のアクションを使用してグラフの現在の状態を変更する際に、現在表示されているノードとエッジのセットを別の視点で表示したい場合があります。グラフ画面の上部にあるタブを使用すると、データをさまざまなビューに変換できます。
各視点では、ノードをクリックしてフォーカスすることができます。
グラフ生成プロセスは、Pythonライブラリを使用してプログラム的に実行できます。グラフ生成プロセスは3つのステップで構成されています。
DataSourceクラスがデータを解析し、イベントを1つずつ生成します。Transformerクラスがそれらの入力を受け取り、ProcessなどのさまざまなNodeクラスに変換します。Backendクラスがノードの配列を受け取り、グラフ構造に配置して、目的の場所に送信します。Pythonパッケージはpipでインストールできます。
pip install pybeagle
グラフを作成するには、これらを連鎖させる必要があります。これはto_graph()関数を使用して自動的に行えます。
from beagle.datasources import HXTriage
# デフォルトでは、to_graph()クラスはNetworkXと最初のトランスフォーマーを使用します。
G = HXTriage('test.mans').to_graph()
<networkx.classes.multidigraph.MultiDiGraph at 0x12700ee10>
各ステップを明示的に実行することもできます。関数呼び出しを使用すると、使用するBackendも定義できます。例えば、DGraphにデータを送信する場合:
from beagle.datasources import HXTriage
from beagle.backends import DGraph
from beagle.transformers import FireEyeHXTransformer
# データは設定ファイルで構成されたDGraphインスタンスに送信されます。
backend = HXTriage('test.mans').to_graph(backend=DGraph)
# Transformerも指定できます。
backend = HXTriage('test.mans').to_transformer(transformer=FireEyeHXTransformer).to_graph(backend=DGraph)
to_graphまたはto_transformerメソッドを呼び出す際に、それらのクラスに任意の引数を渡すことができます。
from beagle.datasources import HXTriage
from beagle.backends import Graphistry
# graphistryに送信し、データを匿名化してURLを返します。
graphistry_url = HXTriage('test.mans').to_graph(backend=Graphistry, anonymize=True, render=False)
上記のプロセスの各ステップを手動で呼び出し、中間出力にアクセスすることもできます。
>>> from beagle.backends import NetworkX
>>> from beagle.datasources import HXTriage
>>> from beagle.transformers import FireEyeHXTransformer
>>> datasource = HXTriage("test.mans")
>>> transformer = FireEyeHXTransformer(datasource=datasource)
>>> nodes = transformer.run()
>>> backend = NetworkX(nodes=nodes)
>>> G = backend.graph()
各ステップを手動で呼び出す場合は、Transformerクラスのインスタンスが提供されたDataSourceクラスの出力と互換性があることを確認する必要があります。
各データソースは、互換性のあるTransformerのリストを定義しており、これは.transformers属性でアクセスできます。
>>> from beagle.datasources import HXTriage
>>> HXTriage.transformers
[beagle.transformers.fireeye_hx_transformer.FireEyeHXTransformer]
デフォルトでは、エッジは凝縮されていません。つまり、プロセスノードuがファイルノードvに5000回書き込む場合、それらのノード間には5000のエッジが存在します。特にデータを視覚化しようとする場合、これはアナリストを圧倒する可能性があります。
すべての5000エッジをそのアクションタイプ(この場合は書き込み)の単一のエッジに凝縮するには、Backendクラスにconsolidate_edges=Trueパラメータを渡します。例えば:
SysmonEVTX("data/sysmon/autoruns-sysmon.evtx").to_graph(NetworkX, consolidate_edges=False)
# グラフには826ノードと2469エッジが含まれます。
SysmonEVTX("data/sysmon/autoruns-sysmon.evtx").to_graph(NetworkX, consolidate_edges=True)
# グラフには826ノードと1396エッジが含まれます
デフォルトでは、Webインターフェースはエッジを凝縮します。
NetworkXバックエンドを使用すると、結果のグラフをJSONオブジェクトとして保存し、後で使用するために保存できます。NetworkX.from_json静的メソッドを使用して、それを読み戻すことができます。
import json
from beagle.datasources import SysmonEVTX
from beagle.backends import NetworkX
# nx.MultiDiGraphオブジェクトを取得
graph = SysmonEVTX("malicious.evtx").to_graph()
# オブジェクトをJSONに変換
graph_json = NetworkX.graph_to_json(graph)
with open("my_graph.json", "w") as f:
json.dump(graph_json, f)
# 後で:
# Gは`.to_graph()`で生成された同じnx.MultiDiGraphオブジェクト
G = NetworkX.from_json("my_graph.json")