Debug ou falha de segurança?

21 de August de 2007 - Fernando Roberto

A um tempo atrás, escrevi um post que fala sobre como substituir drivers defeituosos utilizando o WinDbg. Uma técnica excelente para substituir drivers, que por algum problema, impedem a máquina de iniciar. Mas para conseguir desfrutar de toda essa facilidade, é necessário que haja uma conexão do sistema com o Kernel Debugging. Isso nos leva ao meu último post, que fala justamente sobre como habilitar este recurso bastando apenas estar em frente à máquina, e no pior caso, ter uma porta serial. Tudo isso é muito cômodo, afinal, nunca sabemos onde um problema desconhecido pode acontecer, e muito menos, em qual máquina vai acontecer. Mas essa praticidade toda tem um preço. O efeito colateral disso é que qualquer um pode depurar o Kernel de uma máquina sem ao menos ter qualquer conta válida nela. Na verdade, um notebook, um cabo e uma porta serial já são armas mais que suficientes para desmontar a sengurança do sistema. Sem senha, sem cabo de rede, sem brute-force. Apenas Kernel Debugging.

Instalando um driver pela serial

Drivers são um tipo de software que precisa ser confiável e muito bem escrito. Afinal de contas, eles rodam no nível mais baixo do sistema. Com drivers fica realmente muito fácil enganar o sistema, já que boa parte do sistema roda sobre serviço oferecidos pelo Kernel. Os posts acima me motivaram a escrever uma pequena prova de conceito que tem por finalidade injetar um driver que se instala no sistema, este driver, por sua vez, extrai e instala um programa no Windows que será executado a cada logon no sistema. Para tanto, precisaremos apenas de uma máquina que possa ser depurada. Meu último post mostra que essa condição não é tão difícil de ser encontrada. Quer testar? Qual a percentagem de computadores à sua volta que possuem portas seriais?

Passo a passo

Este é mais um daqueles posts que vêm com código disponível para download. Todo o procedimento demonstrado aqui pode ser reproduzido e modificado pelos leitores deste blog. Este não é um blog especializado em ataques ao Windows e meu objetivo aqui é puramente didático. Não vou explicar cada linha do código de exemplo, caso contrário, esse post ficaria muito extenso. Entretanto, me disponho a responder quaisquer dúvidas a respeito. A figura abaixo enumera os passos a serem tomados para atingir nosso objetivo.

  1. O primeiro passo acontece durante a compilação do driver de exemplo. O solution disponível possui três projetos. O primeiro projeto é o da aplicação a ser injetada. Neste caso, uma aplicação Win32 que apenas mostra uma mensagem e termina. Vamos nos referir a esta aplicação como MyFile.exe. A Run Time do C/C++ foi removida para obtermos a menor aplicação possível. Isso vai contar bastante quando você tiver que transferir tudo por um cabo serial a 19200. O segundo projeto é apenas uma ferramenta. A partir do arquivo MyFile.exe já compilado, esta ferramenta gera um arquivo de header que cria uma variável do tipo array de caracteres com o corpo do arquivo passado como linha de comando. Este não é o método mais avançado de se fazer um Self-Extractor, mas é suficiente para nosso objetivo aqui. Vamos chamar esta ferramenta de HeaderFile.exe. Quando o driver é compilado, este inclui o arquivo de header e ganha uma variável com a aplicação a ser injetada. Vamos chamar nosso driver de MapInject.sys. O driver neste exemplo é compilado utilizando o ddkbuild.cmd com Visual Studio 2005. Mais detalhes a respeito neste post.

    /****
    ***     WinMain
    **
    **      Não faz quase nada e não usa a Run Time do C/C++
    **      para evitar código longo.
    */
     
    int WINAPI WinMain(HINSTANCE   hInstance,
                       HINSTANCE   hPrevInstance,
                       LPSTR       lpCmdLine,
                       int         nShowCmd)
    {
        //-f--> É só isso mesmo...
        MessageBox(NULL,
                   L"A serial port was found",
                   L"DriverEntry.com.br",
                   MB_OK | MB_ICONEXCLAMATION);
     
        return 0;
    }
  2. Utilizando as técnicas de mapeamento de drivers demostradas neste post, podemos fazer com que nosso driver possa ser carregado no lugar de qualquer driver pré-existente no sistema. Obviamente nosso driver não vai realizar todos os passos que o driver sobrescrito deveria realizar, deste modo, não vamos escolher um driver que realize tarefas essenciais à carga do sistema, tais como drivers de disco, de vídeo ou algo assim. Particularmente escolhi utilizar o driver da porta paralela Partport.sys, que é um driver que existirá em qualquer instalação básica de Windows e não vai nos fazer tanta falta enquanto brincamos por aqui. Este também não é nenhum driver do tipo Boot, que no caso do Windows XP, seria necessário ter um Loader especial para poder ser mapeado pelo Debugger.

    map 
    \Windows\System32\drivers\parport.sys 
    Z:\MapInject\Driver\objfre_wnet_x86\i386\MapInject.sys
  3. Com o driver mapeado e carregado pelo sistema, basta um pouco de boa vontade para poder pintar e bordar com o sistema. Quando nosso driver é carregado pela primeira vez, este é carregado no lugar do Parport.sys. Nesta condição, nos instalamos no sistema. Certas coisas nunca mudam. Para instalar um driver no Windows plataforma NT basta criar uma chave e poucos valores no registro do sistema como descrito neste post. Isso ainda funciona no Windows Vista. Nosso driver faz isso neste passo.

  4. Feitas as modificações no registro, agora temos que renomear nosso driver, que pelo fato de ter sido mapeado, ganhou o nome do driver nativo do sistema. Assim, uma função troca o nome do driver de Parport.sys para MapInject.sys. Poderiamos permanecer instalados no sistema da maneira que fomos mapeados se quizéssemos, mas perderiamos nosso lugar caso o verdadeiro driver fosse restaurado.

  5. Como sabem, nosso driver possui uma variável que contém todo o corpo de nossa aplicação. Assim, fica muito simples extrair a aplicação e salvá-la em disco. A pasta System32 vem bem a calhar como destino para nossa aplicação. Como estamos rodando em conta de sistema neste momento, não teremos problemas em fazer isso.

  6. Agora que nossa aplicação foi extraída, temos que fazer com que ela seja executada automagicamente. Alguns de vocês devem saber que não existem meios documentados ou mesmo suficientemente confiáveis de se criar um processo a partir do Kernel, mas no registro existem vários lugares onde poderíamos escrever e fazer com que um processo já existente no Windows execute a nossa aplicação. Uma das mais clássicas chaves do registro que permite isso é a Run do Windows Explorer, mas como mostra este aplicativo, ainda existem outras tantas chaves a serem escolhidas. Quando o Logon é realizando no sistema, o Shell enumera esta chave e executa cada linha na conta do usuário que fez o logon. Isso vai fazer nosso programa ser chamado.

Colocando para funcionar

Mais uma vez, uma máquina virtual nos cai como uma luva para este tipo de brincadeira. Se você não sabe como fazer Kernel Debugging utilizando uma máquina vitual, este post poderá te ajudar. Tudo é muito simples depois que o driver já está codificado. A única coisa necessária para realizar o teste é configurar um mapeamento que substitua o driver Parport.sys pelo MapInject.sys como mostra o arquivo de map acima. Depois disso, é só esperar o sistema subir e pronto. Qualquer usuário que efetuar o logon no sistema verá a mensagem do nosso programa. Um ponto a ser notado é que mesmo se o usuário for esperto o suficiente para encontrar o arquivo MyFile.exe, sua chamada no registro e apague ambos, os mesmos serão recriados quando o driver MapInject for iniciado a cada Boot do sistema. Para interromper esse processo, basta remover o driver MapInject do sistema.

Senha? Pra quê?

O Windows protege seus mais importantes recursos da maioria dos usuários, permitindo apenas que administradores da máquina tenham acesso às configurações que podem comprometer a estabilidade do sistema. Essa frase até que é “bunitinha” e chega até a gerar um certo conforto aos adminitradores de muitas e muitas máquinas. Mas a vida é uma caixinha de surpresas, e numa bela manhã de sol, um post é publicado em um site de RootKits dando dicas de como logar em um sistema em Debug sem qualquer senha. Recentemente, um outro post surgiu a respeito e não vou repetir tudo aqui. Mas posso afirmar que esta mesma técnica ainda funciona com o Windows Vista. De fato, se você puder logar no sistema sem utilizar qualquer senha, não será necessário mapear um driver para fazê-lo rodar nesta máquina. Basta logar como administrador, instalá-lo e pronto. Mas confesso que foi no mínimo divertido escrever esta prova de conceito, e além do mais, os fontes ainda poderão servir de exemplo para algumas tarefas que você queira fazer em Kernel Mode.

Uma possível solução? Talvez deixar sua porta serial desabilidata na BIOS, que deveria estar protegida com senha, seja alguma coisa a ser feita. Mas não há muito que se possa fazer quando se tem acesso físico à maquina.

Chega, já escrevi demais.
[]s.

MapInject.zip

2 Responses to “Debug ou falha de segurança?”

  1. Pra lá de interessante este artigo sobre o uso do map do WinDbg integrado ao boot em modo Debug. Uma senha na BIOS poderia ser quebrada ao zerar a sua memória em máquinas desktop. Em laptops o esquema já é um pouco diferente, e cada um tem seu jeito. Além de que, se você utilizar o modo de hibernação de seu Windows (eu faço isso) o acesso à BIOS por atalho é negado.

  2. […] This post was mentioned on Twitter by Wagner Elias, Wagner Elias and Tiago Oliveira, Fernando Roberto. Fernando Roberto said: Quer dizer então que você não sabia que é possível invadir uma máquina Windows pela porta de debug? http://bit.ly/91bpWO […]

Deixe um comentário