【JavaScript】intigritiの脆弱性クイズ 【XSS】
久々にintigriti社の脆弱性クイズに挑戦しました。
今回は比較的に簡単なXSSです。
intigritiのクイズをやってみたシリーズ
問題
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<script>
let search = new URLSearchParams(location.search)
const redirectURL = search.get('redirectURL');
let regex = /^[a-zA-Z0-9\t]+\:\/\/example\.com\/.*/
let regexUrl = redirectURL.match(regex)
let antiXSS = redirectURL.startsWith('javascript')
if (regexUrl && !antiXSS) {
location.href = redirectURL;
};
</script>
</body>
</html>
解説
公式の解説はこちら
どんなコード?
-
redirectURLパラメータを使用して、リダイレクトする。 -
redirectURLの値の先頭がjavascriptでないかを検証する。 -
redirectURLの値がexample.comのURLであるかを検証する。
どうやって攻撃する?
-
redirectURLに悪意のあるペイロードを入れる。
例えば、javascript:alert(1)などのペイロードです。
もし、このコードが検証されていなければ、このペイロードを設定することで、ウェブページにアクセスしたユーザ全員に対してアラートを表示させることができます。
しかし、前述の通り、redirectURLの値の先頭がjavascriptでないかを検証しているため、このペイロードは検証に引っかかります。
バイパスするには
-
redirectURLがjavascript:で始まらないことを確認するantiXSSチェック
-
redirectURLが特定のパターンに一致することを確認する正規表現チェック
1のantiXSSのバイパスは簡単です。
javascript:alert(1)のようなペイロードをjavascriptで始まらないようにするだけです。
javascriptを全て大文字(JAVASCRIPT:alert(1))にしたり、jだけ大文字(Javascript:alert(1))にしたり、などの方法があります。
2の正規表現は、/^[a-zA-Z0-9\t]+\:\/\/example\.com\/.*/です。
任意の英数字の後に://example.com/という文字列が続くURLかどうかを検証しています。
そのため、redirectURL=https://example.com/の場合は、当然検証に引っかからず、リダイレクトが行われます。
では、redirectURL=Javascript:alert(1)のようなペイロードを設定するにはどうすればいいでしょうか。
改行を利用したバイパス
example.comというテキストが含まれないといけないので、次のようなペイロードを作ります。
redirectURL=Javascript://example.com/
これは、正規表現チェックもantiXSSチェックも通過します。
一方で、javascriptでは//を使うことで、その行の残りの部分がコメントアウトされてしまうので、それ以降に何を書いても無視されます。
そこで、改行を利用します。
//example.com/
alert(1)
これをredirectURLに設定できれば、alert(1)が実行されるれるので、XSSが発生します。
改行はURLに含めることができないので、URLエンコードを利用します。
Webで改行をURLエンコーディングについて検索すると次のような文字列が得られます。
-
%0D%0A: CRLF -
%0A: CR
WindowsならCRLF、MacやLinuxならCRなどといった違いがあるようですが、今回使うのはどちらでもありません。
%250aを使います。
%25は%のURLエンコードなので、%250aは%0aと同じ、つまり、改行を2回エンコードしたものです。
解答
よって、次のペイロードが答えです。
redirectURL=Javascript://example.com/%250aalert(1)
なぜ2回エンコードするのか
ペイロードがredirectURL=Javascript://example.com/%0aalert(1)だった場合、
let search = new URLSearchParams(location.search)
const redirectURL = search.get('redirectURL');
この部分での、redirectURLの値がJavascript://example.com/\nalert(1)になります。
これだと改行コードも含めてコメントアウトされてしまします。
ペイロードがredirectURL=Javascript://example.com/%0250aalert(1)であれば、
redirectURLの値がJavascript://example.com/%0aalert(1)となるので、リダイレクトした時に改行コードに変換されて、alert(1)が実行されます。
Discussion