Yuval Gordon Investigador de Segurança | Microsoft

Como potenciais atacantes podem obter persistência privilegiada em um DC por meio de DnsAdmins

A equipa de investigação da Semperis expandiu recentemente uma investigação anterior que mostrava um abuso de funcionalidades no ambiente do Windows Active Directory (AD), em que os utilizadores do grupo DnsAdmins podiam carregar uma DLL arbitrária num serviço DNS em execução num controlador de domínio. Yuval Gordon, da equipa de investigação da Semperis, expandiu esta investigação para mostrar como um problema com a técnica anterior pode ser ultrapassado e para mostrar que um adversário pode utilizar esta táctica para deixar uma backdoor não detectada no Active Directory de uma empresa - um risco de segurança significativo.

Numa publicação no Medium em 2017, os investigadores de segurança mostraram como os utilizadores do grupo DnsAdmins podiam utilizar uma "funcionalidade" no protocolo de gestão do Microsoft DNS para fazer com que o serviço DNS carregasse qualquer DLL. Este serviço é executado nos Controladores de Domínio como NT AuthoritySystem, permitindo que os DnsAdmins aumentem os privilégios para SYSTEM no DC (com permissões iguais, pelo menos, às dos Administradores de Domínio). Este "truque giro", como lhe chamou o investigador original, Shay Ber, pode ser útil para as equipas vermelhas que exploram o escalonamento de privilégios no AD e é uma potencial porta das traseiras para os atacantes no controlador de domínio.

Leitura relacionada

Neste post, vou expandir a pesquisa de Shay Ber, mostrando como superar um problema com a técnica anterior e como torná-la mais furtiva. Também analisarei as permissões necessárias para mostrar que um adversário pode utilizar esta táctica para deixar uma backdoor no DC que provavelmente não seria notada e poderia contornar algumas ferramentas.

Para recapitular a pesquisa anterior conduzida por Shay Ber e Nikhil Mittal, eles mostraram que é possível carregar uma DLL arbitrária em um serviço DNS em execução em um Controlador de Domínio através das seguintes etapas:

  1. O atacante precisa de fazer parte do grupo DnsAdmins para executar o executável dnscmd e apontar o serviço para uma DLL num caminho UNC.
  2. O atacante reinicia o serviço DNS utilizando "sc.exe stop/start dns" - esta é uma limitação, uma vez que as configurações padrão não permitem que os utilizadores DnsAdmins parem e iniciem serviços.

A minha investigação alarga a compreensão desta capacidade de ataque das seguintes formas:

  1. Não é estritamente necessário fazer parte do DnsAdmins para efectuar este ataque, mas apenas ter acesso de leitura/escrita ao contentor MicrosoftDNS e acesso RPC ao DC.
  2. É possível reiniciar o serviço DNS apenas com os privilégios indicados em 1.

Por conseguinte, é possível que um atacante com privilégios suficientes crie/actualize um utilizador com permissões mínimas e apenas acesso directo de leitura/escrita ao contentor MicrosoftDNS. Este utilizador passaria, na maioria dos casos, "despercebido", uma vez que as permissões do contentor raramente são monitorizadas. Este utilizador poderia permanecer sem ser detectado e poderia ser utilizado para executar comandos arbitrários com privilégios DC SYSTEM carregando uma DLL no processo DNS.

Antecedentes da investigação

Há três anos, no post do Medium "Feature, not bug: DnsAdmin to DC compromise in one line", Shay Ber observou que qualquer membro do grupo DnsAdmins poderia fazer com que o serviço do Servidor DNS carregasse uma DLL como NT AuthoritySystem no DC na próxima reinicialização do serviço.

Por predefinição, o DnsAdmins não tem a permissão necessária para reiniciar o serviço no DC remotamente, o que significa que os atacantes que pretendam abusar dele terão de esperar (ou utilizar outros métodos) até que o servidor ou o serviço seja reiniciado para executar o seu payload.

A minha missão de investigação era procurar uma forma de forçar o serviço a reiniciar ou a carregar a DLL instantaneamente e fazê-lo da forma mais discreta possível. (Mesmo que eu tivesse as permissões para reiniciar usando o sc.exe, isso geraria vários logs e provavelmente seria detectado). Essa abordagem acabou sendo surpreendentemente fácil, mas teve algumas consequências inesperadas. Antes de continuar a ler, recomendo que leia primeiro a pesquisa original de Ber.

Um novo começo
Comecei simplesmente por rever as especificações do MS-DNSP, procurando qualquer menção à palavra Reiniciar, quando me deparei com o seguinte:

Reiniciar a pszOperation
Figura 1: Reiniciar a pszOperation

Esta linha indica que um dos comandos que o servidor aceita (pszOperation) em R_DnssrvOperation é restart, que irá (sem surpresa) reiniciar o processo do servidor DNS. Parece perfeito!

Para facilitar a minha vida, consultei a documentação da ferramenta dnscmd (ferramenta CLI para gestão de servidores DNS) e procurei uma forma de a utilizar para enviar um comando de reinício para o servidor DNS, mas não encontrei nada.

Achei que devia tentar ver as cadeias de caracteres da ferramenta para "reiniciar" e (surpreendentemente), lá estava ela:

Figura 2 Cadeia de reinício dentro das cadeias de caracteres do dnscmd
Figura 2: Cadeia de reinício dentro das cadeias de caracteres do dnscmd

Embora nem a documentação da Microsoft nem a ajuda da ferramenta o mencionem, existe uma opção "/Restart" que pode utilizar no dnscmd para activar o reinício do processo de um servidor DNS.

Figura 3 Chamada bem sucedida do comando restart
Figura 3: Chamada bem sucedida do comando restart

O serviço accionou um reinício interno, chamando uma função interna chamada "reloadShutdown" e, em seguida, iniciando tudo de novo sem terminar o processo, ao contrário de um reinício de serviço normal.

Então agora eu sabia como acionar um recarregamento e carregar a DLL instantaneamente, mas quais eram as permissões necessárias?

Voltando à documentação, a verificação inicial de qualquer operação de DNS seria testar as credenciais do cliente para o privilégio de leitura no contentor MicrosoftDNS. O privilégio de escrita em relação ao mesmo objecto também é necessário para as nossas operações específicas (reiniciar e ServerLevelPluginDll).

Por esta altura, tinha activado um recarregamento, fazendo com que o serviço carregasse a DLL enviada anteriormente (o comando mostrado na secção do cenário) e deixando menos vestígios, uma vez que não estavam a ser gerados registos sobre o reinício do serviço ou a criação de processos.

Os registos que foram gerados, ambos no registo do servidor DNS, foram o ID de evento 770 (foi carregada uma DLL de plug-in ao nível do servidor) e o ID de evento 140:

Figura 4: Entradas de registo do servidor DNS

Na próxima secção, abordarei a razão pela qual este erro está a ser gerado. Se quiser saltar os pormenores, pode saltar para a secção "impacto potencial".

O Bug
Aconteceu algo inesperado ao executar o comando de reinicialização: A DLL foi carregada (como esperado) e o serviço continuou a ser executado, mas o seguinte registo foi gerado no registo do servidor DNS:

Figura 5: Registo de erros gerado após a operação de reinício
Figura 5: Registo de erros gerado após a operação de reinício

A verificação do código de erro mostrou que havia um problema com o ponto de extremidade RPC (0x6cc - O ponto de extremidade é um duplicado).

Quando tentei enviar qualquer outro comando para o mesmo servidor DNS, usando dnscmd, de repente nada funcionou:

Figura 6 Nada funciona
Figura 6: Nada funciona

Nem mesmo a consola de gestão do DNS funcionava agora:

Figura 7 Mais erros
Figura 7: Mais erros

Para perceber o que estava a falhar, utilizei o ApiMonitor e vi que havia um problema com o registo do ponto final após o reinício.

Ao reiniciar o serviço do servidor DNS da maneira usual (por exemplo, services.msc), o serviço para e inicia sem gerar nenhum erro. Portanto, o próximo passo que tomei foi ver por que um erro não foi lançado aqui, ao contrário de quando uma recarga usando o comando /restart está sendo transmitida para o servidor.

No entanto, aconteceu uma coisa interessante. Tanto o reinício do serviço como o recarregamento do serviço falharam na mesma chamada à API.

Esta mensagem diz-me alguma coisa, não diz? O serviço falhou ao cancelar o registo do ponto de extremidade RPC e, em seguida, gerou um erro duplicado ao tentar utilizar o ponto de extremidade.

A explicação para o facto de não haver erros subsequentes após um reinício do serviço é que, quando o serviço é reiniciado, o processo é encerrado, o que faz com que o ponto final cancele o registo automaticamente. Isto não ocorre quando se acciona um recarregamento do serviço (o processo não está realmente a ser reiniciado, daí não haver saída do processo).

Impacto potencial

Utilizando estes métodos, um atacante pode executar DLLs arbitrárias dentro do contexto de segurança do serviço DNS.

Uma vez que o serviço DNS é frequentemente executado em controladores de domínio, esta vulnerabilidade oferece oportunidades para os atacantes aumentarem os privilégios de qualquer utilizador no domínio que esteja sob o seu controlo. Tal como descrito na próxima secção, para além de fazer avançar o seu ataque actual, as especificidades das ACLs do contentor do Active Director dão aos atacantes a oportunidade de criar "administradores adormecidos" - e utilizadores sem privilégios que podem aumentar os privilégios à vontade.

Para que estes ataques funcionem, um atacante deve ter o seguinte:

  • Dnscmd (não é necessário, mas poupa tempo e esforço)
  • RPC aberto a DC
  • Permissões de leitura e escrita no contentor MicrosoftDNS (no contentor do sistema)

Exemplo de cenário

Os atacantes que conseguem comprometer um utilizador do grupo DnsAdmin podem expandir a sua posição de várias formas. Para além do aumento imediato de privilégios para o utilizador SYSTEM num DC (permitindo-lhes adicionar utilizadores Domain Admin ou mesmo obter uma Skeleton Key), podem também dar a um utilizador com poucos privilégios a capacidade de elevar privilégios atribuindo-lhe acesso de Leitura/Escrita ao contentor MicrosoftDNS como parte do seu ataque inicial.

Este utilizador pode ser criado pelo atacante, ou por um utilizador existente com uma palavra-passe comprometida ou SPN conhecido para posterior kerberoasting. Embora os grupos privilegiados do AD, como os administradores de domínio, sejam frequentemente monitorizados de perto, as ACLs de objectos exactos são notoriamente difíceis de monitorizar eficazmente. Isto cria uma situação em que os utilizadores parecem não ter privilégios mas, na realidade, podem reiniciar o serviço DNS e injectar DLLs novamente para recuperar o acesso privilegiado, fornecendo uma porta traseira persistente para o ambiente.

Figura 8: Utilizadores do domínio

Na captura de ecrã acima, o utilizador "haxer" parece um utilizador não privilegiado porque é apenas um membro dos utilizadores do domínio. Mas tudo o que ele precisa para se tornar um administrador do domínio é ter RPC para o CD e acesso de escrita a uma partilha acessível pelo CD.

Neste exemplo, a DLL iniciará um shell no carregamento que receberá comandos de um arquivo em um compartilhamento (command.txt) e gravará a saída em outro arquivo no mesmo compartilhamento (out.txt).

O atacante inicia sessão como utilizador "haxer", que não é actualmente membro de nenhum grupo privilegiado, e cria uma partilha com acesso de leitura/escrita para todos com a sua DLL maliciosa:

Figura 9: O atacante inicia sessão como "haxer"

Agora, tudo o que o atacante precisa de fazer é registar a DLL como ServerLevelPluginDll no DC, desencadear um reinício do serviço e começar a enviar comandos utilizando o ficheiro que irá criar:

Figura 10: Registar a DLL

Dois aspectos deste cenário são importantes de recordar:

  1. Se o DC não conseguir aceder ao caminho enviado como ServerLevelPluginDLL, o accionador de reinício fará com que o serviço DNS termine e o serviço não poderá ser iniciado novamente até que o DC consiga aceder ao caminho ou o caminho seja removido do registo do DC. (E como um DnsAdmin, provavelmente não poderemos iniciar o serviço quando ele estiver inativo).
  2. Devido ao erro descrito acima, o accionamento de um recarregamento causará problemas com a duplicação do ponto de extremidade RPC e não será possível enviar mais comandos ou accionar outro reinício:
Figura 11: O comando Restart falha

Registo e detecção

Aqui estão alguns passos que as empresas podem seguir para registar e detectar potenciais intrusões. Em primeiro lugar, é importante notar que se o processo do Servidor DNS foi reiniciado utilizando a operação restart pszOperation, NÃO irá gerar um registo com a ID de evento 7036 porque não se trata de um reinício de serviço.

1. O ID de evento 770 será criado no registo do Servidor DNS no CD quando este carregar a DLL após um reinício, com o caminho da DLL especificado.

Figura 12: Evento 770 registado

2. O ID de evento 140 será criado quando um reinício for accionado utilizando R_DnssrvOperation (apenas por causa do erro; idealmente, isto não acontecerá no futuro).

Figura 13: Evento 140 registado

3. Monitorizar as alterações de ntSecurityDescriptor no grupo MicrosoftDNS e DnsAdmins (ID de evento 5136).

4. Monitorizar a adição de membros ao grupo DnsAdmins.

5 Trate os utilizadores e grupos que já têm essas permissões como Administradores do domínio e monitorize-os em conformidade.

6. Os utilizadores e grupos com essas permissões devem ser adicionados ao grupo de Utilizadores Protegidos para uma maior protecção.

7. Utilizando o IPSIDS, pode monitorizar os pedidos R_DnssrvOperation e R_DnssrvOperation2 de computadores não administrados para servidores DNS.

8. Monitorizar as alterações ao caminho de registo "HKLMSYSTEMCurrentControlSetServicesDNSParametersServerLevelPluginDLL" nos servidores DNS.

Protegendo seu serviço Microsoft DNS

Ao implementar estas práticas recomendadas de registo e detecção, a sua organização pode proteger-se contra um cenário em que os utilizadores que já têm permissões para gerir o DNS podem aproveitá-lo para comprometer um Controlador de Domínio - ou deixar uma porta traseira furtiva no domínio para intrusos indesejados.