
Un outil d'énumération d'ID de compte S3 et de découverte de buckets
Un outil d'énumération d'ID de compte S3 et de découverte de buckets
Étant donné un seul bucket S3 accessible, bucky extrait l'ID de compte AWS à 12 chiffres qui le possède, puis découvre d'autres buckets appartenant au même compte en testant des noms de bucket à partir d'une wordlist — le tout en une seule commande.
s3:ResourceAccount pour forcer brutalement l'ID de compte AWS à 12 chiffres, un chiffre à la fois, via des politiques de session STS inlineLes noms de bucket S3 partageaient à l'origine un espace de noms global unique, ce qui a donné naissance au bucketsquatting — des attaquants pouvaient squatter des noms qu'ils s'attendaient à ce que des organisations créent. AWS a résolu ce problème en déployant des espaces de noms régionaux par compte, un schéma de nommage qui lie chaque bucket à son compte et sa région propriétaires :
{nom}-{IDcompte}-{région}-an
Un bucket nommé myapp-123456789123-eu-north-1-an se trouverait à l'adresse https://myapp-123456789123-eu-north-1-an.s3.eu-north-1.amazonaws.com. AWS recommande désormais ce format pour les nouveaux buckets, bien qu'il ne soit pas encore le format par défaut. (Pour en savoir plus sur la façon dont le nouvel espace de noms élimine le bucketsquatting, consultez One Cloud Please.)
La contrepartie est que l'ID de compte et la région sont désormais intégrés dans le nom du bucket lui-même. Une fois qu'un attaquant obtient l'ID de compte d'une cible, il peut le combiner avec une wordlist et construire systématiquement des URL de bucket valides — et S3 confirmera si chacune existe, même si le bucket est privé. Cette seule réponse constitue une reconnaissance utile.
Bucky exploite exactement cela. S'appuyant sur des recherches de Pwned Labs, il récupère d'abord l'ID de compte à 12 chiffres à partir de n'importe quel bucket accessible en utilisant la technique s3-account-search, puis force brutalement le motif {nom}-{IDcompte}-{région}-an pour découvrir l'empreinte S3 plus large de la cible.
s3:ListBucket ou s3:GetObject sur le bucket ciblests:AssumeRole sur ce rôle, en passant une politique de session inline avec une condition s3:ResourceAccount comme "1*"1, l'appel HeadBucket réussit ; sinon, il retourne une erreur 403Cela nécessite au maximum 120 appels API (12 positions × 10 chiffres) et se termine généralement en moins d'une minute.
go installgo install github.com/umair9747/bucky@latest
git clone https://github.com/umair9747/bucky.git
cd bucky
go build -o bucky .
sudo mv bucky /usr/local/bin/
bucky --update
Cela télécharge et installe la dernière version depuis le dépôt.
Avant d'utiliser bucky, vous avez besoin d'un rôle IAM dans votre propre compte AWS qui peut accéder au bucket S3 cible. Le bucket cible doit être accessible publiquement ou avoir une politique de bucket qui permet l'accès depuis votre compte.
Créez trust-policy.json — cela permet à votre utilisateur IAM d'assumer le rôle :
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::<VOTRE_ID_COMPTE>:root"
},
"Action": "sts:AssumeRole"
}
]
}
Remplacez
<VOTRE_ID_COMPTE>par votre ID de compte AWS à 12 chiffres. Vous pouvez limiter le principal à un utilisateur IAM ou à un ARN de rôle spécifique au lieu de:root.
Créez s3-policy.json — le rôle nécessite un accès large en lecture S3 (la condition s3:ResourceAccount dans la politique de session inline de bucky gère le filtrage au niveau du compte) :
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket",
"s3:GetObject"
],
"Resource": "*"
}
]
}
aws iam create-role \
--role-name bucky-role \
--assume-role-policy-document file://trust-policy.json
aws iam put-role-policy \
--role-name bucky-role \
--policy-name S3ReadAccess \
--policy-document file://s3-policy.json
aws iam get-role --role-name bucky-role --query 'Role.Arn' --output text
# Sortie : arn:aws:iam::123456789012:role/bucky-role
Si votre utilisateur IAM n'a pas déjà la permission sts:AssumeRole, ajoutez-la :
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::<VOTRE_ID_COMPTE>:role/bucky-role"
}
]
}
La principale façon d'utiliser bucky — énumérer l'ID de compte à partir d'un bucket connu, puis tester pour trouver plus de buckets en une seule commande :
bucky \
--role-arn arn:aws:iam::123456789012:role/bucky-role \
--bucket target-bucket \
--wordlist wordlists/default.txt \
--access-key AKIA... \
--secret-key wJal...
Avec une clé d'objet connue (améliore la fiabilité) :
bucky \
--role-arn arn:aws:iam::123456789012:role/bucky-role \
--bucket s3://target-bucket/index.html \
--wordlist wordlists/default.txt \
--workers 20
Plusieurs buckets (séparés par des virgules) :
bucky \
--role-arn arn:aws:iam::123456789012:role/bucky-role \
--bucket bucket1,bucket2,bucket3 \
--wordlist wordlists/default.txt
Plusieurs buckets depuis un fichier :
bucky \
--role-arn arn:aws:iam::123456789012:role/bucky-role \
--bucket-file targets.txt \
--wordlist wordlists/default.txt
Sauvegarder les résultats au format JSON :
bucky --bucket target-bucket --wordlist wordlists/default.txt --json
bucky --bucket target-bucket --wordlist wordlists/default.txt --json --output results.json
Sortie :
=== Phase 1 : Énumération de l'ID de compte ===
[*] Vérification de l'accès au bucket : target-bucket
[+] Accès confirmé
[+] Région du bucket : us-west-2
[*] Énumération de l'ID de compte...
[██████████████████████████████] 12/12 | 675351422352
[+] ID de compte : 675351422352
=== Phase 2 : Découverte de buckets ===
[*] Test des buckets pour le compte : 675351422352
[*] 312 candidats chargés depuis la wordlist
[+] TROUVÉ : target-backups
[+] TROUVÉ : target-logs
[██████████████████████████████] 312/312 | 2 trouvés
=== Résumé ===
ID de compte : 675351422352
Source : target-bucket
Région : us-west-2
Découverts : 2 bucket(s) supplémentaire(s)
- target-backups
- target-logs
Si vous avez seulement besoin de l'ID de compte :
bucky enum \
--role-arn arn:aws:iam::123456789012:role/bucky-role \
--bucket target-bucket
Les buckets multiples et la sortie JSON fonctionnent aussi avec les sous-commandes :
bucky enum --bucket bucket1,bucket2 --json
bucky enum --bucket-file targets.txt --json --output results.json
Si vous avez déjà un ID de compte et souhaitez découvrir des buckets :
bucky fuzz \
--role-arn arn:aws:iam::123456789012:role/bucky-role \
--account-id 675351422352 \
--wordlist wordlists/default.txt \
--workers 20
Tous les drapeaux peuvent être définis via des variables d'environnement. Les drapeaux ont la priorité lorsque les deux sont définis.
export AWS_ACCESS_KEY_ID=AKIA...
export AWS_SECRET_ACCESS_KEY=wJal...
export BUCKY_ROLE_ARN=arn:aws:iam::123456789012:role/bucky-role
# Maintenant, spécifiez simplement la cible
bucky --bucket target-bucket --wordlist wordlists/default.txt
Bucky est livré avec une wordlist par défaut dans wordlists/default.txt contenant environ 300 motifs de nommage courants pour les buckets S3 :
backups, logs, data, assets, uploads)cloudtrail-logs, terraform-state, lambda-artifacts)prod-logs, staging-data, dev-backups)api, web-assets, cdn-origin)ci-artifacts, , )Pour des interventions ciblées, générez une wordlist personnalisée en préfixant le nom de l'organisation :
ORG="acme"
while read -r line; do
[[ "$line" =~ ^#.*$ || -z "$line" ]] && continue
echo "${ORG}-${line}"
echo "${line}-${ORG}"
echo "${ORG}${line}"
done < wordlists/default.txt > wordlists/acme.txt
Toute wordlist compatible avec des outils comme ffuf ou gobuster fonctionne. Format : un nom de bucket par ligne, les commentaires # et les lignes vides sont ignorés.
| Commande | Description |
|---|---|
bucky | Workflow complet — énumère l'ID de compte puis teste pour trouver plus de buckets |
bucky enum | Énumère l'ID de compte à 12 chiffres à partir d'un bucket connu |
bucky fuzz | Teste des noms de bucket avec un ID de compte connu |
Drapeaux globaux (toutes les commandes) :
bucky (workflow complet) :
| Drapeau | Description |
|---|
bucky enum :
| Drapeau | Description |
|---|---|
--bucket | Bucket(s) S3 cible(s), séparés par des virgules |
--bucket-file | Fichier avec les noms/URL des buckets, un par ligne |
bucky fuzz :
| Drapeau | Description |
|---|---|
Les drapeaux --bucket et --bucket-file acceptent plusieurs formats d'entrée. Bucky extrait automatiquement le nom du bucket (et la clé optionnelle) à partir de :
| Format | Exemple |
|---|---|
| Nom simple | my-bucket |
| URI S3 | s3://my-bucket/path/to/key |
Plusieurs buckets peuvent être passés séparés par des virgules via --bucket :
--bucket bucket1,s3://bucket2/key,https://bucket3.s3.amazonaws.com/
Ou listés un par ligne dans un fichier via --bucket-file :
my-bucket
s3://another-bucket/index.html
https://third.s3.us-east-1.amazonaws.com/
Lorsque plusieurs buckets correspondent au même ID de compte, bucky déduplique et n'exécute le test qu'une seule fois par compte unique.
Utilisez --json pour sauvegarder les résultats dans un fichier JSON. Le nom de fichier par défaut est bucky-{uuid}.json dans le répertoire courant, ou vous pouvez spécifier un chemin avec --output :
bucky --bucket target-bucket --wordlist wordlists/default.txt --json
bucky --bucket target-bucket --wordlist wordlists/default.txt --json --output results.json
Format de sortie :
{
"timestamp": "2024-01-15T10:30:00Z",
"results": [
{
"bucket": "target-bucket",
"account_id": "675351422352",
"region": "ap-south-1",
"discovered_buckets": [
"dev-675351422352-ap-south-1-an.s3.ap-south-1.amazonaws.com",
"prod-675351422352-ap-south-1-an.s3.ap-south-1.amazonaws.com"
]
}
]
}
Bucky détecte automatiquement la région des buckets cibles. Lorsque S3 retourne une redirection 301 (le bucket se trouve dans une région différente de --region), bucky résout la région correcte via l'en-tête de réponse HTTP x-amz-bucket-region et la met en cache pour toutes les requêtes suivantes. Aucune configuration manuelle de région n'est nécessaire pour le bucket cible.
Si vous avez des questions ou des retours sur Genzai ou si vous souhaitez simplement me contacter, n'hésitez pas à me joindre via LinkedIn ou par Email.
| Variable | Drapeau | Description |
|---|
AWS_ACCESS_KEY_ID | --access-key | ID de clé d'accès AWS |
AWS_SECRET_ACCESS_KEY | --secret-key | Clé d'accès secrète AWS |
AWS_SESSION_TOKEN | --session-token | Jeton de session AWS (pour les identifiants temporaires) |
AWS_REGION | --region | Région AWS (par défaut : us-east-1) |
AWS_DEFAULT_REGION | --region | Alternative si AWS_REGION n'est pas défini |
AWS_PROFILE | --profile | Profil nommé AWS depuis ~/.aws/credentials |
BUCKY_ROLE_ARN | --role-arn | ARN du rôle IAM à assumer |
BUCKY_BUCKET | --bucket | Nom du bucket S3 cible |
BUCKY_ACCOUNT_ID | --account-id | ID de compte AWS cible (uniquement fuzz) |
BUCKY_WORDLIST | --wordlist | Chemin vers le fichier wordlist |
BUCKY_WORKERS | --workers | Workers concurrents pour le test (par défaut : 10) |
build-outputdocker-images| Drapeau | Description |
|---|
--access-key | ID de clé d'accès AWS |
--secret-key | Clé d'accès secrète AWS |
--session-token | Jeton de session AWS |
--region | Région AWS (par défaut : us-east-1) |
--profile | Profil nommé AWS |
--role-arn | ARN du rôle IAM à assumer |
--json | Sauvegarde les résultats dans un fichier JSON |
--output | Chemin du fichier de sortie JSON (par défaut : bucky-{uuid}.json) |
--bucket | Bucket(s) S3 cible(s), séparés par des virgules |
--bucket-file | Fichier avec les noms/URL des buckets, un par ligne |
--wordlist | Chemin vers le fichier wordlist |
--workers | Workers concurrents (par défaut : 10) |
--account-id |
| ID de compte AWS cible à 12 chiffres |
--wordlist | Chemin vers le fichier wordlist |
--workers | Workers concurrents (par défaut : 10) |
--regions | Régions séparées par des virgules pour les mutations de noms |
| URL hébergée virtuelle |
https://my-bucket.s3.us-west-2.amazonaws.com/key |
| URL de style chemin | https://s3.us-west-2.amazonaws.com/my-bucket/key |