ox0xo infosec tutorial

S2-057 CVE-2018-11776


このポストは S2-057を発見したLGTMのリサーチャーであるMan Yue Moと、 githubにPoCを公開したリサーチャーのjas502n、Ivan1ee、Fnzer0の情報にもとづいて書かれています。 詳細については文末を確認してください。

脆弱性の概要

脆弱な設定

struts.xmlに以下の脆弱な設定が記述されている場合、受け取ったHTTPリクエストに含まれるEL式やOGNL式を無害化できず、任意のコマンドを実行される可能性があります。 struts.xmlからincludeされている各xmlも同様に脆弱性の原因となります。

  • actionタグもしくはurlタグを含むpackageタグにnamespaceの指定が無い

脆弱性が有るxml

<struts>
  <package name="actionchaining" extends="struts-default">
    <action name="actionChain1" class="org.apache.struts2.showcase.actionchaining.ActionChain1">
      <result type="redirectAction">
        <param name="actionName">register2</param>
      </result>
  </package>
</struts>

脆弱性が無いxml

<struts>
  <package name="actionchaining" extends="struts-default" namespace="/hoge">
    <action name="actionChain1" class="org.apache.struts2.showcase.actionchaining.ActionChain1">
      <result type="redirectAction">
        <param name="actionName">register2</param>
      </result>
  </package>
</struts>

想定される攻撃ベクタ

  • リクエストされるURLに%{もしくは${が含まれる

    例1 http://localhost/app/${1+1}/index

    例2 http://localhost/app/%{(1+1)}/index

    URLエンコードされている可能性があります

    http://localhost/app/%24%7B1%2B1%7D/index

    http://localhost/app/%25%7B1%2B1%7D/index

仕組み

Struts2の基本

HTTPリクエストに応じて適切なActionクラスを呼び出すためにActionProxyクラスが使われます。 ActionProxyクラスの基本動作はstruts.xmlに記述されたactionタグによって定義され、受け取ったHTTPリクエストに応じて具体的な動作が決定されます。

以下の例ではhogeに対してSampleClassがマッピングされています。 この状態でhttp://localhost/app1/hoge.actionにアクセスするとSampleClassが呼び出された後にhttp://localhost/app1/index.jspが表示されます。 ActionProxyクラスがURL文字列を解析してSampleClassクラスを呼び出す事によりこの動作が実現されます。

<struts>
  <package name="test" extends="struts-default" namespace="/app1">
    <action name="hoge" class="SampleClass">
      <result type="dispatcher">
        <param name="actionName">/index.jsp</param>
      </result>
    </action>
  </package>
</struts>

解析された文字列からクラスを呼び出す際にOGNLが使われます。 OGNLは文字列をプログラムコードとして解釈実行できるため脆弱性の温床になる可能性があります。 安全に使うためにはプログラマが意図した文字列だけを受け取るような仕組みが必要です。

脆弱性

今回発見された脆弱性はnamespaceを判断する機能が悪用されたものです。 packageタグにnamespace属性が指定されていない場合はURLから読み取った/app1という文字列からnamespaceが判定されます。 この時OGNLが利用されるために以下のようなURLを使ったコードが実行可能になります。

http://localhost/app1/${1+1}/hoge.action

  • サーバは localhost
  • action は hoge.action
  • namespace は /app1/${1+1} ←これがOGNLに渡される

環境構築

jas502n/St2-057はStruts2.2.3.1でないとRCEが成立しません。 今回問題となっているStruts2.3およびStruts2.5ではシンプルな数値計算しか行えずjavaのメソッド呼び出しには失敗するためです。 そういった意味ではjas502n/St2-057には改善の余地があります。 しかし2018.08.24時点で唯一のPoCであり数値計算が出来る以上はRCEの成立まであと一歩の可能性があるという事で動作確認をしていきます。

jas502n/St2-057以外にStruts2.3.34で再現可能なPOCが公開されています

やるべきことは全てSt2-057/README.mdに書いてあります。 今回はそれらの手順を読み解く必要もなく暗黙の了解を知らなくても良いスクリプトを作りました。 VirtualBoxにCentOS7_minimalを新規インストールしてスクリプトを使ってください。 環境がプロキシ配下にある場合はプロキシ設定もしてください。

プロキシ設定

必要に応じて設定してください。

export PROXY='proxy.sample.local:8080'
cat > /etc/profile.d/proxy.sh << END
PROXY=$PROXY
export http_proxy=$PROXY
export HTTP_PROXY=$PROXY
export https_proxy=$PROXY
export HTTPS_proxy=$PROXY
END
source /etc/profile

mkdir -p /etc/systemd/system/docker.service.d
cat > /etc/systemd/system/docker.service.d/proxy.conf << END
[Service]
Environment="HTTP_PROXY=http://$PROXY/" "HTTPS_PROXY=https://$PROXY/"
END
systemctl daemon-reload

Struts2

Struts2.2.3.1とStruts2.3.34とStruts2.5.16を用意します。

curl -LO https://gist.githubusercontent.com/ox0xo/17673b22fc3fa3260be4eab8687be5e5/raw/4c0181485b9a8f66f81cdb8bfcfe91b51bf3f4d9/s2-057.sh
chmod +x s2-057.sh
./s2-057.sh

一部ローカル環境向け

# s2-057というディレクトリを作って以下のファイル群を展開しておく
#
# docker-compose-Linux-x86_64
# docker-compose.yml
# st2231.war
# st2334.war
# st2516.war
# struts-actionchaining.xml
# vulhub.tar.gz
#
# その後s2-057の中に入ってから以下のコマンドを実行する

curl -LO https://gist.githubusercontent.com/ox0xo/2738af32e40b17e98863d230f73c34df/raw/cc06cbc7001aa8d0e301e3f03636dba60a58a3ca/s2-057-local.sh
chmod +x s2-057-local.sh
./s2-057-local.sh

PoC

AES-256-CBCで暗号化してあります。 弊社略称4文字に28byteの0を付け加えた32byteキーで復号してください。

Struts2.2.3.1

サーバの/etc/passwdを読み取る

ee570b2c7ebab7e4892661e62a3dff939119d7d69b3c8dc45e71c733884aff536f725c0d3fc032e569ca32eb75931a5fc78303f824a3cbb3488ad4f6949fb3f448024d48c753fa919bb4d2717a0916e053a2854c4e23a905284ed36dc31a8a2116eaab5573f29e3a1652ed5840f24532f2cdc4735ee7fecd1f4927dcedf12240e4eb0913a0bd9fd03ea3c019cde21b009ddac5ea86c710c7636f22d7975c7ba4b4177939aa634f7f44c5e0180dde14e37c29f33aacc4bbac5559e7e31a809fc09796d430053e42f7bf88e40617443878187aa172ef04aa6e9e5bf23c13a449e8e8d34ace1631fb27ad3a9f87d3d46f1ca3d09c900081ce2a63d4d6109a1edabcd8eaf5d381f58b2b47447e3f458c0e6d9648cfa3e251d6f08c9d94b5454edf1a87b22aa3039bb739dbdca73a361ea3c9f85ed5229ab0a29b6a8b5de46434dfbf7641580ff63f889433f4922c83b55f320dd704ccbac9c8f83c1be080cc693aa43e79bd59950a545fbcd41acc086dc791a9da1c5bb20bb7792c2b2a4088a74bc6e8108da3347d36e24ad171740c04c69e1dd8b7095a5af05f1a8ff87bec69dbc1ca4716a052a70e7a99405a16e0cdd7b95c8324f8a06a8cb7579eb8e17be65c517ccdc7d8c35fd93bc283bb54ee5554cbab18d06ae7346f66568c9910d16fcf0f73941bae1c9b9cb8f4e7134f2a4d4a17446ac472eda485f6b3ff29b1087d67f7dd3b199804697cfe7c6b7054e3543b26d15b151f3188c6a84c5c8dc8b1a0af9d

サーバ上に/tmp/this_server_was_hackedを作成する

ee570b2c7ebab7e4892661e62a3dff939119d7d69b3c8dc45e71c733884aff536f725c0d3fc032e569ca32eb75931a5f7ac28a22e680b607da193ab0ffedb6d527f23fd77365af42404097a4cbca3f29f35015439860e9b8337b73086eb4c780b997a191e1598091dca277285d76ae326bd281a5e3d16c75d7bcd95089a0999124bdc4fdd79aae3ff991e2307326be07fbefee4cad972677697f8a498c8fba6d208b083763d4f6cb943e96797af6552ebede160a8d73297cec565f54d001938aa5e7a037773d62ed07c5b3a7529eab873d759b9e1cf7ea3cb1176b3669d326b99647dcf05c01fdaef20ad3fb1dc24cd2

Struts2.3.34

サーバの/etc/passwdを読み取る

ee570b2c7ebab7e4892661e62a3dff939ff709906314a0a1a8e1363f95891723c886369e41e6b1bea08cf5268b4e5784a50f5d185f524c581952df01486346ee875f7bd136cdab6b7f53f0503cb40f6c604afcc4f8f75298b96583078ae1fc953dd73bf39c221d2b431af0bce170f1d775560f702577fdb9e310df3c0e7d39620a2e1dec1e0fbdcf49c1be9f15ca40798d30fdff0eccb720e21ef53aa3abfbefdede7111f1a1124a806adaced6c150304023f325a7ea39b327b8440876983a423a3b25da44b79b3b2a4d7e0a75febe48c896031e489b8b2dfb8ce2c6d67ba9dd16fdeb79daa145d8fa8afba9473f08e343552bf396809580a3579282531f7970404b8631a4ced11f2cfec01df60e6044176a006f16781d7744b4fb142e669b366cca77fa53c9c273896c01931900848ae1c499c4768f176edb9d996df189859f8c727e429344f94f151d022738b287b6f42291fbbe2896da6667868c859a85e515914eedd56c4557c3e1b42a4dab0ffd4be9b1d496461590443eb42f630f46545727b39a4815b7d818803b812ac51b65e914b84996c240dd6a3aaa0e2be5400693f02b54b67b196a7238071a421b5fa59d8b4940832d7e004c7b801f8945be4ace046b13bab788e12249ebc1655b1d4e9eed7adb5656215b3080310ff98dc0c2b1b163994c4915400c01ee789d410a199467f7f420ffec150d303cb0d7e6ffd4212662cb6545317d95d582899f84bc4d18397f8a612f3d8c3a37a5a1a6444d33ebdb5ef256a2c05a2c16570687ce1ed458b4fe3bb54ef8120b797b0d50d03c3509d02ecc97a9f15496d57126c10b6ac5ee69b31a6db80805700a43b22075c7fa8bea84a437366b166401ab133f3b1347b08e25092605025763b4c0a34b54397c3d2b96ed2a840e4c49ebb9d0dc8b3aa926531a4f2d185d3ffe959266d010db4e244787aecd1cebd11bb904d6ec2e4baf2b4fdd6722449408ca8c16b550f88de0306a6e65ec39f8d120bd7ebb5846b661ad989ebee34265db42b902d21ed2ff805d5eb31742538d702d4c9348184ebbb814f0bd7c84c30554873e8c5a9a716a4f

サーバ上に/tmp/this_server_was_hackedを作成する

ee570b2c7ebab7e4892661e62a3dff939ff709906314a0a1a8e1363f95891723c886369e41e6b1bea08cf5268b4e5784a50f5d185f524c581952df01486346ee875f7bd136cdab6b7f53f0503cb40f6c604afcc4f8f75298b96583078ae1fc953dd73bf39c221d2b431af0bce170f1d775560f702577fdb9e310df3c0e7d39620a2e1dec1e0fbdcf49c1be9f15ca40798d30fdff0eccb720e21ef53aa3abfbefdede7111f1a1124a806adaced6c150304023f325a7ea39b327b8440876983a423a3b25da44b79b3b2a4d7e0a75febe48c896031e489b8b2dfb8ce2c6d67ba9dd16fdeb79daa145d8fa8afba9473f08e343552bf396809580a3579282531f7970404b8631a4ced11f2cfec01df60e6044176a006f16781d7744b4fb142e669b366cca77fa53c9c273896c01931900848ae1c499c4768f176edb9d996df189859f8c727e429344f94f151d022738b287b6f42291fbbe2896da6667868c859a85e515914eedd56c4557c3e1b42a4dab0ffd4be9b1d496461590443eb42f630f46545727b39a4815b7d818803b812ac51b65e914b84996c240dd6a3aaa0e2be5400693f02b54b67b196a7238071a421b5fa59d8b4940832d7e004c7b801f8945be4addef03f3e099a6b4240a313ed8f9e2a0a89550fac60610fd2601f2b14c76f5be751f686e26b76a11ff512a20a66f67ad77a109c9eb9dd46e0ec455dc10e6f5e5499c63675a7087c628d3a000ec1b29a5835c1f1cb6301ee0b10269fda61d9b0e75c385d1fc776fdce1900a29fca5264fda823ca4ccaca4f651171c411331a34e

struts2.5.16

サーバの/etc/passwdを読み取る

ee570b2c7ebab7e4892661e62a3dff93cc361854bc8d6d423b52f45ede67ecc653e9024338ce58bf7a661066af7df834c990e4349a28e77d2460fc7a46b766b35ce3629804e780213a9d1179eac7784d6a77a057c23da4dde00ec32b5c31e336e152b95d7ff906b7edf2992058237e61aa5fd97ad6b95c0d7002a749d99fd37532105e3619be351452092926b5e7142a8aff453b36101ce0ed6db01e40dba0e005cd61b098ce305281a55fb1c0e9cf76c5f623543622c9b0524c8627e4222de2ce4e83eafa2b6af6f3ca454ec0b97671f6d61c1ac31d863a87893947c6b036a6295318e6d831f1905ead5008ec27485d396d1057419dbf9f5dced0a97b1930cf093cecd7f558df60a2ba6500e642c94795a9ac0f2a2349ea1058ee527133262ef084f6b1767ea49afb6d8144b8d846fc2d89ab91ee7411f757fe9128ef3bd504a852178c81712afd05826eb93ed190395b899810645adeac4f16a77f210d1bb0508fc21e5da64025cf5bfb86694993597e922fb8cf8682ebad4ab670ae4f2553f103ea9cfeca003f259137179e8b4ebea29e055d5395c151b39831ff1360aa7d93b2d08071cb3ce0ae50b1569090591c382ac72f072982b97019465b5565e782883169cd3536e5011208051079457ad8e542947266cb7ef5b571e7de5beb8290b45dbecfcdba210e5bd3258fdba04f6e2b677a15f7d460a1094e9d65f5d2f7fc828c194198f6b73754dee0b7c0eedf5f43da7a9e0d5b2f6bdfcd1caed6a37699648c951bf25bd0122f717ebd80497128f0e711c15dbd9cd98a7d74deed8333f678d054d937c4203a2e5fc15d382b7832edfd93c948392966bd93e603baf43da86df7a51d1583e06834e1afe16dfc45ecfc837b5aaea3056d891d6176975425eace42b18eff565314962ab64c40e3e7bffe8443b33f809d6fc9aaf2443f6e54efcca338d6902c677856e5dcac0dc75fb1180504c042a1514ad0fb5d3eb6712e1b92c4945fdc21fcd548bc734fe0ed0a833159151eb13c293e7c4e11e80dba3b674678ea416897b9f7d52fe7f107eac4f8f9ab65a123dd612e6218d9025e9a83714e36bbfce1bcdf06ec7d8ccc583fe29f2124dee34128e49bb8d3922fa1830af4

サーバ上に/tmp/this_server_was_hackedを作成する

ee570b2c7ebab7e4892661e62a3dff93cc361854bc8d6d423b52f45ede67ecc653e9024338ce58bf7a661066af7df834c990e4349a28e77d2460fc7a46b766b35ce3629804e780213a9d1179eac7784d6a77a057c23da4dde00ec32b5c31e336e152b95d7ff906b7edf2992058237e61aa5fd97ad6b95c0d7002a749d99fd37532105e3619be351452092926b5e7142a8aff453b36101ce0ed6db01e40dba0e005cd61b098ce305281a55fb1c0e9cf76c5f623543622c9b0524c8627e4222de2ce4e83eafa2b6af6f3ca454ec0b97671f6d61c1ac31d863a87893947c6b036a6295318e6d831f1905ead5008ec27485d396d1057419dbf9f5dced0a97b1930cf093cecd7f558df60a2ba6500e642c94795a9ac0f2a2349ea1058ee527133262ef084f6b1767ea49afb6d8144b8d846fc2d89ab91ee7411f757fe9128ef3bd504a852178c81712afd05826eb93ed190395b899810645adeac4f16a77f210d1bb0508fc21e5da64025cf5bfb86694993597e922fb8cf8682ebad4ab670ae4f2553f103ea9cfeca003f259137179e8b4ebea29e055d5395c151b39831ff1360aa7d93b2d08071cb3ce0ae50b1569090591c382ac72f072982b97019465b5565e782883169cd3536e5011208051079457ad8e542947266cb7ef5b571e7de5beb82906874d87c5f5e713ae072af5b7dd2ec12f497a3361fa4a4b0c1d38851ff29f4590e54cef74b274e5bc9e6a2f7bca7b64584522990f1286b66494cf63e27ea4b0618713c60e267e5a0bf15fb6fc66806eb37a6f28b096583816033d4eea7ac6604f334b923273f007d7825bd05fca9ed4a574206358753a1bd884d8ee8c7fc8015

参考

Man Yue Mo: CVE-2018-11776: How to find 5 RCEs in Apache Struts with Semmle QL

jas502n: St2-057 在线靶机环境,Enjoy!

Ivan1ee: Struts2-057/CVE-2018-11776两个版本RCE漏洞分析(含EXP)

Fnzer0: S2-057本地测试与复现


Content