EMET failed

novembre 1st, 2009 at 10:25 admin

Il y a quelques jours, la team MSRC de Microsoft a sortit EMET (Enhanced Mitigation Evaluation Toolkit). Un outil aidant à la gestion des différentes protections fournies par Windows, comme le DEP. Je me suis dit qu’il serait intéressant d’y jeter un oeil pour voir si toutes les protections mises en place sont solides.

EMET est constitué de plusieurs binaires :

  • EMET_conf.exe qui permet de configurer les binaires qu’on veut protéger.
  • EMET_launcher.exe et EMET_launcher64.exe qui vont initialiser le processus à protéger
  • EMET.dll la DLL qui est injecté dans le processus pour mettre en place la protection.

En fait EMET se base sur l’Image File Execution Options. Cette feature de Windows permet d’exécuter un binaire à la place d’un autre, cela est indiqué par la clé registre ‘HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options’. On spécifie une sous-clé contenant le nom du processus et les valeurs qui vont déterminer le comportement à avoir quand ce processus sera lancé. EMET utilise la valeur « Debugger » pour faire appel au launcher qui va aller lire « HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\EMET » pour parser les options à appliquer au niveau de la protection.

Une des features qui m’a le plus intéressé est l’anti-allocation en 0. Je cite :

NULL page allocation

This blocks attackers from being able to take advantage of NULL dereferences in user mode. It functions by allocating the first page of memory before the program starts. Right now the exploitation techniques for these types of vulnerabilities are only theoretical. However, this mitigation will protect you even if that changes. Please note this protection does not impact kernel mode NULL dereferences as the current version of EMET only supports user mode mitigations.

J’ai disass EMET.dll et je suis tombé sur le code suivant :

int __fastcall sub_110E0(int a1)
{
  int v1; // eax@3
  HMODULE v2; // eax@6
  FARPROC v3; // eax@7
  int result; // eax@9
  int v5; // [sp+4h] [bp-4h]@1

  v5 = a1;
  if ( sub_11070(L"heap_allocations") == 1 )
    sub_11190();
  v1 = sub_11070(L"null_allocation");
  if ( v1 == 1 )
    VirtualAlloc((LPVOID)v1, 0x400u, 0x3000u, v1);
  if ( sub_11070(L"enable_dep") == 1 )
  {
    v2 = GetModuleHandleW(L"Kernel32.dll");
    if ( v2 )
    {
      v3 = GetProcAddress(v2, "SetProcessDEPPolicy");
      if ( v3 )
        ((int (__stdcall *)(signed int))v3)(3);
    }
  }
  result = sub_11070(L"sehop");
  if ( result == 1 )
  {
    GetModuleHandleExW(5, sub_110E0, &v5);
    result = sub_11610();
    dword_1B6B8 = 1;
  }
  return result;
}

On voit très bien que la protection ‘anti-allocation-en-0′ est basé sur cet appel à VirtualAlloc() :

VirtualAlloc(1, 1024, MEM_COMMIT|MEM_RESERVE, PAGE_NOACCESS);

Sachant cela je me code un petit binaire qui effectue exactement la même opération et là c’est le drame, VirtuallAlloc renvoie 0, indiquant une erreur de type ‘ERROR_INVALID_PARAMETER (00000057)’.

Je trace alors un peu le code de VirtuaAlloc pour tomber sur ceci :

LPVOID __stdcall VirtualAlloc(LPVOID lpAddress, DWORD dwSize, DWORD flAllocationType, DWORD flProtect)
{
  return VirtualAllocEx((HANDLE)0xFFFFFFFF, lpAddress, dwSize, flAllocationType, flProtect);
}

LPVOID __stdcall VirtualAllocEx(HANDLE hProcess, LPVOID lpAddress, DWORD dwSize, DWORD flAllocationType, DWORD flProtect)
{
  int v5; // eax@2
  int v7; // [sp+Ch] [bp-20h]@2
  CPPEH_RECORD ms_exc; // [sp+14h] [bp-18h]@2

  if ( lpAddress && (unsigned int)lpAddress < 0x1000) )
  {
    SetLastError(0x57u);
  }
  else
  {
    v5 = NtAllocateVirtualMemory(hProcess, &lpAddress, 0, &dwSize, flAllocationType, flProtect);
    v7 = v5;
    ms_exc.disabled = -1;
    if ( v5 >= 0 )
      return lpAddress;
    BaseSetLastNTError(v5);
  }
  return 0;
}

En fait si VirtualAlloc me renvoie une erreur c’est parce que le paramètre ‘lpAddress’ est inférieur à 0×1000). On regarde la doc :

lpAddress [in, optional]

The starting address of the region to allocate. If the memory is being reserved, the specified address is rounded down to the nearest multiple of the allocation granularity. If the memory is already reserved and is being committed, the address is rounded down to the next page boundary. To determine the size of a page and the allocation granularity on the host computer, use the GetSystemInfo function. If this parameter is NULL, the system determines where to allocate the region.

On nous dit que si ce paramètre est à 0 alors le système choisit l’adresse de l’allocation, sinon l’utilisateur peut spécifier une adresse.

Apparemment une adresse inférieure à 0×1000 n’est pas apprécié par VirtualAlloc c’est pourquoi dans EMET.dll l’appel échoue. On peut donc tout naturellement allouer de la mémoire en 0 dans un processus protéger avec EMET grâce ce code :

//
// Allocate NULL address in userland memory space
//
BOOL AllocateNullPage()
{
	NTSTATUS Status;
	DWORD Addr=1;
	DWORD Len=0x1000;
	
	Status=ZwAllocateVirtualMemory(GetCurrentProcess(), 
	Addr, 
	0, 
	&Len, 
	MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN, 
	PAGE_EXECUTE_READWRITE);
	if(!NT_SUCCESS(Status))
	{
		printf("[-] Error with ZwAllocateVirtualMemory : 0x%x\n", Status);
		return FALSE;
	}
	
	return TRUE;
}

On utilise directement ZwAllocateVirtualMemory qui nous évite de passer par VirtualAlloc.

Donc, quand je lis dans le readme.rtf de EMET :

EMET has been tested with the following OS:
32 bit: Windows XP, Server 2003, Vista, Server 2008 and Windows 7
64 bit: Vista and Windows 7 and Windows 2008 R2

Je me dis : failed ! (pour info je suis sous WinXP SP3).

Pour corriger le tir il suffirait de faire appel directement à ZwAllocateVirtualMemory pour mettre la page en 0 en PAGE_NOACCESS.

Enfin je trouve qu’EMET ressemble pas mal à WehnTrust.

Sinon hdmoore s’est fait plaisir en lâchant les adresses d’opcodes intéressantes pour l’exploitation au sein de la DLL

Entry Filed under: RE

12 Comments

  • 1. teach  |  novembre 2nd, 2009 at 20:07

    A quoi ca peut bien servir de proteger le mmaping de la first page d’un process userland?
    Au mieux cela pourrait servir si un user avait la possibilité d’injecter du code dans les pages memoire d’un process et en cas de null deref, que ce code soit exec avec les privileges de ce process. Mais pourquoi se faire chier à chercher des null derefs si on peut deja exec inject du code et detourner le flot d’execution pour l’executer avec d’autres priv? :(


  • 2. newsoft  |  novembre 2nd, 2009 at 20:43

    @teach: exact, ça ne sert à rien IMHO …

    @ivan: je ne vois pas le rapport avec WehnTrust ? WehnTrust ça ajoute de l’ASLR sur des systèmes qui ne le supportent pas, « à la PaX ».


  • 3. admin  |  novembre 2nd, 2009 at 23:52

    @teach & newsoft

    De deux choses l’une, d’abord ce post montre que le code utilisé par EMET est foireux pour mettre la NULL page en PAGE_NOACESS. Cela se rapproche de linux et de son mmap_min_addr. Ensuite si on se place dans le cas ou tous les binaires du systèmes sont « blindés » avec EMET, on est mesure de forger un binaire qui ira allouer de la mémoire en 0 pour exploiter un branchement sur NULL réalisé par du code noyau, comme on l’a souvent vu, donc un privilege escalation. De ce point de vu je ne pense pas que cela ne serve à rien !

    @newsoft
    On retrouve Matt Miller impliqué dans les 2 projets, ensuite une des seules choses qui différencie EMET de WehnTrust est l’ALSR. Pour le reste on déjà le SEHOP et la gestion DEP. EMET poursuit donc WehTrust en ajout l’anti NULL page alloc et la protection contre le heap-spraying.


  • 4. teach  |  novembre 3rd, 2009 at 00:05

    u right dawg. c’etait uniquement pour les process userland dont je parlais bien sur. l’anti null page alloc a tout son sens quand on parle de bugs sur le noyau … à moins d’avoir un trickz (un obscure appel systeme du diable de l’enfer | ou qui a dit un binaire malpoli mais de confiance qui bypass tout) qui vient foutre toute cette belle protect dans la bouse :p


  • 5. EMET, le nouvel utilitair&hellip  |  novembre 3rd, 2009 at 15:05

    [...] UPDATE: ivanlef0u a analyser la partie protection contre l’allocation en NULL page, le résultat est [...]


  • 6. Matt  |  novembre 5th, 2009 at 16:33

    De toute facon, Skape s’etait fait rachete sa boite et a rejoint MSFT donc rien d’etonnant si ils ont prit des trucs de WehnTrust .


  • 7. Dreg  |  novembre 7th, 2009 at 01:40

    Interesting :-)


  • 8. Eek  |  décembre 1st, 2009 at 16:43

    Ca fait du bien de voir qu’il y’a encore des cinglés (francophones) qui pratiquent la « dissection » de code…

    Peu de personne manie le bistourie à ton niveau…

    … Est il possible de rentrer en contact avec toi (vous) via IRC (sur un server qui supporte ssl) ?

    Evidement, je ne cherche pas à rentrer en contact avec ton chirugien ;)
    … Réponds moi par mail, si tu le souhaites…


  • 9. Zenol  |  décembre 13th, 2009 at 15:46

    Instructif.


  • 10. Merry X-Mas =) / Implemen&hellip  |  décembre 24th, 2009 at 21:01

    [...] et Wehntrust. L’idée m’est en effet venue après avoir lu un article de Ivanlef0u (EMET failed) dans lequel il analyse une des protections de [...]


  • 11. newsoft  |  décembre 29th, 2009 at 21:38

    Heu, désolé mais à la lecture de la doc EMET, je ne vois nulle part que ce truc ajoute de l’ASLR ???

    Je ne vois pas comment ils feraient pour rebaser le .EXE, et pour ajouter de l’ASLR « à la PaX » dans Windows XP il faudrait un peu plus que modifier quelques flags dans l’entête PE il me semble …


  • 12. admin  |  décembre 29th, 2009 at 22:04

    @newsoft
    Déjà on parlait de WehnTrust qui je cite :

    How it works
    WehnTrust randomizes the base addresses of memory allocations to make it more difficult to exploit software vulnerabilities such as buffer overflows. This technique is commonly known as Address Space Layout Randomization (ASLR) and was originally conceived by the PaX team

    Après je n’ai pas regardé comment c’était implémenté.


Trackback this post


Calendar

juillet 2016
L Ma Me J V S D
« fév    
 123
45678910
11121314151617
18192021222324
25262728293031

Most Recent Posts