close search bar

Sorry, not available in this language yet

close language selection
 

大規模なApache Strutsリサーチ、第2部:実行環境

CVE-2018-11776のリサーチ中、Apache Strutsの115バージョンを構築した後、我々は、実行環境を再構築する課題に取り掛からなければなりませんでした。

大規模なApache Strutsリサーチ、第2部:実行環境

2019年8月、SynopsysのCybersecurity Research Center(CyRC)は、Apacheソフトウェア財団と連携してApache Strutsセキュリティ勧告S2-058を発表しました。この勧告は、Strutsの115バージョンの64件の脆弱性に照準を合わせてベルファストで実施されたリサーチを反映したもので、脆弱性別に影響を受けた約50のバージョンが特定されています。このブログ・シリーズでは、これまでの経験を読者の皆さんにシェアいたします。

このブログ・シリーズは技術系読者向けです。このブログ・シリーズでは、このプロジェクト中に我々が得た洞察や遭遇した問題、思い付いた解決策を公開しています。

これからお届けするのは当ブログ・シリーズの2回目の投稿です。初めての方は、第1回目の投稿をお読みになるようお勧めします。

その他の投稿もお見逃しなく。このブログの購読をぜひお申し込みください!

Apache Strutsをリサーチした理由

2018年8月、我々は新しく発表されたApache Strutsの遠隔コード実行の脆弱性(CVE-2018-11776/S2-057)を検証しました。独自の概念実証を作成し、Apache Strutsの過去のリリースに対してこれをテストした結果、当初の報告よりも多くのバージョンが脆弱性の影響を受けたことを発見しました。我々は、当社の責任ある開示方針に従いこれらの知見を報告しました。しかし、この発見によって、これまで報告されたすべてのApache Strutsの脆弱性についてはどうだったのか?という疑問が浮かんできました。我々は、脆弱性の大規模なリサーチを実施するためのシステムの構築に取り掛かりました。

手始めに

我々のApache Strutsリサーチ・プロジェクトは、さまざまなJava環境の構築から始まりました。

Javaは、「一度書けば、どこでも実行できる」汎用バイナリとコンポーネントというアイデアを推進する最初の言語の一つです。その意義は、開発および実行のための安定したプラットフォームを提供することにありました。しかし、Javaはかなり古く、長年にわたり多くの変遷を遂げています。Javaプラットフォームには微妙な問題があり、Struts 2の場合、これといって決まった1つのサーブレット・ランナーがあるわけではありません。

Apache Struts 2の最初のバージョンであるStruts 2.0.1は、10年以上前の2006年9月にリリースされました。当時優位だったのは(このときもWindows 95といった古いオペレーティング・システムをサポートしていた)Java 1.5でした。(最近になってサポートが停止された、2009年にリリースされたWindows 7のように、古いオペレーティング・システムの廃止は今ほど簡単ではなかったようです。)

これまで存在した環境をすべて残らず再現する代わりに、我々は、まずシンプルな手法によってJavaランタイムとサーブレット・ランナーの妥当な中間物を試行し、エッジ・ケースが存在する場所を観察することにしました。

当初の環境

我々は、まず、さまざまなバージョンのStrutsを手あたり次第に実行しました。システムに付属しているTomcat 8およびJava8パッケージを使用し、Ubuntu 18 LTSにTomcat基本インストールをセットアップしました。Java 8には、起点となるJava 1.5用のコンパイル機能があります。Tomcat 8には、1996年まで遡るJavaサーブレット1.0仕様と下位互換性がありますが、これは、Struts 2のWARファイルから割り出したものよりはるかに古いものでした。また、これは理論的には十分新しく、新しいバージョンのStrutsもその多くが同じインスタンスで実行できる可能性があります。

Ubuntu 18でStrutsを簡単にセットアップできることに驚きました。必要だったのはいくつかのチェーン・コマンドだけで、数分で初期構成を稼働させることができます。

Bashシェル
sudo apt-get update && sudo apt-get -y dist-upgrade && sudo apt-get -y install openjdk-8-jdk tomcat8 tomcat8-user && sudo service tomcat8 stop && sudo update-java-alternatives -s java-1.8.0-openjdk-amd64 && sudo service tomcat8 start

Ubuntu 18でのTomcat 8およびJava 8のセットアップ

準備したWARの多くが予測どおりにエラーなく実行できました。当初よく利用したのがShowcase WARファイルで、まず、Strutsの基本機能をいくつかテストしました。

また、Eclipse IDEを使ってリモート・デバッグ機能をセットアップし、エクスプロイトをトリガしたときに何が起きるのか追跡しました。

エクスプロイトの作成と再現

エクスプロイトの再現や既知の情報に基づく新しいエクスプロイトの作成の際はさまざまな障壁が待ち受けていました。これらについて以下に詳しく述べます。

Tomcat

S2-021

この脆弱性は、CookieInterceptorのブラックリストが不十分なためにClassLoader操作を招いてDoS攻撃を許します。

サーバーにペイロードを送り始めた際、ペイロードによって何もトリガされなかったことがリモート・デバッグで明らかになりました。ペイロードの有無を確かめるためによく観察しても、リモート・デバッグ・ツールでは何も発見できませんでした。Tomcat 404エラー・メッセージも送られてきました。

Tomcat 404エラー・メッセージ

ペイロード
/showcase.action?Class.ClassLoader.resources.dirContext.docBase=%2Ftmp

ペイロードを考えると、環境によってこれが問題になるとは考えられませんでした。しかし、最終的に、サーブレットに渡される前にデータが何らかの理由でサニタイズされたことが明らかになったのです。さらに興味深いことに、Tomcatで生成されたアクセス・ログをチェックすると、アクセス先のURLが想定とは異なっていました。

Tomcat 8のアクセス・ログ
“GET /j8-2.3.16.1/showcase.action HTTP/1.1” 404 989

Tomcat 6.5に切り替え、エクスプロイトを再度実行しました。ペイロードは正常に機能しました。そのうえ、Tomcat 6.5のアクセス・ログもTomcat 8とはまったく異なっていました。

Tomcat 6.5のアクセス・ログ
“GET /j8-2.3.16.1/showcase.action?Class.ClassLoader.resources.dirContext.docBase=%2Ftmp HTTP/1.0” 200 12502

これは、古いソフトウェアをアップグレードし、これにインフラストラクチャを合わせることで脆弱性を低減できる方向に近づくことを示す好例です。裏読みすると、新しいインフラストラクチャほど平均的なインストールが実行される可能性が高くなるため、他の製品に存在する、このようなエクスプロイトが検出されなかったのかもしれません。

S2-008

この脆弱性では、ExceptionDelegatorに対してOGNL評価を引き起こします。OGNL式はチューリング完全であり、Javaベース・クラスに頻繁にアクセスします。攻撃者はさらにこれを利用してホスト・アプリケーションのコンテキストおよび機能内でコードを実行し、遠隔コード実行(RCE)を引き起こします。

この脆弱性によって、ペイロードはcookieヘッダを通過しました。この脆弱性について興味深いのは、Apache Strutsを内包していること自体がセキュリティホールとなり、blank.warアプリケーションでさえ攻撃の対象となった点です。我々のサンプル・ペイロードでは、OGNLを使用してシェル・コマンドを起動し、ファイルにアクセスするだけに決めました。

HTTPペイロードのやり取り
GET /blank_j8-2.3.1/example/HelloWorld.action HTTP/1.1 Host: localhost User-Agent: Synopsys-CyRC/2019 Cookie: (#_memberAccess[“allowStaticMethodAccess”]\u003dnew\u0020java.lang.Boolean(true))(x)=1; x[@java.lang.Runtime@getRuntime().exec(“touch@/tmp/RCE”.split(“@”))]=1
HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Set-Cookie: JSESSIONID=52154AE434607CD570E5280CBD321A19; Path=/blank_j8-2.3.1 Content-Type: text/html;charset=UTF-8 Content-Length: 534

以上のペイロードはうまくいき、Tomcat 6で/tmp/RCEが生成されました。しかし、Tomcat 8にこれと同じペイロードを試行すると、cookie入力が即座にサニタイズされ、ステータス・ログに以下の不愉快な現象が現れました。

Tomcat 8のステータス・ログ – 試行失敗
org.apache.tomcat.util.http.parser.Cookie.logInvalidHeader A cookie header was received [(#_memberAccess[“allowStaticMethodAccess”]\u003dnew\u0020java.lang.Boolean(true))(x)=1; x[@java.lang.Runtime@getRuntime().exec(“touch@/tmp/CVE-2012-0392/2.3.1”.split(“@”))]=1] that contained an invalid cookie. That cookie will be ignored.Note: further occurrences of this error will be logged at DEBUG level.

前述したように、古いバージョンのソフトウェアをアップグレードし、インフラストラクチャをこれに合わせると、脆弱性の低減に有効かもしれないことがこのログでも明らかです。

Javaランタイム環境

S2-052

この脆弱性は、Struts RESTプラグインをXStreamハンドラとともに使用してXMLを解析する際にRCE攻撃を引き起こします。

このRCE攻撃が機能するかどうかを検証することにしました。脆弱性を再現することができました。この脆弱性は、公知のペイロードの適合バージョンを使うと型変換例外が発生します。

Java Runtime Environment 8の脆弱性例外
com.thoughtworks.xstream.converters.ConversionException: java.lang.String cannot be cast to java.security.Provider$Service : java.lang.String cannot be cast to java.security.Provider$Service

Java Runtime Environment 11およびその他に対してこれらと同じエクスプロイトを試行した結果、このペイロードが機能しなかったことが分かりました。これは一つには、ランタイム・ディストリビューションに追加された変更によるものであり、その結果、com.thoughtworks.xstream.mapper.CannotResolveClassExceptionが発生しました。

しかし、ペイロードに修正を加えると、Java Runtime Environment 11で機能するようになりました。脆弱性は一見低減しているが、修正の追加によってエクスプロイトが作り出される可能性があることは経験上分かっています。この場合、脆弱性のあるコンポーネント周囲の環境をアップグレードするだけでは脆弱性を低減することはできませんでした。

エクスプロイトに関する次の投稿では、エクスプロイトとこれに似たシナリオの修正が必要な理由について深く掘り下げます。

検証

S2-006

このプロジェクトのお陰で、S2-006がクロスサイト・スクリプティング(XSS)の脆弱性と表現されていることがエラー・ページで明らかになりました。

S2-006が当初、公開された際、その基本情報はあまり意味がありませんでした。

S2-006脆弱性の概要
<s:url>および<s:a>タグに対するクロスサイト・スクリプティング(XSS)の脆弱性

<s:url>タグと<s:a>タグのいずれも、このタグで生成されるURLが構築およびレンダリングされる際、適切にエスケープされないパラメータ値を挿入する可能性があります。既知のシナリオは次のとおりです。

  • <s:a>の結果の構造に含まれているパラメータ値は未エスケープの二重引用符を挿入することができるため、レンダリングされたhref属性をエスケープ処理することによって、生成されるHTML内にコードを埋め込むことができる。
  • <s:url>タグと<s:a>タグはいずれも、includeParamsが”none”以外の値に設定されたときに<script>タグをエスケープ処理できないため、含む側のJSP/actionをGETパラメータとともに呼び出すことで(例:http://localhost/foo/bar.action? <script>alert(1)</script>test=hello)攻撃を受けやすくなる。

さざまな試行錯誤を繰り返した結果、開発モードでStrutsが実行されると、これらの脆弱性のあるタグがエラー・ページにより生成されたことが最終的に明らかになりました。開発モードでは、Apache Strutsは独自のエラー・ページを生成します。それ以外の場合、Apache Tomcatはエラー・ページを生成し、このページは以上のような問題に対する脆弱性はありません。

まとめ

環境に左右されます。たとえ、互換性の高いJavaなどの環境であってもです。ランタイム・バージョン、サーバー・ソフトウェア、さらにソフトウェア構成はいずれも効果があります。ランタイムおよびサーブレット・ソフトウェアが新しいと、一部の問題が緩和されることに驚きました。その他の場合、エクスプロイトを粉砕することはできますが、代替のペイロードを使用して問題に何とか対処する必要があります。

リサーチャー

  • Stephen Mort
  • Padraig Donnelly
  • Ashley Stone
  • Omer Demirok

2019年のオープンソースのセキュリティおよびリスク解析を入手する

 
Christopher Fearon

投稿者

Christopher Fearon


More from セキュリティに関するニュースとリサーチ