Symlink abuse in a sudo script
Un patrón frecuente de escalada en Linux: un usuario sin privilegios puede ejecutar por sudo (a menudo con NOPASSWD) un script propio del sistema que manipula ficheros como root. Si ese script sigue enlaces simbólicos sin resolver la ruta real, el usuario controla qué fichero acaba leyendo o tocando root.
El fallo típico. El script intenta protegerse comprobando el destino de un enlace y rechazando rutas sensibles:
LINK_TARGET=$(readlink "$LINK") # solo el PRIMER salto
if echo "$LINK_TARGET" | grep -Eq '(etc|root)'; then
unlink "$LINK" # lo borra
else
cat "$QUAR_DIR/$LINK_NAME" # lo lee como root
fiEl error está en usar readlink (un solo salto) en vez de readlink -f (resuelve la cadena completa). Solo se inspecciona el destino directo.
El bypass: doble enlace. Se encadenan dos symlinks. El primero apunta a un destino "inocente"; el segundo, al fichero sensible:
ln -s /root/root.txt pwn.txt # eslabón oculto (destino real)
ln -s pwn.txt pwn.png # lo que ve readlink: 'pwn.txt', pasa el filtroreadlink pwn.png devuelve pwn.txt (no contiene etc ni root, así que el filtro lo deja pasar). Pero cuando el script hace cat pwn.png, el kernel resuelve la cadena entera hasta /root/root.txt y root lee ese contenido por nosotros.
Variantes y matices. A veces el comportamiento del script depende de una variable de entorno (en LinkVortex, CHECK_CONTENT): si la regla de sudoers conserva esa variable con env_keep, basta exportarla (sudo CHECK_CONTENT=true ...) para activar la rama que imprime el contenido. El objetivo más rentable no es solo root.txt: leer /root/.ssh/id_rsa da una clave privada con la que entrar por SSH como root y obtener shell completa, no solo una flag.
Cómo detectarlo. sudo registra la invocación del script en /var/log/auth.log con su usuario y argumentos; la firma del abuso es el proceso privilegiado abriendo, a través de un enlace, un fichero fuera de su directorio de trabajo esperado (/root/.ssh/id_rsa, /etc/shadow): auditd sobre open/openat con ppid del script revela la ruta real resuelta por el kernel, distinta de la que el script creía validar. La creación de una cadena de symlinks en el directorio de quarantine/trabajo (ln -s encadenados) justo antes del sudo es el indicio previo. Un sudo <script> con una variable de entorno inesperada (CHECK_CONTENT=true) conservada por env_keep también delata la manipulación.
Defensa. En cualquier script privilegiado, resolver siempre la ruta canónica (realpath/readlink -f) antes de decidir, no seguir enlaces ajenos, y minimizar env_keep en /etc/sudoers. Relacionado con el abuso de SUID y, en general, con confiar en rutas que el usuario controla.
Máquinas donde se aplica
- LinkVortexHackTheBox
- MarketingProving Grounds Practice