
Gera shellcode independente de posição para x86, x64 ou AMD64+x86 que carrega assemblies .NET, arquivos PE e outros payloads do Windows a partir da memória e os executa com parâmetros.

Versão atual: v1.1
Donut é um código independente de posição que permite a execução em memória de arquivos VBScript, JScript, EXE, DLL e assemblies dotNET. Um módulo criado pelo Donut pode ser obtido de um servidor HTTP ou embutido diretamente no próprio carregador. O módulo é opcionalmente criptografado usando a cifra de bloco Chaskey e uma chave de 128 bits gerada aleatoriamente. Após o arquivo ser carregado e executado em memória, a referência original é apagada para dificultar scanners de memória. O gerador e o carregador suportam as seguintes funcionalidades:
Existem bibliotecas dinâmicas e estáticas tanto para Linux quanto para Windows que podem ser integradas em seus próprios projetos. Há também um módulo Python sobre o qual você pode ler mais em Compilando e usando a extensão Python.
Donut contém carregadores individuais para cada tipo de arquivo suportado. Para assemblies dotNET EXE/DLL, Donut usa a API Unmanaged CLR Hosting para carregar o Common Language Runtime. Uma vez que o CLR é carregado no processo hospedeiro, um novo Application Domain é criado para permitir a execução de Assemblies em AppDomains descartáveis. Quando o AppDomain está pronto, o Assembly dotNET é carregado via o método AppDomain.Load_3. Finalmente, o Ponto de Entrada para EXEs ou método público para DLLs especificado pelo usuário é invocado com quaisquer parâmetros adicionais. Consulte a MSDN para documentação sobre a API Unmanaged CLR Hosting. Para um exemplo independente de um CLR Host, consulte o código aqui.
Arquivos VBScript e JScript são executados usando a interface IActiveScript. Há também suporte mínimo para alguns dos métodos fornecidos pelo Windows Script Host (wscript/cscript). Para um exemplo independente, consulte o código aqui. Para uma descrição mais detalhada, leia: Execução em Memória de JavaScript, VBScript, JScript e XSL
Arquivos EXE/DLL não gerenciados ou nativos são executados usando um carregador PE personalizado com suporte para Importações Atrasadas, TLS e correção da linha de comando. Apenas arquivos com informações de realocação são suportados. Leia Execução em Memória de DLL para mais informações.
O carregador pode desabilitar AMSI e WLDP para ajudar a evitar a detecção de arquivos maliciosos executados em memória. Para mais informações, leia Como Equipes Vermelhas Contornam AMSI e WLDP para Código Dinâmico .NET. Ele também suporta descompressão de arquivos em memória usando aPLib ou a API RtlDecompressBuffer. Leia Compressão de Dados para mais informações.
A partir da v1.0, o ETW também é contornado. Assim como com AMSI/WLDP, este é um sistema modular que permite substituir o bypass padrão pelo seu próprio. O bypass padrão é derivado da pesquisa de XPN. Leia Escondendo seu .NET - ETW para mais informações.
Por padrão, o carregador sobrescreverá os cabeçalhos PE de PEs não gerenciados (do endereço base até `IMAGE_OPTIONAL_HEADER.SizeOfHeaders`). Se nenhum módulo falso for usado (sobrecarga de módulo), os cabeçalhos PE serão zerados. Se um módulo falso for usado, os cabeçalhos PE do módulo falso serão usados para sobrescrever os do módulo carregado. Isso visa dificultar a detecção por comparação dos cabeçalhos PE de módulos em memória com o arquivo que os originou em disco. O usuário pode solicitar que todos os cabeçalhos PE sejam preservados em seu estado original. Isso é útil para cenários onde o módulo carregado precisa acessar seus cabeçalhos PE, como ao procurar por recursos PE embutidos.
Para um passo a passo detalhado usando o gerador e como o Donut afeta as técnicas de operação, leia Donut - Injetando Assemblies .NET como Shellcode. Para mais informações sobre o carregador, leia Carregando Assemblies .NET a Partir da Memória.
Aqueles que desejam saber mais sobre os detalhes internos devem consultar as Notas do desenvolvedor.
Existem dois tipos de compilação. Se você deseja depurar o Donut, consulte a documentação aqui. Caso contrário, continue lendo para a compilação de lançamento.
De um prompt de comando do Windows ou terminal Linux, clone o repositório.
git clone http://github.com/thewover/donut.git
O próximo passo depende do seu sistema operacional e do compilador que você decidir usar. Atualmente, o modelo do gerador e do carregador para Donut pode ser compilado com sucesso tanto com Microsoft Visual Studio 2019 quanto com MingGW-64. Para usar as bibliotecas em seu próprio projeto C/C++, consulte os exemplos fornecidos aqui.
Para gerar o modelo do carregador, a biblioteca dinâmica donut.dll, a biblioteca estática donut.lib e o gerador donut.exe. Inicie um Prompt de Comando do Desenvolvedor Microsoft Visual Studio x64, mude para o diretório onde você clonou o repositório Donut e digite o seguinte:
nmake -f Makefile.msvc
Para fazer o mesmo, exceto usando MinGW-64 no Windows ou Linux, mude para o diretório onde você clonou o repositório Donut e digite o seguinte:
make -f Makefile.mingw
Para gerar a biblioteca dinâmica donut.so, a biblioteca estática donut.a e o gerador donut. Mude para o diretório onde você clonou o repositório Donut e simplesmente digite make.
Donut pode ser instalado e usado como um módulo Python. Para instalar a partir do código-fonte, é necessário o pip para Python3. Primeiro, certifique-se de que versões antigas do donut-shellcode não estão instaladas executando o seguinte comando no terminal Linux ou no prompt de comando do Microsoft Visual Studio.
pip3 uninstall donut-shellcode
Após confirmar que versões antigas não estão mais instaladas, execute o seguinte comando.
pip3 install .
Você também pode instalar o Donut como um módulo Python obtendo-o do repositório PyPi.
pip3 install donut-shellcode
Para mais informações, consulte Compilando e usando a extensão Python.
Compilando o contêiner Docker.
docker build -t donut .
Executando o donut.
docker run -it --rm -v "${PWD}:/workdir" donut -h
Donut inclui vários outros executáveis que podem ser compilados separadamente. Estes incluem "hash.exe", "encrypt.exe","inject.exe" e "inject_local.exe". Os dois primeiros são usados na geração de shellcode. Os dois últimos são fornecidos para auxiliar no teste do shellcode do donut. "inject.exe" injeta um arquivo binário bruto (loader.bin) em um processo por seu PID ou nome do processo. "inject_local.exe" injeta um arquivo binário bruto em seu próprio processo.
Para compilar esses executáveis de suporte separadamente, você pode usar o makefile MSVC. Por exemplo, para compilar "inject_local.exe" para testar seu shellcode donut, você pode executar.
nmake inject_local -f Makefile.msvc
Tags foram fornecidas para cada versão de lançamento do Donut que contêm os executáveis compilados.
Atualmente, existem dois outros geradores disponíveis.
A tabela a seguir lista os parâmetros suportados pela versão de linha de comando do gerador.
Existem alguns requisitos específicos que seu payload deve atender para que o Donut o carregue com sucesso.
Executáveis Cygwin usam rotinas de inicialização que esperam que o processo hospedeiro esteja sendo executado a partir do disco. Se executado a partir da memória, o processo hospedeiro provavelmente irá travar.
Existem quatro projetos complementares fornecidos com o donut:
Você pode querer adicionar suporte para mais tipos de payloads, alterar nosso conjunto de funcionalidades ou integrar o Donut em suas ferramentas existentes. Fornecemos documentação do desenvolvedor. Funcionalidades adicionais são deixadas como exercícios para o leitor. Nossas sugestões:
Se você tiver alguma pergunta ou comentário sobre o Donut. Junte-se ao canal #Donut no Slack BloodHound Gang
Não somos responsáveis por qualquer uso indevido deste software ou técnica. Donut é fornecido como uma demonstração de Injeção de CLR e carregamento em memória através de shellcode, a fim de fornecer às equipes vermelhas uma maneira de emular adversários e às equipes defensoras um ponto de referência para construir análises e mitigações. Isso inevitavelmente corre o risco de autores de malware e atores de ameaças o utilizarem indevidamente. No entanto, acreditamos que o benefício líquido supera o risco. Esperamos que isso esteja correto. No caso de produtos EDR ou AV serem capazes de detectar o Donut por meio de assinaturas ou padrões comportamentais, não atualizaremos o Donut para contrapor assinaturas ou métodos de detecção. Para evitar se ofender, por favor, não pergunte.
| Parâmetro | Argumento | Descrição |
|---|---|---|
| -a | arch | Arquitetura alvo para o carregador: 1=x86, 2=amd64, 3=x86+amd64 (padrão). |
| -b | level | Comportamento para contornar AMSI/WLDP: 1=Nenhum, 2=Abortar em caso de falha, 3=Continuar em caso de falha (padrão). |
| -k | headers | Preservar cabeçalhos PE. 1=Sobrescrever (padrão), 2=Manter todos. |
| -j | decoy | Caminho opcional do módulo falso para Sobrecarga de Módulo. |
| -c | class | Nome da classe opcional. (obrigatório para DLL .NET) Pode também incluir namespace: ex. namespace.class |
| -d | name | Nome do AppDomain a ser criado para .NET. Se a entropia estiver habilitada, um será gerado aleatoriamente. |
| -e | level | Nível de entropia. 1=Nenhum, 2=Gerar nomes aleatórios, 3=Gerar nomes aleatórios + usar criptografia simétrica (padrão). |
| -f | format | O formato de saída do carregador salvo em arquivo. 1=Binário (padrão), 2=Base64, 3=C, 4=Ruby, 5=Python, 6=PowerShell, 7=C#, 8=Hexadecimal. |
| -m | name | Método ou função opcional para DLL. (um método é obrigatório para DLL .NET) |
| -n | name | Nome do módulo para estagiamento HTTP. Se a entropia estiver habilitada, um é gerado aleatoriamente. |
| -o | path | Especifica onde o Donut deve salvar o carregador. O padrão é "loader.bin" no diretório atual. |
| -p | parameters | Parâmetros/linha de comando opcionais entre aspas para o método/função DLL ou EXE. |
| -r | version | Versão do runtime CLR. MetaHeader usado por padrão ou v4.0.30319 se nenhum estiver disponível. |
| -s | server | URL para o servidor HTTP que hospedará um módulo Donut. Credenciais podem ser fornecidas no seguinte formato: https://username:[email protected]/ |
| -t | Executar o ponto de entrada de um EXE não gerenciado/nativo como uma thread e aguardar o fim da thread. | |
| -w | A linha de comando é passada para a função DLL não gerenciada em formato UNICODE. (o padrão é ANSI) | |
| -x | option | Determina como o carregador deve sair. 1=sair da thread (padrão), 2=sair do processo, 3=Não sair nem limpar e bloquear indefinidamente. |
| -y | addr | Cria uma nova thread para o carregador e continua a execução em um endereço que é um deslocamento relativo ao executável do processo hospedeiro. O valor fornecido é o deslocamento. Esta opção suporta carregadores que desejam retomar a execução do processo hospedeiro após o donut completar a execução. |
| -z | engine | Empacotar/Comprimir o arquivo de entrada. 1=Nenhum, 2=aPLib, 3=LZNT1, 4=Xpress, 5=Xpress Huffman. Atualmente, os três últimos são suportados apenas no Windows. |
| Ferramenta | Descrição |
|---|---|
| DemoCreateProcess | Um Assembly .NET de exemplo para usar em testes. Aceita dois parâmetros de linha de comando, cada um especificando um programa a ser executado. |
| DonutTest | Um injetor de shellcode C# simples para usar em testes do donut. O shellcode deve ser codificado em base64 e copiado como uma string. |
| ModuleMonitor | Uma ferramenta de prova de conceito que detecta injeção de CLR como é feita por ferramentas como Donut e execute-assembly do Cobalt Strike. |
| ProcessManager | Uma ferramenta de Descoberta de Processos que operadores ofensivos podem usar para determinar no que injetar e operadores defensivos podem usar para determinar o que está em execução, quais propriedades esses processos têm e se eles têm o CLR carregado ou não. |