# AWS - S3 Unauthenticated Enum

{{#include ../../../../banners/hacktricks-training.md}}

## S3 Public Buckets

A bucket is considered **“public”** if **any user can list the contents** of the bucket, and **“private”** if the bucket's contents can **only be listed or written by certain users**.

Companies might have **buckets permissions miss-configured** giving access either to everything or to everyone authenticated in AWS in any account (so to anyone). Note, that even with such misconfigurations some actions might not be able to be performed as buckets might have their own access control lists (ACLs).

**Learn about AWS-S3 misconfiguration here:** [**http://flaws.cloud**](http://flaws.cloud/) **and** [**http://flaws2.cloud/**](http://flaws2.cloud)

### Finding AWS Buckets

Different methods to find when a webpage is using AWS to storage some resources:

#### Enumeration & OSINT:

- Using **wappalyzer** browser plugin
- Using burp (**spidering** the web) or by manually navigating through the page all **resources** **loaded** will be save in the History.
- **Check for resources** in domains like:

```
http://s3.amazonaws.com/[bucket_name]/
http://[bucket_name].s3.amazonaws.com/
```

- Check for **CNAMES** as `resources.domain.com` might have the CNAME `bucket.s3.amazonaws.com`
- **[s3dns](https://github.com/olizimmermann/s3dns)** – DNS トラフィックを解析してクラウドストレージ buckets (S3, GCP, Azure) を受動的に識別する軽量な DNS サーバーです。CNAME を検出し、解決チェーンを辿り、bucket パターンと照合します。ブルートフォースや API ベースの検出の静かな代替手段を提供し、recon と OSINT ワークフローに最適です。
- Check [https://buckets.grayhatwarfare.com](https://buckets.grayhatwarfare.com/), a web with already **discovered open buckets**.
- The **bucket name** and the **bucket domain name** needs to be **the same.**
- **flaws.cloud** is in **IP** 52.92.181.107 and if you go there it redirects you to [https://aws.amazon.com/s3/](https://aws.amazon.com/s3/). Also, `dig -x 52.92.181.107` gives `s3-website-us-west-2.amazonaws.com`.
- To check it's a bucket you can also **visit** [https://flaws.cloud.s3.amazonaws.com/](https://flaws.cloud.s3.amazonaws.com/).

#### Brute-Force

You can find buckets by **brute-forcing name**s related to the company you are pentesting:

- [https://github.com/sa7mon/S3Scanner](https://github.com/sa7mon/S3Scanner)
- [https://github.com/clario-tech/s3-inspector](https://github.com/clario-tech/s3-inspector)
- [https://github.com/jordanpotti/AWSBucketDump](https://github.com/jordanpotti/AWSBucketDump) (Contains a list with potential bucket names)
- [https://github.com/fellchase/flumberboozle/tree/master/flumberbuckets](https://github.com/fellchase/flumberboozle/tree/master/flumberbuckets)
- [https://github.com/smaranchand/bucky](https://github.com/smaranchand/bucky)
- [https://github.com/tomdev/teh_s3_bucketeers](https://github.com/tomdev/teh_s3_bucketeers)
- [https://github.com/RhinoSecurityLabs/Security-Research/tree/master/tools/aws-pentest-tools/s3](https://github.com/RhinoSecurityLabs/Security-Research/tree/master/tools/aws-pentest-tools/s3)
- [https://github.com/Eilonh/s3crets_scanner](https://github.com/Eilonh/s3crets_scanner)
- [https://github.com/belane/CloudHunter](https://github.com/belane/CloudHunter)

<pre class="language-bash"><code class="lang-bash"># Generate a wordlist to create permutations
curl -s https://raw.githubusercontent.com/cujanovic/goaltdns/master/words.txt > /tmp/words-s3.txt.temp
curl -s https://raw.githubusercontent.com/jordanpotti/AWSBucketDump/master/BucketNames.txt >>/tmp/words-s3.txt.temp
cat /tmp/words-s3.txt.temp | sort -u > /tmp/words-s3.txt

# Generate a wordlist based on the domains and subdomains to test
## Write those domains and subdomains in subdomains.txt
cat subdomains.txt > /tmp/words-hosts-s3.txt
cat subdomains.txt | tr "." "-" >> /tmp/words-hosts-s3.txt
cat subdomains.txt | tr "." "\n" | sort -u >> /tmp/words-hosts-s3.txt

# Create permutations based in a list with the domains and subdomains to attack
goaltdns -l /tmp/words-hosts-s3.txt -w /tmp/words-s3.txt -o /tmp/final-words-s3.txt.temp
## The previous tool is specialized increating permutations for subdomains, lets filter that list
<strong>### 末尾が「.」で終わる行を削除</strong>cat /tmp/final-words-s3.txt.temp | grep -Ev "\.$" > /tmp/final-words-s3.txt.temp2
### Create list without TLD
cat /tmp/final-words-s3.txt.temp2 | sed -E 's/\.[a-zA-Z0-9]+$//' > /tmp/final-words-s3.txt.temp3
### Create list without dots
cat /tmp/final-words-s3.txt.temp3 | tr -d "." > /tmp/final-words-s3.txt.temp4http://phantom.s3.amazonaws.com/
### Create list without hyphens
cat /tmp/final-words-s3.txt.temp3 | tr "." "-" > /tmp/final-words-s3.txt.temp5

## Generate the final wordlist
cat /tmp/final-words-s3.txt.temp2 /tmp/final-words-s3.txt.temp3 /tmp/final-words-s3.txt.temp4 /tmp/final-words-s3.txt.temp5 | grep -v -- "-\." | awk '{print tolower($0)}' | sort -u > /tmp/final-words-s3.txt

## Call s3scanner
s3scanner --threads 100 scan --buckets-file /tmp/final-words-s3.txt  | grep bucket_exists
</code></pre>

#### Loot S3 Buckets

Given S3 open buckets, [**BucketLoot**](https://github.com/redhuntlabs/BucketLoot) can automatically **search for interesting information**.

### Find the Region

You can find all the supported regions by AWS in [**https://docs.aws.amazon.com/general/latest/gr/s3.html**](https://docs.aws.amazon.com/general/latest/gr/s3.html)

#### By DNS

You can get the region of a bucket with a **`dig`** and **`nslookup`** by doing a **DNS request of the discovered IP**:
```bash
dig flaws.cloud
;; ANSWER SECTION:
flaws.cloud.    5    IN    A    52.218.192.11

nslookup 52.218.192.11
Non-authoritative answer:
11.192.218.52.in-addr.arpa name = s3-website-us-west-2.amazonaws.com.
```
解決されたドメインに "website" という語が含まれていることを確認します。\
静的ウェブサイトには次のURLにアクセスして確認できます: `flaws.cloud.s3-website-us-west-2.amazonaws.com`\
またはバケットにアクセスするには次を訪問します: `flaws.cloud.s3-us-west-2.amazonaws.com`



#### 試して確認する

バケットにアクセスしようとしたとき、**ドメイン名に別のリージョンを指定した場合**（例えばバケットが `bucket.s3.amazonaws.com` にあるのに `bucket.s3-website-us-west-2.amazonaws.com` にアクセスしようとした場合）、**正しい場所が示されます**:

![](<../../../images/image (106).png>)

### バケットの列挙

バケットの公開状態を確認するには、ユーザーがブラウザのURL欄にそのURLを入力するだけです。プライベートなバケットは "Access Denied" と応答します。パブリックなバケットは保存されている最初の1,000個のオブジェクトを一覧表示します。

全員に公開:

![](<../../../images/image (201).png>)

プライベート:

![](<../../../images/image (83).png>)

これをcliで確認することもできます:
```bash
#Use --no-sign-request for check Everyones permissions
#Use --profile <PROFILE_NAME> to indicate the AWS profile(keys) that youwant to use: Check for "Any Authenticated AWS User" permissions
#--recursive if you want list recursivelyls
#Opcionally you can select the region if you now it
aws s3 ls s3://flaws.cloud/ [--no-sign-request] [--profile <PROFILE_NAME>] [ --recursive] [--region us-west-2]
```
バケットにドメイン名がない場合、列挙を試みるときは、**バケット名だけを入力**し、AWSs3ドメイン全体は入力しないでください。例: `s3://<BUCKETNAME>`

### 公開URLテンプレート
```
https://{user_provided}.s3.amazonaws.com
```
### 公開 Bucket からアカウントIDを取得

新しい **`S3:ResourceAccount`** **Policy Condition Key** を利用することで、AWS アカウントを特定することが可能です。この条件は **restricts access based on the S3 bucket** an account is in (他のアカウントベースのポリシーは、要求元プリンシパルが所属するアカウントに基づいて制限します)。\
また、ポリシーに **wildcards** を含めることができるため、アカウント番号を **just one number at a time** で見つけることが可能です。

このツールはそのプロセスを自動化します:
```bash
# Installation
pipx install s3-account-search
pip install s3-account-search
# With a bucket
s3-account-search arn:aws:iam::123456789012:role/s3_read s3://my-bucket
# With an object
s3-account-search arn:aws:iam::123456789012:role/s3_read s3://my-bucket/path/to/object.ext
```
この手法は、API Gateway URLs、Lambda URLs、Data Exchange data sets、そして tags の値（tag key を知っていれば）を取得することにも使えます。詳細は [**original research**](https://blog.plerion.com/conditional-love-for-aws-metadata-enumeration/) および、この悪用を自動化するツール [**conditional-love**](https://github.com/plerionhq/conditional-love/) を参照してください。

### バケットが AWS アカウントに属していることを確認する

説明したように [**this blog post**](https://blog.plerion.com/things-you-wish-you-didnt-need-to-know-about-s3/)**、もしバケットを一覧表示する権限がある場合**、バケットが属する accountID を次のようなリクエストを送信して確認できます：
```bash
curl -X GET "[bucketname].amazonaws.com/" \
-H "x-amz-expected-bucket-owner: [correct-account-id]"

<?xml version="1.0" encoding="UTF-8"?>
<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">...</ListBucketResult>
```
If the error is an “Access Denied” it means that the account ID was wrong.

### rootアカウントの列挙に使用されたメール

As explained in [**this blog post**](https://blog.plerion.com/things-you-wish-you-didnt-need-to-know-about-s3/), it's possible to check if an email address is related to any AWS account by **メールに権限を付与しようとする** over a S3 bucket via ACLs. If this doesn't trigger an error, it means that the email is a root user of some AWS account:
```python
s3_client.put_bucket_acl(
Bucket=bucket_name,
AccessControlPolicy={
'Grants': [
{
'Grantee': {
'EmailAddress': 'some@emailtotest.com',
'Type': 'AmazonCustomerByEmail',
},
'Permission': 'READ'
},
],
'Owner': {
'DisplayName': 'Whatever',
'ID': 'c3d78ab5093a9ab8a5184de715d409c2ab5a0e2da66f08c2f6cc5c0bdeadbeef'
}
}
)
```
## 参考資料

- [https://www.youtube.com/watch?v=8ZXRw4Ry3mQ](https://www.youtube.com/watch?v=8ZXRw4Ry3mQ)
- [https://cloudar.be/awsblog/finding-the-account-id-of-any-public-s3-bucket/](https://cloudar.be/awsblog/finding-the-account-id-of-any-public-s3-bucket/)

{{#include ../../../../banners/hacktricks-training.md}}
