Earlier this year I spent some days approaching Google as a target for some research. There was a long time since last time and I actually lost my 0x07 in their Security Hall of Fame. Some really great people took my spot, so it wasn’t that bad after all.
Anyway, I wanted to share some funny techniques that I found to be really useful, you might already know about them – but with hindsight – not everyone seems to.
Youtube Annotation Link XSS due to weak whitelist regex
In Youtube, you’re able to put annotations on your videos. This are basically active areas placed inside the video that will do a certain action if you click on them. There are some limitations to these areas. For example, you can only do links to specific websites that will redirect the user when clicking on the area. In the editor of the annotations you’re able to select:
- A Google+-link
- another Youtube-video
- a Youtube-playlist
- a Kickstarter-project page
When selecting one of these, a request is made to Youtube with an XML:
As you see, there’s an action
-node with the type openUrl
together with the URL that should be used.
Now, everything is accepted when posting values to the URL. However, as soon as a video is starting, there’s a call that fetches a similar XML that will tell the player if there’s any annotation with a link in the video. And if the value of the URL is not matching Google’s whitelist, the link will not be included in this XML.
Attack method
So, I knew there was multiple regular expressions used for this filtering of valid and non-valid URLs. My first idea was actually to try and see if the regex for Kickstarter was insufficient. I tried different subdomains:
<url value="https://xxx.kickstarter.com/x" target="new"> – No luck <url value="https://xxx.kickstarter.com@example.com/x" target="new"> – No luck <url value="https://notkickstarter.com/x" target="new"> – No luck
Looked pretty patched up so far! Now, let’s try one of the regular ones, to Google’s own sites like Google+:
<url value="https://plus.google.com.example.com" target="new"> – No luck <url value="https://plus.google.com@example.com" target="new"> – No luck <url value="httpsx://plus.google.com/" target="new"> – Works! WTH!
Okay, so the domain is validated, but not the protocol? This is great(!) news if you want to do something bad. Let’s try something else, a little trick:
Also works!
Let’s see what happens:
What happens is that the URL above is actually the javascript-scheme running, the //
after thejavascript:
tells the browser all content after is a one-line comment. By using the new-line character %0a
you’re able to exit that comment. You’re now in javascript-land and can do whatever you want! In my example I just triggered an alert.
Nice! This also worked when embedding the player wherever you wanted, always triggering onwww.youtube.com. This was fixed the same week.
Striiiike 1!
Google Translate XSS due to inline script-data breakout
First, when watching source code of webpages, you’ve most likely seen something like this in the code, a script element with dynamic data in the variables:
In the Google Translate example, we first need to understand the basics ofhttps://translate.google.com
This domain is not only hosting the regular translation service, it’s also helping other Google services with translations. One of these services is the Chrome Webstore Translation Manager located at: https://translate.google.com/manager/chrome/inapp/
This URL won’t give you any happy time now, but when provided with the proper variables you’ll be asked to purchase to get external translators to translate your application.
Now, on this URL, the data for the current Chrome app was presented inline inside a script variable. One parameter was the application name. The problem was, the data was not sanitized in anyway except by escaping quotes:
{"src_lang": "all", "title": "</Hello> World \" Test"...
As you see, quotes was being escaped, but not anything else. This can get interesting.
Attack method
The thing is, if you insert a closing element of </script>
inside a <script>
-element, you will always break out of the script element. It doesn’t matter where it is, you’ll break the node anyway. One great example of this is by looking at Chrome’s view-source with syntax highlighting and you’ll see what happens. This is the vulnerable example on Google Translate:
As you see here, we now break the current script, and will insert our own image with an onerror-attribute with our payload in it. Now let’s watch it in action:
By going to this URL, the XSS will trigger without any interaction.
But..
There’s one problem. This page will only render if the current user is a developer of the current application. In that sense, this is more of a Self XSS. Back to figuring out a way to attack someone else..
Reading about the Chrome Web Store it looks like there are some ways to actually invite other developers. After spending some time on it trying to figure out how, I was able to do the following:
- Create a new Chrome Webstore Developer account.
- Activate something called “Google Group publishing” which basically means that all users invited to this group gets to be a developer of the application. All the users in the group will have access to the application.
- Invite a victim to my Google Group.
- Wait about 30 minutes for it to reflect inside the Chrome Webstore Developer Dashboard.
- Send them the vulnerable URL.
- XSS will trigger!
Striiiiike two! A double!
Google Docs XSS using our nice friend Mr Flash.
In Google Docs there are a few sorts of charts you can create and embed to your Spreadsheet (or embed to any other document). One of these charts is called Trend / Motion Chart which is still made in Flash. This specific SWF-file is located on gstatic.com but embedded on docs.google.com. I noticed the following issue with the Flash file during my testing:
- Data is saved in the chart.
- Flash is loaded. The Flash gets a URL as a flash-parameter to load the data from the chart.
- Data is presented in the Flash. When doing actions with the Flash, it sends over data to docs.google.com using
ExternalInterface.call
through javascript.
Attack method
The issue I found was that backslashes was never escaped properly in the data presented to the Flash. And you probably already know that Flash does not properly handle backslashes. This meant, by creating the following Spreadsheet:
And then creating a chart out of it. Pressing any object in the Flash that triggered the ExternalInterface over to docs.google.com would trigger the payload provided in the chart:
This attack needed interaction, for example by clicking the red big dot. You could make the dot bigger or try to hide it below any other object, but it was sufficient to make Google patch this issue since the link could be shared with anyone.
Striiiiike three! A turkey!
(What a turkey is? Play bowling!)