静的分析によるPowerShellスクリプトの実用的振る舞いプロファイリング (1)

By

Category: Malware, Unit 42

Tags: ,

This post is also available in: English (英語)

概要

3部構成となる本シリーズでは、PowerShellスクリプトの静的分析に対する実用的アプローチと、この静的分析実行のためのプラットフォームに依存しないPythonスクリプトの開発に焦点を当てる予定です。また本シリーズでは、振る舞いプロファイリングの詳細、PowerShellスクリプトでよく見られる難読化方法、データ隠蔽方法、スクリプトのリスク評価のためのスコアリングシステム構築方法についても説明していく予定です。本シリーズの目的は、セキュリティ アナリストや組織のサイバーセキュリティ担当者が、実用的なスクリプティングの基礎と概念を身につけられるようにすることにあります。

はじめに

いきなり詳細に入る前に、「本稿のそもそもの目的や達成したい目標とは何か?」という問いと「静的分析アプローチが現実にどの程度役に立つのか?」という問い、そして「組織のセキュリティエコシステム全体で見て、静的分析アプローチは、その活用方法をしっかり身につけ使いこなすという意味で、どのような貢献をしてくれるものなのか?」という3つの問いに答えておきたいと思います。これらについて説明しようと思うと、取り上げるべき情報がかなり多くなってしまいますので、シリーズ化することですべての問いに応えられるようしました。そこでまずはここで、先の3つの問いについて簡単に説明をしておきます。

最初の問いである「何を達成したいのか?」についての答えはシンプルです。私は多くのPowerShellスクリプトをレビューしていますが、リスク評価や分析を待つファイルは常に何千個も存在しています。それらの分析・評価をいちいち手で実行していたのでは時間がかかりすぎますし、経験からいって、さまざまな理由で動的解析は精確な結果を出すのに失敗することが多いのです。スクリプトの分析・評価は、まさにコメディドラマ『シリコン・バレー』に登場したあの「ある料理がホットドッグかそうでないかを見分ける判別器」のようなものなので、このとにかく面倒なタスクを可能な限り自動化する方法を見つけたかった、というのがその答えです。

図1 人気コメディドラマ『シリコン・バレー』でホットドッグを判別するシーン
図1 人気コメディドラマ『シリコン・バレー』でホットドッグを判別するシーン

2つめの「静的分析アプローチは現実にどの程度役に立つのか」については、答えがもう少し複雑です。静的分析と動的分析には、それぞれに一長一短があります。どちらかがより優れていると主張するかたもおられるでしょうが、私自身はどちらも同じくらい重要だし、相補的なものだと考えています。ですが、PowerShellスクリプトの分析を始めてすぐにわかったことがひとつあります。それは、通常の動的分析レポートと比べ、コンテキストのない静的な振る舞い分析はほぼ無意味だということです。つまり、悪意のないスクリプトと悪意のあるスクリプトとが同じ振る舞いや機能を見せるのはよくあることなので、なにかそこに補足してくれるコンテキストやメタデータがないかぎり、表層からその意図を汲み取るのは難しいのです。

最後は「PowerShellスクリプトの振る舞いをプロファイリングするツールは、組織のセキュリティエコシステム全体で見て一体何に貢献してくれるのか」という問いについてです。あらゆる組織にはそれぞれにニーズやリソース状況が異なるので、この問いに答えるのは少々やっかいなのですが、私自身は、静的分析アプローチを単にPowerShellにこめられた謎を解くものだとは考えていません。静的分析アプローチは、既存の機能を強化し、大規模な分析を支援してくれる方法のひとつであり、結果として防御の構築により多くの時間を確保してくれる存在である、と考えています。

ということで、さっそく静的解析で中心となる概念や、静的解析アプローチの長所・短所について見ていくことにしましょう。

PowerShellにおける「振る舞い」の定義

さて、設計や概念について説明する前に、この文脈で言う「振る舞い」とは何かを定義し、PowerShellというスクリプト言語についても少々ふれておかねばなりません。PowerShellに慣れていない方のために説明すると、PowerShellというのは「cmdlet(コマンドレット)」と呼ばれる関数に「動詞-名詞」という形式の命名規則が使われているMicrosoftのスクリプト言語です。ただしPowerShellは、ネイティブのWindowsコマンドラインのほか、 .NETコードも解釈・実行してくれます。たとえば、以下の3行のPowerShellスクリプトは、それぞれに異なる呼び出しメソッドを使っていますが、すべて同じ出力結果となります。

こうした柔軟性のせいでめざすプロファイリングはより困難なものになります。なぜなら、同じ内容でも複数の表現方法があるという点を考慮しなければならないからです。

なお、ここで言う「振る舞い」とは「ある特定の機能を果たす構成全体」を指しています。つまり、かならずしもある一つのコマンドや、コマンドの種類一つだけを指してはいません。たとえば"Get-Date"というコマンドレットは、自身が実行されているホストシステムの関連データを取得することから「列挙」という振る舞いに分類されうりますし、.NETの"New-Object System.Net.WebClient.DownloadFile"も、ファイルをリモートから取得するために使用されることから「ダウンローダ」の振る舞いに分類するひとがいるかもしれません。

後半のツール設計セクションでこの「振る舞い」については詳細に説明しますが、先に進む前にこの「振る舞い」についての概要は掴んでおいてほしいと思います。

動的分析 対 静的分析

さて、私たちが特定したいのは「振る舞い」なわけですが、あるスクリプトが悪性か良性を判断するのに、「振る舞い」だけでは十分でないことがあります。むしろ決定要因として機能するのは「それらの振る舞いがどのような意図のもとに発生したのか」でしょう。では、この「意図」はどうすれば推測できるのでしょうか。これを示すため、次の2つのサンプルを見てください。視覚的にも似たこれらサンプルは、「ダウンローダ」、「スリープ」、「列挙」、「ワンライナー」という同じ「振る舞い」を含んでいます。

図2 悪意のないPowerShellスクリプト
図2 悪意のないPowerShellスクリプト
図3 悪意のあるPowerShellスクリプト
図3 悪意のあるPowerShellスクリプト

この「意図を推測する方法」についての質問に答えるには、一歩下がって少々歴史を振り返る必要があります。

動的マルウェア分析が軌道に乗るよりはるか昔、悪意の有無を判定するのに使われた主な方法は、ファイルを静的にレビューすることでした。静的レビューは、当時の防衛戦略の中核となっていたもので、サンプル固有の特性を識別する方法を提供してくれていました。ところが、やがて月日が流れ、動的分析が注目を集め始めるようになると、業界は静的な属性のかわりに悪意のあるファイルが示す動的な特性を中心としたツール環境や製品、防衛対応戦略に傾倒しはじめます。動的分析は、膨大な情報を与えてくれました。しかも使用するリソース、必要な技術スキル、分析に費やされる時間は、大幅に削減されたのです。振る舞い分析はあらゆる点で何倍も費用対効果に優れた方法だったため、やがて分析の主役の座を占めるようになりました。

そして、これらの振る舞いが現代的環境におけるマルウェア対応のアプローチをかたちづくり、時間の経過とともに、悪意のあるファイルが示す一般的な特性も特定されてきました。こうした特性は、「良いソフトウェア」と「悪いソフトウェア」を区別するのに役立ち、これを活用することでインフラの保護にも成功しました。ところが、動的分析が生成する特性と、静的ファイルとそれら特性との相関という観点で言えば、これらが常にきれいに一対一で対応するとは限らないのです。

たとえば、「別のスクリプトをダウンロードして実行し、システム情報を列挙し、圧縮やBase64を多用するPowerShellスクリプト」があるとしましょう。これで最初に思い浮かぶのは、これが悪意のあるスクリプトだ、ということではないでしょうか。というのもこの振る舞いは、動的マルウェア分析で、誰もが関連付けするのに慣れている振る舞いだからです。ところがこの事例についていえば、そのスクリプトは単に、リック・アストリーのアスキー アート アニメーション(「リックロール」と呼ばれる釣り動画)を表示するだけのPowerShellスクリプトでした。こうして私たちは、「リック・アストリーに抱く感情次第では悪意を疑えなくもない、さりとて技術的には悪意があるものではない」というにっちもさっちもいかない状況に置かれることになるのです。

図4 リー・ホームズによる「リックロール」PowerShellスクリプト(リー・ホームズはオライリー社の『Windows PowerShell Cookbook』の著者)

単に振る舞いを静的にプロファイリングするだけでは、コードの使われ方からその良し悪しを判断できるないケースがある、ということです。だからこそ、意図が非常に重要になります。あらゆることを考慮してても、意図こそが分析の主たる要素なわけで、私はこれを本シリーズのいたるところで強調していくつもりです。

ところで、本ブログのための演習問題をつくっているとき、私は、一般的な組織は、私が慣れ親しんでいるものとはまったく異なる方法でPowerShellを活用している、ということに気付きました。とっつきやすくて間口が広いスクリプト言語は非常に人気があります。学ぶのも書くのも従来のプログラミング言語にくらべて簡単だし、フレームワークは手軽に拡張できるし、配布もたやすいし、クロスプラットフォームで動作させるのも容易です。

要するに、PowerShellスクリプトはいまや多くの組織にとって欠かせない歯車となっているわけで、通常のソフトウェアでは考えられないような使われかたをしているのです。ですから、そうしたスクリプトを実行ファイルと対比させて振る舞い分析をするのであれば、問題も違う角度から捉える必要があるのです。

意図を決定する

さて、意図を決定するにあたって私は、「ツール変更が既知の判定のスコアリングにどのような影響を与えるか」を確認するための"グランドトゥルース(正しい答え)"を確立する必要がある、と考えました。これを実現するため、実環境で見つかった数千の良性と悪性のPowerShellスクリプトを手入力し、それぞれに個別に「良性」、「悪性」のラベルを付けました。つまり『シリコン・バレー』の「ホットドッグ」「ホットドッグではない」のラベル付けと同じあれです。

この処理をしたおかげで、ツール変更がスコアリングに及ぼす変化を監視できましたし、新しい振る舞い、新しい難読化手法、新しいデータ隠蔽方法の特定もできました。また、既知の悪意のあるスクリプトが自分が設定した検出しきい値を下回ることがあれば、そのサンプルがしきい値を上回るよう集中的に取り組むことによって、残りのサンプルについての全体的な精度も高めることができました。

こうして手で分類したことで、私は考えつくかぎりのあらゆる種類のスクリプトに触れることができました。様々な管理スクリプトやブートストラップ スクリプトがありましたが、「会議から抜けたいときにメールで使える言い訳生成スクリプト」だとか、個人的なお気に入りのものには「今いる場所に基づいてランチを食べる店をランダムにひとつ選びメニューをアスキー表示するスクリプト」などというものもありました。文字通り、考えつくかぎりありとあらゆる種類のスクリプトがありました。

サンプル セットの分類を済ませた後は、意図の問題についてより深く考えられるようになりましたし、振る舞いだけでは意図を決定できない場合に、スクリプトを本当に弁別しうるものが何かについて理解できるようになりました。そこで、これらスクリプトを眺めて振る舞いのプロファイリング作業を始めたとき、私は「スクリプトの全体的な意図に占める役割という観点から振る舞いのもつ重みを考えると、それはどの程度のものなのだろうか」と考えました。

たとえば、「実行可能ファイルをダウンロードして実行するだけのスクリプト」と「プロセスをダウンロードして実行して難読化して全体を1行にまとめたスクリプト」とを比較した場合、前者がログを生成するか、適切に構造化されたコードであれば、悪意のあるスクリプトである可能性は低くなります。同様に、ある振る舞いが特定されたら、その振る舞いが良悪両スクリプト全体にどの程度分布しているのかを確認し、どちらかのスクリプトについてその振る舞いがどの程度「希少」であるかを観測し、それに応じてスコアの重みづけを調整することができます。

置かれたコンテキストにとって重要な振る舞いを特定し、それらを適切にスコアリングする方法を見つけることが、このプロファイリングの肝といえます。こうして振る舞いを作成して対応スコアを適用したら、次はリスク階調スケールを作成してそのスケールにすべてのサンプルをマッピングし、そこから「スイートスポット」を見つけてさらにきめ細かく調整していきます。次のチャートは、PowerShellスクリプトで静的にリスクをスコアリングするガイドラインとして私が使用した階調スケールです。

図5 リスクを決定するための階調スケール
図5 リスクを決定するための階調スケール

ここでは、しきい値である6.0付近に悪意のあるスクリプトをスコアリングすることを目指しました。このチャートは本シリーズを通じて参照することになります。なお、このチャートは、スコアが高ければ高いほど、確度も高くなります。このしきい値を下回ればリスクは減少しますが、これはかならずしもそのスクリプトに悪意がないことを保証するものではありません。ただし、あるスクリプトがしきい値を下回ったかどうかを知れば、そこからどういう点に注力して新たな振る舞いやコンテキストのヒントを特定・プロファイリングするリサーチや分析を進めていけばいいのかについての方向性を与えてくれます。

考慮すべきこと

それではいよいよ、PowerShellスクリプトを静的にプロファイリングするツールの設計構築方法についての議論に移りたいと思いますが、ここでいくつか心にとめておいてほしいことがあります。

まず、確実にオオカミを殺せる銀の弾丸のような特効薬は存在しないということ。なかなかに受け入れがたいことですが、このツールについても同じことが言えます。PowerShellは驚くほど柔軟な言語で、スクリプト作成者には、同じ機能をなんの制約もなく呼び出すための、さまざまな方法が与えられているのです。もちろんこれは、スクリプトの画一性を失わせ、ばらつきを生じさせる大きな原因となり、悪意のあるスクリプトのすべてを静的に捕捉することはできない、ということを意味します。スクリプト作成者が検出回避を狙った場合はとくにそうだと言えます。

そのため、特定しようとしている振る舞い指標の一部は見逃すケースがある、ということは念頭に置く必要があります。そうしたケースでは、慎重を期して偽陰性側に寄せました。振る舞いの一部を過大評価して潜在的に良性のスクリプトに高いスコアを与えてしまうよりは、悪意のあるスクリプトにしきい値未満のスコアを与える方を選んだわけです。これにくわえ、「意図」という観点で見た「悪意のあるコード」と、「記述された形式」という観点で見た「悪意のあるコード」を対比して分析してみる必要もあります。何かが意図的に難読化されているのか、書き方が悪いだけなのか、あるいはその両方なのか(実際よくある)を判断するのは簡単なことではありません。

このほかに分析中私が観測したのは、「悪意のないスクリプトはスタンドアロンであることが多い」ということです。悪意のないスクリプトは完全に自己完結型で、パラメーターや依存関係なく実行できるのです。それに対し悪意のあるスクリプトはたいてい、より大きなパズルの小さなピースとして存在します。パズルのピースが小さくなれば、それだけプロファイルに使える潜在的な振る舞いやコンテキストも限られることになります。

図6 追加コンテンツを取得するだけのCradleスクリプトをダウンロード
図6 追加コンテンツを取得するだけのCradleスクリプトをダウンロード

ただこれに関して言えば、振る舞いを構成するコードの長さに「絶対ない」はありえませんし、既知の判定結果を持つサンプル セットがあれば、潜在的な振る舞いがスコアリングに与える影響の理論についてはテストできます。さらに、機能に基づく振る舞い判定だけではうまくいかないケースでも、コンテキストによるキーワード(たとえば"Invoke-DLLInjection")やメタデータ(文字頻度分析など)を独自の振る舞いとして使用することで、スコアリングに影響を与えることができます。

これにくわえて暗黙の振る舞いについても考慮する必要があります。前述のとおり、PowerShellは驚くほど柔軟な言語で、コード難読化や振る舞い隠蔽に使える数千ものメソッドを備えています。以前書いたブログで私は、"EncodedCommand"パラメータだけでも10万を超えるバリエーションがあることを示したことがあります。たとえば、スクリプトのコンテンツに悪意のあるURLを明確に確認できるのにもかかわらず、そのURLからペイロードをダウンロードする方法を識別できなかったとしたら、私は「このスクリプトにはまだ知られていないダウンロードの振る舞いがあるのではないか」と推定するかもしれません。このような推定された振る舞いは、脅威ハンティングやプロファイリングを進めるうえですばらしい情報源となります。これにより、レーダーをかいくぐるよう設計された新しいテクニックやスクリプトを見つけることができるからです。

同様に、こうした方法でスクリプトをプロファイリングすることは、悪意のあるスクリプトが使う手口や、その手口が時間とともにどのように進化するかを理解するのに最も適した方法といえます。ですから、私がリリースするツールを使用する(羽目に陥った)皆さんが、プロファイリングの新しい方法論を発見したならば、ぜひその振る舞いをツールに追加してください。ひとは自分が何を知らないかを知ることはできません。この機会を探索と学習の機会ととらえてもらえるとよいでしょう。

結論

シリーズ最初のブログを締めくくるにあたり、上で説明した概念やアイデアをかいつまんでまとめておきます。

まず、PowerShellは非常にリッチで冗長なスクリプト言語なので、その圧倒的柔軟性は同時に呪いでもあるということ。PowerShellにおける振る舞いとは、単一の、ないし単純な関数呼び出しに限定されるものではなく、振る舞いを識別する側にも同様の柔軟性が求められること。そのため、振る舞いのプロファイリングにおいては、コンテンツの難読化を解除し、解きほぐし、正規化しなければならないこと。そのさいは動的分析から得られたものと同じ概念、教訓を静的分析にも適用できるようにすること。

同様に、PowerShellスクリプトの動作プロファイリングに静的にアプローチする場合、コンテキストにおける手がかりと加重スコアリングから振る舞いの意図を決定する方法を検討すること。そして、ここでの全体的な目標は、リスクを評価し、それを成功に導くことなので、スコアリングの基礎となる"グラウンドトゥルース(正しい答え)"の用意が絶対に欠かせないこと。

次回は、より技術的な観点から詳しい説明をし、PowerShell内にデータを隠蔽するために使われる一般的な難読化手法や方法について検討します。さらに、私が観測した振る舞いと、それらの振る舞いがこれからリリースする予定のスクリプトのスコアリング全体に与える影響についても説明します。