En esta serie de entradas, repasaremos algunas técnicas para realizar pentesting sobre entornos en Azure. En esta quinta entrada, vamos a ver como buscar información teniendo un acceso al entorno para luego poder elevar privilegios.
Antes de comenzar, si estás viendo este contenido por primera vez, te recomendamos ir a las partes anteriores:
- https://labitacoradelhacker.com/atacar-a-la-nube-pentesting-en-azure-parte-1-fundamentos/
- https://labitacoradelhacker.com/atacar-a-la-nube-pentesting-en-azure-parte-2-iaas-y-paas/
- https://labitacoradelhacker.com/atacar-a-la-nube-pentesting-en-azure-parte-3-azure-ad/
- https://labitacoradelhacker.com/atacar-a-la-nube-pentesting-en-azure-parte-4-ganando-acceso/
Ahora sí, comencemos:
Luego de comprometer una credencial de usuario y haber enumerado lo que sea posible de acuerdo a su rol, tenemos múltiples formas de elevar privilegios, sin embargo, es imposible cubrirlas todas en un post por lo que listaremos algunas:
- Revisar contraseñas embebidas en recursos específicos, como deployments. Los resultados de Microburst pueden proporcionarnos esta información
- Explorar Functions. Existen roles de lector con acceso al código de los function, los cuales podrían contener claves o API Key embebidas
- Buscar opciones de compromiso de MV, y posterior a ello usar Mimikatz para extraer credenciales de acceso con mayor privilegio.
- Validar los accesos de nuestro usuario comprometido. Por lo general, si un usuario tiene acceso de Global Reader, puede ser con propósitos de Auditoría o de revisión, por lo que podría tener tambien privilegios de lectura sobre Keyvault o Bases de Datos.
En este artículo veremos un vector que es probable encontrar en un entorno empresarial, sobre todo cuando existen aplicaciones.
Escalar privilegios vía Service Principals
¿Cómo se produce nuestro escenario de elevación?
Vayamos de menos a más.
En muchas organizaciones, se utilizan aplicaciones. Para que estas aplicaciones interactúen con otros servicios o recursos, necesita ser registrada, entonces se crea en Azure AD un «App Registration»:

Entendamos los valores:
- Application (client) ID, es el identificador de la app registrada, es única para todos los tenant, en caso la aplicación sea multitenant.
- Object ID, es el identificador del objeto de la aplicación, similar a un «username». Este valor es el que (junto con el secret) le permite autenticarse al tenant. Este valor solo sirve dentro del tenant donde la app se ha registrado.
- Directory (tenant) ID, es el identificador del tenant de la organización
Cuando se registra una App dentro de Azure, se crean automaticamente un Objeto de aplicación, y un Objeto Service Principal en el tenant. El objeto de aplicación es como la plantilla, mientras que el service principal es la instancia. Haciendo una analogía con el desarrollo de software, un objeto de aplicación es la clase, mientras que el service principal es un objeto.
Dentro de Azure, podemos ver al objeto de aplicación dentro del módulo App Registration en Azure AD, mientras que al service principal podemos verlo en el módulo Enterprise Application. El Enterprise application está vinculado al objeto de aplicación a través del application ID.

Ahora bien, para que la app pueda ejecutar acciones sobre otros recursos o servicios de Azure, muchas veces, los administradores les conceden roles privilegiados, ya que son necesarios a la hora de ejecutar sus tareas.
Hasta acá solo hemos hablado de la interacción que existe a nivel de una aplicación. Pero ¿quién registra una app? Una organización típica, con roles diferenciados, es probable que tenga un responsable encargado de crear/registrar aplicaciones, y para ello, se le brinda el rol privilegiado «Application administrator». En nuestro escenario, tenemos la siguiente configuración:
Kim Bauer: Usuario con el rol de Application Administrator, sin embargo, no puede hacer ni ejecutar ninguna otra acción sobre ningún recurso en Azure. Esta es nuestra cuenta comprometida.
App Registration: Aplicación con permisos privilegiados dentro del tenant.
Veamos un diagrama para entender el escenario de escalamiento:

Entonces, supongamos luego de haber comprometido la cuenta inicial con acceso de lector (ver parte 4 de esta serie de entradas), nos hacemos con la cuenta de Kim Bauer, la cual tiene permisos de administrador de aplicaciones:

Cambiamos el inicio de sesión, para pasar del usuario prueba (lector) al usuario Kim Bauer, la cual nos servirá para escalar:

Ahora, si enumeramos información con cualquier herramienta, ya sea PowerZure o Microburst, nos daremos cuenta que no tenemos acceso a los recursos, a pesar de que tiene como rol «Application Administrator»

Podríamos pensar que con el rol de tipo lector, teníamos al menos acceso parcial a la información interna y ahora no, por lo que parece que ahora estamos en desventaja, sin embargo, nuestro rol lector no tiene privilegios para crear nada dentro del tenant, por lo que el escenario no nos permitiría ejecutar acciones sobre las que se pueden necesitar mayores privilegios como: crear máquinas virtuales, agregar usuarios, leer llaves de bóveda, acceder a bases de datos, descargar imágenes de discos, etc.
Por ello, para nuestro vector de ataque, nos servirá tener al usuario con rol de administrador de aplicaciones.
Una vez dentro, validamos los identificadores de la aplicación:

Ahora, veamos qué objetos tienen privilegios de Global Admin:
Get-AzureADDirectoryRole | ?{$_.DisplayName -eq 'Global Administrator'} | select DisplayName,ObjectID,RoleTemplateID
Get-AzureADDirectoryRoleMember -ObjectID [ObjectId] | Select ObjectId,DisplayName

Como vemos, la aplicación tiene privilegios de Global Admin. Pero, ¿cómo pasamos del usuario Kim Bauer a la cuenta de servicio para escalar privilegios?
Para ello generaremos una nueva contraseña para nuestra aplicación, y luego, desde Az Powershell iniciaremos sesión con las credenciales creadas:
$AppKeyCred = New-AzureADApplicationPasswordCredential -ObjectId '[ObjectID de la aplicación]'
$AppKeyCred.value


Para iniciar sesión, ejecutamos el siguiente código:
$azureApplicationID = "[AppID]"
$azureTenantID = "[Tenant ID]"
$azurePassword = ConvertTo-SecureString $AppKeyCred.Value -AsPlainText -Force
$psCred = New-Object System.Management.Automation.PSCredential($azureApplicationID, $AzurePassword)
Connect-AzAccount -Credential $psCred -TenantId $azureTenantId -ServicePrincipal
$context=[Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile.DefaultContext
$aadToken = [Microsoft.Azure.Commands.Common.Authentication.AzureSession]::Instance.AuthenticationFactory.Authenticate($context.Account,$context.Environment,$context.Tenant.Id.ToString(),$null,[Microsoft.Azure.Commands.Common.Authentication.ShowDialog]::Never,$null,"https://graph.windows.net").AccessToken
Connect-AzureAD -AadAccessToken $aadToken -AccountId $context.Account.Id -TenantId $context.tenant.id

Hemos conseguido acceder con un privilegio mayor, ahora, podemos nuevamente descargar toda la información (con mucho mayor acceso que un Global Reader):


Sin embargo, podemos hacer Global Admin a otro usuario, como Kim Bauer por ejemplo, y con ello ganar acceso total al entorno de Azure, o quizá crear una MV para tener un recurso dentro de la plataforma. Las posibilidades son infinitas. Recuerda: El cielo es el límite.
Con esto finalizamos nuestra serie de entradas sobre pentesting en Azure. Esperamos que te haya sido de utilidad.