🛰️

AWSのIAMポリシーに対するクエリを実行するIAMActionHunterを試してみる

2023/07/18に公開

IAMActionHunter

Pacuの開発をしているRhino Security Labsから新たにIAMActionHunterが開発されました。
このIAMActionHunter自体は単体のツールとして提供されていますが、クエリの機能はPacuのモジュールにも追加されています。

https://rhinosecuritylabs.com/aws/iamactionhunter-aws-iam-permissions/

IAMActionHunterで実現できること

Rhino Security LabsのブログのOffensive and Defensive Use Casesを見ると、以下のようにあります。

While other tools perform scans to identify privilege escalation risks, this tool enables a more manual approach, allowing users to investigate any permission they choose and quickly assess the roles, users, and resources they apply to for targeted analysis or privilege escalation path idea generation.

Google翻訳
他のツールは権限昇格のリスクを特定するためにスキャンを実行しますが、このツールはより手動のアプローチを可能にし、ユーザーが選択した権限を調査し、対象を絞った分析や権限昇格パスのアイデア生成のために適用するロール、ユーザー、およびリソースを迅速に評価できるようにします。

今までPacuを積極的に使うようなことがなかったのであまり意識がなかったのですが、iam__bruteforce_permissionsiam__enum_permissionsのようなモジュールは単一のIAMロールやIAMユーザに焦点を当てたツールでしたが、このツールでは取得したIAMユーザやIAMロールに対して調査したい権限を探す、といった使い方が想定されているようです。

https://github.com/RhinoSecurityLabs/pacu/wiki/Module-Details#iam__enum_action_query

使ってみる

IAMActionHunterの導入

https://github.com/RhinoSecurityLabs/IAMActionHunter

git clone https://github.com/RhinoSecurityLabs/IAMActionHunter.git
cd IAMActionHunter
pip install .
iamactionhunter --help
iamactionhunter --collect --profile <some-aws-profile>

調査用のIAMユーザの作成

今回は調査用にReadOnlyAccessを持ったIAMユーザを作成しました。

アクセスキーを作成し、認証情報を~/.aws/credentialsに保存します。
私はprofileはiamactionにしました。

[iamaction]
aws_access_key_id = アクセスキー
aws_secret_access_key = シークレットキー

認証情報の取得

collect

まずはIAMユーザとIAMロールに結び付くポリシーを取得します。
--profileには~/.aws/credentialsに指定したProfile名を指定すること。

$ iamactionhunter --collect --profile iamaction
Downloading IAM policies for account [AWSアカウントID]...
Finished downloading IAM policies for account [AWSアカウントID].
Processing files for [AWSアカウントID]...

実行すると./actionhunter_output/[AWSアカウントID]フォルダ配下にjsonファイルが保存される。

list

クエリが実行できるアカウントがリストできるようです。collectを一か所にしかしていないので一つだけ表示されました。

$ iamactionhunter --list
[AWSアカウントID]

query

クエリにs3:putobject*などアスタリスクを利用できるほか、iam:createrole,sts:assumeroleのようにカンマ区切りに指定することができます。
出力パターンとしては[+]がそのアクションを許可できるユーザ/ロールで、[-]にコンディション句などで権限が制限していることを表しているようです。

サンプル

[+] role:aws-elasticbeanstalk-service-role vulnerable to CreateEC2WithExistingIP:
ec2:runinstances
*
[-] With the following conditions:
{'ArnLike': {'ec2:LaunchTemplate': 'arn:aws:ec2:*:*:launch-template/*'}}
iam:passrole
arn:aws:iam::*:role/*
[-] With the following conditions:
{'StringEquals': {'iam:PassedToService': ['elasticbeanstalk.amazonaws.com', 'ec2.amazonaws.com', 'ec2.amazonaws.com.cn', 'autoscaling.amazonaws.com', 'elasticloadbalancing.amazonaws.com', 'ecs.amazonaws.com', 'cloudformation.amazonaws.com']}}

恐らく以下のフォーマット
[-]は該当すれば表示

[+] principal:iam名/role名 vulnerable to 該当するポリシー名:
アクション1(iam:passroleなど)
アクション1のリソース
[-] With the following conditions:
{コンディション句}
アクション2(iam:passroleなど)
アクション2のリソース
etc...

以下は私の環境での実行結果のAWS CDKに関連するロールでの抜粋です。基本は検証で使う程度で常駐しているリソースはないものの放置されてるIAMロールなどがいくつかあるはずです。
今回は全部で167件の出力。

$ iamactionhunter --account [AWSアカウントID] --query s3:putobject*
< --snip-- >
[+] role:cdk-hnb659fds-cfn-exec-role-[AWSアカウントID]-ap-northeast-1 can perform s3:putobjectlegalhold on the following resources:
*
< --snip-- >
[+] role:cdk-hnb659fds-file-publishing-role-[AWSアカウントID]-ap-northeast-1 can perform s3:putobjecttagging on the following resources:
arn:aws:s3:::cdk-hnb659fds-assets-[AWSアカウントID]-ap-northeast-1
arn:aws:s3:::cdk-hnb659fds-assets-[AWSアカウントID]-ap-northeast-1/*
< --snip-- >
[+] role:cdk-hnb659fds-deploy-role-[AWSアカウントID]-us-west-2 can perform s3:putobjecttagging on the following resources:
*
[-] With the following conditions:
{'StringNotEquals': {'s3:ResourceAccount': '[AWSアカウントID]'}}
< --snip-- >
別パターンの表示

恐らくいろいろなパターンがあると思いますが、たまたま見つけたので一応載せておきます。

[+] role:AWSServiceRoleForEC2Spot can perform ec2:runinstances on the following resources:
*
[-] If the resources are not included in:
arn:aws:ec2:*:*:instance/*
[-] These Deny rules only apply if the following conditions are met:
{'StringNotEquals': {'ec2:InstanceMarketType': 'spot'}}
user/role

--user,--roleで結果のフィルタ。
cdk-hnb659fds-deploy-role-cdk-hnb659fds-deploy-role-*での部分一致はできませんでした。

$ iamactionhunter --account [AWSアカウントID] --query s3:putobject* --role cdk-hnb659fds-deploy-role-[AWSアカウントID]-us-west-2
[+] role:cdk-hnb659fds-deploy-role-[AWSアカウントID]-us-west-2 can perform s3:putobjectversiontagging on the following resources:
*
[-] With the following conditions:
< --snip-- >
csv

結果をcsvファイルとして出力。

Principal,Allowed Action,Denied Action,Resource,Conditions
user:pacu-iam,ses:getimportjob,,*,[]
user:pacu-iam,rds:describedbparametergroups,,*,[]
< --snip-- >
role:cdk-hnb659fds-deploy-role-[AWSアカウントID]-ap-northeast-1,s3:deleteobject,,*,[{'StringNotEquals': {'s3:ResourceAccount': '[AWSアカウントID]'}}]
< --snip-- >

config

configs/配下に置くことで、--configで指定した条件でクエリできるっぽい。

、、、が、jsonファイルを適当に書いてみたが動かせなかった。

読み込めてはいそうなので設定ファイルが違うのかもしれない。all.pyに追記すれば動きそうな気はするが試していない。

{
    "Description": "",
    "Name": "DangerousIAMActions",
    "ActionsNeeded": [
        "s3:putobject*"
    ],
    "AllOrNone": "0"
}
$ iamactionhunter --account [AWSアカウントID] --config mys3
Traceback (most recent call last):
  File "/home/lea/.local/bin/iamactionhunter", line 8, in <module>
    sys.exit(main())
  File "/home/lea/.local/lib/python3.10/site-packages/IAMActionHunter/IAMActionHunter.py", line 312, in main
    process_config_file_query(permissions, config, f"{principal_type}:{principal_name}", args)
  File "/home/lea/.local/lib/python3.10/site-packages/IAMActionHunter/IAMActionHunter.py", line 171, in process_config_file_query
    query = config["ActionsNeeded"]
TypeError: string indices must be integers

ブログにあるdangerous_iamはデフォルトで入っている。
他にはwrite系アクションを見つけるためのwrite_actionsと権限昇格につながるアクションを見つけるprivescsがありました。
https://github.com/RhinoSecurityLabs/IAMActionHunter/blob/main/IAMActionHunter/configs/all.py

$ iamactionhunter --account [AWSアカウントID] --config dangerous_iam
[+] role:pacu-role vulnerable to DangerousIAMActions:
iam:putrolepolicy
*
iam:createloginprofile
*
< --snip-- >
$ iamactionhunter --account [AWSアカウントID] --config privescs
< --snip-- >
[+] role:aws-elasticbeanstalk-service-role vulnerable to CreateEC2WithExistingIP:
ec2:runinstances
*
[-] With the following conditions:
{'ArnLike': {'ec2:LaunchTemplate': 'arn:aws:ec2:*:*:launch-template/*'}}
iam:passrole
arn:aws:iam::*:role/*
[-] With the following conditions:
{'StringEquals': {'iam:PassedToService': ['elasticbeanstalk.amazonaws.com', 'ec2.amazonaws.com', 'ec2.amazonaws.com.cn', 'autoscaling.amazonaws.com', 'elasticloadbalancing.amazonaws.com', 'ecs.amazonaws.com', 'cloudformation.amazonaws.com']}}
< --snip-- >

all or none

--all-or-noneを付けることで、queryのすべてにマッチするものだけを出力することができます。

iam:createrolests:assumeroleについて-all-or-noneの出力を比較します。

$ iamactionhunter --account [AWSアカウントID] --query iam:createrole,sts:assumerole --all-or-none | wc -l
54
$ iamactionhunter --account [AWSアカウントID] --query iam:createrole,sts:assumerole | wc -l
65

私の環境では以下の3つのroleが差分として出力されています。

[+] role:AWSServiceRoleForCloudFormationStackSetsOrgMember can perform iam:createrole on the following resources:
arn:aws:iam::*:role/stacksets-exec-*

[+] role:AWSReservedSSO_AWSPowerUserAccess_895d5e4887af7b9f can perform sts:assumerole on the following resources:
*

[+] role:AWSServiceRoleForSSO can perform iam:createrole on the following resources:
arn:aws:iam::*:role/aws-reserved/sso.amazonaws.com/*
[-] With the following conditions:
{'StringNotEquals': {'aws:PrincipalOrgMasterAccountId': '${aws:PrincipalAccount}'}}

AWSServiceRoleForCloudFormationStackSetsOrgMemberにはAWSマネージド管理ポリシーであるCloudFormationStackSetsOrgMemberServiceRolePolicyのみがアタッチされています。
ポリシーの通り、iam:createroleの権限を持つが、sts:assumeroleは持っていないようです。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "iam:CreateRole",
                "iam:DeleteRole",
                "iam:GetRole"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:iam::*:role/stacksets-exec-*"
            ]
        },
        {
            "Action": [
                "iam:DetachRolePolicy",
                "iam:AttachRolePolicy"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:iam::*:role/stacksets-exec-*"
            ],
            "Condition": {
                "StringEquals": {
                    "iam:PolicyARN": "arn:aws:iam::aws:policy/AdministratorAccess"
                }
            }
        }
    ]
}

おわりに

クエリをたたく用途が見つけられる人にはいい感じに使えそうな気がするが、そもそも何をクエリにすればいいかを見つけるのはなかなかレベルが要求されそう。
他人任せだけども、、dangerous_iamのようなデフォルトで使えるconfigがあるととりあえず使ってみようとはなりそうなので、いい感じに増えてほしい。。

同様の機能がpacuにあると書いてあるが、configの機能はなかったように思うのであくまでクエリができるところまでっぽい。ちゃんと確認はしてない。
https://github.com/RhinoSecurityLabs/pacu/wiki/Module-Details#iam__enum_action_query

csvのアウトプットなど、Excelで操作できるとかは用途がある気はするので、単体のツールとしてある理由も理解できるので、入れておいてもいいかも。

リソースポリシーも見れると嬉しいけどさすがに範囲が広くて難しそうかな。。

Discussion