雑記

いち情報系大学生

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"ボタンをクリックしてみた↓
f:id:unyamahiro:20201229102325p:plain

右クリックして、”フレームのソースを表示”をクリック

<!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>と入力すればいけそうだなって思って、試すと
f:id:unyamahiro:20201229104936p:plain

解けたっぽい。



Level2
https://xss-game.appspot.com/level2/frame

今回もalert()を挿入してポップアップを表示させるのがゴール。
そして標的にするのはチャットサービス。

今回もHelloと入力して投稿。その後h1タグをつけて再度投稿。
f:id:unyamahiro:20201229115438p:plain

前問の流れのままに"<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()">'

すると
f:id:unyamahiro:20201229130733p:plain

解けた。SQLインジェクションっぽさを感じた。
( 1'&gt;&lt;img src=X onerror="alert()"&gt;'という複雑な文になってるけれど、<と>をそれぞれエスケープシーケンス: &lt と&gt に置き換えているだけです)



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(' と入力する。
f:id:unyamahiro:20201229140308p:plain



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('');

f:id:unyamahiro:20201229142626p:plain

解けた。



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の#以下の部分を上記に書き換えてみる。
f:id:unyamahiro:20201229151711p:plain

するとこの通り、うまくいった。



ということで無事全て解き終えることができた。
基礎的な部分を復習しつつ、新たな知見も得られたのでよかった。