Inserting arbitrary files into anyone’s Google Earth Studio Projects Archive

Google Earth Studio is a web-based animation tool for Google Earth’s satellite and 3D imagery. It was first released in 2018 as an invite-only beta.

Google Earth Studio
Google Earth Studio landing screen

Creating projects and folders

Google Earth Studio lets users create 3D animations which are saved in projects. Each project contains information like its name, what folder it is stored in, when it was last created/edited, and so on.

Every project is saved in a folder — either the root folder or a sub-folder the user has created. Surprisingly, folders have incremental IDs. That means the first folder ever created has ID 0, the thousandth folder has ID 999 etc.

Allowing access to resources using incremental IDs (also known as IDOR = Insecure Direct Object Reference) is a bad practice as — if proper authorization restrictions are missing — it makes it possible to enumerate through all the entries that exist in the database. One way of preventing this is to use UUIDs.

Google Earth Studio Open Project Dialog
Open project dialog with projects and folders

Saving projects

When a project is saved, a POST request is sent to with the following JSON body:

  "name": "My project",
  "data": { .... some json project data .... },
  "version": 16,
  "folder": ""

The folder parameter contains a reference to the folder ID where it’s going to be saved, name is the title of the project and data contains a JSON object with the project configuration.

In this case, 31337 is an ID of a folder we have created before in our account. If however, another user creates a new folder in their own account that will have ID let’s say 12345 — and we use this ID (12345) instead of the ID of our own folder, the project will get saved there!

That means it’s possible to save our projects into folders that we don’t own.

Although the project is saved in the folder of another user, the user won’t see that project listed there. The code that shows the projects most likely checks if the user is the owner of the project as well.

Projects Archive

There’s however a place where the project does show up in the folder — the Projects Archive.

Google Earth Studio Preferences
Google Earth Studio preferences

The Projects Archive is a zip file that contains a copy of all your projects.

The projects are stored in .esp files with their name as the filename and in corresponding folders. The content of the file is simply the data value as a serialized JSON. And this time the project we have created is included here as well.

So far we have found a way to save projects into zip archives of other users.

Google Earth Studio zip Archive
Project .zip archive

File payload

Since we know that the project’s data JSON value is reflected in the file’s content, we can try changing the JSON itself. As it turns out, we can change the value to any valid JSON. And a string is a valid JSON as well.

This means if we change the data value to <script>alert('oops')</script>, this payload is going to be reflected in the file as well.

So we have a file with a JavaScript payload saved in someone’s folder.

HTML payload source
HTML file with a payload

Changing the filename

When we open the file, the payload won’t be executed because the filename still ends with .esp. The filename is made with the project’s name and the just mentioned file extension. This gives us control of the filename — or at least the part before the extension — by changing the project’s name.

Changing the name simply to dangerous_file.html won’t work as the resulting filename will be dangerous_file.html.esp.

I tried to make the filename really long, hoping for some kind of overflow vulnerability that would make the filename end with .html. I’ve seen this one work in PHP, but unfortunately, it didn’t work this time.

Another option would be to add a null character at the end of the filename. Fortunately, adding special characters is easy in JSON. All we need to do is: dangerous_file.html\u0000.

JSON request
JSON request with modified parameters

In most low-level programming languages, a null byte represents the termination of a string, which means that what would be dangerous_file.html<NULL>.esp becomes dangerous_file.html just thanks to the fact that null is treated as the end of the string. Many frameworks/languages defend against this Null Byte Injection by simply not allowing null characters in the filename, but this was not the case at Google’s side.

Now we have a file saved in someone else’s folder, the file contains a JavaScript payload in a script tag, and the file is saved as .html.

Malicious files in a .zip archive
Malicious files in a .zip archive


Thanks to multiple combined vulnerabilities we are able to insert arbitrary files into anyone’s Google Earth Studio Projects Archive.

All we need now is that a user downloads their Projects Archive and opens the malicious file.

Google decided that this issue is not severe enough to qualify for a reward, but they fixed the vulnerability anyways.

2019-01-30Vulnerability reported
2019-01-31Priority changed to P2
2019-02-05No reward issued
Follow me on Twitter: @ThomasOrlita