Exfiltration de données Azure Storage : SAS et logs blob
Enquêter sur une exfiltration Azure Storage : listAccountSas et listKeys dans l'Activity Log, rafales de GetBlob, hash des jetons SAS, ce qu'il faut renouveler.
En bref. L'exfiltration depuis un compte de stockage laisse deux types de traces. Dans l'Activity Log : listKeys/action, listAccountSas/action, listServiceSas/action, et les changements de configuration qui ouvrent le compte (allowBlobPublicAccess: true, pare-feu en defaultAction: Allow). Dans les logs de ressources Storage (StorageRead / StorageBlobLogs, uniquement s'ils sont activés) : des requêtes GetBlob avec l'IP de l'appelant, le type d'authentification, un hash du SAS ou du jeton, la clé de l'objet et les octets renvoyés. Un SAS signé côté client avec une clé de compte n'est jamais journalisé à sa création ; on ne le voit que lorsqu'il est utilisé. Renouveler les deux clés du compte révoque les SAS de compte et de service.
Le compte de stockage, c'est là que sont les données. Après une compromission cloud, la question est presque toujours « qu'ont-ils pris ? », et pour le stockage blob on peut y répondre, à condition que le bon paramètre de diagnostic ait existé.
Comment les attaquants atteignent les données
| Chemin | Trace plan de contrôle (Activity Log) | Trace plan de données (log Storage) |
|---|---|---|
| Lire les clés du compte et signer leur propre SAS hors ligne | Microsoft.Storage/storageAccounts/listKeys/action | GetBlob avec authentification SAS ou AccountKey |
| Demander à Azure Resource Manager de générer un SAS de compte ou de service | listAccountSas/action / listServiceSas/action | GetBlob avec authentification SAS, statusText SASSuccess |
| Utiliser une identité Entra dotée d'un rôle de données (Storage Blob Data Reader…) | Éventuellement un roleAssignments/write avant | GetBlob avec OAuth, object ID du demandeur |
| Rendre un conteneur public | storageAccounts/write ou containers/write avec accès public | GetBlob en Anonymous |
| Ouvrir le pare-feu du stockage | storageAccounts/write avec defaultAction: Allow ou accès réseau public activé | Requêtes depuis des IP bloquées auparavant |
MITRE ATT&CK suit la collecte sous T1530 Data from Cloud Storage. Storm-0501, tel que documenté par Microsoft Threat Intelligence, a utilisé listkeys/action et exfiltré avec AzCopy avant de supprimer massivement des comptes de stockage.
Le problème des SAS : la création est invisible
Une signature d'accès partagé (SAS) est une URL signée. La documentation Microsoft est sans ambiguïté : il n'est pas possible d'auditer la génération de jetons SAS, et un jeton SAS n'est suivi d'aucune manière par Azure Storage (vue d'ensemble des SAS). Un SAS signé localement avec une clé de compte ne produit aucun événement. Ce que l'on peut voir :
listKeys/action: quelqu'un a récupéré les clés (et pouvait signer une infinité de SAS hors ligne).listAccountSas/action/listServiceSas/action: quelqu'un a demandé à ARM d'en signer un. Le corps de la requête indique les services, permissions, début et expiration demandés.- Chaque utilisation d'un SAS, dans les logs de ressources Storage, s'ils sont activés.
La recommandation de Microsoft d'interdire l'autorisation par clé partagée (Shared Key) sur les comptes qui n'en ont pas besoin supprime toute la catégorie : sans Shared Key, les SAS de compte et de service cessent de fonctionner.
Lire StorageBlobLogs
La référence de supervision de Blob Storage documente les champs. Ceux qui comptent pour l'exfiltration :
| Champ (export de stockage) | Exemple | Pourquoi |
|---|---|---|
operationName | GetBlob, ListBlobs, PutBlob, DeleteBlob | Ce qui s'est passé |
callerIpAddress | 203.0.113.66:51234 | D'où (notez le port en suffixe) |
identity.type | SAS, AccountKey, OAuth, Anonymous | Comment la requête a été autorisée |
identity.tokenHash | key1(…),SasSignature(…) | Quelle clé a signé le SAS, et un SHA-256 du SAS lui-même |
identity.requester.objectId | GUID | L'identité Entra, en OAuth |
properties.objectKey | /account/container/blob | Quel blob |
properties.responseBodySize | octets | Quelle quantité est sortie |
properties.userAgentHeader | AzCopy/10.x … | Quel outil |
statusCode / statusText | 200 / SASSuccess | Succès ou échec |
Le hash SasSignature(…) est votre pivot : toutes les requêtes portant le même hash ont utilisé le même jeton SAS, quel qu'en soit le détenteur. L'analyseur l'utilise comme principal pour les accès SAS (affiché sas:<début du hash>), si bien qu'un SAS fuité apparaît comme une seule entité avec ses IP et son total d'octets.
Les logs Storage sont volumineux. L'analyseur écarte les lectures de routine du tableau des événements, mais les compte et les évalue toutes.
Ce que signale l'analyseur
| Règle | Détecte | Niveau |
|---|---|---|
AZ-ST-001 | SAS de compte ou de service généré via ARM (listAccountSas, listServiceSas) | Haut |
AZ-ST-002 | Clés du compte listées ou régénérées | Faible |
AZ-ST-003 | Accès anonyme aux blobs activé sur le compte ou un conteneur | Haut |
AZ-ST-004 | Pare-feu du stockage ouvert à tous les réseaux | Moyen |
AZ-ST-005 | Téléchargement en masse : au moins 50 blobs distincts lus par la même identité depuis la même IP en 60 minutes, avec le total d'octets | Haut |
AZ-ST-006 | Lectures anonymes de blobs | Moyen |
AZ-VM-005 | Disque ou snapshot exporté via une URL SAS | Haut |
AZ-ST-002 est volontairement faible : le navigateur de stockage du portail, les Function Apps et les outils de sauvegarde listent les clés en permanence. Il devient intéressant à côté d'autres constats.
Mesurer l'exposition
Le travail de notification de violation exige des faits, pas « l'attaquant avait accès au compte ». Construisez-les à partir des logs :
- Listez les blobs lus par le principal / hash de SAS / IP suspect : clés d'objet, tailles, horodatages. L'analyseur Azure Forensics les regroupe par identité, IP et compte, avec le total d'octets.
- Distinguez lectures et listages.
ListBlobsrévèle des noms ;GetBlobrévèle le contenu. - Vérifiez les lectures partielles. Un champ
downloadRangesignifie que seule une partie du blob a été transférée. - Vérifiez écritures et suppressions (
StorageWrite,StorageDelete) : les acteurs de type rançongiciel suppriment après avoir copié. - Vérifiez les autres services. Les logs blob ne couvrent ni Files, ni Queues, ni Tables ; chacun a ses propres catégories de logs.
Par exemple, dans l'exemple fictif du site, un SAS utilisé depuis une IP lit 330 blobs de sauvegarde distincts en 18 minutes, environ 48,6 Go au total. C'est ce chiffre, par conteneur, dont les équipes juridiques ont besoin.
Remédiation
- Renouvelez les deux clés du compte de stockage. Microsoft documente que les SAS de compte et de service sont signés avec la clé du compte : la régénérer les invalide. Les SAS de délégation d'utilisateur se révoquent en révoquant les clés de délégation d'utilisateur.
- Désactivez l'accès anonyme et rétablissez le pare-feu (action par défaut Deny, points de terminaison privés).
- Envisagez d'interdire l'autorisation Shared Key.
- Activez dès maintenant
StorageRead/StorageWrite/StorageDeletesur le service blob des comptes sensibles. - Établissez quelles données ont été lues, pour les obligations de notification (par exemple la notification à l'autorité de contrôle sous 72 heures du RGPD, article 33).