GhostAcademy logo GhostAcademy
p
y
t
h
o
n
3
p
t
y
s
t
t
y
r
a
w
-
e
c
f
g
C
Z
T
T
Y
b
a
s
e
x
p
o
r
t
T
E
R
M
TTY · pty · reverse shell · post-explotación · HTB / CTF
Tratamiento
de la TTY
// Dumb shell → Full Interactive TTY en 3 pasos

Transforma una shell básica no interactiva (reverse shell, web shell, post-explotación) en una TTY completamente funcional: con historial, autocompletado, job control (Ctrl+Z), sudo interactivo y visualización correcta de programas como vim o nano. Técnica estándar en CTF, HTB y auditorías de penetración.

python3 -c 'import pty; pty.spawn("/bin/bash")' stty raw -echo && export TERM=xterm Ctrl+Z → stty raw -echo → fg stty rows <N> columns <N>
💀
El Problema: Dumb Shell / Shell No Interactiva
Cuando accedes a un sistema tras explotar una vulnerabilidad o lanzar una reverse shell, obtienes una shell deficiente que carece de TTY. Sin TTY, la interacción con el sistema es muy limitada.

Una shell no interactiva ocurre porque la conexión remota (netcat, reverse shell, web shell) no establece un controlador de terminal (TTY) que maneje las secuencias de escape del teclado. El resultado es una shell "ciega":

⬆️
Sin historial
Las flechas ↑ ↓ no navegan por comandos anteriores — aparecen como caracteres extraños.
⇥
Sin autocompletado
La tecla Tab no completa nombres de comandos ni rutas de archivos.
⏸️
Sin job control
Ctrl+Z no suspende procesos — en su lugar puede matar toda la conexión.
💥
Programas rotos
vim, nano, less, sudo fallan o se ven corrompidos al no conocer las dimensiones del terminal.
⚡
Antes vs. Después del Tratamiento
El objetivo es claro: pasar de una shell inútil a una Full Interactive TTY equivalente a estar en la consola física de la máquina.
✗ Dumb Shell (sin tratamiento)
  • Flechas ↑↓ muestran ^[[A
  • Tab no autocompleta
  • Ctrl+Z rompe la conexión
  • sudo no pide contraseña correctamente
  • vim / nano corrompidos
  • No hay control de señales
  • stty: standard input errores
✓ Full Interactive TTY (con tratamiento)
  • Historial completo con flechas
  • Autocompletado con Tab
  • Ctrl+Z suspende procesos
  • sudo oculta contraseñas correctamente
  • vim, nano, less funcionales
  • Control completo de señales
  • Dimensiones de terminal correctas
🐍
Paso 1 — Crear la Pseudo-Terminal con Python
Usa el módulo pty de Python para crear y vincular una pseudo-terminal (/dev/pty). Ejecutado en la máquina remota.
shell remota — Python 3 (moderno, recomendado)
python3 -c 'import pty; pty.spawn("/bin/bash")'
shell remota — Python 2 (sistemas legacy)
python -c "import pty; pty.spawn('/bin/bash')"
📖 Desglose del comando
python3 -c Ejecuta una línea de código Python directamente sin necesidad de un archivo.
import pty Importa el módulo pty de la librería estándar de Python — gestiona pseudo-terminales.
pty.spawn() Ejecuta /bin/bash dentro de un nuevo contexto de pseudo-terminal (Pty), creando el canal bidireccional necesario.
⚠️ Estado tras el Paso 1: Ahora tienes una shell con pseudo-terminal, pero todavía está "sorda": no maneja bien las teclas especiales y no conoce las dimensiones de tu terminal local. Necesitas continuar con el Paso 2.
⌨️
Paso 2 — Ctrl+Z, stty raw -echo y fg
La secuencia crítica: suspende la shell de Python, configura la terminal en modo crudo desde la shell madre, y reanuda con las nuevas configuraciones heredadas.
A
Ctrl+Z — Suspender el proceso Python máquina remota
Pulsa Ctrl+Z. El proceso python3 pty.spawn... queda suspendido en segundo plano y recuperas el control de la shell madre.
B
export TERM=xterm máquina remota
Declara el tipo de terminal como xterm — un estándar ampliamente soportado que entiende la mayoría de secuencias de escape.
C
stty raw -echo crítico
Configura la terminal en modo crudo:
 • raw: cada pulsación se envía inmediatamente sin buffering
 • -echo: desactiva la visualización de lo que escribes (imprescindible para que sudo oculte contraseñas)
D
fg — Reanudar en primer plano máquina remota
Trae la shell de Python suspendida de vuelta al primer plano. Ahora hereda las nuevas configuraciones de stty — la shell pasa a ser totalmente interactiva.
secuencia completa — paso 2
# 1. En la shell remota: pulsar Ctrl+Z para suspender python3
^Z
# [1]+  Stopped    python3 -c 'import pty; pty.spawn("/bin/bash")'

# 2. Configurar la terminal (en la shell madre)
export TERM=xterm
stty raw -echo

# 3. Reanudar la shell de Python con las nuevas configuraciones
fg
✅ Tras el fg: La shell ahora soporta historial, autocompletado con Tab, Ctrl+Z funcional y sudo oculta correctamente las contraseñas.
📐
Paso 3 — Ajustar Dimensiones del Terminal
Sincroniza el tamaño de tu terminal local con la shell remota. Vital para programas como vim, nano, less o cualquier TUI.
terminal LOCAL — obtener dimensiones
# Ejecutar en tu máquina LOCAL antes de entrar a la remota
stty -a | head -n 1
# Ejemplo de salida: speed 38400 baud; rows 35; columns 120; ...
shell REMOTA — aplicar dimensiones
# Sustituye los valores por los de tu terminal local
stty rows 35 columns 120

# Alternativa: obtener las dimensiones directamente (si tput está disponible)
stty rows $(tput lines) columns $(tput cols)
ℹ️ ¿Por qué importa? Sin las dimensiones correctas, vim renderiza líneas truncadas, less no pagina bien y cualquier programa que dibuje en pantalla se verá corrupto. Este paso convierte la TTY en completamente funcional.
🔄
El Rol de Ctrl+Z — Por Qué es Necesario
Ctrl+Z es el mecanismo que permite configurar la terminal subyacente antes de reanudar la shell con las mejoras aplicadas.
1
python3 pty.spawn → shell con pty
La pseudo-terminal existe, pero está en modo no interactivo. Los atajos de teclado y el job control no funcionan aún.
2
Ctrl+Z → suspende python3
El proceso Python queda en segundo plano. Vuelves a la shell madre donde puedes ejecutar configuraciones de bajo nivel sobre la terminal.
3
stty raw -echo → configura la terminal
Desde la shell madre configuras el controlador de terminal: modo crudo y sin eco. Estos cambios afectan a la sesión completa.
4
fg → reanuda con configuración heredada
Python/Bash suspendido vuelve al primer plano y hereda automáticamente la nueva configuración de stty. La shell ahora es completamente interactiva.
Resumen: Ctrl+Z se usa para pausar la shell deficiente, tener la oportunidad de configurar la terminal subyacente con stty raw -echo, y luego reanudarla con fg heredando todas las mejoras.
📖
Explicación de Comandos Clave
Qué hace cada pieza del proceso de tratamiento de TTY.
📋 Desglose completo
pty.spawn("/bin/bash") Crea una pseudo-terminal (/dev/pty) y ejecuta bash dentro de ella, estableciendo comunicación bidireccional completa.
Ctrl+Z Envía la señal SIGTSTP al proceso en primer plano, suspendiéndolo y devolviéndote el control de la shell madre.
export TERM=xterm Declara el tipo de terminal. xterm es el estándar universal — informa a los programas qué secuencias de escape puede interpretar.
stty raw Modo crudo: cada pulsación de tecla se transmite inmediatamente sin esperar un Enter. Habilita el job control real.
stty -echo Desactiva el eco de los caracteres tecleados. Imprescindible para que sudo oculte la contraseña al escribirla.
fg Trae el proceso suspendido de vuelta al primer plano. Hereda la configuración de stty aplicada mientras estaba suspendido.
stty -a | head -n 1 Muestra la configuración actual de la terminal, incluyendo rows y columns. Ejecutar en la máquina LOCAL.
stty rows N columns N Sincroniza las dimensiones de la terminal remota con las de tu terminal local para que vim/nano/less se rendericen correctamente.
📋
Cheatsheet — Tratamiento TTY Completo
La secuencia completa de comandos para ir de dumb shell a Full Interactive TTY.
🖥️ Secuencia completa de tratamiento de TTY
━━━ PASO 1: Crear pseudo-terminal (ejecutar en la shell remota) ━━━
python3 -c 'import pty; pty.spawn("/bin/bash")'

━━━ PASO 2: Suspender + configurar + reanudar ━━━
^Z                          # Ctrl+Z — suspende python3
export TERM=xterm          # declara tipo de terminal
stty raw -echo             # modo crudo + ocultar eco
fg                         # reanuda con nueva config heredada

━━━ PASO 3: Ajustar dimensiones ━━━
# En tu terminal LOCAL:
stty -a | head -n 1        # anota rows y columns

# En la shell REMOTA (sustituye los valores):
stty rows 35 columns 120

━━━ ALTERNATIVA si python3 no está disponible ━━━
script /dev/null -c bash   # usando el comando script
python -c "import pty; pty.spawn('/bin/bash')"  # python2
perl -e 'exec "/bin/bash"' # con Perl
ruby -e 'exec "/bin/bash"'  # con Ruby
💡 Truco rápido: Si estás en una situación de CTF y solo necesitas una solución rápida, el comando script /dev/null -c bash también funciona para obtener una TTY sin necesidad de Python — y luego aplicas los mismos pasos 2 y 3.