flaws2.cloudのWriteupを書いたよ!
皆さん今日は! 今年の夏は日本にいるので、TLに流れてくるラスベガスで楽しんでいるセキュリティクラスタの友人達のつぶやきをうらやましげに眺めているとある診断員です。 色々忙しくて、めちゃくちゃ久々のブログ更新になってしまいました…。
もう随分前になっちゃいますが、今年3月に開催したJAWS DAYS 2019にて、仲の良いPentesterの有志にて、AWSの認証情報に対する攻撃手法や防御策などに関するセッション行いました。 近年日本でもAWSを利用している環境は非常に多く、個人的にも診断対象としてAWSを相手にする機会が多かったため、ちょっと前から有志と一緒にAWSのセキュリティや攻撃手法などについて調査をしていました。 調査して色々学んだことをまとめて発表したのがこちらのスライドになりますので、宜しければ是非ご覧ください。
さて、AWSセキュリティについて調査をする中で個人的にも非常に勉強になったのが、Scott Piper氏(@0xdabbad00)が提供しているflaws.cloudというサイトです。
このサイトでは、CTFのようなセキュリティゲームとなっていて、AWS固有の発生しがちなセキュリティ問題に関して学べるサイトとなっています。 また、ヒントや解説などもちゃんとのっているので、基本的にはそれを読んでいけば必ず問題が解けるようになっています。 実際に手を動かして、一体何が問題であるのかを学習することができるため、非常に勉強になりました。 何より楽しく勉強できる所が良いですね!
また、ほんとについ最近の話題ですが、Capital Oneにおいて、AWS環境においてSSRFの脆弱性を利用されて不正アクセスされてしまうという事案がありました。
SSRF攻撃によるCapital Oneの個人情報流出についてまとめてみた - piyolog
SSRFを利用してクラウドサービスのクレデンシャル情報を取得されてしまう手法については、以前よりバグバウンティ界隈などでは非常に有名な話であり、↑のスライドにも記載しています。 flaws.cloudではこちらの事案と全く同じようなシナリオを体験して学習することができます。
そして、以前からこのサイトを皆でワイワイやったら楽しそうだなと思っていたので、細かい部分などを解説する資料を作って、先日OWASP Sendai ミーティングにお邪魔させていただきハンズオン形式で進めていくイベントを開催してみました!
第36回OWASP Sendai ミーティング - connpass
こちらの資料は修正してその内改めて公開する予定です(仙台では思ったよりも好評だったので、ニーズがあればもしかしたら東京でも開催するかもしれませんw)。 なお、flaws.cloudについては多数のwriteupが公開されており、日本語の記事ですと@kou_ei_さんが書かれている以下のQiitaの記事が非常に参考になります。
AWSセキュリティ学習サイトflaws.cloudのwriteup 前編 - Qiita
AWSセキュリティ学習サイトflaws.cloudのwriteup 中編 - Qiita
AWSセキュリティ学習サイトflaws.cloudのwriteup 後編 - Qiita
まだ、やったことがない方は是非チャレンジしてみてください!
続編があります。
さて、ここからがある意味今回の記事の本題なのですが、flaws.cloudには実は続編となるflaws2.cloudがあります。
flaws2.cloudは前作と同様にAWS固有のセキュリティ問題をゲーム形式で学べるサイトです。前作との最大の違いは、Attacker SideとDefender Sideの二つの経路があり、Defender SideはAWSにおけるインシデントレスポンスの作業を体験できるようなものになっています。(チュートリアルに従ってコマンドを打っていくようなスタイルです)。ちなみに前作のflaws.cloudにて学んだ技術を色々使ったりするので、まずそちらをやってからチャレンジすることをお勧めします。また、flaws.cloudは既に攻略していて、未トライの方は是非チャレンジしてみたらいかがでしょうか?
私はこちらのサイトでも勉強してみたのですが、flaws2.cloudについては日本語の解説記事が見つかりませんでした(見落としているかもしれないのでもしあれば教えてください!)。 もしかしたら多少ニーズがあるのかなと思いましたので折角なので今回は、flaws2.cloudのAttacker SideについてのWriteUPを書こうと思います。ちなみに問題数は前作は6問でしたが、flaws2は全3問です。また、AWSだけではなくdockerなどについても勉強できる内容となっています。
Level1
問題文を読むと以下のようなことが書いてあります。
- 正しいPINコードを入力する必要があります。
- 正しいPINコードは100桁だから、ブルートフォースとかは意味ないよ!
とりあえず、適当な数字を入力すると「Code must be a number」とポップアップが上がります。 数字以外はダメみたいですね。HTMLのソースコードを見てみると以下のようなJavaScriptが書かれています。
<script type="text/javascript"> function validateForm() { var code = document.forms["myForm"]["code"].value; if (!(!isNaN(parseFloat(code)) && isFinite(code))) { alert("Code must be a number"); return false; } } </script>
お分かりのようにJSでフォームに入力された値が数字かどうかをチェックするバリデーションがされています。ということで、数字以外の文字列を入力したい場合には直接HTTPリクエストをブン投げれば良さそうですね。
サブミットしているURLは以下なので
https://2rfismmoo8.execute-api.us-east-1.amazonaws.com/default/level1?code=1234
試しに数字以外の適当に値を書き換えてアクセスしてみます。
https://2rfismmoo8.execute-api.us-east-1.amazonaws.com/default/level1?code=abcd
そうすると以下のようにエラー内容が出力されたレスポンスが返ってきます。
内容を見ると環境変数の情報が出力されており、なんとクレデンシャル情報が出力されていることが分かります。 実際のサイトでこんなのがあったら大変危険ですね…。
ここからは前作のflaws.cloudで出題されていた問題とほぼ同じ流れで解けます。 問題が出題されているドメイン「level1.flaws2.cloud」について調査すると
S3を利用していることが分かり、バケット名は「level1.flaws2.cloud」であることも分かります。 URL経由ではS3にアクセスすることはできないようになっているので、取得したクレデンシャル情報を利用してAWS CLIでS3バケットにアクセスします。
中身を見てみると、この問題のflagと思われるページのhtml名が分かるので、そこにアクセスすればクリアです!
この問題は以下の内容を学ぶ目的のものだったようです。
- EC2インスタンスは、169.254.169.254のメタデータサービスからIAMロールの認証情報を取得するが、AWS Lambdaは環境変数から認証情報を取得している。
Lambda 関数で使用できる環境変数 - AWS Lambda - デバッグのためにエラー画面に環境変数をダンプしている場合などには、機密情報が環境変数に含まれることがあるため危険。
- IAMロールがその操作に必要ではなかったバケットの内容をリストする権限を持っていたことも問題。
- クライアント側での入力値検証に依存すると簡単にバイパスされてしまうので危険。
私自身はまだ遭遇した経験はないのですが、知り合いのセキュリティエンジニアの方からはアプリケーションエラー画面にて環境変数が出力されており、そこ経由でクレデンシャルを取得できたというお話を聞いたことがあったので、このシナリオは現実にも起きうる問題とだと思っています。
Level2
続いてはLevel2です。
- 問題文に記載されているURLではコンテナが動作している。
- S3バケットと同じように、AWS上の他のリソースについても誰でもアクセスできるようすることはできる。
- ECR(Elastic Container Registry)の名前は「level2」である。
記載されている以下のURLにアクセスするとBasic認証が要求されます。どうにかしてこの認証を突破しなければなりません。
前作を攻略した方はBasic認証でピピンと来たかと思いますが、この問題のアプローチとしては、前作のLevel4に近い感じです。 なんらかの方法でサーバ内部に保管してあるBasic認証のパスワードを取得するといった感じです。前作との最大の違いは、問題文にも書いてありますが、この問題の環境はDockerコンテナで動作しているということです。
ちなみにこの問題では以下の二つのAWSサービスが利用されています。
ECR(Elastic Container Registry)
AWSが提供しているDocker向けのレジストリーサービス。 Dockerのレジストリーサービスと言えばDocker社が提供しているDockerHubですが、そのAWS版です。
Amazon Elastic Container Registry とは - Amazon ECRECS(Elastic Container Service)
AWSが提供しているDocker向けのコンテナオーケストレーションサービスです。 AWS上でDockerコンテナを稼働させる環境と、そのコンテナをスケールするための機能などを提供しています。
Amazon ECS(Docker コンテナを実行および管理)| AWS
問題文からも分かる通り、動作しているコンテナのDockerイメージはECR上にあることが推測されます。ということでまずは、Dockerイメージの情報を収集していきましょう。
以下のAWS CLIでERCのリポジトリに登録されているDockerイメージの一覧を列挙することが可能です。リポジトリ名は問題文に指定されていたものを指定します。
list-images — AWS CLI 1.16.230 Command Reference
先ほど取得したlevel1のクレデンシャル情報を利用して以下を実行するとDockerイメージの情報を取得することができます。
aws ecr list-images --repository-name level2 --profile level1で取得したクレデンシャルのプロファイル名
実行すると、ECR上のリポジトリに登録されているDockerイメージの情報を確認することができました。
公式の解説によると、ここからのアプローチは以下の二つのパターンを想定しているようです。
1.Dockerコマンドを利用してこのDockerイメージをダウンロードして解析する
2.AWS CLIを使用してゴリゴリやる
私は、前者の方法でこの問題を解きましたので、今回はそちらを解説したいと思います。 2番の方法が気になる方はヒントのリンクをたどっていって、公式の解説をご覧ください。
ECRから、docker pullコマンドを利用してdockerイメージをダウンロードする方法については以下に記載されています。
プルする場合には上記にも書いてある通り引数としてregistry/repository[:tag]を指定する必要があります。 今までの情報からrepository[:tag]はlevel2:latestと判明しているので、後はregistryを正しく指定する必要があります。
ECRレジストリのURLの構成要素は以下のようになっています。
https://AWSアカウントID.dkr.ecr.リージョン名.amazonaws.com
【参考】Amazon ECR レジストリ - Amazon ECR
リージョンはLevel1のレスポンスの結果よりus-east-1であることが推測されます。 ということで後はAWSアカウントIDを調べるだけでよさそうです。そちらは前作でも利用しましたが、以下のコマンドでアカウントに紐づく情報を取得することができます。
aws sts get-caller-identity
以下は、level1で取得したクレデンシャル情報を指定して実行した結果です。
AWSアカウントIDが653711331788であることが判明しました。ここまで取得した情報にてregistry/repository[:tag]の値は以下だと分かります。
653711331788.dkr.ecr.us-east-1.amazonaws.com/level2:latest
以下コマンドを実行してローカル環境にDockerイメージをダウンロードします。
aws ecr get-login --profile level1のプロファイル名 docker pull 653711331788.dkr.ecr.us-east-1.amazonaws.com/level2:latest
aws ecr get-loginを実行すると、レスポンスにdocker loginコマンドが表示されます。表示されたコマンドを実行して、Amazon ECR レジストリに対して Dockerクライアントを認証し、その後docker pullでイメージをダウンロードします。
ここからはダウンロードしてきたDockerイメージを解析します。
dokcer historyコマンドを実施してイメージを変更履歴を見てみると、何やら興味深いコマンドが見えますねw
docker history 653711331788.dkr.ecr.us-east-1.amazonaws.com/level2:latest
--no-trunオプションを指定すると隠れている部分も全部見えます。その結果、dockerfile内で以下のコマンドを実行しているのが分かるのでBasic認証のID・パスワードが判明します。
/bin/sh -c htpasswd -b -c /etc/nginx/.htpasswd flaws2 secret_password
上記のID・パスワード利用してBasic認証後のページにアクセスすればクリアとなります!
こちらの問題は以下の内容を学ぶ目的のものだったようです。
- AWSのリソースを不特定多数に公開することの危険性
※ちなみに、ヒントや解説にECRのリポジトリはパブリックに公開しているような記載があるのですが、私が試した時には、情報の取得やイメージのpullにはlevel1のクレデンシャルが必要でした。level1のクレデンシャルを利用すれば上述したように普通に問題は解けます。 - AWS ECRの仕様やdockerについて
私は以前、AWS上でCTFを作成した時にECRを使ったことはあったのですが、仕様などについてはあまり意識していなかったので非常に勉強になりました。
Level3
はい!そしていよいよ最後の問題です。
- 前回の問題で利用したコンテナのWebサーバーでは、シンプルなプロキシが利用できます。
問題文に書かれているようにURLパスに指定したURLにアクセスして、結果を表示するProxyとして動作しています。
前作でも全く同じような設問がありましたし、この時点でピピンとくる方も多いと思います。 というわけでこの問題ではSSRFを利用します。
SSRFについては、徳丸さんのブログが非常に分かりやすく解説されているのでお勧めです! SSRF(Server Side Request Forgery)徹底入門 | 徳丸浩の日記
前作にもほぼ同じ問題が出題されていましたが、SSRFの脆弱性を利用してクレデンシャル情報を取得します。 一つポイントなのは、今回の環境はEC2ではないので、例えば以下のようなEC2で通るPayloadではクレデンシャル情報を取得できません。
http://169.254.169.254/latest/meta-data/iam/security-credentials/ロール名
Proxyが動作しているコンテナはECSで動作をしています。ECSより一時的なIAMロールのクレデンシャルを要求する場合には以下内部APIへのアクセスとなります。
http://169.254.170.2/v2/credentials/GUID
※GUIDの値はサーバ内における以下の環境変数に設定されています。
AWS_CONTAINER_CREDENTIALS_RELATIVE_URI
【参考】タスク用の IAM ロール - Amazon Elastic Container Service
では、環境変数の値を知るにはどうしたらよいでしょう? Linuxシステムであれば以下を参照することで環境変数を取得することができます。
/proc/self/environ
というわけで、ここでもSSRFを利用してこの値を取得しに行きます。 fileスキーマを利用すれば、内部ファイルにアクセスすることができますのでこちらを利用します。
http://container.target.flaws2.cloud/proxy/file:///proc/self/environ
環境変数の値が分かったので、GUIDの値が判明しました。これを組み合わせて、SSRFを利用して、内部APIに対してクレデンシャルを要求します。
http://container.target.flaws2.cloud/proxy/http://169.254.170.2/v2/credentials/468f6417-4361-4690-894e-3d03a0394609
このような感じで、見事にクレデンシャル情報を取得することができます。
クレデンシャルを取得した後にどうするかというと、そこは前作と同様です。AWS CLIを利用して取得したクレデンシャル情報を利用してS3バケットの一覧を取得すると、ゴールのURLが分かります。
こちらの問題は以下の内容を学ぶ目的のものだったようです。
- EC2以外にもSSRFを利用してクレデンシャル方法を取得することができる
なお、ECSにおけるSSRFについてはこちらの記事が参考になりました。
Privilege escalation in the Cloud: From SSRF to Global Account Administrator
また、SSRFのテクニックなどについては以下にまとまっています。
PayloadsAllTheThings/Server Side Request Forgery at master · swisskyrepo/PayloadsAllTheThings · GitHub
最後に
いかがでしたでしょうか?もしこのブログが、flaws2.cloudのサイトにて学習する方の何かのお役に立てば幸いです。 最後に、このような素晴らしいサイトを公開されているScott Piper氏にあらためて感謝したいと思います。 私は非常に楽しく学ばせていただきました!ありがとうございます。