
Implante de canal oculto DNS para Red Teams.
WEASEL é um pequeno implante em memória que utiliza Python 3 sem dependências. O cliente beacon envia uma pequena quantidade de informações de identificação sobre seu host para uma zona DNS que você controla. O servidor WEASEL pode instruir os clientes a executar comandos pré-definidos ou arbitrários.
WEASEL é uma carga útil do estágio 1, projetada para ser difícil de detectar e útil para recuperar o acesso quando seus estágios completos e barulhentos são capturados.
Status
Consulte o uso no README do cliente e no README do servidor para instruções específicas.
Para iniciar o servidor ou o cliente, execute os scripts diretamente ou passe-os para o interpretador Python.
Certifique-se de que cada domínio C2 tenha um registro NS apontando para o endereço IP do host que executa o server.py.
O WEASEL requer Python 3.6+.
O cliente é autossuficiente e usa apenas bibliotecas padrão, portanto, pode ser executado em macOS, Linux, etc.
O servidor tem algumas dependências do pip, incluídas no requirements.txt do servidor. O servidor deve ser executado no Linux, mas não há nada que impeça sua execução no macOS ou outros *nix.
Neste caso, não é necessário ofuscar e minimizar o beacon. As declarações de impressão são preservadas. Como no Uso acima, certifique-se de que os registros NS para o(s) domínio(s) em servers no beacon.py apontem para o endereço IP do server.py.
No host do servidor:
sudo python3 server.py
No host da vítima (pode ser o mesmo do servidor):
python3 beacon.py
Você não precisa entender nada disso para usar o WEASEL.
O Beacon se comunica via DNS usando consultas e respostas AAAA. Ele não usa registros TXT devido ao fato de serem conhecidos por serem usados por malwares e túneis DNS. As equipes azuis geralmente têm detecções de tunelamento DNS que alertam sobre grandes consultas TXT.
O lado do cliente não precisa de root para operar, não usa sockets brutos e não cria pacotes DNS malformados. Ele usa interfaces regulares fornecidas pelo sistema e pela linguagem para fazer solicitações DNS. As informações são codificadas + criptografadas nos próprios registros.
Este beacon foi projetado para ser lento e discreto, com pouca largura de banda. Deve nos informar em quais hosts está e nos dar uma maneira de lançar estágios adicionais conforme necessário, e nada mais. Embora tenha suporte a comandos arbitrários, não se destina a ser usado como um shell interativo regular ou canal de comunicação.
WEASEL é um estágio 1 que você mantém em execução, garantindo acesso contínuo à medida que seus estágios completos (e, portanto, mais barulhentos) são capturados.
O WEASEL foi inicialmente direcionado para servidores com alto tempo de atividade, onde tínhamos um vetor de exploração/ponto de apoio confiável. Evitar a forense era uma prioridade alta. Como resultado, ele não possui recursos de persistência nativos.
Você pode torná-lo persistente adicionando sua execução à sua técnica de persistência favorita, o que fica como exercício para o leitor :)
Uma solicitação (do cliente) é uma única consulta AAAA para um nome formatado como:
<preâmbulo><dados>.<fluxo>.<sessão>.domínio.tld
O preâmbulo tem 2 bytes. O Preâmbulo[0] é o número de sequência desse pacote. O Preâmbulo[1] é o número total de pacotes nesse fluxo.
Os dados são limitados a 50 bytes (configurável) e contêm a carga útil. A carga útil é codificada em base32 com um alfabeto personalizado.
Primeiro, todos os caracteres 'w' são trocados por '-'.
Em seguida, o caractere de preenchimento é trocado de '=' para 'w' para estar em conformidade com o conjunto de caracteres DNS: [a-z0-9] e [-].
Não trocamos '=' por '-' diretamente porque o preenchimento estará sempre no final da string, e terminar um nome de host em '---' é suspeito e contra a RFC do DNS. Dessa forma, quando uma string tiver preenchimento, ela terminará em 'www', que é menos suspeito e está em conformidade com a RFC.
Uma resposta (do servidor) é composta por uma ou mais respostas AAAA.
Cada resposta AAAA é uma carga útil criptografada de 16 bytes representada como um endereço IPv6 usando socket.inet_ntop. As respostas em uma resposta DNS não mantêm sua ordem durante o trânsito, portanto, são sequenciadas e remontadas como as solicitações do cliente.
A carga útil do transporte é uma string de elementos de dados separados pelo caractere ^.
As solicitações e respostas seguem este formato:
<tipo>|<dados>
As sessões são de longa duração: um cliente inicia uma sessão quando o beacon é executado pela primeira vez, e essa sessão deve durar todo o tempo em que o beacon estiver ativo naquele cliente. Observe que, como o beacon está na memória e não é persistente, os dados da sessão são armazenados na memória do processo Python. Qualquer nova invocação do beacon iniciará uma nova sessão.
Iniciar uma sessão envolve o cliente criar uma mensagem com um preâmbulo não-dados exclusivamente identificador (para sinalizar ao servidor que esta é uma nova sessão): a concatenação de uma chave pública Diffie-Hellman de 32 bytes e um IV AES aleatório de 16 bytes.
O servidor recebe isso e responde com sua própria chave pública de 32 bytes. Neste ponto, o cliente e o servidor estabeleceram uma chave de sessão compartilhada que será usada durante toda a vida útil desta sessão para criptografar as cargas úteis de dados usando AES-128 no modo CTR. A troca Diffie-Hellman Efêmera garante que cada conexão cliente-servidor use uma chave de sessão única com sigilo de encaminhamento.
A criptografia é propositalmente fraca por vários motivos:
Aqui estão alguns problemas conhecidos com o esquema de criptografia:
p é o Grupo 5 da RFC 3526 truncado para os primeiros 32 bytes. Isso não apenas limita as chaves públicas e privadas a 32 bytes, mas o Grupo 5 já está obsoleto e recomendado contra. Chamo essa má decisão de "Grupo 1".a em vez de um CSPRNG.Cada mensagem enviada entre um cliente e um servidor precisa ser dividida em pacotes de no máximo 50 bytes, para permanecer abaixo do limite de 52 bytes para detecções comuns de canais encobertos DNS. Todos os pacotes de uma mensagem específica fazem parte do mesmo fluxo. Mensagem == Fluxo.
Os fluxos são identificados com um número hexadecimal aleatório de 2 bytes. Lembre-se de que o formato da solicitação do cliente é:
<preâmbulo><dados>.<fluxo>.<sessão>.domínio.tld
O preâmbulo de 2 bytes de cada pacote no fluxo tem um número de sequência e o número total de pacotes nesse fluxo. Isso permite que o servidor saiba quando tudo chegou.
Por ser DNS, estamos fazendo isso tudo por UDP, que não fornece garantias sobre a ordem em que os datagramas chegarão. É por isso que o WEASEL precisa lidar com sequenciamento, remontagem e rastreamento de vários fluxos de muitos beacons.
Cada fluxo reinicializa uma cifra AES-128-CTR globalmente compartilhada para criptografar/descriptografar cargas úteis.
A carga útil só pode ser descriptografada quando um fluxo estiver completo (todos os pacotes chegarem). Se não fosse pelo base32, poderíamos descriptografar o que temos da mensagem mesmo se estivéssemos perdendo pacotes (porque AES-CTR é uma cifra de fluxo), mas não podemos decodificar base32 de fluxos parciais. Azar. Pela natureza dos clientes DNS, as solicitações são feitas várias vezes (geralmente 2 ou 4 vezes) até que uma resposta seja recebida, portanto, temos uma boa probabilidade de receber todos os pacotes em um fluxo, pois cada pacote deve ser enviado pelo cliente pelo menos duas vezes. Se perdermos pacotes ou fluxos, não é grande coisa; o beacon fará check-in novamente mais tarde e provavelmente terá mais sorte então.
Consulte o arquivo CONTRIBUTING para saber como ajudar.
WEASEL é licenciado sob MIT, conforme encontrado no arquivo LICENSE.
| Tipo | Significado (remetente) | AKA | Dados |
|---|
| 0 | Reconhecido | ACK | Hex aleatório |
| 1 | Check-in (cliente) | PING | Hex aleatório |
| 2 | Encerre-se (servidor), encerrando-me (cliente) | FIN | |
| 3 | Mensagem de inicialização (cliente) | SYN | `versão |
| 4 | Reconectar (servidor) | RST | |
| 5 | Definir intervalo de callback (servidor) | segundos | |
| 6 | Obter dados da interface de rede | eth0 1.2.3.4/24\neth1 fe80:::/64\n... | |
| 8 | Avaliar código Python3 arbitrário de até 666 bytes (servidor), retornando os primeiros 400 bytes da saída (cliente) | EVAL | script oneliner python3 |
| 9 | Executar comando arbitrário de até 666 bytes (servidor), retornando os primeiros 400 bytes da saída (cliente) | EXEC | comando bash |