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

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:

Cloud SSRF - HackTricks

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:

Az - Azure App Services

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
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

bash
# 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

Az - Functions App Privesc

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