DLL Hijacking – técnica simples, que confere maior furtividade ao ataque; entenda

Escrito por: Alexandre Siviero

O recente ataque do ransomware REvil através da infraestrutura da Kaseya é o mais recente de uma série de ataques que incorporaram uma técnica conhecida como DLL Side-Loading. Segundo o framework MITRE ATT&CK, trata-se de uma técnica de hijacking do fluxo de execução de um processo (razão pela qual também é chamada de DLL hijacking). Sua aplicação é simples, ainda mais considerando outras explorações de DLL como injeção refletida, e confere maior furtividade ao ataque. Para entende-la, primeiro é preciso compreender o que são DLLs e como elas são carregadas por um arquivo.

Dynamic-Link Libraries

Pela documentação da Microsoft, uma DLL é um módulo que contém funções e dados que podem ser usados por outros módulos. Tornando ainda mais simples, é um executável tal qual um PE, mas que não roda sozinho. Seu propósito é trazer um funcionamento modular para aplicações, por exemplo oferecendo funções nativas do Windows através de APIs para que os programadores não precisem reinventar a roda. Se seu programa utilizará comunicação via TCP/IP, por exemplo, você não precisa programar toda essa parte; é só importar a DLL que possui as APIs que você necessita (como utilizar sockets para conexões de rede) e seguir em frente.

O termo dynamic-link também sugere que existem outros tipos de links possíveis para aplicações: static-link e runtime-link.

Static-link

Consiste em incluir dentro do código de uma aplicação absolutamente todas as funções necessárias para seu funcionamento. Nenhuma importação é necessária durante a execução, mas isso resulta em um software compilado com um tamanho maior e com maior dificuldade para atualizações e ajustes. Por quê? Porque ao invés de corrigir apenas um módulo auxiliar que seu programa usa, você precisa mexer no código-fonte e recompilar para qualquer alteração.

Dynamic-link

As DLLs são importadas para a memória de um processo durante sua inicialização. Isso significa que o executável em disco lista todos os módulos e funções correspondentes em uma tabela de importações. Durante as operações que transferem um executável para a memória e o transformam em um processo, o Windows vai ler essa tabela, olhar o código das funções pedidas nas DLLs associadas e copiá-lo para a memória desse processo. É essa tabela de importações que softwares que analisam executáveis lêem.

Runtime-link

Uma alternativa para dynamic-link, ou importar DLLs e funções durante a inicialização do processo, é fazê-lo durante a execução da aplicação (por isso o termo runtime). Existem usos legítimos para essa abordagem, como por exemplo não gastar tempo ou memória importando funções que raramente serão usadas pelo processo – pense nele como um modelo de importação “sob demanda”. Autores de malware gostam bastante desse tipo de importação por outro motivo: obscurecer as funcionalidades de seus softwares maliciosos. Quando você conhece DLLs de sistema o suficiente, ler a tabela de importações de um executável em disco te traz muita informação sobre o que aquele programa vai fazer quando rodar. Ninguém coloca DLLs a toa, então se um software importar algo para interagir com o registro do Windows, ele vai interagir com o registro do Windows.

Para evitar que esse tipo simples de análise estática mostre o que o malware se propõe a fazer, os autores importam apenas DLLs estritamente necessárias para o funcionamento do processo via dynamic-link. Todas as funções realmente interessantes vão ser enumeradas e importadas durante a execução.

DLL Hijacking

Ok, falamos inúmeras vezes em importar, mas até agora sem explicar como isso realmente funciona. Há pouco mencionamos DLLs estritamente necessárias; uma delas é Kernel32.dll, que provê uma série de APIs usadas para inicializar corretamente um processo, entre elas LoadLibraryA e LoadLibraryEx. Ambas são utilizadas para importar uma DLL, tanto em casos de dynamic-link como em casos de runtime-link (as diferenças entre as duas APIs são pequenas e irrelevantes para o tema aqui tratado).

Ambas as APIs têm como parâmetro lpLibFileName, que pode fornecer um PE (.exe) ou uma DLL (.dll) a ser carregado no processo. O nome do arquivo passado a esse parâmetro pode ou não conter seu path completo (localização em disco). Se contiver, o arquivo alvo será lido no diretório fornecido e mapeado para a memória. Mas e se você fornecer apenas o nome do arquivo, sem sua localização?

Nesses casos, o Windows vai buscar pelo arquivo em disco obedecendo uma ordem pré-determinada, que está disponível na documentação da Microsoft. O modo de busca segura, ou Safe Dll Search Mode, é habilitado por padrão e afeta a ordem dos locais onde o executável a ser importado será buscado. Com ele habilitado, a ordem é:

  1. O diretório do qual a aplicação foi lançada
  2. O diretório de sistema (C:\Windows\System32)
  3. A versão 16-bit do diretório de sistema
  4. O diretório do Windows (C:\Windows\)
  5. O diretório atual

Com Safe Dll Search Mode desabilitado, a ordem muda para:

  1. O diretório do qual a aplicação foi lançada
  2. O diretório atual
  3. O diretório de sistema (C:\Windows\System32)
  4. A versão 16-bit do diretório de sistema
  5. O diretório do Windows (C:\Windows\)

PS: Eu omiti a 6ª entrada da lista por questão de brevidade e porque ela é irrelevante para a técnica que vamos discutir, mas a lista completa está disponível no link para a documentação fornecido no parágrafo anterior.

“Ahá! Pela diferença entre as duas, aposto que DLL hijacking usa o diretório atual!”. Bom chute, mas não. Na verdade, pra essa técnica o estado da busca segura é completamente irrelevante. A exploração acontece logo no primeiro lugar buscado, o diretório do qual a aplicação foi lançada.

No caso específico do REvil, a Sophos mostrou como o dropper desse ataque salva um antigo (e legítimo) binário do Microsoft Defender em disco e usa-no como alvo de DLL hijacking. Abaixo, note que normalmente a DLL legítima MpSvc (selecionada) reside no mesmo diretório que MsMpEng.exe, um dos binários do Defender:

 

Logo, seguindo a ordem de busca de DLLs importadas sem o caminho em disco completo, ela está no primeiro lugar onde o Windows procuraria. Se aproveitando disso, o grupo simplesmente nomeou sua DLL maliciosa como MpSvc.dll e salvou-a no mesmo diretório que o binário antigo do Defender.

Por que agir dessa maneira ao invés de escrever um software malicioso e rodá-lo como processo? Porque o Defender rodando numa máquina chama menos atenção.

Furtivo, mas quanto?

Toda técnica que foge do comportamento normal do sistema operacional vai deixar rastros, mesmo as furtivas. Você pode ser discreto em uma frente, mas vai acabar sendo barulhento em outra. No caso do REvil, a versão antiga do Windows Defender (msmpeng.exe) usada como veículo para o side-loading de uma DLL maliciosa é salva em C:\windows\msmpeng.exe. Essa é a primeira pista de que algo não está certo: o executável do Defender sempre residiu dentro do diretório “Arquivos de Programas” (ou “Program Files”), na pasta Windows Defender. No Windows 10, esse diretório migrou para ProgramData; embora diferentes, nenhum dos caminhos trazia o msmpeng.exe salvo diretamente no diretório do Windows.

O processo pai do Defender também seria motivo de desconfiança. O dropper usado pelo grupo era salvo em uma pasta do Kaseya (C:\KWORKING\AGENT.EXE), logo a árvore de processos mostraria que o Defender foi iniciado por… um executável do Kaseya? Não faz nenhum sentido.

Claro, existem diversas nuances na detecção em tempo real de um ataque desses. Uma análise forense mostraria de modo trivial o comportamento suspeito, mas em casos de ransomware analisar o ocorrido pós ataque significa que o estrago já foi feito. Para jogar mais lenha ainda na fogueira, a própria Kaseya recomendava a seus clientes excepcionar diretórios de suas aplicações nos antivírus das máquinas. Sendo o mais claro possível: DLL hijacking/side loading é fácil de entender; não significa que seja igualmente fácil de detectar e/ou evitar.

Bibliografia:

https://docs.microsoft.com/en-us/troubleshoot/windows-client/deployment/dynamic-link-library

https://news.sophos.com/en-us/2021/07/04/independence-day-revil-uses-supply-chain-exploit-to-attack-hundreds-of-businesses/

https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-search-order#standard-search-order-for-desktop-applications

https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexa

https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibrarya

https://github.com/sophoslabs/IoCs/blob/master/Ransomware-REvil-Kaseya.csv

https://attack.mitre.org/techniques/T1574/002/

https://news.thewindowsclub.com/new-path-windows-defender-installation-windows-10-91061/

https://www.ghacks.net/2017/12/18/microsoft-changes-windows-defender-path-on-windows-10/