WindowsイベントログをGraylogにInputする

WindowsイベントログをGraylogにInputする

Graylogは色んなログをどんどん取り込むことができるので、SIEMとして活用できそうです。試しに今回はWindowsのイベントログをGraylogに取り込んでみたいと思います。

やり方は色々あると思いますが、ここではPythonからGELFを使って取り込みます。

環境情報

Graylogサーバー

・CentOS7
・Graylog v3.0.1

クライアント

・Windows10 or 7
・Python3.6.2

Windowsイベントログを取得

Windowsイベントログはpowershellやwmicなど色んな方法で取得できますが、ここではwevtutilコマンドを使って取得します。

wevtutilコマンドはBookmark機能があるので、すでに取り込んだログを取り込むことなく2回目以降高速に取得できるからです。

wevtutil qe System /f:text /sbm:bookmark.xml > system.txt

ローカルPCのSystemイベントログを取得するにはこのようにします。

wevtutil qe System /f:text /bm:bookmark.xml /sbm:bookmark.xml > system.txt

2回目以降は /bm オプションを追加して、前回のbookmarkの位置を取得するようにします。

wevtutil qe System /r:remotecomputer /f:text /bm:bookmark.xml /sbm:bookmark.xml > system.txt

また、リモートPCのイベンログを取得するには /r オプションを指定します。

出力形式をText形式にすると、出力に時間がかかるようになりますが、xml形式だとGraylogに送信するときにメッセージが日本語で表示できなくなりますので、Text形式で取得しています。

Inputの設定

[System / Imputs] – [Inputs]を開きます。

GELF HTTPを選択して、[Launch new input]をクリックします。

分かりやすいタイトルを入力し、[Save]をクリックします。
なお、ここで指定したPort番号に対して送信しますので、覚えておいてください。

GELF形式について

Graylog(Graylog Extended Log Format)は、JSON形式のGraylog用のログフォーマットです。

基本的にはJSON形式にすればいいのですが、次のフィールドを必要とします。

  • version string (UTF-8)
    • 必須フィールドです。 1.1と指定してください。
  • host string (UTF-8)
    • 必須フィールドです。ここに指定する文字列が、Graylog側でのSourceフィールドとなります。
  • short_message string (UTF-8)
    • 必須フィールドです。ここに指定する文字列が、Graylog側でのmessageフィールドとなります。
  • full_message string (UTF-8)
    • short_messageより長い文字列が必要な場合はオプションで。
  • timestamp number
    • オプションですが、ログのtimestampは入れておいたほうがいいでしょう。UNIXエポックタイムを指定します。
  • level number
    • オプションです。デフォルトでは1となります。
  • facility string (UTF-8)
    • オプションです。facilityを指定したい場合は入力。
  • line number
    • オプションです。エラーとなったファイルの行数を指定しますが、このフィールドは非推奨のようです。
  • file string (UTF-8)
    • オプションです。こちらも非推奨なのですが、エラーとなったファイル名またはフルパスを指定します。
  • _[additional field] string (UTF-8) or number
    • 上記以外のフィールドを追加するには、_を付けて追加フィールドを作成します。

PythonでイベントログをGELF形式に変換してGraylogに送信

それでは、wevtutilで取得したテキスト形式のイベントログをGELF形式に変換してGraylogに送信してみます。

#-*- coding: utf-8 -*-
import urllib.request, json
from datetime import datetime, timedelta
import os

url = "http://graylogserver:12202/gelf"
method = "POST"
headers = {"Content-Type" : "application/json"}

def posteventlog(evntfile):
    f = open(evntfile, encoding="shift-jis")
    lines = f.readlines()
    f.close()

    dsfl = False
    lists = []
    dstr = ""
    for line in lines:
        line = line.replace("\n", "")

        if "Event[0]" in line:
            continue

        if dsfl == False:
            lists.append(line.split(": ")[1])

            if "Description:" in line:
                dsfl = True

        else:
            if "Event[" in line and dsfl == True:

                short_message = "pc eventlog"
                timestamp = datetime.strptime(lists[2], "%Y-%m-%dT%H:%M:%S.%f")
                data = {
                    "version" : "1.1", "host" : "pc", "short_message" : short_message,
                    "timestamp" : int(timestamp.timestamp()),
                    "_LogName" : lists[0], "_Source" : lists[1], "_Date" : lists[2], "_EventID" : lists[3],
                    "_Task" : lists[4], "_Level" : lists[5], "_Opcode" : lists[6], "_Keyword" : lists[7],
                    "_User" : lists[8], "_UserName" : lists[9], "_Computer" : lists[10], "_Description" : dstr
                }
                json_data = json.dumps(data).encode("utf-8")

                dstr = ""

                # httpリクエストを準備してPOST
                request = urllib.request.Request(url, data=json_data, method=method, headers=headers)
                with urllib.request.urlopen(request) as response:
                    response_body = response.read().decode("utf-8")

                lists = []
                dsfl = False
            else:
                dstr += line

if __name__ == "__main__":
   posteventlog("System.txt")

ちょっとあれなコードですが、ゴリゴリ回して変換してます。
まあでも、そんなに時間はかからず送信できますのでご容赦を。

これでGraylogにWindowsのイベントログを送信することができるようになります。