Terrance DeJesus

探索 AWS STS AssumeRoot

AWS Organizations 中的 AssumeRoot 滥用和检测策略

阅读 19 分钟安全研究
Exploring AWS STS AssumeRoot

前言

欢迎阅读另一篇关于使用 Elastic 进行 AWS 检测工程的文章。本文将深入探讨新的 AWS 安全令牌服务 (STS) API 操作 AssumeRoot,在沙盒 AWS 环境中模拟一些实际行为,并探索 Elastic SIEM 中的检测功能。

本文的预期内容

  • 对 AWS STS Web 服务的基本了解
  • 对 STS 的 AssumeRoot API 操作的了解
  • 使用 Terraform 和 Python 代码的 AssumeRoot 威胁场景
  • 针对潜在 AssumeRoot 滥用的检测和狩猎机会

了解 AWS STS 和 AssumeRoot API

AWS 安全令牌服务 (STS) 是一项 Web 服务,使用户、帐户和角色能够请求临时的、有限权限的凭证。对于 IAM 用户,他们的帐户通常在 AWS 身份和访问管理 (IAM) 中注册,其中附加登录配置文件以访问控制台,或者创建访问密钥和密钥以供 Lambda、EC2 等服务以编程方式使用。

虽然 IAM 凭证是持久的,但 STS 凭证是临时的。这些凭证(包括访问密钥、密钥和会话令牌)在请求时授予,并且在特定时间内有效。请求通常发送到全局 sts.amazonaws.com 端点,该端点会响应用户的临时凭证或角色。然后,可以使用这些凭证代表指定的用户或角色访问其他 AWS 服务,前提是相关权限策略明确允许该操作。

此过程通常称为承担角色,通过 AssumeRole API 执行。它经常用于各种场景的 AWS 环境和组织中。例如

  • 附加角色的 EC2 实例将自动使用 AssumeRole 来检索 API 请求的临时凭证。
  • 同样,Lambda 函数经常调用 AssumeRole 进行身份验证并执行其指定的操作。

尽管 AssumeRole 非常有用,但如果组织的角色的权限过高,则可能会构成风险。配置不当且权限过多的策略可能允许攻击者滥用这些角色,尤其是在不严格执行最小权限原则 (PoLP) 的环境中。请注意,与 AssumeRole 相关的安全风险通常归因于配置不当或组织未遵循最佳安全实践。这些不是 AssumeRole 甚至 AssumeRoot 开发决策的结果。

AssumeRoot 简介

AWS 最近向 STS 引入了 AssumeRoot API 操作。与 AssumeRole 类似,它允许用户检索临时凭证,但专门用于 AWS 组织中成员帐户的根用户

什么是成员帐户?

在 AWS 中,成员帐户是组织内拥有自己的 IAM 用户、服务和角色的独立帐户。这些帐户与管理帐户不同,但它们仍属于同一组织层次结构。每个 AWS 组织都是使用在设置期间使用的电子邮件地址绑定的唯一根帐户创建的。同样,每个成员帐户在创建时都需要根用户或电子邮件地址,从而有效地建立其自己的根身份。

AssumeRoot 的工作原理是什么?

当管理帐户中的特权用户需要成员帐户的根级别权限时,他们可以使用 AssumeRoot API 来检索成员帐户的根用户的临时凭证。与 AssumeRole 的目标主体是用户 ARN 不同,AssumeRoot 的目标主体是成员帐户 ID 本身。此外,必须指定任务策略 ARN,该 ARN 定义临时凭证允许的特定权限。

以下是 AssumeRoot 的可用任务策略 ARN

任务策略的潜在滥用

虽然这些预定义的任务策略限制了 AssumeRoot 可以执行的操作,但在适当的情况下,它们的范围仍然可以在理论上被滥用。例如

  • IAMCreateRootUserPassword:此策略授予 iam:CreateLoginProfile 权限,允许为通常不需要控制台访问权限的用户创建登录配置文件。如果攻击者获得对编程凭证的访问权限,他们可以创建一个登录配置文件,并获得对该帐户的更持久的控制台访问权限。
  • IAMDeleteRootUserCredentials:此策略允许删除根凭证,但还授予 iam:ListAccessKeysiam:ListMFADevices 等权限。这些权限可以帮助攻击者收集有关访问凭证或 MFA 配置的关键信息,以进一步利用。

AssumeRoot 实际操作

现在我们已经了解了 AssumeRoot 的工作原理、它与 AssumeRole 的不同之处,以及与不当安全实践相关的潜在风险,让我们通过一个实际场景来模拟其用法。应该注意的是,这只是可能或可能滥用 AssumeRoot 的许多潜在场景之一。截至本文发布之时,尚未有任何关于野外活跃滥用的报告,正如较新的 AWS 功能所预期的那样。

以下是我们在以下部分中将要完成的简单描述

在深入探讨之前,需要强调的是,我们正在使用一个配置为本地 AWS CLI 默认配置的管理员级别 IAM 用户。此设置使我们能够使用 Terraform 正确配置环境,并在 AWS 中模拟潜在的威胁场景以进行检测。

成员账户创建

第一步是为成员账户启用集中式根访问权限,如 AWS 文档中所述。集中式根访问权限允许我们将所有 AWS 账户分组到一个组织中,每个成员账户都有自己的根用户。

接下来,我们通过 AWS 管理控制台的“账户”部分在我们的组织中手动创建一个成员账户。在这种情况下,关键要求是记下成员账户 ID,这是一个唯一的 12 位数字。在我们的示例中,我们假设此 ID 为 000000000001,并将其命名为 *AWSAssumeRoot*。对于可能将不同运营服务分离到不同 AWS 账户但希望保持集中式管理的公司来说,集中式 AWS 账户管理是一种常见做法。

我们还将成员账户添加为集中式根访问的委派管理员,这允许该根成员账户对组织的任何其他成员账户具有集中式根访问权限。

虽然我们不会深入讨论,但我们还在身份和访问管理 (IAM) 中启用了新的资源控制策略 (RCP),这将允许对我们组织中账户内的资源授予权限进行集中管理,但默认情况下,*RCPFullAWSAccess* 策略允许所有主体对所有服务的所有权限,并且直接附加到根。

环境设置

在我们的模拟中,我们使用 Terraform 创建一个名为 compromised_user 的过度授权 IAM 用户。此用户被授予预定义的AdministratorAccess 策略,该策略提供管理员级别的权限。此外,我们为此用户生成了一个访问密钥,同时故意省略了登录配置文件,以反映凭证以编程方式使用的典型设置。这并非不常见的做法,尤其是在开发人员环境中。

下面是用于创建资源的 main.tf 配置

provider "aws" {
  region = var.region
}

data "aws_region" "current" {}

# Create an IAM user with AdministratorAccess (simulated compromised user)
resource "aws_iam_user" "compromised_user" {
  name = "CompromisedUser"
}

# Attach AdministratorAccess Policy to the compromised user
resource "aws_iam_user_policy_attachment" "compromised_user_policy" {
  user       = aws_iam_user.compromised_user.name
  policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"
}

# Create access keys for the compromised user
resource "aws_iam_access_key" "compromised_user_key" {
  user = aws_iam_user.compromised_user.name
}

我们还定义了一个 outputs.tf 文件来捕获有关环境的关键详细信息,例如区域、访问凭证和用户 ARN

output "aws_region" {
  description = "AWS Region where the resources are deployed"
  value       = var.region
}

output "compromised_user_access_key" {
  value       = aws_iam_access_key.compromised_user_key.id
  sensitive   = true
  description = "Access key for the compromised IAM user"
}

output "compromised_user_secret_key" {
  value       = aws_iam_access_key.compromised_user_key.secret
  sensitive   = true
  description = "Secret key for the compromised IAM user"
}

output "compromised_user_name" {
  value       = aws_iam_user.compromised_user.name
  description = "Name of the compromised IAM user"
}

output "compromised_user_arn" {
  value       = aws_iam_user.compromised_user.arn
  description = "ARN of the compromised IAM user"
}

一旦我们运行 terraform apply,该配置将创建一个具有高度权限的 IAM 用户 (compromised_user) 和关联的凭证。这些凭证模拟攻击者可能获得的用于初始访问或提升权限的凭证。

这是攻击者的第一个障碍之一,即收集有效的凭证。在当今的威胁形势中,信息窃取恶意软件和网络钓鱼活动比以往任何时候都更加常见,旨在获取可以出售或用于横向移动的凭证。虽然这是一个障碍,但初始访问时凭证被盗的可能性很高 - 例如 SCATTERED SPIDERSCARLETEEL 所使用的凭证。

使用被盗凭证建立 STS 客户端会话

下一步是使用被盗凭证 (compromised_user 访问密钥和密钥) 建立 STS 客户端会话。此会话允许攻击者代表被盗用户向 AWS STS 发出请求。

以下是使用 AWS Boto3 SDK(用于创建、配置和管理 AWS 服务(如 Amazon EC2 和 Amazon S3)的 AWS SDK)建立 STS 客户端的 Python 代码。此 Python 代码用于使用被盗的 IAM 用户凭证创建 STS 客户端

 sts_client = boto3.client(
     "sts",
     aws_access_key_id=compromised_access_key,
     aws_secret_access_key=compromised_secret_key,
     region_name=region,
     endpoint_url=f'https://sts.{region}.amazonaws.com'
 )

注意:在测试期间,我们发现 endpoint_url 必须显式指向 https://sts.<region>.amazonaws.com。省略此项可能会导致在尝试调用 AssumeRoot API 时出现 InvalidOperation 错误。

此 STS 客户端会话构成了模拟攻击者行为的基础,因为我们已获取了被盗的凭证并启动了恶意操作。

代表被盗用户承担成员账户的根身份

在以被盗用户的身份建立 STS 客户端会话后,我们可以继续调用 AssumeRoot API。此请求允许我们承担 AWS 组织中成员账户的根身份。对于该请求,TargetPrincipal 设置为我们之前获得的成员账户 ID,会话持续时间设置为 900 秒(15 分钟),并且 TaskPolicyArn 定义为 IAMCreateRootUserPassword。此策略将权限范围限定为与创建或管理根登录凭证相关的操作。

此策略中包含的一个值得注意的权限是 CreateLoginProfile,它允许为根用户创建登录密码。这允许以根用户身份访问 AWS 管理控制台。

以下是以 IAMCreateRootUserPassword 限定权限的 Python 代码,用于承担成员账户 000000000001 的根身份。

response = sts_client.assume_root(
    TargetPrincipal=member_account_id,
    DurationSeconds=900,
    TaskPolicyArn={"arn": "arn:aws:iam::aws:policy/root-task/IAMCreateRootUserPassword"},
)
root_temp_creds = response["Credentials"]

如果 AssumeRoot 请求成功,响应将为目标成员的根账户提供临时凭证 (root_temp_creds)。这些凭证包括访问密钥、密钥和会话令牌,允许在会话期间获得临时的根级别访问权限。

为成员根账户创建登录配置文件

有了临时根凭证,下一步是以成员账户的根用户身份建立经过身份验证的 IAM 客户端会话。使用此会话,我们可以调用 create_login_profile() 方法。此方法允许我们为根用户分配登录密码,从而启用控制台访问。

以下 Python 代码建立了经过身份验证的 IAM 客户端并创建了一个登录配置文件

iam_client = boto3.client(
    "iam",
    aws_access_key_id=root_temp_creds["AccessKeyId"],
    aws_secret_access_key=root_temp_creds["SecretAccessKey"],
    aws_session_token=root_temp_creds["SessionToken"],
)

response = iam_client.create_login_profile()

值得注意的是,create_login_profile() 方法不需要为根用户显式参数,因为它作用于当前经过身份验证的会话的凭证。在这种情况下,它将应用于成员账户的根用户。

重置管理员密码并登录 AWS 控制台

在此阶段,我们几乎完成了!让我们回顾一下目前的进展

  1. 使用被盗的 IAM 用户凭证,我们建立了一个 STS 会话来承担过度授权用户的身份。
  2. 利用此会话,我们承担了目标成员账户的根用户的身份,获取了范围限定为 IAMCreateRootUserPassword 任务策略的临时凭证。
  3. 使用这些临时根凭证,我们建立了 IAM 客户端会话并成功为根用户创建了登录配置文件。

最后一步是重置根用户密码以获得对 AWS 管理控制台的永久访问权限。为此,请访问 AWS 控制台登录页面并尝试以根用户身份登录。选择“忘记密码”选项以启动密码恢复过程。这将提示 CAPTCHA 挑战,之后将向根用户的电子邮件地址发送密码重置链接。这将是攻击者的第三个障碍,因为他们需要访问根用户的电子邮件收件箱才能继续密码重置工作流程。应该承认,如果调用 *CreateLoginProfile*,您可以指定用户的密码并强制执行“需要重置密码”。但是,默认情况下,AWS 不允许对根账户执行此操作,而且这样做也是有充分理由的。与拥有有效凭证的第一个障碍不同,访问用户的收件箱可能更加困难且可能性较小,但同样,只要有足够的动机和资源,仍然有可能实现。

选择密码重置链接后,您可以为根用户设置新密码。此步骤提供了对控制台的持久访问权限,因为该用户是根用户。与之前获得的临时凭证不同,此访问权限不再受会话持续时间或 IAMCreateRootUserPassword 策略的范围权限的限制,从而授予对成员账户的无限制管理控制权。

在继续之前,如果您跟进并在您的环境中尝试了此操作,我们想温和地提醒您使用 Terraform 删除测试资源,方法是在您初始化和部署资源的同一文件夹中使用 terraform destroy 命令。

检测和搜寻机会

从攻击者的角度探索云功能和 API 具有启发性,但我们的最终责任在于检测和减轻恶意或异常行为、提醒利益相关者并有效响应。此外,虽然这种场景尚未在野外公开记录,我们也不应该等待成为受害者,而是应该主动做出反应,这正是我们进行白盒场景的原因。

以下检测和搜寻查询依赖于使用 AWS 集成 摄取到 Elastic Stack 中的 AWS CloudTrail 数据。如果您的环境不同,您可能需要针对自定义摄取过程调整这些查询,或将其调整为不同的 SIEM 或查询工具。

注意:确保为组织中的所有账户启用 AWS CloudTrail,以便全面了解整个 AWS 环境中的活动。您可能还需要启用用于监控整个组织的特定跟踪,以便正确观察所有成员账户。

搜寻 - IAM 用户访问密钥的异常操作

此查询识别可能被盗用的 IAM 访问密钥,这些访问密钥用于发出不寻常的 API 调用。它按升序对结果进行排序,以显示最近两周内不太频繁的 API 调用。可以调整此查询以考虑不同的 API 调用或包含其他 CloudTrail 特定的字段。

搜寻查询:AWS IAM 用户 AWS 访问密钥的异常使用

MITRE ATT&CK

语言:ES|QL

FROM logs-aws.cloudtrail*
| WHERE @timestamp > now() - 14 day
| WHERE
    event.dataset == "aws.cloudtrail"
    and event.outcome == "success"
    and aws.cloudtrail.user_identity.access_key_id IS NOT NULL
    and aws.cloudtrail.resources.arn IS NOT NULL
    and event.action NOT IN ("GetObject")
| EVAL daily_buckets = DATE_TRUNC(1 days, @timestamp)
| STATS
    api_counts = count(*) by daily_buckets, aws.cloudtrail.user_identity.arn, aws.cloudtrail.user_identity.access_key_id, aws.cloudtrail.resources.arn, event.action
| WHERE api_counts < 2
| SORT api_counts ASC

检测 - 罕见 IAM 用户的异常 Assume Root 操作

检测规则:AWS STS 从罕见用户和成员账户执行 AssumeRoot 操作

此查询用于识别在过去 14 天内未执行此操作的 IAM 用户 ARN 和成员账户发起的 AssumeRoot API 调用实例。此基于异常的检测使用了 Elastic 的新术语检测规则。

  • aws.cloudtrail.user_identity.arn 字段用于标识来自管理 AWS 账户的源 IAM 用户。
  • aws.cloudtrail.resources.account_id 字段反映了目标成员账户。

MITRE ATT&CK

语言:KQL

event.dataset: "aws.cloudtrail"
    and event.provider: "sts.amazonaws.com"
    and event.action: "AssumeRoot"
    and event.outcome: "success"

新术语字段
如果这些字段的任何组合在过去 14 天内未被看到执行 AssumeRoot,则会生成警报。

  • aws.cloudtrail.user_identity.arn
  • aws.cloudtrail.resources.account_id

检测 - 为根成员账户创建的自建登录配置文件

此查询检测根成员账户由根账户本身创建登录配置文件的实例,这可能表明存在未经授权或异常行为。

检测规则:为根账户添加 AWS IAM 登录配置文件

MITRE ATT&CK

语言:ES|QL

FROM logs-aws.cloudtrail* 
| WHERE
    // filter for CloudTrail logs from IAM
    event.dataset == "aws.cloudtrail"
    and event.provider == "iam.amazonaws.com"
    // filter for successful CreateLoginProfile API call
    and event.action == "CreateLoginProfile"
    and event.outcome == "success"
    // filter for Root member account
    and aws.cloudtrail.user_identity.type == "Root"
    // filter for an access key existing which sources from AssumeRoot
    and aws.cloudtrail.user_identity.access_key_id IS NOT NULL
    // filter on the request parameters not including UserName which assumes self-assignment
    and NOT TO_LOWER(aws.cloudtrail.request_parameters) LIKE "*username*"
| keep
    @timestamp,
    aws.cloudtrail.request_parameters,
    aws.cloudtrail.response_elements,
    aws.cloudtrail.user_identity.type,
    aws.cloudtrail.user_identity.arn,
    aws.cloudtrail.user_identity.access_key_id,
    cloud.account.id,
    event.action,
    source.address
    source.geo.continent_name,
    source.geo.region_name,
    source.geo.city_name,
    user_agent.original,
    user.id

这些检测是我们特定场景下的,但并不完全包含所有潜在的 AssumeRoot 滥用。如果您选择探索并发现一些额外的搜索或威胁检测机会,请随时在我们的 检测规则存储库或我们的威胁狩猎库中分享。

AssumeRoot 使用的强化实践

AWS 文档包含关于 IAM、STS 和许多其他服务安全的最佳实践的几个重要考虑事项。然而,云安全并非“一刀切”的工作流程,安全实践应根据您的环境、风险承受能力等进行定制。

可见性是关键: 如果您看不到,就无法保护它。首先启用组织范围内的 CloudTrail,以记录所有账户的活动。重点捕获 IAM 和 STS 操作,以深入了解访问和权限使用情况。将此与 Security Hub 结合使用,以进行持续监控,并使用 Elastic 或 GuardDuty 等工具来搜索不寻常的 AssumeRoot 操作。

锁定 AssumeRoot 权限: 将 AssumeRoot 的使用范围限定为仅限审计或恢复等关键任务,方法是将任务策略限制为 IAMAuditRootUserCredentials 等基本要素。将这些权限分配给管理账户中的特定角色,并严格控制这些角色。定期审查并删除不必要的权限,以维护 PLoP。

MFA 和根访问的护栏: 对所有用户(尤其是那些有权访问 AssumeRoot 的用户)强制执行 MFA。使用 AWS Organizations 禁用根凭证恢复(除非绝对必要),并完全删除未使用的根凭证。RCP 可以帮助集中和收紧涉及 AssumeRoot 或其他敏感操作的任务权限。

结论

我们希望本文能让您深入了解 AWS 的 AssumeRoot API 操作、攻击者如何滥用它以及一些威胁检测和搜索指南。滥用 AssumeRoot 是攻击者有能力针对的众多云上生存 (LotC) 技术之一,但我们鼓励其他人探索、研究并相应地与社区和 AWS 分享他们的发现。