Skip to content
KitploitKITPLOIT
HerramientasExploitsBlog
Log in
Enviar
HerramientasExploitsBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
CVE-2024-43630-POC — POC de desbordamiento de búfer en la pila de NtCopyFileChunk | Kitploit
Herramientas/GitHubGitHub/quasarbinary/cve-2024-43630-poc
Forensia de MemoriaAnálisis de VulnerabilidadesExplotaciónIngeniería InversaExplotación de Binarios
GitHubquasarbinary/cve-2024-43630-poc

CVE-2024-43630-POC

POC de desbordamiento de búfer en la pila de NtCopyFileChunk

Ver Repositorio
119hace 1 añoAún no revisado

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

CVE-2024-43630-POC

Este repositorio contiene un POC que desencadena una escritura fuera de límites (OOB) en la pila cuando se ejecuta, provocando el bloqueo del sistema. Esta vulnerabilidad es una reliquia extremadamente interesante y poco común que demuestra las complejidades y peculiaridades de la programación de kernels, especialmente en la gestión de objetos. Además, la vulnerabilidad afecta al kernel de Windows 11 24h2, Windows 10 22h2/21h2, pero no a Windows 11 22h2/23h2, lo que solo aumenta el interés.

Parcheado el 12 de noviembre de 2024

Versiones de Windows afectadas

  • Windows 11 Versión 24H2
  • Windows 10 Versión 22H2
  • Windows 10 Versión 21H2
  • Windows Server 2025
  • Windows Server 2022, Edición 23H2
  • Windows Server 2022
  • Probado en: Windows 11 24h2 (x64) ntoskrnl.exe versión 10.0.26100.1742

Resumen de la vulnerabilidad

Existe una vulnerabilidad de desbordamiento de búfer basada en pila (más técnicamente, una escritura fuera de límites u OOB) en la función de syscall del kernel de Windows NtCopyFileChunk.

NtCopyFileChunk permite realizar dos operaciones en una única llamada al sistema: leer el archivo de origen y escribir en el archivo de destino.

NT_COPYFILE_DATA_BUFFER es una estructura que contiene todo lo necesario para la copia. Tenga en cuenta que esta estructura se obtuvo mediante ingeniería inversa y que su nombre fue inventado. Por lo tanto, tenga esto en cuenta.

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 función se ve más o menos así en pseudocódigo:

// 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], podemos ver StackEvent, que es nuestro objeto problemático. En [2], si el archivo de destino se abrió en modo síncrono, el kernel utiliza un evento de pila para esperar de forma síncrona a que se complete la operación de escritura en el archivo de destino. Para ello, usa IopWaitForSynchronousIoEvent (no mostrado en el pseudocódigo) sobre el evento de pila en lugar del evento proporcionado por el usuario. Primero, el kernel espera el evento de pila y solo después actualiza el evento proporcionado por el usuario. De manera similar, en [3], se puede ver que UserEvent de WriteIrp apunta al evento de pila. Sin embargo, ¿qué sucede si formamos la solicitud correcta pero pasamos un evento de entrada incorrecto? En [4], podemos ver cómo hace referencia al evento de entrada, donde podemos pasar un identificador (handle) no válido (por ejemplo, el valor 1). Y luego la memoria se libera en [5]. Aquí es donde ocurre lo más interesante.

Analicemos la función IopFreeCopyObjectsFromDataBuffer y veamos qué sucede cuando se libera el IRP. Echemos un vistazo más de cerca a 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);
  [...]
}
Descargar herramienta