Exploração de enclaves VBS para criar malware evasivo
Sumário
Introdução
A VBS (Virtualization-Based Security, ou segurança baseada em virtualização) é uma das mais significativas inovações recentes em cibersegurança. A capacidade de isolar componentes críticos do sistema operacional permitiu à Microsoft alcançar avanços substanciais em segurança, com recursos como Credential Guard e HVCI (Hypervisor-Protected Code Integrity).
Uma funcionalidade frequentemente negligenciada, possibilitada pelo VBS, são os enclaves VBS, uma tecnologia que permite isolar uma região de um processo, tornando-a inacessível para outros processos, para o próprio e até mesmo para o kernel.
Os enclaves VBS possuem uma ampla gama de aplicações em segurança, sendo utilizados pela Microsoft para implementar diversos serviços importantes, incluindo o polêmico recurso Recall. Além disso, a Microsoft incentiva o desenvolvimento de enclaves VBS por terceiros e promove ativamente sua adoção.
Embora os enclaves tenham sido projetados para aprimorar a segurança dos sistemas, eles também podem ser explorados por invasores: um malware executado dentro de um enclave pode se tornar praticamente invisível para mecanismos de detecção baseados em análise forense e de memória.
Nosso objetivo foi explorar os enclaves VBS e compreender como eles podem ser utilizados para fins maliciosos. Este artigo detalha nossas principais descobertas. Vamos aprofundar a análise dos enclaves VBS, explorando comportamentos ainda não documentados, descrevendo diferentes cenários que poderiam permitir a execução de código malicioso dentro deles e examinando as diversas técnicas que um "malware de enclave" pode empregar.
Também apresentaremos o Mirage, uma técnica de evasão de memória baseada em uma abordagem inovadora que chamamos de"Bring your own vulnerable enclave" (Traga seu próprio enclave). Vamos explorar como invasores podem utilizar versões antigas e vulneráveis de enclaves legítimos para implementar essa técnica furtiva de evasão.
Níveis de confiança virtual
Historicamente, o Windows confiava nos níveis de privilégio do processador (processor ring levels) para impedir que aplicativos em modo de usuário alterassem o sistema operacional. Essa funcionalidade de hardware permite a separação entre o sistema operacional e os aplicativos do usuário: o kernel opera no ring0, isolado dos aplicativos que rodam no ring3 (modo de usuário). O problema dessa abordagem é que ela oferece aos invasores um caminho relativamente fácil para comprometer o sistema operacional: as explorações no kernel.
O kernel do Windows expõe uma superfície de ataque muito rica. Uma grande lista de drivers de terceiros, junto a uma ampla variedade de serviços expostos pelo próprio kernel, leva ao desenvolvimento de um fluxo aparentemente constante de explorações no kernel. Usando uma exploração desse tipo, um invasor poderia controlar todos os aspectos do sistema operacional. A barreira entre os modos de usuário/kernel estava se mostrando insuficiente.
Para fechar essa lacuna, a Microsoft introduziu uma nova camada de segurança no sistema operacional na forma de VTLs (Virtual Trust Levels, ou níveis de confiança virtual). Os privilégios de VTL são baseados no acesso à memória — cada nível de confiança fornece às entidades que operam sob ele diferentes permissões de acesso à memória física. Entre outras coisas, essas permissões garantem que níveis inferiores de VTL não possam acessar a memória de níveis superiores.
Semelhante à arquitetura tradicional de anéis de processador, os VTLs segmentam o sistema operacional em diferentes "modos" de execução, começando do VTL0 e indo até (potencialmente) o VTL16. Ao contrário dos níveis de privilégio do processador, onde o ring0 é o mais privilegiado, os VTLs mais altos são mais privilegiados do que os níveis inferiores.
Atualmente, o Windows usa dois níveis principais de confiança: VTL0 e VTL1 (o VTL2 também é utilizado, mas está fora do escopo deste post). O VTL0 é usado para executar os componentes tradicionais do sistema operacional, incluindo o kernel e os aplicativos no modo de usuário. O VTL1, que é mais privilegiado que o VTL0, cria dois novos modos de execução: modo kernel seguro e modo de usuário isolado.
Modo kernel seguro
O modo kernel seguro refere-se ao modo de execução VTL1 ring0. Esse modo é utilizado para executar o kernel seguro, um kernel que roda em VTL1 e, portanto, é mais privilegiado do que o kernel normal. Usando esses privilégios, o kernel seguro pode impor políticas sobre o kernel normal e restringir seu acesso a regiões sensíveis da memória.
Como observamos, o kernel expõe uma grande superfície de ataque e é vulnerável a comprometimentos. Ao remover alguns privilégios do kernel normal e concedê-los ao kernel seguro, podemos reduzir o impacto de um comprometimento.
Em teoria, uma comprometimento do kernel seguro ainda poderia permitir que um invasor comprometesse completamente o sistema. Apesar disso, esse cenário é muito menos provável, pois o kernel seguro é bastante restrito e não dá suporte a drivers de terceiros, o que cria uma superfície de ataque significativamente reduzida.
Modo de usuário isolado
O VTL1 também cria outro modo de execução interessante, chamado modo de usuário isolado (IUM), que se refere ao modo de execução VTL1 ring3. O IUM é utilizado para executar processos seguros, um tipo especial de processo em modo de usuário que aproveita as capacidades de isolamento de memória do VTL1. A memória dentro do IUM não pode ser acessada por nenhum código VTL0, incluindo o kernel normal. Esse modo de execução é a base para funcionalidades baseadas em isolamento, como o Credential Guard.
Em resumo, a introdução de VTL0/1 resulta em quatro modos de execução (Figura 1).
- Ring0 VTL0 — modo kernel normal
- Ring0 VTL1 — modo kernel seguro
- Ring3 VTL0 — modo de usuário normal
- Ring3 VTL1 — modo de usuário isolado
O que são enclaves VBS?
Outra funcionalidade que é habilitada através do IUM são os enclaves VBS. Um enclave VBS é uma seção de um processo em modo de usuário que reside no IUM, onde podemos carregar DLLs chamadas "módulos de enclave".
Quando um módulo é carregado em um enclave, ele se torna um "ambiente de execução confiável" — os dados e o código dentro do enclave ficam inacessíveis a qualquer coisa executada em VTL0 e, portanto, não podem ser adulterados ou roubados (Figura 2). Esse recurso é útil para isolar operações sensíveis de invasores que podem comprometer o sistema.
Um processo em modo de usuário pode chamar as APIs dedicadas do Windows para criar um enclave, carregar um módulo nele e inicializá-lo. Um módulo de enclave vem na forma de uma DLL que foi compilada especificamente para esse propósito. Após a inicialização do enclave, o processo de modo de usuário que o hospeda não pode acessar sua memória, e só pode interagir com ele invocando as funções exportadas pelos seus módulos usando a API CallEnclave .
A Figura 3 é um exemplo de código implementando esse processo (um exemplo mais detalhado é fornecido pela Microsoft).
Como a Microsoft visa restringir ao máximo o acesso ao VTL1, carregar uma DLL em um enclave requer que ela seja corretamente assinada usando um certificado especial emitido pela Microsoft. Qualquer tentativa de carregar um módulo sem essa assinatura falhará. A opção de assinar módulos de enclave é delegada apenas a terceiros confiáveis. Curiosamente, não há restrições sobre quem pode carregar esses módulos arbitrários em um enclave, desde que sejam assinados.
Os módulos de enclave são projetados para funcionar como pequenas “unidades computacionais”, com uma capacidade muito limitada de interagir com ou afetar o sistema. Por essa razão, eles são restritos ao uso de um conjunto mínimo de APIs,o que impede o acesso à maioria dos componentes do sistema operacional.
As APIs disponíveis dentro de enclaves são importadas de bibliotecas dedicadas carregadas no VTL1. Por exemplo, enquanto processos normais dependem da biblioteca ntdll.dll para solicitar serviços do sistema operacional, os módulos de enclave usam a vertdll.dll, uma "substituta" da ntdll utilizada para se comunicar com o kernel seguro por meio de syscalls.
Malware de enclave
O conceito de malware de enclave pode ser muito atraente para os invasores, pois oferece duas vantagens significativas:
Execução em uma região isolada da memória: o espaço de endereçamento dos enclaves é inacessível a qualquer código em execução no VTL0, o que inclui EDRs e ferramentas de análise, tornando a detecção muito mais complexa.
Chamadas de API indetectáveis: as chamadas de API feitas de dentro de um enclave podem ser invisíveis a EDRs. Normalmente, as EDRs monitoram as APIs em modo de usuário colocando hooks em bibliotecas do sistema e utilizando drivers para monitorar a atividade no kernel. No entanto, chamadas de API disparadas de dentro de um enclave não podem ser detectadas por essas técnicas, pois as chamadas de enclave são realizadas a partir do VTL1 e não passam por nenhum dos componentes do VTL0 que são "monitorados" por essas ferramentas.
A Figura 4 mostra essa vantagem: um processo normal que invoca uma API do Windows pode ser monitorado por meio de um hook dentro da NTDLL ou o próprio kernel. No entanto, um módulo de enclave passa pela vertdll residente no VTL1 e invoca chamadas para o kernel seguro — os dois igualmente inacessíveis a EDRs.
Reconhecendo esse potencial, decidimos investigar o conceito de malware de enclave. Para explorar enclaves para esse fim, duas questões precisam ser abordadas:
- Como os invasores podem executar código malicioso dentro de um enclave?
- Quais técnicas os invasores podem empregar uma vez dentro de um enclave?
Como os invasores podem executar código malicioso dentro de um enclave?
Como mencionamos anteriormente, os módulos de enclave precisam ser assinados com um certificado emitido pela Microsoft para serem carregados, o que significa que apenas entidades aprovadas por ela deveriam ser capazes de executar seu próprio código dentro de um enclave. No entanto, os invasores ainda têm algumas opções.
Primeiro, um invasor pode se aproveitar de uma vulnerabilidade do sistema operacional. Um exemplo disso ocorreu com a CVE-2024-49706, uma vulnerabilidade descoberta por Alex Ionescu (da Winsider Seminars & Solutions), que poderia permitir que um invasor carregasse um módulo não assinado em um enclave. Essa vulnerabilidade foi corrigida pela Microsoft, mas invasores motivados podem identificar bugs semelhantes no futuro.
Uma segunda abordagem direta seria obter uma assinatura legítima — isso poderia ocorrer, já que a Microsoft expõe a assinatura de enclaves para terceiros através da plataforma Trusted Signing . Embora certamente não seja trivial, um invasor avançado poderia conseguir acesso a uma entidade do Trusted Signing e assinar seus próprios enclaves.
Além dessas duas opções, exploramos duas técnicas adicionais que podem permitir que invasores executem código dentro de um enclave VBS: abusar de módulos de enclave depuráveis e explorar enclaves vulneráveis.
Abuso de módulos de enclave depuráveis
Quando um desenvolvedor cria um módulo de enclave VBS, ele pode configurá-lo como depurável. Compilar um módulo com essa configuração permite, bem... depurá-lo. Como os módulos de enclave são executados no VTL1, normalmente não é possível depurá-los, pois o depurador não consegue acessar a memória do enclave para recuperar dados ou colocar pontos de interrupção. A Figura 5 apresenta um exemplo em que um depurador falha ao tentar acessar um endereço de memória dentro de um enclave.
Curiosamente, quando um módulo de enclave depurável é executado, ele ainda é carregado no VTL1. Para permitir a depuração, o kernel seguro implementa algumas exceções que se aplicam aos módulos de enclave depuráveis. Por exemplo, ao tentar ler a memória de um módulo desse tipo, o kernel normal emite uma chamada para a chamada do kernel seguro SkmmDebugReadWriteMemory , que verifica se o módulo de destino é realmente depurável antes de realizar a operação solicitada.
Como demonstrado na Figura 6, após carregar um enclave com suporte à depuração, o depurador consegue ler a memória do enclave corretamente.
De forma similar, as permissões de memória dentro de um módulo de enclave depurável também podem ser modificadas pelo processo VTL0 (uma exceção implementada na chamada SkmmDebugProtectVirtualMemory do kernel seguro).
A Microsoft recomenda fortemente que os desenvolvedores evitem distribuir módulos de enclave depuráveis, pois isso compromete o principal objetivo dos enclaves: isolar uma seção da memória VTL0 (Figura 7). Usar um módulo depurável significa que os dados tratados por ele podem ser facilmente expostos.
Os riscos de um aplicativo em produção executar um módulo de enclave depurável são claros, mas os invasores podem abusar disso para outro propósito: executar código não assinado no VTL1. Se um invasor obtiver qualquer módulo de enclave assinado e depurável, ele pode realizar a execução de código no VTL1 através dos quatro passos a seguir:
- Obter o endereço de uma rotina dentro do módulo de enclave usando o GetProcAddress
- Alterar a proteção de memória da rotina para RWX
- Substituir o código da rotina por shellcode arbitrário
- Acionar a rotina usando o CallEnclave
A Figura 8 ilustra um código que implementa esse processo.
O problema óbvio para o invasor é que isso é uma espada de dois gumes — assim como o invasor pode acessar a memória do enclave, uma ferramenta EDR também pode fazê-lo. Apesar disso, essa abordagem tem a vantagem de evadir o monitoramento de APIs — chamadas de API realizadas pelo módulo de enclave ainda passam pelas DLLs do VTL1 e pelo kernel seguro, limitando a visibilidade das EDRs.
No geral, esse método pode ser útil para criar um implante "semi-VTL1" furtivo, que aproveita algumas das vantagens obtidas por rodar dentro de um enclave.
Tentamos usar o VirusTotal e outras fontes para identificar um módulo de enclave assinado e depurável, mas até o momento da escrita, não fomos bem-sucedidos. No entanto, acreditamos que é seguro supor que, com o tempo, e à medida que a tecnologia de enclaves se populariza, alguns módulos vão acabar vazando.
Bring your own vulnerable enclave (Traga seu próprio enclave)
Como discutimos, o Windows usa assinaturas para impedir o carregamento de enclaves não confiáveis no VTL1. Essa abordagem não é única para enclaves; o conceito surgiu através da imposição de assinatura de drivers (DSE), que impede drivers não confiáveis de serem executados no kernel do Windows.
Para contornar essa imposição, os invasores começaram a usar a técnica BYOVD, ou seja, o invasor não pode carregar seu próprio driver, então ele carrega um driver legítimo assinado com uma vulnerabilidade conhecida. Ele pode então explorar essa vulnerabilidade para executar código não assinado no kernel.
Nos propusemos a explorar essa abordagem no contexto dos enclaves: podemos abusar de um módulo de enclave assinado vulnerável para executar código no IUM?
O primeiro passo foi encontrar esse enclave, o que nos levou rapidamente à CVE-2023-36880 , uma vulnerabilidade em um módulo de enclave VBS usado pelo Microsoft Edge. A vulnerabilidade permite que um invasor leia e grave dados arbitrários dentro do enclave. Embora a Microsoft tenha classificado essa vulnerabilidade como um problema de divulgação de informações, as notas mencionam que ela também pode permitir execução limitada de código (Figura 9).
A vulnerabilidade foi descoberta por Alex Gough, da equipe de segurança do Chrome, que também compartilhou uma prova de conceito para explorá-la. Após encontrarmos uma versão vulnerável desse enclave no VirusTotal,começamos a tentar explorá-la para obter a execução de código.
Nossa ideia era abusar da primitiva de leitura/gravação para substituir a pilha do enclave com uma cadeia ROP, o que nos permitiria executar shellcode dentro do enclave. Enquanto explorávamos essa opção, nos deparamos com um fato interessante: os enclaves são protegidos contra execução de código não assinado por meio do ACG (Arbitrary Code Guard).
O ACG é uma mitigação de segurança projetada para bloquear a execução de código gerado dinamicamente, ou seja, código criado em tempo de execução, ao invés de fazer parte do executável original do processo ou suas bibliotecas DLL. O ACG é implementado por meio da aplicação de duas regras:
- Novas páginas executáveis não podem ser geradas após o carregamento inicial do processo.
- Uma página que já é executável não pode se tornar gravável.
O ACG é aplicado por padrão no kernel normal, mas no modo de usuário, ele só se aplica a processos configurados para utilizá-lo. Nossa pesquisa mostrou que, para processos do IUM (que incluem enclaves), o ACG parece ser aplicado automaticamente, assim como ocorre no kernel normal.
Podemos observar isso ao tentar alocar uma nova página de RWX dentro de um enclave usando o VirtualAlloc; a operação falha com o código de erro 0x677, STATUS_DYNAMIC_CODE_BLOCKED (Figura 10). Tentar usar o VirtualProtect para modificar as permissões de uma página executável ou torná-la executável resulta no mesmo erro.
Para entender esse comportamento, podemos examinar SecureKernel!NtAllocateVirtualMemoryEx, que é a função do kernel seguro responsável pela alocação dinâmica de memória no IUM. A função avalia a máscara de proteção solicitada e, se uma página executável for requisitada, retorna o erro do ACG STATUS_DYNAMIC_CODE_BLOCKED. Verificações semelhantes são implementadas na SkmmProtectVirtualMemory para impedir mudanças em páginas existentes dentro do IUM (Figura 11).
Não encontramos um método para contornar o ACG dentro de um enclave e carregar código não assinado nele. Em teoria, uma exploração completa de ROP é possível — permitindo que invasores invoquem APIs arbitrárias no VTL1, por exemplo — mas não seguimos por essa direção. Apesar disso, ainda conseguimos identificar outra aplicação interessante para enclaves vulneráveis, que discutiremos mais adiante neste post.
Quais técnicas os invasores podem empregar uma vez dentro de um enclave?
Entendendo que os enclaves têm grande potencial para atividades maliciosas e que sua inicialização pode ser possível para um invasor motivado, a próxima questão que abordamos foi quais técnicas poderiam estar disponíveis para esse tipo de malware.
O propósito mais direto seria utilizar os enclaves exatamente como foram projetados para ser usados. Assim como um enclave pode proteger dados confidenciais contra invasores, ele também pode ser usado pelos invasores para esconder seus próprios "segredos" de entidades VTL0.
Isso poderia ser útil em várias situações: armazenar cargas úteis fora do alcance de EDRs, manter chaves de criptografia escondidas de analistas ou manter configurações sensíveis de malware longe de despejos de memória.
Quanto a opções mais avançadas, muitas técnicas tradicionais de malware são impossíveis de implementar dentro de um enclave. Como os enclaves são restritos a um conjunto limitado de APIs do sistema, eles são impedidos de interagir com componentes chave do SO, como arquivos, o registro, redes, outros processos, entre outros.
Apesar disso, ainda existem várias técnicas que podem ser realizadas dentro de um enclave, permitindo aproveitar as vantagens adquiridas ao operar em um IUM.
Acesso à memória no modo de usuário do VTL0
Apesar do acesso limitado ao sistema, os enclaves ainda podem acessar um recurso crítico: a memória do processo. Os enclaves podem realizar operações de leitura/gravação dentro de todo o espaço de endereços do processo, incluindo o VTL0.
Algumas restrições se aplicam a esse acesso: o código executado dentro dos enclaves segue as permissões da memória e não pode alterá-las. Isso significa que um enclave não será capaz de gravar em memória não gravável, nem tornar a memória não executável em executável. A Figura 12 apresenta um código executado dentro de um enclave, demonstrando diferentes possibilidades e restrições.
Ao acessar a memória do modo de usuário do VTL0, podemos implementar várias técnicas úteis. Ao carregar um enclave malicioso em um processo alvo, podemos monitorar e roubar informações confidenciais de forma furtiva ou alterar valores dentro do processo para modificar seu comportamento.
Implementar essas técnicas usando um enclave oferece uma vantagem significativa: como descrevemos anteriormente, acionar APIs a partir de um enclave nos permite evitar o monitoramento de EDRs. Como o acesso à memória nessas técnicas é realizado por um enclave, elas podem permanecer invisíveis.
Execução de código no modo de usuário do VTL0
Embora um enclave possa ler/gravar na memória do modo de usuário do VTL0, desde que tenha as permissões apropriadas, o código armazenado no VTL0 nunca pode ser executado dentro de um enclave, mesmo que tenha permissões de execução.
Apesar de não ser capaz de rodar código do VTL0 dentro de um enclave, ele tem a opção de acionar esse código "remotamente". Ao usar a API CallEnclave com um endereço VTL0, um enclave pode acionar a execução de código do VTL0 em uma thread normal de modo de usuário (Figura 13).
Ao fazer com que o processo no modo de usuário "atue em seu nome", os enclaves podem acessar o sistema de formas que normalmente não seriam possíveis para eles. Por exemplo, um enclave pode acionar uma rotina de VTL0 que leia um arquivo, crie um soquete e assim por diante.
É importante notar que executar código no modo de usuário dessa maneira não oferece vantagem em termos de evasão, já que o código é executado como qualquer outro código de modo de usuário, ele pode ser visível para EDRs.
Antidepuração
Outra aplicação interessante para o malware de enclave é a de antidepuração. O fato de o código executado dentro do enclave permanecer inacessível para aplicativos do VTL0, incluindo depuradores, oferece ao malware uma vantagem significativa sobre eles.
A redução nas APIs expostas aos enclaves significa que nem todas as técnicas tradicionais antidepuração estarão disponíveis dentro de um enclave. Por exemplo, as APIs NtQueryInformationProcess ou IsDebuggerPresent e todas as de data e hora não estão disponíveis para enclaves. Apesar disso, ainda existem algumas opções.
Primeiro, podemos contar com o acesso do enclave ao espaço de endereços VTL0 do processo, permitindo que ele leia manualmente o PEB do processo e verifique o valor do sinalizador"BeingDebugged". Se um depurador for detectado, o processo pode ser finalizado pelo enclave.
Outra abordagem seria a implementação de uma técnica antidepuração baseada em tempo (Figura 14). Embora as APIs de data e hora não estejam disponíveis para enclaves, elas ainda podem usar a instrução assembly rdtsc . Essa instrução retorna o número de ciclos de clock do processador desde a inicialização. Usando-a, podemos medir o tempo gasto entre diferentes chamadas de enclave e finalizar o processo se for detectado um atraso significativo.
Ao mover partes críticas do nosso código para um enclave com uma verificação de antidepuração, podemos criar um malware que seja quase completamente imune à análise dinâmica. O malware depende do enclave para funcionar corretamente, enquanto o processo no modo de usuário não pode modificar as verificações que estão sendo executadas dentro dele. Se implementada corretamente, essa abordagem só poderia ser derrotada ao depurar o Hyper-V ou o kernel seguro.
BYOVE — Rodada 2
Em uma seção anterior, tentamos explorar um módulo vulnerável de enclave para alcançar a execução de código no IUM. Quando percebemos que isso poderia não ser possível, pensamos em ver se o conceito de BYOVE poderia ter outras aplicações e decidimos explorar mais a fundo o módulo de enclave vulnerável.
A vulnerabilidade (CVE-2023-36880) decorre das funções SealSettings e UnsealSettings que são exportadas pelo módulo do enclave. A função SealSettings recebe um ponteiro para um buffer de dados, o criptografa e grava os resultados em um endereço de destino fornecido pelo chamador. UnsealSettings funciona de maneira semelhante, descriptografando um buffer fornecido e gravando-o em um endereço especificado.
O problema com as duas funções é que elas não validam nem o endereço de destino nem o endereço do buffer de origem, permitindo que esses apontem para qualquer endereço dentro do processo, incluindo endereços dentro do próprio enclave. A Figura 15 ilustra o código vulnerável, mostrando a UnsealSettings realizando um memcpy para um endereço arbitrário fornecido pelo usuário.
Essa vulnerabilidade concede a um invasor duas capacidades (Figura 16).
Gravação arbitrária dentro do enclave: um invasor pode chamar SealSettings para criptografar dados arbitrários e, em seguida, UnsealSettings para apontar para um endereço de destino dentro do enclave. Isso resulta na gravação dos dados originais na memória do enclave.
Leitura arbitrária dentro do enclave: um invasor pode chamar SealSettings, fornecendo um endereço dentro do enclave como ponteiro para o buffer de origem. Isso fará com que o enclave criptografe os dados da memória do enclave e os grave em um local controlado pelo invasor. O invasor pode então descriptografar esses dados chamando UnsealSettings, o que permite a leitura de dados arbitrários do enclave.
Mirage — evasão de memória baseada em VTL1
Embora isso não tenha permitido a execução de código em VTL1, o primitivo de gravação arbitrária oferece duas habilidades únicas:
Armazenar dados arbitrários no VTL1, tornando-os inacessíveis para entidades VTL0.
Gravar dados arbitrários no espaço de endereçamento do processo normal (VTL0) a partir do VTL1, impedindo que entidades VTL0 monitorem essa operação.
Além disso, como essas capacidades são facilitadas pelo carregamento de um módulo de enclave assinado, elas podem ser usadas por qualquer invasor,sem que seja necessário que eles assinem nada.
Para demonstrar o potencial dessas capacidades, criamos uma técnica de evasão de escaneamento de memória chamada "Mirage". O Mirage se inspira no Gargoyle,uma técnica de evasão que cria uma carga útil que alterna continuamente entre um estado benigno e um estado armado (Figura 17).
Enquanto o Gargoyle implementa isso alternando entre memória executável e não executável, o Mirage visa alcançar um resultado semelhante ao transitar entre as memórias VTL1 e VTL0 — ele armazena o shellcode na memória do enclave no VTL1, transfere-o periodicamente para o VTL0 usando a vulnerabilidade, executa-o e depois apaga-o rapidamente da memória VTL0 (Figura 18).
Essa abordagem possui duas principais vantagens. Primeiro, como a carga útil passa a maior parte do tempo oculta no VTL1, ela é resistente a varreduras e despejos de memória. Isso é vantajoso em relação à técnica Gargoyle, pois, durante seu estágio inativo, nossa carga útil não é apenas "furtiva", mas inacessível.
A segunda vantagem é que a gravação do shellcode em VTL0 é realizada pelo enclave. Como já mencionamos, as EDRs não conseguem monitorar o código executando em VTL1, o que significa que os hooks típicos de EDRs não serão capazes de interceptar o shellcode enquanto ele está sendo gravado na memória.
Desenvolvemos uma PoC para o Mirage (Figura 19). Essa PoC tem como objetivo apenas demonstrar a ideia por trás da técnica, e portanto, não está totalmente armada para uso malicioso.
Detecção
Atualmente, os enclaves são usados por um número muito limitado de aplicativos. Mesmo que se tornem mais amplamente adotados, ainda assim serão carregados apenas por processos específicos, e não por processos arbitrários. Por exemplo, calc.exe provavelmente nunca deve carregar um enclave VBS.
Por conta disso, o uso anômalo de enclaves pode ser uma excelente oportunidade de detecção. Os defensores devem aproveitar essa oportunidade criando uma linha de base de usos legítimos conhecidos de enclaves VBS e sinalizando qualquer desvio. O uso de enclaves pode ser identificado de duas maneiras: monitorando as APIs dos enclaves e detectando as DLLs de enclaves carregadas.
APIs de enclaves
As seguintes APIs são usadas para gerenciar enclaves VBS por um processo de host, e provavelmente indicam que um enclave está sendo carregado:
- CreateEnclave
- LoadEnclaveImageW
- InitializeEnclave
- CallEnclave
- DeleteEnclave
- TerminateEnclave
DLLs de enclaves carregadas
Outra opção para detectar o uso anômalo de enclaves seria detectar o carregamento de DLLs de ambiente que são tipicamente usadas por eles, como: Vertdll.dll e ucrtbase_enclave.dll. Como essas DLLs não devem ser usadas por nada além de um enclave, sua presença indica que o processo provavelmente está utilizando um.
Conclusão
Os enclaves VBS são uma ferramenta incrível para os desenvolvedores protegerem seções sensíveis de seus aplicativos mas, como mostramos, também podem ser usados por agentes maliciosos para "proteger" seu malware. Embora esse conceito ainda seja teórico em grande parte, é certamente possível que agentes de ameaças avançadas comecem a usar enclaves VBS para fins maliciosos no futuro.
Agradecimentos
Gostaríamos de agradecer o trabalho realizado por Matteo Malvica, da Offsec, e Cedric Van Bockhaven, da Outflank, que recentemente conduziram um projeto de pesquisa muito semelhante a esse. Confira o primeiro post no blog deles, de uma série em duas partes, e fique ligado para a parte 2 que será publicada após o Insomni’Hack 2025.