diff --git a/src/SharpCompress/Archives/IArchiveEntryExtensions.cs b/src/SharpCompress/Archives/IArchiveEntryExtensions.cs index f4f8cb6b..d66669b9 100644 --- a/src/SharpCompress/Archives/IArchiveEntryExtensions.cs +++ b/src/SharpCompress/Archives/IArchiveEntryExtensions.cs @@ -48,6 +48,7 @@ namespace SharpCompress.Archives { string destinationFileName; string file = Path.GetFileName(entry.Key); + string fullDestinationDirectoryPath = Path.GetFullPath(destinationDirectory); options = options ?? new ExtractionOptions() { @@ -58,19 +59,35 @@ namespace SharpCompress.Archives if (options.ExtractFullPath) { string folder = Path.GetDirectoryName(entry.Key); - string destdir = Path.Combine(destinationDirectory, folder); + string destdir = Path.GetFullPath( + Path.Combine(fullDestinationDirectoryPath, folder) + ); + if (!Directory.Exists(destdir)) { + if (!destdir.StartsWith(fullDestinationDirectoryPath)) + { + throw new ExtractionException("Entry is trying to create a directory outside of the destination directory."); + } + Directory.CreateDirectory(destdir); } destinationFileName = Path.Combine(destdir, file); } else { - destinationFileName = Path.Combine(destinationDirectory, file); + destinationFileName = Path.Combine(fullDestinationDirectoryPath, file); } + if (!entry.IsDirectory) { + destinationFileName = Path.GetFullPath(destinationFileName); + + if (!destinationFileName.StartsWith(fullDestinationDirectoryPath)) + { + throw new ExtractionException("Entry is trying to write a file outside of the destination directory."); + } + entry.WriteToFile(destinationFileName, options); } } diff --git a/tests/SharpCompress.Test/Zip/ZipArchiveTests.cs b/tests/SharpCompress.Test/Zip/ZipArchiveTests.cs index a613abad..c776dcf9 100644 --- a/tests/SharpCompress.Test/Zip/ZipArchiveTests.cs +++ b/tests/SharpCompress.Test/Zip/ZipArchiveTests.cs @@ -433,7 +433,34 @@ namespace SharpCompress.Test.Zip } } } + } + [Fact] + public void Zip_Evil_Throws_Exception() + { + Exception expectedExcetpion = null; + string zipFile = Path.Combine(TEST_ARCHIVES_PATH, "Zip.Evil.zip"); + + try + { + using (var archive = ZipArchive.Open(zipFile)) + { + foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory)) + { + entry.WriteToDirectory(SCRATCH_FILES_PATH, new ExtractionOptions() + { + ExtractFullPath = true, + Overwrite = true + }); + } + } + } + catch (Exception ex) + { + expectedExcetpion = ex; + } + + Assert.NotEqual(expectedExcetpion, null); } class NonSeekableMemoryStream : MemoryStream diff --git a/tests/TestArchives/Archives/Zip.Evil.zip b/tests/TestArchives/Archives/Zip.Evil.zip new file mode 100644 index 00000000..3474c88b Binary files /dev/null and b/tests/TestArchives/Archives/Zip.Evil.zip differ