Un bref rappel:
Les failles que je décris se situent dans le driver SVGA de VMWare (patché depuis plusieurs mois). Nous pouvons interagir avec ce driver en écrivant des commandes dans la mémoire FIFO. (Si vous n’avez pas suivi allez voir le post précédent).
En fonction du fichier de configuration de votre VM et de la version de VMWare vous aurez accès ou non à certaines commandes. Je ne traiterai pas toutes les commandes. Pour jouer avec les requêtes 3D il vous faut ajouter à votre fichier de configuration: mks.enable3d = “TRUE”
Les requêtes 3D ne sont pas documentées et la mémoire FIFO est utilisée comme couche de transport pour l’architecture SVGA3D utilisé par D3D. Je ne m’y suis pas frotté. On fera juste le tour des commandes RECT_COPY
et DRAW_GLYPH
, qui appartiennent aux requêtes 2D.
I] Lecture mémoire relative.
Pour pouvoir lire la mémoire de l’host on peut utiliser la commande RECT_COPY
:
Source X
prend comme paramètre des coordonnées en pixel. C’est-à-dire que si SourceX
vaut 1 la copie s’effectuera avec un décalage de 4 bytes par rapport au début du frame buffer. Avec 0×80000000-offset
, on obtient donc un offset négatif. Pour que la commande RECT_COPY
soit exécutée, il faut que deux conditions soit remplies: SourceX>0
et SourceX+Width<0
sachant que SourceX+Width
est stockée dans une variable non signée. Dans notre code on aura SourceX+Width = 0×80000000-offset+offset = -2147483647
. Pour dumper la mémoire après le frame buffer, il suffit de jouer avec les deux paramètres vu précédemment.
II] Lecture mémoire absolue.
Le problème de RECT_COPY
c’est que la lecture mémoire est relative. Si l’on essaye de copier une page mémoire de vmware-vmx qui n’existe pas, on crash le programme. Donc pour fiabiliser l’exploitation du bug il faut trouver où se situe le frame buffer du côté host. Sous un host vista, la page précédant le frame buffer contient l’adresse que nous recherchons. Sous xp c’est plus ardu, on peut retrouver l’adresse avec une commande 3D ou se risquer à utiliser la même méthode que pour un host vista. Mais il y a des risques de violation d’accès mémoire. Chez moi, la plupart de ces techniques fonctionnent (VMWare player Build: 118166
) mais sur d’autres configurations cela est impossible.
Maintenant que l’on a retrouvé l’adresse du frame buffer, on peut lire précisément la mémoire de l’host. On peut donc par exemple récupérer le PeHeader
de vmware-vmx (se situant toujours en 0×400000) pour avoir la version de VMWare et une vue précise des sections principales de l’exécutable code/data etc.
III] Écriture en mémoire.
On peut utiliser la commande RECT_COPY
pour écraser la mémoire de l’host. Mais cette commande est mieux filtrée au niveau de la destination car dépendante des valeurs de SVGA_REG_WIDTH
et SVGA_REG_HEIGHT
. Donc on ne peut écraser seulement quelques Ko précédant le frame buffer. Sur ma version de VMWare, la zone mémoire modifiable correspond au heap
. J’ai pensé récupérer le TEB
se situant en 0x7FFDF000
pour ensuite exploiter un heap overflow
. Mais à cette adresse, j’ai des valeurs ne correspondant pas à une structure de type TEB
. Et un heap overflow n’est pas forcément une exploitation fiable surtout quand il est dépendant de deux valeurs qu’on ne peut ajuster comme on le désire.
J’ai dû me tourner vers la commande DRAW_GLYPH
pour vérifier si elle est disponible:
Si ce n’est pas le cas il faut rajouter svga.yesGlyphs=”TRUE”
dans votre fichier de configuration. Cette commande n’est absolument pas filtrée au niveau de la destination en X/Y, permettant ainsi d’écrire en mémoire où l’on veut. La taille minimale d’un glyph est de 32 pixels et il va écrire un seul pixel à l’offset 0×6
par rapport à Destination X
. Il faut donc faire attention aux violations d’accès quand on écrit au bord d’une plage mémoire. Un petit exemple:
On peut donc lire/écrire en mémoire de façon fiable. En résumé, le plus dur est de retrouver l’adresse du frame buffer sans crasher vmware-vmx. Il est ensuite possible d’outrepasser des protections telles que l’ASLR
ou le DEP
et créer un canal de communication dans une zone mémoire partagée entre le guest et l’host (le framme buffer par exemple) et exécuter du code. VMWare tournant en Administrateur/root et possédant le token SeLoadDriverPrivilege
sous windows, au niveau de l’execution de code on peut tout faire!