Return of the SMM

mars 29th, 2009 at 03:23 admin

Encore un post qui parle du SMM, c’est la mode en cette saison. Pour ceux qui débarquent, je vous conseil d’abord de lire ce post pour vous mettre dans le bain. Je tiens juste d’emblée à préciser que le SMM c’est joli, c’est puissant, c’est funny mais qu’au final c’est quand même de la branlette intellectuelle. Il faut savoir que beaucoup de choses faisables en SMM le sont déjà en ring 0. Mis à part le cas très spécifique de la corruption d’hyperviseurs comme l’équipe de Invisible Things Lab l’a montré en profitant d’un bug permettant d’atteindre la SMRAM je ne vois pas en quoi le SMM est utile pour un attaquant. Attention je dis cela parce qu’il est plus simple actuellement de réaliser certaines attaques indétectables, comme par exemple un keylogger, sans avoir à se mettre en SMM. Finalement je rejoins l’opinion d’autres personnes qui disent qu’il faut prendre en compte le du risque SMM mais qu’on a déjà assez de choses non-secure à traiter pour le moment. Donc au final pas de quoi paniquer.

Justement parlons de ce fameux bug. Loïc Duflot a montré à CansecWest une nouvelle attaque visant le mode SMM. Sachant qu’actuellement les chipsets de type northbridge sont bridés afin que personne n’accède à la SMRAM il devient quasiment impossible à l’utilisateur de lire ou d’écrire dans cette mémoire. Cette attaque consiste à modifier la politique du cache au niveau de la SMRAM. On dit au CPU de ne pas aller chercher le code SMM dans la DRAM mais dans son cache directement, cache que l’on contrôle bien sur. Chose marrante c’est précisément ce même bug qu’on utiliser les personnes d’ITL pour atteindre la SMRAM et ainsi infecter l’hyperviseur de XEN. Les grands esprits se rencontrent :]

L’attaque se déroule en 3 étapes et nécessite au moins d’être admin sur la b0x :

  1. On modifie la gestion du cache à l’aide des MTRRs (Memory Type Range Register). Ils se présentent sous la forme d’un ensemble de MSRs, leur taille est donc de 64 bits. Un MTRR sert à associer un espace de mémoire physique à un type de cache. Les différents types de cache sont :
    mtrr_caching

    Je ne vais pas tous les décrire, sachez que ceux qui nous intéressent sont les types UC et WB.
    Il existe 2 types de MTRR ceux qui sont constants et ceux qui sont variables. Pour le moment seul les constants nous intéresse car ils sont utilisés pour décrire la gestion du cache pour le premier mega de la mémoire physique, comme le montre le schéma suivant :
    mtrr_mapping2

    C’est précisément dans ce premier mega de mémoire qu’est situé la SMRAM. Elle est normalement située à l’adresse physique 0xA0000. Pour connaitre quel est le type de cache appliqué à la SMRA il suffit de lire la doc :

    Register IA32_MTRR_FIX64K_00000 :
    Maps the 512-KByte address range from 0H to 7FFFFH. This range is divided into eight 64-KByte sub-ranges.

    Registers IA32_MTRR_FIX16K_80000 and IA32_MTRR_FIX16K_A0000 :
    Maps the two 128-KByte address ranges from 80000H to BFFFFH. This range is divided into sixteen 16-KByte sub-ranges, 8 ranges per register.

    Registers IA32_MTRR_FIX4K_C0000 through IA32_MTRR_FIX4K_F8000 :
    Maps eight 32-KByte address ranges from C0000H to FFFFFH. This range is divided into sixty-four 4-KByte sub-ranges, 8 ranges per register.

    C’est donc le MSR IA32_MTRR_FIX16K_A0000 (0×259) qui détermine que politique de cache est appliquée à la SMRAM. La structure d’un MTRR est simple, le MSR est découpé en champ de 8 bits qui décrivent le caching sur une plage de mémoire. Dans le cas du MSR IA32_MTRR_FIX16K_A0000 chacun de ses champs décrit un espace mémoire de taille 16KB.
    mtrr_struct

    Il existe 2 encodage différent pour le champ Type, le plus simple utilise uniquement les 2 premiers bits pour définir le type de chacun, les autres sont reservés et mit à 0. Le second encodage, dit étendu n’est dispo que pour les CPU AMD et ne nous intéresse pas ici. Maintenant avec le LKD on peut lire la valeur du MSR IA32_MTRR_FIX16K_A0000.

    	lkd> rdmsr 259
    	msr[259] = 00000000`00000000

    Cela montre que pour le moment la SMRAM est donc UC. Tout accès en écriture ou lecture dans cette mémoire ne sera jamais mis en cache. Ce qui fait que tout le code SMM est chargé depuis la DRAM. Ainsi la demande d’accès à la mémoire physique de la SMRAM passe forcément par le northbridge qui contrôle si le CPU est bien en mode SMM.

    Pour le moment l’utilisateur ne peut toujours pas accéder par lui même à la SMRAM car le chipset verrouille le bit qui sert à aiguiller l’accès entre la SMRAM (dans la DRAM) et l’adresse du buffer vidéo (je rappel que par défaut ce bit oriente l’accès mémoire sur le buffer vidéo). Ce bit d’aiguillage est mise à jour lorsque que chipset est certain que le CPU est en mode SMM.

    Maintenant on va modifier cela pour que la zone mémoire sur l’intervalle [0xA0000, 0xA0000+0x4000] soit en WB. C’est à dire que toutes les lectures et écritures seront mises en cache si possible. On définit donc les 2 premiers bits du IA32_MTRR_FIX16K_A0000 à la valeur 0×6.

  2. On balance une SMI sur le CPU. Le CPU va donc accéder à la SRAM et du fait de la nouvelle politique de cache mise en place, la SMRAM va donc se retrouver dans le cache. Le SMI handler est exécuter normalement depuis le cache.
  3. Sachant que notre SMRAM est dans le cache, l’accès à la mémoire physique 0xA0000 ne passe plus par le northbridge ! Aucun contrôle n’est donc réalisé sur le mode du CPU. Il suffit donc de mapper cet espace mémoire physique dans notre espace virtuel pour y écrire/lire comme si de rien n’était, kewl =] Attention en utilisant la pagination d’autres bits, notamment la PAT (Page Attribute Table), doivent prit en compte. Ce sont les bits CD et NW du CR0, les bits PCD et PNW du PDE/PTE qui sont concernés. En fait on voudrait éviter de tomber sur une combinaison entre le MTRR et la PAT qui rendrait la mémoire non cachable lorsqu’on la mappe.

Concernant l’implémentation d’un exploit sous Windows. Il est possible de lire des MSR depuis le user-land avec l’API ZwSystemDebugControl, modifier le IA32_MTRR_FIX16K_A0000 ne pose donc pas de problème. On peut aussi générer un SMI à l’aide d’une instruction ‘OUT 0×0, 0xB2′ du moment qu’on à modifier l’IOPL courant à l’aide de l’API ZwSetInformationProcess et du SeTcbPrivilege. On peut réaliser tout ceci depuis le ring3. Reste à mapper l’adresse physique 0xA000, on pourrait penser qu’utiliser le \Device\PhysicalMemory est suffisant mais ce dernier n’est qu’en lecture seule sous WinXP. En plus il n’est pas possible de contrôler les flags de caching pour les pages qui mappent la SMRAM en user-land.

Il existe aussi l’API native ZwSystemDebugControl avec ControlCode SysDbgReadPhysical (10) qui permet de lire de la mémoire physique depuis l’user-land. Voici une fonction la mettant en oeuvre :

ULONG ReadPhysicalMem(PHYSICAL_ADDRESS Addr, PVOID Buff, ULONG Size)
{
	NTSTATUS Status;
	DWORD RetBytes;
	SYSDBG_PHYSICAL PhysMem;
	
	PhysMem.Address=Addr;
	PhysMem.Buffer=Buff;
	PhysMem.Request=Size;
		
	Status=ZwSystemDebugControl(SysDbgReadPhysical, &PhysMem, sizeof(PhysMem), NULL, 0, &RetBytes);
	if(!NT_SUCCESS(Status))
	{
		printf("Error with ZwSystemDebugControl (SysDbgReadPhysical) : 0x%x\n", Status);	
		
		return 0;
	}
	
	return RetBytes;
}

Par contre je n’ai pas compris mais l’API renvoie STATUS_UNSUCCESSFUL (0xC0000001) lorsqu’on essaye de lire l’adresse physique 0xA0000. Surement que le noyau refuse qu’on lise dans le premier mega de mémoire physique :( je n’ai pas investit plus dans cette direction

Jusqu’ici on voit que pour atteindre la SMRAM depuis l’user-land c’est la misère. Alors solution bourrin, on sort le driver. Le code est quasiment le même qu’en user-land sauf qu’on utilise MmMapIoSpace pour mapper la SMRAM dans notre espace virtuel noyau. Après si l’exploit marche on peut aussi bien lire et écrire dans la SMRAM mise en cache.

Une fois qu’on arrive à écrire dans la SMRAM mise en cache tout est gagné. On peut reloger la SMRAM sur une zone mémoire qu’on contrôle. Par contre cette modification ne peut se faire qu’en SMM.
Pour réaliser cela, on modifie le SMI handler dans le cache afin qu’il exécute un shellcode qui va modifier la valeur du champ SMBASE. Ce champ est situé à l’adresse SMBASE+0x7EF8. Notre shellcode va mette à jour le champ SMBASE pour qu’il pointe sur la zone de mémoire physique avec notre SMRAM custom. Une fois qu’on à fait cela on relance une SMI, le handler va exécuter notre shellcode, le champ SMBASE est donc modifié et on flush le cache pour que la valeur soit mise à jour dans la DRAM. Lors d’un prochaine SMI ce sera notre custom SMRAM qui sera prise en compte, yeepee :)

J’ai codé 2 programmes qui réalisent l’attaque cité plus haut afin de dumper la SMRAM. Le premier est en user-land et tente de lire la SMRAM depuis le cache avec le \Device\PhysicalMemory. Le second est un driver qui utilise MmMapIoSpace. Par contre, par manque de temps et surtout de motivation je n’ai pas vraiment testé mes binaires. C’est surtout du au fait que l’attaque n’est pas réalisable depuis une VM puisque les VM comme VMware et Virtual PC qui n’utilisent pas la virtualisation hardware émule le mode SMM et que je n’ai pas trop envie de le tester sur ma machine de taff. Bref c’est du code de base si vous voulez investir le sujet, si vous avez besoin d’aide n’hésitez pas à me contacter !

En parlant de Virtual PC 2k7, j’ai remarqué que ce dernier n’aimait pas trop qu’on touche à ses MTRR. Une modification du IA32_MTRR_FIX16K_A0000 n’est pas prise à compte par la VM ce qui en fait une astuce de plus pour détecter Virtual PC. Toujours pratique dans le cas d’un rk kernel-land qui voudrait éviter d’être exécuter sur cette VM.

Pendant que je suis dans la SMM, je vous conseil de lire l’excellent article de chpie qui installe un keylogger SMM sous VMware. En fait VMware (tout comme Virtual PC 2k7) émule un northbridge de type Intel 440BX AGPset 82443BX, dont la documentation est disponible ici. Ce qui est cool, c’est que le bit D_LCK est mis à jours 0. Ce qui veut dire que le bit D_OPEN peut être modifié librement par l’utilisateur ! Je me suis donc codé un petit dumper pour SMRAM. Le principe est simple on écrit le SMRAM Control Register du northbridge pour qu’il nous laisse accéder à la SMRAM librement. L’outil va écrire un .bin sur le disque qui correspond à l’interval de mémoire [0xA0000, 0xA0000+0x20000] que IDA se fera un plaisir d’analyser. Pour vous dire on retrouve des choses assez marrantes dans la SMRAM ;)

Ce qui faut retenir dans tout ca, c’est que jouer avec le SMM c’est cool, cela permet de comprendre plein de choses sur le fonctionnement de notre machine. Par contre en terme de fonctionnalités, le SMM reste limité, même si on dit que c’est super-furtif on est loin de voir apparaître des malwares qui infectent le SMM (je dis ça mais ils sont bien arrivés dans nos MBR les petits batards). En fait la grosse difficulté est du au fait qu’on est très proche du matériel et qu’il n’existe pas forcément de documentation pour tous les chipsets northbridge grand public. Pour mon laptop par exemple je n’ai accès à aucune datasheet concernant mon northbridge. Donc en termes de généricité on est vite limité. Enfin comme je l’ai dit au début pas besoin d’aller se planquer dans la SMRAM pour poser un keylogger ou sniffer réseau qui bypass une bonne partie des AV/FW, alors pourquoi faire compliqué quand on peut faire simple :]

Voici l’url pour les binaires et codes :
http://ivanlef0u.fr/repo/smm_attack.rar

Pour finir, quelques liens intéressants :

!exploitable

An Analysis of Conficker’s Logic and Rendezvous Points

Anti-Debugging Series

Emulation/AV Awareness

Cons and thing

Microsoft GdiPlus EMF GpFont.SetData Integer Overflow

Guide des principes fondamentaux de l’enquête informatique pour Windows

Pushing the Limits of Windows: Paged and Nonpaged Pool

Plongeon dans les appels systèmes Windows

Et pour info le coding du tool IDT Sniffer avance tranquillement :p

Entry Filed under: RE

6 Comments

  • 1. Matt  |  mars 31st, 2009 at 08:31

    C’est clair pour la genericite. Mon pc utilise meme pas le legacy mode :(


  • 2. Matt  |  mars 31st, 2009 at 08:37

    PS. « On peut réaliser tout ceci depuis le ring3. Reste à mapper l’adresse physique 0xA000″ -> On peut réaliser tout ceci depuis le ring3. Reste à mapper l’adresse physique 0xA0000″


  • 3. [SFX]-Zeus  |  avril 2nd, 2009 at 22:54

    Salut, bon je suis complètement hors sujet mais je n’ai pas vu d’adresse mail pour t’écrire.

    Je suis en train d’écrire un petit code pour lister les fichiers à partir de la mft (sans faire une simple boucle sur les filerecord) afin d’accélérer le listage des fichiers pour SuperCopier.

    Seulement je bute un peu sur l’IndexRoot et l’IndexAllocation où j’ai un peu du mal à trouver de bonnes informations. Ainsi que sur le $bitmap qui sert aussi apparemment pour le btree.
    J’ai vu que tu avais pas mal travaillé sur la MFT donc si tu as des informations sur mes problèmes ci-dessus je suis preneur :)

    Cordialement.


  • 4. Le_Clown  |  avril 7th, 2009 at 21:49

    *UBER-LOL*


  • 5. L33ckma  |  avril 8th, 2009 at 17:39

    WTFbbq??


  • 6. newsoft  |  juin 30th, 2009 at 11:33

    @Zeus: il te faudrait une copie de l’IFS Kit, ça irait plus vite …

    Sinon, si c’est pour de la copie de fichiers, l’API Volume Shadow Copy est p/e à regarder (je n’ai aucune idée de la performance, mais c’est assez bas niveau).


Trackback this post


Calendar

novembre 2014
L Ma Me J V S D
« fév    
 12
3456789
10111213141516
17181920212223
24252627282930

Most Recent Posts