not cve-2013-xxxx

55
Not CVE-2013- XXXX struts とととととととと ととととと ととととととととと

Upload: abendcve99990001

Post on 12-Nov-2014

1.217 views

Category:

Documents


5 download

DESCRIPTION

 

TRANSCRIPT

Page 1: Not CVE-2013-xxxx

Not CVE-2013-XXXX

struts と愉快な脆弱性達 続編の続編ただのバグだったよ

Page 2: Not CVE-2013-xxxx

自己紹介Twitter:abend@number3to4

Web アプリケーションのセキュリティをメインでやってます。

Page 3: Not CVE-2013-xxxx

はじめにこの話は未知の脆弱性を見つけようと思いたち、見つけたナニカが脆弱性になるのではと通報したが、脆弱性じゃねーよと言われるまでの3 か月間のたいしてオチのない物語である。

ただ、今後のセキュリティに少しでも助けとなることを願い、公開するものである。

Page 4: Not CVE-2013-xxxx

きっかけは2013 年 7 月 16 日に公開された struts2.3.15 以前に存在する S02-16 ( CVE-2013-2251 )や S02-005 ( CVE-2010-1870 )など様々な脆弱性が報告されています。

もしかして、まだまだあるんじゃないの?

じゃあ、探してみるか。

<参考>CVE-2010-1870 :http://www.slideshare.net/abend_cve_9999_0001/cve20101870CVE-2013-2251 : http://www.slideshare.net/abend_cve_9999_0001/cve-20132251 

Page 5: Not CVE-2013-xxxx

じゃあ、どうする? 1ソースコードでも見てみるか。2.3.15.1 は、ファイル数 4188  サイズ 17.8MB

見たいけど

Page 6: Not CVE-2013-xxxx

じゃあ、どうする? 2だったら、ある程度あたりをつけて、ソースコードを読もう!!

どうあたりをつける?

ユーザからの入力を受け付けているところを漁ってみる。

Page 7: Not CVE-2013-xxxx

じゃあ、どうする? 3キーワード「 input 」で、拡張子を java に限定して検索してみる。

まだまだ多いって

Page 8: Not CVE-2013-xxxx

じゃあ、どうする? 4

だけど、無理なものは無理だって

Page 9: Not CVE-2013-xxxx

じゃあ、どうする? 5なので、もっと絞り込むため、 S02-16 に倣って、同じようなところから探ってみる。S02-16 は、 org.apache.struts2.dispatcher.mapper.DefaultActionMapperが原因で「 action: 」、「 redirect: 」、「 redirectAction: 」にセットされた値のチェックが行われず、 OS コマンドを実行してしまう。

org.apache.struts2.dispatcher パッケージに含まれているプログラムを中心に見ていこう。

<参考>CVE-2013-2251 : http://www.slideshare.net/abend_cve_9999_0001/cve-20132251 

Page 10: Not CVE-2013-xxxx

じゃあ、どうする? 6 S02-16 は、 DefaultActionMapper に以下の変数定義がされ、処理に問題があったので・・・protected static final String METHOD_PREFIX = "method:";protected static final String ACTION_PREFIX = "action:";protected static final String REDIRECT_PREFIX = "redirect:";protected static final String REDIRECT_ACTION_PREFIX = "redirectAction:";

文字列として定義されている箇所がほかにもあるか探してみることにした。※ 文字列の変数定義が悪いという訳ではなく、特別に処理される HTTP パラメータなどが存在するかあたりをつけるために探すことにした。

Page 11: Not CVE-2013-xxxx

Let’s Try it!!1

まずは 8 ファイルを中心に見てみました。

Page 12: Not CVE-2013-xxxx

Let’s Try it!!2put(ACTION_PREFIX, new ParameterAction() { public void execute(String key, ActionMapping mapping) { String name = key.substring(ACTION_PREFIX.length()); if (allowDynamicMethodCalls) { int bang = name.indexOf('!'); if (bang != -1) { String method = name.substring(bang + 1); mapping.setMethod(method); name = name.substring(0, bang); } } mapping.setName(cleanupActionName(name)); }});

なんで、「 ! 」の出現場所でチェックしているのだろうか??

DefaultActionMapper に気になる箇所があった。

Page 13: Not CVE-2013-xxxx

Let’s Try it!!3 protected ActionMapping parseActionName(ActionMapping mapping) { if (mapping.getName() == null) { return null; } if (allowDynamicMethodCalls) { // handle "name!method" convention. String name = mapping.getName(); int exclamation = name.lastIndexOf("!"); if (exclamation != -1) { mapping.setName(name.substring(0, exclamation));

mapping.setMethod(name.substring(exclamation + 1)); } } return mapping; }

ほかにも。

Page 14: Not CVE-2013-xxxx

Let’s Try it!!4

RFC2616 Hyper Text Transfer Protocol3.2.2 http URLhttp_URL = "http:" "//" host [ ":" port ] [ abs_path [ "?" query ]]

HTTP で「 ! 」ってあんま見ない。

という訳で、「 ! 」がどういう使われ方をしているか調べてみることにした。

Page 15: Not CVE-2013-xxxx

Let’s Try it!!5「 ! 」だけで、ソース内検索すると悲劇しか起こらない。コメントに「 <!-- --> 」に使われるため、すべてのプログラムに引っかかってしまうため、デスマーチになってしまう。

Page 16: Not CVE-2013-xxxx

Let’s Try it!!6

具体的には、「” !” 」と「’ !’ 」の使われている箇所を探してみた。

という訳で、文字列または文字として「 ! 」を使っている箇所を探すことに。

Page 17: Not CVE-2013-xxxx

Let’s Try it!!7「” !” 」と「’ !’ 」の検索結果

PackageConfig.javaTimerInterceptor.javaActionChainResult.javaPropertiesReader.javaDefaultActionMapper.javaOsgiUtil.javaPortletUrlHelper.javaRestActionMapper.java

RestActionInvocation.javaTagFileProcessor.javaResolverUtil.javaDOTRenderer.javaJsr168Dispatcher.javaRestActionMapper.javaJspRuntimeLibrary.javaParserController.javaELParser.java

17 ファイルがヒットしたので、詳細調査を行うことに。

Page 18: Not CVE-2013-xxxx

Let’s Try it!!82つの方法で詳細な調査を試してみました。

①  ホワイトボックス的手法・・・ソースコード読みながら探ってみる。②  ブラックボックス的手法・・・ Web アプリケーション診断やファジング

※   XX 的手法と表現しているのは、プライベートでやっていたので体系化  されておらず独自手法のため、このような表現としています。

Page 19: Not CVE-2013-xxxx

やっちまおうぜ 1① ホワイトボックス的手法DefaultActionMapper.java 、 RestActionMapper.java に共通して「 name!method 」が含まれていた。「 name!method 」って、なんなんだろうと思ったので、これを調べてみることに。

Page 20: Not CVE-2013-xxxx

やっちまおうぜ 2「 name!method 」 は、 Dynamic Method Invocation といわれるものだった。

Dynamic Method Invocation って?

Page 21: Not CVE-2013-xxxx

やっちまおうぜ 3Dynamic Method Invocation ( DMI )って

There's a feature embedded in WebWork 2 that lets the "!" (bang) character invoke a method other than execute. In WebWork, it doesn't really have a name. During the S2 discussions, we coined the term "dynamic method invocation" to describe how WW/S2 use the bang notation.Dynamic Method Invocation (DMI) will use the string following a "!" character in an action name as the name of a method to invoke (instead of execute). A reference to "Category!create.action", says to use the "Category" action mapping, but call the create method instead.For Struts 2, we added a switch to disable DMI for two reasons. First, DMI can cause security issues if POJO actions are used. Second, DMI overlaps with the Wildcard Method feature that we brought over from Struts 1 (and from Cocoon before that). If you have security concerns, or would like to use the "!" character with Wildcard Method actions, then set struts.enable.DynamicMethodInvocation to FALSE in the application configuration.The framework does support DMI, just like WebWork 2, but there are problems with way DMI is implemented. Essentially, the code scans the action name for a "!" character, and finding one, tricks the framework into invoking the other method instead of execute. The other method is invoked, but it uses the same configuration as the execute method, including validations. The framework "believes" it is invoking the Category action with the execute method.The Wildcard Method feature is implemented differently. When a Wildcard Method action is invoked, the framework acts as if the matching action had been hardcoded in the configuration. The framework "believes" it's executing the action Category!create and "knows" it is executing the create method of the corresponding Action class. Accordingly, we can add for a Wildcard Method action mapping its own validations, message resources, and type converters, just like a conventional action mapping. For this reason, the Wildcard Method is preferred.

http://struts.apache.org/release/2.1.x/docs/action-configuration.html

Page 22: Not CVE-2013-xxxx

やっちまおうぜ 4簡単に言うと・・・「 Categoly 」 + 「 ! 」 + 「 Method 」という形で、「 Categoly 」で定義されている「 Method 」を呼び出すことができるような仕組み

Categoly:「 employee」Method:「 create」

Method:「 delete」Categoly である「 employee 」に Method である「 create 」、「 delete 」が定義されており、 「 create 」を実行した場合に以下へのアクセスで処理を実行する。http://server/employee!create

Page 23: Not CVE-2013-xxxx

やっちまおうぜ 5「 Categoly 」 + 「 ! 」 + 「 Method 」の「 Method 」が任意に指定できたら??結構、やばくない?

っていうことで、 DMI をターゲットに。

「 ! 」って英語だと bang っていうんだね。

Page 24: Not CVE-2013-xxxx

やっちまおうぜ 6なので、サンプルで DMI を使っている箇所を探すことに・・・

いろいろと探したところ、「 Person Manager 」-「 Create a new person 」で使われていることをハッケーン!!

※ サンプルで試す理由は、自分で DMI を実装した場合、自分の作りが悪いのか 脆弱性なのかの評価が必要となるため。

Page 25: Not CVE-2013-xxxx

やっちまおうぜ 7

Web アプリケーション診断とファジングを行う。② ブラックボックス的手法

Web アプリケーション診断って?http://www.slideshare.net/abend_cve_9999_0001/web-22186183

ファジングって?

Page 26: Not CVE-2013-xxxx

やっちまおうぜ 8ファジングって?アプリケーションの不具合を発見するための手法の一つで、様々な値を対象となるアプリケーションに送り、エラーを発生させ、その内容から不具合を検出する。・大量の文字列を送信・境界値の送信( -1 、 0 、 255 、 256 など)・特定の文字( \0A や \0D など)                  etc…

IPAhttp://www.ipa.go.jp/security/vuln/fuzzing.html

Taof というファジングツールが紹介されています。

Page 27: Not CVE-2013-xxxx

やっちまおうぜ 9Taof の画面ってこんな感じ。。。

Taof の使い方は、 IPA の資料参照してください。

Page 28: Not CVE-2013-xxxx

やっちまおうぜ 10ソースを見た際にポイントとした「 ! 」をベースに 3 パターンでファジング①   http://server/person/new-person!input.action

②   http://server/person/new-person!input.action

③  http://server/person/new-person!input.action

Page 29: Not CVE-2013-xxxx

やっちまおうぜ 11結果は、 3.16M になった。

出力された結果をどう評価すればいいのだろうか・・・。

Page 30: Not CVE-2013-xxxx

やっちまおうぜ 12ポイントは Internal Server Error ( 500エラー)。

理由は・・・アプリケーションが異常終了しているから。。。

異常終了しているということは、アプリケーションの制御に問題がある可能性があるから。

Page 31: Not CVE-2013-xxxx

やっちまおうぜ 13

http://server/person/new-person!aにアクセスすると500エラー、結構発生しています。

Page 32: Not CVE-2013-xxxx

やっちまおうぜ 14Taof でできることは、ここまでなので次のフェーズへ

続いては、 Web アプリケーション診断の知識を生かした疑似攻撃。

まずは、様々な記号を入力してみて、エラーがどう出るのか試してみる。

Page 33: Not CVE-2013-xxxx

やっちまおうぜ 15

http://server/person/new-person!!aにアクセスすると・・・色々と試した結果、これまでとエラーの出方が変わるパターンを発見!!

Page 34: Not CVE-2013-xxxx

やっちまおうぜ 16????

もしかして、別のクラスの関数を呼び出してるんじゃ??

なぜ、 ActionSupport.a() を呼び出そうとしてエラーに??

Page 35: Not CVE-2013-xxxx

やったぜま、まさか、糸口発見か!?

ヒャッハーー!!

Page 36: Not CVE-2013-xxxx

脆弱性見つけた? 1

extends しているクラスを呼び出そうとしていたのでは?

そんなわけで、ソースを見てみることにした。public class NewPersonAction extends ActionSupport {

private static final long serialVersionUID = 200410824352645515L;

@Autowiredprivate PersonManager personManager;private Person person;

public String execute() {personManager.createPerson(person);return "list";

}

      ~~~ 一部省略 ~~~}

Page 37: Not CVE-2013-xxxx

脆弱性見つけた? 2じゃあ、次に ActionSupport のソースを見てみた。public class ActionSupport implements Action, Validateable, ValidationAware, TextProvider, LocaleProvider, Serializable {

public boolean hasFieldErrors() { return validationAware.hasFieldErrors(); }

public String execute() throws Exception { return SUCCESS; }

public boolean hasKey(String key) { return getTextProvider().hasKey(key); }

public ResourceBundle getTexts() { return getTextProvider().getTexts(); }

}

※ ソースから一部抜粋

Page 38: Not CVE-2013-xxxx

脆弱性見つけた? 3public boolean hasFieldErrors()http://server/person/new-person!!hasFieldErrors

引数がなく、戻り値が boolean型だと CASTエラーが発生している。

Page 39: Not CVE-2013-xxxx

脆弱性見つけた? 4http://server/person/new-person!!execute

http://server/person/new-person!!executea

execute では 404エラーだが、 executeaだと 500エラーに変化。

public String execute()

戻り値( String型)だと処理を行い、表示しようとしたがコンテンツが存在しなくてエラーと推測。

Page 40: Not CVE-2013-xxxx

脆弱性見つけた? 5public void addActionError(String anErrorMessage) http://server/person/new-person!!addActionError

引数の指定の仕方が特定できなかった。そのため、引数のないaddActionErrorは存在しないというエラーと思われる。

Page 41: Not CVE-2013-xxxx

脆弱性見つけた? 6public void clearFieldErrors() http://server/person/new-person!!clearFieldErrors

戻り値、引数のない関数を指定すると 200OK となるが、レスポンスボディは0 で、何も表示されない。挙動の違いから、関数が処理されたと推測される。

HTTP/1.1 200 OKServer: Apache-Coyote/1.1Content-Length: 0Date: Wed, 25 Sep 2013 22:56:15 GMT

Page 42: Not CVE-2013-xxxx

脆弱性見つけた? 7public ResourceBundle getTexts() http://server/person/new-person!!getTexts

戻り値が ResourceBundle だが、 200OK であるため、処理されたと思われる。

HTTP/1.1 200 OKServer: Apache-Coyote/1.1Content-Length: 0Date: Wed, 25 Sep 2013 23:37:50 GMT

ある程度、状況が分かったので次のステップへ。

Page 43: Not CVE-2013-xxxx

<検証時に分かったこと>・ ActionSupport の関数を呼び出せた(と思う)。

→呼び出せたかもしれないが、引数の必要な関数は無理だった。→戻り値が String型は呼び出せた(と思う)。

任意のクラスの関数の呼び出しはうまくいきませんでした。呼び出せる関数が限定的であったが、任意のクラスを呼び出すことが不可能であるという evidence は見つからなかった。

脆弱性見つけた? 8

→片っ端からソースを見て回ったが、原因の特定に至らず。

!!って入力したら、本当にびっくりするような事案が発生。

Page 44: Not CVE-2013-xxxx

呼び出せる関数が限定的であったが、任意のクラスを呼び出すことが不可能であるという確証もないので・・・

脆弱性見つけた? 9

リスクがあると判断し、所定の手続きへ。

Page 45: Not CVE-2013-xxxx

通報してみたんです 1IPA の脆弱性情報の受付へ通報してみました。

Page 46: Not CVE-2013-xxxx

通報してみたんです 2

ただ、 8:39 にメールして、 10:18 に返信があったけど、自動応答メールなんだ。

内容の精査し、脆弱性なのかバグなのか判定して、結果を改めて連絡するよって返信がありました。

Page 47: Not CVE-2013-xxxx

ある日の出来事 11回メールのやりとりをした後は、特になにもないまま平凡な日々を過ごしていましたが・・・struts でセキュリティ FIX に伴う 2.3.15.2 がリリースされていたことを知る。※11/9時点で最新は 2.3.15.3

内容を見てみると 2 つのセキュリティ FIX が存在するとのこと。

Page 48: Not CVE-2013-xxxx

ある日の出来事 2① 「 action: 」の処理に問題があり、セキュリティの制約を迂回できる。S2-018 、 S2-019 という管理番号が付けられたものです。

②DMI にセキュリティ上の問題がある。DMI って、つい最近見たような・・・まさか、報告したものが脆弱性として修正された?

ラブストーリー並みに突然な出来事

って思ったが、あとで無関係であること知ることになる。

Page 49: Not CVE-2013-xxxx

直したそうです 1

DMI にセキュリティ上、問題のある機能だが、デフォルトで ON になってたからオフってね的なことが書かれている。

Page 50: Not CVE-2013-xxxx

直したそうです 3Vulnerabilities have been discovered in Apache Struts which could allow remote code execution.  Apache Struts is an open source, model-view-controller (MVC) framework used for building Java web applications.  Successful exploitation could result in an attacker executing arbitrary code in the context of affected application. Depending on the privileges associated with the application, an attacker could then install programs; view, change, or delete data; or create new accounts with full user rights.

実行権限にもよるが、プログラムをインストールされたり、変更されたり、消されたりと色々できちゃうよ。

Page 51: Not CVE-2013-xxxx

直したそうです 4

DMI を使っていた箇所にアクセスすると 404エラーとなる。

2.3.15.2 で試してみました。

Page 52: Not CVE-2013-xxxx

直したそうです 5元々どんな感じだったのか。

~~ 略 ~~ protected boolean allowDynamicMethodCalls = true;~~ 略 ~~ public void execute(String key, ActionMapping mapping) { String name = key.substring(ACTION_PREFIX.length()); if (allowDynamicMethodCalls) { int bang = name.indexOf('!'); if (bang != -1) { String method = name.substring(bang + 1); mapping.setMethod(method); name = name.substring(0, bang); } } mapping.setName(cleanupActionName(name)); }~~ 略 ~~

「 ! 」に関する修正は、 DefaultActionMapper でしか確認ができず。

注)すべてのソースで diff をとった訳ではないので漏れの可能性もあります。

Page 53: Not CVE-2013-xxxx

直したそうです 6どんな修正したのか。

~~ 略 ~~ protected boolean allowDynamicMethodCalls = false;~~ 略 ~~ public void execute(final String key, ActionMapping mapping, HttpServletRequest request) { if (request != null && request.getAttribute(STRUTS2_ACTION_PREFIX_PARSED) == null) { request.setAttribute(STRUTS2_ACTION_PREFIX_PARSED, true); String name = key.substring(ACTION_PREFIX.length()); if (allowDynamicMethodCalls) { int bang = name.indexOf('!'); if (bang != -1) { String method = name.substring(bang + 1); mapping.setMethod(method); name = name.substring(0, bang); } } String actionName = cleanupActionName(name); mapping.setName(actionName); if (getDefaultExtension() != null) { actionName = actionName + "." + getDefaultExtension(); } mapping.setResult(new ServletDispatcherResult(actionName)); } } ~~ 略 ~~

変わった訳ではないがここがポイント!!

Page 54: Not CVE-2013-xxxx

バグだったよ脆弱性として認められたかと思ったが、後日以下の内容(抜粋)のメールが来ました。

・ ActionSuppot クラスの一部メソッド(引数なし、返値なし)だけしか 呼べないのであれば、被害は生じない。・ただし、 ActionSupport クラスの将来的な仕様変更による潜在的な リスクがあるため、参考情報とする。

Page 55: Not CVE-2013-xxxx

まとめ今度こそ、大物が出てくるように精進します。結果的に、脆弱性ではないバグを 1件発見して終わった。