GitHub上に既に作成された環境コードをクローンします。
//⚠️環境コードのダウンロードパスに日本語やスペースを含めないでください
git clone https://github.com/Ha0Liu/CVE-2022-22947.git

IDEAでダウンロードしたコードパッケージを開きます。[Open] → [ダウンロードしたファイルのパス] → [Open] の順に選択します。
自分で手動でプロジェクトを作成し、環境を構築します。
(1)新規プロジェクトを作成し、設定後はそのまま「Next」をクリックします。

(2)プロジェクトのディレクトリ構成を分析します。
1. .ideaフォルダはIntelliJ IDEAのデフォルト設定ファイルで、特に用途はありません。必要に応じて削除または保持できます。
2. srcフォルダは主にプロジェクト全体のコード領域であり、javaとresourceの2つのフォルダを含みます。javaはJavaコードを記述する領域、resourceはプロジェクト全体の設定領域です。SpringプロジェクトではデフォルトでjavaにSpringApplicationメソッドが追加され、これがSpringのデフォルト起動メソッドです。resourceにはデフォルトでapplication.propertiesが追加され、これがSpringプロジェクトの設定ファイルです。
3. testフォルダはテスト用フォルダで、テストメソッドを記述できます。
4. pom.xmlはMavenの設定ファイルで、プロジェクトに必要な依存関係や設定などを含みます。
5. .imlはMaven依存パッケージの設定で、デフォルトで追加されます。
6. External Librariesフォルダはこのプロジェクトのすべての依存パッケージです。
(3)Maven依存関係をpom.xmlファイルに追加します(Mavenリポジトリにすべての依存関係の詳細が含まれています)。
1. pom.xmlファイルにはデフォルトで一部のXMLコードが生成されます。詳細は次のとおりです。

2. プロジェクトに必要な依存関係をインポートします。このプロジェクトはSpring Bootプロジェクトであるため、サーバースターターとしてspring-boot-starter依存関係が必要です。次に、この脆弱性はSpring CloudのGatewayに関するもので、危険なバージョンは3.1.1未満のため、今回は3.1.0バージョンを使用して脆弱性の再現を行います。また、actuatorインターフェースを介してゲートウェイを監視・アクセスする必要があるため、この依存関係も必要です。具体的な内容は次のとおりです。

(4)Springの設定ファイルを変更します(パス: src → main → resources → application.properties)。詳細は次のとおりです。
1. server.portはSpringサーバーの起動ポートで、デフォルトは8080です。状況に応じて設定できます。
2. management.endpoint.gateway.enabled=trueはactuatorエンドポイントでSpring Cloud Gatewayを検出するためのもので、デフォルトはfalseです。この脆弱性ではゲートウェイの状態を監視する必要があるため、手動でtrueに変更して監視を有効にします。
3. management.endpoints.web.exposure.include=gatewayはサーバーのゲートウェイとしてGatewayゲートウェイを選択するものです。この脆弱性はGatewayゲートウェイの脆弱性であるため、設定ファイルでゲートウェイにGatewayを選択することを宣言します。

(5)新規プロジェクト作成後に自動生成されるJavaクラスを変更します(クラス名は通常「プロジェクト名+Application」、パスはsrc → main → java → com.xxx.xxx → xxxApplication)。詳細は以下の図を参照してください。

(6)プロジェクトを起動します。詳細は以下の図のとおりです。

(7)http://localhost:9000にアクセスし、ページがスクリーンショットと一致していれば、環境構築が成功したことを示します。

(1)まず、公式の修正パッチを確認します。差分は次のとおりです。https://github.com/spring-cloud/spring-cloud-gateway/commit/337cef276bfd8c59fb421bfe7377a9e19c68fe1e 公式はorg.springframework.cloud.gateway.support.ShortcutConfigurable#getValue関数で、GatewayEvaluationContextを使用してStandardEvaluationContextを置き換え、SPEL式を実行しています。

上の図から、このパッチは主にSPEL式の解析方法を変更していることがわかります。66行目のif文から、SPEL式は「#{」で始まり「}」で終わる必要があることがわかります。このgetValueメソッドはSPEL式を解析する機能を持ち、この脆弱性がSPEL式から引き起こされるRCE脆弱性であることがわかります。
(2)control + マウス左クリックでgetValueフィールドをクリックし、org.springframework.cloud.gateway.support.ShortcutConfigurable.ShortcutType列挙型までバックトレースします。

上のdefaultメソッドから、列挙型のDEFAULTメソッドが呼び出されていることがわかります。メソッドの詳細は次のとおりです。
default ShortcutType shortcutType() {
return ShortcutType.DEFAULT;
}

(3)org.springframework.cloud.gateway.support.ConfigurationService.class#normalizeProperties()までバックトレースします。

このnormalizeProperties()はフィルターのプロパティを解析し、フィルターの設定プロパティをnormalizeに渡し、最終的にgetValueでSPEL式を実行してSPELインジェクションを引き起こします。
(1)ドキュメント[https://cloud.spring.io/spring-cloud-gateway/multi/multi__actuator_api.html](https://cloud.spring.io/spring-cloud-gateway/multi/multi actuator_api.html ) によると、ユーザーはactuatorを介してゲートウェイにルートを作成および削除できます。次の図はゲートウェイの基本構造です。

(2)IDEAでは、actuatorのmapping機能を使用して、ゲートウェイの作成、削除などの機能インターフェースを見つけることができます。

(3)RouteDefinitionクラスをトレースすると、このクラスがゲートウェイの構造内容を宣言していることがわかります。

(4)その中のFilterDefinitionクラスをトレースすると、Filterにはnameとargsの2つのパラメータがあることがわかります。
(5)このnameパラメータをトレースすると、AbstractGatewayControllerEndpoint#save()メソッドでnameがフィルタリングされていることがわかります。saveメソッドはゲートウェイを作成するためのインターフェースで、このメソッドはゲートウェイのid(カスタマイズ可能)とRouteDefinitionの2つのパラメータを呼び出します。上記で、このオブジェクトが作成されたゲートウェイの構造内容を宣言していることが説明されており、これにより脆弱性がトリガーされます。

(6)ブレークポイントを設定してisAvailable()メソッドを動的にデバッグし、どのnameがこのフィルターを通過できるかを確認します。


上図のようなnameを使用してname検証をバイパスできます。
(7)上記の分析により、指定された「name」パラメータと「#{」で始まり「}」で終わるSPEL式を使用してRCE攻撃を行うことができます。ペイロードは次のとおりです。
/**
* ペイロードのSPEL式の説明
* ここでは式を介してコマンドを実行する必要があるため、T(java.lang.Runtime).getRuntime().exec()の形式でコマンド実行メソッドを呼び出す必要があります。
* コマンド実行時にはString型の文字列として式を渡す必要があるため、式を強制的にStringオブジェクトに型変換する必要があります。
* 式を渡す際にはバイトストリームとして渡す必要があるため、T(org.springframework.util.StreamUtils).copyToByteArray()メソッドを呼び出す必要があります。
/
{
"id": "任意に変更可能(以前作成したidと重複しないこと)",
"filters": [{
"name": "👆上のスクリーンショット内の任意のname",
"args": {
"name": "任意に変更可能",
//このvalueは電卓を起動するコマンド(MacOS)
"value": "#{new String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{\"/System/Applications/Calculator.app/Contents/MacOS/Calculator\"}).getInputStream()))}"
}
}],
"uri": "http://example.com"
}