Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Einreichen
ToolsExploitsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
CVE-2024-43630-POC — NtCopyFileChunk Stack-Pufferüberlauf POC | Kitploit
Tools/GitHubGitHub/quasarbinary/cve-2024-43630-poc
SpeicherforensikSchwachstellenanalyseExploitationReverse EngineeringBinary-Exploitation
GitHubquasarbinary/cve-2024-43630-poc

CVE-2024-43630-POC

NtCopyFileChunk Stack-Pufferüberlauf POC

Repository anzeigen
119vor 1 JahrNoch nicht geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

CVE-2024-43630-POC

Dieses Repository enthält einen POC, der bei der Ausführung einen Stack-OOB-Write auslöst und dadurch den Systemabsturz verursacht. Diese Schwachstelle ist ein äußerst interessantes und seltenes Relikt, das die Komplexität und Eigenheiten der Kernel-Programmierung, insbesondere der Objektverwaltung, veranschaulicht. Darüber hinaus betrifft die Schwachstelle den Kernel von Windows 11 24h2, Windows 10 22h2/21h2, nicht jedoch Windows 11 22h2/23h2, was das Ganze nur noch interessanter macht.

Gepatcht am 12. November 2024

Betroffene Windows-Versionen

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

Überblick über die Schwachstelle

Eine Schwachstelle in Form eines stack-basierten Pufferüberlaufs (technisch gesehen ein OOB-Write) existiert in der Windows-Kernel-Syscall-Funktion NtCopyFileChunk.

NtCopyFileChunk ermöglicht es, zwei Operationen in einem einzigen Syscall auszuführen: das Lesen der Quelldatei und das Schreiben in die Zieldatei.

NT_COPYFILE_DATA_BUFFER ist eine Struktur, die alles enthält, was zum Kopieren erforderlich ist. Bitte beachten Sie, dass diese Struktur durch Reverse Engineering ermittelt wurde und ihr Name erfunden ist. Seien Sie sich dessen also bewusst.

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;
};

Im Pseudocode sieht die Funktion ungefähr so aus:

// Pseudocode für die Funktion 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); //zeigt auf die Stelle nach NT_COPYFILE_DATA_BUFFER

	// Quelldatei anhand des Handles referenzieren
	ret = IopReferenceFileObject(SourceHandle, 1u, PreviousMode, (PVOID*)&DataBuffer_2->SourceFileObject, 0);
	if (ret < 0)
		goto RET;

	// Zieldatei anhand des Handles referenzieren
	ret = ObReferenceFileObjectForWrite(
		(ULONG_PTR)DestHandle,
		PreviousMode,
		(_FILE_OBJECT*)&DataBuffer->DestFileObject,
		(_OBJECT_HANDLE_INFORMATION*)&HandleInformation);
	[...]

	//ArbDataBuffer mit den Daten füllen, die wir in die Zieldatei schreiben
	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 enthält einen Zeiger auf das Stack-Event!
		DataBuffer->WriteIrp->Flags |= IRP_MJ_WRITE;
	}
	else
	{
		//für den asynchronen Modus brauchen wir das nicht
		[...]
	}
	UserInputEventObject = 0;
  // [4]
	ret = ObReferenceObjectByHandle(
		UserInputHandleEvent,
		2u,
		(POBJECT_TYPE)ExEventObjectType,
		PreviousMode,
		&UserInputEventObject,
		0);
	if (ret >= 0)
	{
		//Wenn der Benutzer das korrekte Event übergeben hat, fahren wir mit der Hauptlogik zum Kopieren einer Datei in eine andere fort. 
		//Diesen Codeabschnitt habe ich der Einfachheit halber ausgelassen.
		KeResetEvent((PRKEVENT)UserInputEventObject);
		goto NEXT_PATH_TO_READ_FILE_QUERY;
	}
RET:
	//Hier ist es! Geben Sie die DataBuffer-Struktur frei (denken Sie an WriteIrp, das einen Zeiger auf das Stack-Event enthält).
  // [5]
	if (ArbDataBuffer)
		IopFreeCopyObjectsFromDataBuffer((__int64)ArbDataBuffer, 1);
	if (UserInputEventObject_1)
		ObfDereferenceObject(UserInputEventObject_1);
	return (unsigned int)ret;

}

In [1] sehen wir StackEvent, unser Problemobjekt. In [2] verwendet der Kernel, wenn die Zieldatei im synchronen Modus geöffnet wurde, ein Stack-Event, um synchron auf den Abschluss des Schreibvorgangs in die Zieldatei zu warten. Dazu nutzt er IopWaitForSynchronousIoEvent (im Pseudocode nicht gezeigt) auf dem Stack-Event und nicht auf dem vom Benutzer übergebenen Event. Zuerst wartet der Kernel auf das Stack-Event und aktualisiert erst danach das vom Benutzer übergebene Event. In [3] sieht man außerdem, dass UserEvent von WriteIrp auf das Stack-Event zeigt. Was aber, wenn wir die korrekte Anfrage bilden, aber ein falsches Eingabe-Event übergeben? In [4] sehen wir, wie das Eingabe-Event referenziert wird, wobei wir ein ungültiges Handle (zum Beispiel den Wert 1) übergeben können. Danach wird der Speicher in [5] freigegeben. Genau hier passiert das Interessanteste.

Analysieren wir die Funktion IopFreeCopyObjectsFromDataBuffer und sehen wir uns an, was passiert, wenn der IRP freigegeben wird. Schauen wir uns WriteIrp->UserEvent genauer an.

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);

      //Wir gehen tiefer hinein und behalten UserEvent genau im Auge
      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, das ist es! Aber wie kann man den Referenzzähler für ein Stack-Objekt dekrementieren, das keinen OBJECT_HEADER hat?
  //Schwachstelle!
  if ( UserEvent )
    ObfDereferenceObject(UserEvent);
  if ( P )
    ExFreePoolWithTag(P, 0);
  [...]
}
Tool herunterladen