Thursday, May 3, 2007

On-site request forgery

Request forgery is a familiar attack payload for exploiting stored XSS vulnerabilities. In the MySpace worm, Samy placed a script within his profile which caused any user viewing the profile to perform various unwitting actions, including adding Samy as a friend and copying his script into their own profile. In many XSS scenarios, when you simply wish to perform a particular action with different privileges, on-site request forgery is easier and more reliable than attempting to hijack a victim’s session.

What is less well appreciated is that stored on-site request forgery bugs can exist when XSS is not possible. Consider a message board application which lets users submit items that are viewed by other users. Messages are submitted using a request like the following:

POST /submit.php
Content-Length: 34


which results in the following being added to the messages page:

  <td><img src="/images/question.gif"></td>

In this situation, you would of course test for XSS. However, it turns out that the application is properly HTML-encoding any " < and > characters which it inserts into the page. Having satisfied yourself that this defence cannot be bypassed in any way, you might move on to the next test.

But look again. We control part of the target of the <img> tag. Although we can’t break out of the quoted string, we can modify the URL to cause any user who views our message to make an arbitrary on-site GET request. For example, submitting the following value in the type parameter will cause anyone viewing our message to make a request which attempts to add a new administrative user:

../admin/newUser.php?username=daf2&password=0wned &role=admin#

When an ordinary user is induced to issue our crafted request, it will of course fail. But when an administrator views our message, our backdoor account gets created. We have performed a successful on-site request forgery attack even though XSS is not possible. And of course, the attack will succeed even if administrators take the precaution of disabling JavaScript.

(In the above attack string, note the # character which effectively terminates the URL before the .gif suffix. We could just as easily use & to incorporate the suffix as a further request parameter.)