Commit adf5c3c2 authored by dbates@webkit.org's avatar dbates@webkit.org
Browse files

XSS filter bypass via non-standard URL encoding

https://bugs.webkit.org/show_bug.cgi?id=66588

Reviewed by Adam Barth.

Source/WebCore: 

Tests: http/tests/security/xssAuditor/script-tag-with-16bit-unicode-surrogate-pair.html
       http/tests/security/xssAuditor/script-tag-with-16bit-unicode.html
       http/tests/security/xssAuditor/script-tag-with-16bit-unicode2.html
       http/tests/security/xssAuditor/script-tag-with-16bit-unicode3.html
       http/tests/security/xssAuditor/script-tag-with-16bit-unicode4.html
       http/tests/security/xssAuditor/script-tag-with-16bit-unicode5.html
       http/tests/security/xssAuditor/script-tag-with-three-times-url-encoded-16bit-unicode.html
       http/tests/security/xssAuditor/window-open-without-url-should-not-assert.html

Implement support for decoding non-standard 16-bit Unicode escape sequences of
the form %u26C4 as described in <http://www.w3.org/International/iri-edit/draft-duerst-iri.html#anchor29>.

See also <http://en.wikipedia.org/wiki/Percent-encoding#Non-standard_implementations>.

* GNUmakefile.list.am: Added DecodeEscapeSequences.h.
* WebCore.gypi: Ditto.
* WebCore.pro: Ditto.
* WebCore.vcproj/WebCore.vcproj: Ditto.
* WebCore.xcodeproj/project.pbxproj: Ditto.
* html/parser/XSSAuditor.cpp:
(WebCore::decode16BitUnicodeEscapeSequences): Added.
(WebCore::decodeStandardURLEscapeSequences): Added.
(WebCore::fullyDecodeString): Modified to call decode16BitUnicodeEscapeSequences().
(WebCore::XSSAuditor::init): Modified to return early when the URL of the document
is the empty string. This can happen when opening a new browser window or calling
window.open("").
* platform/KURL.cpp:
(WebCore::decodeURLEscapeSequences): Abstracted code into template-function decodeEscapeSequences().
This function just calls decodeEscapeSequences<URLEscapeSequence>().
* platform/text/DecodeEscapeSequences.h: Added.
(WebCore::Unicode16BitEscapeSequence::findInString):
(WebCore::Unicode16BitEscapeSequence::matchStringPrefix):
(WebCore::Unicode16BitEscapeSequence::decodeRun):
(WebCore::URLEscapeSequence::findInString):
(WebCore::URLEscapeSequence::matchStringPrefix):
(WebCore::URLEscapeSequence::decodeRun):
(WebCore::decodeEscapeSequences):

LayoutTests: 

Add tests for decoding non-standard 16-bit Unicode escape sequences.

Also add a test to ensure that we don't cause an assertion failure when
calling window.open("").

* http/tests/security/xssAuditor/resources/echo-intertag-decode-16bit-unicode.pl: Added.
(isUTF16Surrogate):
(decodeRunOf16BitUnicodeEscapeSequences):
(decode16BitUnicodeEscapeSequences):
* http/tests/security/xssAuditor/script-tag-with-16bit-unicode-expected.txt: Added.
* http/tests/security/xssAuditor/script-tag-with-16bit-unicode-surrogate-pair-expected.txt: Added.
* http/tests/security/xssAuditor/script-tag-with-16bit-unicode-surrogate-pair.html: Added.
* http/tests/security/xssAuditor/script-tag-with-16bit-unicode.html: Added.
* http/tests/security/xssAuditor/script-tag-with-16bit-unicode2-expected.txt: Added.
* http/tests/security/xssAuditor/script-tag-with-16bit-unicode2.html: Added.
* http/tests/security/xssAuditor/script-tag-with-16bit-unicode3-expected.txt: Added.
* http/tests/security/xssAuditor/script-tag-with-16bit-unicode3.html: Added.
* http/tests/security/xssAuditor/script-tag-with-16bit-unicode4-expected.txt: Added.
* http/tests/security/xssAuditor/script-tag-with-16bit-unicode4.html: Added.
* http/tests/security/xssAuditor/script-tag-with-16bit-unicode5-expected.txt: Added.
* http/tests/security/xssAuditor/script-tag-with-16bit-unicode5.html: Added.
* http/tests/security/xssAuditor/script-tag-with-fancy-unicode-expected.txt: Updated expected
result since we now pass this test. We should rename this file to something more descriptive,
see <https://bugs.webkit.org/show_bug.cgi?id=67818>.
* http/tests/security/xssAuditor/script-tag-with-three-times-url-encoded-16bit-unicode-expected.txt: Added.
* http/tests/security/xssAuditor/script-tag-with-three-times-url-encoded-16bit-unicode.html: Added.
* http/tests/security/xssAuditor/window-open-without-url-should-not-assert-expected.txt: Added.
* http/tests/security/xssAuditor/window-open-without-url-should-not-assert.html: Added.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@94828 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 4fc0052d
2011-09-08 Daniel Bates <dbates@webkit.org>
XSS filter bypass via non-standard URL encoding
https://bugs.webkit.org/show_bug.cgi?id=66588
Reviewed by Adam Barth.
Add tests for decoding non-standard 16-bit Unicode escape sequences.
Also add a test to ensure that we don't cause an assertion failure when
calling window.open("").
* http/tests/security/xssAuditor/resources/echo-intertag-decode-16bit-unicode.pl: Added.
(isUTF16Surrogate):
(decodeRunOf16BitUnicodeEscapeSequences):
(decode16BitUnicodeEscapeSequences):
* http/tests/security/xssAuditor/script-tag-with-16bit-unicode-expected.txt: Added.
* http/tests/security/xssAuditor/script-tag-with-16bit-unicode-surrogate-pair-expected.txt: Added.
* http/tests/security/xssAuditor/script-tag-with-16bit-unicode-surrogate-pair.html: Added.
* http/tests/security/xssAuditor/script-tag-with-16bit-unicode.html: Added.
* http/tests/security/xssAuditor/script-tag-with-16bit-unicode2-expected.txt: Added.
* http/tests/security/xssAuditor/script-tag-with-16bit-unicode2.html: Added.
* http/tests/security/xssAuditor/script-tag-with-16bit-unicode3-expected.txt: Added.
* http/tests/security/xssAuditor/script-tag-with-16bit-unicode3.html: Added.
* http/tests/security/xssAuditor/script-tag-with-16bit-unicode4-expected.txt: Added.
* http/tests/security/xssAuditor/script-tag-with-16bit-unicode4.html: Added.
* http/tests/security/xssAuditor/script-tag-with-16bit-unicode5-expected.txt: Added.
* http/tests/security/xssAuditor/script-tag-with-16bit-unicode5.html: Added.
* http/tests/security/xssAuditor/script-tag-with-fancy-unicode-expected.txt: Updated expected
result since we now pass this test. We should rename this file to something more descriptive,
see <https://bugs.webkit.org/show_bug.cgi?id=67818>.
* http/tests/security/xssAuditor/script-tag-with-three-times-url-encoded-16bit-unicode-expected.txt: Added.
* http/tests/security/xssAuditor/script-tag-with-three-times-url-encoded-16bit-unicode.html: Added.
* http/tests/security/xssAuditor/window-open-without-url-should-not-assert-expected.txt: Added.
* http/tests/security/xssAuditor/window-open-without-url-should-not-assert.html: Added.
2011-09-08 Fumitoshi Ukai <ukai@chromium.org>
 
Unreviewed. Chromium rebaseline of css3/bdi-element.html
#!/usr/bin/perl -wT
use strict;
use CGI;
use Encode;
my $cgi = new CGI;
use constant Unicode16BitEscapeSequenceLength => 6; # e.g. %u26C4
my $unicode16BitEscapeSequenceRegEx = qr#%u([0-9A-Za-z]{1,4})#;
sub isUTF16Surrogate($)
{
my ($number) = @_;
return $number >= 0xD800 && $number <= 0xDFFF;
}
# See <http://en.wikipedia.org/wiki/Percent-encoding#Non-standard_implementations>.
sub decodeRunOf16BitUnicodeEscapeSequences($)
{
my ($string) = @_;
my @codeUnits = grep { length($_) } split(/$unicode16BitEscapeSequenceRegEx/, $string);
my $i = 0;
my $decodedRun = "";
while ($i < @codeUnits) {
# FIXME: We fallback to the UTF-8 character if we don't receive a proper high and low surrogate pair.
# Instead, we should add error handling to detect high/low surrogate mismatches and sequences
# of the form low surrogate then high surrogate.
my $hexDigitValueOfPossibleHighSurrogate = hex($codeUnits[$i]);
if (isUTF16Surrogate($hexDigitValueOfPossibleHighSurrogate) && $i + 1 < @codeUnits) {
my $hexDigitValueOfPossibleLowSurrogate = hex($codeUnits[$i + 1]);
if (isUTF16Surrogate($hexDigitValueOfPossibleLowSurrogate)) {
$decodedRun .= decode("UTF-16LE", pack("S2", $hexDigitValueOfPossibleHighSurrogate, $hexDigitValueOfPossibleLowSurrogate));
$i += 2;
next;
}
}
$decodedRun .= chr($hexDigitValueOfPossibleHighSurrogate);
$i += 1;
}
return $decodedRun;
}
sub decode16BitUnicodeEscapeSequences
{
my ($string) = @_;
my $stringLength = length($string);
my $searchPosition = 0;
my $encodedRunPosition = 0;
my $decodedPosition = 0;
my $result = "";
while (($encodedRunPosition = index($string, "%u", $searchPosition)) >= 0) {
my $encodedRunEndPosition = $encodedRunPosition;
while ($stringLength - $encodedRunEndPosition >= Unicode16BitEscapeSequenceLength
&& substr($string, $encodedRunEndPosition, Unicode16BitEscapeSequenceLength) =~ /$unicode16BitEscapeSequenceRegEx/) {
$encodedRunEndPosition += Unicode16BitEscapeSequenceLength;
}
$searchPosition = $encodedRunEndPosition;
if ($encodedRunEndPosition == $encodedRunPosition) {
++$searchPosition;
next;
}
$result .= substr($string, $decodedPosition, $encodedRunPosition - $decodedPosition);
$result .= decodeRunOf16BitUnicodeEscapeSequences(substr($string, $encodedRunPosition, $encodedRunEndPosition - $encodedRunPosition));
$decodedPosition = $encodedRunEndPosition;
}
$result .= substr($string, $decodedPosition);
return $result;
}
print "Content-Type: text/html; charset=UTF-8\n\n";
print "<!DOCTYPE html>\n";
print "<html>\n";
print "<body>\n";
print decode16BitUnicodeEscapeSequences($cgi->param('q'));
print "</body>\n";
print "</html>\n";
CONSOLE MESSAGE: line 1: Refused to execute a JavaScript script. Source code of script found within request.
CONSOLE MESSAGE: line 1: Refused to execute a JavaScript script. Source code of script found within request.
<!DOCTYPE html>
<html>
<head>
<script>
if (window.layoutTestController) {
layoutTestController.dumpAsText();
layoutTestController.setXSSAuditorEnabled(true);
}
</script>
</head>
<body>
<iframe src="http://localhost:8000/security/xssAuditor/resources/echo-intertag.pl?q=<script>alert(/XS%uD834%uDD1E/)</script>">
</iframe>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<script>
if (window.layoutTestController) {
layoutTestController.dumpAsText();
layoutTestController.setXSSAuditorEnabled(true);
}
</script>
</head>
<body>
<iframe src="http://localhost:8000/security/xssAuditor/resources/echo-intertag-decode-16bit-unicode.pl?q=%25u003c%25u0073%25u0063%25u0072%25u0069%25u0070%25u0074%25u003e%25u0061%25u006c%25u0065%25u0072%25u0074%25u0028%25u002f%25u0058%25u0053%25u0053%25u002f%25u0029%25u003c%25u002f%25u0073%25u0063%25u0072%25u0069%25u0070%25u0074%25u003e">
</iframe>
</body>
</html>
CONSOLE MESSAGE: line 1: Refused to execute a JavaScript script. Source code of script found within request.
<!DOCTYPE html>
<html>
<head>
<script>
if (window.layoutTestController) {
layoutTestController.dumpAsText();
layoutTestController.setXSSAuditorEnabled(true);
}
</script>
</head>
<body>
<iframe src="http://localhost:8000/security/xssAuditor/resources/echo-intertag-decode-16bit-unicode.pl?q=<script>alert(/XS%u002525u0053/)</script>">
</iframe>
</body>
</html>
CONSOLE MESSAGE: line 1: Refused to execute a JavaScript script. Source code of script found within request.
<!DOCTYPE html>
<html>
<head>
<script>
if (window.layoutTestController) {
layoutTestController.dumpAsText();
layoutTestController.setXSSAuditorEnabled(true);
}
</script>
</head>
<body>
<iframe src="http://localhost:8000/security/xssAuditor/resources/echo-intertag-decode-16bit-unicode.pl?q=%25u003c%25u0073%25u0063%25u0072%25u0069%25u0070%25u0074%25u003e%25u0061%25u006c%25u0065%25u0072%25u0074%25u0028%25u002f%25u0058%25u0053%25u0053%25u2620%25u002f%25u0029%25u003c%25u002f%25u0073%25u0063%25u0072%25u0069%25u0070%25u0074%25u003e">
</iframe>
</body>
</html>
CONSOLE MESSAGE: line 1: Refused to execute a JavaScript script. Source code of script found within request.
<!DOCTYPE html>
<html>
<head>
<script>
if (window.layoutTestController) {
layoutTestController.dumpAsText();
layoutTestController.setXSSAuditorEnabled(true);
}
</script>
</head>
<body>
<iframe src="http://localhost:8000/security/xssAuditor/resources/echo-intertag-decode-16bit-unicode.pl?q=<script>alert('%u0058%u0053%u0053%u0020%u05d0%u05d1%u05d8%u05d7%u05d4%u0020%u05e4%u05d2%u05d9%u05e2%u05d5%u05ea-%u8de8%u7ad9%u5f0f%u811a%u672c%u653b%u51fb')</script>">
</iframe>
</body>
</html>
CONSOLE MESSAGE: line 1: Refused to execute a JavaScript script. Source code of script found within request.
<!DOCTYPE html>
<html>
<head>
<script>
if (window.layoutTestController) {
layoutTestController.dumpAsText();
layoutTestController.setXSSAuditorEnabled(true);
}
</script>
</head>
<body>
<iframe src="http://localhost:8000/security/xssAuditor/resources/echo-intertag.pl?q=<script>alert('%u0058%u0053%u0053%u0020%u05d0%u05d1%u05d8%u05d7%u05d4%u0020%u05e4%u05d2%u05d9%u05e2%u05d5%u05ea-%u8de8%u7ad9%u5f0f%u811a%u672c%u653b%u51fb')</script>">
</iframe>
</body>
</html>
ALERT: /XSS/
CONSOLE MESSAGE: line 1: Refused to execute a JavaScript script. Source code of script found within request.
CONSOLE MESSAGE: line 1: Refused to execute a JavaScript script. Source code of script found within request.
<!DOCTYPE html>
<html>
<head>
<script>
if (window.layoutTestController) {
layoutTestController.dumpAsText();
layoutTestController.setXSSAuditorEnabled(true);
}
</script>
</head>
<body>
<iframe src="http://localhost:8000/security/xssAuditor/resources/echo-intertag.pl?q=<script>%252525u0061lert(/XSS/)</script>">
</iframe>
</body>
</html>
This test PASSED if we don't trigger an assertion failure when opening a pop-up window without a URL. To run this test by hand, ensure that pop-up windows aren't blocked before loading this page.
PASSED
<!DOCTYPE html>
<html>
<head>
<script>
if (window.layoutTestController) {
layoutTestController.dumpAsText();
layoutTestController.setXSSAuditorEnabled(true);
layoutTestController.setCanOpenWindows();
layoutTestController.setCloseRemainingWindowsWhenComplete(true);
layoutTestController.waitUntilDone();
}
</script>
</head>
<body>
<p>This test PASSED if we don't trigger an assertion failure when opening a pop-up window without a URL. To run this test by hand, ensure that pop-up windows aren't blocked before loading this page.</p>
<pre id="console"></pre>
<script>
function finish()
{
document.getElementById("console").innerText = "PASSED";
if (window.layoutTestController)
layoutTestController.notifyDone();
}
function runTest()
{
var childWindow = window.open("");
if (!childWindow) {
document.getElementById("console").innerText = "FAILED to open pop-up window. Ensure that pop-up windows aren't blocked.";
return;
}
childWindow.document.open();
childWindow.document.write("PASSED");
<!-- Break up the HTML Script Element so it is not interpreted by HTML4 parsers as per <http://www.w3.org/TR/html4/types.html#type-cdata>. -->
childWindow.document.write("<scr" + "ipt>window.opener.finish()<" + "/script>");
childWindow.document.close();
}
runTest();
</script>
</body>
</html>
2011-09-08 Daniel Bates <dbates@webkit.org>
XSS filter bypass via non-standard URL encoding
https://bugs.webkit.org/show_bug.cgi?id=66588
Reviewed by Adam Barth.
Tests: http/tests/security/xssAuditor/script-tag-with-16bit-unicode-surrogate-pair.html
http/tests/security/xssAuditor/script-tag-with-16bit-unicode.html
http/tests/security/xssAuditor/script-tag-with-16bit-unicode2.html
http/tests/security/xssAuditor/script-tag-with-16bit-unicode3.html
http/tests/security/xssAuditor/script-tag-with-16bit-unicode4.html
http/tests/security/xssAuditor/script-tag-with-16bit-unicode5.html
http/tests/security/xssAuditor/script-tag-with-three-times-url-encoded-16bit-unicode.html
http/tests/security/xssAuditor/window-open-without-url-should-not-assert.html
Implement support for decoding non-standard 16-bit Unicode escape sequences of
the form %u26C4 as described in <http://www.w3.org/International/iri-edit/draft-duerst-iri.html#anchor29>.
See also <http://en.wikipedia.org/wiki/Percent-encoding#Non-standard_implementations>.
* GNUmakefile.list.am: Added DecodeEscapeSequences.h.
* WebCore.gypi: Ditto.
* WebCore.pro: Ditto.
* WebCore.vcproj/WebCore.vcproj: Ditto.
* WebCore.xcodeproj/project.pbxproj: Ditto.
* html/parser/XSSAuditor.cpp:
(WebCore::decode16BitUnicodeEscapeSequences): Added.
(WebCore::decodeStandardURLEscapeSequences): Added.
(WebCore::fullyDecodeString): Modified to call decode16BitUnicodeEscapeSequences().
(WebCore::XSSAuditor::init): Modified to return early when the URL of the document
is the empty string. This can happen when opening a new browser window or calling
window.open("").
* platform/KURL.cpp:
(WebCore::decodeURLEscapeSequences): Abstracted code into template-function decodeEscapeSequences().
This function just calls decodeEscapeSequences<URLEscapeSequence>().
* platform/text/DecodeEscapeSequences.h: Added.
(WebCore::Unicode16BitEscapeSequence::findInString):
(WebCore::Unicode16BitEscapeSequence::matchStringPrefix):
(WebCore::Unicode16BitEscapeSequence::decodeRun):
(WebCore::URLEscapeSequence::findInString):
(WebCore::URLEscapeSequence::matchStringPrefix):
(WebCore::URLEscapeSequence::decodeRun):
(WebCore::decodeEscapeSequences):
2011-09-08 Adam Barth <abarth@webkit.org>
 
DocumentWriter::deprecatedFrameEncoding doesn't need to refert to Settings
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment