#はじめに
先日(2019/06/11)、Sysmon v10がリリースされ、DNSクエリーのイベントログ採取機能がサポートされました!
標的型攻撃やサプライチェーン攻撃に対しては、ネットワーク機器やサーバ等で採取されたログ分析に加えて、攻撃を受けたまたはマルウェア感染したPCなどエンドポイント上におけるプロセス動作ログやユーザ操作ログを合わせて横断的に分析することが有効と言われています。
Sysmonではこれまでもプロセスによる通信(L3/L4)をログ採取する機能が提供されてきましたが、さらにこのDNSログ採取機能も悪意あるプロセス動作の検出や分析作業において有効活用が期待できます。
早速、Elasticsearch + Winlogbeatを使って動作を見てみたいと思います。
(本記事は情報量が多いため「設定編」と「動作確認編」の二回に分けて投稿します)
#作業内容
- Sysmon(v10.1)を設定
- Winlogbeatを設定
- DNSクエリーに対応したマッピングをElasticsearchへ設定
- DNSクエリーを解析しやすいように加工するパイプライン処理(Elasticsearc/ingestノード)を設定
※本記事で利用するWinlogbeatやSysmonの設定例はこちらへ仮置きしておきます。
###いくつかのツールやアプリを動かしてログの内容を確認
- ping.exe
- nslookup.exe
- powershell.exe
- dnscat2.exe
- Google Chrome(chorome.exe): 国際化ドメイン名 (IDN)
- Firefox(firefox.exe): DNS over HTTPS (DoH)
###DNSのいくつかのレコードタイプで試してみる
- A/AAAAレコード
- CNAMEレコード
- TXTレコード
- NXDOMAIN応答
これらの動作確認ではマルウェア検出に使えそうな情報がどのように採取できるかの観点から見てみたいと思います。
#評価環境
評価環境には以前にご紹介した以下のログ解析基盤の環境を利用します。この環境へDNSクエリー関連の設定を追加します。
- 「標的型攻撃に対するJPCERT/CCのおすすめログ設定をElasticsearchで構築してみる - エンドポイントログ編(その1- 概要/Sysmon)」
-
「標的型攻撃に対するJPCERT/CCのおすすめログ設定をElasticsearchで構築してみる - エンドポイントログ編(その2) - Winlogbeat/Elasticsearch」
#利用するソフトウェア
- OS: Ubuntu 18.04
- DNSサーバ: Dnsmasq (2.79)
- Elasticsearch (6.6.0)
- Kibana (6.6.0)
- Winlogbeat (6.6.0)
- Sysmon (v10.1)
- VMware Workstation Player等のVMソフトウェア
- Windows 10 (クライアントPC)
#PC(Windows 10)へSysmonをインストール
###設定ファイルを指定してインストール
今回は以下のイベントIDで識別されるログを全て採取する設定を行います。
ID | イベントタグ | 説明 | 有効化 |
---|---|---|---|
1 | ProcessCreate | プロセス起動 | デフォルトで有効 |
3 | NetworkConnect | ネットワーク接続 | コマンドオプション/設定ファイル |
22 | DNSイベント | プロセスによるDNSクエリー | 設定ファイル |
設定ファイルとして以下を利用します。
<Sysmon schemaversion="4.21">
<HashAlgorithms>md5,sha256</HashAlgorithms>
<EventFiltering>
<RuleGroup name="" groupRelation="or">
<ProcessCreate onmatch="exclude">
</ProcessCreate>
</RuleGroup>
<RuleGroup name="" groupRelation="or">
<NetworkConnect onmatch="exclude">
</NetworkConnect>
</RuleGroup>
<RuleGroup name="" groupRelation="or">
<ProcessTerminate onmatch="exclude">
</ProcessTerminate>
</RuleGroup>
<RuleGroup name="" groupRelation="or">
<DnsQuery onmatch="exclude">
</DnsQuery>
</RuleGroup>
</EventFiltering>
</Sysmon>
設定ファイルを指定してインストールを行います。
# Sysmonのインストール
Sysmon64.exe -i my_sysmon_config.xml
# 設定の確認
Sysmon64.exe -c
#Winlogbeatの設定
「標的型攻撃に対するJPCERT/CCのおすすめログ設定をElasticsearchで構築してみる -エンドポイントログ編(その2)- Winlogbeat/Elasticsearch」を参照ください。インストール方法や設定ファイル等は同じです。
#DNSログを確認
SysmonをインストールしたPC(Windows 10)からFQDNを指定してPingを打ってみます。
ping.exe www.youtube.com
youtube-ui.l.google.com [172.217.25.238]に ping を送信しています 32 バイトのデータ:
172.217.25.238 からの応答: バイト数 =32 時間 =27ms TTL=127
...
###コマンドラインから確認
Elasticsearchに対してコマンドからログを取得してみます(log.example.com[Ubuntu 18.04])。
curl -XGET http://log.example.com:9200/winlogbeat-6.6.0-2019.06.20/_search?pretty -H 'Content-Type: application/json' -d '
{
"query": {
"bool":{
"filter": [
{
"term": {
"log_name" : "Microsoft-Windows-Sysmon/Operational"
}
},
{
"term": {
"event_id" : 22
}
}
]
}
},
"size":10000
}
'
以下のイベントログ情報を取得できました。
{
"took" : 3,
"timed_out" : false,
"_shards" : {
"total" : 3,
"successful" : 3,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 136,
"max_score" : 0.0,
"hits" : [
...
{
"_index" : "winlogbeat-6.6.0-2019.06.20",
"_type" : "doc",
"_id" : "xxxxxxsBK78qCAAzxyug",
"_score" : 0.0,
"_source" : {
"@timestamp" : "2019-06-20T13:38:34.803Z",
"type" : "wineventlog",
"version" : 5,
"event_id" : 22,
"record_number" : "24656",
"opcode" : "情報",
"host" : {
"name" : "xxxxxxxxxxxx",
"id" : "22052e76-xxxx-4007-86f6-xxxxe89dxxxx",
"architecture" : "x86_64",
"os" : {
"build" : "17763.557",
"platform" : "windows",
"version" : "10.0",
"family" : "windows",
"name" : "Windows 10 Pro"
}
},
"log_name" : "Microsoft-Windows-Sysmon/Operational",
"task" : "Dns query (rule: DnsQuery)",
"computer_name" : "xxxxxxxxxxxx",
"beat" : {
"name" : "xxxxxxxxxxxx",
"hostname" : "xxxxxxxxxxxx",
"version" : "6.6.0"
},
"source_name" : "Microsoft-Windows-Sysmon",
"event_data" : {
"ProcessGuid" : "{22052e76-8c58-5d0b-0000-001018c26100}",
"ProcessId" : "3512",
"QueryName" : "www.youtube.com",
"QueryStatus" : "0",
"QueryResults" : "type: 5 youtube-ui.l.google.com;::ffff:172.217.31.174;::ffff:172.217.161.46;::ffff:216.58.197.206;::ffff:216.58.197.238;::ffff:172.217.24.142;::ffff:172.217.26.14;::ffff:216.58.197.174;::ffff:216.58.197.142;::ffff:172.217.31.142;::ffff:172.217.25.206;::ffff:172.217.161.78;::ffff:172.217.26.46;",
"Image" : "C:\\Windows\\System32\\PING.EXE",
"UtcTime" : "2019-06-20 13:38:32.815"
},
"process_id" : 2972,
"user" : {
"domain" : "NT AUTHORITY",
"type" : "User",
"identifier" : "S-1-5-18",
"name" : "SYSTEM"
},
"level" : "情報",
"message" : "Dns query:\nRuleName: \nUtcTime: 2019-06-20 13:38:32.815\nProcessGuid: {22052e76-8c58-5d0b-0000-001018c26100}\nProcessId: 3512\nQueryName: www.youtube.com\nQueryStatus: 0\nQueryResults: type: 5 youtube-ui.l.google.com;::ffff:172.217.31.174;::ffff:172.217.161.46;::ffff:216.58.197.206;::ffff:216.58.197.238;::ffff:172.217.24.142;::ffff:172.217.26.14;::ffff:216.58.197.174;::ffff:216.58.197.142;::ffff:172.217.31.142;::ffff:172.217.25.206;::ffff:172.217.161.78;::ffff:172.217.26.46;\nImage: C:\\Windows\\System32\\PING.EXE",
"provider_guid" : "{5770385f-c22a-43e0-bf4c-06f5698ffbd9}",
"thread_id" : 4320
}
},
...
クエリー結果を見てみると以下のフィールドが取得されています。
フィールド名 | 説明 |
---|---|
event_data.ProcessGuid | プロセスGUID。この値によりProcessCreateイベントやNetworkConnectイベントなど他のイベントログとの照合が可能になります |
event_data.ProcessId | プロセスID |
event_data.Image | プロセスイメージパス |
event_data.UtcTime | イベントのタイムスタンプ |
event_data.QueryName | DNSクエリ名 |
event_data.QueryStatus | DNSクエリステータス |
event_data.QueryResults | DNSクエリ結果 |
DNSクエリステータスはこちらの値。例えば「event_data.QueryStatus: 9003」ならば「DNS_ERROR_RCODE_NAME_ERROR(DNS name does not exist)」ですね。
DNSクエリ結果については以下のような点に気づきます。
- 複数の応答結果がマージされている(CNAME(type: 5)やAレコードもマージされている)
- 解決されたIPアドレス(Aレコード)にはtype: 1が付かない
- 解決されたIPアドレスはIPv4-Mapped IPv6 Addressで記録される場合がある
3.に関してはDNSプロトコルレベルではAレコード(IPv4)で応答されているので、(実際のところは不明ですが・・・)例えばプロセス(ツール/アプリ)の実装がIPv6ソケットで行われているためなどかもしれません。
ちょっとこのままでは見づらいですし、ツールで解析するにしても扱いづらいですね。また以下の点も気になります。
- @timestamp(Winlogbeatによりイベントログがインポートされた時刻)とイベントログのタイムスタンプ(event_data.UtcTime)が一致していない
- イベントログのタイムスタンプのフォーマットが@timestampで利用されるISO8601 形式でない
#DNSログ用のパイプライン設定をElasticsearchへ追加
DNSクエリー結果のフィールド値がこのままでは扱いづらいので、「エンドポイントログ編(その2) - Winlogbeat/Elasticsearch」の時と同様にDNSクエリーログのフィールドについても加工を行うパイプライン設定を行います。
フィールド | 利用するプロセッサ | 処理内容 |
---|---|---|
event_data.UtcTime | Date | このフィールド値をパースして@timestampを上書きします |
event_data.UtcTime | Date | それぞれのタイムスタンプをISO8601形式へ変換します |
event_data.QueryResults | split foreach gsub |
応答のレコードタイプ毎に分割。またIPv4-Mapped IPv6 Addressの場合にはIPv4アドレスへ置き換えます |
event_data.QueryStatus | Convert | ステータスコード値が文字列型のためlong型へ変換します |
message | Remove | event_dataに設定されている情報と重複しているので削除します |
パイプライン処理を以下のようにpipeline.jsonファイルとして定義します。
{
"description": "Winlogbeat-v6.6.0 pipiline for Sysmon-v10.1.",
"processors": [
{
"date": {
"field": "event_data.UtcTime",
"formats": [
"yyyy-MM-dd HH:mm:ss.SSS"
],
"if": "ctx.source_name == \"Microsoft-Windows-Sysmon\"",
"ignore_failure": true
}
},
...
{
"split": {
"field": "event_data.QueryResults",
"separator": ";",
"if": "ctx.source_name == \"Microsoft-Windows-Sysmon\" && ctx.event_id == 22",
"ignore_missing": true,
"ignore_failure": true
}
},
{
"foreach" : {
"field" : "event_data.QueryResults",
"processor" : {
"gsub": {
"field": "_ingest._value",
"pattern": ": ",
"replacement": ":",
"ignore_missing": true,
"ignore_failure": true
}
},
"if": "ctx.source_name == \"Microsoft-Windows-Sysmon\" && ctx.event_id == 22",
"ignore_failure": true
}
},
{
"foreach" : {
"field" : "event_data.QueryResults",
"processor" : {
"gsub": {
"field": "_ingest._value",
"pattern": "\\:\\:ffff\\:",
"replacement": "",
"ignore_missing": true,
"ignore_failure": true
}
},
"if": "ctx.source_name == \"Microsoft-Windows-Sysmon\" && ctx.event_id == 22",
"ignore_failure": true
}
},
{
"date": {
"field": "event_data.UtcTime",
"target_field": "event_data.UtcTime",
"formats": [
"yyyy-MM-dd HH:mm:ss.SSS"
],
"if": "ctx.source_name == \"Microsoft-Windows-Sysmon\"",
"ignore_failure": true
}
},
...
{
"convert": {
"field": "event_data.QueryStatus",
"type": "long",
"if": "ctx.source_name == \"Microsoft-Windows-Sysmon\" && ctx.event_id == 22",
"ignore_missing": true,
"ignore_failure": true
}
},
{
"remove": {
"field": "message",
"if": "ctx.source_name == \"Microsoft-Windows-Sysmon\"",
"ignore_missing": true,
"ignore_failure": true
}
}
]
}
上記の作成済みのパイプライン処理を定義したJSONファイルはこちらに置いておきました。
このパイプライン設定をmy-sysmon-10.1-winlogbeat-6.6.0という名前でElasticsearch/ingestノードへ登録します。
$ curl -XPUT http://log.example.com:9200/_ingest/pipeline/my-sysmon-10.1-winlogbeat-6.6.0 -H 'Content-Type: application/json' -d @pipeline.json
#DNSログ用のマッピング(テンプレート)をElasticsearchへ追加
「標的型攻撃に対するJPCERT/CCのおすすめログ設定をElasticsearchで構築してみる - エンドポイントログ編(その2)- Winlogbeat/Elasticsearch」と同様に、DNSクエリーイベントログのフィールドには完全一致ではなく、大文字と小文字を区別せずに検索したり、部分一致またはあいまい検索ができるように変更します。
そこで以下のフィールドについてはkeyword型以外でマッピングを作成しElasticsearchへ設定します。
Field | 変更後 | デフォルト |
---|---|---|
event_data.QueryName | text | keyword |
event_data.QueryResults | text | keyword |
event_data.QueryStatus | long | keyword |
event_data.Image | text | keyword |
event_data.UtcTime | date | keyword |
以下の手順でElasticsearchへSysmon用のテンプレート(マッピング)を設定します。
(1) デフォルトのWinlogbeatテンプレートをElasticsearchから取得
$ curl -XGET http://log.example.com:9200/_template/winlogbeat-6.6.0?pretty > template.json
(2) 取得したテンプレートをベースに前述のSysmon用フィールドのデータ型を反映したマッピングを追加定義
{
"index_patterns": [
"winlogbeat-6.6.0-*"
],
...
"mappings": {
"doc": {
"_meta": {
"version": "6.6.0"
},
"date_detection": false,
"dynamic_templates": [
{
"event_data": {
"mapping": {
"type": "keyword"
},
"match_mapping_type": "string",
"path_match": "event_data.*"
}
},
...
],
"properties": {
...
"event_data": {
"type": "object",
"properties": {
"UtcTime": {
"type": "date"
},
...
"Image": {
"type": "text",
"norms": false
},
...
"QueryName": {
"type": "text",
"norms": false
},
"QueryResults": {
"type": "text",
"norms": false
},
"QueryStatus": {
"type": "long"
},
"OriginalFileName": {
"type": "text",
"norms": false
}
}
},
...
}
**event_data.***のフィールドに対してdatatypeを指定しています。
上記の作成済みのテンプレートを定義したJSONファイルはこちらに置いておきました。
(3) Elasticsearchへ更新したテンプレートを再設定する
$ curl -XPUT http://log.example.com:9200/_template/winlogbeat-6.6.0 -H 'Content-Type: application/json' -d @template.json
マッピングを再生成するためにインデクスを削除します。
$ curl -XDELETE http://log.example.com:9200/winlogbeat-6.6.0-2015.06.20
#Winlogbeatの転送先パイプラインを設定
Windows 10 PC上でWinlogbeatインストールディレクトリ配下の設定ファイル(例: C:\Program Files\winlogbeat-6.6.0-windows-x86_64\winlogbeat.yml)へ以下の通り転送先パイプライン名(my-sysmon-10.1-winlogbeat-6.6.0)設定を追加します。
winlogbeat.event_logs:
- name: "Microsoft-Windows-Sysmon/Operational"
output.elasticsearch:
hosts: ["log.example.com:9200"]
#ログ転送先のパイプライン名を設定
pipeline: "my-sysmon-10.1-winlogbeat-6.6.0"
設定を確認してWinlogbeatサービスを再起動します。
#Winlogbeatサービスを停止
PS C:\Program Files\winlogbeat-6.6.0-windows-x86_64> Stop-Service winlogbeat
#設定をテスト
PS C:\Program Files\winlogbeat-6.6.0-windows-x86_64> .\winlogbeat.exe test output -e -d "*"
#Winlogbeatサービスを再起動
PS C:\Program Files\winlogbeat-6.6.0-windows-x86_64> Start-Service winlogbeat
#DNSログを再確認
このようなパイプラインおよびマッピングを定義した場合には以下のようなイベントログ結果を取得できます。
curl -XGET http://log.example.com:9200/winlogbeat-6.6.0-2019.06.20/_search?pretty -H 'Content-Type: application/json' -d '
{
"query": {
"bool":{
"filter": [
{
"term": {
"log_name" : "Microsoft-Windows-Sysmon/Operational"
}
},
{
"term": {
"event_id" : 22
}
}
]
}
},
"size":10000
}
'
{
"took" : 3,
"timed_out" : false,
"_shards" : {
"total" : 3,
"successful" : 3,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 136,
"max_score" : 0.0,
"hits" : [
...
{
"_index" : "winlogbeat-6.6.0-2019.06.20",
"_type" : "doc",
"_id" : "p8tWdxxBK78qCAxxxxxd",
"_score" : 0.0,
"_source" : {
"computer_name" : "xxxxxxxxxxxx",
"process_id" : 2972,
"log_name" : "Microsoft-Windows-Sysmon/Operational",
"level" : "情報",
"record_number" : "24659",
"event_data" : {
"ProcessId" : "2744",
"Image" : "C:\\Windows\\System32\\PING.EXE",
"QueryStatus" : 0,
"ProcessGuid" : "{22052e76-8c5c-5d0b-0000-0010d9c66100}",
"QueryResults" : [
"type:5 youtube-ui.l.google.com",
"172.217.31.174",
"172.217.161.46",
"216.58.197.206",
"216.58.197.238",
"172.217.24.142",
"172.217.26.14",
"216.58.197.174",
"216.58.197.142",
"172.217.31.142",
"172.217.25.206",
"172.217.161.78",
"172.217.26.46"
],
"UtcTime" : "2019-06-20T13:38:36.570Z",
"QueryName" : "www.youtube.com"
},
"type" : "wineventlog",
"opcode" : "情報",
"version" : 5,
"thread_id" : 4320,
"@timestamp" : "2019-06-20T13:38:36.570Z",
"event_id" : 22,
"task" : "Dns query (rule: DnsQuery)",
"provider_guid" : "{5770385f-c22a-43e0-bf4c-06f5698ffbd9}",
"beat" : {
"hostname" : "xxxxxxxxxxxx",
"name" : "xxxxxxxxxxxx",
"version" : "6.6.0"
},
"host" : {
"os" : {
"build" : "17763.557",
"name" : "Windows 10 Pro",
"family" : "windows",
"version" : "10.0",
"platform" : "windows"
},
"name" : "xxxxxxxxxxxx",
"id" : "22052e76-721a-4007-86f6-6346e89d0c86",
"architecture" : "x86_64"
},
"user" : {
"identifier" : "S-1-5-18",
"domain" : "NT AUTHORITY",
"name" : "SYSTEM",
"type" : "User"
},
"source_name" : "Microsoft-Windows-Sysmon"
}
},
event_data.QueryResultsフィールドの値がだいぶ見やすくなりました。
#まとめ
Sysmon v10にて新たにサポートされたDNSクエリーログを採取するためのElasticsearch環境の設定を行ってみました。
次回はこの設定した環境でいくつかのツールやアプリを実際に動かし、採取されるログ内容について見ていきたいと思います。
「動作確認編」へ続く