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ステージは変更しなくてよさそうです。
- Inputsステージに、WOWHoneypot(HTTP/HTTPS両方)のログのファイルパスを追加する。
- Filterステージに、WOWHoneypotのログをパースして項目分割する定義を追加する。
- 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で、稼働確認した際のリクエストを見てみます。

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