Introdução
Neste artigo, veremos o conceito de sequestro de DLL e como ele pode ser usado para alcançar a persistência do ambiente do usuário em sistemas Windows. Este método é descrito em MITER ATT & CK em: "Intercepting DLL Search Order (T1038) ".
A falsificação de DLL pode ser usada por invasores para muitas finalidades diferentes, mas este artigo se concentrará em obter resiliência com aplicativos de inicialização automática. Por exemplo, como o Slack e o Microsoft Teams são iniciados na inicialização (por padrão), a falsificação de DLL em um desses aplicativos permitiria a um invasor obter acesso persistente ao seu alvo - sempre que um usuário efetuar login.
Depois de apresentar o conceito de DLLs, ordem de pesquisa de DLL e falsificação de DLL, orientarei você no processo de automação da detecção de interceptação de DLL . Este artigo falará sobre a detecção de caminhos de interceptação de DLL no Slack, Microsoft Teams e Visual Studio Code.
Por fim, descobri vários caminhos de interceptação de DLL usados por diferentes aplicativos, investiguei a causa raiz e descobri que os aplicativos que usam certas chamadas de API do Windows são propensos à interceptação de DLL quando não estão em execução
C:\Windows\System32\.
Quero agradecer ao meu colega Josiah Massari (
@Airzero24) por ser o primeiro a descobrir alguns desses ganchos de DLL, explicar sua metodologia e me inspirar a automatizar a detecção.
O que é uma DLL?
Uma DLL é uma biblioteca que contém código e dados que podem ser usados simultaneamente por mais de um programa. ( Fonte ) A
funcionalidade de uma DLL pode ser usada por um aplicativo do Windows usando uma das funções
LoadLibrary*. Os aplicativos podem fazer referência a DLLs projetadas especificamente para esses aplicativos ou a DLLs do Windows já existentes no disco do System32. Os desenvolvedores podem carregar DLLs do System32 para usar a funcionalidade já implementada no Windows em seus aplicativos sem ter que escrever essa funcionalidade do zero.
Por exemplo, um desenvolvedor que precisa fazer solicitações HTTP pode usar a biblioteca WinHTTP (
winhttp.dll) em vez de implementar solicitações HTTP usando soquetes brutos.
Ordem de pesquisa de DLL e interceptação
Como as DLLs existem como arquivos no disco, você deve estar se perguntando como um aplicativo sabe de onde carregar a DLL. A Microsoft documentou a ordem de pesquisa da DLL em detalhes aqui .
A partir do Windows XP SP2, o modo de pesquisa segura de DLL é habilitado por padrão (
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode). Quando o modo de segurança está ativado, a ordem de pesquisa da DLL é a seguinte:
- O diretório do qual o aplicativo foi carregado.
- Diretório do sistema. Use a função GetSystemDirectory para obter o caminho para este diretório.
- Diretório do sistema de 16 bits. Não há função que forneça um caminho para esse diretório, mas ele é pesquisado.
- Diretório do Windows. Use a função GetWindowsDirectory para obter o caminho para este diretório.
- Diretório atual.
- , PATH. , , App Paths. App Paths DLL.
Um sistema pode conter várias versões da mesma DLL. Os aplicativos podem controlar a escolha do local de onde a DLL deve ser carregada, especificando o caminho completo ou usando outro mecanismo, como um manifesto. ( Fonte )
Se o aplicativo não especificar de onde carregar a DLL, o Windows usará a ordem de pesquisa padrão da DLL mostrada acima. A primeira posição na ordem de pesquisa da DLL (o diretório de onde o aplicativo é carregado) é de interesse dos invasores.
Se o desenvolvedor do aplicativo pretende carregar a DLL de
C:\Windows\System32, mas não o escreveu explicitamente no aplicativo, a DLL mal-intencionada colocada no diretório do aplicativo será carregada antes da DLL legítima do System32. O carregamento de uma DLL mal-intencionada é chamado de falsificação de DLL (ou interceptação) e é usado por invasores para carregar código mal-intencionado em aplicativos confiáveis / assinados.
Usando DLL Spoofing para Obter Resiliência
A falsificação de DLL pode ser usada para obter resiliência quando um aplicativo / serviço vulnerável é iniciado e uma DLL mal-intencionada é colocada em um local vulnerável. Um colega meu
@Airzero24descobriu o spoofing de DLL no Microsoft OneDrive, Microsoft Teams e Slack as userenv.dll.
Foram esses programas que se tornaram o alvo da interceptação, porque por padrão eles são configurados para iniciar na inicialização do Windows. Isso pode ser visto abaixo no Gerenciador de tarefas:
Aplicativos Windows configurados para inicialização automática
Para testar a falsificação de DLL, criei um carregador de shellcode DLL que iniciou o Cobalt Strike Beacon. Renomeei a DLL maliciosa para
userenv.dlle copiei-a para o diretório do aplicativo afetado. Iniciei o aplicativo e vi meu novo retorno de chamada do Beacon.
Cobalt Strike Beacon por meio de interceptação de DLL
usandoProcess Explorer , posso verificar se minha DLL maliciosa foi realmente carregada por um aplicativo vulnerável.
Process Explorer mostrando DLL malicioso carregado
Detecção automática do potencial de interceptação de DLL
Depois de confirmar o sequestro de DLL conhecido anteriormente, eu queria ver se conseguia encontrar outros recursos de falsificação de DLL que pudessem ser explorados.
O código usado em meu checkout pode ser encontrado aqui .
Usando o Slack como exemplo
Para iniciar este processo, executei o Process Monitor (ProcMon) com os seguintes filtros:
- Nome do processo -
slack.exe - Resultado contém
NOT FOUND - O caminho termina com
.dll.
Encontre DLLs ausentes no ProcMon.
Então eu iniciei o Slack e examinei o ProcMon em busca de qualquer DLL que o Slack estava procurando, mas não conseguiu encontrar.
Possíveis caminhos de interceptação de DLL descobertos pelo ProcMon
Eu exportei esses dados do ProcMon como um arquivo CSV para facilitar a análise no PowerShell.
Com minha DLL atual do carregador de código de shell, não consegui descobrir facilmente os nomes das DLL que foram carregados com êxito pelo Slack. Eu criei uma nova DLL, que é usada
GetModuleHandleEx, e GetModuleFileNamepara determinar o nome da DLL carregada e gravá-la em um arquivo de texto .
Meu próximo objetivo era analisar o arquivo CSV para caminhos DLL na lista, visualizar essa lista, copiar minha DLL de teste para o caminho especificado, iniciar o processo de destino, interromper o processo de destino e excluir a DLL de teste. Se a DLL de teste foi carregada com êxito, ela gravará seu nome no arquivo resultante.
Quando esse processo terminar, terei uma lista de possíveis sequestros de DLL (espero) gravada em um arquivo de texto.
Toda a mágica em meu projeto DLLHijackTest é feita por um script PowerShell . Ele aceita o caminho para o arquivo CSV gerado pelo ProcMon, o caminho para sua DLL maliciosa, o caminho para o processo que você deseja executar e quaisquer argumentos que deseja passar para o processo.
Parâmetros
Get-PotentialDLLHijack Get-PotentialDLLHijack.ps1
Depois de alguns minutos, verifico o arquivo de texto listado em minha DLL "maliciosa" para possíveis sequestros de DLL. Encontrei os seguintes caminhos de interceptação possíveis para o Slack:
PS C:Users\John\Desktop> Get-PotentialDLLHijack -CSVPath .\Logfile.CSV -MaliciousDLLPath .\DLLHijackTest.dll -ProcessPath "C:\Users\John\AppData\Local\slack\slack.exe"
C:\Users\John\AppData\Local\slack\app-4.6.0\WINSTA.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\LINKINFO.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\ntshrui.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\srvcli.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\cscapi.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\KBDUS.DLL
Usando o Microsoft Teams como exemplo
Realizamos o processo descrito acima novamente:
- Use o ProcMon para identificar caminhos de interceptação de DLL em potencial, exporte esses dados como um arquivo CSV.
- Determine o caminho para iniciar o processo.
- Defina os argumentos que deseja passar para o processo.
- Execute
Get-PotentialDLLHijack.ps1com os argumentos apropriados.
Encontrei os seguintes caminhos de interceptação possíveis para o Microsoft Teams:
PS C:Users\John\Desktop> Get-PotentialDLLHijack -CSVPath .\Logfile.CSV -MaliciousDLLPath .\DLLHijackTest.dll -ProcessPath "C:\Users\John\AppData\Local\Microsoft\Teams\Update.exe" -ProcessArguments '--processStart "Teams.exe"'
C:\Users\John\AppData\Local\Microsoft\Teams\current\WINSTA.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\LINKINFO.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\ntshrui.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\srvcli.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\cscapi.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\WindowsCodecs.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\TextInputFramework.dll
Nota : Tive que fazer pequenas alterações no script do PowerShell para ser concluídoTeams.exe, pois meu script está tentando encerrar o processo que estava tentando iniciar, neste caso, estáUpdate.exe.
Usando o código do Visual Studio como exemplo
Ao repetir o processo acima, encontrei os seguintes caminhos de interceptação em potencial para o Visual Studio Code:
PS C:Users\John\Desktop> Get-PotentialDLLHijack -CSVPath .\Logfile.CSV -MaliciousDLLPath .\DLLHijackTest.dll -ProcessPath "C:\Users\John\AppData\Local\Programs\Microsoft VS Code\Code.exe"
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\WINSTA.dll
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\LINKINFO.dll
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\ntshrui.dll
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\srvcli.dll
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\cscapi.dll
Compartilhando DLLs
Percebi que o Slack, o Microsoft Teams e o Visual Studio Code compartilham as seguintes DLLs:
WINSTA.dllLINKINFO.dllntshrui.dllsrvcli.dllcscapi.dll
Achei isso interessante e queria entender o que causa esse comportamento.
Metodologia: Compreendendo as formas de interceptação de DLL compartilhada
Eu assisti Tracy pilha quando falha tentou carga
WINSTA.dll, LINKINFO.dll, ntshrui.dll, srvcli.dlle cscapi.dll.
DLL com carregamento lento
notei semelhanças em Tracy pilha ao carregar
WINSTA.dll, LINKINFO.dll, ntshrui.dlle srvcli.dll.
Rastreamento de pilha quando Code.exe tenta carregar
WINSTA.dll
um rastreamento de pilha ao
Teams.exetentar carregar LINKINFO.dll,
rastreamento de pilha quando o Slack tenta carregar
ntshrui.dll
um rastreamento de pilha constantemente contém uma chamada
_tailMerge_<dllname>_dll, delayLoadHelper2seguido LdrResolveDelayLoadedAPI. Esse comportamento foi o mesmo para todos os três aplicativos.
Eu determinei que esse comportamento está relacionado ao carregamento lento de DLL . Da pilha de rastreamento na inicialização
WINSTA.dllPude ver que o módulo responsável por esse carregamento lento era wtsapi32.dll.
Abri
wtsapi32.dllem Ghidra e usei Search -> For Strings -> Filter: WINSTA.dll. Clique duas vezes na linha encontrada para levá-lo à sua localização na memória.
A linha "
WINSTA.dll" emwtsapi32.dll
Clicando com o botão direito em um local da memória, podemos encontrar qualquer referência a este endereço.
Links para
WINSTA.dll
Seguindo os links, podemos ver que a string
WINSTA.dllé passada para uma estrutura chamada ImgDelayDescr. Olhando a documentação para esta estrutura, podemos confirmar que ela está relacionada ao carregamento lento de DLL.
typedef struct ImgDelayDescr {
DWORD grAttrs; //
RVA rvaDLLName; // RVA dll
RVA rvaHmod; // RVA
RVA rvaIAT; // RVA IAT
RVA rvaINT; // RVA INT
RVA rvaBoundIAT; // RVA IAT
RVA rvaUnloadIAT; // RVA IAT
DWORD dwTimeStamp; // 0, ,
// O.W. / DLL, (Old BIND)
} ImgDelayDescr, * PImgDelayDescr;
Essa estrutura pode ser passada para
__delayLoadHelper2, que usará LoadLibrary/ GetProcAddresspara carregar a DLL especificada e corrigir o endereço da função importada na tabela de endereços de importação de carregamento lento (IAT).
FARPROC WINAPI __delayLoadHelper2(
PCImgDelayDescr pidd, // ImgDelayDescr
FARPROC * ppfnIATEntry // IAT
);
Ao encontrar outras referências à nossa estrutura
ImgDelayDescr, podemos encontrar uma chamada __delayLoadHelper2que então chama ResolveDelayLoadedAPI. Eu renomei o nome da função, tipos e variáveis para torná-lo mais fácil de entender.
__delayLoadHelper2e ResolveDelayLoadedAPIna Ghidra
Excelente! Isso é consistente com o que vimos em nosso rastreamento de pilha do ProcMon quando o Slack tentou carregar
WINSTA.dll.
__delayLoadHelper2 e ResolveDelayLoadedAPIno ProcMon.
Este comportamento foi uniformemente para
WINSTA.dll, LINKINFO.dll, ntshrui.dlle srvcli.dll. A principal diferença entre cada DLL de carregamento lento era a DLL "pai". Em todos os três aplicativos:
wtsapi32.dllcarregado adiadoWINSTA.dllshell32.dllcarregado preguiçosamenteLINKINFO.dllLINKINFO.dllcarregado adiadontshrui.dllntshrui.dllcarregado adiadosrvcli.dll
Você notou algo interessante? Parece que ele
shell32.dllbaixa LINKINFO.dll, que baixa ntshrui.dll, que finalmente baixa srvcli.dll. Isso nos leva à nossa última opção comum de spoofing de DLL - cscapi.dll.
Substituição de DLL em NetShareGetInfo e NetShareEnum
Eu segui o rastreamento da pilha quando o Slack tentou carregar
cscapi.dlle vi uma chamada LoadLibraryExWque aparentemente veio de srvcli.dll.
Abri o
rastreamento de pilha na inicialização
cscapi.dll no Ghidra e usei . Clicar duas vezes na linha encontrada e seguir os links leva à chamada esperada . chama LoadLibrary para
renomear a função que contém a chamada e, seguindo os links, obtive dois lugares onde a função é usada:
srvcli.dllSearch -> For Strings -> Filter: cscapi.dllLoadLibrary
srvcli.dllcscapi.dll
LoadLibrary
NetShareEnum downloads cscapi.dll
NetShareGetInfo downloads
cscapi.dll
Eu verifiquei isso com programas PoC que chamam
NetShareEnume NetShareGetInfo:
NetShareEnum.exedownloads cscapi.dll
NetShareGetInfo.exedownloadscscapi.dll
resultados
Os seguintes caminhos de spoofing de DLL estão disponíveis no Slack:
C:\Users\John\AppData\Local\slack\app-4.6.0\WINSTA.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\LINKINFO.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\ntshrui.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\srvcli.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\cscapi.dll
C:\Users\John\AppData\Local\slack\app-4.6.0\KBDUS.DLL
Os seguintes caminhos de spoofing de DLL estão disponíveis no Microsoft Teams:
C:\Users\John\AppData\Local\Microsoft\Teams\current\WINSTA.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\LINKINFO.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\ntshrui.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\srvcli.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\cscapi.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\WindowsCodecs.dll
C:\Users\John\AppData\Local\Microsoft\Teams\current\TextInputFramework.dll
Os seguintes caminhos de spoofing de DLL estão disponíveis no Visual Studio Code:
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\WINSTA.dll
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\LINKINFO.dll
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\ntshrui.dll
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\srvcli.dll
C:\Users\John\AppData\Local\Programs\Microsoft VS Code\cscapi.dll
Além disso, descobri que os programas usam
NetShareEnume NetShareGetInfofornecem a capacidade de substituir a DLL na forma cscapi.dlldevido à chamada embutida no código LoadLibrary. Eu verifiquei esse comportamento com Ghidra e PoC.
Conclusão
Como um lembrete, a interceptação de DLL é um método pelo qual invasores podem interferir na execução de código em aplicativos assinados / confiáveis. Criei ferramentas para ajudar a automatizar a detecção do caminho de interceptação de DLL. Usando essa ferramenta, descobri caminhos de interceptação de DLL no Slack, Microsoft Teams e Visual Studio Code.
Percebi que os caminhos de interceptação de DLL desses três aplicativos se sobrepõem e investiguei a causa. Eu destaquei meu método de compreensão dessa coincidência. Aprendi sobre DLLs de carregamento lento e descobri duas chamadas de API que tornam possível interceptar DLLs em qualquer programa que as chame:
NetShareEnumcargascscapi.dllNetShareGetInfocargascscapi.dll
Obrigado por reservar um tempo para ler este artigo, espero que você tenha aprendido alguma coisa sobre APIs do Windows, Ghidra, ProcMon, DLLs e interceptação de DLLs!
Links
Um grande olá aos meus colegas Daniel Heinsen (
@hotnops), Lee Christensen ( @tifkin_) e Matt Hand ( @matterpreter) por ajudarem com o Ghidra / ProcMon!
Verificando PoCs públicos para uso em pentesting