Cатсн²² (in)sесuяitу / ChrisJohnRiley

Because we're damned if we do, and we're damned if we don't!

SurveyMonkey: IP Spoofing

It’s amazing the things you find when you’re not really looking for them!

A few weeks back I was finalizing some of the survey results for my #BSidesLondon talk when I noticed something interesting, if a little strange. When somebody fills out a survey on the Surveymonkey website, they record a number of pieces of meta data along with the survey answers. Things like data, time, link used to access the survey, and the IP Address of the personal completing the survey. This final piece of data was the one that really caught my attention, especially when I started seeing a number of RFC1918 addresses in with the mix. That’s a bit weird… why, and more interestingly, how are they getting these local addresses.

A lot of thoughts went through my mind… client-side java checking for local address maybe… something like decloak. Still, that wouldn’t account for the fact that only occasional responses had the private address, when others had the public address (about 5-6 in the 100 responses I looked at).

So, firing up Burp Suite, I threw a couple of fake survey responses through to Surveymonkey for testing and quickly found that remote system was picking up the public internet routable address on all my test responses. No funky JavaScript, no Java (at all), so it must be something in the request from the client to the server. Taking a look at the various options I started playing about with the X-Forwarded-For and X-Real-IP request headers and quickly discovered that by setting an X-Forwarded-For header on the survey traffic I could set any IP address I wanted on the response.

GET /
host: surveymonkey.com
User-Agent: Mozilla/5.0
X-Forwarded-For: 127.0.0.1
X-Real-IP: 127.0.0.2
...

Well that’s a bit of fun… I can set RFC1918 addresses… how totally fun, and at the same time useless as well. So taking this one step further, I thought, What would be possible with this. I can spoof the IP address of a person filling out a survey. Well, maybe I could specify a public IP address other than my own in this header too. If they’re not checking the string, maybe I can spoof a survey response from somebody who didn’t fill it out. Not really BIG impact, but if I fill out an anti-government survey from a Whitehouse IP address, I’m sure it’ll cause a bit of a stur. So, lets see if I can fill out this survey from China… after all, if the IP says China, it must be them right 😉

OMG… China are all up in my survey, APTing me! (1.2.2.2 is one of the IP ranges assigned to China). Still aside from framing nation states for filling in nasty comments on your surveys, what else can you do with this?

I’m so glad you asked. Well, just because the X-Forwarded-For header is meant for transporting IP addresses of the client, doesn’t mean that’s what we’re going to put in there!

The IP address is returned to the owner of the survey, and as such, is only viewable by authenticated users. I’m sure there are also places where this IP address are returned to administrators, support staff, etc… but that’s not something I was able to check. So, how about we put in something other than an IP address. Something simple to prove the point… some kind of alert box maybe.

Well, no. Not because it’s filtered though. In the case of the Surveymonkey, the returned data is filtered to 20 characters. Anything longer is stripped. So anything flashy is pretty much out of question. Actually, almost anything interesting is out of scope, unless you happen to own a domain name that’s 5 characters long (in total). Sadly, I only own a domain that’s 6 characters (c22.cc) which is a pity.

Still, I threw together a quick PoC that triggers an iFrame from another site. An attacker (given a suitable domain name) could use this to load Javascript using script src instead of iframe src. Not really the kind of PoC I was hoping for, but it proves the point I guess.

GET /
host: surveymonkey.com
User-Agent: Mozilla/5.0
X-Forwarded-For: <iframe src=//aa.bb>
...

I contacted Surveymonkey with the information discovered and they’ve begun looking into correcting the issue. The question that really interests me is, how many other sites are using the same system and trusting user provided headers. This is something that webapp testers “should” be testing for. Still, there are lots of things that testers “should” be doing!


20 responses to “SurveyMonkey: IP Spoofing

  1. ChrisJohnRiley April 23, 2011 at 18:51

    That’s interesting, as I’d not seen automated checks for this with the required logic to discover the issue. I’d love to find out how you’re achieving this in automated tests. The bug in question (although only an example) is spread across 2 access levels. The first with write access to complete the survey, and the second with read access to extract the survey results.

    Thinking about it logically, the only way I can imagine an automated check working would be to first write a check value to each possible input including the X-Forwarded-For header) and then check to read the values out and check which have been stored. Is this how Acunetix does it? or am I way off the mark?

  2. Bogdan Calin April 23, 2011 at 20:06

    Sorry, i was referring to testing x-forwarded-for and similar headers. That’s what we have for a long time. However, we do have what you mentioned as well. It was introduced a few months ago.

    At the end of the normal scan we have something called stored tests. We inject a marker string in each input. Then we visit all pages and look for the stored content. With this first step we can detect stored xss. However, if AcuSensor is enabled we also check all sql queries, included files, os execution strings and so on. If we find a match, we test each match individually: inject a value of page A, look for result on page B (where it was reflected). Like this we can find stored sql injections or second level sql injections (how some other people are calling it). We found some nice bugs with this technique. It doesn’t work in all cases but it’s good enough.

  3. Dan Kaminsky April 24, 2011 at 19:10

    Neat, but I’m pretty sure there’s no security boundary being crossed. There’s no way to send a normal user from badguy.com to survey.com with arbitrary headers. At the point an attacker has BurpSuite in the way, he doesn’t need to post malicious stuff, he can just return whatever he wants.

  4. Dan Kaminsky April 24, 2011 at 19:31

    Though if you want to pollute SurveyMonkey’s backend dataset, this does absolutely work.

  5. ChrisJohnRiley April 24, 2011 at 20:01

    In regards to the security boundary… the header (and therefore the spoofed IP Address recorded in the database) is sent by an attacker completing the survey. There’s no direct interaction with the targeted user. The owner of the survey then views the completed surveys and the spoofed data is returned.

    As it’s a stored attack and not reflective, the attacker never needs to force the targeted user to send an arbitrary header.

%d bloggers like this: