
Exploit distant du système de fichiers réseau Windows pour CVE-2022-30136
auteur : Ricardo Narvaja
À des fins de démonstration uniquement. L'exploit complet fonctionne sur les systèmes Windows Server vulnérables.
Consultez l'article détaillé Analyse de CVE-2022-30136 « Vulnérabilité du système de fichiers réseau Windows ».
J'ai voulu rédiger cet article pour démontrer l'analyse que j'ai effectuée lors du développement de l'exploit Core Impact « Windows Network File System Remote » qui exploite la vulnérabilité CVE-2022-30136.
La vulnérabilité d'exécution de code à distance dans le système de fichiers réseau Windows est une erreur de calcul de taille qui se produit lors de la création de la réponse du serveur dans une REQUÊTE COMPOSÉE utilisant la version 4.1 de NFS.
Le serveur calcule une taille plus petite que nécessaire pour allouer le pool, puis, lors de la copie des données pour générer la réponse, provoque un débordement du tampon.
La fonction Nfs4SvrXdrpGetEncodeOperationResultByteCount dans nfssvr.sys est appelée pour chaque opération et renvoie une taille plus petite que nécessaire (4 octets de moins pour chaque opération).
Un correctif a été appliqué pour Nfs4SvrXdrpGetEncodeOperationResultByteCount.
Cette fonction est appelée lors de chaque OPÉRATION d'une REQUÊTE COMPOSÉE afin de renvoyer les octets nécessaires pour chacune d'elles en fonction de l'OPCODE. Elle est ensuite ajoutée à l'en-tête et aux autres parties de la réponse. Ensuite, elle calcule la taille finale de l'ensemble de la réponse à allouer, puis copie dessus pour répondre.
Dans chaque cas, nous pouvons voir que la valeur de la taille renvoyée pour chaque opération est de quatre octets inférieure dans la version vulnérable par rapport à la version corrigée.
J'ai construit le POC pour Windows Server 2019.
Ci-dessous se trouve la version vulnérable de nfssvr.sys utilisée pour ce POC, suivie de la version corrigée pour Windows Server 2019 :

L'image suivante montre le CAS 26 dans la différence :

Dans l'exemple du CAS 26, nous pouvons voir que la constante ajoutée à la valeur calculée est 0x2c dans la version vulnérable, et 0x30 dans la version corrigée.
On observe la même chose dans chaque cas correspondant à chaque OPCODE. La version vulnérable renvoie toujours une taille de quatre octets inférieure à celle de la version corrigée.
Nous n'allons pas montrer tous les cas car le correctif est similaire pour tous les OPCODES.
Le parent de Nfs4SvrXdrpGetEncodeOperationResultByteCount est Nfs4SvrXdrEncodeCompoundResults. Il lit le nombre d'opérations envoyées dans la REQUÊTE COMPOSÉE.
Dans ce POC, la valeur est 0x34 (52d). Lorsque mon POC se connecte au serveur sur le port 2049 (le port par défaut pour NFS), je dois placer un point d'arrêt conditionnel pour un arrêt.


Dans cet exemple, il s'arrête lorsque number_of_operations=0x34.

Le pool avec le tag ARGS est alloué ici.

Je vais ensuite créer une structure nommée TAG_ARGS_0x10e0 pour inverser les champs.

Il copie number_of_operations dans r13 et boucle dans la fonction vulnérable une fois par opération, jusqu'à ce que le compteur atteigne la valeur de r13.

Cela montre que le premier package_OPCODE = 0x35, qui correspond à SEQUENCE dans la première opération obligatoire d'une REQUÊTE COMPOSÉE. Dans l'image ci-dessous, la flèche pointe vers cet OPCODE dans mon paquet.

Ici, nous pouvons voir les arguments de la fonction vulnérable.


À l'intérieur de la fonction vulnérable, elle lit l'OPCODE et se rend au CAS correspondant.

Trois est soustrait de la valeur d'OPCODE d'origine (53).

Et saute au CAS 50, renvoyant 0x28 comme taille nécessaire pour cette opération.


Nous pouvons voir dans la différence comment la version corrigée renvoie 0x2c.

Cette valeur renvoyée est ajoutée à la valeur précédente des autres champs de la réponse afin de calculer la taille des opérations. Dans ce cas, cette valeur est 0x40c.

Ci-dessous, nous pouvons voir les valeurs en cours d'ajout :

Lorsqu'elle sort de la boucle, la taille totale est calculée. Dans ce cas, la taille totale est 0x1310.

Nous pouvons deviner la différence entre la version vulnérable et la version corrigée en calculant la taille, à l'aide de la formule : number_of_operations * 4.
Dans ce cas, l'allocation dans la version corrigée sera de 0x34 * 4 = 0x68 plus grande que dans la version vulnérable.

Après cela, elle ajoute 0x24. Cette valeur est calculée de manière similaire dans les deux versions, vulnérable et corrigée.

Elle ajoute ensuite la constante 0xf dans les deux cas.
