コントロールできていると感じますか?攻撃ツールとしての AWS CloudControl API の分析

AWS CloudControl API を悪用して、リソースを密かに列挙し、アカウント内で永続化し、検出を回避する手法を解説します。

Bleon Proko

Bleon Proko

クラウドセキュリティの議論では、「アイデンティティは新たな境界線である」という表現がよく使われますが、それには十分な理由があります。適切な権限があれば、ほぼすべてのクラウドリソースを API 経由で管理できます。各クラウドプロバイダーは、リソースベースのアクセス制御を通じて API アクセスをそれぞれ異なる方法で扱っています。特定の API 呼び出しに必要な権限をそのアイデンティティが持っていれば、その操作を実行できます。

問題は、特定の情報を取得したり、特定のリソースにアクセスしたりするために必要な API 呼び出しを、すべて正確に覚えておくのが難しいことです。AWS はこの課題を認識し、AWS CloudControl API を提供しました。これは、さまざまなリソースを統一的に扱い、一括で作成、更新、削除、取得できる API です。これにより、どのサービスを使うべきか、どの API 呼び出しを行うべきか、どのパラメータが必要かを個別に把握していなくても、リソース管理を大幅に簡素化できます。

しかし注意すべき点があります。正規ユーザーにとって使いやすいものは、攻撃者にとっても使いやすいことが少なくありません。AWS CloudControl API を使ってリソース情報を取得するツールはすでに存在し、この手法は注目を集めつつあります。

では、CloudControl API は本当にステルス性の高い列挙手法として有効なのでしょうか。本記事では、CloudControl API とは何か、どのようにリソース管理を簡素化するのか、攻撃者がどのように悪用できるのか、その制約、そして検出方法について検証します。さらに Exaforce は、本記事で紹介する攻撃手法と検出手法の両方を自動化するツール「CloudConqueror」を開発しました。

AWS CloudControl API とは

AWS CloudControl API は、AWS アカウント内のサービスやリソースの管理を容易にするために AWS が提供する API です。どのサービスや API 呼び出し、あるいは API 実行時の入力パラメータを知らなくても、作成、読み取り、更新、削除、一覧表示(CRUD-L)操作を実行できます。

AWS CloudControl API の AWS API ドキュメントでは、次のように説明されています。「AWS Cloud Control API を使用すると、AWS およびサードパーティーの幅広いサービスに属するクラウドリソースに対して、作成、読み取り、更新、削除、一覧表示(CRUD-L)を実行できます。Cloud Control API の標準化された API セットを使うことで、AWS アカウント内でサポートされている任意のリソースに対して CRUD-L 操作を実行できます。Cloud Control API を利用すれば、それらのリソースを管理する各サービスごとに個別のコードやスクリプトを作成する必要はありません。」

CloudControl API は、1 つの共通リソースを軸に複数のリソースを関連付けて扱うことで、リソース管理も支援します。内部的には CloudFormation スキーマを利用しています。たとえば IAM ユーザーの取得をリクエストすると、返される情報はそのスキーマに沿った形式になります。

{
  "Type" : "AWS::IAM::User",
  "Properties" : {
      "Groups" : [ String, ... ],
      "LoginProfile" : LoginProfile,
      "ManagedPolicyArns" : [ String, ... ],
      "Path" : String,
      "PermissionsBoundary" : String,
      "Policies" : [ Policy, ... ],
      "Tags" : [ Tag, ... ],
      "UserName" : String
    }
}

AWS CloudControl では 7 種類の API 呼び出しが利用できます。そのうち 5 つは標準的な CRUD-L 操作です。残りの 2 つは、リクエストの一覧表示と、作成・更新・削除操作のステータス確認に使われます。

Operation API Call Required Input Parameters
List resources of a specific type ListResources The resource type to list
Get a specific resource using an identifier GetResource The resource type and its name as the identifier
Create a resource on the account CreateResources The resource type, its name as the identifier, and the resource properties
Modify a resource’s attributes UpdateResource The resource type, its name as the identifier, and the resource properties that will be updated
Delete a resource on the account DeleteResource The resource type and its name as the identifier
List create, delete, and update requests being made on the account ListResourceRequests No input required
Get the status of a specific resource request GetResourceRequestStatus The request token is required as input

AWS は、AWS CloudControl API でサポートされるすべてのリソースタイプと、それぞれのリソースでサポートされる CRUD-L 操作をまとめた一覧を公開しています。現在、237 のサービスにまたがる 1,220 種類のリソースタイプがサポートされています。

AWS CloudControl を攻撃ツールとして使う場合の良い点、悪い点、厄介な点

良い点: AWS CloudControl によるリソースアクセス

AWS CloudControl API は、これまでも攻撃ツールとして使われてきました。主な用途は列挙です。というのも、この API 自体を AWS リソースのインベントリ取得に使えるからです。一方で、AWS CloudControl API によるリソースの変更や更新機能は、それほど一般的には使われていません。

リソースの取得

AWS CloudControl API を使うと、リソース名やその設定情報を簡単に取得できます。通常、従来の AWS API を使う場合、1 つのリソースに関する情報をすべて取得するには複数の API 呼び出しが必要になることがあります。

AWS IAM user data flow showing commands from listing IAM users to retrieving user groups via GetUser and ListUserPolicies.
ユーザーおよび関連データを取得するための一般的な API 呼び出しパス

AWS CloudControl API は CloudFormation スキーマを利用しているため、各リソースには複数の関連情報が、1 つの共通リソースの下にまとめられています。つまり、AWS IAM ユーザーのスキーマには、ユーザー情報(ユーザー名、パス、アクセス許可境界、タグ)に加え、ログインプロファイル、グループ、ポリシー(アタッチされたポリシーとインラインポリシー)が含まれます。

{
  "Type" : "AWS::IAM::User",
  "Properties" : {
      "Groups" : [ String, ... ],
      "LoginProfile" : LoginProfile,
      "ManagedPolicyArns" : [ String, ... ],
      "Path" : String,
      "PermissionsBoundary" : String,
      "Policies" : [ Policy, ... ],
      "Tags" : [ Tag, ... ],
      "UserName" : String
    }
}

リソースの一覧表示または取得には、2 つの API 呼び出しが使えます。cloudcontrol:ListResources は、指定したリソースタイプの各リソースを一覧表示します。

$ aws cloudcontrol list-resources --type-name AWS::IAM::User

cloudcontrol:ListResources が返す出力は、指定したリソースタイプに属するリソース識別子の JSON リストです。

{
    "ResourceDescriptions": [
        {
            "Identifier": "someUser",
            "Properties": "{\\"UserName\\":\\"someUser\\"}"
        }
    ],
    "TypeName": "AWS::IAM::User"
}

これらの識別子は、後で cloudcontrol:GetResource に渡して、そのリソースの情報を取得できます。違いは、cloudcontrol:GetResource では CloudFormation スキーマ形式で整形された情報を取得できる点です。

$ aws cloudcontrol get-resource --type-name AWS::IAM::User --identifier <identifier>

列挙手法として見ると、cloudcontrol:ListResources を使って特定リージョン・特定リソースタイプのすべてのリソースを列挙し、その後 cloudcontrol:GetResource をループ実行して詳細情報を取得する、という使い方が可能になります。

Flowchart describing AWS IAM user enumeration loop using ListResources and username retrieval.
すべてのユーザー情報のダンプを取得するプロセス

ブルートフォースによるリソース名の特定

攻撃者は、権限が制限されているために特定の操作を実行できない状況に置かれることがよくあります。これにより、リソース名や ID など、一部の識別子情報を取得できない場合があります。そのため、攻撃者は別の情報取得に進む前に、代替手段でそうした情報を把握する必要があります。

このような場合、ブルートフォースや推測が有効な代替手段になります。アカウント内に存在しそうなリソース名のリストを持つ攻撃者は、それらを cloudcontrol:GetResource に渡して、リソースが存在するかどうかを確認できます。攻撃者に cloudcontrol:GetResource の実行権限があり、かつ対象リソースが存在する場合は、そのリソースの情報を取得できます。API 呼び出しを実行する権限がない場合は AccessDenied エラーが返されます。実行権限はあるものの、リソースが存在しない場合は ResourceNotFoundException が返されます。これにより、引き受けたロールに必要な権限があるか、対象リソースが存在するかを判別できます。

Attacker execution flow using AWS CloudControl GetResource command to retrieve resource details or trigger exceptions.
権限の確認と、ブルートフォースまたは推測されたデータの検証

リソースを改変してアクセスを獲得する

AWS CloudControl API には、リソースの一覧表示や情報取得に加えて、アカウント内のリソースを作成、更新、削除するための 3 つの API 呼び出しがあります。

  • cloudcontrol:CreateResource
  • cloudcontrol:UpdateResource
  • cloudcontrol:DeleteResource

リソースの作成と更新に必要な入力は、リソースタイプ、リソースタイプに対応する CloudFormation スキーマから取得される入力パラメータです。リソースの削除と更新には、これに加えて識別子も必要です。

AWS CLI output showing creation of IAM role with cloudcontrol create-resource command in progress.
CloudControl を使用してロールを作成する AWS CLI コマンド

CUD(作成、更新、削除)操作のリクエストが CloudControl API に送信されると、そのリクエストは CloudControl API によってログに記録されます。cloudcontrol:ListResourceRequests を使用すると、リクエストとそのステータス(成功または失敗)を一覧表示でき、失敗した場合はエラーコードも確認できます。列挙機能として見ると、これは有用な場合があります。攻撃者は、特定のアイデンティティが持つアクセス権、組織レベルポリシー(SCP)、作成または更新されたリソースの識別子名に関する情報を取得できるためです。

AWS CLI output showing failed IAM user creation due to access denial and successful IAM role creation.
CloudControl を使用してリソースリクエストを一覧表示する AWS CLI コマンド

悪い点:呼び出しを実行するには依然として権限が必要

私たちが検証した疑問の 1 つは、AWS CloudControl API がどのように動作し、どのような権限を必要とするのかという点でした。もしこの API が CloudControl 固有の権限だけで動作するのであれば、未確認のまま放置するには非常に危険な API になり得ます。

IAM ユーザーの取得を試みるリクエストのイベントを確認したところ、複数のイベントが実行されていることが分かりました。cloudcontrol:GetResource が実行されると、バックエンドでは CloudControl がさらに 7 つの API リクエストを実行します。

  • iam:GetUser は 2 回実行されます。おそらく、1 回目のリクエストでユーザー名、パス、タグを取得し、2 回目のリクエストでアクセス許可境界を取得しています。
  • iam:ListUserPolicies は、ユーザーのインラインポリシーを取得するために使用されます。
  • iam:GetUserPolicy は、ポリシーの内容を取得するために使用されます。ユーザーに割り当てられているインラインポリシーの数によっては、複数回実行される場合があります。
  • iam:ListAttachedUserPolicies は、ユーザーにアタッチされている AWS 管理ポリシーおよびカスタム管理ポリシーを取得するために使用されます。
  • iam:GetLoginProfile は、そのユーザーにログインプロファイルが割り当てられているか、つまりマネジメントコンソールへのアクセス権があるかを確認するために使用されます。
  • iam:ListGroupsForUser は、そのユーザーが所属している IAM グループの一覧を取得するために使用されます。

AWS イベントは、必ずしも正しい順序で記録されるとは限りません。非常に短い時間内に複数の API 呼び出しが実行されると、イベント履歴上では異なる順序で表示される場合があります。

つまり、インベントリに必要な情報を提供するイベントは、その情報が存在するかどうかに関係なく実行されます。そのため、ステルス性を維持するうえで問題が生じます。攻撃者が対象に対して API 呼び出しを実行しようとしていることが検出され得るためです。リソースの作成や更新を試みる場合、この問題はさらに大きくなります。検出ツールやセキュリティチームが、侵害の可能性に気付くきっかけになり得るためです。

壊れた連鎖

しかし、ここで疑問が生じました。呼び出しの実行方法に問題があったのです。AWS が CloudControl API の背後で API 呼び出しを実行する際、IAM ユーザーの認証情報にアクセスできるはずはありません。では、どのように呼び出しを実行しているのでしょうか。実行されたリクエストの 1 つを確認すると、いくつかの点が分かります。

  • sourceIPAddressuserAgent の値は cloudformation.amazonaws.com に設定されており、このイベントが AWS CloudControl API によってトリガーされていることを示しています。
  • このリクエストは IAM ユーザーによって開始されていますが(ARN で示されています)、アクセスキーは ASIA で始まっており、AWS の一時認証情報であることを示しています。sessionContext.attributes.creationDateeventTime を比較すると、このセッションはイベントの直前に実行されたように見えます。
{
    "eventVersion": "1.11",
    "userIdentity": {
        "type": "IAMUser",
        "principalId": "AIDA****************",
        "arn": "arn:aws:iam::0123456789012:user/bleonUser",
        "accountId": "0123456789012",
        "accessKeyId": "ASIA4MTWIL**********",
        "userName": "bleonUser",
        "sessionContext": {
            "attributes": {
                "creationDate": "2025-08-15T14:52:54Z",
                "mfaAuthenticated": "false"
            }
        },
        "invokedBy": "cloudformation.amazonaws.com"
    },
    "eventTime": "2025-08-15T14:52:55Z",
    "eventSource": "iam.amazonaws.com",
    "eventName": "ListAttachedUserPolicies",
    "awsRegion": "us-east-1",
    "sourceIPAddress": "cloudformation.amazonaws.com",
    "userAgent": "cloudformation.amazonaws.com",
    "requestParameters": {
        "userName": "bleonUser"
    },
    "responseElements": null,
    "requestID": "00bcc3e5-ed84-4cbb-a8ad-61b252e387bb",
    "eventID": "ced62c58-a981-40b8-9e7c-3666a310e908",
    "readOnly": true,
    "eventType": "AwsApiCall",
    "managementEvent": true,
    "recipientAccountId": "851725277864",
    "eventCategory": "Management"
}

つまり AWS は、そのアイデンティティ用の一時認証情報一式を生成し、その認証情報を使って AWS CloudControl API エンドポイントから残りの呼び出しを実行しているということです。

Flowchart showing AWS CloudControl event process
AWS が CloudControl API 呼び出しを行うための認証情報を作成するプロセス

CloudTrail には、新しい認証情報の生成を示すイベントはありません。実際、AWS CloudControl API に関連するイベントだけを許可するポリシーを作成しても、情報取得の試みは防げず、一時認証情報を生成したイベントも CloudTrail には表示されません。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Statement3",
            "Effect": "Allow",
            "Action": [
                "iam:GetUser",
                "iam:ListUserPolicies",
                "iam:GetUserPolicy",
                "iam:ListAttachedUserPolicies",
                "iam:GetLoginProfile",
                "iam:ListGroupsForUser",
                "cloudformation:GetResource"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}

厄介な点:1 つの権限不足で連鎖全体が破綻する

最後に検証した疑問は、特定の API 呼び出しが失敗した場合にどうなるのか、また、ある API 呼び出しが取得しようとする特定の設定をリソースが持っていない場合、リクエストがどうなるのかという点でした。

リクエスト元のアイデンティティが必要な各 API 呼び出しを実行する適切な権限を持っているものの、リソース側に一部の情報が存在しない場合、そのフィールドは出力に含まれません。たとえば、以下の例では、ユーザーが AWS IAM グループに所属している場合と、グループに所属していない場合の出力の違いを確認できます。

# User is part of bleonTestGroup IAM Group
{
  "Path": "/",
  "UserName": "bleonUser",
  "Groups": [
    "bleonTestGroup"
  ],
  "Arn": "arn:aws:iam::0123456789012:user/bleonUser",
  "LoginProfile": {
    "PasswordResetRequired": false
  },
  "Tags": [
    {
      "Value": "Prod",
      "Key": "Deployment"
    }
  ]
}

# User is not part of bleonTestGroup IAM Group
{
  "Path": "/",
  "UserName": "bleonUser",
  "Arn": "arn:aws:iam::0123456789012:user/bleonUser",
  "LoginProfile": {
    "PasswordResetRequired": false
  },
  "Tags": [
    {
      "Value": "Prod",
      "Key": "Deployment"
    }
  ]
}

これは、リクエスト元ユーザーがすべての権限を持っていない場合とは異なります。AWS IAM Cloud Control では、実行トランザクション全体の中で 1 つの API 呼び出しでも失敗すると、リクエスト全体が失敗します。

AWS CLI terminal output showing an AccessDeniedException error
制限された権限により失敗する AWS CLI CloudControl の get-resource コマンド

つまり、攻撃者がユーザーに関する情報を要求したものの、グループを一覧表示する権限(iam:ListGroupsForUser)を持っていない場合、他の情報は攻撃者に返されず、権限不足を示すエラーコードが返されます。

Flowchart showing an attacker’s use of cloudcontrol:GetResource to retrieve IAM user information
制限された権限で API 呼び出しが失敗するフロー

さらに、イベントは引き続き実行され、ログに記録されます。つまり、攻撃者は情報を取得できず、必要なタスクも実行できませんが、その試行はログに残ります。

AWS CloudTrail event log listing actions performed by user bleonUser
失敗した API 呼び出しを示す CloudTrail ログ

AWS CloudControl API は攻撃ツールとしてどれほど有効か

AWS CloudControl API には、攻撃者のツールとして多くの制約があります。追加の権限が必要であること、イベントがログに記録されること、なりすましたアイデンティティに適切な権限がない時点で連鎖が破綻することなどです。しかし、これらの制約も正しく利用すれば、高権限アカウント内での永続化に利用できます。以下のポリシーは、割り当てられたアイデンティティに対して CloudControl 関連の API 呼び出しのみを直接実行できるようにし、それ以外の操作は CloudControl 経由でのみ実行されるよう制限します。CloudControl API は CloudFormation オペレーションを使用するため、ここでのサービスは CloudControl ではなく CloudFormation になります。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowViaCloudFormation",
            "Effect": "Allow",
            "Action": "*",
            "Resource": "*",
            "Condition": {
                "ForAnyValue:StringEquals": {
                    "aws:CalledVia": "cloudformation.amazonaws.com"
                },
                "Bool": {
                    "aws:ViaAWSService": "true"
                }
            }
        },
        {
            "Sid": "DenyDirectAccess",
            "Effect": "Deny",
            "NotAction": [
                "cloudformation:GetResource",
                "cloudformation:GetResourceRequestStatus",
                "cloudformation:ListResourceRequests",
                "cloudformation:ListResources",
                "cloudformation:UpdateResource",
                "cloudformation:DeleteResource",
                "cloudformation:CreateResource",
                "cloudformation:CancelResourceRequest"
            ],
            "Resource": "*",
            "Condition": {
                "Bool": {
                    "aws:ViaAWSService": "false"
                }
            }
        },
        {
            "Sid": "AllowDirectCloudControlAcccess",
            "Effect": "Allow",
            "Action": [
                "cloudformation:GetResource",
                "cloudformation:GetResourceRequestStatus",
                "cloudformation:ListResourceRequests",
                "cloudformation:ListResources",
                "cloudformation:UpdateResource",
                "cloudformation:DeleteResource",
                "cloudformation:CreateResource",
                "cloudformation:CancelResourceRequest"
            ],
            "Resource": "*"
        }
    ]
}

ポリシーシミュレーションでは、すべてのイベントが「拒否」として表示されるため、この永続化手法はさらにステルス性が高まります。

Screenshot of AWS IAM Policy Simulator for role “CCRole”
ブロックされたイベントを表示するポリシーシミュレーター

CloudControl が許可するもの以外のリクエストを実行しようとすると、ポリシー内の 2 つ目のステートメント(DenyDirectAccess)によって失敗します。

AWS CLI error showing AccessDenied for GetRole on cloudcontrolRole5.
厳格な権限によりブロックされた AWS CLI コマンド

一方で、CloudControl API 経由で API 呼び出し(任意の CRUD-L 操作)を実行しようとすると許可されます。

AWS CLI output showing cloudcontrol create-resource command in progress.
CloudControl API 使用時に正常に完了した AWS CLI コマンド

このポリシーを割り当てられたアイデンティティは、通常の非管理者アイデンティティのように見えながら、実際には Administrator Access を持つことになります。

過剰権限ポリシーの検出

このポリシーには 1 つ問題があります。サービスへの権限自体は引き続き許可されており、それらを AWS CloudControl API 経由でプロキシしているだけです。

IAM ポリシー作成画面を見ると、AWS は CloudControl API 以外のすべてのサービスを明示的拒否(Explicit Deny)として表示します。つまり、そのアイデンティティはそれらの権限を直接実行できないということです。

AWS console showing explicit deny for 447 of 448 services with full access.
CloudControl API 以外のすべてのサービスを表示する明示的拒否の一覧

しかし、許可済みサービスのセクションを見ると、すべてのサービスが実際には許可済みとしてマークされていることが分かります。これにより、この永続化手法は検出可能になります。

AWS console showing allow for all 448 services with full access permissions.
実際に許可されているサービスを示す許可済みサービス

AWS Simulator と実行したテストのどちらでも、このアイデンティティのアクセスは引き続き拒否として表示されます。

AWS console showing allow for all 448 services with full access permissions.
API 呼び出しの明示的拒否を示す AWS CLI
AWS policy simulator showing denied IAM actions for user bleonUser.
サービス権限が拒否として表示されるポリシーシミュレーター

ポリシーに含まれる条件を把握していれば、IAM Policy Simulator を使用して、実際にはアカウントに対する管理者権限を持っていることを証明できます。

AWS policy simulator showing allowed IAM actions when called via AWS service.
適切なポリシーでポリシーシミュレーターを再実行し、管理者権限があることを示す結果

CloudConqueror

この調査は、CloudConqueror というオープンソースツールに結実しました。CloudConqueror は 4 つの機能で構成され、この調査で示したすべての手法をシミュレートできます。

  • cloudcontrol:ListResourcescloudcontrol:GetResource を利用したリソース一覧取得
  • cloudcontrol:GetResource を利用したリソース名のブルートフォース
  • CloudControl 経由のアクセスのみを許可するインラインポリシーを持つ IAM ユーザーまたはロールの作成による永続化
  • アカウント内の CloudControl イベントの一覧表示
Terminal showing CloudConqueror help output with available attack modules.
CloudConqueror ツールのプレビュー

CloudConqueror は Python で構築されており、ローカル環境でも Docker を利用する場合でも、簡単にインストールできます。実際に試すには、リポジトリを参照してください。

ツールのインストール

ローカルインストール

CloudConqueror は Python 3 で構築されており、必要なライブラリを含むファイル(requirements.txt)がツールのメインフォルダ内にあります。ツールをローカルにインストールする場合は、仮想環境(python-venv)を使用する場合でも、ライブラリをシステムに直接インストールする場合でも、requirements.txt 内のライブラリをインストールするだけで済みます。

(venv) ~$ python3 -m pip install -r requirements.txt
Requirement already satisfied: boto3 in ./venv/lib/python3.12/site-packages (from -r requirements.txt (line 1)) (1.40.5)
Requirement already satisfied: termcolor in ./venv/lib/python3.12/site-packages (from -r requirements.txt (line 2)) (3.1.0)
Requirement already satisfied: botocore in ./venv/lib/python3.12/site-packages (from -r requirements.txt (line 3)) (1.40.5)
Requirement already satisfied: tabulate in ./venv/lib/python3.12/site-packages (from -r requirements.txt (line 4)) (0.9.0)
Requirement already satisfied: prettytable in ./venv/lib/python3.12/site-packages (from -r requirements.txt (line 5)) (3.16.0)
Requirement already satisfied: jmespath<2.0.0,>=0.7.1 in ./venv/lib/python3.12/site-packages (from boto3->-r requirements.txt (line 1)) (1.0.1)
Requirement already satisfied: s3transfer<0.14.0,>=0.13.0 in ./venv/lib/python3.12/site-packages (from boto3->-r requirements.txt (line 1)) (0.13.1)
Requirement already satisfied: python-dateutil<3.0.0,>=2.1 in ./venv/lib/python3.12/site-packages (from botocore->-r requirements.txt (line 3)) (2.9.0.post0)
Requirement already satisfied: urllib3!=2.2.0,<3,>=1.25.4 in ./venv/lib/python3.12/site-packages (from botocore->-r requirements.txt (line 3)) (2.5.0)
Requirement already satisfied: wcwidth in ./venv/lib/python3.12/site-packages (from prettytable->-r requirements.txt (line 5)) (0.2.13)
Requirement already satisfied: six>=1.5 in ./venv/lib/python3.12/site-packages (from python-dateutil<3.0.0,>=2.1->botocore->-r requirements.txt (line 3)) (1.17.0)

その後、Python を使用してツールを実行できます。

(venv) ~$ python3 CloudConqueror.py -h
---------------------------------------------------------------------------------

   _____ _                 _  _____
  / ____| |               | |/ ____|
 | |    | | ___  _   _  __| | |     ___  _ __   __ _ _   _  ___ _ __ ___  _ __
 | |    | |/ _ \\| | | |/ _` | |    / _ \\| '_ \\ / _` | | | |/ _ \\ '__/ _ \\| '__|
 | |____| | (_) | |_| | (_| | |___| (_) | | | | (_| | |_| |  __/ | | (_) | |
  \\_____|_|\\___/ \\__,_|\\__,_|\\_____\\___/|_| |_|\\__, |\\__,_|\\___|_|  \\___/|_|
                                                  | |
                                                  |_|

---------------------------------------------------------------------------------
                                                  by gl4ssesbo1 @ Exaforce
---------------------------------------------------------------------------------
usage: CloudConqueror.py [-h] {LISTRESOURCES,BRUTEFORCERESOURCES,IAMPERSISTENCE,CHECKUSAGE} ...

CloudConqueror

positional arguments:
  {LISTRESOURCES,BRUTEFORCERESOURCES,IAMPERSISTENCE,CHECKUSAGE}
                        Select the attack to execute on the target
    LISTRESOURCES       Bruteforce AWS Resources by utilizing cloudcontrol:ListResources and cloudcontrol:GetResource
    BRUTEFORCERESOURCES
                        Bruteforce AWS Resources by utilizing cloudcontrol:GetResource
    IAMPERSISTENCE      Persist on the Account using an IAM User or Role and a Policy which only allows access through CloudControl API.
    CHECKUSAGE          Search through AWS CloudTrail Logs using cloudtrail:LookupEvents to find occurrences of bruteforce

options:
  -h, --help            show this help message and exit

Docker インストール

CloudConqueror には Dockerfile が含まれています。これを使用して Docker イメージを作成し、その中からツールを実行できます。Docker イメージを作成するには、ツールのディレクトリで docker build を実行します。

~$ docker build -t cloudconqueror .
Sending build context to Docker daemon  99.07MB
Step 1/7 : FROM python:3.10
3.10: Pulling from library/python
80b7316254b3: Pull complete
36e4db86de6e: Pull complete
8ea45766c644: Pull complete
3cb1455cf185: Pull complete
013acb959c95: Pull complete
ee334269ae4f: Pull complete
3eca4263ed42: Pull complete
Digest: sha256:4585309097d523698d382a2de388340896e021319b327e2d9c028f3b4c316138
Status: Downloaded newer image for python:3.10
 ---> d565b0a5e178
Step 2/7 : WORKDIR /cloudconqueror
 ---> Running in e2e79b4829a4
 ---> Removed intermediate container e2e79b4829a4
 ---> 6f7ef917c82b
Step 3/7 : COPY . .

--snip--

Successfully built 559c27b10eae
Successfully tagged cloudconqueror:latest

次に、ツールを実行するには、docker run を使用してコンテナを起動します。保存済みの awscli セッションと、ツールのベースディレクトリからの出力フォルダをツールが取得できるように、ローカルの AWS プロファイルディレクトリ(~/.aws ディレクトリ)をマウントすることが推奨されます。

~$ docker run -v ~/.aws:/root/.aws -v ./output:/cloudconqueor/output -it cloudconqueror -h
---------------------------------------------------------------------------------

   _____ _                 _  _____
  / ____| |               | |/ ____|
 | |    | | ___  _   _  __| | |     ___  _ __   __ _ _   _  ___ _ __ ___  _ __
 | |    | |/ _ \\| | | |/ _` | |    / _ \\| '_ \\ / _` | | | |/ _ \\ '__/ _ \\| '__|
 | |____| | (_) | |_| | (_| | |___| (_) | | | | (_| | |_| |  __/ | | (_) | |
  \\_____|_|\\___/ \\__,_|\\__,_|\\_____\\___/|_| |_|\\__, |\\__,_|\\___|_|  \\___/|_|
                                                  | |
                                                  |_|

---------------------------------------------------------------------------------
                                                  by gl4ssesbo1 @ Exaforce
---------------------------------------------------------------------------------
usage: CloudConqueror.py [-h] {LISTRESOURCES,BRUTEFORCERESOURCES,IAMPERSISTENCE,CHECKUSAGE} ...

CloudConqueror

positional arguments:
  {LISTRESOURCES,BRUTEFORCERESOURCES,IAMPERSISTENCE,CHECKUSAGE}
                        Select the attack to execute on the target
    LISTRESOURCES       Bruteforce AWS Resources by utilizing cloudcontrol:ListResources and cloudcontrol:GetResource
    BRUTEFORCERESOURCES
                        Bruteforce AWS Resources by utilizing cloudcontrol:GetResource
    IAMPERSISTENCE      Persist on the Account using an IAM User or Role and a Policy which only allows access through CloudControl API.
    CHECKUSAGE          Search through AWS CloudTrail Logs using cloudtrail:LookupEvents to find occurrences of bruteforce

options:
  -h, --help            show this help message and exit

リソースの一覧取得

CloudConqueror は cloudcontrol:ListResources を使用して、アカウント内の特定リソースタイプのリソースを一覧表示します。リソースを一覧表示して識別子を取得した後、それぞれに対して cloudcontrol:GetResource の実行を試み、プロパティを取得します。ツールに必要な入力は、awscli ディレクトリに保存された AWS プロファイルと、一覧表示するリソースタイプだけです。

CloudConqueror script lists 44 IAM roles from AWS account using CloudControl API
CloudConqueror を使用したリソース一覧取得

すべてのリソースタイプは、ツールの --resource-type フラグの選択肢として表示されます。このフラグにより、AWS CloudControl API で管理されていないリソースは除外されます。

Terminal showing extensive list of AWS service types parsed by CloudConqueror
リソースタイプ呼び出しの出力

リソースのブルートフォース

本記事で説明した手法の 1 つは、存在する可能性のあるリソース名のリストに対して cloudcontrol:GetResource API 呼び出しを実行し、その中のどれかが存在するかを確認する方法です。つまり、基本的には、アカウント内リソースに対する認証済みの名前ファジングです。

BRUTEFORCE コマンドでは、攻撃者が AWS プロファイル、リソースタイプ、AWS リージョン、リソース名のリストを指定し、それぞれに対して cloudcontrol:GetResource を実行します。存在するリソースについては、そのプロパティが返されます。

CloudConqueror finds IAM user with CloudTrail update access using brute force test
既存リソースを探す CloudControl ブルートフォース

AWS アカウント内での永続化

攻撃者は、「AWS CloudControl API は攻撃ツールとしてどれほど有効か」のセクションで説明したように、CloudControl API 経由のアクセスのみを許可する IAM ポリシーを作成し、それを IAM ユーザー、グループ、またはロールにアタッチすることで、それらを使って永続化できます。

CloudConqueror の IAMPERSISTENCE コマンドはこの手法を使用し、ユーザーまたはロールを作成します。攻撃者が指定しない場合、デフォルト名は CCUser または CCRole です。さらに、CCInlinePolicy というインラインポリシーをそのユーザーまたはロールに割り当てます。ポリシー定義は、「AWS CloudControl API は攻撃ツールとしてどれほど有効か」のセクションで示したものと同じです。

CloudConqueror creates new IAM role and inline policy for persistence testing
アカウント内で永続化するためのポリシーを作成する CloudConqueror コマンド

CloudControl 悪用の発生箇所を見つける

最後に、CloudConqueror は検出の一部も支援できます。このツールの CHECKUSAGE コマンドは、cloudtrail:LookupEvents を使用して、アカウント内で CloudControl API が実行された痕跡を検索し、その結果をテーブルと CSV として出力します。

CloudConqueror detects thousands of CloudControl API abuses across account
CloudControl API 呼び出しの実行を確認する CloudConqueror

The output CSV will be stored in the directory path output/<Account ID>/cloudcontrol-events.csv in the tool’s directory.

Output file cloudcontrol-events.csv successfully created by CloudConqueror
CloudControl API 呼び出しを含む CSV の作成

エクサフォースが CloudControl API の悪用特定をどのように支援するか

エクサフォースは、列挙、リソースのなりすまし、異常な使用など、CloudControl API の悪用を特定するための包括的な検出機能を提供します。私たちのアプローチでは、ビヘイビアベースラインと異常検知を活用し、正当な CloudFormation アクティビティと、CloudControl を使用する攻撃者の手法を切り分けます。この調査を受けて、CloudControl の不正利用からお客様を保護するための新しい検出機能を有効化しました。

Two medium-severity IAM anomaly findings flagged for CloudControl and CloudFormation misuse
CloudControl API の悪用によって発生した、不審な CloudControl API 列挙パターンと CloudFormation 異常の検出例

検出概要では、アラートに対するエクサボットの自動トリアージによるサマリーと結論を提示し、関与したアイデンティティや問題となった特定の API 呼び出しなど、重要な詳細を強調します。関連するすべての API 呼び出しを 1 つのセッションとして関連付けることで、CloudControl が攻撃シーケンスの中でどのように使用され、どのリソースが影響を受けたのかを、アナリストが完全な文脈で把握できるようにします。

Exaforce alert showing IAM brute force activity using CloudControl API enumeration
CloudControl API の悪用に失敗した試行の脅威検出結果

さらに、エクサフォースの Identity 調査では、CloudControl を通じて作成されたユーザーやロールを自動的に抽出し、永続化のために作成された可能性のある IAM リソースを可視化します。

Exaforce dashboard showing AWS role “CCRole” detected with zero third-party access
CloudControl API によって作成された AWS IAM ロール

CloudControl を監視下に置く

AWS CloudControl API は、AWS API が持つ膨大な API 呼び出しを、AWS ユーザーが整理された形で簡単に管理・活用できるようにする強力な機能です。しかし、よくあるように、ユーザーにとって使いやすいものは、攻撃者にとっても悪用しやすいものになり得ます。

AWS CloudControl API を攻撃ツールとして利用する手法には制約がありますが、検出の連鎖を断ち切る有効な方法になり得ます。その結果、攻撃者がアカウント内で不正な操作を行いながら、正規の挙動に紛れ込む可能性があります。そのため、この機能は継続的に監視し、望ましくない主体によって悪意を持って使用されていないことを確認する価値があります。

エクサフォースは CloudControl API の悪用に対する検出機能を提供し、AWS CloudControl API の悪意ある使用を迅速に特定し、速やかな対応につなげます。

関連記事

理想のSOCチーム。
24時間365日、お客様とともに稼働します。

お客様の環境を一元的かつリアルタイムに把握する4つのエクサボットが、検出、トリアージ、調査、対応をカバーします。プラットフォームを自社で運用することも、エクサフォースに運用を任せることもできます。