Movatterモバイル変換


[0]ホーム

URL:


3,347 views

Apache Struts2 における任意の Java メソッド実行の脆弱性

Embed presentation

Copyright©2013 JPCERT/CC All rights reserved.「Javaアプリケーション脆弱性事例調査資料」についてこの資料は、Javaプログラマである皆様に、脆弱性を身近な問題として感じてもらい、セキュアコーディングの重要性を認識していただくことを目指して作成しています。「JavaセキュアコーディングスタンダードCERT/Oracle版」と合わせて、セキュアコーディングに関する理解を深めるためにご利用ください。JPCERTコーディネーションセンターセキュアコーディングプロジェクトsecure-coding@jpcert.or.jp1Japan Computer Emergency Response TeamCoordination Center電子署名者 : Japan Computer Emergency Response Team Coordination CenterDN : c=JP, st=Tokyo, l=Chiyoda-ku, email=office@jpcert.or.jp, o=Japan Computer Emergency ResponseTeam Coordination Center, cn=Japan Computer Emergency Response Team Coordination Center日付 : 2013.06.26 10:59:43 +09'00'
Apache Struts 2 における任意のJava メソッド実行の脆弱性CVE-2012-0838JVNDB-2012-0000122
Copyright©2013 JPCERT/CC All rights reserved.Apache Struts 2とは Java のWebアプリケーションを開発するためのオープンソースのフレームワーク アプリケーションの開発効率やメンテナンス性を向上させることを目的としている3Apache Struts2JAVAアプリケーションWebサーバークライアント
Copyright©2013 JPCERT/CC All rights reserved.Apache Struts 2とは4• Model-View-Controller (MVC)アーキテクチャを採用• アプリケーションの開発者はModelとViewを実装する。Model: ビジネスロジックの実装 (javaで実装)View: 画面デザイン (jspで実装)Controller: クライアントからの入力イベントを処理し、ModelやViewに振り分ける(Struts2で実装).jsp.javaクライアントWebサーバー
Copyright©2013 JPCERT/CC All rights reserved.脆弱性の概要—クライアントから送信されてきた文字列の処理で発生するエラーの取り扱いに不備が存在。—具体的には、数値型の変数に対して文字列が送信されてきた際に発生する変換エラー処理。—送信する文字列を細工することで、任意のJavaメソッドが実行可能となる。5
Copyright©2013 JPCERT/CC All rights reserved.脆弱性が悪用された場合のリスク任意のJavaメソッドが実行できるため、Runtime::execメソッドを使えばOSコマンドを実行することが可能アプリケーションの外部から、アプリケーションが稼働するサーバ上で任意のコマンドが実行可能となり、サーバを乗っ取られる可能性がある6Runtime::exec()WebサーバJavaメソッド実行!!細工された文字列
Copyright©2013 JPCERT/CC All rights reserved.Struts2 内部で変換エラーが発生した場合の処理7※Struts2付属のサンプルアプリ「showcase」を元に処理を解説する① クライアントから、エラーの原因となる文字列を含むリクエストが送信される。② Struts上で、文字列→数値に変換する際にエラーが発生し、エラー(例外)処理を行う。③ エラー処理で、変換エラーの原因となった文字列が保持される。④ jsp側からエラーの原因となった文字列が取り出され、レスポンスの一部としてクライアントへ送信される。HelloWorldLong型 empId エラー値HelloWorld.jspエラー値HelloWorldHelloWorldエラーempIdは数値ですHelloWorldempId= HelloWorld① ②③④クライアントエラー発生!
Copyright©2013 JPCERT/CC All rights reserved.8private Long empId;:public Long getEmpId() {return empId;}:<s:textfield label="Employee Id"name="currentEmployee.empId"/>:Javaファイル(Model)/showcase/action/EmployeeAction.javaJspファイル(View)/empmanager/editEmployee.jsp変数empIdをModel(.java)から取得して表示する。数値型(Long)の変数empIdが存在し、クライアントから送信されたパラメータempIdの値が格納される数値型の変数empIdに対して文字列を送信するとエラーが発生する。クライアントからのリクエストサンプルアプリ「showcase」
Copyright©2013 JPCERT/CC All rights reserved.①クライアントからエラーの原因となる文字列を含むリクエストが送信される9GET /?empId=HelloWorld HTTP/1.1Host: localhost:8080<form action=‘/’ method=‘GET’>:<input type=‘text’ name=‘empId’ value=‘HelloWorld’>:</form>HTTPリクエスト上記HTTPリクエストを送信するためのHTMLパラメータempIdの値として”HelloWorld”という文字列を送信する。(empIdはサーバ側では数値型として扱われることに注意。)empId= HelloWorld①クライアント
Copyright©2013 JPCERT/CC All rights reserved.②文字列→数値に変換する際にエラー発生、エラー(例外)処理を行う10public class ConversionErrorInterceptor extends AbstractInterceptor {:public String intercept(ActionInvocation invocation) throws Exception {:クライアントから送信されてきたパラメータempIdの値”HelloWorld”を、数値型変数empIdに対して挿入する際に変換エラーが発生し、エラー処理が行われる。変換エラー処理はConversionErrorInterceptorクラスのinterceptメソッド内でエラー例外処理が行われる。ConversionErrorInterceptor.javaHelloWorldLong型 empId②
Copyright©2013 JPCERT/CC All rights reserved.③エラー処理で、変換エラーの原因となった文字列が保持される11public class ConversionErrorInterceptor extends AbstractInterceptor {:public String intercept(ActionInvocation invocation) throws Exception {:HashMap<Object, Object> fakie = null;:String propertyName = (String) entry.getKey();Object value = entry.getValue();:fakie.put(propertyName, getOverrideExpr(invocation, value));:ConversionErrorInterceptor.javaエラーとなった変数名が<クラス名.変数名>という形式で取得され、変数propertyNameに格納される。currentEmployee.empId
Copyright©2013 JPCERT/CC All rights reserved.12public class ConversionErrorInterceptor extends AbstractInterceptor {:public String intercept(ActionInvocation invocation) throws Exception {:HashMap<Object, Object> fakie = null;:String propertyName = (String) entry.getKey();Object value = entry.getValue();:fakie.put(propertyName, getOverrideExpr(invocation, value));:変数valueには変換エラーとなった文字列の値が代入される。“HelloWorld”③エラー処理で、変換エラーの原因となった文字列が保持されるConversionErrorInterceptor.java
Copyright©2013 JPCERT/CC All rights reserved.13public class ConversionErrorInterceptor extends AbstractInterceptor {:public String intercept(ActionInvocation invocation) throws Exception {:HashMap<Object, Object> fakie = null;:String propertyName = (String) entry.getKey();Object value = entry.getValue();:fakie.put(propertyName, getOverrideExpr(invocation, value));:protected Object getOverrideExpr(ActionInvocation invocation, Object value) {return "'" + value + "'";}getOverrideExprメソッドgetOverrideExprメソッドでは第2引数を’(シングルクオート)で囲って返却する処理を行う“HelloWorld”‘HelloWorld’③エラー処理で、変換エラーの原因となった文字列が保持されるConversionErrorInterceptor.java
Copyright©2013 JPCERT/CC All rights reserved.14public class ConversionErrorInterceptor extends AbstractInterceptor {:public String intercept(ActionInvocation invocation) throws Exception {:HashMap<Object, Object> fakie = null;:String propertyName = (String) entry.getKey();Object value = entry.getValue();:fakie.put(propertyName, getOverrideExpr(invocation, value));:getOverrideExpr関数を介した後の値は、変数propertyNameとセットでHashMap変数fakieに代入される。fakie:currentEmployee.empId : ‘HelloWorld’:currentEmployee.empId‘HelloWorld’③エラー処理で、変換エラーの原因となった文字列が保持されるConversionErrorInterceptor.java
Copyright©2013 JPCERT/CC All rights reserved.15public class ConversionErrorInterceptor extends AbstractInterceptor {:public String intercept(ActionInvocation invocation) throws Exception {:fakie.put(propertyName, getOverrideExpr(invocation, value));:invocation.getStack().setExprOverrides(fakie);public void setExprOverrides(Map overrides) {if (this.overrides == null) {this.overrides = overrides;}OgnlValueStack.javaエラー値を含む変数fakieはOgnlValueStackクラスのインスタンス変数overridesとして保持される。:currentEmployee.empId :‘HelloWorld’fakiefakie:currentEmployee.empId : ‘HelloWorld’:③エラー処理で、変換エラーの原因となった文字列が保持されるConversionErrorInterceptor.java
Copyright©2013 JPCERT/CC All rights reserved.④Jsp側からエラーの文字列が取り出され、レスポンスとしてクライアントへ送信する。Jspに記述されたコード(OGNL式)にしたがって、変数empIdの値が取得される。 OGNLとは⇒Object-Graph Navigation Language (OGNL) OGNLはJavaのクラス(Model)の変数を設定/取得するための言語 サンプルコードのjspに記載されたOGNL式は、変数currentEmployee.empIdの値を取得して表示をする式 下記のような表記で直接Javaメソッドを呼び出すことも可能::<s:textfield label="Employee Id" name="currentEmployee.empId"/>:Jspファイル(View)/empmanager/editEmployee.jsp<property name="roots">@java.io.File@listRoots()</property>16
Copyright©2013 JPCERT/CC All rights reserved.④Jsp側からエラーの文字列が取り出され、レスポンスとしてクライアントへ送信する。Jspに記述されたOGNL式にしたがって、OgnlValueStack.findValueメソッドを経由して変数currentEmployee.empId の値(エラーとなった文字列)が取得される。::<s:textfield label="Employee Id" name="currentEmployee.empId"/>:Jspファイル(View) /empmanager/editEmployee.jsppublic Object findValue(String expr, Class asType) {:if ((overrides != null) && overrides.containsKey(expr)) {expr = (String) overrides.get(expr);:Object value = OgnlUtil.getValue(expr, context, root, asType);:}OgnlValueStack.javaTextFieldTag.doEndTag()TextField.end()TextField.evaluateParams()TextField.findValue()TextParseUtil.translateVariables()TextParseUtil.translateVariables()TextParseUtil.translateVariables()OgnlValueStack.findValue()経由する関数currentEmployee.empId17
Copyright©2013 JPCERT/CC All rights reserved.④Jsp側からエラーの文字列が取り出され、レスポンスとしてクライアントへ送信する。::<s:textfield label="Employee Id" name="currentEmployee.empId"/>:public Object findValue(String expr, Class asType) {:if ((overrides != null) && overrides.containsKey(expr)) {expr = (String) overrides.get(expr);:Object value = OgnlUtil.getValue(expr, context, root, asType);:}前述の変数overridesから、変数exprとセットの値(エラーが発生する原因となった文字列)がとりだされる。‘HelloWorld’fakie‘HelloWorld’currentEmployee.empId:currentEmployee.empId :‘HelloWorld’18OgnlValueStack.javaTextFieldTag.doEndTag()TextField.end()TextField.evaluateParams()TextField.findValue()TextParseUtil.translateVariables()TextParseUtil.translateVariables()TextParseUtil.translateVariables()OgnlValueStack.findValue()経由する関数Jspに記述されたOGNL式にしたがって、OgnlValueStack.findValueメソッドを経由して変数currentEmployee.empId の値(エラーとなった文字列)が取得される。Jspファイル(View) /empmanager/editEmployee.jsp
Copyright©2013 JPCERT/CC All rights reserved.④Jsp側からエラーの文字列が取り出され、レスポンスとしてクライアントへ送信する。::<s:textfield label="Employee Id" name="currentEmployee.empId"/>:public Object findValue(String expr, Class asType) {:if ((overrides != null) && overrides.containsKey(expr)) {expr = (String) overrides.get(expr);:Object value = OgnlUtil.getValue(expr, context, root, asType);:}変数exprの値はOgnlUtil::getValueメソッドにてOGNL式として評価された後にクライアントに返却される。‘HelloWorld’fakieOGNL:currentEmployee.empId :‘HelloWorld’文字列’HelloWorld’はOGNL式として意味を持たないため、’HelloWorld’のまま19TextFieldTag.doEndTag()TextField.end()TextField.evaluateParams()TextField.findValue()TextParseUtil.translateVariables()TextParseUtil.translateVariables()TextParseUtil.translateVariables()OgnlValueStack.findValue()経由する関数OgnlValueStack.javaJspファイル(View) /empmanager/editEmployee.jspJspに記述されたOGNL式にしたがって、OgnlValueStack.findValueメソッドを経由して変数currentEmployee.empId の値(エラーとなった文字列)が取得される。
Copyright©2013 JPCERT/CC All rights reserved.Javaファイル(Model)Jspファイル(View)Jspに記述されたOGNL式では、OgnlValueStack.findValueメソッドによってJava(Model)の処理結果を取得後、必ずOgnlUtil.getValueメソッドによってOGNL式による評価が行われる。処理OgnlUtil.getValueメソッドによるOGNL式の評価Model(Java)による処理が・・・• 正常処理の場合 → 正常値• エラー処理の場合 → エラー値が保持されるクライアント処理結果処理後の値OgnlValueStack.findValue()リクエストHello WorldJava(Model)側の処理後の値を取得後、Java(Model)側の処理がエラーかどうかに関わらず、必ずOGNL式として評価される。①②③20④Jsp側からエラーの文字列が取り出され、レスポンスとしてクライアントへ送信する。
Copyright©2013 JPCERT/CC All rights reserved.④Jsp側からエラーの文字列が取り出され、レスポンスとしてクライアントへ送信する21レスポンスがクライアントに返される。クライアント上ではエラーメッセージが表示される。
Copyright©2013 JPCERT/CC All rights reserved.攻撃コード22■攻撃コードのポイントパラメーターempIdに対し、JavaメソッドであるgetRuntime.execでコマンドを実行するOGNL式を指定している。GET /?empId='%2B@java.lang.Runtime@getRuntime().exec(“notepad.exe")%2B' HTTP/1.1Host: localhost:8080<form action=‘/’ method=‘GET’>:<input type=‘hidden’ name=‘empId’value="'+@java.lang.Runtime@getRuntime().exec(&quot;notepad.exe&quot;)+'">:</form>攻撃コードのHTTPリクエスト攻撃コードのHTTPリクエストを送信するためのHTML
Copyright©2013 JPCERT/CC All rights reserved.変換エラーが発生した際の処理フロー※Struts2に付属しているサンプルアプリ「showcase」を元に処理を解説する① クライアントから、エラーの原因となる文字列を含むリクエストが送信される。② Struts上で、文字列→数値に変換する際にエラーが発生し、エラー(例外)処理を行う。③ エラー処理で、変換エラーの原因となった文字列が保持される。④ Jsp側からエラーの原因となった文字列が取り出され、レスポンスの一部としてクライアントへ送信される。攻撃コードが実行された際の処理23攻撃コードが実行された際でも処理のフローは正常処理と全く変わらないが、④の処理内容で違いが発生する。
Copyright©2013 JPCERT/CC All rights reserved.攻撃コード実行時④Jsp側からエラーの文字列が取り出され、レスポンスとしてクライアントへ送信するJspの内容にしたがって、変数empIdの値が取得され、エラーの原因となった文字列が返されるが・・・::<s:textfield label="Employee Id" name="currentEmployee.empId"/>:public Object findValue(String expr, Class asType) {:if ((overrides != null) && overrides.containsKey(expr)) {expr = (String) overrides.get(expr);:Object value = OgnlUtil.getValue(expr, context, root, asType);:}OgnlValueStack.java前述の変数overridesから、エラーが発生した原因となる文字列が変数exprにとりだされる。: fakie'+@java.lang.Runtime@getRuntime().exec(“notepad.exe")+'24Jspファイル(View) /empmanager/editEmployee.jsp
Copyright©2013 JPCERT/CC All rights reserved.25public Object findValue(String expr, Class asType) {:if ((overrides != null) && overrides.containsKey(expr)) {expr = (String) overrides.get(expr);:Object value = OgnlUtil.getValue(expr, context, root, asType);:}変数exprがOGNL式として評価される際にJavaメソッドが実行されてしまう!!'+@java.lang.Runtime@getRuntime().exec(“notepad.exe")+'25OgnlValueStack.java::<s:textfield label="Employee Id" name="currentEmployee.empId"/>:攻撃コード実行時④Jsp側からエラーの文字列が取り出され、レスポンスとしてクライアントへ送信するJspの内容にしたがって、変数empIdの値が取得され、エラーの原因となった文字列が返されるが・・・Jspファイル(View) /empmanager/editEmployee.jsp
Copyright©2013 JPCERT/CC All rights reserved.問題点 今回のアプリケーションにおける具体的な問題点引数をOGNL式として評価するOgnlUtil::getValueメソッドに対し、無害化していないデータを渡してしまっていた。26以下のコーディングガイドに違反している!!「 IDS00-J. 信頼境界を越えて渡される信頼できないデータは無害化する」 問題点に対してどうすべきだったか。OgnlUtil::getValueメソッドの引数として渡す前に、データがOGNL式として解釈されないように無害化する必要があった。
Copyright©2013 JPCERT/CC All rights reserved.変換エラーが発生した際の処理フロー※Struts2付属のサンプルアプリ「showcase」を元に処理を解説する① クライアントから、エラーの原因となる文字列を含むリクエストが送信される。② Struts上で、文字列→数値に変換する際にエラーが発生し、エラー(例外)処理を行う。③ エラー処理で、変換エラーの原因となった文字列が保持される。④ Jsp側からエラーの原因となった文字列が取り出され、レスポンスの一部としてクライアントへ送信される。修正版コード: バージョン2.2.3.1で修正27この処理のコードに修正が入っているHelloWorldLong型 empId エラー値HelloWorld.jspエラー値HelloWorldHelloWorldエラーempIdは数値ですHelloWorldempId= HelloWorld① ② ③ ④
Copyright©2013 JPCERT/CC All rights reserved.修正版コード: 脆弱バージョンのおさらい28public class ConversionErrorInterceptor extends AbstractInterceptor {:public String intercept(ActionInvocation invocation) throws Exception {:HashMap<Object, Object> fakie = null;:Object value = entry.getValue();:fakie.put(propertyName, getOverrideExpr(invocation, value));:ConversionErrorInterceptor.java変数valueには変換エラーとなった入力値が代入される。“HelloWorld”③エラー処理で、変換エラーの原因となった文字列が保持される
Copyright©2013 JPCERT/CC All rights reserved.29public class ConversionErrorInterceptor extends AbstractInterceptor {:public String intercept(ActionInvocation invocation) throws Exception {:HashMap<Object, Object> fakie = null;:Object value = entry.getValue();:fakie.put(propertyName, getOverrideExpr(invocation, value));:protected Object getOverrideExpr(ActionInvocation invocation, Object value) {return "'" + value + "'";}変数valueはgetOverrideExpr関数を介してHashMap変数fakieに代入される。getOverrideExprメソッドgetOverrideExprメソッドでは第2引数を’(シングルクオート)で囲って返却する処理を行う“HelloWorld”fakie:‘HelloWorld’:修正版コードではgetOverrideExprメソッドに修正が加えられている。ConversionErrorInterceptor.java修正版コード: 脆弱バージョンのおさらい③エラー処理で、変換エラーの原因となった文字列が保持される
Copyright©2013 JPCERT/CC All rights reserved.修正版コード: getOverrideExprメソッドの修正内容30protected Object getOverrideExpr(ActionInvocation invocation, Object value) {return "'" + value + "'";}getOverrideExprメソッド(修正前)protected Object getOverrideExpr(ActionInvocation invocation, Object value) {return "¥"" + StringEscapeUtils.escapeJava(String.valueOf(value)) + "¥"";}getOverrideExprメソッド(修正後)StringEscapeUtils.escapeJavaメソッドを使ってエスケープ処理を行っている。getOverrideExprメソッドでは第2引数を’(シングルクオート)で囲って返却する処理を行う③エラー処理で、変換エラーの原因となった文字列が保持される
Copyright©2013 JPCERT/CC All rights reserved.修正版コード: StringEscapeUtils.escapeJavaメソッドによるエスケープ31• StringEscapeUtils.escapeJavaメソッドによるエスケープ処理エスケープ対象文字列 エスケープ処理後の文字列¥b ¥¥b¥n ¥¥n¥t ¥¥t¥f ¥¥f¥r ¥¥r‘(シングルクオート) ¥’“(ダブルクオート) ¥”¥ ¥¥/ ¥/■攻撃コードで送信される値がエスケープされると・・・・'%2B@java.lang.Runtime@getRuntime().exec(“notepad.exe")%2B'↓¥'%2B@java.lang.Runtime@getRuntime().exec(¥“notepad.exe¥")%2B¥'⇒OGNL式として解釈されない文字列にエスケープされる。
Copyright©2013 JPCERT/CC All rights reserved.修正版コード: エスケープ実施後のOgnlUtil::getValueメソッドの動作32::<s:textfield label="Employee Id" name="currentEmployee.empId"/>:public Object findValue(String expr, Class asType) {:if ((overrides != null) && overrides.containsKey(expr)) {expr = (String) overrides.get(expr);:Object value = OgnlUtil.getValue(expr, context, root, asType);:}OgnlValueStack.java変数exprはエスケープされているため、OGNL式として評価されてもJavaメソッドは実行されない¥'+@java.lang.Runtime@getRuntime().exec(¥“notepad.exe¥")+¥'StringEscapeUtils::escapeJavaメソッドでエスケープされた値をOgnlUtil::getValueメソッドの引数として渡すことで、OGNL式として評価されてもJavaメソッドは実行されなくなる。32Jspファイル(View) /empmanager/editEmployee.jsp
Copyright©2013 JPCERT/CC All rights reserved.補足今回は数値型への変換エラーの際の処理であったが、それ以外のエラー処理にも同様の脆弱性が存在する可能性がある。Struts2の脆弱性でありながら、その上で動くJAVAアプリケーションの仕様によって影響を受けるかどうかが変わる33
Copyright©2013 JPCERT/CC All rights reserved.まとめ34■この脆弱性から学べるプログラミングの注意点• SQLクエリやHTMLなど、異なる処理系にデータを出力する際には、出力先の処理を考慮した無害化が必要• 無害化を実施しないとSQLインジェクションやクロスサイトスクリプティング等の脆弱性が発生する• 今回はOGNL式にデータを渡す際に、OGNL式として解釈されないような無害化処理を実施していなかったため、脆弱性が発生した■上記への対策•データを出力する際には、出力先でデータがどのように解釈されるかを確認する•出力先でデータが意図しない解釈をされないように適切な無害化を行う
Copyright©2013 JPCERT/CC All rights reserved.著作権・引用や二次利用について本資料の著作権はJPCERT/CCに帰属します。本資料あるいはその一部を引用・転載・再配布する際は、引用元名、資料名および URL の明示をお願いします。記載例引用元:一般社団法人JPCERTコーディネーションセンターJava アプリケーション脆弱性事例解説資料Apache Strus2 における任意の Java メソッド実行の脆弱性https://www.jpcert.or.jp/research/materials-java-casestudies/No.2_Apache_Struts2.pdf本資料を引用・転載・再配布をする際は、引用先文書、時期、内容等の情報を、JPCERT コーディネーションセンター広報(office@jpcert.or.jp)までメールにてお知らせください。なお、この連絡により取得した個人情報は、別途定めるJPCERT コーディネーションセンターの「プライバシーポリシー」に則って取り扱います。本資料の利用方法等に関するお問い合わせJPCERTコーディネーションセンター広報担当E-mail:office@jpcert.or.jp35本資料の技術的な内容に関するお問い合わせJPCERTコーディネーションセンターセキュアコーディング担当E-mail:secure-coding@jpcert.or.jp

Recommended

PDF
ClassLoader Leak Patterns
 
PDF
ログ+メトリック+トレースの組み合わせで構築する一元的なオブザーバビリティ
PPTX
[社内勉強会]ELBとALBと数万スパイク負荷テスト
PDF
UEFIベアメタルプログラミング
PPTX
3D間取りを支える技術
PPTX
優れた研究論文の書き方
PDF
MongoDBの脆弱性診断 - smarttechgeeks
PPTX
CloudFront経由でのCORS利用
PDF
PyConAPAC2023 ワークフローエンジン Apache Airflowを用いた 大規模データパイプライン構築と改善
PDF
Javaはどのように動くのか~スライドでわかるJVMの仕組み
PDF
今から始めるUbuntu入門_202307.pdf
PDF
ドメイン駆動設計 本格入門
PPTX
JAVA_HOME/binにあるコマンド、いくつ使っていますか?[JVM関連ツール編](JJUGナイトセミナー「Java解析ツール特集」 発表資料)
PDF
Spring Bootでチャットツールを作りながらWebの仕組みを理解しよう!
PPTX
A2 SORACOM API使いこなしレシピ集 | SORACOM Technology Camp 2020
PDF
ドメイン駆動設計 ( DDD ) をやってみよう
PDF
ChatGPT + LlamaIndex 0 .6 による チャットボット の実装
PDF
Python 3.9からの新定番zoneinfoを使いこなそう
PPTX
若手エンジニアのためのセキュリティ講座
PDF
Djangoフレームワークのユーザーモデルと認証
PPTX
C#/.NETがやっていること 第二版
PPTX
C#とILとネイティブと
PDF
入社1年目のプログラミング初心者がSpringを学ぶための手引き
PDF
PFN のオンプレML基盤の取り組み / オンプレML基盤 on Kubernetes 〜PFN、ヤフー〜
PPTX
OpenAI FineTuning を試してみる
PDF
ディープラーニングのフレームワークと特許戦争
PDF
スマホアプリ開発者のためのWeb api開発入門の入門
PDF
20200721 AWS Black Belt Online Seminar AWS App Mesh
PDF
例外設計における大罪
PDF
OpenJDKのコミッタってどんなことしたらなったの?解決してきた技術課題の事例から見えてくる必要な知識と技術(JJUG CCC 2023 Spring)

More Related Content

PDF
ClassLoader Leak Patterns
 
PDF
ログ+メトリック+トレースの組み合わせで構築する一元的なオブザーバビリティ
PPTX
[社内勉強会]ELBとALBと数万スパイク負荷テスト
PDF
UEFIベアメタルプログラミング
PPTX
3D間取りを支える技術
PPTX
優れた研究論文の書き方
PDF
MongoDBの脆弱性診断 - smarttechgeeks
PPTX
CloudFront経由でのCORS利用
ClassLoader Leak Patterns
 
ログ+メトリック+トレースの組み合わせで構築する一元的なオブザーバビリティ
[社内勉強会]ELBとALBと数万スパイク負荷テスト
UEFIベアメタルプログラミング
3D間取りを支える技術
優れた研究論文の書き方
MongoDBの脆弱性診断 - smarttechgeeks
CloudFront経由でのCORS利用

What's hot

PDF
PyConAPAC2023 ワークフローエンジン Apache Airflowを用いた 大規模データパイプライン構築と改善
PDF
Javaはどのように動くのか~スライドでわかるJVMの仕組み
PDF
今から始めるUbuntu入門_202307.pdf
PDF
ドメイン駆動設計 本格入門
PPTX
JAVA_HOME/binにあるコマンド、いくつ使っていますか?[JVM関連ツール編](JJUGナイトセミナー「Java解析ツール特集」 発表資料)
PDF
Spring Bootでチャットツールを作りながらWebの仕組みを理解しよう!
PPTX
A2 SORACOM API使いこなしレシピ集 | SORACOM Technology Camp 2020
PDF
ドメイン駆動設計 ( DDD ) をやってみよう
PDF
ChatGPT + LlamaIndex 0 .6 による チャットボット の実装
PDF
Python 3.9からの新定番zoneinfoを使いこなそう
PPTX
若手エンジニアのためのセキュリティ講座
PDF
Djangoフレームワークのユーザーモデルと認証
PPTX
C#/.NETがやっていること 第二版
PPTX
C#とILとネイティブと
PDF
入社1年目のプログラミング初心者がSpringを学ぶための手引き
PDF
PFN のオンプレML基盤の取り組み / オンプレML基盤 on Kubernetes 〜PFN、ヤフー〜
PPTX
OpenAI FineTuning を試してみる
PDF
ディープラーニングのフレームワークと特許戦争
PDF
スマホアプリ開発者のためのWeb api開発入門の入門
PDF
20200721 AWS Black Belt Online Seminar AWS App Mesh
PyConAPAC2023 ワークフローエンジン Apache Airflowを用いた 大規模データパイプライン構築と改善
Javaはどのように動くのか~スライドでわかるJVMの仕組み
今から始めるUbuntu入門_202307.pdf
ドメイン駆動設計 本格入門
JAVA_HOME/binにあるコマンド、いくつ使っていますか?[JVM関連ツール編](JJUGナイトセミナー「Java解析ツール特集」 発表資料)
Spring Bootでチャットツールを作りながらWebの仕組みを理解しよう!
A2 SORACOM API使いこなしレシピ集 | SORACOM Technology Camp 2020
ドメイン駆動設計 ( DDD ) をやってみよう
ChatGPT + LlamaIndex 0 .6 による チャットボット の実装
Python 3.9からの新定番zoneinfoを使いこなそう
若手エンジニアのためのセキュリティ講座
Djangoフレームワークのユーザーモデルと認証
C#/.NETがやっていること 第二版
C#とILとネイティブと
入社1年目のプログラミング初心者がSpringを学ぶための手引き
PFN のオンプレML基盤の取り組み / オンプレML基盤 on Kubernetes 〜PFN、ヤフー〜
OpenAI FineTuning を試してみる
ディープラーニングのフレームワークと特許戦争
スマホアプリ開発者のためのWeb api開発入門の入門
20200721 AWS Black Belt Online Seminar AWS App Mesh

Similar to Apache Struts2 における任意の Java メソッド実行の脆弱性

PDF
例外設計における大罪
PDF
OpenJDKのコミッタってどんなことしたらなったの?解決してきた技術課題の事例から見えてくる必要な知識と技術(JJUG CCC 2023 Spring)
PDF
Apache CommonsのHttpClientに おけるSSLサーバ証明書検証不備 (CVE-2012-5783)
PPTX
セキュアコーディング方法論再構築の試み
PPT
試験にでるSpring
PDF
JBoss Application Server におけるディレクトリトラバーサルの脆弱性
PDF
JRE標準ライブラリの脆弱性事例を理解する (AtomicReferenceArrayクラス と Type Confusion)
PPTX
演習:プログラミング言語処理をやってみよう
PDF
Apache Axis2におけるXML署名検証不備
PPTX
Cve 2013-0422
PDF
Javaセキュアコーディングセミナー東京第1回 講義
PDF
Java/Androidセキュアコーディング
PDF
Unit test in android
PDF
Javaセキュアコーディングセミナー東京第4回講義
PDF
Javaセキュアコーディングセミナー東京第1回演習の解説
PDF
Javaセキュアコーディングセミナー東京第1回 演習
PDF
Apache Sling におけるサービス運用妨害(無限ループ)の脆弱性
PDF
Blojsom におけるクロスサイトスクリプティングの脆弱性
KEY
Java7再入門講座
PDF
レガシーコード改善はじめました 横浜道場
例外設計における大罪
OpenJDKのコミッタってどんなことしたらなったの?解決してきた技術課題の事例から見えてくる必要な知識と技術(JJUG CCC 2023 Spring)
Apache CommonsのHttpClientに おけるSSLサーバ証明書検証不備 (CVE-2012-5783)
セキュアコーディング方法論再構築の試み
試験にでるSpring
JBoss Application Server におけるディレクトリトラバーサルの脆弱性
JRE標準ライブラリの脆弱性事例を理解する (AtomicReferenceArrayクラス と Type Confusion)
演習:プログラミング言語処理をやってみよう
Apache Axis2におけるXML署名検証不備
Cve 2013-0422
Javaセキュアコーディングセミナー東京第1回 講義
Java/Androidセキュアコーディング
Unit test in android
Javaセキュアコーディングセミナー東京第4回講義
Javaセキュアコーディングセミナー東京第1回演習の解説
Javaセキュアコーディングセミナー東京第1回 演習
Apache Sling におけるサービス運用妨害(無限ループ)の脆弱性
Blojsom におけるクロスサイトスクリプティングの脆弱性
Java7再入門講座
レガシーコード改善はじめました 横浜道場

More from JPCERT Coordination Center

PDF
脆弱性事例に学ぶセキュアコーディング「SSL/TLS証明書検証」編 (JavaDayTokyo2015)
PDF
Apache Tomcat における クロスサイトリクエストフォージェリ (CSRF) 保護メカニズム回避の脆弱性
PDF
クロスサイトリクエストフォージェリ(CSRF)とその対策
PDF
Apache ActiveMQにおける認証処理不備の脆弱性(AMQ-1272)
PDF
DLL読み込みの問題を読み解く
PDF
Android Secure Coding
PDF
脆弱性事例に学ぶセキュアコーディング「SSL/TLS証明書検証」編 (KOF2014)
PDF
OWASP ASVS と Cheat Sheet シリーズ (日本語版) のご紹介 (OSC2016Hokkaido)
PDF
Case Studies and Lessons Learned from SSL/TLS Certificate Verification Vulner...
PDF
CERT コーディングスタンダードご紹介 (OSC2017@Osaka)
PDF
脆弱性情報はこうしてやってくる
PDF
デブサミ2015 事例から学ぶAndroidアプリのセキュアコーディング「SSL/TLS証明書検証の現状と対策」
PPTX
Android Platform の URLConnection に HTTP ヘッダインジェクションの脆弱性
PDF
Spacewalkにおけるクロスサイト リクエストフォージェリ(CSRF)の脆弱性
PDF
MySQL Connector/J における SQL インジェクションの脆弱性
PDF
安全なプラグインに必要なこと: 脆弱性届出状況に見る傾向と対策 (WordCampTokyo 2017)
PDF
Lessons (to be) Learned from Handling OpenSSL Vulnerabilities
PDF
ソフトウェアセキュリティ保証成熟度モデル
PDF
いま改めて製品開発者の脆弱性対応について考える ~情報セキュリティ早期警戒パートナーシップを運用する調整機関の視点から~
PDF
WordBench東京 7月勉強会「夏のLT大会!」『WordPress とバックアップの話』
脆弱性事例に学ぶセキュアコーディング「SSL/TLS証明書検証」編 (JavaDayTokyo2015)
Apache Tomcat における クロスサイトリクエストフォージェリ (CSRF) 保護メカニズム回避の脆弱性
クロスサイトリクエストフォージェリ(CSRF)とその対策
Apache ActiveMQにおける認証処理不備の脆弱性(AMQ-1272)
DLL読み込みの問題を読み解く
Android Secure Coding
脆弱性事例に学ぶセキュアコーディング「SSL/TLS証明書検証」編 (KOF2014)
OWASP ASVS と Cheat Sheet シリーズ (日本語版) のご紹介 (OSC2016Hokkaido)
Case Studies and Lessons Learned from SSL/TLS Certificate Verification Vulner...
CERT コーディングスタンダードご紹介 (OSC2017@Osaka)
脆弱性情報はこうしてやってくる
デブサミ2015 事例から学ぶAndroidアプリのセキュアコーディング「SSL/TLS証明書検証の現状と対策」
Android Platform の URLConnection に HTTP ヘッダインジェクションの脆弱性
Spacewalkにおけるクロスサイト リクエストフォージェリ(CSRF)の脆弱性
MySQL Connector/J における SQL インジェクションの脆弱性
安全なプラグインに必要なこと: 脆弱性届出状況に見る傾向と対策 (WordCampTokyo 2017)
Lessons (to be) Learned from Handling OpenSSL Vulnerabilities
ソフトウェアセキュリティ保証成熟度モデル
いま改めて製品開発者の脆弱性対応について考える ~情報セキュリティ早期警戒パートナーシップを運用する調整機関の視点から~
WordBench東京 7月勉強会「夏のLT大会!」『WordPress とバックアップの話』

Apache Struts2 における任意の Java メソッド実行の脆弱性

  • 1.
    Copyright©2013 JPCERT/CC Allrights reserved.「Javaアプリケーション脆弱性事例調査資料」についてこの資料は、Javaプログラマである皆様に、脆弱性を身近な問題として感じてもらい、セキュアコーディングの重要性を認識していただくことを目指して作成しています。「JavaセキュアコーディングスタンダードCERT/Oracle版」と合わせて、セキュアコーディングに関する理解を深めるためにご利用ください。JPCERTコーディネーションセンターセキュアコーディングプロジェクトsecure-coding@jpcert.or.jp1Japan Computer Emergency Response TeamCoordination Center電子署名者 : Japan Computer Emergency Response Team Coordination CenterDN : c=JP, st=Tokyo, l=Chiyoda-ku, email=office@jpcert.or.jp, o=Japan Computer Emergency ResponseTeam Coordination Center, cn=Japan Computer Emergency Response Team Coordination Center日付 : 2013.06.26 10:59:43 +09'00'
  • 2.
    Apache Struts 2における任意のJava メソッド実行の脆弱性CVE-2012-0838JVNDB-2012-0000122
  • 3.
    Copyright©2013 JPCERT/CC Allrights reserved.Apache Struts 2とは Java のWebアプリケーションを開発するためのオープンソースのフレームワーク アプリケーションの開発効率やメンテナンス性を向上させることを目的としている3Apache Struts2JAVAアプリケーションWebサーバークライアント
  • 4.
    Copyright©2013 JPCERT/CC Allrights reserved.Apache Struts 2とは4• Model-View-Controller (MVC)アーキテクチャを採用• アプリケーションの開発者はModelとViewを実装する。Model: ビジネスロジックの実装 (javaで実装)View: 画面デザイン (jspで実装)Controller: クライアントからの入力イベントを処理し、ModelやViewに振り分ける(Struts2で実装).jsp.javaクライアントWebサーバー
  • 5.
    Copyright©2013 JPCERT/CC Allrights reserved.脆弱性の概要—クライアントから送信されてきた文字列の処理で発生するエラーの取り扱いに不備が存在。—具体的には、数値型の変数に対して文字列が送信されてきた際に発生する変換エラー処理。—送信する文字列を細工することで、任意のJavaメソッドが実行可能となる。5
  • 6.
    Copyright©2013 JPCERT/CC Allrights reserved.脆弱性が悪用された場合のリスク任意のJavaメソッドが実行できるため、Runtime::execメソッドを使えばOSコマンドを実行することが可能アプリケーションの外部から、アプリケーションが稼働するサーバ上で任意のコマンドが実行可能となり、サーバを乗っ取られる可能性がある6Runtime::exec()WebサーバJavaメソッド実行!!細工された文字列
  • 7.
    Copyright©2013 JPCERT/CC Allrights reserved.Struts2 内部で変換エラーが発生した場合の処理7※Struts2付属のサンプルアプリ「showcase」を元に処理を解説する① クライアントから、エラーの原因となる文字列を含むリクエストが送信される。② Struts上で、文字列→数値に変換する際にエラーが発生し、エラー(例外)処理を行う。③ エラー処理で、変換エラーの原因となった文字列が保持される。④ jsp側からエラーの原因となった文字列が取り出され、レスポンスの一部としてクライアントへ送信される。HelloWorldLong型 empId エラー値HelloWorld.jspエラー値HelloWorldHelloWorldエラーempIdは数値ですHelloWorldempId= HelloWorld① ②③④クライアントエラー発生!
  • 8.
    Copyright©2013 JPCERT/CC Allrights reserved.8private Long empId;:public Long getEmpId() {return empId;}:<s:textfield label="Employee Id"name="currentEmployee.empId"/>:Javaファイル(Model)/showcase/action/EmployeeAction.javaJspファイル(View)/empmanager/editEmployee.jsp変数empIdをModel(.java)から取得して表示する。数値型(Long)の変数empIdが存在し、クライアントから送信されたパラメータempIdの値が格納される数値型の変数empIdに対して文字列を送信するとエラーが発生する。クライアントからのリクエストサンプルアプリ「showcase」
  • 9.
    Copyright©2013 JPCERT/CC Allrights reserved.①クライアントからエラーの原因となる文字列を含むリクエストが送信される9GET /?empId=HelloWorld HTTP/1.1Host: localhost:8080<form action=‘/’ method=‘GET’>:<input type=‘text’ name=‘empId’ value=‘HelloWorld’>:</form>HTTPリクエスト上記HTTPリクエストを送信するためのHTMLパラメータempIdの値として”HelloWorld”という文字列を送信する。(empIdはサーバ側では数値型として扱われることに注意。)empId= HelloWorld①クライアント
  • 10.
    Copyright©2013 JPCERT/CC Allrights reserved.②文字列→数値に変換する際にエラー発生、エラー(例外)処理を行う10public class ConversionErrorInterceptor extends AbstractInterceptor {:public String intercept(ActionInvocation invocation) throws Exception {:クライアントから送信されてきたパラメータempIdの値”HelloWorld”を、数値型変数empIdに対して挿入する際に変換エラーが発生し、エラー処理が行われる。変換エラー処理はConversionErrorInterceptorクラスのinterceptメソッド内でエラー例外処理が行われる。ConversionErrorInterceptor.javaHelloWorldLong型 empId②
  • 11.
    Copyright©2013 JPCERT/CC Allrights reserved.③エラー処理で、変換エラーの原因となった文字列が保持される11public class ConversionErrorInterceptor extends AbstractInterceptor {:public String intercept(ActionInvocation invocation) throws Exception {:HashMap<Object, Object> fakie = null;:String propertyName = (String) entry.getKey();Object value = entry.getValue();:fakie.put(propertyName, getOverrideExpr(invocation, value));:ConversionErrorInterceptor.javaエラーとなった変数名が<クラス名.変数名>という形式で取得され、変数propertyNameに格納される。currentEmployee.empId
  • 12.
    Copyright©2013 JPCERT/CC Allrights reserved.12public class ConversionErrorInterceptor extends AbstractInterceptor {:public String intercept(ActionInvocation invocation) throws Exception {:HashMap<Object, Object> fakie = null;:String propertyName = (String) entry.getKey();Object value = entry.getValue();:fakie.put(propertyName, getOverrideExpr(invocation, value));:変数valueには変換エラーとなった文字列の値が代入される。“HelloWorld”③エラー処理で、変換エラーの原因となった文字列が保持されるConversionErrorInterceptor.java
  • 13.
    Copyright©2013 JPCERT/CC Allrights reserved.13public class ConversionErrorInterceptor extends AbstractInterceptor {:public String intercept(ActionInvocation invocation) throws Exception {:HashMap<Object, Object> fakie = null;:String propertyName = (String) entry.getKey();Object value = entry.getValue();:fakie.put(propertyName, getOverrideExpr(invocation, value));:protected Object getOverrideExpr(ActionInvocation invocation, Object value) {return "'" + value + "'";}getOverrideExprメソッドgetOverrideExprメソッドでは第2引数を’(シングルクオート)で囲って返却する処理を行う“HelloWorld”‘HelloWorld’③エラー処理で、変換エラーの原因となった文字列が保持されるConversionErrorInterceptor.java
  • 14.
    Copyright©2013 JPCERT/CC Allrights reserved.14public class ConversionErrorInterceptor extends AbstractInterceptor {:public String intercept(ActionInvocation invocation) throws Exception {:HashMap<Object, Object> fakie = null;:String propertyName = (String) entry.getKey();Object value = entry.getValue();:fakie.put(propertyName, getOverrideExpr(invocation, value));:getOverrideExpr関数を介した後の値は、変数propertyNameとセットでHashMap変数fakieに代入される。fakie:currentEmployee.empId : ‘HelloWorld’:currentEmployee.empId‘HelloWorld’③エラー処理で、変換エラーの原因となった文字列が保持されるConversionErrorInterceptor.java
  • 15.
    Copyright©2013 JPCERT/CC Allrights reserved.15public class ConversionErrorInterceptor extends AbstractInterceptor {:public String intercept(ActionInvocation invocation) throws Exception {:fakie.put(propertyName, getOverrideExpr(invocation, value));:invocation.getStack().setExprOverrides(fakie);public void setExprOverrides(Map overrides) {if (this.overrides == null) {this.overrides = overrides;}OgnlValueStack.javaエラー値を含む変数fakieはOgnlValueStackクラスのインスタンス変数overridesとして保持される。:currentEmployee.empId :‘HelloWorld’fakiefakie:currentEmployee.empId : ‘HelloWorld’:③エラー処理で、変換エラーの原因となった文字列が保持されるConversionErrorInterceptor.java
  • 16.
    Copyright©2013 JPCERT/CC Allrights reserved.④Jsp側からエラーの文字列が取り出され、レスポンスとしてクライアントへ送信する。Jspに記述されたコード(OGNL式)にしたがって、変数empIdの値が取得される。 OGNLとは⇒Object-Graph Navigation Language (OGNL) OGNLはJavaのクラス(Model)の変数を設定/取得するための言語 サンプルコードのjspに記載されたOGNL式は、変数currentEmployee.empIdの値を取得して表示をする式 下記のような表記で直接Javaメソッドを呼び出すことも可能::<s:textfield label="Employee Id" name="currentEmployee.empId"/>:Jspファイル(View)/empmanager/editEmployee.jsp<property name="roots">@java.io.File@listRoots()</property>16
  • 17.
    Copyright©2013 JPCERT/CC Allrights reserved.④Jsp側からエラーの文字列が取り出され、レスポンスとしてクライアントへ送信する。Jspに記述されたOGNL式にしたがって、OgnlValueStack.findValueメソッドを経由して変数currentEmployee.empId の値(エラーとなった文字列)が取得される。::<s:textfield label="Employee Id" name="currentEmployee.empId"/>:Jspファイル(View) /empmanager/editEmployee.jsppublic Object findValue(String expr, Class asType) {:if ((overrides != null) && overrides.containsKey(expr)) {expr = (String) overrides.get(expr);:Object value = OgnlUtil.getValue(expr, context, root, asType);:}OgnlValueStack.javaTextFieldTag.doEndTag()TextField.end()TextField.evaluateParams()TextField.findValue()TextParseUtil.translateVariables()TextParseUtil.translateVariables()TextParseUtil.translateVariables()OgnlValueStack.findValue()経由する関数currentEmployee.empId17
  • 18.
    Copyright©2013 JPCERT/CC Allrights reserved.④Jsp側からエラーの文字列が取り出され、レスポンスとしてクライアントへ送信する。::<s:textfield label="Employee Id" name="currentEmployee.empId"/>:public Object findValue(String expr, Class asType) {:if ((overrides != null) && overrides.containsKey(expr)) {expr = (String) overrides.get(expr);:Object value = OgnlUtil.getValue(expr, context, root, asType);:}前述の変数overridesから、変数exprとセットの値(エラーが発生する原因となった文字列)がとりだされる。‘HelloWorld’fakie‘HelloWorld’currentEmployee.empId:currentEmployee.empId :‘HelloWorld’18OgnlValueStack.javaTextFieldTag.doEndTag()TextField.end()TextField.evaluateParams()TextField.findValue()TextParseUtil.translateVariables()TextParseUtil.translateVariables()TextParseUtil.translateVariables()OgnlValueStack.findValue()経由する関数Jspに記述されたOGNL式にしたがって、OgnlValueStack.findValueメソッドを経由して変数currentEmployee.empId の値(エラーとなった文字列)が取得される。Jspファイル(View) /empmanager/editEmployee.jsp
  • 19.
    Copyright©2013 JPCERT/CC Allrights reserved.④Jsp側からエラーの文字列が取り出され、レスポンスとしてクライアントへ送信する。::<s:textfield label="Employee Id" name="currentEmployee.empId"/>:public Object findValue(String expr, Class asType) {:if ((overrides != null) && overrides.containsKey(expr)) {expr = (String) overrides.get(expr);:Object value = OgnlUtil.getValue(expr, context, root, asType);:}変数exprの値はOgnlUtil::getValueメソッドにてOGNL式として評価された後にクライアントに返却される。‘HelloWorld’fakieOGNL:currentEmployee.empId :‘HelloWorld’文字列’HelloWorld’はOGNL式として意味を持たないため、’HelloWorld’のまま19TextFieldTag.doEndTag()TextField.end()TextField.evaluateParams()TextField.findValue()TextParseUtil.translateVariables()TextParseUtil.translateVariables()TextParseUtil.translateVariables()OgnlValueStack.findValue()経由する関数OgnlValueStack.javaJspファイル(View) /empmanager/editEmployee.jspJspに記述されたOGNL式にしたがって、OgnlValueStack.findValueメソッドを経由して変数currentEmployee.empId の値(エラーとなった文字列)が取得される。
  • 20.
    Copyright©2013 JPCERT/CC Allrights reserved.Javaファイル(Model)Jspファイル(View)Jspに記述されたOGNL式では、OgnlValueStack.findValueメソッドによってJava(Model)の処理結果を取得後、必ずOgnlUtil.getValueメソッドによってOGNL式による評価が行われる。処理OgnlUtil.getValueメソッドによるOGNL式の評価Model(Java)による処理が・・・• 正常処理の場合 → 正常値• エラー処理の場合 → エラー値が保持されるクライアント処理結果処理後の値OgnlValueStack.findValue()リクエストHello WorldJava(Model)側の処理後の値を取得後、Java(Model)側の処理がエラーかどうかに関わらず、必ずOGNL式として評価される。①②③20④Jsp側からエラーの文字列が取り出され、レスポンスとしてクライアントへ送信する。
  • 21.
    Copyright©2013 JPCERT/CC Allrights reserved.④Jsp側からエラーの文字列が取り出され、レスポンスとしてクライアントへ送信する21レスポンスがクライアントに返される。クライアント上ではエラーメッセージが表示される。
  • 22.
    Copyright©2013 JPCERT/CC Allrights reserved.攻撃コード22■攻撃コードのポイントパラメーターempIdに対し、JavaメソッドであるgetRuntime.execでコマンドを実行するOGNL式を指定している。GET /?empId='%2B@java.lang.Runtime@getRuntime().exec(“notepad.exe")%2B' HTTP/1.1Host: localhost:8080<form action=‘/’ method=‘GET’>:<input type=‘hidden’ name=‘empId’value="'+@java.lang.Runtime@getRuntime().exec(&quot;notepad.exe&quot;)+'">:</form>攻撃コードのHTTPリクエスト攻撃コードのHTTPリクエストを送信するためのHTML
  • 23.
    Copyright©2013 JPCERT/CC Allrights reserved.変換エラーが発生した際の処理フロー※Struts2に付属しているサンプルアプリ「showcase」を元に処理を解説する① クライアントから、エラーの原因となる文字列を含むリクエストが送信される。② Struts上で、文字列→数値に変換する際にエラーが発生し、エラー(例外)処理を行う。③ エラー処理で、変換エラーの原因となった文字列が保持される。④ Jsp側からエラーの原因となった文字列が取り出され、レスポンスの一部としてクライアントへ送信される。攻撃コードが実行された際の処理23攻撃コードが実行された際でも処理のフローは正常処理と全く変わらないが、④の処理内容で違いが発生する。
  • 24.
    Copyright©2013 JPCERT/CC Allrights reserved.攻撃コード実行時④Jsp側からエラーの文字列が取り出され、レスポンスとしてクライアントへ送信するJspの内容にしたがって、変数empIdの値が取得され、エラーの原因となった文字列が返されるが・・・::<s:textfield label="Employee Id" name="currentEmployee.empId"/>:public Object findValue(String expr, Class asType) {:if ((overrides != null) && overrides.containsKey(expr)) {expr = (String) overrides.get(expr);:Object value = OgnlUtil.getValue(expr, context, root, asType);:}OgnlValueStack.java前述の変数overridesから、エラーが発生した原因となる文字列が変数exprにとりだされる。: fakie'+@java.lang.Runtime@getRuntime().exec(“notepad.exe")+'24Jspファイル(View) /empmanager/editEmployee.jsp
  • 25.
    Copyright©2013 JPCERT/CC Allrights reserved.25public Object findValue(String expr, Class asType) {:if ((overrides != null) && overrides.containsKey(expr)) {expr = (String) overrides.get(expr);:Object value = OgnlUtil.getValue(expr, context, root, asType);:}変数exprがOGNL式として評価される際にJavaメソッドが実行されてしまう!!'+@java.lang.Runtime@getRuntime().exec(“notepad.exe")+'25OgnlValueStack.java::<s:textfield label="Employee Id" name="currentEmployee.empId"/>:攻撃コード実行時④Jsp側からエラーの文字列が取り出され、レスポンスとしてクライアントへ送信するJspの内容にしたがって、変数empIdの値が取得され、エラーの原因となった文字列が返されるが・・・Jspファイル(View) /empmanager/editEmployee.jsp
  • 26.
    Copyright©2013 JPCERT/CC Allrights reserved.問題点 今回のアプリケーションにおける具体的な問題点引数をOGNL式として評価するOgnlUtil::getValueメソッドに対し、無害化していないデータを渡してしまっていた。26以下のコーディングガイドに違反している!!「 IDS00-J. 信頼境界を越えて渡される信頼できないデータは無害化する」 問題点に対してどうすべきだったか。OgnlUtil::getValueメソッドの引数として渡す前に、データがOGNL式として解釈されないように無害化する必要があった。
  • 27.
    Copyright©2013 JPCERT/CC Allrights reserved.変換エラーが発生した際の処理フロー※Struts2付属のサンプルアプリ「showcase」を元に処理を解説する① クライアントから、エラーの原因となる文字列を含むリクエストが送信される。② Struts上で、文字列→数値に変換する際にエラーが発生し、エラー(例外)処理を行う。③ エラー処理で、変換エラーの原因となった文字列が保持される。④ Jsp側からエラーの原因となった文字列が取り出され、レスポンスの一部としてクライアントへ送信される。修正版コード: バージョン2.2.3.1で修正27この処理のコードに修正が入っているHelloWorldLong型 empId エラー値HelloWorld.jspエラー値HelloWorldHelloWorldエラーempIdは数値ですHelloWorldempId= HelloWorld① ② ③ ④
  • 28.
    Copyright©2013 JPCERT/CC Allrights reserved.修正版コード: 脆弱バージョンのおさらい28public class ConversionErrorInterceptor extends AbstractInterceptor {:public String intercept(ActionInvocation invocation) throws Exception {:HashMap<Object, Object> fakie = null;:Object value = entry.getValue();:fakie.put(propertyName, getOverrideExpr(invocation, value));:ConversionErrorInterceptor.java変数valueには変換エラーとなった入力値が代入される。“HelloWorld”③エラー処理で、変換エラーの原因となった文字列が保持される
  • 29.
    Copyright©2013 JPCERT/CC Allrights reserved.29public class ConversionErrorInterceptor extends AbstractInterceptor {:public String intercept(ActionInvocation invocation) throws Exception {:HashMap<Object, Object> fakie = null;:Object value = entry.getValue();:fakie.put(propertyName, getOverrideExpr(invocation, value));:protected Object getOverrideExpr(ActionInvocation invocation, Object value) {return "'" + value + "'";}変数valueはgetOverrideExpr関数を介してHashMap変数fakieに代入される。getOverrideExprメソッドgetOverrideExprメソッドでは第2引数を’(シングルクオート)で囲って返却する処理を行う“HelloWorld”fakie:‘HelloWorld’:修正版コードではgetOverrideExprメソッドに修正が加えられている。ConversionErrorInterceptor.java修正版コード: 脆弱バージョンのおさらい③エラー処理で、変換エラーの原因となった文字列が保持される
  • 30.
    Copyright©2013 JPCERT/CC Allrights reserved.修正版コード: getOverrideExprメソッドの修正内容30protected Object getOverrideExpr(ActionInvocation invocation, Object value) {return "'" + value + "'";}getOverrideExprメソッド(修正前)protected Object getOverrideExpr(ActionInvocation invocation, Object value) {return "¥"" + StringEscapeUtils.escapeJava(String.valueOf(value)) + "¥"";}getOverrideExprメソッド(修正後)StringEscapeUtils.escapeJavaメソッドを使ってエスケープ処理を行っている。getOverrideExprメソッドでは第2引数を’(シングルクオート)で囲って返却する処理を行う③エラー処理で、変換エラーの原因となった文字列が保持される
  • 31.
    Copyright©2013 JPCERT/CC Allrights reserved.修正版コード: StringEscapeUtils.escapeJavaメソッドによるエスケープ31• StringEscapeUtils.escapeJavaメソッドによるエスケープ処理エスケープ対象文字列 エスケープ処理後の文字列¥b ¥¥b¥n ¥¥n¥t ¥¥t¥f ¥¥f¥r ¥¥r‘(シングルクオート) ¥’“(ダブルクオート) ¥”¥ ¥¥/ ¥/■攻撃コードで送信される値がエスケープされると・・・・'%2B@java.lang.Runtime@getRuntime().exec(“notepad.exe")%2B'↓¥'%2B@java.lang.Runtime@getRuntime().exec(¥“notepad.exe¥")%2B¥'⇒OGNL式として解釈されない文字列にエスケープされる。
  • 32.
    Copyright©2013 JPCERT/CC Allrights reserved.修正版コード: エスケープ実施後のOgnlUtil::getValueメソッドの動作32::<s:textfield label="Employee Id" name="currentEmployee.empId"/>:public Object findValue(String expr, Class asType) {:if ((overrides != null) && overrides.containsKey(expr)) {expr = (String) overrides.get(expr);:Object value = OgnlUtil.getValue(expr, context, root, asType);:}OgnlValueStack.java変数exprはエスケープされているため、OGNL式として評価されてもJavaメソッドは実行されない¥'+@java.lang.Runtime@getRuntime().exec(¥“notepad.exe¥")+¥'StringEscapeUtils::escapeJavaメソッドでエスケープされた値をOgnlUtil::getValueメソッドの引数として渡すことで、OGNL式として評価されてもJavaメソッドは実行されなくなる。32Jspファイル(View) /empmanager/editEmployee.jsp
  • 33.
    Copyright©2013 JPCERT/CC Allrights reserved.補足今回は数値型への変換エラーの際の処理であったが、それ以外のエラー処理にも同様の脆弱性が存在する可能性がある。Struts2の脆弱性でありながら、その上で動くJAVAアプリケーションの仕様によって影響を受けるかどうかが変わる33
  • 34.
    Copyright©2013 JPCERT/CC Allrights reserved.まとめ34■この脆弱性から学べるプログラミングの注意点• SQLクエリやHTMLなど、異なる処理系にデータを出力する際には、出力先の処理を考慮した無害化が必要• 無害化を実施しないとSQLインジェクションやクロスサイトスクリプティング等の脆弱性が発生する• 今回はOGNL式にデータを渡す際に、OGNL式として解釈されないような無害化処理を実施していなかったため、脆弱性が発生した■上記への対策•データを出力する際には、出力先でデータがどのように解釈されるかを確認する•出力先でデータが意図しない解釈をされないように適切な無害化を行う
  • 35.
    Copyright©2013 JPCERT/CC Allrights reserved.著作権・引用や二次利用について本資料の著作権はJPCERT/CCに帰属します。本資料あるいはその一部を引用・転載・再配布する際は、引用元名、資料名および URL の明示をお願いします。記載例引用元:一般社団法人JPCERTコーディネーションセンターJava アプリケーション脆弱性事例解説資料Apache Strus2 における任意の Java メソッド実行の脆弱性https://www.jpcert.or.jp/research/materials-java-casestudies/No.2_Apache_Struts2.pdf本資料を引用・転載・再配布をする際は、引用先文書、時期、内容等の情報を、JPCERT コーディネーションセンター広報(office@jpcert.or.jp)までメールにてお知らせください。なお、この連絡により取得した個人情報は、別途定めるJPCERT コーディネーションセンターの「プライバシーポリシー」に則って取り扱います。本資料の利用方法等に関するお問い合わせJPCERTコーディネーションセンター広報担当E-mail:office@jpcert.or.jp35本資料の技術的な内容に関するお問い合わせJPCERTコーディネーションセンターセキュアコーディング担当E-mail:secure-coding@jpcert.or.jp

[8]ページ先頭

©2009-2025 Movatter.jp