Skip to content
KitploitKITPLOIT
FerramentasExploitsBlog
Log in
Enviar
FerramentasExploitsBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
CVE-2024-43630-POC — POC de estouro de buffer de pilha NtCopyFileChunk | Kitploit
Ferramentas/GitHubGitHub/quasarbinary/cve-2024-43630-poc
Forensia de MemóriaAnálise de VulnerabilidadesExploraçãoEngenharia ReversaExploração de Binários
GitHubquasarbinary/cve-2024-43630-poc

CVE-2024-43630-POC

POC de estouro de buffer de pilha NtCopyFileChunk

Ver Repositório
119há 1 anoAinda não revisado

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

CVE-2024-43630-POC

Este repositório contém um POC que aciona uma gravação OOB na pilha quando executado, causando a falha do sistema. Essa vulnerabilidade é uma relíquia extremamente interessante e rara que demonstra as complexidades e peculiaridades da programação do kernel, especialmente o gerenciamento de objetos. Além disso, a vulnerabilidade afeta o kernel do Windows 11 24h2, Windows 10 22h2/21h2, mas não o Windows 11 22h2/23h2, o que só aumenta o interesse.

Corrigido em 12 de novembro de 2024

Versões do Windows afetadas

  • Windows 11 Versão 24H2
  • Windows 10 Versão 22H2
  • Windows 10 Versão 21H2
  • Windows Server 2025
  • Windows Server 2022, Edição 23H2
  • Windows Server 2022
  • Testado em: Windows 11 24h2 (x64) ntoskrnl.exe versão 10.0.26100.1742

Visão Geral da Vulnerabilidade

Uma vulnerabilidade de estouro de buffer baseada em pilha (mais tecnicamente, gravação OOB) existe na chamada de sistema do kernel do Windows NtCopyFileChunk.

NtCopyFileChunk permite que duas operações sejam realizadas em uma única chamada de sistema: leitura do arquivo de origem e gravação no arquivo de destino.

NT_COPYFILE_DATA_BUFFER é uma estrutura que contém tudo necessário para a cópia. Observe que esta estrutura foi obtida através de engenharia reversa e seu nome foi inventado. Portanto, esteja ciente disso.

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

A função se parece com algo assim em 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;

}

Em [1], podemos ver StackEvent, que é nosso objeto problemático. Em [2], se o arquivo de destino foi aberto em modo síncrono, o kernel usa um evento de pilha para aguardar sincronizadamente a operação de gravação no arquivo de destino. Para fazer isso, ele usa IopWaitForSynchronousIoEvent (não mostrado no pseudocódigo) no evento de pilha, em vez do evento passado pelo usuário. Primeiro, o kernel aguarda o evento de pilha e só então atualiza o evento passado pelo usuário. Da mesma forma, em [3], você pode ver que UserEvent de WriteIrp aponta para o evento de pilha. No entanto, e se formarmos a solicitação correta, mas passarmos um evento de entrada incorreto? Em [4], podemos ver como ele faz referência ao evento de entrada, onde podemos passar um handle inválido (por exemplo, o valor 1). E então a memória é limpa em [5]. É aqui que acontece a coisa mais interessante.

Vamos analisar a função IopFreeCopyObjectsFromDataBuffer e ver o que acontece quando o irp é limpo. Vamos dar uma olhada mais de perto em 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);
  [...]
}
Baixar ferramenta