Ad

Fixing A Zip Path Traversal Vulnerability In Android

- 1 answer

I have uploaded My Application in Google Play Store and Google has given warning that is "Android Security".

In Application, we downloaded the Zip folder and save this Zip folder in internal Storage and than unZip that folder in internal Storage of device.

here is the UnZip Folder Code:

public static void doUnzip(String inputZipFile, String 
   destinationDirectory, ZipProgressListener zipProgressListener) throws 
    IOException, RuntimeException {

 Log.e(TAG, "doUnzip:inputZipFile: " + inputZipFile);
 Log.e(TAG, "doUnzip:destinationDirectory: " + destinationDirectory);

int BUFFER = 6 * 1024;
List zipFiles = new ArrayList();
  File sourceZipFile = FileUtils.createValidFile(inputZipFile);
   File unzipDestinationDirectory = 
  FileUtils.createValidFile(destinationDirectory);
unzipDestinationDirectory.mkdir();
   String newPath = unzipDestinationDirectory.getAbsolutePath() + 
 File.separator + 
     FileUtils.getFileNameWithoutExtension(sourceZipFile.getName());
  new File(newPath).mkdir();

 ZipFile zipFile;
// Open Zip file for reading
zipFile = new ZipFile(sourceZipFile, ZipFile.OPEN_READ);
int entries = zipFile.size();
int total = 0;
Log.e(TAG, "doUnzip: entries Found !!" + entries);

// Create an enumeration of the entries in the zip file
Enumeration zipFileEntries = zipFile.entries();

if (zipProgressListener != null) {
    zipProgressListener.onZipStart();
}

// Process each entry
while (zipFileEntries.hasMoreElements()) {
    // grab a zip file entry
    ZipEntry entry = (ZipEntry) zipFileEntries.nextElement();

    String currentEntry = entry.getName();
    Log.i(TAG, "[doUnzip] " + currentEntry);

    File file = new File(newPath);

    File destFile = new File(newPath, currentEntry);
    Log.i(TAG, "doUnzip getCanonicalPath : " + 
destFile.getCanonicalPath());

    if (Build.VERSION.SDK_INT <= VERSION_CODES.LOLLIPOP) {
        Log.i(TAG, "doUnzip: LOLLIPOP");
        if 
  (!destFile.getCanonicalPath().startsWith(destinationDirectory)) {
            throw new RuntimeException(destFile.getCanonicalPath() + 
  " is outside of targetDirectory: " + destinationDirectory);
        }
    } else {
        Log.i(TAG, "doUnzip: Above ");
        if(!destFile.getCanonicalPath().contains(file.getName()) && 
    !destFile.getCanonicalPath().contains("/")){
            throw new RuntimeException(destFile.getCanonicalPath() + 
     " is outside of targetDirectory: " + destinationDirectory);
          }
      }

      if (currentEntry.endsWith(".zip")) {
        zipFiles.add(destFile.getAbsolutePath());
    }

    // grab file's parent directory structure
    File destinationParent = destFile.getParentFile();
    // create the parent directory structure if needed
    destinationParent.mkdirs();

       try {
        // extract file if not a directory
        if (!entry.isDirectory()) {
            BufferedInputStream is = new 
       BufferedInputStream(zipFile.getInputStream(entry));
            int currentByte;
            // establish buffer for writing file
            byte data[] = new byte[BUFFER];

            // write the current file to disk
            FileOutputStream fos = new FileOutputStream(destFile);
            BufferedOutputStream dest = new BufferedOutputStream(fos, 
        BUFFER);

            // read and write until last byte is encountered
            while ((currentByte = is.read(data, 0, BUFFER)) != -1) {
                dest.write(data, 0, currentByte);
            }

            Log.e(TAG, "unzip:outPath: =>" + 
        destFile.getAbsolutePath() + "\nFile size: " + destFile.length() 
         / 1024);
            dest.flush();
            dest.close();
            is.close();
        }

        int progress = 0;
        if (zipProgressListener != null) {
            progress = (total++ * 100 / entries);
            zipProgressListener.onZipProgressUpdate(progress);
        }
        Log.e(TAG, "unzip: PROGRESS::" + progress);
      } catch (IOException ioe) {
        ioe.printStackTrace();
      }
       }
       zipFile.close();

      for (Object zipFile1 : zipFiles) {
         String zipName = (String) zipFile1;
         Log.i(TAG, "doUnzip: ");
         doUnzip(zipName, destinationDirectory + File.separator + 
         zipName.substring(0, zipName.lastIndexOf(".zip")),
            zipProgressListener);
     }

   if (zipProgressListener != null) {
    Log.i(TAG, "doUnzip: " + sourceZipFile.getName());

    zipProgressListener.onZipCompleted(destinationDirectory +
            File.separatorChar + sourceZipFile.getName().substring(0, 
  sourceZipFile.getName().lastIndexOf(".zip")));
  }

   }

Here is Google warning :

This information is intended for developers with the app(s) that contain unsafe unzipping patterns, which may potentially lead to a Zip Path Traversal attack. Locations of vulnerable app classes containing unsafe unzipping patterns can be found in the Play Console notification for your app.

Additional details

Zip files can contain an entry (file or directory) having path traversal characters (“../”) in its name. If developers unzip such zip file entries without validating their name, it can potentially cause a path traversal attack, leading to writes in arbitrary directories or even overwriting the files in the app's private folders.

We recommend fixing this issue in your app by checking if canonical paths to unzipped files are underneath an expected directory. Specifically, before using a File object created using the return value of ZipEntry's getName() method, always check if the return value of File.GetCanonicalPath() belongs to the intended directory path. For example:

InputStream is = new InputStream(untrustedFileName);
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(is));
while((ZipEntry ze = zis.getNextEntry()) != null) {
  File f = new File(DIR, ze.getName());
  String canonicalPath = f.getCanonicalPath();
  if (!canonicalPath.startsWith(DIR)) {
    // SecurityException
  }
  // Finish unzipping…
}

How can I solve this warning in Above Android OS-6?

Ad

Answer

Check vulnerability like this

InputStream is = new InputStream(untrustedFileName);
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(is));
while((ZipEntry ze = zis.getNextEntry()) != null) {
    File outputFile = new File(outputDir, ze.getName());
    try {
        ensureZipPathSafety(outputFile, outputDir);
    } catch (Exception e) {
        e.printStackTrace();
        return;
    }
    // Finish unzipping…
}


private void ensureZipPathSafety(final File outputFile, final String destDirectory) throws Exception {
    String destDirCanonicalPath = (new File(destDirectory)).getCanonicalPath();
    String outputFilecanonicalPath = outputFile.getCanonicalPath();
    if (!outputFileCanonicalPath.startsWith(destDirCanonicalPath)) {
        throw new Exception(String.format("Found Zip Path Traversal Vulnerability with %s", canonicalPath));
    }
}
Ad
source: stackoverflow.com
Ad