Chamada e registro — ataque de retransmissão ao cliente WinReg RPC
Resumo executivo
Stiv Kupchik, pesquisador da Akamai, encontrou uma nova vulnerabilidade de elevação de privilégio (EoP) no cliente de registro remoto da Microsoft, CVE-2024-43532, com uma pontuação CVSS de 8,8.
A vulnerabilidade explora um mecanismo de fallback na implementação do cliente WinReg que usa protocolos de transporte obsoletos de forma desprotegida quando o transporte SMB está indisponível.
Ao explorar essa vulnerabilidade, um invasor pode retransmitir os detalhes de autenticação NTLM do cliente para os Serviços de Certificados do Active Directory (ADCS) e solicitar um certificado de usuário para utilizar em outras autenticações no domínio. Fornecemos uma prova de conceito em nosso repositório do GitHub.
A vulnerabilidade foi divulgada de forma responsável ao Microsoft Security Resource Center em fevereiro de 2024 e corrigida como parte da Patch Tuesday de outubro de 2024.
A vulnerabilidade afeta todas as versões sem correção do Windows.
Nossas descobertas também foram apresentadas na conferência de segurança de computadores No Hat.
Introdução
MS-RPC é a implementação da Microsoft do protocolo e padrão RPC (Chamada de procedimento remoto). RPC é uma forma de mecanismo de comunicação entre processos que permite que os processos exponham funcionalidades que podem ser chamadas por outros processos. Ele é um componente essencial do sistema operacional Windows e vários serviços dependem dele, desde o gerenciador de serviços até os desligamentos no wininit.
Nossa equipe fez muitas pesquisas sobre o MS-RPC, tanto pesquisas ofensivas, nas quais descobrimos um grande vetor de ataque na forma de ataques de cache, quanto pesquisas defensivas, nas quais analisamos mecanismos de segurança para ele.
Desta vez, queríamos analisar o RPC de uma perspectiva diferente. Qualquer protocolo que permita a comunicação e as operações entre computadores diferentes precisa estar envolvido com a autenticação do usuário e, de fato, o protocolo RPC oferece suporte à passagem de credenciais e à autenticação como parte de seu processo de vinculação. No entanto, onde há autenticação, há potencialidade de retransmissão de autenticação, por isso nos propusemos a encontrar oportunidades de retransmissão.
RPC, autenticação e aspectos intermediários
As sessões de RPC são operadas através de vínculos. Um aplicativo cliente se conecta a um aplicativo servidor, vincula-se à interface RPC necessária e solicita a execução de uma função específica (Figura 1).
A solicitação e a resposta do vínculo podem transportar vários campos de dados, conforme necessário para a conexão. Normalmente, se não houver autenticação envolvida, a vinculação RPC será usada simplesmente para decidir sobre a sintaxe de transferência que será usada para encapsular parâmetros de função em chamadas subsequentes.
O que falta nessa interação? Autenticação, é claro! Como o servidor pode saber a identidade do cliente e se esse cliente tem permissão para executar a ação solicitada? A resposta é: isso não acontece, a menos que o cliente tenha adicionado especificamente o contexto de segurança (autenticação) ao vínculo. Por padrão, todas as conexões RPC não são autenticadas, e nem todos os servidores RPC exigem autenticação.
Para autenticar (ou, em termos de RPC, "adicionar contexto de segurança"), o cliente precisa acrescentar outros dados à solicitação de vinculação, negociar o protocolo de autenticação (por exemplo, NTLM ou Kerberos) e inserir metadados adicionais exigidos pelo protocolo de autenticação (como nome de usuário, domínio e outros; Figura 2).
Encontrar alvos de pesquisa
A primeira ordem do dia é entender como deve ser a autenticação do ponto de vista de API. Isso é feito por meio de uma chamada a uma das funções RpcBindingSetAuthInfo* do cliente após a criação de um identificador de vínculo. Se você analisar a documentação dessas funções, notará um campo chamado AuthenticationLevel; ele indica o nível de segurança que a autenticação oferece.
A segurança com autenticação é mais do que apenas verificar se o usuário existe e está autorizado: ela também pode ser usada para evitar adulterações. Os níveis de autenticação variam desde uma simples verificação de que a conexão foi bem-sucedida (RPC_C_AUTHN_LEVEL_CONNECT) até a criptografia e assinatura completas de todo o tráfego para garantir que nada seja adulterado (RPC_C_AUTHN_LEVEL_PKT_PRIVACY). É claro que os invasores se interessam pelo primeiro nível: sem defesas no tráfego, ele pode ser adulterado.
Mas a história não é tão simples. Os ataques de retransmissão de RPC não são um conceito novo, portanto, muitos dos clientes e servidores de RPC no Windows já foram corrigidos para usar o nível mais alto de autenticação e garantir que os ataques de retransmissão não sejam bem-sucedidos. Precisaremos vasculhar o sistema operacional na esperança de encontrar algumas porções de código mais antigas que ainda estejam desprotegidas por algum motivo (Figura 3).
WinReg — um candidato promissor
Como era de se esperar, a lista de alvos potenciais que encontramos incluía menos de 5% do total de servidores e clientes RPC; a maioria simplesmente não usa mais autenticação desprotegida. Mas encontramos um candidato promissor em advapi32.dll.
advapi32.dll é um componente central da API do Windows e implementa grande parte da lógica "avançada" do Windows (como o próprio nome sugere). Ele exporta mais de 800 funções de vários campos: registro de eventos, criptografia, WMI e mais.
Para nossos objetivos, descobrimos que, em algumas ocasiões, a função interna BaseBindToMachine chama RpcBindingSetAuthInfoA com um nível de autenticação de RPC_C_AUTHN_LEVEL_CONNECT, que é o que queremos. BaseBindToMachine é chamada pela função exportada (embora não documentada) RegConnectRegistryExW (Figura 4), se receber um caminho UNC para um nome de computador.
Ao analisar a BaseBindToMachine, vemos que, na verdade, ela contém chamadas para RpcBindingSetAuthInfoW e RpcBindingSetAuthInfoA. O primeiro é usado com segurança, com o nível de autenticação RPC_C_AUTHN_LEVEL_PKT_PRIVACY, enquanto o segundo usa o nível de autenticação RPC_C_AUTHN_LEVEL_CONNECT, que pode ser retransmitido, pois não verifica a autenticidade nem a integridade da conexão (Figura 5).
Só precisamos descobrir por que há duas chamadas conflitantes. Ao analisar a lógica da função, vemos que ela tem uma variável de ponteiro de função e uma matriz de funções (Figura 6). Essas funções definem as informações de vinculação RPC para usar um transporte RPC específico; por padrão, ele tenta usar SMB e pipes nomeados, mas, se falha, ele tenta se vincular por SPX, TCP/IP e outros.
Por algum motivo, quando ele volta a usar qualquer outro protocolo além do SMB, ele usa o RpcBindingSetAuthInfoA para definir o nível de autenticação como Connect, que não é protegido.
O fallback para TCP/IP é bastante promissor, pois significa que podemos usar o método de autenticação desprotegido para retransmitir o tráfego usando um ataque machine-in-the-middle sem que o cliente perceba. Embora isso também seja possível com os outros protocolos de transporte, eles são bastante obsoletos, portanto, pode não ser realista encontrá-los em uma rede moderna (e usá-los pode gerar algumas preocupações). O TCP/IP é muito mais comum como transporte RPC, portanto, não deve haver problema, mesmo em uma configuração de equipe vermelha.
É importante saber que tanto BaseBindToMachine como RegConnectRegistryExW aceitam um sinalizador como argumento que impede o comportamento de fallback, mas a função básica RegConnectRegistryW chama RegConnectRegistryExW sem a presença desse sinalizador.
O processo de retransmissão
A retransmissão é bastante simples, pois a retransmissão NTLM é uma técnica comum. A maior parte da lógica de que precisamos já está implementada no ntlmrelayx do Impacket, que é o que mais usaremos.
Criação do servidor de retransmissão RPC
O que falta ao ntlmrelayx é um servidor TCP/IP RPC, pois ele implementou apenas um servidor SMB. Dessa forma, precisaremos criar nosso próprio servidor de retransmissão, que rejeita o pipe winreg nomeado para acionar um fallback para a função de vinculação TCP/IP.
Há três pontos críticos que precisamos implementar:
O mapeador de pontos de extremidade RPC
A solicitação de vinculação RPC com NTLM
O desafio NTLM
O mapeador de pontos de extremidade RPC é responsável por traduzir os UUIDs da interface RPC em seus respectivos pontos de extremidade, que, no caso do transporte TCP/IP, seria um número de porta. Ao contrário do SMB, em que os pontos de extremidade são pipes nomeados que são exclusivos e podem ser conhecidos antecipadamente, os pontos de extremidade TCP usam portas efêmeras, sendo necessária outra camada de tradução.
A parte crítica são os problemas relacionados ao NTLM. A forma como a vinculação RPC funciona com NTLM é que uma mensagem de negociação NTLM é enviada durante a solicitação de vinculação, e um desafio NTLM é enviado com a resposta de vinculação. Por fim, o cliente precisa enviar outra mensagem, chamada AUTH3, com a resposta do desafio (Figura 7).
Basta analisar as mensagens correspondentes em nosso servidor RPC para retransmitir. Quando vemos uma mensagem de negociação NTLM em uma mensagem de associação, abrimos nossa própria conexão com o servidor de autenticação de destino e também solicitamos a autenticação via NTLM. Depois, basta capturar o desafio que o servidor nos envia, retransmiti-lo à vítima e retransmitir a resposta de volta ao servidor para obter nossa própria sessão autenticada.
Tudo que precisamos considerar é para qual servidor queremos retransmitir a autenticação.
Retransmissão de RPC para RPC
A ideia imediata seria fazer a retransmissão para outro servidor RPC em um computador diferente, como o gerenciador de serviços ou o agendador de tarefas, e obter uma execução remota de código dessa forma. O problema com isso, no entanto, é que ninguém mais usa autenticação desprotegida via RPC, então não podemos retransmitir para nenhum servidor RPC de alto perfil. (Essa falta de autenticação desprotegida via RPC é o mesmo motivo pelo qual tínhamos alvos de pesquisa limitados.)
Os servidores RPC do gerenciador de serviços e do agendador de tarefas exigem RPC_C_AUTHN_LEVEL_PKT_PRIVACY, que criptografa todo o tráfego com o hash NTLMv2 do cliente, que não conhecemos nem mesmo com a retransmissão. Em vez disso, temos que olhar por um ângulo diferente.
De RPC para ADCS
Felizmente, o pessoal da SpecterOps trabalhou muito no ADCS, especificamente na retransmissão de NTLM para o ADCS. Isso também está implementado no Impacket por padrão, portanto, tudo que precisamos fazer é passar nossa sessão autenticada para o módulo HTTPAtack do Impacket e deixar a mágica acontecer.
O servidor da Web HTTP do ADCS não exige nenhuma segurança e é vulnerável a ataques de retransmissão. Ao explorar isso, depois de nos autenticarmos nele, podemos solicitar um certificado de usuário, que pode ser usado por si só para autenticar, sem termos que passar pelo problema de retransmitir a autenticação novamente (Figura 8).
Usamos esse certificado para autenticar o serviço LDAP no controlador de domínio e criar um novo administrador de domínio persistente no domínio comprometido (Figura 9).
Possível impacto
Uma função no advapi não é interessante por si só; ela só tem impacto se outra coisa a estiver usando. Uma rápida pesquisa de importações de RegConnectRegistryExW ou RegConnectRegistryExA não mostra nada em um controlador de domínio atualizado, mas uma pesquisa por RegConnectRegistryW revela muitos candidatos em potencial, como certutil e certsrv (AD CS), EFS, DFS e outros.
Detecção
O serviço de registro remoto não está ativado por padrão em todos os computadores Windows. É possível detectar seu status usando o seguinte osquery:
SELECT display_name, status, start_type, pid FROM services WHERE name='RemoteRegistry'
Isso, no entanto, não protege contra o CVE-2024-43532, pois é um problema de cliente. Os resultados da consulta devem gerar casos de uso reais do registro remoto na organização que talvez seja necessário levar em conta ao fortalecer seus sistemas.
Você pode usar a seguinte regra YARA para detectar clientes que usam qualquer uma das WinAPI vulneráveis:
import "pe"
rule winreg_client_import {
meta:
description = "Detect binaries that rely on RegConnectRegistry"
author = "Stiv Kupchik with Akamai Technologies"
condition:
pe.is_pe and (
pe.imports(pe.IMPORT_ANY, "advapi32.dll", "RegConnectRegistryA")
or pe.imports(pe.IMPORT_ANY, "advapi32.dll", "RegConnectRegistryW")
or pe.imports(pe.IMPORT_ANY, "advapi32.dll", "RegConnectRegistryExA")
or pe.imports(pe.IMPORT_ANY, "advapi32.dll", "RegConnectRegistryExW")
)
}
Os usuários da Akamai Guardicore Segmentation também podem criar regras de política para o tráfego que chega ao serviço RemoteRegistry (Figura 10).
Também é possível usar o ETW (Event Tracing for Windows) para monitorar o tráfego RPC nos lados cliente e servidor da comunicação. Discorremos sobre esse tópico em nossa apresentação na Black Hat 2023 e na postagem no blog relacionada. Os usuários podem usar nossa ferramenta de código aberto de visibilidade de RPC para rastrear chamadas de RPC e filtrar o UUID {338cd001-2244-31f1-aaaa-900038001003} da interface de RPC WinReg.
Conclusão
Embora o protocolo RPC e o MS-RPC tenham sido criados com a segurança em mente, podemos ver claramente a evolução dos princípios de segurança ao longo do tempo analisando várias implementações na interface RPC. Embora a maioria dos servidores e clientes de RPC seja segura atualmente, é possível, periodicamente, descobrir vestígios de implementações desprotegidas em graus variados.
Nesse caso, conseguimos realizar a retransmissão NTLM, que é uma classe de ataques que pertence ao passado. Isso só prova que as defesas de rede devem ser tão completas quanto possível, pois nunca se sabe qual interface antiga ainda está exposta ou em execução.
Cronograma de divulgação
01/02/2024 — Vulnerabilidade divulgada ao MSRC
25/04/2024 — Relatório fechado como problema de documentação
17/06/2024 — Relatório reaberto com melhor PoC e explicação
08/07/2024 — Vulnerabilidade confirmada
08/10/2024 — Vulnerabilidade corrigida
19/10/2024 — Postagem no blog publicada