A short while ago, I decided to prepare a presentation on web vulnerabilities and specifically on XSS attacks. This involved studying the way today’s filtration systems work.
I selected the most popular Russian social networking website, VKontakte.ru, as a test bed. One thing that grabbed my attention was the updated user status system.
The HTML code in the part of the page where users edit their status messages is shown below:
As you can see, filtering is performed by the infoCheck() function. The status itself is located in this string:
What we have here is two-step filtration. The first step is performed when the user enters the status message. The second step involves converting the status message to text and returning it to the page in the shape in which other users will see it.
While the second step definitely works well and it would clearly be impossible to convert to active XSS, things are not as simple where the first step is concerned, so it is that step that we will look at in greater detail.
Predictably, the simple <script>alert()</script> did not work, and the status remained empty. Other ‘script-like’ attempts didn’t work, either – it seems that this particular string is explicitly filtered.
However, the <script> tag is not essential for a script to be executed. The first vulnerability is introduced on the user’s machine by using the <img> tag: by entering the string <img src=1.gif onerror=some_function> as the user’s status, we can get that function to be executed. For example, we can call the function profile.infoSave(), which is called with an empty parameter to clear the status, but use a parameter of our choice. Thus, if we enter <img src=1.gif onerror=profile.infoSave(‘XSS’)>, we get the string “XSS” as our status message:
Another interesting vulnerability associated with the filter is that the tag <A> is not filtered. If we enter <A HREF=”//www.google.com/”>XSS</A> as our status, we get… a hyperlink clicking on which brings up a status editing window and, a moment later, opens google.com.
As we all remember, XSS = cross site scripting, so I decided to test the next vulnerability using a third-party website with a script loaded on it. In addition to the tags mentioned above not being filtered, the <iframe> tag also successfully passed the filter. As a result, entering <iframe src=”yoursite.com” width=”100%” height=”300″> in the status line will produce an iframe which will launch the above-mentioned script loaded on the page. Below is an example of what the iframe can look like:
This is a more serious vulnerability than the other two. One way of exploiting it is by creating a URL to change user status and sending it to the victim user in the hope that the user will click on it. The script will be executed on the user’s page even before the status message is published. This is a classic example of passive XSS.
These vulnerabilities existed from 01 August, 2010 – the time when the new user status system was introduced. We notified VKontakte’s administration on 01 March, 2011 and the vulnerabilities were closed on 03 March.