Skip to content
KitploitKITPLOIT
OutilsExploitsBlog
Log in
Soumettre
OutilsExploitsBlog
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
CVE-2024-43630-POC — POC de dépassement de tampon de pile NtCopyFileChunk | Kitploit
Outils/GitHubGitHub/quasarbinary/cve-2024-43630-poc
Criminalistique MémoireAnalyse des VulnérabilitésExploitationRétro-ingénierieExploitation de Binaires
GitHubquasarbinary/cve-2024-43630-poc

CVE-2024-43630-POC

POC de dépassement de tampon de pile NtCopyFileChunk

Voir le dépôt
119il y a 1 anPas encore vérifié

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

CVE-2024-43630-POC

Ce dépôt contient une POC qui déclenche une écriture OOB sur la pile lorsqu'elle est exécutée, provoquant un crash du système.
Cette vulnérabilité est un vestige extrêmement intéressant et rare qui démontre les complexités et les particularités de la programmation noyau, en particulier la gestion des objets.
De plus, la vulnérabilité affecte le noyau de Windows 11 24h2, Windows 10 22h2/21h2, mais pas Windows 11 22h2/23h2, ce qui ne fait qu'ajouter à l'intérêt.

Corrigé le 12 novembre 2024

Versions Windows affectées

  • Windows 11 Version 24H2
  • Windows 10 Version 22H2
  • Windows 10 Version 21H2
  • Windows Server 2025
  • Windows Server 2022, 23H2 Edition
  • Windows Server 2022
  • Testé sur : Windows 11 24h2 (x64) ntoskrnl.exe version 10.0.26100.1742

Aperçu de la vulnérabilité

Une vulnérabilité de débordement de tampon basé sur la pile (plus techniquement, une écriture OOB) existe dans la fonction d'appel système du noyau Windows NtCopyFileChunk.

NtCopyFileChunk permet d'effectuer deux opérations en un seul appel système : lire le fichier source et écrire dans le fichier de destination.

NT_COPYFILE_DATA_BUFFER est une structure qui contient tout le nécessaire pour la copie. Veuillez noter que cette structure a été obtenue par rétro-ingénierie et que son nom a été inventé. Soyez-en conscient.

struct NT_COPYFILE_DATA_BUFFER // sizeof=0x48
{
    DWORD64 UnknownQword1;
    DWORD64 UnknownQword2;
    DWORD64 UnknownQword3;
    DWORD64 UnknownQword4;
    PIRP WriteIrp;
    PDEVICE_OBJECT HighestDeviceObject;
    PFILE_OBJECT DestFileObject;
    PFILE_OBJECT SourceFileObject;
    DWORD64 SourceOffsetQuadPart;
};

La fonction ressemble à ceci en pseudo-code :

// Pseudocode for the function nt!NtCopyFileChunk in win11 24h2
__int64 __fastcall NtCopyFileChunk(
	void* SourceHandle,
	void* DestHandle,
	void* UserInputHandleEvent,
	struct _IO_STATUS_BLOCK* IoStatusBlock,
	ULONG Length,
	__int64 SourceOffset,
	struct _KTHREAD** DestOffset,
	ULONG* SourceKey,
	_DWORD* DestKey,
	int Flags)
{
	[...]
	NTSTATUS Status;
	char is_alertable_io;
	DWORD64 SourceOffsetStack;
	struct _KTHREAD* DestOffsetValue;
	_OBJECT_HANDLE_INFORMATION* HandleInformation;
	NT_COPYFILE_DATA_BUFFER* DataBuffer_3;
	PVOID UserInputEventObject;
	_FILE_OBJECT* pSourceFileObject;
	PIRP WriteIrp;
	struct _KEVENT StackEvent; // [1]
	[...]

	memset(&StackEvent, 0, sizeof(StackEvent));
	DataBuffer = (NT_COPYFILE_DATA_BUFFER*)ExAllocatePool2(0x43u, Length + sizeof(NT_COPYFILE_DATA_BUFFER), 'pCoI');
	ArbDataBuffer = DataBuffer + sizeof(NT_COPYFILE_DATA_BUFFER); //point after NT_COPYFILE_DATA_BUFFER

	// Reference source file by handle
	ret = IopReferenceFileObject(SourceHandle, 1u, PreviousMode, (PVOID*)&DataBuffer_2->SourceFileObject, 0);
	if (ret < 0)
		goto RET;

	// Reference destination file by handle
	ret = ObReferenceFileObjectForWrite(
		(ULONG_PTR)DestHandle,
		PreviousMode,
		(_FILE_OBJECT*)&DataBuffer->DestFileObject,
		(_OBJECT_HANDLE_INFORMATION*)&HandleInformation);
	[...]

	//Fill ArbDataBuffer with data that we will write to the dest file
	ret = IopPopulateCopyWriteWorkerData(
		(__int64)DestFileObj,
		(__int64)IoStatusBlock,
		(__int64)ArbDataBuffer,
		Length,
		v28,
		(__int64)pSourceFileObject,
		UserInputHandleEvent_1,
		DestOffset,
		DestKey,
		SHIDWORD(HandleInformation),
		(__int64)&DataBuffer_2->WriteIrp);

	[...]


	if (DestFileObj->Flags & FO_SYNCHRONOUS_IO)
	{
    // [2]
		KeInitializeEvent(&StackEvent, SynchronizationEvent, 0);

    // [3]
		DataBuffer_3->WriteIrp->UserEvent = &StackEvent; //WriteIrp contains pointer to stack event!
		DataBuffer->WriteIrp->Flags |= IRP_MJ_WRITE;
	}
	else
	{
		//for asynchronous mode, we don't need that
		[...]
	}
	UserInputEventObject = 0;
  // [4]
	ret = ObReferenceObjectByHandle(
		UserInputHandleEvent,
		2u,
		(POBJECT_TYPE)ExEventObjectType,
		PreviousMode,
		&UserInputEventObject,
		0);
	if (ret >= 0)
	{
		//If the user has submitted the correct event, we proceed to the main logic for copying one file to another. 
		//I have omitted that section of code for simplicity.
		KeResetEvent((PRKEVENT)UserInputEventObject);
		goto NEXT_PATH_TO_READ_FILE_QUERY;
	}
RET:
	//Here it is! Free the DataBuffer structure (remember WriteIrp, which contains a pointer to the stack event).
  // [5]
	if (ArbDataBuffer)
		IopFreeCopyObjectsFromDataBuffer((__int64)ArbDataBuffer, 1);
	if (UserInputEventObject_1)
		ObfDereferenceObject(UserInputEventObject_1);
	return (unsigned int)ret;

}

En [1], nous pouvons voir StackEvent, qui est notre objet problématique. En [2], si le fichier de destination a été ouvert en mode synchrone, le noyau utilise un événement de pile pour attendre de manière synchrone l'opération d'écriture vers le fichier de destination. Pour ce faire, il utilise IopWaitForSynchronousIoEvent (non montré dans le pseudo-code) sur l'événement de pile plutôt que sur l'événement passé par l'utilisateur. D'abord, le noyau attend l'événement de pile, et seulement ensuite met à jour l'événement passé par l'utilisateur. De même, en [3], vous pouvez voir que UserEvent de WriteIrp pointe vers l'événement de pile. Cependant, que se passe-t-il si nous formons la requête correcte mais passons un événement d'entrée incorrect ? En [4], nous voyons comment il référence l'événement d'entrée, où nous pouvons passer un handle invalide (par exemple, la valeur 1). Et ensuite la mémoire est libérée en [5]. C'est là que se produit la chose la plus intéressante.

Analysons la fonction IopFreeCopyObjectsFromDataBuffer et voyons ce qui se passe lorsque l'IRP est libéré. Examinons de plus près WriteIrp->UserEvent.

void __fastcall IopFreeCopyObjectsFromDataBuffer(__int64 ArbDataBuffer, char to_clear_irp)
{
  NT_COPYFILE_DATA_BUFFER *DataBuffer;
  PFILE_OBJECT SourceFileObject;
  PIRP WriteIrp;
  PFILE_OBJECT DestFileObject;

  DataBuffer = (NT_COPYFILE_DATA_BUFFER *)(ArbDataBuffer - 0x48);
  if ( to_clear_irp )
  {
    WriteIrp = DataBuffer->WriteIrp;
    DestFileObject = DataBuffer->DestFileObject;
    if ( WriteIrp )
    {
      IopFreeIrpExtension((__int64)DataBuffer->WriteIrp, 9, 1);

      //We are moving deeper, closely monitoring UserEvent
      IopExceptionCleanupEx((ULONG_PTR)DestFileObject, WriteIrp, WriteIrp->UserEvent, 0, 0);
      return;
    }
    if ( DestFileObject )
      ObfDereferenceObjectWithTag(DataBuffer->DestFileObject, 0x746C6644u);
  }
  SourceFileObject = DataBuffer->SourceFileObject;
  if ( SourceFileObject )
    ObfDereferenceObjectWithTag(SourceFileObject, 0x746C6644u);
  ExFreePoolWithTag(DataBuffer, 0);
}
LONG_PTR __fastcall IopExceptionCleanupEx(ULONG_PTR DestFileObject, PIRP Irp, PVOID UserEvent, PVOID P, char a5)
{
  [...]
  if ( Irp )
  {
    MasterIrp = Irp->AssociatedIrp.MasterIrp;
    if ( MasterIrp )
      ExFreePoolWithTag(MasterIrp, 0);
    [...]
    IoFreeIrp(Irp);
  }
  //Oh, that's it! But how can you decrement the reference counter for a stack object that doesn't have an OBJECT_HEADER?
  //Vuln!
  if ( UserEvent )
    ObfDereferenceObject(UserEvent);
  if ( P )
    ExFreePoolWithTag(P, 0);
  [...]
}
Télécharger l’outil