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.

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.
Using incremental IDs (also known as IDOR = Insecure Direct Object Reference) is a bad practice as it makes possible to enumerate through all the entries that exist in the database. One way of preventing this is to use UUIDs.

Saving projects
When a project is saved, a POST request to is sent to https://earth.google.com/studio/api/projects/
with the following JSON body:
{
"name": "My project",
"data": { .... some json project data .... },
"version": 16,
"folder": "https://earth.google.com/studio/api/folders/31337/"
}
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 put 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.

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.

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 file as well.
So we have a file with a JavaScript payload saved in someone’s folder.

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 buffer overflow 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
.

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 from 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
.

Summary
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.
Timeline:
30.01.2019: Vulnerability reported
31.01.2019: Priority changed to P2
31.01.2019: Accepted
05.02.2019: No reward issued