Az - Function Apps
Reading time: 14 minutes
tip
Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
- Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.
Informações Básicas
Azure Function Apps são um serviço de computação sem servidor que permite executar pequenos trechos de código, chamados de funções, sem gerenciar a infraestrutura subjacente. Elas são projetadas para executar código em resposta a vários gatilhos, como requisições HTTP, temporizadores ou eventos de outros serviços Azure como Blob Storage ou Event Hubs. Function Apps suportam várias linguagens de programação, incluindo C#, Python, JavaScript e Java, tornando-as versáteis para construir aplicações orientadas a eventos, automatizar fluxos de trabalho ou integrar serviços. Elas são econômicas, pois você geralmente paga apenas pelo tempo de computação utilizado quando seu código é executado.
note
Note que Functions são um subconjunto dos App Services, portanto, muitas das funcionalidades discutidas aqui também serão utilizadas por aplicações criadas como Azure Apps (webapp
no cli).
Planos Diferentes
- Flex Consumption Plan: Oferece escalonamento dinâmico e orientado a eventos com preços pay-as-you-go, adicionando ou removendo instâncias de função com base na demanda. Suporta rede virtual e instâncias pré-provisionadas para reduzir inícios a frio, tornando-o adequado para cargas de trabalho variáveis que não requerem suporte a contêineres.
- Traditional Consumption Plan: A opção sem servidor padrão, onde você paga apenas pelos recursos de computação quando as funções são executadas. Ele escala automaticamente com base nos eventos recebidos e inclui otimizações de início a frio, mas não suporta implantações de contêiner. Ideal para cargas de trabalho intermitentes que requerem escalonamento automático.
- Premium Plan: Projetado para desempenho consistente, com trabalhadores pré-aquecidos para eliminar inícios a frio. Oferece tempos de execução estendidos, rede virtual e suporta imagens personalizadas do Linux, tornando-o perfeito para aplicações críticas que necessitam de alto desempenho e recursos avançados.
- Dedicated Plan: Executa em máquinas virtuais dedicadas com faturamento previsível e suporta escalonamento manual ou automático. Permite executar várias apps no mesmo plano, fornece isolamento de computação e garante acesso seguro à rede por meio de App Service Environments, tornando-o ideal para aplicações de longa duração que necessitam de alocação consistente de recursos.
- Container Apps: Permite implantar function apps containerizadas em um ambiente gerenciado, ao lado de microsserviços e APIs. Suporta bibliotecas personalizadas, migração de aplicativos legados e processamento GPU, eliminando a necessidade de gerenciamento de clusters Kubernetes. Ideal para aplicações containerizadas escaláveis e orientadas a eventos.
Buckets de Armazenamento
Ao criar um novo Function App não containerizado (mas fornecendo o código para executar), os códigos e outros dados relacionados à função serão armazenados em uma conta de Armazenamento. Por padrão, o console da web criará um novo por função para armazenar o código.
Além disso, ao modificar o código dentro do bucket (nos diferentes formatos em que pode ser armazenado), o código do aplicativo será modificado para o novo e executado na próxima vez que a Função for chamada.
caution
Isso é muito interessante do ponto de vista de um atacante, pois o acesso de gravação sobre este bucket permitirá que um atacante comprometa o código e eleve privilégios para as identidades gerenciadas dentro do Function App.
Mais sobre isso na seção de elevação de privilégios.
Também é possível encontrar as chaves mestre e de funções armazenadas na conta de armazenamento no contêiner azure-webjobs-secrets
dentro da pasta <app-name>
nos arquivos JSON que você pode encontrar dentro.
Note que as Functions também permitem armazenar o código em um local remoto apenas indicando a URL para ele.
Networking
Usando um gatilho HTTP:
- É possível dar acesso a uma função de toda a Internet sem exigir qualquer autenticação ou dar acesso baseado em IAM. Embora também seja possível restringir esse acesso.
- Também é possível dar ou restringir acesso a um Function App de uma rede interna (VPC).
caution
Isso é muito interessante do ponto de vista de um atacante, pois pode ser possível pivotar para redes internas a partir de uma Function vulnerável exposta à Internet.
Configurações do Function App & Variáveis de Ambiente
É possível configurar variáveis de ambiente dentro de um aplicativo, que podem conter informações sensíveis. Além disso, por padrão, as variáveis de ambiente AzureWebJobsStorage
e WEBSITE_CONTENTAZUREFILECONNECTIONSTRING
(entre outras) são criadas. Estas são especialmente interessantes porque contêm a chave da conta para controlar com PERMISSÕES COMPLETAS a conta de armazenamento contendo os dados da aplicação. Essas configurações também são necessárias para executar o código da Conta de Armazenamento.
Essas variáveis de ambiente ou parâmetros de configuração também controlam como a Função executa o código, por exemplo, se WEBSITE_RUN_FROM_PACKAGE
existir, isso indicará a URL onde o código da aplicação está localizado.
Function Sandbox
Dentro do sandbox linux, o código-fonte está localizado em /home/site/wwwroot
no arquivo function_app.py
(se python for usado) o usuário que executa o código é app
(sem permissões sudo).
Em uma função Windows usando NodeJS, o código estava localizado em C:\home\site\wwwroot\HttpTrigger1\index.js
, o nome de usuário era mawsFnPlaceholder8_f_v4_node_20_x86
e fazia parte dos grupos: Mandatory Label\High Mandatory Level Label
, Everyone
, BUILTIN\Users
, NT AUTHORITY\INTERACTIVE
, CONSOLE LOGON
, NT AUTHORITY\Authenticated Users
, NT AUTHORITY\This Organization
, BUILTIN\IIS_IUSRS
, LOCAL
, 10-30-4-99\Dwas Site Users
.
Identidades Gerenciadas & Metadados
Assim como VMs, Functions podem ter Identidades Gerenciadas de 2 tipos: Atribuídas pelo sistema e Atribuídas pelo usuário.
A atribuição pelo sistema será uma identidade gerenciada que apenas a função que a tem atribuída poderá usar, enquanto as identidades gerenciadas atribuidas pelo usuário são identidades gerenciadas que qualquer outro serviço Azure poderá usar.
note
Assim como em VMs, Functions podem ter 1 identidade gerenciada atribuída pelo sistema e várias atribuídas pelo usuário, então é sempre importante tentar encontrar todas elas se você comprometer a função, pois você pode ser capaz de elevar privilégios para várias identidades gerenciadas a partir de apenas uma Função.
Se uma identidade gerenciada pelo sistema não for usada, mas uma ou mais identidades gerenciadas pelo usuário estiverem anexadas a uma função, por padrão você não poderá obter nenhum token.
É possível usar os scripts PEASS para obter tokens da identidade gerenciada padrão a partir do endpoint de metadados. Ou você pode obtê-los manualmente como explicado em:
Note que você precisa descobrir uma maneira de verificar todas as Identidades Gerenciadas que uma função tem anexadas, pois se você não indicar, o endpoint de metadados usará apenas a padrão (verifique o link anterior para mais informações).
Chaves de Acesso
note
Note que não há permissões RBAC para dar acesso a usuários para invocar as funções. A invocação da função depende do gatilho selecionado quando foi criada e se um Gatilho HTTP foi selecionado, pode ser necessário usar uma chave de acesso.
Ao criar um endpoint dentro de uma função usando um gatilho HTTP, é possível indicar o nível de autorização da chave de acesso necessário para acionar a função. Três opções estão disponíveis:
- ANONYMOUS: Todos podem acessar a função pela URL.
- FUNCTION: O endpoint é acessível apenas para usuários usando uma chave de função, host ou mestre.
- ADMIN: O endpoint é acessível apenas para usuários com uma chave mestre.
Tipo de chaves:
- Chaves de Função: As chaves de função podem ser padrão ou definidas pelo usuário e são projetadas para conceder acesso exclusivamente a endpoints de função específicos dentro de um Function App, permitindo um acesso mais granular sobre os endpoints.
- Chaves de Host: As chaves de host, que também podem ser padrão ou definidas pelo usuário, fornecem acesso a todos os endpoints de função dentro de um Function App com nível de acesso FUNCTION.
- Chave Mestre: A chave mestre (
_master
) serve como uma chave administrativa que oferece permissões elevadas, incluindo acesso a todos os endpoints de função (nível de acesso ADMIN incluído). Esta chave não pode ser revogada. - Chaves do Sistema: As chaves do sistema são gerenciadas por extensões específicas e são necessárias para acessar endpoints de webhook usados por componentes internos. Exemplos incluem o gatilho do Event Grid e Funções Duráveis, que utilizam chaves do sistema para interagir de forma segura com suas respectivas APIs.
tip
Exemplo para acessar um endpoint de API de função usando uma chave:
https://<function_uniq_name>.azurewebsites.net/api/<endpoint_name>?code=<access_key>
Autenticação Básica
Assim como nos App Services, Functions também suportam autenticação básica para conectar ao SCM e FTP para implantar código usando um nome de usuário e senha em uma URL fornecida pelo Azure. Mais informações sobre isso em:
Implantações Baseadas no Github
Quando uma função é gerada a partir de um repositório do Github, o console web do Azure permite criar automaticamente um Workflow do Github em um repositório específico, de modo que sempre que este repositório for atualizado, o código da função seja atualizado. Na verdade, o yaml da Ação do Github para uma função em python se parece com isso:
Github Action Yaml
# Docs for the Azure Web Apps Deploy action: https://github.com/azure/functions-action
# More GitHub Actions for Azure: https://github.com/Azure/actions
# More info on Python, GitHub Actions, and Azure Functions: https://aka.ms/python-webapps-actions
name: Build and deploy Python project to Azure Function App - funcGithub
on:
push:
branches:
- main
workflow_dispatch:
env:
AZURE_FUNCTIONAPP_PACKAGE_PATH: "." # set this to the path to your web app project, defaults to the repository root
PYTHON_VERSION: "3.11" # set this to the python version to use (supports 3.6, 3.7, 3.8)
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Python version
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Create and start virtual environment
run: |
python -m venv venv
source venv/bin/activate
- name: Install dependencies
run: pip install -r requirements.txt
# Optional: Add step to run tests here
- name: Zip artifact for deployment
run: zip release.zip ./* -r
- name: Upload artifact for deployment job
uses: actions/upload-artifact@v4
with:
name: python-app
path: |
release.zip
!venv/
deploy:
runs-on: ubuntu-latest
needs: build
permissions:
id-token: write #This is required for requesting the JWT
steps:
- name: Download artifact from build job
uses: actions/download-artifact@v4
with:
name: python-app
- name: Unzip artifact for deployment
run: unzip release.zip
- name: Login to Azure
uses: azure/login@v2
with:
client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_6C3396368D954957BC58E4C788D37FD1 }}
tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_7E50AEF6222E4C3DA9272D27FB169CCD }}
subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_905358F484A74277BDC20978459F26F4 }}
- name: "Deploy to Azure Functions"
uses: Azure/functions-action@v1
id: deploy-to-function
with:
app-name: "funcGithub"
slot-name: "Production"
package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}
Além disso, uma Identidade Gerenciada também é criada para que a Ação do Github do repositório possa fazer login no Azure com ela. Isso é feito gerando uma credencial Federada sobre a Identidade Gerenciada, permitindo o Emissor https://token.actions.githubusercontent.com
e o Identificador do Sujeito repo:<org-name>/<repo-name>:ref:refs/heads/<branch-name>
.
caution
Portanto, qualquer pessoa que comprometer esse repositório poderá comprometer a função e as Identidades Gerenciadas anexadas a ela.
Implantações Baseadas em Contêiner
Nem todos os planos permitem implantar contêineres, mas para aqueles que permitem, a configuração conterá a URL do contêiner. Na API, a configuração linuxFxVersion
terá algo como: DOCKER|mcr.microsoft.com/...
, enquanto na console web, a configuração mostrará as configurações da imagem.
Além disso, nenhum código-fonte será armazenado na conta de armazenamento relacionada à função, pois não é necessário.
Enumeração
# List all the functions
az functionapp list
# List functions in an function-app (endpoints)
az functionapp function list \
--name <app-name> \
--resource-group <res-group>
# Get details about the source of the function code
az functionapp deployment source show \
--name <app-name> \
--resource-group <res-group>
## If error like "This is currently not supported."
## Then, this is probalby using a container
# Get more info if a container is being used
az functionapp config container show \
--name <name> \
--resource-group <res-group>
# Get settings (and privesc to the sorage account)
az functionapp config appsettings list --name <app-name> --resource-group <res-group>
# Get access restrictions
az functionapp config access-restriction show --name <app-name> --resource-group <res-group>
# Check if a domain was assigned to a function app
az functionapp config hostname list --webapp-name <app-name> --resource-group <res-group>
# Get SSL certificates
az functionapp config ssl list --resource-group <res-group>
# Get network restrictions
az functionapp config access-restriction show --name <app-name> --resource-group <res-group>
# Get acess restrictions
az functionapp config access-restriction show --name <app-name> --resource-group <res-group>
# Get connection strings
az rest --method POST --uri "https://management.azure.com/subscriptions/<subscription>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/config/connectionstrings/list?api-version=2022-03-01"
az rest --method GET --uri "https://management.azure.com/subscriptions/<subscription>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/config/configreferences/connectionstrings?api-version=2022-03-01"
# Get SCM credentials
az functionapp deployment list-publishing-credentials --name <app-name> --resource-group <res-group>
# Get function, system and master keys
az functionapp keys list --name <app-name> --resource-group <res-group>
# Get Host key
az rest --method POST --uri "https://management.azure.com/<subscription>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/functions/<function-endpoint-name>/listKeys?api-version=2022-03-01"
# Get source code with Master Key of the function
curl "<script_href>?code=<master-key>"
curl "https://<func-app-name>.azurewebsites.net/admin/vfs/home/site/wwwroot/function_app.py?code=<master-key>" -v
# Get source code using SCM access (Azure permissions or SCM creds)
az rest --method GET \
--url "https://<func-app-name>.azurewebsites.net/admin/vfs/home/site/wwwroot/function_app.py?code=<master-key>" \
--resource "https://management.azure.com/"
# Get source code with Azure permissions
az rest --url "https://management.azure.com/subscriptions/<subscription>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/hostruntime/admin/vfs/function_app.py?relativePath=1&api-version=2022-03-01"
## Another example
az rest --url "https://management.azure.com/subscriptions/9291ff6e-6afb-430e-82a4-6f04b2d05c7f/resourceGroups/Resource_Group_1/providers/Microsoft.Web/sites/ConsumptionExample/hostruntime/admin/vfs/HttpExample/index.js?relativePath=1&api-version=2022-03-01"
Escalação de Privilégios
Referências
tip
Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
- Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.