xssless Update – Self Propagation & Why JavaScript Worms Can Be Very Scary

Well, it’s been awhile since I’ve crashed Firefox due to insane JavaScript usage so I thought I’d write another blog post.

I recently released a new feature for xssless which allows you to make the payload POST itself. Meaning that you can very easily make payloads that will spread themselves via JavaScript to unsuspecting viewers of your unsanitized input.

Example Usage of Self Propagation Feature

So I’ve created for us a little playground to practice our XSS magic. We’ll view it in Firefox with Burp proxy as our middleman (xssless takes Burp traffic exports as input).


Notice how I’ve added a little test to see if the input is unsanitized (gee I wonder?!)


…and would you look at that…


…the page appears to be vulnerable to persistent XSS!

Great, so let’s generate a self-propagating payload using xssless.

We select this request in Burp:


Export it for xssless:


Now we run it through xssless:

mandatory@mandatorys-box:~/Programming/xssless$ ./xssless.py -m=metalist.txt xssland 

___  ___  ______ _____|  |   ____   ______ ______
\  \/  / /  ___//  ___/  | _/ __ \ /  ___//  ___/
 >    <  \___ \ \___ \|  |_\  ___/ \___ \ \___ \ 
/__/\_ \/____  >____  >____/\___  >____  >____  >
      \/     \/     \/          \/     \/     \/ 
               The automatic XSS payload generator
                     By mandatory (Matthew Bryant)

Notice that we’ve used the -m option which specifies what POST fields to replace with our payload. In the file we specified the “content” field and the payload was adjusted accordingly.

Now, this line right here:

doRequest('/xssland/index.php', 'POST', 'content=%3Cscript%3Em()%3B' + encodeURIComponent(m.toString()) + '%3C%2Fscript%3E');

This is where the magic happens. The “content” field is set to equal:

%3Cscript%3Em()%3B' + encodeURIComponent(m.toString()) + '%3C%2Fscript%3E'

Which is URL encoded:


JavaScript has the neat ability which allows you to take entire functions and turn them into strings. Which is being done by the “m.toString()” part of the code. Then the “encodeURIComponent()” function is used to make the function content safe for transport by URL encoding it.

But enough explaining, let’s see this in action!



Cool, but did it work?


It did! Notice have we have the initial POST and the response but then we get another POST right afterwards (followed by a response for that POST).

Perfect but I don’t think I’ve really conveyed how out of hand things can get. Let’s refresh the page shall we?


Interesting, so now without doing any form submitting we have two POST requests that run in the background. Which, of course, makes sense. We have our initial payload doing a POST and the payload it posted doing a POST as well.

For those folks keep track at home, that means we will double the amount of payloads on the page every pageview.

After another refresh:


That’s four POST requests being preformed (asynchronously by the way, so they are all being done at once).

A few more refreshes:


Oh boy…things are starting to get out of hand…


After only a few refreshes of the page our database has grown quite a bit!


Bonus points for anyone who figures out how many page refreshes I did to get that many posts in the database 😉

So, in conclusion, we see that JavaScript worms can be very dangerous indeed. Many people write off XSS as a low-risk issue but when situations like this occur it would take a very little amount of time to take even the largest site and grind it to a halt. Not to mention the denial of service attack is being preformed by the users themselves (while they remain non-the-wiser)! This payload only posted itself, imagine if it also preformed another action – like sending a penny to a bank account, or sending a message to your friends on the site!

Folks, be sure to sanitize that input, do your part in defending against super-neato attacks like this one.

Until next time,


Matthew Bryant (mandatory)

Matthew Bryant (mandatory)
Security researcher who needs to sleep more. Opinions expressed are solely my own and do not express the views or opinions of my employer.