
S3 계정 ID 열거 및 버킷 발견 도구
S3 계정 ID 열거 및 버킷 검색 도구
단일 접근 가능한 S3 버킷이 주어지면, bucky는 소유한 12자리 AWS 계정 ID를 추출한 후, 단일 명령으로 단어 목록을 사용하여 버킷 이름을 퍼징(fuzzing)하여 동일 계정의 추가 버킷을 발견합니다.
s3:ResourceAccount IAM 조건 키를 사용하여 인라인 STS 세션 정책을 통해 12자리 AWS 계정 ID를 한 자리씩 무차별 대입(brute-force)합니다.S3 버킷 이름은 원래 단일 글로벌 네임스페이스를 공유했으며, 이로 인해 버킷스쿼팅(bucketsquatting) 이 발생했습니다. 공격자는 조직이 생성할 것으로 예상되는 이름을 선점할 수 있었습니다. AWS는 계정-리전 네임스페이스를 도입하여 이를 해결했습니다. 이 명명 체계는 각 버킷을 소유 계정 및 리전에 연결합니다.
{name}-{accountID}-{region}-an
myapp-123456789123-eu-north-1-an이라는 버킷은 https://myapp-123456789123-eu-north-1-an.s3.eu-north-1.amazonaws.com에 위치합니다. AWS는 이제 새 버킷에 대해 이 형식을 권장하지만 아직 기본값은 아닙니다. (새 네임스페이스가 버킷스쿼팅을 없애는 배경은 One Cloud Please를 참조하세요.)
단점은 계정 ID와 리전이 이제 버킷 이름 자체에 포함된다는 것입니다. 공격자가 대상의 계정 ID를 얻으면 단어 목록과 결합하여 체계적으로 유효한 버킷 URL을 구성할 수 있으며, S3는 버킷이 비공개인 경우에도 각각이 존재하는지 확인해 줍니다. 그 응답만으로도 유용한 정찰 정보가 됩니다.
Bucky는 바로 이 점을 악용합니다. Pwned Labs의 연구를 기반으로, 먼저 s3-account-search 기술을 사용하여 접근 가능한 모든 버킷에서 12자리 계정 ID를 복구한 다음, {name}-{accountID}-{region}-an 패턴을 무차별 대입하여 대상의 더 넓은 S3 공격 표면을 드러냅니다.
s3:ListBucket 또는 s3:GetObject 권한이 있는 IAM 역할을 생성합니다.sts:AssumeRole을 호출하고, "1*"과 같은 s3:ResourceAccount 조건이 포함된 인라인 세션 정책을 전달합니다.1로 시작하면 HeadBucket 호출이 성공하고, 그렇지 않으면 403을 반환합니다.이 과정은 최대 120회의 API 호출(12개 위치 × 10자리 숫자)이 필요하며 일반적으로 1분 이내에 완료됩니다.
go install 사용go 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
이 명령은 리포지토리에서 최신 버전을 가져와 설치합니다.
bucky를 사용하기 전에 자신의 AWS 계정에 대상 S3 버킷에 접근할 수 있는 IAM 역할이 필요합니다. 대상 버킷은 공개적으로 접근 가능하거나 계정에서의 접근을 허용하는 버킷 정책이 있어야 합니다.
trust-policy.json 생성 — IAM 사용자가 역할을 수임(assume)할 수 있도록 합니다.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::<YOUR_ACCOUNT_ID>:root"
},
"Action": "sts:AssumeRole"
}
]
}
<YOUR_ACCOUNT_ID>를 12자리 AWS 계정 ID로 바꾸세요.:root대신 특정 IAM 사용자 또는 역할 ARN으로 보안 주체를 좁힐 수 있습니다.
s3-policy.json 생성 — 역할에 광범위한 S3 읽기 액세스가 필요합니다(bucky의 인라인 세션 정책에 있는 s3:ResourceAccount 조건이 계정 수준 필터링을 처리합니다).
{
"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
# 출력: arn:aws:iam::123456789012:role/bucky-role
IAM 사용자에게 sts:AssumeRole 권한이 아직 없으면 추가합니다.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::<YOUR_ACCOUNT_ID>:role/bucky-role"
}
]
}
bucky의 기본 사용 방법 — 알려진 버킷에서 계정 ID를 열거한 다음 한 번에 더 많은 버킷을 퍼징합니다.
bucky \
--role-arn arn:aws:iam::123456789012:role/bucky-role \
--bucket target-bucket \
--wordlist wordlists/default.txt \
--access-key AKIA... \
--secret-key wJal...
알려진 객체 키와 함께 사용 (신뢰성 향상):
bucky \
--role-arn arn:aws:iam::123456789012:role/bucky-role \
--bucket s3://target-bucket/index.html \
--wordlist wordlists/default.txt \
--workers 20
여러 버킷 (쉼표로 구분):
bucky \
--role-arn arn:aws:iam::123456789012:role/bucky-role \
--bucket bucket1,bucket2,bucket3 \
--wordlist wordlists/default.txt
파일에서 여러 버킷:
bucky \
--role-arn arn:aws:iam::123456789012:role/bucky-role \
--bucket-file targets.txt \
--wordlist wordlists/default.txt
JSON으로 결과 저장:
bucky --bucket target-bucket --wordlist wordlists/default.txt --json
bucky --bucket target-bucket --wordlist wordlists/default.txt --json --output results.json
출력:
=== Phase 1: Account ID Enumeration ===
[*] Verifying access to bucket: target-bucket
[+] Access confirmed
[+] Bucket region: us-west-2
[*] Enumerating account ID...
[██████████████████████████████] 12/12 | 675351422352
[+] Account ID: 675351422352
=== Phase 2: Bucket Discovery ===
[*] Fuzzing buckets for account: 675351422352
[*] Loaded 312 candidates from wordlist
[+] FOUND: target-backups
[+] FOUND: target-logs
[██████████████████████████████] 312/312 | 2 found
=== Summary ===
Account ID : 675351422352
Source : target-bucket
Region : us-west-2
Discovered : 2 additional bucket(s)
- target-backups
- target-logs
계정 ID만 필요한 경우:
bucky enum \
--role-arn arn:aws:iam::123456789012:role/bucky-role \
--bucket target-bucket
여러 버킷과 JSON 출력도 서브커맨드에서 사용 가능:
bucky enum --bucket bucket1,bucket2 --json
bucky enum --bucket-file targets.txt --json --output results.json
이미 계정 ID를 알고 있고 버킷을 검색하려는 경우:
bucky fuzz \
--role-arn arn:aws:iam::123456789012:role/bucky-role \
--account-id 675351422352 \
--wordlist wordlists/default.txt \
--workers 20
모든 플래그는 환경 변수로 설정할 수 있습니다. 둘 다 설정된 경우 플래그가 우선합니다.
export AWS_ACCESS_KEY_ID=AKIA...
export AWS_SECRET_ACCESS_KEY=wJal...
export BUCKY_ROLE_ARN=arn:aws:iam::123456789012:role/bucky-role
# 이제 대상만 지정하면 됩니다
bucky --bucket target-bucket --wordlist wordlists/default.txt
Bucky는 wordlists/default.txt에 약 300개의 일반적인 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, , )대상 맞춤형 작업을 위해 조직 이름을 접두사로 추가하여 사용자 정의 단어 목록을 생성하세요.
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
ffuf 또는 gobuster와 같은 도구와 호환되는 모든 단어 목록이 작동합니다. 형식: 한 줄에 하나의 버킷 이름, # 주석, 빈 줄은 무시됩니다.
| 명령어 | 설명 |
|---|---|
bucky | 전체 워크플로우 — 계정 ID 열거 후 추가 버킷 퍼징 |
bucky enum | 알려진 버킷에서 12자리 계정 ID 열거 |
bucky fuzz | 알려진 계정 ID로 버킷 이름 퍼징 |
전역 플래그 (모든 명령어):
bucky (전체 워크플로우):
| 플래그 | 설명 |
|---|---|
--bucket | 대상 S3 버킷(들), 쉼표로 구분 |
bucky enum:
| 플래그 | 설명 |
|---|---|
--bucket | 대상 S3 버킷(들), 쉼표로 구분 |
--bucket-file | 버킷 이름/URL이 한 줄에 하나씩 있는 파일 |
bucky fuzz:
| 플래그 | 설명 |
|---|---|
--account-id | 대상 12자리 AWS 계정 ID |
--bucket 플래그와 --bucket-file은 여러 입력 형식을 허용합니다. Bucky가 버킷 이름(및 선택적 키)을 자동으로 추출합니다.
| 형식 | 예시 |
|---|---|
| 일반 이름 | my-bucket |
| S3 URI | s3://my-bucket/path/to/key |
| 가상 호스팅 URL |
여러 버킷은 --bucket을 통해 쉼표로 구분하여 전달할 수 있습니다.
--bucket bucket1,s3://bucket2/key,https://bucket3.s3.amazonaws.com/
또는 --bucket-file을 사용하여 파일에 한 줄에 하나씩 나열합니다.
my-bucket
s3://another-bucket/index.html
https://third.s3.us-east-1.amazonaws.com/
여러 버킷이 동일한 계정 ID로 확인되면 bucky는 중복을 제거하고 고유한 계정당 한 번만 퍼징을 실행합니다.
--json을 사용하여 결과를 JSON 파일로 저장합니다. 기본 파일명은 현재 디렉터리의 bucky-{uuid}.json이며, --output으로 경로를 지정할 수 있습니다.
bucky --bucket target-bucket --wordlist wordlists/default.txt --json
bucky --bucket target-bucket --wordlist wordlists/default.txt --json --output results.json
출력 형식:
{
"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는 대상 버킷의 리전을 자동으로 감지합니다. S3가 301 리디렉션을 반환하면(버킷이 --region과 다른 리전에 있는 경우) bucky는 x-amz-bucket-region HTTP 응답 헤더를 통해 올바른 리전을 확인하고 이후 모든 요청에 대해 캐시합니다. 대상 버킷에 대한 수동 리전 구성이 필요하지 않습니다.
Genzai에 관한 질문이나 피드백이 있거나 저와 연결하고 싶으시면 LinkedIn 또는 이메일로 연락주세요.
| 변수 | 플래그 | 설명 |
|---|
AWS_ACCESS_KEY_ID | --access-key | AWS 액세스 키 ID |
AWS_SECRET_ACCESS_KEY | --secret-key | AWS 시크릿 액세스 키 |
AWS_SESSION_TOKEN | --session-token | AWS 세션 토큰 (임시 자격 증명용) |
AWS_REGION | --region | AWS 리전 (기본값: us-east-1) |
AWS_DEFAULT_REGION | --region | AWS_REGION이 설정되지 않은 경우 대체 |
AWS_PROFILE | --profile | ~/.aws/credentials의 AWS 명명된 프로필 |
BUCKY_ROLE_ARN | --role-arn | 수임할 IAM 역할의 ARN |
BUCKY_BUCKET | --bucket | 대상 S3 버킷 이름 |
BUCKY_ACCOUNT_ID | --account-id | 대상 AWS 계정 ID (fuzz 전용) |
BUCKY_WORDLIST | --wordlist | 단어 목록 파일 경로 |
BUCKY_WORKERS | --workers | 동시 퍼징 작업자 수 (기본값: 10) |
build-outputdocker-images| 플래그 | 설명 |
|---|
--access-key | AWS 액세스 키 ID |
--secret-key | AWS 시크릿 액세스 키 |
--session-token | AWS 세션 토큰 |
--region | AWS 리전 (기본값: us-east-1) |
--profile | AWS 명명된 프로필 |
--role-arn | 수임할 IAM 역할의 ARN |
--json | 결과를 JSON 파일로 저장 |
--output | JSON 출력 파일 경로 (기본값: bucky-{uuid}.json) |
--bucket-file | 버킷 이름/URL이 한 줄에 하나씩 있는 파일 |
--wordlist | 단어 목록 파일 경로 |
--workers | 동시 작업자 수 (기본값: 10) |
--wordlist | 단어 목록 파일 경로 |
--workers | 동시 작업자 수 (기본값: 10) |
--regions | 이름 변형(mutation)을 위한 쉼표로 구분된 리전 |
https://my-bucket.s3.us-west-2.amazonaws.com/key| 경로 스타일 URL | https://s3.us-west-2.amazonaws.com/my-bucket/key |