# cloud-bucket-brute

Discover publicly readable cloud storage by permuting a company name into likely bucket names and probing AWS S3, Google Cloud, DigitalOcean, Alibaba, Oracle, and Vultr. Use to find exposed buckets.

- **Kind:** skill
- **Source:** https://github.com/forefy/.context
- **Page:** https://forefy.com/skills/25d91ea5-ab71-4618-baed-afa85230a647
- **API (JSON + files):** https://forefy.com/api/asr/25d91ea5-ab71-4618-baed-afa85230a647

---

## SKILL.md

---
name: cloud-bucket-brute
description: Discover publicly readable cloud storage by permuting a company name into likely bucket names and probing AWS S3, Google Cloud, DigitalOcean, Alibaba, Oracle, and Vultr. Use to find exposed buckets.
---

## Contents
- Scope & authorization
- Name permutation scheme
- Probe logic
- Runnable snippets
- Output
- Reference file: `references/cloud-storage-endpoints.md`

## Scope & authorization

Run only against organizations you own or are contractually engaged to test. This is an **aggressive-3rdparty** check: it does not touch the target's own infrastructure, but it fires a high volume of requests at third-party cloud providers (AWS/GCP/DigitalOcean/Alibaba/Oracle/Vultr) about the target. Expect provider-side rate-limiting and logging. Keep the candidate list scoped to the org actually in scope.

Input is the set of the target's domains. Output is any bucket name that resolves to an anonymously reachable object store.

## Name permutation scheme

Turn each in-scope domain into candidate bucket names (this is the valuable part - carry it exactly):
1. Reduce the domain to its registrable root label (`tldextract(...).domain`, e.g. `foo-bar.co.uk` -> `foo-bar`) and seed the variation set with the raw name.
2. If the root contains `-`, split into `name` + `second_name`, and also add the **initials** `name[0]+second_name[0]`.
3. For each "common company word" that appears inside the root (`company, group, tech, solutions, international, services, world, global, ai, io, team, inc, ask, digital, data, bits, bit, open, edu, educaiton, learning, auto, stack`), add the name with that word **stripped out**, plus the **initials** of the two parts around it. (So `bugcrowd` yields `bugcrowd`, `bug`/`crowd` fragments, `bc`, etc.)
4. Expand every variation through the permutation templates against the suffix wordlist. Bare `{name}` is always tried; multi-word templates (`{name}_{word}`, `{word}-{name}`, `{word}_{name}`, `{name}{word}`, `{name}{second_name}`, `{name}{second_name}-{word}`, `{name}{second_name}_{word}`, `{name}-{second_name}-{word}`, `{name}_{second_name}_{word}`, `{name}{second_name}{word}`) are only applied to non-domain-looking single/two-part variations.

The full provider endpoint templates, per-provider **fail indications**, region lists, the 40-word suffix list, and the permutation templates are in `references/cloud-storage-endpoints.md`.

## Probe logic

For each candidate: GET the endpoint (5s timeout). Parse the body as XML/JSON/text by `Content-Type`. By default pick **one random region** per region-templated endpoint (set an "iterate all regions" flag only for a deep, much slower pass). Discard any response containing that provider's fail indications (e.g. AWS `AccessDenied`, `NoSuchBucket`, `IllegalLocationConstraintException`, `AllAccessDisabled`, `PermanentRedirect`; GCP `The specified bucket does not exist` / `Anonymous caller does not have storage.buckets.get`; Oracle `AnonymousUserSubject`; Vultr/DO `NoSuchBucket`), and discard any body containing `Burp Suite Professional` (interception artifact).

**Report a finding when**: an endpoint returns a body with **none** of its fail indications - the bucket exists and is anonymously reachable. Severity: Information Disclosure (verify listability/read of objects before rating impact).

## Runnable snippets

```bash
# single candidate, AWS virtual-host + GCP JSON API
NAME=acme-backups
curl -s "https://$NAME.s3.amazonaws.com" | grep -qiE 'AccessDenied|NoSuchBucket|IllegalLocationConstraint|AllAccessDisabled' \
  && echo "aws: not public" || echo "aws: PUBLIC/exists -> https://$NAME.s3.amazonaws.com"
curl -s "https://www.googleapis.com/storage/v1/b/$NAME" | grep -qiE 'does not exist|does not have storage.buckets.get' \
  && echo "gcp: not public" || echo "gcp: PUBLIC/exists"
```

```bash
# generate candidate names (permutation scheme) for a domain
python3 - <<'PY'
import tldextract
words=["archive","artifacts","assets","backup","bin","bucket","data","dev","dev-data","dev_data","devops","files","git","it","logs","media","mediauploads","onboarding","ops","proj","project","prod","prod-data","prod_data","prod-files","prod_files","reports","scripts","stage","staging","static","storage","temp","terraform","tf","tf-files","tf_files","terraformbinaries","test","tmp","user-files","user_files","uploads"]
common={"company","group","tech","solutions","international","services","world","global","ai","io","team","inc","ask","digital","data","bits","bit","open","edu","educaiton","learning","auto","stack"}
name=tldextract.extract("acme-corp.com").domain
variations=[(name,)]
if "-" in name:
    a,b=name.split("-",1); variations+=[(a,b),(a[0]+b[0],)]
for w in common:
    if w in name:
        variations+=[(name.replace(w,""),)]
tmpl_base=["{name}"]
tmpl_multi=["{name}_{word}","{word}-{name}","{word}_{name}","{name}{word}","{name}{second_name}","{name}{second_name}-{word}","{name}{second_name}_{word}","{name}-{second_name}-{word}","{name}_{second_name}_{word}","{name}{second_name}{word}"]
out=[]
for v in variations:
    tmpls=tmpl_base+(tmpl_multi if len(v)<=2 else [])
    for w in words:
        for t in tmpls:
            if "{second_name}" in t and len(v)!=2: continue
            s=t.replace("{name}",v[0]).replace("{word}",w)
            if len(v)==2: s=s.replace("{second_name}",v[1])
            if s not in out: out.append(s)
print("\n".join(out))
PY
```

## Output

Finish with a `candidate / provider / reachable?` ledger (or just the confirmed hits when the candidate list is large), then a verdict:
- **Clean** - candidates generated and probed across all six providers, nothing anonymously reachable.
- **Exposed** - list each public bucket URL, its provider, and whether objects are listable/readable. Fix: make buckets private, require authentication, and audit bucket-policy/ACL for anonymous grants.

Report whether the sweep was rate-limited or partial (e.g. one-region-only), so an incomplete run is not reported as clean.

## references

```

```

## references/cloud-storage-endpoints.md

# Cloud-storage endpoints, fail indications & name permutations (Step 1)

Full provider endpoints, fail indications, and region lists for the public-bucket brute, plus
the name-permutation wordlists and templates.

## Contents
- Provider endpoints and fail indications (AWS, GCS, DigitalOcean, Alibaba, Oracle, Vultr)
- Name permutation wordlists (suffix words, common company words)
- Permutation templates and variation-building rules

## Provider endpoints and fail indications

Substitute `{name}` (candidate bucket name) and `{region}`. Treat a response as "exists / public"
only if its body contains NONE of that endpoint's fail indications (and does not contain
`Burp Suite Professional`). Parse XML/JSON/text by Content-Type; 5s timeout.

### AWS S3
- `https://{name}.s3.amazonaws.com`
  fail: `AccessDenied`, `NoSuchBucket`, `IllegalLocationConstraintException`, `AllAccessDisabled`
- `https://{name}.s3-{region}.amazonaws.com`
  fail: `AccessDenied`, `NoSuchBucket`, `PermanentRedirect`, `IllegalLocationConstraintException`, `AllAccessDisabled`
  regions: us-east-2, us-east-1, us-west-1, us-west-2, af-south-1, ap-east-1, ap-south-2,
  ap-southeast-3, ap-southeast-4, ap-south-1, ap-northeast-3, ap-northeast-2, ap-southeast-1,
  ap-southeast-2, ap-northeast-1, ca-central-1, eu-central-1, eu-west-1, eu-west-2, eu-south-1,
  eu-west-3, eu-south-2, eu-north-1, eu-central-2, il-central-1, me-south-1, me-central-1,
  sa-east-1, us-gov-east-1, us-gov-west-1

### Google Cloud Storage
- `https://www.googleapis.com/storage/v1/b/{name}`
  fail: `The specified bucket does not exist`, `Anonymous caller does not have storage.buckets.get`
- `https://{name}.storage.googleapis.com/`
  fail: (none - treat any non-error body as a hit; inspect manually)

### DigitalOcean Spaces
- `https://{name}.{region}.digitaloceanspaces.com`
  fail: (none defined - inspect body)
  regions: nyc1, nyc3, ams3, sfo2, sfo3, sgp1, lon1, fra1, tor1, blr1, syd1

### Alibaba OSS
- `https://{name}.oss-{region}.aliyuncs.com`
  fail: (none defined - inspect body)
  regions: oss-cn-hangzhou, oss-cn-shanghai, oss-cn-nanjing, oss-cn-qingdao, oss-cn-beijing,
  oss-cn-zhangjiakou, oss-cn-huhehaote, oss-cn-wulanchabu, oss-cn-shenzhen, oss-cn-heyuan,
  oss-cn-guangzhou, oss-cn-chengdu, oss-cn-hongkong, oss-us-west-1, oss-us-east-1,
  oss-ap-northeast-1, oss-ap-northeast-2, oss-ap-southeast-1, oss-ap-southeast-2,
  oss-ap-southeast-3, oss-ap-southeast-5, oss-ap-southeast-6, oss-ap-southeast-7, oss-ap-south-1,
  oss-eu-central-1, oss-eu-west-1, oss-me-east-1

### Oracle Cloud Object Storage (S3-compat)
- `https://{name}.compat.objectstorage.{region}.oraclecloud.com`
  fail: `AnonymousUserSubject`
  regions: ap-sydney-1, ap-melbourne-1, sa-saopaulo-1, sa-vinhedo-1, ca-montreal-1, ca-toronto-1,
  sa-santiago-1, eu-paris-1, eu-marseille-1, eu-frankfurt-1, ap-hyderabad-1, ap-mumbai-1,
  il-jerusalem-1, eu-milan-1, ap-osaka-1, ap-tokyo-1, mx-queretaro-1, mx-monterrey-1,
  eu-amsterdam-1, me-jeddah-1, eu-jovanovac-1, ap-singapore-1, af-johannesburg-1, ap-seoul-1,
  ap-chuncheon-1, eu-madrid-1, eu-stockholm-1, eu-zurich-1, me-abudhabi-1, me-dubai-1

### Vultr Object Storage
- `https://{region}.vultrobjects.com/{name}`
  fail: `NoSuchBucket`
  regions: ams1, blr1, ewr1, sjc1, sgp1, del1

By default probe **one random region** per region-templated endpoint (keep volume sane against
third-party infra). Only iterate every region for a deliberate deep pass.

## Name permutation wordlists

### Suffix words (appended/prefixed via templates)
archive, artifacts, assets, backup, bin, bucket, data, dev, dev-data, dev_data, devops, files,
git, it, logs, media, mediauploads, onboarding, ops, proj, project, prod, prod-data, prod_data,
prod-files, prod_files, reports, scripts, stage, staging, static, storage, temp, terraform, tf,
tf-files, tf_files, terraformbinaries, test, tmp, user-files, user_files, uploads

### Common company words (used to split the root label into fragments/initials)
company, group, tech, solutions, international, services, world, global, ai, io, team, inc, ask,
digital, data, bits, bit, open, edu, educaiton, learning, auto, stack

### Permutation templates
- Base (always applied): `{name}`
- Non-domain (applied only to non-domain-looking single/two-part variations):
  `{name}_{word}`, `{word}-{name}`, `{word}_{name}`, `{name}{word}`, `{name}{second_name}`,
  `{name}{second_name}-{word}`, `{name}{second_name}_{word}`, `{name}-{second_name}-{word}`,
  `{name}_{second_name}_{word}`, `{name}{second_name}{word}`

Variation building: root label via `tldextract`; if it contains `-`, split into
`name`/`second_name` and add initials `name[0]+second_name[0]`; for each common word found inside
the root, add the root with that word removed and the initials of the two surrounding parts.

