-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathZipSlip.cs
More file actions
139 lines (118 loc) · 5.64 KB
/
ZipSlip.cs
File metadata and controls
139 lines (118 loc) · 5.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
using System;
using System.IO;
using System.IO.Compression;
namespace ZipSlip
{
class Program
{
public static void UnzipFileByFile(ZipArchive archive,
string destDirectory)
{
foreach (var entry in archive.Entries)
{
string fullPath = Path.GetFullPath(entry.FullName);
string fileName = Path.GetFileName(entry.FullName);
string filename = entry.Name;
string file = entry.FullName;
if (!string.IsNullOrEmpty(file))
{
// BAD
string destFileName = Path.Combine(destDirectory, file);
entry.ExtractToFile(destFileName, true);
// GOOD
string sanitizedFileName = Path.Combine(destDirectory, fileName);
entry.ExtractToFile(sanitizedFileName, true);
// BAD
string destFilePath = Path.Combine(destDirectory, fullPath);
entry.ExtractToFile(destFilePath, true);
// BAD: destFilePath isn't fully resolved, so may still contain ..
if (destFilePath.StartsWith(destDirectory))
entry.ExtractToFile(destFilePath, true);
// BAD
destFilePath = Path.GetFullPath(Path.Combine(destDirectory, fullPath));
entry.ExtractToFile(destFilePath, true);
// GOOD: a check for StartsWith against a fully resolved path
if (destFilePath.StartsWith(destDirectory))
entry.ExtractToFile(destFilePath, true);
}
}
}
private static int UnzipToStream(Stream zipStream, string installDir)
{
int returnCode = 0;
try
{
// normalize InstallDir for use in check below
var InstallDir = Path.GetFullPath(installDir + Path.DirectorySeparatorChar);
using (ZipArchive archive = new ZipArchive(zipStream, ZipArchiveMode.Read))
{
foreach (ZipArchiveEntry entry in archive.Entries)
{
// figure out where we are putting the file
String destFilePath = Path.Combine(InstallDir, entry.FullName);
Directory.CreateDirectory(Path.GetDirectoryName(destFilePath));
using (Stream archiveFileStream = entry.Open())
{
// BAD: writing to file stream
using (Stream tfsFileStream = new FileStream(destFilePath, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.None))
{
Console.WriteLine(@"Writing ""{0}""", destFilePath);
archiveFileStream.CopyTo(tfsFileStream);
}
// BAD: can do it this way too
using (Stream tfsFileStream = File.Create(destFilePath))
{
Console.WriteLine(@"Writing ""{0}""", destFilePath);
archiveFileStream.CopyTo(tfsFileStream);
}
// BAD: creating stream using fileInfo
var fileInfo = new FileInfo(destFilePath);
using (FileStream fs = fileInfo.OpenWrite())
{
Console.WriteLine(@"Writing ""{0}""", destFilePath);
archiveFileStream.CopyTo(fs);
}
// BAD: creating stream using fileInfo
var fileInfo1 = new FileInfo(destFilePath);
using (FileStream fs = fileInfo1.Open(FileMode.Create))
{
Console.WriteLine(@"Writing ""{0}""", destFilePath);
archiveFileStream.CopyTo(fs);
}
// GOOD: Use substring to pick out single component
string fileName = destFilePath.Substring(destFilePath.LastIndexOf("\\"));
var fileInfo2 = new FileInfo(fileName);
using (FileStream fs = fileInfo2.Open(FileMode.Create))
{
Console.WriteLine(@"Writing ""{0}""", destFilePath);
archiveFileStream.CopyTo(fs);
}
}
}
}
}
catch (Exception ex)
{
Console.WriteLine("Error patching files: {0}", ex.ToString());
returnCode = -1;
}
return returnCode;
}
static void Main(string[] args)
{
string zipFileName;
zipFileName = args[0];
string targetPath = args.Length == 2 ? args[1] : ".";
using (FileStream file = new FileStream(zipFileName, FileMode.Open))
{
using (ZipArchive archive = new ZipArchive(file, ZipArchiveMode.Read))
{
UnzipFileByFile(archive, targetPath);
// GOOD: the path is checked in this extension method
archive.ExtractToDirectory(targetPath);
UnzipToStream(file, targetPath);
}
}
}
}
}