Introduction

Google Cloud Shell is a product of the Google Cloud Platform (GCP) that provides a number of interesting features, such as an interactive shell environment and an integrated code editor, with the intent of making experimenting and administration of GCP products easier while requiring very little setup.

As part of the Google Vulnerability Reward Program (VRP) I discovered that the code editor of the Cloud Shell exposed an endpoint serving arbitrary files, thus making the product vulnerable to Cross-Site Scripting (XSS).

Discovery

After discovering another XSS vulnerability in Google Cloud Shell's code editor where the XSS payload was served inside a SVG file I decided to take a closer look and try to find other variations of the initial attack scenario. The initial vulnerability was easily exploitable because image files were treated in a special way by the editor in that they were by default opened in preview mode instead of edit mode. I tried to perform the same exploit with a simple HTML file, but clicking on the file would only open it up in edit mode.

html-edit.png

Figure 1: A HTML file opened up inside the editor.

The editor also offered the option to manually open a HTML file in preview mode, which by then, as for SVG files, would also execute embedded scripts. However this was essentially caused by the same vulnerability and furthermore required an additional step, thus making a potential exploitation less likely.

html-preview.png

Figure 2: A HTML file whose embedded script gets executed when previewed inside the editor.

I therefore decided to go into another direction and see if the endpoint of the editor's mini-browser extension, which was used to serve files for previewing inside the Theia IDE, could be accessed by navigating to it directly within a separate browser window. It turned out that the file was served and the embedded script was executed.

html-script-execution.png

Figure 3: A HTML file with an embedded script served inside a separate window.

Exploitability

Since this XSS vulnerability is closely related to the XSS vulnerability caused by SVG files the potential impact would also the same. A successful exploit would allow a potential attacker the execution of arbitrary commands on the assigned user's virtual machine and could thus be used to obtain access to a Cloud Shell user's GCP resources.

Attack scenario

For a potential attacker to exploit this vulnerability they would have to accomplish two things:

  1. Put a malicious HTML file on the Cloud Shell user's environment.
  2. Make the Cloud Shell user navigate to the editor's endpoint serving the HTML file.

Doing some more research I found out that the "Open in Cloud Shell" feature, which I also used in the attack scenario of the related XSS vulnerability, could not only be used to automatically clone git repositories but also for automatically opening up cloned files inside the editor. I came up with the idea of automatically opening up a markdown file that contained a link to the malicious HTML file so that it would be more likely that the link would be clicked. This markdown file could then be included in the git repository together with the malicious HTML file.

markdown.png

Figure 4: A link in a markdown file displayed inside the editor.

Besides the link looking suspicious, that approach had another problem. The link, being of the form https://970-dot-123456789-dot-devshell.appspot.com/mini-browser/home/user/repository/page.html, varied for each Cloud Shell user. A unique ID is assigned to each Cloud Shell user which is used to make up the domain name. While the relative path to the malicious HTML file inside the repository was constant the absolute path also included the respective username. The complete link, including those variables, thus would have to be of the form https://970-dot-$ID-dot-devshell.appspot.com/mini-browser/home/$USER/repository/page.html.

I therefore had to find a way a potential attacker could obtain these variables. I decided to try whether a link clicked inside the editor would send referrer information. It turned out that the referrer information was included but only provided the required ID without the username. After further consideration I came up with the idea of inferring the required username from some other information, like an email address, which a potential attacker could possibly obtain in different ways. With these two pieces of information a potential attacker would then be able to construct the correct link and redirect the Cloud Shell user to the malicious page, enabling execution of the XSS payload.

markdown-referrer.png

Figure 5: Referrer information being forwarded when a link in a markdown file inside the editor is followed.

The steps of the final attack scenario are summarized as follows:

  1. A Cloud Shell user clicks on an "Open in Cloud Shell" link, cloning the repository and opening up a file containing a link to a page controlled by the attacker.
  2. repository.png

    Figure 6: A git repository containing an "Open in Cloud Shell" link.

  3. Inside the Cloud Shell's editor, the user clicks on the link, loading the page of the attacker with the referrer included.
  4. repository-cloned.png

    Figure 7: The git repository being cloned as a result of following an "Open in Cloud Shell" link.

  5. On the attacker's page, the Cloud Shell user provides their email address, enabling the attacker to derive the user name.
  6. input.png

    Figure 8: A possibility to obtain the final piece of information an attacker requires to perform an exploit.

  7. The attacker constructs the link to the malicious page and redirects the user to the address. The malicious page is loaded and the XSS payload is executed.

redirection.png

Figure 9: A Cloud Shell user being redirected to the malicious HTML file previously cloned into their Cloud Shell environment.

Fix

After a proof of concept had been submitted to Google the vulnerability was fixed. This was done by specifying the sandbox directive in the Content Security Policy (CSP) for any file served by the editor's mini-browser endpoint, as can be seen below:

@injectable()
export class CloudShellMiniBrowserEndpoint extends MiniBrowserEndpoint {
  protected async response(uri: string, response: Response): Promise<Response> {
    response.setHeader('content-security-policy', 'sandbox;');
    return super.response(uri, response);
  }
}

After the fix was applied, loading a HTML file served through the mini-browser's endpoint was would be blocked from executing its embedded script code.

html-script-blocked.png

Figure 10: A sandboxed HTML file whose embedded script gets blocked from execution.

The fix implemented for the related vulnerability, where a malicious SVG file was embedded in an iframe inside the Cloud Shell's editor, would only sandbox the files when served through the editor's web application. This additional fix, however, provides sandboxing whenever files are served through that endpoint.

Take away messages

  • While the sandbox attribute of an iframe protects from XSS attacks when user-provided resources are embedded in that particular context it does not provide protection in case the browser is navigated to such resources directly. This is particularly problematic when embedded and embedding content are served from the same origin. In such a scenario untrusted user-provided resources should be served with the sandbox directive in the CSP.
  • When integrating components, such as the Theia IDE, into larger projects, such as Google Cloud Shell, it is necessary to check whether the component's security measures are also adequate within the context of the larger project or customization is required.