Como ignorar o controle de aplicações do Windows Defender com o Loki C2
O Windows Defender Application Control (WDAC) é uma solução de segurança que restringe a execução a softwares confiáveis. Como é classificado como um limite de segurança, a Microsoft oferece recompensas por bugs para desvios qualificáveis, tornando-o um campo de pesquisa ativo e competitivo.
Resultados típicos de uma submissão a um programa de recompensas por vulnerabilidades para contornar o WDAC:
Ao analisar a lista de bloqueio recomendada do WDAC pela Microsoft, vemos que figuras renomadas como Jimmy Bayne (@bohops) e Casey Smith (@subTee) descobriram bypasses do WDAC que continuam sem correção, mas que receberam menções honorárias. Além dessa lista, o Projeto LOLBAS contém outros desvios não corrigidos que não foram reconhecidos na lista de bloqueios da Microsoft. Um exemplo é a aplicação Microsoft Teams, que continua sendo um desvio viável para o WDAC,apesar de estar documentado no LOLBAS.
Ao nos depararmos com o WDAC durante as operações da red team, nós o contornamos com sucesso e executamos a carga útil de comando e controle (C2) do estágio 2 usando as seguintes técnicas:
1. Use um LOLBIN conhecido como MSBuild.exe
2. Carregar lateralmente uma aplicação confiável com uma DLL não confiável
3. Exploração da regra de exclusão personalizada da política WDAC do cliente
4. Encontrar uma nova cadeia de execução em uma aplicação confiável que permita a implementação C2
Como Ruben Boonen (@FuzzySec) explicou em sua palestra no Wild West Hackin' Fest Statikk Shiv: Leveraging Electron Applications for Post-Exploitation, aplicações Electron funcionam como navegadores da web que renderizam aplicações de desktop usando tecnologias padrão como HTML, JavaScript e CSS. O mecanismo de JavaScript no Electron é o Node.js, que disponibiliza APIs poderosas capazes de interagir com o sistema operacional hospedeiro. Essas APIs permitem ações como leitura e gravação de arquivos, execução de programas e outras operações típicas de aplicações nativas.
No tempo de execução, uma aplicação Electron lê arquivos JavaScript, interpreta seu código e os executa dentro do processo Electron. A animação abaixo demonstra como a aplicação Microsoft Teams Electron lê um arquivo JavaScript em tempo de execução, que, em seguida, usa o módulo child_process para executar o whoami.exe.
Neste exemplo, o processo do Teams Electron lê o arquivo JavaScript, que então gera o whoami.exe usando o módulo child_process. Esse módulo aciona o processo Electron para executar sua API exportada uv_spawn, responsável por interagir com o sistema operacional para criar um novo processo.
A arquitetura tradicional de uma aplicação do Windows consiste em:
O EXE chama funções exportadas de DLLs para ampliar seus recursos. No entanto, as aplicações Electron revertem essa arquitetura. Em vez de o EXE chamar as APIs das DLLs, o próprio Electron EXE expõe as exportações de API, que são chamadas de:
Essa estrutura permite que o JavaScript Node.js e os módulos Node interajam com o sistema operacional de maneiras que o JavaScript tradicional em um navegador não consegue.
Na imagem abaixo, examinamos a aplicação Teams Electron usando o PE Bear, uma ferramenta incrível criada por @hasherezade, que revela que o executável do Teams Electron contém 2.977 APIs exportadas. Essa grande superfície da API oferece ampla funcionalidade que pode ser aproveitada por arquivos JavaScript Node.js e módulos Node para interagir com o sistema operacional.
Como as aplicações Electron executam JavaScript no tempo de execução, modificar esses arquivos JavaScript permite que os invasores injetem código Node.js arbitrário no processo Electron. Ao aproveitar as APIs do Node.js e do Chromium, o código JavaScript pode interagir com o sistema operacional.
A capacidade de modificar arquivos JavaScript de aplicações Electron confiáveis para executar código JavaScript Node.js arbitrário não foi descoberta por mim. As referências mais antigas que consegui encontrar são de 2022.
No início de 2022, Andrew Kisliakov publicou o blog “Microsoft Teams e outros aplicativos Electron como LOLbins ". Andrew e @mrd0x contribuíram com suas descobertas para o projeto LOLBAS.
No final de 2022, Valentina Palmiotti (@chompie1337), Ellis Springe (@knavesec) e Ruben exploraram ainda mais essa abordagem, o que levou ao desenvolvimento de uma ferramenta de persistência interna que desde então tem sido usada em operações de red team.
Também em 2022, Michael Taggart lançou o projeto quASAR, uma ferramenta projetada para modificar aplicações do Electron para viabilizar a execução de comandos. Em seu blog “Quasar: Compromising Electron Apps”, ele compartilhou que, em setembro de 2022, um membro do projeto Electron entrou em contato com ele, afirmando que a verificação de integridade era uma funcionalidade experimental e que, provavelmente, seria totalmente suportada no futuro.
Com base em experiências pessoais com aplicações Electron mais recentes, como o Signal, confirmei que algumas aplicações Electron agora possuem verificações de integridade que impedem a modificação de seus arquivos JavaScript. Ainda assim, muitas aplicações Electron distribuídas permanecem vulneráveis.
Essa técnica também foi observada em ataques do mundo real. Em 2022, um agente da ameaça fez backdoor na aplicação de bate-papo MiMi, modificando seus arquivos JavaScript agrupados no servidor de distribuição. A Trend Micro identificou isso como um ataque à cadeia de suprimentos, no qual o aplicativo Electron comprometido foi distribuído aos usuários finais, possibilitando a execução de código JavaScript malicioso que baixou e executou uma carga útil C2 de segundo estágio.
Em abril de 2024, eu, Bobby Cooke (@0xBoku), estava procurando uma nova cadeia de execução para usar na preparação de uma futura operação de red team para um cliente do setor financeiro. Esse setor tem padrões de segurança mais altos e regulamentações mais rígidas, muitas vezes implementando controles de segurança adicionais, como o WDAC. Durante minha pesquisa, me deparei com outra aplicação vulnerável do Electron. No entanto, como não foi assinado pela Microsoft, era improvável que contornasse a política WDAC do cliente.
Em seguida, mudei para a aplicação legada do Microsoft Teams, que é assinado pela Microsoft e pode ignorar até mesmo as políticas mais rígidas do WDAC. Nesse ponto, Dylan Tran (@d_tranman) se juntou a mim nessa missão, e começamos a procurar uma forma de escalar de uma execução arbitrária Node.js JavaScript para executar nosso shellcode C2 estágio 2.
Embora o Node.js possa interagir com o sistema operacional por meio de suas APIs, ele não tem a funcionalidade completa do C, onde os desenvolvedores podem chamar diretamente WINAPIs e NTAPIs. Para preencher essa lacuna, os desenvolvedores criaram módulos Node, que ampliam os recursos do framework Node.js. Esses módulos, compilados a partir de código C++, podem chamar WINAPIs, interagir com APIs do Node.js e executar JavaScript nas aplicações Electron. Os módulos Node compilados possuem uma extensão .node e são carregadas em processos do Windows por meio de um evento de carregamento de DLL.
Durante nossa pesquisa, examinamos várias aplicações Electron e analisamos os módulos Node assinados. Descobrimos que esses módulos poderiam interagir diretamente do JavaScript, o que nos permite aproveitar seus recursos integrados.
Embora criar nossos próprios módulos Node personalizados para executar shellcode seja uma abordagem viável e um recurso do Loki C2, isso apresenta um problema do tipo "quem veio primeiro: o ovo ou a galinha?". Carregar um módulo Node a partir de JavaScript aciona um evento de carregamento de DLL, que pode ser bloqueado pelas políticas do WDAC que impõem regras rigorosas contra DLLs não assinadas. Felizmente, existe um grande número de módulos Node assinados em aplicações Electron legítimas.
Essa abordagem para executar nossa carga útil parecia promissora, por isso compartilhamos nossas descobertas com a Valentina e ela se juntou a nós nessa busca. Com a ajuda dela, nos aprofundamos na reversão de módulos Node assinados, procurando vulnerabilidades ou recursos integrados que nos permitissem executar shellcode arbitrário.
Um exemplo de um módulo Node com recursos úteis é o windows_process_tree.node, um módulo assinado pela Microsoft junto com o Visual Studio Code. Quando examinado no PE Bear, revela duas funções exportadas, conforme visto abaixo.
Ao contrário das DLLs tradicionais, os módulos Node não listam todas as funções disponíveis na tabela de exportação. A função exportada napi_register_module_v1 é chamada pelo processo Electron e é responsável por carregar o módulo e expor sua funcionalidade exportada ao processo Electron. Isso atua como uma ponte, permitindo que o JavaScript dentro do processo Electron chame e interaja com as funções do módulo.
Uma maneira trivial de listar todas as funções que podem ser chamadas em um módulo Node é aproveitar o código Node.js abaixo.
Ao executar este script Node.js no PowerShell, vemos que existem duas funções que podem ser chamadas em windows_process_tree.node. São elas getProcessList e getProcessCpuUsage.
Com persistência, é possível determinar como chamar essas funções a partir do JavaScript. Uma limitação do Node.js é a falta de uma API integrada para listar todos os processos em execução no sistema. Essa limitação é a razão pela qual a Microsoft introduziu a função getProcessList nesse módulo, expandindo os recursos da aplicação Electron do VS Code.
É possível recuperar essas informações diretamente em JavaScript utilizando o módulo child_process para executar o PowerShell em um processo secundário, que retorna detalhes sobre os processos em execução. Na imagem abaixo, o Loki C2 gera um processo secundário do PowerShell para recuperar a lista de processos.
Essa abordagem apresenta riscos significativos à segurança operacional. A execução de processos secundários do PowerShell é altamente detectável e aumenta a probabilidade de uma operação ser sinalizada ou bloqueada. Para evitar isso, o Loki C2 aproveita módulos Node assinados como windows_process_tree.node para estender os recursos do Node.js.
O Loki C2 inclui o comando ps, que recupera informações do processo carregando o módulo assinado pela Microsoft windows_process_tree.node e chamando a função getProcessList, como mostrado na imagem abaixo.
O código JavaScript Loki C2 que chama a função getProcessList no módulo windows_process_tree.node é mostrado abaixo. A getProcessList retorna dados de processos em formato JSON, que o Loki C2 formata em uma tabela estruturada para melhor legibilidade.
Determinar como chamar funções adequadamente nos módulos Node pode ser desafiador, já que suas estruturas internas não estão documentadas. No entanto, ao usar ferramentas como o Ghidra, desenvolvido pela NSA, e colaborar com profissionais de engenharia reversa qualificados como a Valentina, analisamos com sucesso esses módulos e identificamos como interagir com suas funções.
A Valentina finalmente descobriu uma maneira de executar nosso shellcode C2 de estágio 2 sem carregar uma DLL não assinada, mas deixarei que ela conte os detalhes. Juntos, Dylan, Valentina e eu trabalhamos para refinar a técnica para garantir a estabilidade da próxima campanha de phishing.
Infelizmente, nossa campanha inicial de phishing por e-mail foi denunciada e bloqueada pela equipe de segurança. Após esse contratempo, Brett Hawkins (@h4wkst3r) e eu começamos a nos preparar para uma segunda campanha. Como responsável pela carga útil, eu não queria reutilizar a mesma carga útil, isso facilitaria demais para a equipe de segurança nos rastrear e interromper nossa segunda campanha. No entanto, não tivemos tempo suficiente para aplicar a técnica da Valentina a uma nova carga útil, então comecei a desenvolver uma nova carga útil usando uma abordagem alternativa.
Normalmente, a capacidade de executar JavaScript arbitrário em aplicações Electron confiáveis é usada para executar comandos que implementam um agente C2. No entanto, sem a técnica da Valentina, essa abordagem falharia no que diz respeito ao WDAC, pois acabaria exigindo a execução de um programa não assinado, que provavelmente seria bloqueado.
Com apenas alguns dias para me preparar para a segunda campanha, tive uma ideia: E se eu criasse um framework C2 inteiro em JavaScript?
Se o próprio agente C2 fosse inteiramente escrito em JavaScript, ele poderia estabelecer um canal C2 mesmo contra as políticas WDAC mais rigorosas. A partir daí, o reconhecimento poderia ser realizado para encontrar uma maneira de implementar uma carga útil C2 de estágio 2. Não haveria eventos de carregamento de DLL não assinados, apenas JavaScript sendo executado dentro do processo confiável do Teams.
Tudo o que precisávamos era de funcionalidade suficiente para:
Aproveitando todo o código Node.js que eu havia escrito durante minha pesquisa, criei uma prova de conceito C2 durante a noite. No dia seguinte, compartilhei com Dylan e, juntos, rapidamente expandimos para um C2 totalmente funcional baseado em JavaScript. Nosso C2 era capaz de:
O JavaScript C2, agora conhecido como Loki C2, foi um sucesso na segunda campanha. Desde então, continuamos refinando e expandindo o Loki C2, adicionando mais funcionalidades, aumentando a estabilidade e aprimorando os recursos.
Com todo o conhecimento do Electron que adquiri com essa pesquisa, construí uma interface gráfica de usuário para o Loki C2 usando o framework Electron.
No vídeo abaixo, demonstro como contornar uma política rígida do WDAC com o Loki C2.As duas seções abaixo explicam o que está acontecendo no vídeo.
Para esta demonstração, o WDAC é implementado por meio do aplicativo Control Policy Wizard em uma instância EC2 do Windows Server 2025 atualizada na AWS. O assistente oferece três modelos de política de base:
O modo padrão do Windows é o mais rigoroso, permitindo a execução de:
Na demonstração, a política "Modo padrão do Windows" está selecionada. O Modo de Auditoria padrão é desativado para que o WDAC aplique a política imediatamente. Além disso, as opções mesclar com listas de bloqueios recomendadas estão marcadas, o que inclui as regras na lista de bloqueios do WDAC recomendada pela Microsoft. O aplicativo Control Wizard gera um arquivo XML e CIP para a política do WDAC, que é então implementado no servidor usando o CITool.exe.
Depois que o WDAC está ativo, tento executar o Loki C2 Agent.exe, mas o WDAC o bloqueia, pois o executável não é assinado pela Microsoft.
Para contornar essa restrição, copio o conteúdo do diretório do Loki Agent /resources/app/. Uma pasta chamada "teams" está na área de trabalho, contendo uma aplicação legada legítima do Microsoft Teams. A exibição das propriedades do Teams.exe confirma que ele foi assinado pela Microsoft.
Em seguida, navego até o diretório /resources/ da aplicação do Teams e excluo todos os arquivos existentes. Após limpar, eu colo o diretório Loki C2 Agent /resources/app/ copiado anteriormente em ~/Desktop/teams/resources/app/.
Com essa modificação, executo o Teams.exe clicando nele. Como o executável do Teams é assinado pela Microsoft, o WDAC não o bloqueia. No System Informer, podemos ver que o processo do Teams foi criado com sucesso sem a intervenção do WDAC. No entanto, como substituí o diretório do Teams /resources/app/ pelo código do Loki C2 Agent, a aplicação Teams baseada em Electron agora executa o JavaScript do Loki C2 Agent dentro do processo confiável do Teams.
O processo do Teams faz chamadas de volta com sucesso para o cliente Loki C2, e eu executo vários comandos para demonstrar o controle remoto do servidor comprometido.
Após obter acesso inicial com Loki C2, identificamos múltiplas formas de executar um agente C2 de estágio 2 mais capaz, como Dragon, o C2 interno desenvolvido por Shawn Jones (@anthemtotheego) e por mim. Embora todos os diferentes métodos de escalonamento que descobrimos desde a criação inicial do Loki C2 não sejam divulgados nesta postagem, planejamos abordá-los em versões futuras.
Quando implementada corretamente, essa técnica continua contornando as soluções de Endpoint Detection & Response (EDR) de ponta. No entanto, sem um C2 de estágio 2 oculto, os operadores precisam confiar na execução de comandos via spawn , que executa comandos em processos secundários. Isso acionará rapidamente as detecções pós-invasão contra as principais EDRs.
O Loki C2 se alinha com a técnica MITRE ATT&CK T1218.011 - execução por proxy de binário do sistema: aplicações Electron.
Depois de pesquisar na internet, não encontrei essa técnica de esvaziar aplicações Electron e substituir o código por um C2 divulgado publicamente ou usado em campo. No entanto, após compartilhar o Loki C2 com red teams confiáveis, uma delas confirmou ter desenvolvido recursos semelhantes internamente.
Mesmo com um TTP MITRE ATT&CK, múltiplas publicações de pesquisa e uma entrada no LOLBAS, essa técnica de esvaziamento de aplicação Electron permanece indetectada. Minha suposição é que as soluções de EDR não se concentram na detecção disso, mas sim em indicadores pós-invasão, como a geração de processos secundários para executar comandos. Desde que desenvolvemos métodos para implementar o C2 de estágio 2 evitando essas detecções comuns pós-invasão, usamos essa técnica com sucesso em múltiplos engajamentos, evitando a detecção.
Com tudo isso em mente, da próxima vez que você ouvir um fornecedor prometendo "Cobertura MITRE de 100%", vale a pena questionar o que isso realmente significa...