【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