じゅのぶろ

社内SEが自宅でSOC/CSIRTするために色々頑張っていきたいブログ 画像が見れない場合はjavascriptを有効にするかデスクトップからご覧下さい。

Splunkでログを調べる(正規表現編)

Splunkで正規表現を使って検索する方法をご紹介します。 大体以下のコマンドを使うことになると思います。

  1. regexコマンド
    フィルタのみ行いたい場合
  2. rexコマンド
    マッチした値をフィールド値として保持したい場合
  3. erexコマンド
    正規表現がわからない場合

regexコマンド

正規表現にマッチしたサーチ結果のみを返すコマンドです。
正規表現にマッチしたかどうかを知りたいだけならこのコマンドが良いでしょう。
公式のSyntaxはこのとおりです。

regex (<field>=<regex-expression> | <field>!=<regex-expression> | <regex-expression>)

オプション

fieldを指定しない場合は「_raw」フィールドが検索対象になります。
検索パフォーマンスが低下するのでできるだけ指定した方が良いです。

  • dest_ipフィールドが52.0.0.0/8のレンジにあるかを調べる場合。
index=squid sourcetype=mysquid 
| regex dest_ip="^52\.\d+\.\d+\.\d+$"

※CIDRを調べる場合はwhereを使った方が良いですが。

index=squid sourcetype=mysquid 
| where cidrmatch("52.0.0.0/8", dest_ip)

rexコマンド

正規表現の名前付きグループ(名前付きキャプチャ)にマッチした結果をフィールドにするためのコマンドです。
名前付きキャプチャとは(?<名前>正規表現)というように書きます。
※または(?'名前'正規表現)(?P<名前>正規表現)など複数あるのでお好きなキャプチャをお使いください。

公式のSyntaxはこのとおりです。

rex [field=<field>] ( <regex-expression> [max_match=<int>] [offset_field=<string>] ) | (mode=sed <sed-expression>)

※mode=sedを指定すると、シェルのsedコマンドのように使うこともできます。

オプション

fieldを指定しない場合は「_raw」フィールドが検索対象になります。
検索パフォーマンスが低下するのでできるだけ指定した方が良いです。

max_matchはデフォルトで1なため、1つのイベントで1回しかマッチしません。
指定すれば指定した数字分イベントを検索してくれます。

offset_fieldを指定すると、イベントの初めから何文字目がマッチしたかを返します。
詳しくは以下の例を御覧ください。

  • dest_ipフィールドが52.0.0.0/8のレンジにあるかを調べる場合。
    regexと異なり一度フィールドに値を入れ、フィールド値の有無を調べることでフィルタします。
index=squid sourcetype=mysquid 
| rex field=dest_ip "^(?<regex_match>52\.\d+\.\d+\.\d+)$"
| search regex_match=*
  • _rawから10文字ずつ3回、マルチバリューとしてフィールド抽出する
index=squid sourcetype=mysquid 
| head 1
|  rex mode=sed field=_raw "s/(^.{40}).*/\1 ... 省略/g" 
|  rex field=_raw max_match=3 offset_field=offset "(?<test>.{10})." 
| table test* offset _raw

sedモードのrexで_rawを40文字+「...省略」にしています。
offsetフィールドは「test=0-9&test=11-20&test=22-31」となっています。
&がセパレータになっており、1つ目の正規表現は0~9文字目がマッチしているとわかります。

erexコマンド

erexコマンドは正規表現がわからない人でも、機械学習?により正規表現を使えるようにするコマンドです。
いくつかのマッチパターンを引数で渡し、Splunkがそれに合った正規表現で検索してくれます。
(このコマンドを覚えるなら正規表現を覚えたほうが早い気がしますが..)
公式のSyntaxはこのとおりです。

erex [<field>] examples=<string> [counterexamples=<string>] [fromfield=<field>] [maxtrainers=<int>]

オプション

examplesに正規表現で抽出したい値を入力します。

counterexamplesに正規表現で抽出したくない例外値を入力します。

index=squid sourcetype=mysquid 
| erex erex_mathch examples="2019/07/23"
| fillnull value="" erex_mathch
| stats count by erex_mathch

yyyy/mm/ddで日付が抽出できていることがわかります。

ジョブをクリックすると使用された正規表現がわかります。
今回は(?i)^\"(?P<erex_mathch>[^ ]+)が使われたようです。
もう少しサンプル数を増やすと面白いかもしれません。

Successfully learned regex. Consider using: | rex "(?i)^\"(?P<erex_mathch>[^ ]+)"`