こんとろーるしーこんとろーるぶい

週末にカチャカチャッターン!したことを貼り付けていくブログ

T-PotのELK環境へWOWHoneypotログ取り込み

[更新履歴]

  • 2018/06/30
    WOWHoneypotのログからdest_portをELKに連携するようにlogstash.confを変更。

前回の続きです。 graneed.hatenablog.com

T-Potは、各ハニーポットのログをELKスタックに取り込んでビジュアライズしています。前回、WOWHoneypotをT-Pot環境に組み込んだため、ログも同じようにT-PotのELKスタックに取り込みます。

また、WOWHoneypotはHTTPリクエスト全体のデータをBase64エンコードしてログ出力しているため、ついでに Logstashのフィルタ機能を使用してBase64デコードします。これにより、任意のHTTPリクエストヘッダーやPOSTされたデータも検索可能になるはずです。

1. Logstashの定義変更

Logstashの処理は、Inputs→Filters→Outputsの3つのステージに分かれています。 InputsおよびFiltersステージの定義を変更します。Outputsステージは変更しなくてよさそうです。

  1. Inputsステージに、WOWHoneypot(HTTP/HTTPS両方)のログのファイルパスを追加する。
  2. Filterステージに、WOWHoneypotのログをパースして項目分割する定義を追加する。
  3. Filterステージの、ホスト名とIP付与する処理の条件に、WOWHoneypotを追加する。

ポイントは2です。備忘録も兼ねて説明を記載します。
まず、追加する定義は以下の通りです。

if [type] == "WOWHoneypot" or [type] == "WOWHoneypotssl" {
  grok {
    match => [ "message", '\A\[%{TIMESTAMP_ISO8601:timestamp}\]%{SPACE}%{IP:src_ip}%{SPACE}%{IPORHOST:http.hostname}:%{NUMBER:dest_port}%{SPACE}"%{WORD:http.http_method}%{SPACE}(?:%{URIPATHPARAM:http.url}|%{URI:http.url})%{SPACE}%{DATA:http.protocol}"%{SPACE}%{NUMBER:http.http_status}%{SPACE}%{WORD:mrrid}%{SPACE}%{GREEDYDATA:http.request_b64}' ]
    remove_field => ["port"]
  }
  date {
    match => [ "timestamp", "yyyy-MM-dd HH:mm:ssZ" ]
    remove_field => ["timestamp"]
  }
  ruby {
    init => "require 'base64'"
    code => "event.set('http.request', Base64.decode64(event.get('http.request_b64')))"
  }
}

grokでは、パターンを使用して、ログから項目を切り出すための定義を行います。

以下の公式ページを参考にしました。
Grok filter plugin | Logstash Reference [6.3] | Elastic

パターンの種類は以下のページを参考にしました。
logstash-patterns-core/grok-patterns at master · logstash-plugins/logstash-patterns-core · GitHub

定義したgrokは以下のページでテストできました。便利。
Test grok patterns

なお、remove_field => ["port"]しているのは、URIパターンを使用すると勝手に出現するport項目を削除するためです。

dateでは、該当ログのタイムスタンプを示すための定義を行います。例えば、Kibanaで日時を条件にして検索やソートする際に使用されるようです。

rubyでは、任意のrubyコードを実行できますが、今回はWOWHoneypotのログにあるHTTPリクエスト全体のデータをBase64デコードするために使用しました。

以下、作業手順です。

# ディレクトリ移動
[root@massshoemaker:~]# cd /opt/tpot/docker/elk/logstash/

# 比較用にバックアップ
[root@massshoemaker:/opt/tpot/docker/elk/logstash]# cp -p dist/logstash.conf dist/logstash.conf.org

# 定義変更。具体的な変更箇所はdiff結果を参照
[root@massshoemaker:/opt/tpot/docker/elk/logstash]# vi dist/logstash.conf
[root@massshoemaker:/opt/tpot/docker/elk/logstash]# diff -u dist/logstash.conf.org dist/logstash.conf
--- dist/logstash.conf.org      2018-06-10 01:30:22.786237401 +0900
+++ dist/logstash.conf  2018-06-16 02:33:11.528242645 +0900
@@ -93,6 +93,18 @@
     path => ["/data/vnclowpot/log/vnclowpot.log"]
     type => "Vnclowpot"
   }
+
+# WOWHoneypot
+  file {
+    path => ["/data/wowhoneypot/log/access_log"]
+    type => "WOWHoneypot"
+  }
+
+# WOWHoneypotssl
+  file {
+    path => ["/data/wowhoneypotssl/log/access_log"]
+    type => "WOWHoneypotssl"
+  }
 }

 # Filter Section
@@ -342,6 +354,22 @@
     }
   }

+# WOWHoneypot
+  if [type] == "WOWHoneypot" or [type] == "WOWHoneypotssl" {
+    grok {
+      match => [ "message", '\A\[%{TIMESTAMP_ISO8601:timestamp}\]%{SPACE}%{IP:src_ip}%{SPACE}%{IPORHOST:http.hostname}:%{NUMBER:dest_port}%{SPACE}"%{WORD:http.http_method}%{SPACE}(?:%{URIPATHPARAM:http.url}|%{URI:http.url})%{SPACE}%{DATA:http.protocol}"%{SPACE}%{NUMBER:http.http_status}%{SPACE}%{WORD:mrrid}%{SPACE}%{GREEDYDATA:http.request_b64}' ]
+      remove_field => ["port"]
+    }
+    date {
+      match => [ "timestamp", "yyyy-MM-dd HH:mm:ssZ" ]
+      remove_field => ["timestamp"]
+    }
+    ruby {
+      init => "require 'base64'"
+      code => "event.set('http.request', Base64.decode64(event.get('http.request_b64')))"
+    }
+  }
+
 # Drop if parse fails
 if "_grokparsefailure" in [tags] { drop {} }

@@ -378,7 +406,7 @@
   }

 # Add T-Pot hostname and external IP
-  if [type] == "ConPot" or [type] == "Cowrie" or [type] == "Dionaea" or [type] == "ElasticPot" or [type] == "eMobility" or [type] == "Glastopf" or [type] == "Honeytrap" or [type] == "Mailoney" or [type] == "Rdpy" or [type] == "Suricata" or [type] == "Vnclowpot" {
+  if [type] == "ConPot" or [type] == "Cowrie" or [type] == "Dionaea" or [type] == "ElasticPot" or [type] == "eMobility" or [type] == "Glastopf" or [type] == "Honeytrap" or [type] == "Mailoney" or [type] == "Rdpy" or [type] == "Suricata" or [type] == "Vnclowpot" or [type] == "WOWHoneypot" or [type] == "WOWHoneypotssl" {
     mutate {
       add_field => {
         "t-pot_ip_ext" => "${MY_EXTIP}"

2. Dockerイメージ更新、再起動

定義変更を反映させるため、LogstashのDockerイメージを更新します。

# 停止
[root@massshoemaker:/opt/tpot/docker/elk/logstash]# systemctl stop tpot

# Dockerイメージ更新
[root@massshoemaker:/opt/tpot/docker/elk/logstash]# docker build -t dtagdevsec/logstash:1710 .
Sending build context to Docker daemon 30.72 kB
Step 1/6 : FROM alpine
 ---> 3fd9065eaf02
Step 2/6 : MAINTAINER MO
 ---> Using cache
 ---> 213ca7b23dda
Step 3/6 : ADD dist/ /root/dist/
 ---> 6d20cf1a3a93
Removing intermediate container 0add569df296
(snip)
Removing intermediate container 86dc8db88c7e
Successfully built 1b72b8280ec3

# 起動
[root@massshoemaker:/opt/tpot/docker/elk/logstash]# systemctl start tpot

3. 稼働確認

httpとhttpsでそれぞれアクセスできるか確認します。

[root@massshoemaker:~]# curl http://localhost/ -H "AAA: BBB" -d "aaa=bbb"
<html>
<head>
  <title>sample</title>
</head>
<body>
  <h1>sample page</h1>
</body>
</html>

[root@massshoemaker:~]# curl https://localhost/ -H "AAA: BBB" -d "aaa=bbb" -k
<html>
<head>
  <title>hello</title>
</head>
<body>
  <h1>hello</h1>
</body>
</html>

4. Kibana表示確認

Kibanaで、稼働確認した際のリクエストを見てみます。

f:id:graneed:20180616033758p:plain

http.request項目を見ると、HTTPリクエスト全体が平文で表示されており、HTTPヘッダーもHTTPボディも表示できていることを確認できました。

次回は、KibanaでWOWHoneypotのダッシュボードを作ります。

graneed.hatenablog.com