Skip to content

Commit

Permalink
Merge pull request #121 from shana/bugs/relative-paths
Browse files Browse the repository at this point in the history
Sanitize zip entry paths before extracting
  • Loading branch information
shana committed May 7, 2018
2 parents 1b8aded + ff2922d commit 55d2c13
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 0 deletions.
24 changes: 24 additions & 0 deletions src/Zip Tests/Compatibility.cs
Expand Up @@ -2581,6 +2581,30 @@ public void Extract_AndroidApp()
}


[TestMethod]
public void Extract_ZipWithRelativePathsOutside()
{
_Extract_ZipFile("relative-paths-outside.zip");
Assert.IsTrue(File.Exists(@"extract\good.txt"));
Assert.IsTrue(File.Exists(@"extract\Temp\evil.txt"));
}

[TestMethod]
public void Extract_ZipWithRelativePathsInSubdir()
{
_Extract_ZipFile("relative-paths-in-subdir.zip");
Assert.IsTrue(File.Exists(@"extract\good.txt"));
Assert.IsTrue(File.Exists(@"extract\Temp\evil.txt"));
}

[TestMethod]
public void Extract_ZipWithRelativePathsInSubdirOutside()
{
_Extract_ZipFile("relative-paths-in-subdir-outside.zip");
Assert.IsTrue(File.Exists(@"extract\good.txt"));
Assert.IsTrue(File.Exists(@"extract\Temp\evil.txt"));
}

private void _Extract_ZipFile(string fileName)
{
TestContext.WriteLine("Current Dir: {0}", CurrentDir);
Expand Down
9 changes: 9 additions & 0 deletions src/Zip Tests/Zip Tests.csproj
Expand Up @@ -159,6 +159,15 @@
<Content Include="zips\wizzquiz.zip">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="zips\relative-paths-in-subdir.zip">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="zips\relative-paths-outside.zip">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="zips\relative-paths-in-subdir-outside.zip">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<Content Include="zips\winzip-sfx.exe">
Expand Down
Binary file not shown.
Binary file added src/Zip Tests/zips/relative-paths-in-subdir.zip
Binary file not shown.
Binary file added src/Zip Tests/zips/relative-paths-outside.zip
Binary file not shown.
40 changes: 40 additions & 0 deletions src/Zip.Shared/Shared.cs
Expand Up @@ -157,6 +157,46 @@ public static string NormalizePathForUseInZipFile(string pathName)
return SimplifyFwdSlashPath(pathName);
}

/// <summary>
/// Sanitize paths in zip files. This means making sure that relative paths in a zip file don't go outside
/// the top directory. Entries like something/../../../../Temp/evil.txt get sanitized to Temp/evil.txt
/// when extracting
/// </summary>
/// <param name="path">A path with forward slashes as directory separator</param>
/// <returns>sanitized path</returns>
public static string SanitizePath(string path)
{
System.Collections.Generic.List<string> dirs = new System.Collections.Generic.List<string>();
int level = 0;
foreach (string dir in path.Split('/'))
{
if (dir == "..")
{
if (level == 0)
continue;
level--;
}
else
{
if (dirs.Count - 1 < level)
dirs.Add(dir);
else
dirs[level] = dir;
level++;
}
}

path = "";
for (int i = 0; i < level; i++)
{
if (i > 0)
path += "/";
path += dirs[i];
}

return path;
}


//static System.Text.Encoding ibm437 = System.Text.Encoding.GetEncoding("IBM437");
static System.Text.Encoding utf8 = System.Text.Encoding.GetEncoding("UTF-8");
Expand Down
2 changes: 2 additions & 0 deletions src/Zip.Shared/ZipEntry.Extract.cs
Expand Up @@ -1422,6 +1422,8 @@ bool IsDoneWithOutputToBaseDir(string baseDir, out string outFileName)
if (f.StartsWith("/"))
f = f.Substring(1);

f = SharedUtilities.SanitizePath(f);

// String.Contains is not available on .NET CF 2.0
outFileName = _container.ZipFile.FlattenFoldersOnExtract
? Path.Combine(baseDir, f.IndexOf('/') != -1 ? Path.GetFileName(f) : f)
Expand Down

0 comments on commit 55d2c13

Please sign in to comment.