XSS gameを解いた
2020年ももう残り3日ですが、実家に帰るわけでもなくやるべきことも特にないので...XSSの復習も兼ねて解いてみました(初見)
Level1
https://xss-game.appspot.com/level1
開いてみると、Googleみたいな見た目をした入力フォーム付きのページがあった。
Inject a script to pop up a JavaScript alert() in the frame below.
Once you show the alert you will be able to advance to the next level.
とりあえずHelloと入力して"search"ボタンをクリックしてみた↓
右クリックして、”フレームのソースを表示”をクリック
<!doctype html> <html> <head> <!-- Internal game scripts/styles, mostly boring stuff --> <script src="/static/game-frame.js"></script> <link rel="stylesheet" href="/static/game-frame-styles.css" /> </head> <body id="level1"> <img src="/static/logos/level1.png"> <div> Sorry, no results were found for <b>Hello</b>. <a href='?'>Try again</a>. </div> </body> </html>
入力した文字列をbタグで太字にしているだけっぽい。そこで試しにフォームに<h1>Hello</h1>と入力してみると、今度はh1タグでHelloが表示された。
ということは<script>alert();</script>と入力すればいけそうだなって思って、試すと
解けたっぽい。
Level2
https://xss-game.appspot.com/level2/frame
今回もalert()を挿入してポップアップを表示させるのがゴール。
そして標的にするのはチャットサービス。
今回もHelloと入力して投稿。その後h1タグをつけて再度投稿。
前問の流れのままに"<script>alert();</script>”を試したけれども、今回は空欄になって出力されてしまった。
ここで初めてソースを確認。
html += "<blockquote>" + posts[i].message + "</blockquote";
内容を引用符で囲むという典型的なやり方でXSS回避している。
しかし、エスケープ処理などはしていない様子。
ということで、XSSでよく使われるonerrorを使って<img src=1 onerror=”alert()”>として投稿したら、次のレベルに進めるようになった。
Level3
https://xss-game.appspot.com/level2/
今回のターゲットページには、Image1,Image2,Image3の3つのタブがあって、クリックするとそれぞれ画像を1枚表示する。
タブをクリックすると、URLが
https://xss-game.appspot.com/level3/frame#1
https://xss-game.appspot.com/level3/frame#2
https://xss-game.appspot.com/level3/frame#3
という風に変化しているので、URLを使った方法とアタリをつけつつソースをみる。
<div class="tab" id="tab1" onclick="chooseTab('1')">Image 1</div>
chooseTab関数の引数によって表示画像を決めていることがわかった。
そこでchooseTab関数を眺めてみる。目をつけたのは次の一文。
<img src='/static/level3/cloud" + num + ".jpg' />
numはchooseTab()の引数で、特別な文字列処理なども特に行っていない。
ということでURLの#以降に以下の文を挿入した。
1'><img src=X onerror="alert()">'
すると
解けた。SQLインジェクションっぽさを感じた。
( 1'><img src=X onerror="alert()">'という複雑な文になってるけれど、<と>をそれぞれエスケープシーケンス: < と> に置き換えているだけです)
Level4
https://xss-game.appspot.com/level4/
今度は、タイマーサイト。整数を入力してから"Create timer"ボタンをクリックし、待機すると、設定秒数後にポップアップが出てきて時間経過を知らせてくれる。
待機中は、URLが以下のようになっている (3を設定した)
https://xss-game.appspot.com/level4/frame?timer=3
5.55と設定してからソースを見てみる
<script> function startTimer(seconds) { seconds = parseInt(seconds) || 3; setTimeout(function() { window.confirm("Time is up!"); window.history.back(); }, seconds * 1000); } </script> 〜略〜 <img src="/static/loading.gif" onload="startTimer('5.55') || alert() ||');" />
入力値をstartTimer(seconds)に渡して、それを seconds = parseInt(seconds) として処理している。前問と同じやり口でalert()をねじ込む。つまりフォームには 3'); alert(' と入力する。
Level5
https://xss-game.appspot.com/level5/
とあるサービスのβ版ページ。まずはsignUPページに飛ぶよう指示があるので、飛んでみるとe-mail入力フォームが登場する。文字列を入力して"Next>>"ボタンをクリックすると、確認ページに飛んで、その後数秒待ってリダイレクトという流れ。
気になったのがe-mail入力画面のURL。
https://xss-game.appspot.com/level5/frame/signup?next=confirm
nextというパラメータがあってconfirmが指定されており、ここを利用すれば攻撃できそうな感じがする。ちょっと調べたら JavaScript疑似プロトコルというものが出てきて、どうやらアドレスバーからjavascriptを簡単に実行できる仕組みらしい。
ということで、以下のようにURLを指定する。
https://xss-game.appspot.com/level5/frame/signup?next=javascript:alert('');
解けた。
Level6
https://xss-game.appspot.com/level6/
最後の問題。
Find a way to make the application request an external file which will cause it to execute an alert().
外部のjavascriptファイルを実行しろと言われてる。ターゲットとなるサイトには特に入力フォームもなく、”Loaded gadget from /static/gadget.js”という一文が書いてあるのみ。ここでURLをみるとhttps://xss-game.appspot.com/level6/frame#/static/gadget.jsとなっていることから、「もしかしたらURLの#以下で指定したファイルを実行してくれると言うことでは?」と容易に予想を立てられる。
となると次にやるべきは「alert()の一文だけ書いたjavascriptのファイルをどこかに保存し、それを読み込ませる」ということだが、何かめんどくさそうだから別の方法を探す。根気強く20-30分くらい調べていると「data URI Scheme」というものを見つけることができた。
データURIスキーム(英語: data URI scheme)とは、あたかも外部リソースを読み込むのと同じように、ウェブページにインラインにデータを埋めこむ手段を提供するURIスキームである。
要は「alert()の一文だけ書いたjavascriptのファイルをどこかに保存し、それを読み込ませる」なんてことしなくても、URLだけで同じようなことができますよということ(多分)。試しに data:text/javascript,alert('');という一文をアドレスバーに打ち込んでみると、"alert()"と書かれたページに飛んだ。これは使えそう。
とりあえずターゲットページに戻って、URLの#以下の部分を上記に書き換えてみる。
するとこの通り、うまくいった。
ということで無事全て解き終えることができた。
基礎的な部分を復習しつつ、新たな知見も得られたのでよかった。