Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2022-22965 | Kitploit
ツール/GitHubGitHub/khidottrivi/cve-2022-22965
脆弱性分析コード分析エクスプロイトウェブアプリケーション悪用学習と教育ラボと実践
GitHubkhidottrivi/cve-2022-22965

CVE-2022-22965

リポジトリを見る
44年前未レビュー

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

CVE 2022-22965_Spring4Shell の分析

脆弱性の説明

Spring4Shell は、Spring Framework の Spring Core に存在する CVE の名前です。

CVSS 3.x スコアは 9.8 で、この脆弱性は最高リスクレベル(クリティカル)に分類されています。この脆弱性により、攻撃者はリモートから任意のコードを実行し、脆弱性のあるサーバーを制御できます。

インターネット上での Spring Core の普及と Spring4Shell の深刻な影響を考慮し、この脆弱性は専門家によって Log4shell に劣らない影響力があると評価されています。

影響範囲

Spring4Shell は、インターネット上の Spring Framework を使用するすべての Web アプリケーションに影響するわけではなく、次の要素をすべて満たす Web アプリケーションにのみ影響します。

  • アプリケーションが Spring Framework バージョン < 5.2、5.2.0 – 5.2.19、または 5.3.0 - 5.3.17 を使用している
  • アプリケーションが Spring-webmvc または Spring-webflux のいずれかの依存関係を使用している
  • アプリケーションが JDK バージョン 9 以上の Java を使用している
  • アプリケーションが従来の Java Web アーカイブ(.war ファイル)としてパッケージ化され、Tomcat にデプロイされている(Spring Boot で実行するアプリケーションではこの脆弱性は確認されていません)

環境構築

今回セットアップする環境は次の構成です。

  • Spring Framework 5.1.0
  • Spring-webmvc 依存関係 5.1.0
  • JDK 11.0.13(Kali 2021.4a の仮想マシンを使用し、この Java はプリインストール版)
  • Apache Tomcat 9.0.45

脆弱性を含む環境・プロジェクトの作成と Intellij でのデバッグ設定

  1. Apache Tomcat のインストール

    前述のとおり、Kali 2021.4a と Apache Tomcat 9.0.45 を使用しています。Apache Tomcat のインストール方法が分からず、Kali Linux にインストールしたい場合は、このリンク を参照してください。

    注: https://mirror.kiu.ac.ug/apache/tomcat/tomcat-9/v9.0.45/bin/apache-tomcat-9.0.45.tar.gz を https://archive.apache.org/dist/tomcat/tomcat-9/v9.0.45/bin/apache-tomcat-9.0.45.tar.gz に置き換えてください。

  2. IDE の選択

    プロジェクトのコードを書き、プロジェクトを .war ファイルとしてパッケージ化し、そして非常に重要なデバッグを行うために IDE が必要です。私は Intellij を使用していますが、Eclipse や Netbeans など、Java をサポートする IDE であれば何でも問題ありません。

  3. 脆弱性を含むシンプルなプロジェクトの作成

    私のプロジェクトは非常にシンプルで、次の構成です。

    • model の HelloWorld.java

      Untitled

    • controller の HelloWorldController.java

      Untitled

    • view の hello.jsp

      Untitled

  4. .war ファイルのビルド

    プロジェクトをパッケージ化するには、次のようにします: Build -> Build Artifacts -> helloworld:war -> Build。

    ビルドが成功するのを待ちます。すると、プロジェクトに out フォルダーが新たに現れます。./out/artifacts/your_war_name/ に移動すると your_war_name.war ファイルがあります。この .war ファイルが、コンパイルおよびパッケージ化された Web プロジェクト本体であり、Apache Tomcat などの Java Servlet にデプロイできます。

    Build Artifacts がグレーアウトしている(Build Artifacts を実行できない)場合は、このプロジェクトに Build Artifacts がまだ設定されていないためです。File -> Project Structure -> Artifacts -> 既存のすべての artifacts を削除 -> Add(+ ボタン)-> Web Application: Exploded -> From Modules... -> OK(Exploded の作成完了)-> Add(+ ボタン)-> Web Application: Archive -> For ‘helloworld:war exploded’ -> OK の順に操作してください。その後、Build Artifacts を再度実行してください。

  5. デプロイとデバッグ設定

    • デプロイ

      .war ファイルを Apache Tomcat にデプロイするには、Apache Tomcat のディレクトリ内の /webapps フォルダーに .war ファイルをコピーするだけです(例: 私の場合は、呼び出しやすいようにリネームした helloworld.war を /opt/tomcat/apache-tomcat-9.0.45/webapps/ にコピーします)。その後、Tomcat サーバーを次の 2 つの方法(Linux の場合)で起動します。

詳細分析

まず、デバッグに使用しているプロジェクトを分析します。前述のとおり、このプロジェクトは単純に次の構成です。

  • model の HelloWorld.java。HelloWorld オブジェクトには message(string)と person(string)の 2 つのプロパティと、setter/getter メソッドがあります(このように単純な構造のため、このオブジェクトは Plain Old Java Object - POJO と呼ばれます)。プロジェクト内に POJO クラスが存在する必要があります。これが Spring4Shell を悪用するための必須条件です。
  • controller の HelloWorldController.java。このクラスには、入力パラメータとして helloWorld オブジェクト(HelloWorld)と model(Model)を受け取る helloPost メソッドがあります。helloPost メソッドでは、helloWorld のプロパティ(person と message)の値から model オブジェクトに addAttribute を行います。Spring4Shell を悪用するための 2 つ目の条件は、POJO オブジェクトを入力として受け取る controller が存在することです。
  • view の hello.jsp。この hello.jsp は、model 内の attribute(HelloWorldController.java から送信されたもの)を呼び出し、ユーザーに表示します。

以下に例を示します。

Untitled

アプリケーションは POST リクエストの params から情報を取得し、helloWorld{“person”:”Leo”, “message”:”Hi there”} オブジェクトを生成します。この helloWorld オブジェクトが helloPost メソッドへの入力になります。アプリケーションは上記の処理を行い、ユーザーにそのレスポンスを返します。

POST リクエストの body 内のパラメータから helloWorld オブジェクトへの変換は、完全に Spring によって自動的に行われます。では、Spring はどのように処理しているのでしょうか。また、入力されたパラメータを検証しているのでしょうか。

発生源(Source)class CachedIntrospectionResults

これはデバッグ中のキャプチャで、body が “class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT” のリクエストを実行した例です(左側(スタックトレース)を (1)、右側を (2) と呼びます):

Untitled

(1) では注意すべき点をハイライトしています(下から上に読んでください)。Spring は POST リクエストの params から helloWorld オブジェクトに対して applyPropertyValue を実行します。params が単純に person=Leo&message=Hi%20there の場合、Spring はキーワード ‘person’ が helloWorld.person に、‘message’ が helloWolrd.message に対応することを見つけ出します。

しかし、Spring は HTTP リクエスト経由でオブジェクトを送信することも許可しています(HTTP でオブジェクトを送信するという言い方は大げさかもしれませんが、簡単に言うとそういうことです)。person プロパティが string ではなく、Person オブジェクトであり、Person の中に name(string)と age(int)の 2 つのサブプロパティがあると仮定します。この Person オブジェクトの情報をサーバーに送信するには、次のようにします: “person.name=Leo&person.age=23”。

つまり、params の形式は A=X ではなく A.B.C.D… = X になります。A.B.C.D… = X という形式を処理するために、たとえば A.B.C= X というパラメータがある場合、Spring は簡単に言うと、その文字列を getA.getB.setC(X) に変換する処理を行います。

getA が何かは説明しませんが、body が “person.name=Leo&person.age=23” のリクエストを例に説明します。Spring は helloWorld オブジェクトに person プロパティと getPerson メソッドが存在するか探します。存在すれば、Spring は helloWorld.getPerson() を呼び出します。これにより、型が Person のオブジェクトが返されるので、仮に person1 と呼びます。次に Spring は person1 に ‘name’ というプロパティと setName メソッド(‘name’ の後ろが ‘=’ なので)が存在するか探し、存在すれば person1 に対して setName(Leo) を呼び出します。

person.age の場合、Spring は最初から person を探してから age に進むことはせず、以前に取得したオブジェクト(この場合は helloWorld と person1)を再利用します。

上記の手順の後、サーバー上には helloWorld{person:{name:”Leo”, age:23}} オブジェクトが存在することになります(message プロパティはひとまず無視してください)。

では、Spring は各オブジェクトのプロパティ(たとえば helloWorld オブジェクトの ‘person’ プロパティ)をどのように見つけているのでしょうか。

(1) の先頭を見てください。CachedIntrospectionResults(beanClass) メソッドがあります。このメソッドは beanClass のプロパティをリストアップします。(2) を見ると、beanClass が model.HelloWorld の場合に 3 つのプロパティがあることがわかります。一方、私が作成した HelloWorld model には ‘person’ と ‘message’ の 2 つのプロパティしかありません。つまり、このメソッドは ‘class’ というプロパティを追加で返しており、‘class’ の行を展開すると propertytype が ‘java.lang.class’ であることがわかります。

つまり、type が java.lang.classclass の class オブジェクトに作用できるということです。これが Spring4Shell の発生源(source)です。

CVE-2010-1622

上記の source に関連する CVE-2010-1622 が過去に存在しました。CVE-2010-1622 の作者は、class.classLoader.URLs[0] = X. という payload を使用してこの source を悪用しました。

java.lang.class 内には getClassLoader() メソッドがあり、これは ClassLoader オブジェクトを返します。この ClassLoader は Tomcat の URLs 配列(リソースのロードに使用)に作用できます。URLs に作用できるため、攻撃者は URLs[0] の値を URL アドレスに変更し、攻撃者が制御する悪意のある Jar ファイルへのリモートアクセスを実行できます。

この問題を修正するため、Spring は CachedIntrospectionResults(beanClass) メソッド内でフィルター(ブラックリスト)を実装しました。

Untitled

‘beanClass’ が Class.class(java.lang.class)の場合、pd は ‘classLoader’ と ‘protectionDomain’ 以外でなければなりません。その証拠に、CachedIntrospectionResults が java.lang.class のすべてのプロパティをロードした後、‘classLoader’ と ‘protectionDomain’ の 2 つのプロパティは存在しません。

Untitled

しかしその代わりに、JDK 9 以降では Class.class に ‘module’ プロパティが追加され、Class.module 内に classLoader プロパティが存在します。

Untitled

→ つまり、JDK 9 以降を使用することで、Spring のブラックリストをバイパスできるのです!!!

到達点(Sink)class AccessLogValue

Spring4Shell の 公開 PoC によると、使用される payload は次の形式であることがわかります:

class.module.classloader.resources.context.parent.pipeline.first ⇔ Class.getModule().getClassLoader().getResources().getContext().getParent().getPipeline().getFirst()

デバッグから、次の gadget chain を確認できます:

java.lang.class.getModule() -> java.lang.module.getClassLoader() -> org.apache.catalia.loader.ParallelWebappClassLoader.getResources() -> org.apache.catalia.webresources.StandardRoot.getContext() -> org.apache.catalia.core.StandardContext.getParent() -> org.apache.catalia.core.StandardHost.getPipeline() -> org.apache.catalia.core.StandardPipeline.getFirst() -> org.apache.catalia.valves.AccessLogValue.

そして、AccessLogValue クラスには次のプロパティがあります:

Untitled

AccessLogValue オブジェクトを呼び出すことができ、この AccessLogValue は Tomcat のログ記録に影響を与えます。

→ Tomcat サーバー上の AccessLogValue オブジェクトのプロパティを設定することで、サーバー上にファイルを作成できます。そのために、PoC では Prefix、Suffix、Pattern、Directory、fileDateFormat のプロパティを設定しています。そして、リクエスト payload は次のようになります:

“class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Bprefix%7Di%20java.io.InputStream%20in%20%3D%20%25%7Bc%7Di.getRuntime().exec(request.getParameter(%22cmd%22)).getInputStream()%3B%20int%20a%20%3D%20-1%3B%20byte%5B%5D%20b%20%3D%20new%20byte%5B2048%5D%3B%20while((a%3Din.read(b))!%3D-1)%7B%20out.println(new%20String(b))%3B%20%7D%20%25%7Bsuffix%7Di&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT&class.module.classLoader.resources.context.parent.pipeline.first.prefix=shell&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=”

  • ブレークポイントの一覧

    デバッグをより簡単にするために、次の場所にブレークポイントを設定できます:

    Untitled

結論

この分析には本来結論はありません。このセクションは、単に「結論らしきもの」を用意するために追加しただけです!!!

修正方法を探しているなら、こちら にあります。

ツールをダウンロード
  • /opt/tomcat/apache-tomcat-9.0.45/bin/catalina.sh start(アプリケーションはこのコマンドを実行したユーザーの権限で実行されます。私の場合は root@@)
  • sudo service tomcat start(アプリケーションは通常 tomcat ユーザーの権限で実行されます。Apache Tomcat セットアップ時の service の設定によって異なります)

デプロイが完了したら、http://localhost:8080/helloworld にアクセスしてください。

  • デバッグ設定

    Tomcat の(リモート)デバッグを設定するには、次の手順を実行します。

    1. サーバー側:

      • catalina.sh ファイルを開き、JPDA_ADDRESS パラメータの localhost の値を仮想マシンの IP アドレスに変更します

        Untitled

      • 次のコマンドで Tomcat サーバーを再起動します: /opt/tomcat/apache-tomcat-9.0.45/bin/catalina.sh jpda start。このとき、Tomcat は HTTP サーバー用のポート 8080 に加えて、接続してデバッグするためのポート 8000 も開きます。

      注意: このデバッグ手順では、Intellij を Windows 10 で実行し、Tomcat を Kali 仮想マシンで実行しているため JDPA_ADDRESS を変更する必要があります。Intellij と Tomcat を同じマシンにセットアップする場合は、変更する必要はありません。

    2. Intellij 側:

      • Run -> Edit Configurations... -> Add(+ ボタン)-> Remote JVM Debug の順に選択します

      • 名前を設定 -> Host と Port を先ほど catalina.sh で変更した IP とポートに変更 -> OK -> Shift + F9(デバッグを開始)

        Untitled