VirusTotal Intelligence による検索では文字列による検索以外にバイナリコードを検索することができます。公式のガイド「VirusTotal for Investigators」ではこれを VTGrep (別名:Content Search) と呼んでいるようです。今回はこの VTGrep について掘り下げていきたいと思います。
参考になる資料
- VirusTotal for Investigators
https://storage.googleapis.com/vt-gtm-wp-media/virustotal-for-investigators.pdf
※ VTI を使っていくうえで学ぶべきことがまとまっています。
今回も基本的にここを参考にしています。 - 公式ドキュメント | VirusTotal > Documentation > Content search (VTGrep)
https://support.virustotal.com/hc/en-us/articles/360001386897-VT-Intelligence-content-search-VTGrep-
※ 公式のドキュメントから VTGrep の部分です。オフセット位置やワイルドカード(??)についても触れられているので知識を深めたい場合は確認するとよいと思います。
VTGrep とは
VTGrep はファイル内のバイナリコードを検索することができる、Retro Hunt や Live Hunt (それぞれバイナリコードを yara で検索/検知する VirusTotal Intelligence のテクニック) に近い機能です。メタデータによる検索ではメタデータ化された文字列しか検索候補になりえませんが、VTGrep を使用するとメタデータ化の有無に関わらずバイナリから文字列データやバイナリパターンを検索します。各 Hunt を作成する前にプロトタイプとして VTGrep で検索してみることも有用でしょう。
(検索結果右の◎をポイントすると一致した個所を表示してくれます。)
強力なところとしては圧縮ファイル内のバイナリパターンも検索可能でマクロや VBA コードも検索可能となっています。
現時点の弱点としては、他の modifier と一緒に使うことができないので、見つかったファイルの中から positives 10 以上とか、peexe だけ、ということがしにくいです(vt-cli を使って自分でパースすれば不可能ではないです)。また、仕様として 60 秒以内に検索出来たものを返す、ということになっているので、タイムアウトが発生した場合はそういう理由だと思います。
VTGrep による検索方法
VTGrep を使った検索には content modifier を使います。バイナリコードの場合は {} で囲みます。文字列をそのまま指定する場合は "" ダブルクォートで囲みます。
- 例1 content:{e697a5e69cac} // 日本
- 例2 content:{e6 97 a5 e6 9c ac} // 日本
- 例3 content:"日本" // UTF-8
上記の例ではそれぞれ「日本」という文字列を含むバイナリパターンを検索しています。
例1と例2はバイトパターンをスペースで区切って見やすくしているかどうかで、どちらでも同じ結果を返します。"" (ダブルクォート) で囲んだ例3の形式で検索した場合、UTF-8 に変換されて検索されるようです。
OR 条件なども使えるので、以下の様に検索することもできます。
- 例1 content:{e697a5e69cac} OR content:{4a6170616e} // 日本 OR Japan
- 例2 content:{e6 97 a5 e6 9c ac} OR content:{4a 61 70 61 6e} // 日本 OR Japan
- 例3 content:"日本" OR content:"Japan" // UTF-8
日本語を含むファイルの VTGrep
日本語などのマルチバイト文字を検索する場合、文字コードやエンディアンによってバイナリコードが変わります。同じ「日本」という文字列でも、
- UTF-8 : e6 97 a5 e6 9c ac
- UTF-16BE (Unicode) : 65 e5 67 2c
- UTF-16LE : e5 65 2c 67
- Shift-JIS : 93 fa 96 7b
…
※ BE = Big Endian, LE = Little Endian
と、バイナリパターンは多岐にわたります。
そこで、各文字コードで VTGrep を行った場合にどのファイルタイプが見つかるのかを確認してみました。
確認しやすさの都合上、文字コード/エンディアンは UTF-8, UTF-16BE, UTF-16LE、ファイルタイプはざっと見てみて確認ができたもののみ、としています。太字にしたファイルタイプは観測した範囲では頻出のものです。特定のファイルタイプに含まれる文字列を検索したい場合に参考にしてください。
また、検索に使用するバイナリパターンを生成するには、CyberChef を使用すると楽でした。URL を併記したのでこちらも検索する際に参考にしてください。
※ URL に含まれる文字と Markdown の相性が悪くうまくリンクにならないので URL をコピペして利用ください。
UTF-8
ファイルタイプ:xml, html, pdf, peexe, android, msi
https://gchq.github.io/CyberChef/#recipe=To_Hex('None')
UTF-16BE (Unicode)
ファイルタイプ:pdf, android, peexe, zip
https://gchq.github.io/CyberChef/#recipe=To_Charcode('Space',16)Find_/_Replace(%7B'option':'Regex','string':'%20'%7D,'',true,false,true,false)
UTF-16LE
ファイルタイプ:xls, doc, peexe, pedll, msi
https://gchq.github.io/CyberChef/#recipe=To_Charcode('Space',16)Find_/_Replace(%7B'option':'Regex','string':'%20'%7D,'',true,false,true,false)Swap_endianness('Hex',2,true)Find_/_Replace(%7B'option':'Regex','string':''%7D,'',true,false,true,false)
Base64 ⇒ UTF-16BE (Unicode)
※ 文字列を Base64 で変換した後、UTF-16BE でさらに変換しています。
ファイルタイプ:email (text), outlook (eml), html, jar, android
https://gchq.github.io/CyberChef/#recipe=To_Base64('A-Za-z0-9%2B/%3D')To_Charcode('Space',16)Find_/_Replace(%7B'option':'Regex','string':''%7D,'',true,false,true,false)
デコードする場合
見つけたバイナリパターンのデコードは以下の通りです。
UTF-8
https://gchq.github.io/CyberChef/#recipe=From_Hex('Auto')
UTF-16BE (Unicode)
https://gchq.github.io/CyberChef/#recipe=Find_/_Replace(%7B'option':'Regex','string':'%20'%7D,'',true,false,true,false)Regular_expression('User%20defined','%5B0-9a-f%5D%7B4%7D',true,true,false,false,false,false,'List%20matches')Find_/_Replace(%7B'option':'Regex','string':'%5C%5Cn'%7D,'%20',true,false,true,false)From_Charcode('Space',16)
UTF-16LE
https://gchq.github.io/CyberChef/#recipe=Swap_endianness('Hex',2,true)Find_/_Replace(%7B'option':'Regex','string':'%20'%7D,'',true,false,true,false)Regular_expression('User%20defined','%5B0-9a-f%5D%7B4%7D',true,true,false,false,false,false,'List%20matches')Find_/_Replace(%7B'option':'Regex','string':'%5C%5Cn'%7D,'%20',true,false,true,false)From_Charcode('Space',16)
UTF-16BE (Unicode) ⇒ Base64
https://gchq.github.io/CyberChef/#recipe=To_Hex('None')To_Base64('A-Za-z0-9%2B/%3D')