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のダッシュボードを作ります。