先日、8/27(日)にAWS Japanの目黒セントラルスクエアオフィスにてSecurity-JAWS【第30回】[Security-JAWS DAYS] ~Day2~が開催されました。
この日はCTF(Capture The Flag)と呼ばれる情報セキュリティに関する知識や技術を駆使して隠されているFlag(答え)を見つけ出すゲームをやり進めるというイベントでした。
運営の方がAWS上に作成した環境の脆弱性を突いて情報を抜き取るシミュレーションをすることで、攻撃者がどのようにしてAWSから情報を抜き取っていくのかを体験することができます。

本記事ではこのCTFの中で私が解けそうで解けなかった問題、誤ったバケットポリシーが設定されているS3から情報を抜き取る方法について深掘りしてみたいと思います。

誤ったバケットポリシーが設定されているS3から情報を抜き取る方法を再現

S3から情報を抜き取るのに必要な情報は「バケット名」と「リージョン」の2つです。
アカウントIDやオブジェクト名、プレフィック、パスは必要ありません。
なお、S3で静的Webホスティングをする際はバケット名とドメイン名が一致しているため、ドメイン名からバケット名を割り出すことが可能です。

試しに以下のようなS3のバケットを作成してみます。

バケット名:suzuki-test-public
リージョン:ap-northeast-1(東京リージョン)

ブロックパブリックアクセスを無効化し、静的Webホスティング等でS3をパブリックに公開する際に設定しそうな以下のバケットポリシーをS3へ設定しパブリックアクセスを許可します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "test",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "*",
            "Resource": [
                "arn:aws:s3:::suzuki-test-public/*",
                "arn:aws:s3:::suzuki-test-public"
            ]
        }
    ]
}

このとき、以下の形式に則ったURLを叩くとS3に保存されているオブジェクトの情報が出力されます。

http://s3-リージョン名.amazonaws.com/バケット名

試しに作成したS3に当てはめると以下のようになります。

http://s3-ap-northeast-1.amazonaws.com/suzuki-test-public/

このURLを叩くと、S3に格納されているオブジェクト名(ファイル名)を特定し、ファイルを抜き出すことが可能となります。

先ほどのURLの末尾にtest1.jpgをつけてみると…

中身が表示できてしまいました。
(CTFで使われていた私のお気に入りの画像を利用しただけで、残念なわけではありません。むしろ大当たりです。)

何がダメでS3の情報が抜き取られてしまったのか

静的Webホスティングを有効化する際に以下のようなバケットポリシーを設定してしまうと今回再現したような方法で情報が抜き取られてしまいます。(静的Webホスティングを有効化していなくても、ブロックパブリックアクセスを無効化し、同様のバケットポリシーを設定すると情報を抜き取ることが可能です。)

  • 「s3:GetObject」だけではなく、「s3:ListBucket」のアクションが許可されている
  • S3バケットの中身(arn:aws:s3:::バケット名/*)だけでなく、S3バケット自体(arn:aws:s3:::バケット名)に対してのアクションが許可されている

つまり、「s3:ListBucket」のアクションやS3バケット自体(arn:aws:s3:::バケット名)に対するアクションは静的Webホスティング上、不要な権限ということになります。

また、「サイトがS3でホストされていることがバレなければ問題ないのでは?」という考えもあるかもしれませんが、nslookupを用いることで簡単に特定できてしまうことがCTFの解説で紹介されていました。

※詳しくは以下の作問者解説のスライドの32ページ以降の内容を参照いただければと
Security-JAWS Days CTF 作問者解説

正しいバケットポリシーを設定する

誤ったバケットポリシーを設定してしまったが故に、保存されている情報を簡単に抜き取れるようなS3ができてしまいました。
では安全にS3の静的Webホスティング機能を利用するにはどのようなバケットポリシーを設定すればいいのでしょうか。
以下のようなバケットポリシーを設定することでパブリックに公開されているS3から保存されているオブジェクトの情報を抜き取れなくすることが可能です。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": [
                "s3:GetObject"
            ],
            "Resource": [
                "arn:aws:s3:::suzuki-test-public/*"
            ]
        }
    ]
}

参照:ウェブサイトアクセスのアクセス許可の設定

バケットポリシーを使用してアクセス許可をウェブサイトに与えることで、Amazon S3 バケットをウェブサイトとして設定します。

まとめ

基本的な話ではありますが、本記事の中で私が一番伝えたいことは以下の2点です。

① S3に不要なファイルを置かない
② バケットポリシーは最小権限を意識する

手軽にAWSで静的なサイトをホスティングできることから、S3の静的Webホスティング機能はとても便利です。
ただし、手軽に使えてしまう分セキュリティへの意識が薄くなってしまうこともあるかと思います。

以前、1つのバケットに静的Webホスティングとログの機能を持たせようとする設計をされているお客様を見かけたことがあります。その経験からS3から情報漏洩が発生するリスクや、それを防ぐ方法について知らない人もいるのだと気付かされました。
私たちは日常的にAWSを触っていて情報が入っているため、当たり前のように知っていますが、普段からAWSには関わっていない人にとっては当たり前ではありません。
「S3に不要なファイルを置かない」、「バケットポリシーは最小権限を意識する」といったようなS3との正しい付き合い方については今後も啓蒙していきたいと思います。

おわりに

私自身、適切な設定をせずにS3をパブリックに公開することは、なんとなく危ないということは理解していたものの、実際にどういった仕組みで情報漏洩が発生するのかということを深掘りできていませんでした。
「S3のバケット名がバレたとしても具体的なファイル名(プレフィックス/パス)がわからなければ、問題ないのでは?」とか思ってました。

今回のCTFを通して、上記認識が誤りであり、「パブリックアクセス可能なS3のバケット名とリージョンがバレると何ができるのか」ということが理解できたので、本イベントには大変感謝しております。