Interesting CSRF bypass

Sebastian recently discovered an interesting CSRF bypass and we would like to share this finding with you.

The webapplication used some forms and submitting them resulted in the following POST request:

1
2
3
4
5
6
7
8
9
10
POST /settings.php?save=1&email=foobar@test.com HTTP/1.1
Host: www.HOST.com
Connection: keep-alive
Content-Length: 150
Origin: https://HOST.com
X-Requested-With: XMLHttpRequest
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Cookie: [Cookies]

CSRFToken[token]=ac1bbdd8b6dd23f780f3594a6d02f62624f2ef430c464f7ddec617728a2999bf&CSRFToken[time]=1423073667737&CSRFToken[URI]=/settings

As you can see, there are multiple CSRF protection mechanisms in place:

  • Origin-header
  • X-Requested-With-header
  • Content-Type-header
  • CSRFToken[token], CSRFToken[time]-parameters

The obvious thing to do is to remove/neutralize all the mechanisms and resend the request. Unfortunately, the application correctly rejected the request due to invalid CSRF tokens.

So what’s next?

Did you notice that the content that is being changed (email parameter) is located in the url? Why would someone put this data in the url when the request is sent using the POST method?

Let’s try to change the request method and remove all the POST-request related stuff:

1
2
3
GET /settings.php?save=1&email=foobar@test.com HTTP/1.1
Host: www.HOST.com
Cookie: [Cookies]

That’s a simple GET request and guess what? The application did not reject the request. We successfully bypassed the CSRF protection.

What did we learn?

  • Changing the request methods can lead to interesting behaviour/ bypasses.
  • Never trust user-supplied data ;)

Kind regards,

the team of internetwache.org