
Analyse détaillée et exploit PoC pour CVE-2025-2825, un contournement d'authentification dans CrushFTP. Inclut des templates nuclei, un scanner multi-thread, et un script de création d'utilisateur pour les tests de pénétration.
Ce document présente l'étude de la vulnérabilité CVE-2025-2825 affectant la partie serveur de CrushFTP, une solution commerciale de transfert et de stockage de fichiers (FTP, SFTP, HTTP/S, interfaces de type S3, etc.).
Le défaut est classé comme contournement d'authentification, permettant à un attaquant distant non authentifié d'obtenir les droits d'administrateur. Une exploitation réussie donne un accès avec les privilèges crushadmin, la visualisation et la modification de fichiers, la gestion des comptes utilisateurs et l'exécution d'opérations administratives via l'interface web et l'API de CrushFTP.
Versions affectées signalées (selon les avis publics et les rapports de chercheurs) :
⚠️ Remarque : dans certaines publications, on trouve des doublons et des chevauchements d'identifiants CVE (par exemple CVE-2025-31161).
Analyser pas à pas la vulnérabilité et démontrer le cycle complet de l'étude, comprenant :
Selon les rapports publics, la vulnérabilité présente un risque critique :
Les instances présentant les caractéristiques suivantes sont critiques :
CrushFTP (toute édition avec interface web).CrushFTP implémente le support d'une API de type S3. Pour l'authentification, l'en-tête Authorization est utilisé :
Authorization: AWS4-HMAC-SHA256 Credential=<AccessKey>/<Date>/<Region>/s3/aws4_request, SignedHeaders=<Headers>, Signature=<Signature>
Le serveur extrait l'AccessKey de Credential et doit vérifier la signature. Cependant, une erreur a été commise dans le code lors de la gestion du flag lookup_user_pass .
// ServerSessionHTTP.java, méthode loginCheckHeaderAuth()
if (this.headerLookup.containsKey("AUTHORIZATION") &&
this.headerLookup.getProperty("AUTHORIZATION").trim().startsWith("AWS4-HMAC")) {
boolean lookup_user_pass = true; // ← erreur critique
if (s3_username3.indexOf("~") >= 0) {
user_pass = user_name.substring(user_name.indexOf("~") + 1);
user_name = user_name.substring(0, user_name.indexOf("~"));
lookup_user_pass = false;
}
if (this.thisSession.login_user_pass(
lookup_user_pass,
false,
user_name,
lookup_user_pass ? "" : user_pass)) {
// Authentification réussie
}
}
Le flag lookup_user_pass est directement transmis comme anyPass :
if (anyPass && user.getProperty("username").equalsIgnoreCase(the_user)) {
return user; // authentification sans vérification du mot de passe
}
Ainsi :
Si le nom d'utilisateur est spécifié sans le caractère ~, le flag reste true.
La vérification du mot de passe n'est pas effectuée.
L'attaquant peut s'authentifier en indiquant uniquement un nom d'utilisateur existant (par exemple crushadmin).
Avec un cookie CrushAuth formellement valide et le paramètre c2f, cela permet de contourner l'authentification et d'obtenir un accès administratif.
Dans la version 11.3.1 et ultérieures, les développeurs :
Ont ajouté le paramètre s3_auth_lookup_password_supported (par défaut false), bloquant le scénario vulnérable.
Ont introduit des vérifications précoces du nom d'utilisateur avec ~.
Ont séparé la logique des flags, supprimant la substitution lookup_user_pass → anyPass.
Recommandation : mettre à jour immédiatement CrushFTP vers 11.3.1+ ou appliquer le workaround avec s3_auth_lookup_password_supported désactivé.
L'exploitation de CVE-2025-2825 est assez simple et ne nécessite pas de préparation complexe. L'attaquant doit simplement envoyer une requête HTTP spécialement conçue, contenant deux éléments clés :
Authorization au format AWS S3 contenant le nom correct d'un utilisateur existant (champ Credential avec AccessKey/nom d'utilisateur).CrushAuth au format attendu et le paramètre c2f dans l'URL/le corps de la requête, dont les valeurs correspondent logiquement (le format du cookie doit correspondre à la structure attendue par le serveur).Si le serveur est vulnérable (version dans la plage 10.0.0—10.8.3 ou 11.0.0—11.3.0 et correctif non appliqué), cette combinaison force le gestionnaire d'authentification à emprunter le chemin vulnérable, où le flag de recherche du mot de passe (lookup_user_pass) est interprété comme « tout mot de passe est accepté », et l'utilisateur est authentifié sur la seule base du nom sans vérification du mot de passe.
Remarque importante :
L'exploitation de cette vulnérabilité nécessite généralement l'envoi de deux requêtes successives. La première, dite de « préchauffage » (warm-up), déclenche le processus d'authentification vulnérable sur le serveur. Un signe caractéristique que le serveur est entré dans l'état souhaité est l'obtention d'une erreur
502 Bad Gatewayou simplement un délai d'attente (timeout). Immédiatement après, la seconde requête, principale, exécute l'action utile (par exemple, création d'un utilisateur) pendant que le serveur est encore dans l'état vulnérable à l'attaque.
GET /WebInterface/function/?command=getUserList&serverGroup=MainUsers&c2f=1111 HTTP/1.1
Host: target-server:8080
Cookie: CrushAuth=1743113839553_vD96EZ70ONL6xAd1DAJhXMZYMn1111
Authorization: AWS4-HMAC-SHA256 Credential=crushadmin/
Pour le test, j'ai utilisé le laboratoire récent sur HTB — Soulmate, qui nécessite justement l'exploitation de CrushFTP.

Grâce à cette vulnérabilité, il est possible d'ajouter un nouvel utilisateur avec les droits d'administrateur à l'aide de la commande setUserItem. Pour ce faire, exécutez new_user.py.
python3 new_user.py --target_host http://ftp.soulmate.htb/ --port 80 --target_user crushadmin --new_user literide --password literide
Analyse de l'en-tête Authorization : Lorsque le serveur voit un en-tête d'autorisation au format S3 (AWS4-HMAC...), il extrait du champ Credential l'identifiant client (AccessKey / nom d'utilisateur). À cette étape, le serveur obtient une chaîne qu'il considère comme le nom d'utilisateur — cette valeur d'identification est ensuite utilisée dans la logique d'authentification.
Le flag lookup_user_pass et son rôle :
Dans le code, il y a un flag booléen lookup_user_pass qui doit indiquer d'où tirer le mot de passe lors de la vérification :
Dans un scénario normal, le flag aide à décider : utiliser le mot de passe transmis dans la requête ou récupérer le mot de passe depuis le stockage utilisateur ;
Cependant, en raison d'une erreur d'implémentation, ce même flag est transmis plus loin à la fonction de vérification et y est interprété différemment — comme un signal permettant d'ignorer la vérification du mot de passe (en substance : « anyPass »).
Transmission du flag dans la chaîne d'appels :
Chemin approximatif : ServerSessionHTTP.loginCheckHeaderAuth() → Session.login_user_pass(...) → UserTools.ut.verify_user(...). En entrée, le flag détermine le comportement, et dans verify_user, il conduit à un retour précoce de l'objet utilisateur trouvé sans comparaison du mot de passe, si le nom correspond. Cela donne le contournement de la vérification d'authentification — le serveur « reconnaît » l'utilisateur par son nom et le considère comme authentifié.
Éléments associés (cookie / c2f) :
Dans les analyses publiques, il a été indiqué que le gestionnaire attend un format correct de cookie/paramètres pour faire correspondre la requête à une session/contexte. Cependant, le défaut clé réside dans l'erreur logique de traitement de lookup_user_pass ; les autres éléments aident simplement la requête à passer les branches standards du traitement.
Cause principale
Credential a conduit à ce que la présence d'un nom d'utilisateur correct soit suffisante pour obtenir les identifiants de l'utilisateur sans vérification du mot de passe.Modèle passif :
Étant donné qu'il est impossible de déterminer la version exacte de Crushftp dans la plupart des services web, ce modèle vérifie simplement si le service utilise Crushftp.
Il est préférable de l'utiliser en combinaison avec le modèle actif
Modèle actif :
Le modèle actif vérifie si la commande getUserList est possible.

Script multithread
Le script fonctionne à peu près comme le modèle actif, mais beaucoup plus rapidement et prend en charge la vérification de plusieurs hôtes simultanément.
python3 scan.py -t http://ftp.soulmate.htb/ -p 80 -u crushadmin

Pour réduire les risques liés à CVE-2025-31161, il est recommandé de prendre les mesures suivantes :
Mise à jour immédiate :
Application du Workaround (si la mise à jour est impossible) :
s3_auth_lookup_password_supported sur false. Cela désactivera la logique d'authentification vulnérable sans mettre à jour l'ensemble du produit.Mesures compensatoires :
AWS4-HMAC-SHA256 dans l'en-tête Authorization, surtout si vous n'utilisez pas l'intégration S3.Authorization anormaux vers les points de terminaison non destinés à l'API S3.