2010
12.17

Over the past several weeks, I’ve been an active participant in Google’s Web Vulnerability Reward Program. I’ve been writing blog posts about each of the vulnerabilities I’ve reported, publishing them once I’m told that the vulnerability has been patched. I’ve also been keeping up with posts that others have written and submitted to places like /r/netsec, /r/xss, and Hacker News. The posts, in aggregate, have explored many areas of web application security: XSS attacks of varying design, CSRF vulnerabilities, HTTP response splitting, clickjacking, etc. However, the program has attracted quite a large number of participants; I’m sure that I’ve seen only a small fraction of what people have posted.

Thus, the idea for this post came into being. My intention is to find and link to reports that people have written about vulnerabilities found as a part of this program. I’ve done a bit of searching and compiled a few links to start with (I’ve ordered them by the date they were posted). If anyone has suggestions for links to add, post in the comments and let me know: I’ll update the post with them.

Title Summary / Notes Posted
Google Calendar CSRF
https://nealpoole.com/blog/
Google Calendar was vulnerable to a series of CSRF vulnerabilities. In at least two separate instances, existing countermeasures (CSRF tokens) were not being validated by the application. 2010-11-30
Google.com XSSHTML Code Injection
http://tinkode27.baywords.com/
Google Maps contained an XSS vulnerability in its “Change default location” feature. The “HTML Code Injection” vulnerability referenced is not a bug: Google Translate has its content properly sandboxed (as the post indicates), mitigating the effects of any vulnerability. 2010-12-01
Google Scholar CSRF
https://nealpoole.com/blog/
Google Scholar was vulnerable to minor but potentially annoying CSRF vulnerabilities in two different pages. The regular search equivalents of both of these pages used CSRF tokens to mitigate these problems. 2010-12-07
Google.com XSS / Google Spreadsheets Clickjacking
http://securitylab.ru/
[English]
Google.com was vulnerable to an XSS attack (the exact details are unclear). It also appears that it was possible to perform a clickjacking attack using a Google Spreadsheet. 2010-12-08
Google XSS Flaw in Website Optimizer Scripts explained
http://www.acunetix.com/blog/web-security-zone/
Google’s Website Optimizer produced “control scripts” that caused websites to become vulnerable to XSS attacks. The attack required that the site already be vulnerable to a cookie injection vulnerability (discussed in more detail in the comments). 2010-12-09
Finding security issues in a website (or: How to get paid by Google)
http://adblockplus.org/blog/
Four different vulnerabilities: one basic XSS in YouTube Help, one XSS in onclick attributes, one HTTP Response Splitting vulnerability, and one last XSS in a tooltips script for Website Optimizer. 2010-12-11
Gmail+Google Chrome XSS Vulnerability
http://spareclockcycles.org/
Gmail contained an XSS vulnerability in the way it handled attachment names in Google Chrome. 2010-12-14
XSS in YouTube
http://www.ebanyu.com.ar/
[English]
YouTube’s inbox allowed an attacker to turn a JSON response into an XSS vector. The attacker needed to know the target’s session token in order to exploit the vulnerability. 2010-12-14
New Google Groups, Non-Persistent XSS
https://nealpoole.com/blog/
The new Google Groups interface contained an XSS vulnerability in its search functionality. The vulnerability required some user interaction to be activated. 2010-12-17
DoubleClick HTTP Header Injection / XSS
http://www.cloudscan.me/
The Doubleclick Ad CDN was vulnerable to HTTP Header Injection and cross site scripting attacks. 2010-12-21
XSS in Google Support Contact Form
https://nealpoole.com/blog/
One page in Google’s Help Center was vulnerable to a reflected cross-site scripting attack. 2010-12-21
Security Token Prediction in Google Scholar Alerts
http://www.garage4hackers.com/
Google Scholar’s Alerts feature used predictable security tokens in its URLs. This weakness allowed an attacker to create / list / delete alerts on behalf of other users. 2011-01-05
XSS in Google Shopping, Maps and Blogs
http://apoup.blogspot.com/
Google Shopping, Google Maps, and Google Blog Search were vulnerable to an unspecified cross-site scripting attack. There are more details available on the reporter’s blog (in the original Japanese and in English). 2011-01-27
XSS Vulnerability in Google Code Static HTML
https://nealpoole.com/blog/
Google Code contained a static HTML page that was vulnerable to a reflected, DOM-based XSS vulnerability. 2011-02-01
XSS in Google Analytics via Event Tracking API
http://spareclockcycles.org/
Google Analytics was vulnerable to a persistent XSS attack. A malicious attacker could generate fake events containing malicious HTML that would be executed on the Analytics dashboard. 2011-02-03
Non-Persistent XSS in Aardvark
https://nealpoole.com/blog/
Aardvark contained several reflected, DOM based XSS vulnerabilities. Due to CSRF protections, exploiting these vulnerabilities remotely was non-trivial. 2011-02-03
Persistent XSS in Google Baraza / Ejabat
https://nealpoole.com/blog/
Google Baraza (www.google.com/baraza/) and Google Ejabat (ejabat.google.com) were vulnerable to a persistent XSS attack. A malicious user could create a post that would trigger JavaScript when an image or link was clicked on. 2011-02-03
Persistent XSS in Blogger Design Preview
https://nealpoole.com/blog/
Blogger’s Design Preview functionality served up author-generated content in the context of blogger.com, allowing an author to perform an XSS attack against a blog administrator. 2011-02-03
Multiple Vulnerabilities in Google Applications
http://d.hatena.ne.jp/masatokinugawa/
[English]
The post covers three different types of vulnerabilities that the author came across. 2011-02-07
Persistent XSS in Google Finance
http://benhayak.blogspot.com/
Google Finance did not properly escape the names of user-created portfolios when using them in JavaScript. As a result, it was possible to craft a name that would cause XSS. 2011-02-16
Persistent XSS in Google Website Optimizer
http://benhayak.blogspot.com/
By using javascript: URIs in place of regular URLs when creating an experiment, the author of the post was able to craft a persistent XSS attack. 2011-02-27
Reflected MHTML Injection in Google Support (mail.google.com)
http://www.wooyun.org/ [English]
It was possible to inject a valid mhtml document into a support page hosted on mail.google.com. As a result, IE users who browsed to a malicious URL using the mhtml protocol handler could have trigger an XSS attack. 2011-03-03
How I Almost Won Pwn2Own via XSS
http://jon.oberheide.org/blog/
The Android Market was vulnerable to an XSS attack due to a lack of output sanitization. Due to how the Android platform works, the vulnerability could have been used to download and execute arbitrary code onto phones. 2011-03-07
Gaining Administrative Privileges on any Blogger.com Account
http://www.nirgoldshlager.com/
Blogger was vulnerable to an HTTP Parameter Pollution vulnerability. By providing the blogID twice in the request (once with a blogID controlled by the attacker and once with a blogID controlled by the victim) it was possible to make requests on behalf of a blog where you were not authorized. 2011-03-10
Reflected XSS in mail.google.com
http://www.cloudscan.me/
Gmail did not properly sanitize input provided by the user in the URL and the cookie. As a result, it was vulnerable to several reflected cross-site scripting attacks. 2011-03-30

Let me know what you think in the comments!

Update (12/21/2010): The comments have spoken and I’ve added a new vulnerability to the list.

Update 2 (12/21/2010): Adding another vulnerability that I reported to the list.

Update 3 (1/6/2011): fb1h2s emailed me about a vulnerability he reported. It has been added to the end of the list.

Update 4 (1/27/2011): We have another vulnerability report submitted via the comments.

Update 5 (2/3/2011): Five new reports have been added to the list, all of them XSS vulnerabilities!

Update 6 (3/4/2011): Three new reports have been added to the list.

Update 7 (3/7/2011): Added a cool new report about an XSS vulnerability in the Android marketplace

Update 8 (3/10/2011): Nir Goldshlager has written in with a link to his first report, an authentication bypass / HTTP Parameter Pollution vulnerability in Blogger.

Update 9 (3/30/2011): New Gmail XSS. Super happy fun time.

2010
12.17

Summary

The new Google Groups interface contained an XSS vulnerability in its search functionality. The vulnerability required some user interaction to be activated.

How Did It Work?

The search box at the top of the new interface is designed to provide some type-ahead functionality: as the user types, his/her input is scanned and used to create a drop down menu of choices. Unfortunately, user input was not properly sanitized; for instance, typing <u> into the search box caused drop down menu items to become underlined. As a result of this oversight, it was possible to type arbitrary HTML/JavaScript into the search box and have it executed by the page.

The new interface's type-ahead functionality, hard at work

The new interface’s type-ahead functionality, hard at work

My next step was to find a way to pass a malicious search string to a user. As it turned out, the interface provided a way to link to search results: visiting https://groups.google.com/forum/?fromgroups#!searchin/googlegroups-announce/<script>alert(document.cookie)<$2Fscript> would put <script>alert(document.cookie)</script> into the user’s search box.

Executing that malicious string required a little user interaction, however. The drop down box (and accordingly, the XSS) would only be activated when the user interacted with the search field. It was possible for a user to avoid the XSS by clicking in the box, highlighting the text, and deleting the entire string (or changing a character in the string so that the script failed to run). However, any other kind of interaction would have triggered the script’s execution.

More Information

The vulnerability mentioned here has been confirmed patched by the Google Security Team. I owe them a ton of thanks for organizing this program and giving me a chance to improve my skills. :-)

Interested readers are encouraged to take a look at other vulnerabilities I’ve reported under Google’s Vulnerability Reward Program.

2010
12.07

Summary

Google Scholar was vulnerable to minor but potentially annoying CSRF vulnerabilities in two different pages. The regular search equivalents of both of these pages used CSRF tokens to mitigate these problems.

Vulnerability #1

There was no CSRF protection used when saving preferences in Google Scholar. So, browsing to the following URL used to set your language on Google Scholars to Arabic and set your search results to return papers written in Chinese: http://scholar.google.com/scholar_setprefs?hl=ar&lang=some&lr=lang_zh-CN&submit. As of right now, the URL no longer updates user preferences (although it does change the language for the current page, and any page accessed from links/forms off of that page).

Vulnerability #2

There was no CSRF check in place for setting up email alerts in Google Scholar. A simple POST to http://scholar.google.com/scholar_alerts?view_op=list_alerts&hl=en where the POST data was

1
2
3
alert_query=[SOME QUERY]&
alert_max_results=10&
create_alert_btn=Create+alert

would have resulted in an alert being created for the currently logged in user (there was a parameter, email_for_op, that was passed in during a real request: removing it seemed to cause the system to default to the currently logged in user’s email address).

More Information

The vulnerabilities mentioned here have all been confirmed patched by the Google Security Team. I owe them a ton of thanks for organizing this program and giving me a chance to improve my skills. :-)

To see more posts I’ve written about vulnerabilities reported under Google’s Vulnerability Reward Program, please click here.

2010
12.02

What is it?

A few weeks ago, I went to a hackathon (hackabit) hosted by bit.ly. Originally, I planned to spend my time working on some personal projects: however, once I got to bit.ly’s offices, I decided to embrace the spirit of the event and work on a project related to bit.ly’s API.

After some consultation with my friend Paul Kernfeld, I began working on bit.ly File Storage (available on github). The idea was fairly simple: files get broken up into chunks, the chunks are stored on bit.ly, and the chunks can be reassembled from a single bit.ly URL.

How does it work?

To start with, I determined that bit.ly could store 2048 total characters in a URL. I also realized that bit.ly would store arbitrary data if it was put in the query string of a URL. So, the first thing I decided was to prefix all my content with ftp://?, to minimize the space taken up by unnecessary data (notice that I didn’t need a hostname: not sure why that was considered optional).

I also ended up base64-encoding the chunks of data, since I wasn’t sure how binary data would interact with the bit.ly API and I didn’t want to find out. I chose to take chunks 1024 bytes long: despite the size increase caused by base64-encoding I probably could have taken larger chunks of data, but I wasn’t particularly worried about the efficiency of the implementation.

Finally, once the chunks were encoded (and turned into bit.ly short URLs), I needed a way to turn them into a single URL. I decided on a binary tree structure because it was simple to implement and provided an easy way for me to expand the data on the other end (via in-order traversal).

I grouped the URLs into pairs: the first two were a pair, the second two were a pair, etc. I then asked bit.ly to generate a short URL for a long URL that looked something like http://?base64_encode(first-url|second-url) (the base64-encoding was not strictly necessary). If there were an odd number of URLs, the last URL on the list would simply be added on to the list of newly generated URLs. I repeated that process on each list of newly generated URLs, building each level of the tree until finally there was only one element: the root.

From the root, it was possible to retrieve the data via the following process:

  1. Call the bit.ly API to get the expanded version of the current node/URL.
  2. If the URL starts with ftp://?, we’ve reached a piece of the file (a leaf node). base64 decode it and echo it out.
  3. If the URL starts with http://?, there’s still more to do. base64 decode the content, split on the pipe character, and then visit the left (and then the right) URL (go to step 1).

I packaged the code as two CLI PHP applications, using an existing bit.ly API wrapper. The end result, excluding the API wrapper, contained fewer than 100 lines of code. I submitted it to the contest email address and headed home.

What happened?

This morning, I got an email telling me I had tied for second place in the contest, which blew me away. I went to the bit.ly blog and I read the following (you can read the announcement here):

* bit.ly File Storage (http://bit.ly/hx2kAc) - A hack for storing data with bit.ly.

We were especially impressed by the use of a binary tree for data retrieval with a single bit.ly URL! While this is not necessarily a use of bit.ly that we would encourage, credit is due for cleverness and chutzpah.

Cleverness and chutzpah? I’ll take it :-)

I also found out that there’s an existing project, furl, which does similar things using other URL shorteners: http://code.google.com/p/furl/.

2010
11.30

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:

1
2
3
4
5
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):

  1. Identify the target. Lets say the target is example@gmail.com.
  2. 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
  3. 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
  4. 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.
  5. 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:

1
2
3
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.

2010
11.30

When a friend of mine told me about Google’s new vulnerability reward program for web applications, my first reaction was a mix of excitement and skepticism. On the one hand, I love web application security and penetration testing: this program was right up my alley (especially given my recent abundance of free time). On the other hand, I had never run across a security vulnerability in a Google application before: I wasn’t sure that I would find anything, even if I looked hard.

As it turned out, I needn’t have worried: I spent many hours testing various Google webapps, but I also found plenty of vulnerabilities. ;-)

Under the terms of the program (and the rules of responsible disclosure), I will not be discussing the details of any vulnerabilities until they are fully resolved. Once the Google Security Team has confirmed to me that a particular issue has been dealt with, I will be doing a little writeup about it on this blog (a full list of the writeups can be found here). Hopefully people will find the writeups informative. :-)

2010
11.21

Warning

The method of preventing CSRF attacks described in this post is now considered to be insufficient. A comment on this post links to more details about an attack that circumvents it.

The Setup

About two weeks ago, I discovered a CSRF vulnerability on a well-known website (I won’t mention it by name). The vulnerability itself was fairly mundane: one of their scripts lacked tokens or any other form of CSRF protection. I sent in an email to their security team to let them know about it and went on my way.

The other day, I looked back at the website to see if the vulnerability had been fixed: it had. I also discovered that the vulnerability had been fixed using a method I had never thought about before. The website used “standard” HTTP headers, rather than a random token in the query string, to ensure that the request was from a valid source.

How does it work?

The browser makes an AJAX request. In that request, a special header is set: X-Requested-With. This header is non-standard, but it’s used by many JavaScript libraries (i.e., jQuery, Prototype).

On the server side, the server validates the request to make sure the header exists in the request. If it doesn’t, the request is rejected. If you’re using a library like jQuery, this is the only bit of code you have to implement.

Why does it work?

To add the header to a request within the context of the browser (which is what you need to do to pull off a CSRF attack properly), the attacker needs to use XMLHttpRequest. However, thanks to same-origin restrictions, XMLHttpRequest doesn’t allow you to make an AJAX request to a third party domain by default. Thus, it’s not possible for an attacker to forge a request with a spoofed X-Requested-With header.

There are, of course, some caveats:

  1. You need to use AJAX requests to take advantage of this protection: regular GETs and POSTs don’t allow for header manipulation.
  2. If your site allows some form of cross-domain AJAX requests (see https://developer.mozilla.org/en/http_access_control for more details), this won’t protect you.
  3. Like any other form of CSRF protection, it can be circumvented under certain circumstances. An insecure crossdomain.xml file, for instance, will still allow malicious Flash applets to go wild on your website.

It is, however, much better than using the Referer header. ;-)

2010
11.14

I spent quite a bit of time last night configuring Pidgin, my new IM client. A large portion of that time was focused on one particular issue: getting a Google Talk account (when using Google Apps for Your Domain) to play nicely with Pidgin. From looking at the search results for “google talk pidgin”, it looks like I’m not the only one with that problem. Since I did eventually get everything set up, I decided to document the process here in the hopes it might help someone else. :-)

The first thing I did was check out Google’s official documentation (http://www.google.com/support/a/bin/answer.py?hl=en&answer=49147). I followed the instructions, but when I went to connect I encountered a variety of error messages. “Read error”, “Unable to connect”, “Server closed the connection”, etc. The documentation was clearly missing a step.

Next, I stumbled on some references in the Google Talk help forum to a post on the Ubuntu forums (http://ubuntuforums.org/showthread.php?t=499906). The post talks about changing some advanced configuration settings for the account. After a little bit of trial and error with the settings, I found a combination that works.

How to configure the account

You’ll want to load the “Modify Account” screen (assuming the account is already created). That can be accessed by going to the Accounts menu, selecting the account in question, and choosing “Edit Account” from the list of options.

Once the screen is loaded, click on the Advanced tab. You’ll be presented with a number of different configuration options. The following list contains the settings I updated, along with what I set their values to. Any omitted settings can be left as-is.

  • Connection security: Use old-style SSL
  • Connect port: 5223 (this was the default, but it’s worth repeating here)
  • Connect server: talk.google.com

With those changes in place, Pidgin connected to Google Talk without complaint. :-)

Note: These steps were performed on Pidgin 2.7.5. If you’re using a different version of Pidgin, your steps may be slightly different, your form fields may have different names, etc.

2010
08.13

A recent Java project (replacing a very slow Excel spreadsheet) required me to do some calculations involving money. The issues involved in using floating point arithmetic to handle monetary calculations are well documented (Google it if you don’t believe me) so, as any smart Java programmer would do, I started writing my program using BigDecimal to represent the money.

Unfortunately, when I started checking my results, I found that my answers wouldn’t match up with Excel’s!

Worse, my answers didn’t match up with ones done directly on the data source that both Excel and my program were using to get data!

And even worse, Excel’s answers exactly matched those from the data source.

I was astonished. How, I asked myself, could floating point arithmetic beat arbitrary precision so badly?

Then, suddenly (and by suddenly I mean a half-hour later), it hit me.

BigDecimal has a notion of something called “scale.” The scale corresponds to the number of digits to the right of the decimal place. Thus, the scale determines how accurate BigDecimal calculations will be. If the scale is set too low, the precision is lowered.

As it turned out, the scale on all of my BigDecimals was a measly four digits (I was following good practice by using BigDecimal’s String constructor, and my data source returned numbers with four decimal places). For comparison, printing out my double at any given point would give me \~10 digits. As soon as I set the scale properly, the calculations became accurate and my BigDecimal formulas started working the way I expected them to. :)

2010
08.09

If you have an Excel spreadsheet containing first and last names, how do you convert those names to email addresses (following the format First.Last@example.com)?

If you’re a programmer, maybe you use something like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<?php

header("Content-type: text/plain");

$names = explode("\n", $_POST['names']);

foreach ($names as $cur_name)
{
    echo str_replace(' ', '.', strtolower(trim($cur_name))) . '@example.com' . "\n";
}

But maybe you’re not a programmer. Maybe you’ve never done any programming before in your life. If that’s the case, how do you solve a problem like this? Maybe I’m missing something obvious, but there doesn’t seem to be a simple way to do it (maybe there’s some kind of Mail Merge feature in Excel that could handle it?).

These kinds of problems crop up all the time in the real world. As a programmer, I often find myself writing small scripts and/or piping together some command-line tools to solve tasks like these; at this point, it’s almost second nature. Unfortunately, I realize that a lot of these tasks are much more difficult for people who don’t know how to program. Instead of writing a simple script, the user ends up looking for an application or tool that provides the functionality they need. If they can’t find it, they’re forced to perform the task manually or give up.

My advice for dealing with these kinds of tasks? Take an introductory computer science course and learn how to program, at least a little bit. Even if you never plan to use those skills again, you never know when they might come in handy.

Of course, it also doesn’t hurt to be friends with someone who knows how to program ( ;) ). I can’t speak for everyone, but I’m more than happy to write simple scripts to help my friends out. In fact, remember that PHP script at the top of the page? I originally wrote it for one of my friends. :-)