Skip to content
KitploitKITPLOIT
ИнструментыЭксплойтыБлог
Log in
Отправить
ИнструментыЭксплойтыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

ЛентыКонтактыКонфиденциальность© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
CVE-2024-43630-POC — POC переполнения буфера стека NtCopyFileChunk | Kitploit
Инструменты/GitHubGitHub/quasarbinary/cve-2024-43630-poc
Криминалистика памятиАнализ уязвимостейЭксплуатацияОбратная инженерияЭксплуатация Бинарных Файлов
GitHubquasarbinary/cve-2024-43630-poc

CVE-2024-43630-POC

POC переполнения буфера стека NtCopyFileChunk

Репозиторий
1191 год назадЕщё не проверено

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

CVE-2024-43630-POC

Этот репозиторий содержит POC, который при выполнении вызывает запись за пределами стека (OOB write), приводящую к краху системы. Эта уязвимость — чрезвычайно интересный и редкий артефакт, демонстрирующий сложность и особенности программирования ядра, особенно управления объектами. Кроме того, уязвимость затрагивает ядро Windows 11 24h2, Windows 10 22h2/21h2, но не Windows 11 22h2/23h2, что только добавляет интереса.

Исправлено 12 ноября 2024 года

Затронутые версии Windows

  • Windows 11 Version 24H2
  • Windows 10 Version 22H2
  • Windows 10 Version 21H2
  • Windows Server 2025
  • Windows Server 2022, 23H2 Edition
  • Windows Server 2022
  • Протестировано на: Windows 11 24h2 (x64) ntoskrnl.exe version 10.0.26100.1742

Обзор уязвимости

Уязвимость переполнения буфера на основе стека (технически — внеплановая запись, OOB write) существует в функции системного вызова ядра Windows NtCopyFileChunk.

NtCopyFileChunk позволяет выполнить две операции в одном системном вызове: чтение исходного файла и запись в файл назначения.

NT_COPYFILE_DATA_BUFFER — это структура, содержащая всё необходимое для копирования. Обратите внимание, что эта структура была получена в результате обратной разработки, а её название придумано. Поэтому имейте это в виду.

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

В псевдокоде функция выглядит примерно так:

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

}

В [1] мы видим StackEvent — наш проблемный объект. В [2], если файл назначения был открыт в синхронном режиме, ядро использует стековое событие для синхронного ожидания завершения операции записи в файл назначения. Для этого оно использует IopWaitForSynchronousIoEvent (не показан в псевдокоде) для стекового события, а не для события, переданного пользователем. Сначала ядро ожидает стековое событие, и только затем обновляет событие, переданное пользователем. Аналогично, в [3] видно, что UserEvent структуры WriteIrp указывает на стековое событие. Однако что будет, если сформировать правильный запрос, но передать неправильное входное событие? В [4] видно, как ядро ссылается на входное событие, куда мы можем передать недопустимый дескриптор (например, значение 1). А затем в [5] происходит очистка памяти. Вот здесь и происходит самое интересное.

Давайте проанализируем функцию IopFreeCopyObjectsFromDataBuffer и посмотрим, что происходит при очистке IRP. Рассмотрим подробнее 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);
  [...]
}
Скачать инструмент