1. ホーム
  2. スクリプト・コラム
  3. パワーシェル

制限された言語パターンを迂回するPowerShellコードインジェクションの脆弱性を防ぐ方法

2022-01-04 14:19:55

はじめに 言語制限モードは、任意の符号なしコードの実行を防ぐことで、PowerShellの攻撃を緩和する方法です。

プレゼンテーション

言語制限モードは、任意の符号なしコードの実行を防ぐことで、PowerShell攻撃を緩和する方法です。ポリシーで許可されていないスクリプトやモジュールは制限付き言語モードに配置されるため、攻撃者による署名なしコードの実行を厳しく制限することができ、Device GuardやAppLockerが強制モードである場合に最も実用的かつ有効な強制的セキュリティ対策となります。言語モードの制限によりAdd-Typeコールを制限する。Add-Typeを制限することは、明らかに、任意のC#コードをコンパイルして実行時空間にロードする能力を考慮に入れています。

しかし、このポリシーでは、PowerShell コードが "Full Language" モードで実行され、Add-Type の実行が許可されるため、Microsoft 署名の PowerShell コードが Add-Type を呼び出すことができるようにします。次のコマンドを実行すると、私が正しいことがわかります。

を使用することで

ここで、以下のPowerShellモジュールのコード(仮に"VulnModule")がMicrosoftによって署名されていた場合を想像してください。

ls C:* -Recurse -Include '*.ps1', '*.psm1' |
 Select-String -Pattern 'Add-Type' |
 Sort Path -Unique |
 % { Get-AuthenticodeSignature -FilePath $_.Path } |
 ? { $_.SignerCertificate.Subject -match 'Microsoft' }


では、制限された言語モードからのAdd-Typesの入力に影響を与えるものは何でしょうか?

一緒に考えてみましょう。

1. Add-Typeは、グローバル変数に型定義として渡される。グローバルなので、我々や攻撃者を含め、誰でもアクセスできる。
2. 問題は、署名されたコードがAdd-Typeの呼び出しの前にグローバル変数を定義しているため、カスタム悪意のあるC#コードを使用すると、これが正規のコードによって上書きされることです。

3. Set-Variableコマンドレットを使うと、変数を読み取り専用に設定できることをご存知でしょうか?今、私が何を考えているかわかりますよね?

兵器化

さて、制限された言語パターンから Add-Type にコードを注入するために、攻撃者は悪意のあるコードを読み取り専用変数として定義する必要があり、したがって、グローバル "Source" 変数を設定して署名されたコードを拒否する必要があります。以下に、兵器化された概念実証を示します。

  $Global:Source = @'
  public class Test {
    public static string PrintString(string inputString) {
      return inputString;
    }
  }'@
Add-Type -TypeDefinition $Global:Source


Add-Typeインジェクションの不具合について簡単に説明します。ホワイトリストに載っていないクラスの.NETメソッドには、プロパティ(ゲッターメソッド)とToStringメソッドの2つの例外があります。上記のPoCでは、ToStringはパラメータを渡すことができるので、静的なToStringメソッドを実装することにしました(getterはできません)。また、.NETクラスのホワイトリストは、New-Objectがオブジェクトをインスタンス化するときにのみ適用されるため、私のクラスは静的です。

では、上記のエクスプロイトコードは非現実的だと思われますか?そう思うかもしれませんが、Microsoft.PowerShell.ODataUtilsモジュールのMicrosoft.PowerShell.ODataUtilsにも、この脆弱性があります。マイクロソフトはCVE-2017-0215、CVE-2017-0216、CVE-2017-0219でこれを修正しました。正直なところ、あまり覚えていません。 matt Nelsonと私は、これらのインジェクションバグを報告しました。

攻撃を軽減する

マイクロソフトがこの脆弱性への対応を進めているにもかかわらず、私たちにできることは何でしょうか?

UMCIバイパスバイナリに有効なブラックリストのルールとして、PEファイル内のバージョン情報リソースにあるオリジナルファイル名に基づいてプログラムの実行をブロックする「ファイル名ルール」があります。なるほど...同じスクリプトに複数の脆弱性がある場合はどうすればいいのでしょうか?今のところ、あなたは1つのハッシュしかブロックしていません。もうお気づきでしょうか?あるスクリプトの過去の全ての脆弱性バージョンを効果的にブロックするためには、全ての脆弱性バージョンのハッシュを知る必要があるのです。マイクロソフトはこの問題を認識しており、過去にリリースされたすべての脆弱性スクリプトをスキャンしてハッシュを収集し、ブラックリストに統合するために最善を尽くしています。

脆弱性のあるスクリプトの全バージョンをハッシュ値でブロックすることは困難ですが、ある程度は攻撃を阻止することができます。そのため、PowerShell 5 のみの実行を許可し、スクリプトブロックのログを有効にすることが急務となっていました。

もう一つの方法は、システム上のほとんどのスクリプトとバイナリがカタログ署名とAuthenticode署名されていることです。カタログ署名は、スクリプトにAuthenticode署名が埋め込まれているわけではなく、そのハッシュがマイクロソフト署名付きカタログファイルに保存されていることを意味します。そのため、Microsoftがアップデートすると、古いバージョンのハッシュは期限切れとなり、署名されなくなる。これで、攻撃者は、古い署名付きカタログファイルをカタログストアに挿入することもできる。脆弱なスクリプトを探す研究者としては、まずAuthenticode署名が埋め込まれた脆弱なスクリプトを探さなければなりません(文字列 "SIG # Begin signature block" を含む)。 "マット・ネルソン氏は、このようなバイパススクリプトが存在すると述べています。

報告

バイパスを発見した場合、请将它上报给[email protected] 、CVEを取得することになります。PowerShellチームはインジェクションの欠陥に積極的に対処していますが、コード実行に影響を与えるために使用されるいくつかの方法にも積極的に対処しています。

概要

言語制限モードは署名されていないコードの実行を防ぐのに有効ですが、PowerShell とその署名付きモジュールまたはスクリプトには、まだ多くの攻撃面があります。私は、誰もがより多くのインジェクション欠陥を探し、それを報告し、公式のMSRCを通じてクレジットを得て、PowerShellエコシステムをより安全なものにすることを推奨します。その一方で、PowerShell のコード作成者が自らを検証してくれることを願っています。

さて、ここまで説明しましたが、Add-Typeの呼び出しには、競合条件を突くことができる設計上の欠陥があるため、インジェクションの脆弱性が残っています。今後もこの問題について詳しく説明し、Microsoftがこの根本的な問題への対処を検討することを望みます。