Vous avez besoin du Cloud Computing ? Commencez dès maintenant

Interfaces RPC exceptionnelles et comment les trouver

Oryan De Paz

écrit par

Oryan De Paz

February 22, 2023

Oryan De Paz

écrit par

Oryan De Paz

Oryan De Paz is a Security Researcher in the Akamai Technologies Enterprise Security Group. In her daily job, she is doing multiple types of research, from vulnerability research to malware and internal mechanisms of the operating system. She is passionate about the Windows operating system internals, reverse engineering, and solving puzzles, which makes working in security research her dream job. In her free time, she likes to bake, travel, and spend time with her dog, Alice; and she is always up for learning new things.

Nous espérons que la poursuite de nos recherches et les outils de notre répertoire permettront de mieux comprendre ce vecteur et inciteront d'autres chercheurs à s'y intéresser également.

Contributions éditoriales et additionnelles de Tricia Howard

Introduction 

Au cours des derniers mois, notre équipe a consacré beaucoup d'efforts à la recherche sur MS-RPC en raison de sa complexité et de sa nature peu étudiée. Vous avez peut-être vu la myriade d'articles sur les vulnérabilités que nous avons découvertes grâce à ce travail, comme srvsvc et Wininit.exepar exemple. Compte tenu de la quantité de données et d'outils que nous avons accumulés tout au long de cette recherche, il était logique de les rassembler en un seul endroit : notre boîte à outils RPC

Ce référentiel open source contient tout ce dont vous avez besoin pour commencer ou poursuivre votre parcours dans le domaine du RPC : outils, articles, billets de blog, conférences, informations sur les vulnérabilités du RPC et démonstrations de faisabilité. Ce référentiel a été créé dans le but de rendre les connaissances en matière de RPC plus accessibles aux défenseurs et aux chercheurs. Après tout, nous sommes tous plus en sécurité lorsque nous travaillons ensemble. À tous ceux qui ont lu nos articles, utilisé un outil ou partagé une partie de notre travail : Merci ! Nous sommes heureux que vous en tiriez profit. 

L'un des outils de la boîte à outils est notre RPC Interface Analyzer, qui aide les professionnels de la sécurité comme vous à identifier rapidement et facilement les pistes vers des interfaces potentiellement vulnérables. Ce billet de blog a pour but de vous présenter l'objectif et les résultats de cet outil, et de donner un aperçu du RPC et de certains de ses mécanismes de sécurité à ceux qui ne les connaissent pas encore. 

Qu'est-ce qu'un RPC et quels en sont les mécanismes de sécurité ?

L'appel de procédure à distance (RPC) est une forme de communication entre processus (IPC) qui permet à un client d'invoquer une procédure exposée par un serveur RPC. Le client appelle la fonction de la même façon que s'il s'agissait d'un appel de procédure normal. Pour une interaction à distance, il n'a (presque) pas besoin de coder les détails. Le serveur peut être hébergé sur une machine distante ou bien sur la même machine, mais dans un processus différent.

MS-RPC, la version Microsoft du RPC, est largement utilisé par Windows pour de nombreux services différents, tels que la planification de tâches, la création de service, les paramètres d'impression et de partage, ainsi que la gestion des données chiffrées conservées à distance. Ce large éventail d'utilisations et la nature à distance du RPC en tant que vecteur sont précisément les raisons pour lesquelles nous discutons de ce sujet aujourd'hui et avons affecté tant de ressources à la recherche sur le RPC. Il intègre beaucoup de fonctionnalités et, par conséquent, suscite beaucoup d'attention du point de vue de la sécurité.

Dans les sections suivantes, nous allons aborder les rappels de sécurité RPC et la manière dont vous pouvez utiliser l'automatisation pour les analyser et potentiellement générer de nouvelles pistes pour la recherche sur la sécurité et les vulnérabilités. 

Qu'est-ce qu'un rappel de sécurité RPC et comment cela fonctionne-t-il ?

En bref, le rappel de sécurité est l'une des nombreuses façons de sécuriser une interface RPC. Il s'agit d'un rappel personnalisé mis en œuvre par le développeur du serveur RPC. Sa logique est laissée à l'appréciation du développeur, qui peut ainsi appliquer le contrôle d'accès basé sur l'utilisateur, l'authentification, les types de transport, ou empêcher l'accès à des fonctions spécifiques exposées par le serveur. 

Finalement, le rappel renvoie RPC_S_OK pour autoriser la communication du client avec le serveur, ou l'un des codes d'erreur RPC, tels que RPC_S_ACCESS_DENIED, pour la refuser.

La décision d'accepter ou de rejeter la demande d'un client repose généralement sur un attribut (ou plusieurs) que nous allons étudier ci-dessous.

Séquence de protocole

Le client peut communiquer avec le serveur via plusieurs transports : TCP, canaux nommés, ALPC, etc. Le rappel de sécurité peut vérifier cet attribut pour filtrer uniquement les demandes de connexion locale, uniquement les demandes à distance, la communication TCP, etc. 

Bien que les valeurs des séquences de protocole ne soient pas documentées, nous avons mis en correspondance les séquences de protocole qui sont transmises au rappel de sécurité dans la structure RpcCallAttributes avec les valeurs suivantes :

#define ncacn_ip_tcp 1
#define ncacn_np 2
#define ncalrpc 3
#define ncacn_http 4

D'autres séquences de protocole (telles que ncacn_hvsocket) peuvent être testées par le rappel de sécurité par le biais d'une analyse syntaxique de la liaison de chaînes.

Niveau d'authentification

La vérification du niveau d'authentification du client est assez courante dans les rappels de sécurité. De cette façon, le serveur peut définir le niveau d'authentification minimal qu'il attend de ses clients.

Il existe plusieurs niveaux d'authentification, chacun prolongeant le niveau précédent :

#define RPC_C_AUTHN_LEVEL_DEFAULT 0
#define RPC_C_AUTHN_LEVEL_NONE 1
#define RPC_C_AUTHN_LEVEL_CONNECT 2
#define RPC_C_AUTHN_LEVEL_CALL 3
#define RPC_C_AUTHN_LEVEL_PKT  4
#define RPC_C_AUTHN_LEVEL_PKT_INTEGRITY 5
#define RPC_C_AUTHN_LEVEL_PKT_PRIVACY 6

Par exemple, un serveur peut définir un niveau d'authentification RPC_C_AUTHN_LEVEL_PKT_PRIVACY pour s'assurer que les données de communication ne sont visibles que par le client et le serveur, ou bien définir le niveau d'authentification RPC_C_AUTHN_LEVEL_NONE pour indiquer l'absence d'authentification.

Service d'authentification

Le service d'authentification spécifie le service qui est chargé de valider la règle d'authentification fournie par le niveau d'authentification. 

Les valeurs des constantes du service d'authentification sont les suivantes :

#define RPC_C_AUTHN_NONE  0
#define RPC_C_AUTHN_DCE_PRIVATE  1
#define RPC_C_AUTHN_DCE_PUBLIC  2
#define RPC_C_AUTHN_DEC_PUBLIC  4
#define RPC_C_AUTHN_GSS_NEGOTIATE  9
#define RPC_C_AUTHN_WINNT  10
#define RPC_C_AUTHN_GSS_SCHANNEL  14
#define RPC_C_AUTHN_GSS_KERBEROS  16
#define RPC_C_AUTHN_DPA  17
#define RPC_C_AUTHN_MSN  18
#define RPC_C_AUTHN_DIGEST  21
#define RPC_C_AUTHN_NEGO_EXTENDER  30
#define RPC_C_NETLOGON   68 (non documenté)
#define RPC_C_AUTHN_MQ   100
#define RPC_C_AUTHN_DEFAULT  0xffffffff

RPC_C_AUTHN_NONE, par exemple, désactive l'authentification tandis que RPC_C_AUTHN_WINNT utilise le protocole NTLM.

La liste complète des services d'authentification et de leurs valeurs est disponible sur cette page GitHub

Session NULL

Une session NULL est une connexion anonyme. Dans ce cas, le client communique avec le serveur sans authentification, c'est-à-dire sans nom d'utilisateur ni mot de passe. 

Dans la plupart des cas, si un rappel de sécurité est enregistré, les sessions NULL sont bloquées par défaut, à moins que l'indicateur RPC_IF_ALLOW_CALLBACKS_WITH_NO_AUTH ne soit fourni lors de l'enregistrement du serveur (voir les autres cas ici). Les rappels de sécurité peuvent également vérifier la présence de sessions NULL. 

En bloquant l'accès à ces sessions, le rappel de sécurité protège l'interface RPC des utilisateurs non authentifiés. 

Numéro d'opération (opnum)

L'opnum représente la fonction d'interface que le client demande à exécuter. Plus précisément, l'opnum est l'index dans la table des fonctions du serveur RPC.

En vérifiant la valeur de l'opnum, le serveur peut limiter ou bloquer l'accès du client à des fonctions spécifiques, telles que les fonctions qui traitent des données sensibles pour les clients à distance, les fonctions qui accèdent à la mémoire du noyau et/ou aux fonctionnalités pour les clients en mode utilisateur, etc.

L'équipe Recherche sur la sécurité d'Akamai a publié un billet de blog présentant un exemple de rappel de sécurité intéressant qui s'appuie sur cette vérification. 

D'autres contrôles de rappel de sécurité peuvent être les suivants :

  • Origine de l'appelant — pour vérifier si l'appelant provient du mode utilisateur ou du mode noyau

  • PID du client — pour permettre uniquement des processus spécifiques

  • Liaison de chaînes — pour valider les attributs de connexion RPC tels que la séquence de protocole, l'adresse réseau, les informations du point de terminaison, etc.

  • Usurpation d'identité — pour vous assurer que le serveur peut exécuter le code dans le contexte de sécurité du client

Il existe également des vérifications complexes. Par exemple, dans le rappel LsaCapRpcIfCallbackFn sur lsasrv.dll, si le service d'authentification est netlogon, le niveau d'authentification doit être inférieur à RPC_C_AUTHN_LEVEL_PKT_INTEGRITY.

RPC Interface Analyzer : un guide pratique

RPC Interface Analyzer est un outil d'automatisation pour la recherche d'interfaces RPC. Il permet aux chercheurs de trouver et d'analyser des interfaces RPC à partir de deux sources différentes, soit des fichiers de définition d'interface (IDL), soit des fichiers PE.

Fichiers IDL

Les fichiers IDL sont les fichiers qui définissent une interface RPC et ses fonctions. En analysant les fichiers IDL accessibles au public, nous pouvons obtenir des informations sur une interface RPC et les fonctions que son serveur expose, ainsi que leurs paramètres et leurs types de valeurs de retour. Avec ces informations, un chercheur peut rechercher des fonctions potentiellement vulnérables ; par exemple, les fonctions qui reçoivent un argument de chemin, comme dans le cas de PetitPotam

Afin d'exécuter notre analyseur IDL, lancez les commandes suivantes :

1. Téléchargez tous les fichiers IDL du site Web de Microsoft sur votre terminal à l'aide du script idl_scraper :

idl_scraper.py [-h] [-o OUTPUT] [-p PROTOCOL]

2. Exécutez ensuite idl_parser pour analyser les fichiers IDL suivants :

idl_parser.py [-h] [-r] input_path [output_path]

Le résultat que vous obtiendrez en retour est un fichier CSV contenant les noms des interfaces RPC, les identifiants universels uniques (UUID), les noms des fonctions exposées et les signatures.

Fichiers PE

L'analyse des fichiers IDL peut être utile, mais nous risquons de manquer certaines interfaces RPC puisque nous n'avons accès qu'aux fichiers IDL accessibles au public. Une autre approche consiste à rechercher les interfaces RPC sur notre système de fichiers local, dans les fichiers PE (fichiers .exe ou .dll). Nous trouvons cette approche préférable à la vérification des processus en direct, car de cette façon nous ne pouvons pas manquer les serveurs RPC qui ne sont pas en activité ou qui sont exécutés dans des processus protégés.

Le RPC PE Analyzer recherchera les interfaces RPC enregistrées par la fonction RpcServerRegisterIf (et ses variantes) et analysera les arguments qui lui sont transmis, au cas où un désassembleur serait fourni. Lorsqu'il est exécuté sans celui-ci, dans le mode par défaut, l'analyseur trouvera les interfaces RPC en utilisant une expression régulière. Cette présentation détaille le processus de recherche.  

Afin d'utiliser RPC PE Analyzer dans son mode par défaut, exécutez la commande suivante :

pe_rpc_scraper.py <scrape_path> <output_path>

Cette commande vous donnera le résultat de base qui inclut l'UUID de l'interface, son rôle (client/serveur), et les noms et adresses de ses fonctions.

Si vous voulez des informations plus détaillées, vous pouvez fournir un désassembleur et son chemin (s'il ne s'agit pas de celui par défaut) au script :

pe_rpc_scraper.py [-d {idapro,radare}] [-P DISASSEMBLER_PATH] <scrape_path> <output_path>

L'utilisation de l'option désassembleur ajoutera également les informations d'enregistrement de l'interface, notamment :

  • Les indicateurs fournis dans l'enregistrement du serveur

  • Le nom et l'adresse de rappel de sécurité de l'interface

  • Le descripteur de sécurité du serveur RPC (s'il en a un)

  • Si la mise en cache globale est activée pour le rappel de sécurité

Notre dernière fonctionnalité, publiée parallèlement à ce billet de blog, fournit également une analyse du rappel de sécurité lui-même. 

Exemple d'utilisation

Disons que nous voulons analyser toutes les interfaces RPC disponibles sur notre terminal. Nous pouvons exécuter RPC PE Analyzer, fournir une copie de C:\Windows\System32 en tant que chemin_scrape et observer le résultat. 

pe_rpc_scraper.py -d idapro “C:\Users\User\Documents\System32_Copy”

La sortie étant au format JSON, il est facile de l'itérer et de rechercher des informations spécifiques. Par exemple :

  • Recherche de tous les clients/serveurs RPC dans un fichier DLL

  • Recherche de tous les clients/serveurs RPC sur une machine

  • Recherche des clients d'une interface RPC spécifique

  • Recherche du rappel de sécurité RPC d'un certain serveur RPC

  • Recherche des interfaces RPC qui utilisent la mise en cache au niveau de l'interface (lire ce billet de blog pour plus d'informations sur les raisons pour lesquelles ce type de mise en cache est problématique)

Ce ne sont là que quelques-unes des nombreuses utilisations de cette sortie. Nous serions ravis de découvrir d'autres applications et idées.

Nouvelle fonctionnalité : informations sur les rappels de sécurité

Structure RpcCallAttributes 

RPC_CALL_ATTRIBUTES est une structure qui contient des données concernant la demande du client. Le rappel de sécurité de l'interface côté serveur peut obtenir ces informations en invoquant la fonction RpcServerInqCallAttributes

typedef struct tagRPC_CALL_ATTRIBUTES_V3_W

{
    unsigned int Version;
    unsigned long Flags;
    unsigned long ServerPrincipalNameBufferLength;
    unsigned short *ServerPrincipalName;
    unsigned long ClientPrincipalNameBufferLength;
    unsigned short *ClientPrincipalName;
    unsigned long AuthenticationLevel;
    unsigned long AuthenticationService;
    BOOL NullSession;
    BOOL KernelModeCaller;
    unsigned long ProtocolSequence;
    RpcCallClientLocality IsClientLocal;
    HANDLE ClientPID; 
    unsigned long CallStatus;
    RpcCallType CallType;
    RPC_CALL_LOCAL_ADDRESS_V1 *CallLocalAddress;
    unsigned short OpNum;
    UUID InterfaceUuid;
    unsigned long          ClientIdentifierBufferLength;
    unsigned char          *ClientIdentifier;
} RPC_CALL_ATTRIBUTES_V3_W;

Nous avons déjà mentionné les tests que les rappels de sécurité exécutent. Ils peuvent interroger certaines de ces valeurs individuellement (par exemple, RpcStringBindingParseW pour recevoir la séquence de protocole, RpcBindingInqAuthClient pour les informations d'authentification, etc.), ou utiliser cette structure qui contient tout et ne requiert qu'un seul appel de fonction. En effet, dans la plupart des rappels de sécurité que nous avons analysés, ils appellent RpcServerInqCallAttributes et utilisent la structure RPC_CALL_ATTRIBUTES pour interroger simultanément tous les attributs. Cela rend cette structure très intéressante si vous voulez comprendre la logique du rappel de sécurité.

La structure possède actuellement trois versions différentes : 1, 2 et 3, et chacune est une extension de sa version précédente et possède des versions ANSI et Unicode. Vous pouvez trouver les différentes versions et leurs membres sur cette page GitHub

Informations sur les rappels de sécurité

Le nouvel ajout à notre boîte à outils RPC correspond aux informations sur les rappels de sécurité, qui font partie du RPC PE Analyzer. Elles donnent un aperçu des contrôles et des vérifications que le rappel de sécurité effectue avant d'approuver ou de refuser les demandes des clients. 

L'analyse de la fonction de rappel de sécurité d'une interface RPC, et plus particulièrement de son accès à la structure RPC_CALL_ATTRIBUTES, peut permettre de mieux comprendre l'interface. De cette façon, vous pouvez rechercher des rappels de sécurité qui vérifient l'attribut du service d'authentification si vous voulez filtrer les interfaces RPC qui utilisent (ou n'utilisent pas) un protocole d'authentification spécifique. Vous pouvez également interroger les interfaces RPC qui ne vérifient pas la présence de sessions NULL avant d'autoriser les demandes des clients et dont les indicateurs d'enregistrement du serveur autorisent les sessions NULL, afin de découvrir des interfaces RPC potentiellement vulnérables.

Comment cela fonctionne-t-il ?

Pour chaque rappel de sécurité, l'analyseur va :

  • Trouver la version de la structure RPC_CALL_ATTRIBUTES utilisée et définir la structure correspondante dans les types IDA locaux

  • Localiser la variable locale RpcCallAttribute et appliquer la structure RPC_CALL_ATTRIBUTES comme type

  • Analyser les contrôles que le rappel de sécurité effectue en utilisant cette structure et indiquer quel membre est testé, la valeur à laquelle il est comparé et avec quel opérateur (== / != / > / < / etc.).

Comment puis-je l'utiliser ?

L'utilisation n'a pas changé : Chaque fois que vous exécutez RPC PE Analyzer avec l'indicateur de désassemblage IDA, la sortie pour chaque interface RPC inclura maintenant ses informations de rappel de sécurité, si elle accède aux membres de la structure RpcCallAttributes et à ce qu'elle teste.

  • Remarque : cet ajout est actuellement disponible uniquement pour IDA, et l'exécution de l'analyseur avec l'option Radare n'inclura pas les informations de rappel de sécurité.

Une fois que vous avez le résultat, vous pouvez l'utiliser pour trouver des interfaces RPC éventuellement vulnérables et les filtrer en fonction de vos besoins. Voici quelques exemples :

  • Obtenir une interface RPC qui utilise uniquement le niveau d'authentification RPC_C_AUTHN_LEVEL_PKT_PRIVACY

  • Obtenir les interfaces RPC qui attendent des connexions locales

  • Obtenez les interfaces RPC qui n'attendent que des appelants en mode noyau

  • Obtenir des interfaces RPC qui vérifient l'opnum, comme dans le cas de la vulnérabilité de la mise en cache

Résumé

Il est devenu évident que le RPC est un terrain propice à la recherche, surtout si l'on considère à quel point il est ancien et intégré dans tant de processus critiques. Nous avons mis en commun les ressources de notre référentiel depuis près d'un an maintenant, et il reste encore beaucoup à faire pour réaliser pleinement le potentiel de menace du RPC. Il est encore largement sous-étudié et, bien qu'il ait suscité davantage d'attention récemment, il reste encore beaucoup à découvrir sur les innombrables façons dont les attaquants peuvent en abuser. 

La nature intrinsèque du CPR justifie la recherche de tous les angles potentiellement dangereux. Nous espérons que la poursuite de nos recherches et les outils de notre répertoire permettront de mieux comprendre ce vecteur et inciteront d'autres chercheurs à s'y intéresser également. Que vous soyez un défenseur chargé de sécuriser les RPC ou un chercheur souhaitant identifier sa prochaine cible, les RPC recèlent un grand potentiel de connaissances et d'informations. 

Vous êtes prêt à commencer ? Consultez le référentiel, et dites-nous sur Twitter ce que vous avez découvert ! 



Oryan De Paz

écrit par

Oryan De Paz

February 22, 2023

Oryan De Paz

écrit par

Oryan De Paz

Oryan De Paz is a Security Researcher in the Akamai Technologies Enterprise Security Group. In her daily job, she is doing multiple types of research, from vulnerability research to malware and internal mechanisms of the operating system. She is passionate about the Windows operating system internals, reverse engineering, and solving puzzles, which makes working in security research her dream job. In her free time, she likes to bake, travel, and spend time with her dog, Alice; and she is always up for learning new things.