BLUF:每条攻击路径都需要一个目的地。这是在 AWS 中描述目标的正式方式。在只有数据平面访问权限的云提供商中,我们将注意力从管理员的武断定义转移到我们关心的资源上。
您的 AWS 环境中有多少名管理员?这有关系吗?
这似乎是一个简单而常见的问题,但往往很难回答,尤其是在大型 AWS 环境中。为了能够回答这个问题,我们首先需要了解“什么是管理员?您可以即兴说,管理员是附加了 AdministratorAccess 策略的任何委托人,或者更具体地说,是具有以下特点的委托人:
{ “Effect”: “Allow”, “Action”: “*”, “Resource”: “*” }
在他们的一项政策中。对于 AWS 初学者,此语句表示允许对账户中的任何资源执行任何操作(在 16982 个定义的 AWS 操作中)。这是一个合乎逻辑的起点,但最终是一个过于简单和限制性的定义。如果我们要修改策略,它就不符合我们当前对 administrator 的定义:
[ { “Effect”: “Allow”, “Action”: “*”, “Resource”: “*” }, { “Effect”: “Deny”, “Action”:“elastictranscoder:readpipeline”, “Resource”:"*" } ]
这里唯一的修改是,我们不能再调用 16982 个操作之一,只留下 16981 个供我们使用。我想大多数人都会直觉地认为我们确实仍然被视为管理员,即使这并不符合我们最初的严格定义。在这种情况下,在我们不再被视为管理员之前,我们可以削减多少权限?在这种情况下,我认为将主要人员分为两组是有帮助的:
-
当前是 “administrator” 的主体。我们将这些权限称为 direct 权限。 -
可以修改环境的某些方面以成为管理员的主体。我们将这些权限称为 indirect permissions。
两者之间的主要区别在于后者需要某种写入操作来获得必要的权限。本文的其余部分将重点介绍直接权限,我将在后面的文章中讨论图形修改。概括地说,我们可以将管理员定义为对其账户中可以执行的操作没有限制的委托人。
一种可能的方法是将特定操作标记为高价值的 “管理员” 操作。这可以包括 iam:updaterolepolicy、iam:passrole、iam:createuserkeys 等操作。我不喜欢这种方法,因为 AWS 策略定义具有灵活性。例如,我可以指定用户可以更新除自身之外的所有委托人的角色策略。这有点像管理员,但不允许主体自动提升。它当然没有达到应有的强大,但仍然非常强大。此外,这需要定义对 AWS 及其提供的操作有更具体的认识,因此该定义无法很好地扩展到其他云平台。确定用于审计的 “管理员操作” 可能会有所帮助,但我需要具体的定义来构建基础。最后,它混合了间接和直接权限,应区别对待。
在这种情况下,说“管理员可以对账户中的所有资源执行所有适用的操作”可能就足够了。这与第一个 AdministratorAccess 策略不同,后者翻译为“可以对可能存在的所有资源执行所有操作”。通俗地说,这是一个有意义的区别,因为大多数(如果不是全部)AWS 账户并未使用 AWS 必须提供的所有服务。例如,大多数 AWS 账户可能没有使用 elastictranscoder 服务。
如果能够对所有 elastictranscoder 资源(即使它们不存在)执行所有 elastictranscoder 操作是管理员考虑的要求,那么该定义就太受限制了。
这样做的结果是遗漏了应该被视为管理员的主体,并忽视了应该随之而来的审查。
让我们退后一步,考虑以下语句:
{ “Effect”: “Allow”, “Action”: “ec2:stopinstances”, “Resource”: “arn:aws:ec2:us-west-2:123456789012:instance/i-0abcd1234efgh5678” }
此语句是唯一的,因为它只允许对单个资源执行一次操作。它创建 ec2:stopinstances 到 arn:aws:ec2:us-west-2:123456789012:instance/i-0abcd1234efgh5678 的操作到资源对。此操作到资源的映射是我们集合处理的原子单元,表示调用方可以进行的成功 API 调用。为了推断这一点,请考虑修改后的语句:
{ “Effect”: “Allow”, “Action”: “ec2:*”, “Resource”: “arn:aws:ec2:us-west-2:123456789012:instance/i-0abcd1234efgh5678” }
此语句创建一组 action-to-resource 条目。由于并非每个 ec2 操作都可以作用于 ec2 实例,因此我们只能包含可作用于资源类型的操作。我们的结果表如下所示,我们将其称为权限矩阵,它只是操作和资源的笛卡尔积。
相反,如果我们在资源中放置通配符而不是操作,则使用账户中存在的所有 ec2 实例填充表。同样,ec2:stop实例只能作用于 ec2:instance 资源,因此我们可以省略所有其他类型的资源。
{ “Effect”: “Allow”, “Action”: “ec2:stopinstances”, “Resource”: “*” }
结果为以下权限矩阵:
当我们在两者中使用通配符时,我们的矩阵会变得非常大,但想法保持不变。使用这些 action-to-resource 集,我们可以按如下方式定义我们的 administrator:
for resourcein (allResourcesInTheAccount): actions = getAllActions(resource) // Gettingall the actions that can act on that resource addEntryToPermissionMatrix(action, resource)
在此伪代码中,我们列举了账户中的每个资源,确定可以对该资源执行哪些操作,并将该操作/资源对添加到我们称为“荒谬管理员矩阵”(RAM) 的权限矩阵中。如果我们重新考虑 AdministratorAccess 策略,权限矩阵定义如下:
AdministratorAccess = CartesianProduct(Every Possible ARN, Every Possible Action)
此时,我们可以说 RAM 是从 AdministratorAccess 策略派生的权限矩阵的子集。很明显,如果我们想识别管理员,我们应该将其定义为具有一组结果策略 (RSOP) 权限矩阵(即 RAM 的超集)的任何委托人。RSOP 的计算方式如下,是 AWS 提供的策略评估逻辑的实现:
# These statements represent every statement that can affect the principal statements = getAllStatementsAttachedToPrincipal(principal, context) for each statementin statements: # Gather all the statements that provide permissions allowActions = getAllowPermissionMatrix() # Gather all the statements that prohibit denyActions = getDenyPermissionMatrix() conditonalAllowActions = getConditionalAllowPermissionMatrix() conditionalDenyActions = getConditionalDenyPermissionMatrix() # Resolve every conditional statement based on things we can deduce, # and use a pre-populated context for things we cannot deduce for conditionalDenyin conditionalDenyActions: denyActions += resolveCondition(conditionalDeny, principal, context) for conditionalAllowin conditionalAllowActions: allowActions += resolveCondition(conditionalAllow, principal, context) # Ensure that session policies and Service Control Policies are accounted for processSessionPolicy(principal, allowStatements, denyStatement) processSCPs(principal, allowStatements, denyStatements) return relativeComplement(allowActions, denyActions)
这为我们提供了以下管理员的伪定义:
IsAdministrator(principal, context) = (RAM) ⊆ RSOP(principal, context)
无论何时我们讨论 RSOP 的未来发展,都可以理解为这是策略的结果集,并且在生成权限矩阵时,所有 SCP、条件、权限边界和会话策略都已考虑。
按理说,如果角色是管理员,那么可以代入该角色的主体也是管理员。我们将 sts:AssumeRole 标识为“IdentityTransform”的一种类型。我们可以引入一个新术语“可传递 RSOP”,以包括我们的角色可以承担的所有角色的所有权限矩阵。例如,如果:
然后,我们可以按如下方式识别 TransitiveRSOP:
TransitiveRSOP(A, context) = RSOP(a, context) ∪ RSOP(b, context) ∪ RSOP(C, context)
这意味着,TransitiveRSOP 是每个主体在给定上下文中可以执行的所有操作的集合。因此,我们可以按如下方式定义我们的管理员:
IsAdministrator(principal, context) = (RAM) ⊆TransitiveRSOP(principal, context)
在此定义中,角色 A、B 或 C 的 RSOP 可能都不包含单独的 RAM 子集,但总的来说,它们都包含 RAM 子集。这反映了角色 A 作为 “管理员” 或任何我们关心的权限集的真实性质。
乍一看,这似乎是一组不必要的复杂规则,用于定义管理员。对我来说,这似乎是一种对大多数人来说非常直观的事情的过度学术化的练习。我个人讨厌管理员的这个定义,因为它甚至根本不实用,管理员定义实在是太严格了。
在所有这些关于权限的迂腐理论之后,人们必须问问自己
定义管理员重要吗?
我们在这里做什么?例如,如果我们不使用 ABAC,管理员可以在我们的 DynamoDB 表上调用 TagResource,这又有什么关系呢?
让我们忘记管理员。相反,如果我们确定我们关心的资源(是的,委托人就是资源)并明确说明我们为什么关心它们,那会怎样?
下面是一个示例。
假设我们有一个作为 EC2 实例运行的域控制器,它的 ARN 为:
arn:aws:ec2:us-west-2:1234567891012:instance/i-domaincontroller
因为它是一种高价值资产,并且被认为是“Tier 0/Super Duper Important”,所以我们关心谁可以访问它。根据 AWS 文档,允许在 EC2 实例上执行以下操作:
其中一些可能是良性的,有些则不是。假设我们想要识别可以在域控制器上执行所有这些操作的所有委托人。使用上面的公式很容易,我们只需将“管理员”的定义替换为我们真正关心的内容,例如“谁可以弄乱域控制器”。我们将此名称称为权限矩阵 0,并将其定义为:
PM0 = CartesianProduct(All Actions above, arn:aws:ec2:us-west-2:1234567891012:instance/i-domaincontroller)
我们现在可以识别这些主体,同上:
isPrincipalWeActuallyCareAbout(prinipal) =PM0 ⊆TransitiveRSOP(principal)
将此公式应用于 AWS 环境中的每个委托人,可以为我们提供一个包含所有委托人(包括身份转换)的列表,这些委托人具有上述所有权限,这可能会损害域控制器的完整性。
当然,这是一个非常狭隘的定义,因为该定义要求主体必须具有所有这些操作,而实际上,只有少数操作可能足以破坏域控制器。这是一个简单的解决方法,我们可以将每个操作或少数操作定义为它们自己的权限矩阵。例如,我们可以将 ec2:stopinstances 和 ec2:detachvolume 定义为它们自己的权限矩阵。这是为了说明停止实例并分离卷以便将其从账户中泄露出来的特定攻击路径。
permissionMatrix = CartesianProduct([ec2:stopinstances, ec2:detachvolume],"arn:aws:ec2:us-west-2:1234567891012:instance/i-domaincontroller") defisPrincipalWeActionCareAbout(principal): if permissionMatrix ⊆ TransitiveRSOP(principal): return true return false
我们现在有一个具体且可测试的定义,我们可以根据我们对妥协的定义,对“谁可以破坏此资源”做出非常真实的答案。资源可以是 AWS 账户 中的任何内容,包括委托人。因此,此定义同样适用于被视为“管理员”的特权主体。我们可以定义多少个集合没有限制。与以身份或基础设施为目标的传统攻击路径管理不同,我们的权限集是目标。
如果还不明显,那么所有这些都是为了在 AWS 中构建攻击路径。到目前为止,它一直基于直觉、已知已知和近似值,例如 AdministratorAccess 策略。每条路径都需要一个目的地,所有这些努力都是为了确定防御者关心的资源,以便我们能够确定通往这些路径的路径,并确保这些路径受到保护,更重要的是,这些路径是有意为之的。我这次咆哮的目的是阐明我们如何讨论 IAM 攻击路径,并引入我们在讨论 IAM 攻击路径时可以精确使用的语言。
原文始发于微信公众号(安全狗的自我修养):AWS 管理员身份危机:第 1 部分
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论