Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Zip path traversal vulnerability #2630

Merged
merged 2 commits into from
Jan 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/assets/locales/android_translatable_strings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ mult.install.bad=The selected ZIP file is not valid. Please choose a valid zip f
mult.install.progress.baddest=Couldn't write multimedia to the local filesystem at: ${0}
mult.install.progress.badentry=There was a bad entry in the zip file: ${0}
mult.install.progress.errormoving=There was a problem copying the multimedia from the zip file, please try again.
mult.install.progress.invalid.ccz=The selected CCZ file is invalid, please verify it and try again!

mult.install.prompt=From here you can install your app multimedia from a ZIP file on the local filesystem
mult.install.button=Install Multimedia
Expand Down
33 changes: 23 additions & 10 deletions app/src/org/commcare/tasks/UnzipTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,38 +77,51 @@ private Integer unZipFromStream(ZipInputStream zis, String destinationPath) {
int count = 0;
ZipEntry entry = null;
try {
String destCanonicalPath = destination.getCanonicalPath();
while ((entry = zis.getNextEntry()) != null) {
publishProgress(Localization.get("mult.install.progress", new String[]{String.valueOf(count)}));
count++;

Logger.log(TAG, "Unzipped entry " + entry.getName());

File entryOutput = new File(destination, entry.getName());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: call it entryFile and path beloe entryPath ?

Copy link
Contributor Author

@avazirna avazirna Jan 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shubham1g5 At this point, it's unclear whether the zip entry is a directory or a file, so the idea was to use a generic term to apply the verification to both. How strongly do you feel about this? we can always put that logic in a helper method

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not strongly, ok to skip.

String outputCanonicalPath = entryOutput.getCanonicalPath();
// Check if the entry path aligns with the destination folder
if (!outputCanonicalPath.startsWith(destCanonicalPath)) {
throw new SecurityException(Localization.get("mult.install.progress.invalid.ccz"));
}

if (entry.isDirectory()) {
FileUtil.createFolder(new File(destination, entry.getName()).toString());
FileUtil.createFolder(entryOutput.toString());
//If it's a directory we can move on to the next one
continue;
}

File outputFile = new File(destination, entry.getName());
if (!outputFile.getParentFile().exists()) {
FileUtil.createFolder(outputFile.getParentFile().toString());
if (!entryOutput.getParentFile().exists()) {
FileUtil.createFolder(entryOutput.getParentFile().toString());
}
if (outputFile.exists()) {

if (entryOutput.exists()) {
//Try to overwrite if we can
if (!outputFile.delete()) {
if (!entryOutput.delete()) {
//If we couldn't, just skip for now
continue;
}
}

if (!copyZipEntryToOutputFile(outputFile, zis)) {
if (!copyZipEntryToOutputFile(entryOutput, zis)) {
return -1;
}
}
} catch (IOException e) {
}
catch (IOException e) {
publishProgress(Localization.get("mult.install.progress.badentry", new String[]{entry.getName()}));
return -1;
} finally {
}
catch (SecurityException e) {
publishProgress(e.getMessage());
return -1;
}
finally {
StreamsUtil.closeStream(zis);
}
Logger.log(TAG, "Successfully unzipped files");
Expand Down