Summary
Google Calendar was vulnerable to a series of CSRF vulnerabilities. In
two separate instances, I found that existing countermeasures (CSRF
tokens) were not being validated by the application.
Walkthroughs
Example #1
In the first instance, I found it was possible to add an arbitrary event
to a user’s calendar. I used Google Calendar’s “quick add” feature: it
allows users to click on a space on the calendar and type in the name of
an event, which adds it to the calendar. By monitoring the HTTP traffic
between my browser and Google, I determined that the calendar entry was
being created by a GET request that looked something like this (I’ve
broken up the URL for the sake of readability):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | http://www.google.com/calendar/event?
dates=20101103T003000%2F20101103T013000
&text=asfsaf
&pprop=HowCreated%3ADRAG
&src=kmVhbF9wb29sLUBicm93bi5lZGU
&ctz=America%2FNew_York
&eid=1288669371381
&sf=true
&action=CREATE
&output=js
&lef=LHZkMjYxNDNmODNlOTBlbnZqMTQ0amh1Ym9AZ3JvdXAuY2FsZW5kYXIuZ29vZ2xlLmNvbQ
&lef=MW4udXNhI2hvbGlkYXlAZ3JvdXVudi5jYWxlbmRhci5nb29nbGUuY29t
&lef=bsVhbF9wb21sZUBicm92bi5lZHU
&droi=20101024T000000%2F20101212T000000
&secid=-_1FyItA6aDLfYZl6GhuK62s74o
|
The first thing I tried doing was removing the secid parameter (which I
assumed to be a CSRF token): surprisingly, while the output of the
response changed slightly, it still created a new event on the calendar.
I then experimented through trial and error with removing more
parameters until I got the URL down to the following:
| http://www.google.com/calendar/event?
dates=20101103T003000%2F20101103T013000
&text=asfsaf
&sf=true
&action=CREATE
|
An attacker could have provided that URL to a target in any number of
ways: just visiting it would have added a corresponding entry to the
target’s calendar.
Example #2
The second instance involved changing the privacy settings of an
existing calendar. To do so, an attacker first needed to determine the
calendar’s unique identifier. I proposed the following method for
finding such an identifier, assuming the target is a Gmail user (and
we’re interested in their default, personal calendar):
- Identify the target. Lets say the target is example@gmail.com.
- Register a Gmail account where the first letter of the account is
different from the target’s. So, here, I might register fxample@gmail.com
- Sign in to Google Calendar as the attacker, take a look at the
printable image version of your calendar. It will have the
attacker’s email address in the upper left hand corner. The URL for
the image looks something like this (I’ve omitted unnecessary
parameters): https://www.google.com/calendar/printable?src=[SOME STR]&psdec=true&pft=png
- Through trial and error, try different permutations of
letters/numbers in the first few characters of the src parameter.
You can see how your changes affect the decoded string by looking in
the upper left of the image: it will display a new email address
based on your changes (sometimes it might tell you that the src is
invalid, in which case you just continue trying). There’s a small
enough number of possibilities that it can be brute-forced.
- Eventually, you figure out what the right src value is for the
target: the email on top will match the target’s email address.
From there, the rest was simple. Privacy settings are controlled by
sending a POST request to
https://www.google.com/calendar/editcaldetails. A CSRF token was
included if the request was made via the web interface, but omitting the
token did not prevent the request from functioning. The POST body
consisted of just the following:
| dtid=[VALID-SRC]
&ap=X19wdWJsaWNfcHJpbmNpcGFsX19dcHVibGljxmNhbGVuZGFyLmdvb2dsZS5jb20
&ap=20
|
where [VALID-SRC] was the valid src found in step 5 and the rest was a
constant derived from the HTML for the corresponding form in the web interface.
More Information
The vulnerabilities mentioned here have all been confirmed patched by
the Google Security Team.
To see more posts I’ve written about vulnerabilities reported under
Google’s Vulnerability Reward Program, please click here.