GHOST_SERVERS: Implementing HTTP via SystemD Sockets & Bash
GHOST_SERVERS: Implementing HTTP via SystemD Sockets & Bash
[ 0x00 ] A GORDURA DOS SERVIDORES MODERNOS
A gente se acostumou mal. Pra servir um simples arquivo JSON ou uma página estática, hoje a galera sobe um container de Node.js, um Apache ou no mínimo um Nginx. Isso puxa dezenas de megabytes de RAM, abre margem pra N vulnerabilidades nas dependências, e deixa um rastro gigantesco.
Mas o que acontece se você precisar levantar um serviço furtivo, ou simplesmente provar que entende de Linux de verdade? E se eu te disser que você pode criar um servidor HTTP funcional usando apenas Bash e o SystemD?
Isso é o que eu chamo de Ghost Server.
[ 0x01 ] SYSTEMD SOCKET ACTIVATION
A mágica começa com uma feature subestimada do Linux: Socket Activation.
Ao invés de deixar um programa rodando 24/7 ouvindo uma porta (gastando memória), você manda o SystemD ouvir a porta. Quando alguém conecta nessa porta, o SystemD acorda o seu script, repassa a conexão via stdin/stdout (entrada e saída padrão), e quando termina, ele mata o processo.
Zero consumo de RAM enquanto está ocioso. Lindo, não?
Crie o arquivo /etc/systemd/system/ghost-http.socket:
[Unit]
Description=Ghost HTTP Socket
[Socket]
ListenStream=8080
Accept=yes
[Install]
WantedBy=sockets.target
Note o Accept=yes. Isso diz pro SystemD spawnar uma nova instância do nosso serviço para cada conexão que chegar.
[ 0x02 ] O SERVIÇO FANTASMA
Agora, criamos o arquivo que diz o que o SystemD deve executar.
/etc/systemd/system/ghost-http@.service:
[Unit]
Description=Ghost HTTP Service
[Service]
StandardInput=socket
ExecStart=/usr/local/bin/ghost-server.sh
[ 0x03 ] O BASH COMO BACKEND DA WEB
E aqui entra o nosso código fonte do servidor. Sem bibliotecas, sem frescura. Ele só precisa cuspir o cabeçalho HTTP válido de volta pelo stdout.
/usr/local/bin/ghost-server.sh:
#!/bin/bash
# Lemos a primeira linha da requisição (ex: GET /index.html HTTP/1.1)
read request
# Removemos quebras de linha sujas
request=$(echo $request | tr -d '\r\n')
# Ignoramos o resto dos headers porque somos minimalistas (e um pouco preguiçosos)
while read line; do
line=$(echo $line | tr -d '\r\n')
[ -z "$line" ] && break
done
# Resposta HTTP crua!
echo -e "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: close\r\n\r\n"
echo -e "<h1>Bem vindo ao Ghost Server</h1><p>Zero NPM. Zero Python. Apenas Bash.</p>"
[ 0x04 ] START AND FORGET
Dá permissão de execução, habilita e pronto:
chmod +x /usr/local/bin/ghost-server.sh
systemctl enable --now ghost-http.socket
Pode dar curl no localhost:8080. Funciona que é uma beleza.
Por que isso é útil? Pra red team, é um C2 (Command and Control) ou servidor de payload absurdamente furtivo. Pra infra, é um jeito incrivelmente seguro e leve de servir métricas internas ou painéis de status que não consomem recursos quando ninguém está olhando.
[ 0x05 ] ROTEOAMENTO BÁSICO NO BASH
Servir uma página estática é legal, mas e se quisermos servir arquivos dinâmicos baseados na URL? O $request que capturamos tem tudo o que precisamos.
Podemos extrair a rota (ex: /api/data) com awk ou bash puro:
route=$(echo "$request" | awk '{print $2}')
if [ "$route" == "/api/status" ]; then
echo -e "HTTP/1.1 200 OK
Content-Type: application/json
"
echo "{ "status": "ghosting", "load": $(cat /proc/loadavg | awk '{print $1}') }"
elif [[ "$route" == *.json ]]; then
file="."$route
if [ -f "$file" ]; then
echo -e "HTTP/1.1 200 OK
Content-Type: application/json
"
cat "$file"
else
echo -e "HTTP/1.1 404 Not Found
"
fi
else
echo -e "HTTP/1.1 403 Forbidden
"
fi
Pronto, você acabou de reinventar o Express.js usando shell script. E incrivelmente, isso aguenta porrada.
[ 0x06 ] LIMITAÇÕES E PERFOMANCE
Isso vai aguentar o tráfego da Amazon na Black Friday? Claro que não.
O SystemD spwana um novo processo bash para cada conexão. Fazer 1000 requisições concorrentes significa 1000 processos bash nascendo e morrendo. A latência média fica na casa dos 5ms, mas a CPU sofre com o custo de context-switching e criação de processos se houver sobrecarga.
Entretanto, para APIs internas, callbacks (webhooks) invisíveis para C2s e administração de sistemas remotos (onde a carga é baixa), é a solução mais silenciosa e elegante possível. O administrador que abrir o top ou o htop dificilmente vai suspeitar de instâncias curtas do /bin/bash rodando pelo sistema (pois o sistema inteiro já faz isso naturalmente).
Às vezes, a melhor ferramenta não é instalar mais pacotes, mas sim usar o que o sistema operacional já te dá de bandeja.