Skip to main content
  1. Posts/

[Reproduce] CVE-2024-48510 - DotNetZip: Path Traversal

·5 mins
CVE

1. Overall #

The vulnerability lies in the DotNetZip library version 1.16.0 - which is used to handle ZIP files.

CVE-2024-48510 is a path traversal vulnerability that allows attackers to write files to directories they are not permitted to access and execute arbitrary code.

The severity level is Critical with a CVSS 3.1 score of 9.8, but the number of PoCs or blogs discussing it is relatively rare or in another words, there is none of it at the time I did the research.

2. Root Cause Analysis #

2.1 Patch diffing #

Normally, to research a CVE, people usually compare the vulnerable and patched versions, but this library has been deprecated and users have switched to using other libraries. Therefore, I can only analyze this CVE by starting from the vulnerable function based on the NIST description:

image.png

In order to analyze, I create a .NET MVC web application that allows users to upload zip files for sharing.

To use this library, you can go to the NuGet Package Manager and search for dotnetzip 1.16.0 and install it.

This is the web interface:

image.png

2.2. Flow analysis #

Coming to the debugging part, we set a breakpoint in the Extract function - where NIST described the vulnerability:

image.png

I created a zip file to observe how the library processes it:

image.png

After sending the file, the program stops here to process it:

image.png

Still haven’t seen anything important, let’s continue stepping into:

image.png

See that this function has called to InternalExtractToBaseDir:

image.png

Here, from 1232-->1257 , it checks params if they exist or null; reset status; set flags and variables; check extraction method and encryption algorithm of the zip file is supported or not.

—> It seems to be preparing for the upcoming extraction.

—> The function IsDoneWithOutputToBaseDir at the end of the image appears to be the target we are aiming for.

Analysis of the IsDoneWithOutputToBaseDir function:

image.png

Here, it doesnt call any functions but only process the path.

At line 1675, it will check if baseDir is null or not.

To line 1679, it takes our FileName (please keep in mind that this variable is an untrusted data , we can manipulate it 100%), change \ to / and then assign it to text :

image.png

According to the comment of the author on Github, doing this will avoid writing files to the root volume of Windows, and you can view the link here.

To line 1680-1682, it removes the drive letter if it exists (C:/folder1/file.txt —> /folder1/file.txt):

image.png

And delete 1 / to turn it into relative path( /folder1/file.txt —>folder1/file.txt) at part 1684-1686:

image.png

We have text after processing a little bit, please take some attention here, and we will call this Detail A .

Next, from 1689-1690, it combines baseDir with text to produce outFileName , I write it down here for us to analyze:

outFileName = (_container.ZipFile.FlattenFoldersOnExtract ? 
    Path.Combine(baseDir, text.Contains("/") ? Path.GetFileName(text) : text) : 
    Path.Combine(baseDir, text));
outFileName = outFileName.Replace('/', Path.DirectorySeparatorChar);

In detail, it checks if FlattenFoldersOnExtract true or not, if it is true then it will check text:

  • Check whether text contains / (folder path) or not. If it does -> only take the filename (Path.GetFileName(text))
  • If it does not contain / -> keep the original text
  • If FlattenFoldersOnExtract is false, then combine them directly.
  • Afterwards, it replaces Unix-style path separators (/) with OS-specific ones.

outFilename after line 1689:

outFilename sau dòng 1689

outFilename after line 1690:

outFilename sau dòng 1690

Path.Combine function is used at line 1689 to combine baseDir and Filename to get the path where the file will be extracted, as I just mentioned, and it will return the result of the CombineInternal function as follows:

image.png

Step into CombineInternal function:

image.png

We can see CombineInternal use IsPathRooted with second parameter (which is text) to check if it is root path or not, if yes then it will return the path of the second parameter instead of combining both parameters. Here you continue to pay attention to this detail, I will call it Detail B .

—> So we have gone through the processing flow of the Extract function !

—> From fileName passed in is D:/CBJS/dotnet_resources/dotnetzip1160/payload/test.txt , we have outFileName as D:\\CBJS\\dotnet_resources\\path_traversal\\dotnetzip1160\\wwwroot\\extracted\\CBJS\\dotnet_resources\\dotnetzip1160\\payload\\test.txt

From 2 above details, we proceed to connect them together to see the vulnerability:

  • At Detail A, it removes drive letter if it exists (if there is a : at index 1, it removes the first two characters). So what happens if I place two drive letters next to each other, and when removing the first character, I still have the second character left? For example, if the entry name is D:D:/..., it will only remove the first D: and leave D:/... :

    image.png

  • At this point, Detail B appears, which is the root path mentioned above. If a root path exists—> The file write address will be anywhere we want:

    image.png

—> It is the path traversal vulnerability we are looking for.

3. PoC Video #

Here is a video that records how I write a text file out of /extracted folder:

Note: because it's just a demo, I already knew the absolute path in advance. This path could be `C:\inetpub\wwwroot` for II.

To elevate the attack level to Remote Code Execution, I utilized the arbitrary file writing feature to upload a shell .cshtml and overwrite the existing endpoint. Since the Razor shell requires a controller to be rendered, I chose to overwrite the existing file /Home/Privacy for the demo.

Note: this is just a demo, in reality it would be slightly different and require us to fuzz the path or combine it with another type of vulnerability, or upload a new controller file directly to the server.

Additionally, when using the Extract function, I used the feature that allows silent overwriting of existing files: `ExtractExistingFileAction.OverwriteSilently`

4. Appendix #

  1. You can find all of the source code of the web app here: https://github.com/havertz2110/CVE-2024-48510-PoC/tree/main/source%20code

  2. Here are the scripts I used to create the zip files for the demo: https://github.com/havertz2110/CVE-2024-48510-PoC/blob/main/payload/PoC_zip_file.py

  3. I have slightly modified it and the source is available here. Here is the modified version: https://github.com/havertz2110/CVE-2024-48510-PoC/blob/main/payload/RCE.py

  4. Reference links: