COVIL HACKER

, ! .


» COVIL HACKER » C/C++/C#/.NET/Java » Artigo Red Team Tactics: Escrevendo Drivers do Kernel do Windows para


Artigo Red Team Tactics: Escrevendo Drivers do Kernel do Windows para

1 2 2

1

Introdução

Esta postagem, como o título sugere, se concentrará em escrever drivers de kernel do Windows para persistência estendida. Como o tema é bastante complexo, resolvi dividir o projeto em três ou quatro partes. Este é o primeiro artigo de uma série e fornecerá as informações básicas que você precisa saber para começar a desenvolver o kernel. Inclui configurar um ambiente de desenvolvimento, configurar a depuração remota do kernel e escrever seu primeiro driver "Hello World".

Se tudo correr conforme o planejado, as postagens subsequentes da série focarão nos seguintes tópicos:

Parte 2: Criando um acionador de rede para controlar remotamente um driver de kernel
Parte 3: Criando processos a partir do kernel

Você deve acabar com um driver que pode ser executado remotamente usando um pacote de rede personalizado para criar processos altamente privilegiados no sistema de destino. Dito isso, vamos começar!

Isenção de responsabilidade

Estou escrevendo estas postagens de blog enquanto estou pesquisando e avançando neste tópico. Portanto, pode levar algum tempo para postar postagens subsequentes. Obrigado por sua paciência e sinta-se à vontade para entrar em contato comigo se encontrar algum bug.

Requisitos

Para começar a desenvolver drivers de kernel, primeiro você precisa configurar um ambiente de laboratório. Aqui estão os requisitos mínimos necessários para começar:

Processador de 64 bits (4 ou mais núcleos)
8 GB de RAM
96 GB de memória disponível
Conta da Microsoft (para Visual Studio)
Software de virtualização
Usarei o VMWare Workstation 16, mas qualquer software compatível com virtualização pode ser usado.
Windows 10 ou 11 ISO
Como alternativa, você também pode usar a imagem de teste MSEdge.

Configuração do laboratório

2 máquinas virtuais (VMs) são necessárias para a configuração do laboratório. Um para desenvolvimento e outro para teste de driver de kernel. Se você planeja trabalhar neste projeto em uma máquina Windows, pode fazer apenas uma VM de teste. No entanto, isso exigirá que você instale todas as ferramentas de desenvolvimento na máquina host, o que eu não recomendaria.

Se você está se perguntando por que precisa de uma VM de teste separada, há vários motivos.

- A depuração eficiente do kernel requer uma VM de teste separada, pois a depuração local do kernel tem muitas limitações, como não ser capaz de definir pontos de interrupção adequados.

-Devido à natureza crítica do kernel, pequenos bugs no código do driver podem causar telas azuis da morte (BSOD) no sistema porque o kernel, ao contrário dos processos do usuário, usa um único espaço de memória para todos os seus drivers e outros recursos .

Acabou, vamos sujar as mãos.

Rede de laboratório

Antes de começarmos a configurar as máquinas virtuais, vamos configurar uma rede de teste.

Primeiro, abra o editor de rede virtual VMWare como administrador:

https://forumupload.ru/uploads/001b/c9/09/2/t326483.png

Em seguida, clique em Adicionar rede... e selecione qualquer rede não atribuída (no meu caso VMNet19 ):

https://forumupload.ru/uploads/001b/c9/09/2/t699290.png

Depois de clicar em OK, você deve retornar ao menu principal e ver a rede que acabou de criar em sua lista de redes. Selecione-o e configure-o com um adaptador somente de host junto com as informações de sub-rede apropriadas.

https://forumupload.ru/uploads/001b/c9/09/2/t345755.png

Para este artigo, trabalharei com uma sub-rede de 10.10.20.0/24, onde a VM de desenvolvimento terá um endereço IP de 10.10.20.2 e a VM de teste terá um endereço IP de 10.10.20.3 Nota Como

um

host- somente a rede não fornece acesso à Internet para máquinas virtuais, é importante atribuir dois adaptadores de rede diferentes para ambas as máquinas virtuais, como o adaptador NAT e o adaptador que acabamos de criar. A rede NAT fornecerá acesso à Internet para ambas as VMs e a rede somente host será usada para comunicação entre elas.

Um benefício dessa configuração é que, uma vez configuradas as duas máquinas, podemos remover o adaptador NAT de ambas as VMs para obter uma rede isolada sem acesso de saída à Internet. Isso elimina o risco de enviar uma amostra acidentalmente para o antivírus e permite também alterar as configurações de firewall das máquinas virtuais sem medo de ataques da rede local.

Isenção de responsabilidade

A postagem do blog cobre apenas a instalação dos pré-requisitos para o desenvolvimento do kernel. O leitor deve concluir a configuração instalando máquinas virtuais Windows e configurando endereços IP estáticos.

VM para desenvolvimento

A VM de desenvolvimento é a máquina que fará a maior parte do trabalho, por isso recomendo fornecer pelo menos 4 núcleos, 6 GB de RAM e 64 GB de armazenamento. Pessoalmente, usarei o Windows 11 22H2, mas o Windows 10 funcionará bem. Com isso em mente, vamos passar para a configuração real.

Visual Studio 2022

Por motivos óbvios, você precisará instalar o Visual Studio. Ao instalar o Visual Studio, certifique-se de selecionar o desenvolvimento de desktop com a carga de trabalho C++ e as bibliotecas de mitigação Spectre. Se você não encontrar as bibliotecas de proteção, procure-as na guia "Componentes individuais".

https://forumupload.ru/uploads/001b/c9/09/2/t531995.png

SDK do Windows

Também precisamos instalar o SDK (Software Development Kit) do Windows. Este SDK contém toda a documentação, arquivos de cabeçalho, bibliotecas, amostras e ferramentas necessárias para desenvolver aplicativos para Microsoft Windows.

Nada mais precisa ser dito. Depois de começar a instalar o SDK, basta clicar nos prompts de instalação até terminar.

Windows WDK

Além do SDK, também precisamos do Windows Driver Kit (WDK). O WDK é usado para desenvolver, testar e implantar drivers para Windows. Ao instalar o WDK, certifique-se de instalar a extensão Visual Studio Driver Kit para Windows.

Observação. O Visual Studio deve ser fechado para que a extensão seja instalada corretamente.

https://forumupload.ru/uploads/001b/c9/09/2/t517429.png

WinDbg

Também precisamos de um depurador. Neste caso, estaremos utilizando o depurador do Windows ( WinDbg Preview ), que é uma ferramenta essencial para o desenvolvimento do kernel. Ele será usado principalmente para solucionar problemas do driver do kernel em caso de travamento ou comportamento inesperado.

Compartilhamento de rede (opcional)

No Visual Studio, temos a capacidade de criar os chamados eventos pós-compilação, que podem executar muitos comandos úteis para nós depois de compilarmos nosso driver. Um desses eventos pós-compilação que você pode criar para simplificar o processo de desenvolvimento é copiar o driver compilado para uma pasta (configurada como um compartilhamento de rede). Esse compartilhamento de rede será usado para armazenar todos os drivers integrados que a VM de teste pode acessar.

Se você configurou seu laboratório de acordo com minhas recomendações, pode evitar o incômodo de configurar um compartilhamento com os controles de acesso e permissões adequados. Basta dar permissões RWX a todos e pronto.

No final, sua configuração deve ficar mais ou menos assim:

https://forumupload.ru/uploads/001b/c9/09/2/t268242.png

Testando a VM

As especificações da máquina virtual que está sendo testada realmente não importam. Apenas certifique-se de fornecer energia suficiente. Por exemplo, minha VM de teste foi configurada com 2 núcleos, 4 GB de RAM e 32 GB de armazenamento. Novamente, ele está executando o Windows 11 22H2, mas você não deve ter problemas se estiver executando o Windows 10.

Dados de configuração de inicialização (BCD)

Em seguida, precisamos configurar o BCD usando o comando bcdedit. Abra um prompt administrativo e digite os seguintes comandos:

https://forumupload.ru/uploads/001b/c9/09/2/t450115.png

O primeiro comando ativa a depuração do kernel e o segundo ativa a assinatura de teste. A depuração do kernel nos permite depurar o kernel da máquina, enquanto a assinatura de teste desativa a verificação da assinatura do driver, permitindo carregar e testar nossos drivers personalizados sem ter que cumprir as rígidas regras de segurança de driver da Microsoft.

Observe que ativar uma assinatura de teste resultará na exibição de uma marca d'água de aviso no canto inferior direito da máquina:

https://forumupload.ru/uploads/001b/c9/09/2/t634550.png

Finalmente, precisamos habilitar a depuração remota. Para fazer isso, podemos usar um comando semelhante ao abaixo:

https://forumupload.ru/uploads/001b/c9/09/2/t62308.png

Apenas tome cuidado para definir a propriedade hostip para o endereço IP da VM de desenvolvimento e defina a porta para um valor entre 50000 e 50039. Além disso, tome cuidado para não misturar os endereços IP das máquinas de desenvolvimento e teste. Nesse caso, queremos inserir o endereço IP da máquina de desenvolvimento para que ela possa se conectar à porta de depuração.

Se tudo correu como esperado, você deve ver a chave gerada exibida no console:

https://forumupload.ru/uploads/001b/c9/09/2/t190537.png

O significado da depuração remota será explicado posteriormente. Por enquanto, certifique-se de reservar a chave gerada.

Firewall

Para evitar interrupções durante a depuração remota, desativaremos o firewall. Para fazer isso, você pode usar a GUI ou executar o seguinte comando em um prompt administrativo:

https://forumupload.ru/uploads/001b/c9/09/2/t258521.png

Como alternativa, você também pode colocar a porta de depuração na lista de permissões por meio das configurações, se preferir não desabilitar o firewall completamente.

Depuração do filtro de impressão

Para garantir que todas as mensagens de depuração do kernel sejam enviadas para o depurador, você deve configurar o filtro de impressão de depuração. Você pode usar o seguinte comando:

reg add "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Debug Print Filter" /v Padrão /t REG_DWORD /d 0xf

Observe que você deve reiniciar o computador para que essa alteração entre em vigor. Não importa se você reiniciar a máquina virtual agora ou depois de configurá-la. Apenas lembre-se de reiniciá-lo em algum momento.

Carregador de driver OSR

OSR Driver Loader é a ferramenta que usaremos para carregar ou "executar" nosso driver. Uma das principais vantagens de usar o bootloader OSR em vez de configurar manualmente os serviços do Windows é que ele fornece uma interface gráfica de usuário amigável que facilita o uso.

Melhorias na qualidade de vida (opcional)

Aqui estão algumas dicas adicionais para economizar tempo:

Se você configurar uma pasta de rede que contenha drivers integrados, poderá montá-la e adicioná-la a um local conveniente, como sua área de trabalho.

Como você provavelmente encontrará uma tela azul inúmeras vezes ao testar um driver, pode ser útil habilitar o login automático sem senha e tirar um instantâneo de uma máquina virtual em execução para que você possa facilmente voltar a ela no caso de uma falha grave.

Desenvolvimento do driver

Finalmente podemos iniciar o processo de desenvolvimento!

Anexando o WinDbg

Com a depuração de kernel remota habilitada, você poderá se conectar remotamente ao kernel da VM em teste a partir da VM de desenvolvimento.

Para fazer isso, abra sua máquina de desenvolvimento e execute o WinDbg. Vá para o menu principal e selecione Anexar ao kernel:

https://forumupload.ru/uploads/001b/c9/09/2/t458729.png

No submenu Net, insira as informações sobre a VM em teste:

https://forumupload.ru/uploads/001b/c9/09/2/t169410.png

No meu caso, o endereço IP da VM em teste é 10.10.20.3, a porta é 50039 e a chave é o valor que eu disse para você salvar anteriormente (sua chave será diferente).

Após clicar em OK, você deve estar conectado ao kernel da máquina de teste:

https://forumupload.ru/uploads/001b/c9/09/2/t446721.png

A partir de agora, você pode definir pontos de interrupção, verificar endereços de memória e muito mais. Esteja ciente de que, se você definir um ponto de interrupção, a VM que você está testando pode entrar em um estado suspenso (congelado). Você precisará remover todos os pontos de interrupção para que a máquina virtual seja retomada. Além disso, o WinDbg também será usado para testar chamadas de impressão de depuração de nosso driver. Como os drivers não possuem um console, usar um depurador para visualizar as mensagens é a única opção disponível para nós.

Criando o projeto

Agora vamos criar nosso primeiro projeto de código do kernel! Comece abrindo o Visual Studio e escolhendo Create a new project. Em seguida, localize o modelo Kernel Mode Driver, Empty (KMDF).

https://forumupload.ru/uploads/001b/c9/09/2/t844374.png

Confirme sua escolha e nomeie o projeto HelloWorld. Depois que o Visual Studio carregar a solução, clique com o botão direito do mouse em Arquivos de origem, clique em Adicionar e, por fim, em Novo item..., .

https://forumupload.ru/uploads/001b/c9/09/2/t662772.png

Uma janela será aberta solicitando que você selecione um elemento para adicionar ao projeto. Selecione Arquivo C++ (.cpp) e nomeie-o como Driver.c. Na verdade, você pode nomeá-lo como quiser, apenas certifique-se de que o arquivo tenha uma extensão .c.

https://forumupload.ru/uploads/001b/c9/09/2/t314481.png


Olá Mundo!

Estamos ficando bons! Nesta seção, finalmente começaremos a escrever o driver.

Aviso

Para escrever drivers de kernel, você deve ter um bom conhecimento da linguagem de programação C. Se você não estiver familiarizado com C, é recomendável que você atualize suas habilidades antes de prosseguir.

Todos os drivers requerem uma sub-rotina DriverEntry que é responsável pela inicialização do driver. Pense nisso como uma função principal em programas C padrão.

Podemos criar um procedimento DriverEntry simples para Driver.c que se parece com isto:

1

#include <ntddk.h>                  // Kernel header

NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT driverObject, _In_ PUNICODE_STRING registryPath) {
    KdPrint(("Hello World!\n"));    // Printf "equivalent"
                                    //  - Only prints data when build settings are set to 'Debug',
                                    //    otherwise doesn't do anything
    return STATUS_SUCCESS;
}



Além da rotina de entrada, também precisamos de algo chamado rotina de "saída" que é chamada toda vez que o driver é descarregado. A principal diferença entre um procedimento de saída e um procedimento de entrada é que um procedimento de saída não possui um nome predefinido. Portanto, precisamos especificar manualmente o procedimento de descarregamento ao inicializar o driver.

No meu caso, criei um novo procedimento de saída chamado DriverUnload. O arquivo Driver.c atualizado após adicionar a sub-rotina deve ficar assim:

#include <ntddk.h>

NTSTATUS DriverUnload(_In_ PDRIVER_OBJECT driverObject) {
    KdPrint(("Goodbye World!\n"));
    return STATUS_SUCCESS;
}

NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT driverObject, _In_ PUNICODE_STRING registryPath) {
    KdPrint(("Hello World!\n"));
    driverObject->DriverUnload = DriverUnload; // Set the unload function to DriverUnload

    return STATUS_SUCCESS;
}

Isso é praticamente tudo sobre programação! Há apenas um problema que precisamos resolver. Se você tentar construir a solução agora, ela falhará com uma mensagem de erro um tanto irritante:

https://forumupload.ru/uploads/001b/c9/09/2/t540452.png

Como o kernel é um componente crítico do sistema operacional e qualquer problema de driver pode ter sérias consequências, a Microsoft adotou uma abordagem cautelosa para o desenvolvimento. Portanto, as soluções configuradas com o padrão Kernel Mode Driver Framework ( KMDF ) sempre tratam quaisquer avisos como erros. Embora esse comportamento possa ser desabilitado, não é recomendável fazê-lo porque quanto mais complexo o driver se torna, mais difícil será solucionar o problema.

Em vez disso, alteraremos nosso código para corrigir o erro. Os avisos indicam a presença de dois parâmetros de função sem referência: driverObject e RegistryPath. Você pode usar esses parâmetros em algum lugar do seu código ou usar a macro UNREFERENCED_PARAMETER() para marcá-los como "não usados".

Com esta configuração, o driver deve estar finalmente completo:

#include <ntddk.h>

NTSTATUS DriverUnload(_In_ PDRIVER_OBJECT driverObject) {
    UNREFERENCED_PARAMETER(driverObject);

    KdPrint(("Goodbye World!\n"));
    return STATUS_SUCCESS;
}

NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT driverObject, _In_ PUNICODE_STRING registryPath) {
    UNREFERENCED_PARAMETER(registryPath);
   
    KdPrint(("Hello World!\n"));
    driverObject->DriverUnload = DriverUnload;

    return STATUS_SUCCESS;
}
3

A partir daqui, certifique-se de definir a arquitetura de destino para x64 e criar o driver no modo de depuração. Se você seguiu todas as etapas corretamente, agora você deve ter o primeiro driver de kernel HelloWorld.sys!

Observação

Se você estiver recebendo um erro semelhante ao DriverVer definido para a data incorreta ao tentar criar seu projeto, não se preocupe. Basta ir nas propriedades do projeto e encontrar a configuração do Inf2Cat. Encontre a linha perguntando se você deseja usar a hora local e selecione Sim (/uselocaltime).

Carregando o driver

Agora que o driver está compilado, precisamos transferi-lo para a VM de teste usando o compartilhamento de rede que criamos anteriormente. Se você não criou uma pasta de rede, encontre uma forma alternativa de transferir o driver.

Para fins de demonstração, coloquei o driver na minha pasta Documentos. Para carregá-lo, usarei o aplicativo OSRLoader.


https://forumupload.ru/uploads/001b/c9/09/2/t411394.png

Você não precisa configurar nada além de especificar a localização do seu driver. Observe, no entanto, que ao carregar um driver pela primeira vez, você precisará registrá-lo como um serviço. Para fazer isso, clique no botão Cadastrar Serviço. Você receberá um alerta que informará se a ação foi bem-sucedida ou não. Se isso foi bem-sucedido, agora você pode clicar no botão Iniciar serviço para carregar o driver e Parar serviço para descarregá-lo!

Com o serviço iniciado e o driver carregado, vamos verificar o WinDbg para garantir que o driver esteja funcionando corretamente. Lembre-se de que programamos o driver para imprimir "Hello World" na inicialização e "Goodbye World" no upload.


https://forumupload.ru/uploads/001b/c9/09/2/t204239.png

Perfeito! Isso é exatamente o que queríamos!

Conclusão

Obrigado por ler até o final do post! Agradeço por ter dedicado seu tempo para lê-lo e espero que o ache útil e informativo. Lembre-se de que esta foi apenas a primeira parte da série, portanto, fique atento para a próxima! Se tudo correr bem da minha parte, a próxima parte deve abranger o processo de criação de um driver que pode ser ativado remotamente usando pacotes de rede personalizados

0

2


» COVIL HACKER » C/C++/C#/.NET/Java » Artigo Red Team Tactics: Escrevendo Drivers do Kernel do Windows para


|