React.jsで起こるXSS (advent calendar 12日目の話)
[追記]この記事は情報が古めです。Reactで起こるXSSパターンは他にも存在するので、CTFやbug bountyなどの言葉と一緒に検索してみてください。
この記事は脆弱性"&'<<>\ Advent Calendar 2016の13日目の記事です。
前日の記事はnull
です。
この記事を見ている皆さんは仮想DOMに魂を震わせられているでしょうか*1、それともjavascriptに疲れてきた頃でしょうか。私はimagemagick関連を調べるのに疲れてきたところです。
React.jsで起こるXSS
ここ数年のwebサービスではReact.jsのような仮想DOMを扱うライブラリを使ってhtmlがレンダリングされていることが多いので、典型的なDOM Based XSSなどは少なくなってきたように感じます*2。React.jsを例にすると、JSXがjsに変換されて仮想DOM経由でDOMを組み立てるので、テンプレートなどからHTMLの文字列組立時にエスケープ漏れになるケースが少なくなったということですね。クライアント側をReact.jsのような仮想DOM、サーバ側ではjsonだけを作る構成にするとXSSのややこしいことを考えることが減って随分と楽になります。
それでもXSSが起こるパターンが有りまして、私が把握しているのは以下の2つのケースです。(細かいことを書くとeval()
やnew Function
とか色々ありますが)
後者はIE特有の動作としてcssのexpression()
経由でjavascriptが呼べるものです。IEについては詳しくないので、IE11であっても互換モードなどを指定せずに動くのかは把握できていません。CSS in JSとかでユーザからの入力をstyleで扱っているケースでは問題になるかもしれません。そんなコードを作る機会もあまりなさそうですが。
advent calendar 12日目の話
http://www.adventar.org/calendars/1404#list-2016-12-12
advent calendar 12日目で書いたのは前者のjavascript schemeのパターンでした。(参考: クロスサイトスクリプティング対策 ホンキのキホン - 葉っぱ日記)
記事のURLを入力する部分で、単にjavascript:...
と入力すると保存できないのですが、後ろに//https://...
とついていると保存できました。
現在は修正されていてこのパターンでは保存できません。昨日の日付が変わったあたりにadventarの作者の一人である @hokaccha さんにtwitterで報告した所、朝にはもう修正されていました*3。出力時のエスケープではなく、入力時のバリデーションによって防がれているため、すでに入力されている12日目のリンクはそのまま変わらず出力されています。
React.jsでもこういったパターンが有るのは知っていましたが、実際に刺さるのは初めてです。今回の場合はリンクのURL自体も表示されていますし、実際問題として(修正前も)あまり悪いこともできないので12日目のリンクはそのままにしています。
このXSSのパターンではユーザがクリックしないと発火しませんが、クリックジャッキングを使うかまたはステータスバーの偽装によって誘導するなどが考えられます。chromeでの例 xss *4
*1:http://qiita.com/mizchi/items/4d25bc26def1719d52e6
*2:単に使用されるjQueryのバージョンが上がったなどもあります
cookie経由のXSSの話 脆弱性"&'<<>\ Advent Calendar 2016 (4日目)
この記事は脆弱性"&'<<>\ Advent Calendar 2016の4日目の記事です。
前日の記事はHack Patch!: CyVDB-1118関連です。
今回の記事は、eval(document.cookie)
になるようなことは避けましょうという内容です。
cookie 経由でのXSSについて。
cookieに値を入れるにはサーバサイドからのレスポンスヘッダーかjavascriptからの操作になります。XSSなどがない限り攻撃者が値を入れることはできなそうですが、以下のような条件により可能です。
特にHTTP通信から攻撃する方法は徳丸先生の記事によるものが詳しく(HTTPSを使ってもCookieの改変は防げないことを実験で試してみた | 徳丸浩の日記)、これを防ぐためにはHSTSをサイト全体に設定する他ない状況となっています。
eval(document.cookie)
と等価になるような実装がされていることはあまり多くないのですが、たまーに見かけるのが現状です。
別サブドメインからのXSS事例
レアケースかと思われますが、数年前に別サブドメインからcookieを経由してXSSが可能だったケースを見つけたことがありました。
某植物系レンタルサーバさんのあるサーバ管理画面にてこんなコードが有りました。(変数名などは念のため変えています。)
var param = $.cookie('cookie_name'); ... ... $('.class_'+param).attr('checked', true);
一見すると問題があるようには見えませんが、XSSが可能です。というのもjQueryの古いバージョンでは$(.class_<img onerror=alert(1) src=.>)
で、DOM Based XSSが発火するためです。(jQuery Migrate Plugin なんてなかった件 - ほむらちゃほむほむ)
ここ数年はjQuery 1.10以上が使われることが多いためjQuery由来の問題は減ってきていますが、画面の作成時期によっては古いjQueryがそのまま使われています。
さて、このままでもMITMによって攻撃可能ですが他の攻撃方法がないかを探してみました。その結果、サーバ管理画面のドメインxxx.jp
の別サブドメイン、blog.xxx.jp
にてDOM Based XSSを見つけました。こちらもjQuery由来の問題でprettyPhoto
というjQuery pluginが脆弱性がある状態で使用されており、細工したURLにアクセスするとXSSが可能な状態でした。
組み合わせると、以下の手順でサーバの管理画面に攻撃することができました。
blog.xxx.jp
にXSSを含むURLをターゲットにアクセスさせる- javascriptから
cookie_name=<img onerror=alert(location.href) src=.>
のようなクッキーを発行する xxx.jp
にリダイレクトさせるxxx.jp
で$(.class_<img onerror=alert(1) src=.>)
が評価されてXSSが発火
eval(document.cookie)
と等価な部分があると別ドメインのXSSにひきずられることがあり、普通のXSSよりも気づにくい状態となります。cookieのセキュリティーポリシーがscheme+domain+portではないことに由来する問題ですね。
幸いサーバ管理画面の方は報告後すぐに修正されていました。
攻撃を受けにくくするために
この攻撃を発見して以降、念のため重要度が高いドメインではそのときだけシークレットウィンドウを開いて操作することを推奨しています。cookieやlocalStorageによる攻撃、CSRF、ブラウザ拡張機能による影響を受けにくくなります。
evernote.comにあったDOM Based XSS
先日evernote.comのコードを見ていたら変わった箇所を見つけまして
url中にstage
が含まれているときだけ実行される処理です。試しに実際に実行してみるとステージング環境であることを示す警告文が表示されます。
コード中で変数j
にdocument.URL
の値が代入されていますが、この値がエスケープされずにhtmlが組み立てられています。document.URL
(やlocation.href
)の値がパーセントエンコードされているかはブラウザによって違いまして、chromeからアクセスしてやるとこうなります。
XSSですね。
evernoteは脆弱性情報窓口が設けられいる( セキュリティ問題の報告 | Evernote)のでそちらから報告しました。次の日には返答があって、数日後には修正がリリースされていました。
WordPress pluginのCSRF脆弱性(CVE-2015-0895) "&'<<>\ Advent Calendar 2015 (14日目)
この記事は脆弱性"&'<<>\ Advent Calendar 2015の14日目の記事です。
前日の記事はWordPress のsecurity系plugin の Blind SQL injection 脆弱性(CVE-2015-0894) "&'<<>\ Advent Calendar 2015 (13日目) - ooooooo_qの日記です。今日は連続してCVE-2015-0895です。
脆弱性内容
違うCVEが割り振られていますが、報告したのはCVE-2015-0894と同じpluginで、WordPress › All In One WP Security & Firewall « WordPress Pluginsです。
昨日書いた記事の中で、クエリパラメータを受け取ってDELETE文が発行されている箇所がありますが、その際リクエスト元のチェックなどはされていません。
GETでアクセス時にDELETEが発行されるようなURLが存在していると検索エンジンのbotに拾われて、勝手に削除されてしまうなんて話もありますが、この場合はログインが必要なのでそうはなりません。しかし、ログインユーザが以下の様なURLにアクセスしてしまうとテーブルの中身が全部消えてしまいます。
/wp-admin/admin.php?page=aiowpsec_firewall&tab=tab6&action=delete&item[0]=) or 1=1
対象はplugin内で使っているテーブルのみなので、それほど影響は大きくないのですがあまり良くはないですね。