16 de octubre de 2026 · 2 min de lectura · WebVerse · Linux · Medium
Opened
Accediendo a la sección de perfil, encontramos una funcionalidad que permite introducir una URL para establecer una foto de perfil, en lugar de subir
Reconocimiento inicial
Al acceder a la aplicación web, observamos que ya contamos con una sesión activa como usuario registrado.

Accediendo a la sección de perfil, encontramos una funcionalidad que permite introducir una URL para establecer una foto de perfil, en lugar de subir un archivo directamente.

Detección de la vulnerabilidad
Al introducir una URL válida (por ejemplo, https://example.com/me.png), la aplicación devuelve el siguiente error:

Could not fetch that image: No such file or directory @ rb_sysopen - https://example.com/me.png
El fragmento rb_sysopen es significativo: se trata de la función interna que usa el intérprete de Ruby (MRI) para abrir archivos a bajo nivel, invocada por métodos como File.open o File.read. Su aparición en el mensaje de error indica que el backend no está realizando una petición HTTP para descargar la imagen (como haría con open-uri, Net::HTTP o HTTParty), sino que está tratando el valor introducido como una ruta de archivo local en el sistema de ficheros del servidor.
Esto sugiere un código del lado del servidor similar a:
def fetch_cover_image(path)
File.open(path) { |f| f.read }
rescue Errno::ENOENT => e
render json: { error: "Could not fetch that image: #{e.message}" }
end
El parámetro controlado por el usuario (path, url, cover, según el caso) se pasa directamente a File.open sin ningún tipo de:
- Validación de esquema: no se comprueba que el valor comience por
http://ohttps://. - Sandboxing de directorio: no se concatena con una carpeta base restringida (p. ej.
uploads/images/). - Lista blanca de rutas o extensiones permitidas.
Explotación
Partiendo de esta hipótesis, sustituimos la URL por una ruta absoluta del sistema, /etc/passwd, clásico indicador de prueba de concepto para LFI por tratarse de un archivo legible por cualquier usuario en sistemas Unix/Linux:

La aplicación devuelve el contenido del archivo, confirmando que el input se pasa sin sanitizar a File.open y que no existe ningún prefijo de directorio delante de la ruta proporcionada (de lo contrario habría sido necesario usar path traversal, ../../../../etc/passwd, para escapar del directorio base).