V5628. OWASP. Possible Zip Slip vulnerability. Potentially tainted data is used in the path to extract the file.

Анализатор обнаружил операцию извлечения файла по непроверенному пути, включающему имя файла. В случае наличия в имени файла "dot-dot-slash" последовательностей эта операция приведет к возникновению уязвимости Zip Slip в приложении.

Zip Slip проводится через передачу в приложение архива с вредоносными файлами внутри: они содержат в имени "dot-dot-slash" последовательности ("../../evil.csx"). Спровоцировав распаковку такого архива, злоумышленник может переписать любые файлы, к которым у приложения есть доступ.

В большинстве архиваторов или операционных систем создать файл с названием вида '../../evil.csx' не получится из-за встроенных ограничений. Тем не менее, существуют инструменты, допускающие эту операцию. Из-за этого атака Zip Slip и становится возможной.

Рассмотрим пример небезопасного кода:

public void ExtractArchive(ZipArchive archive, string destinationDirectory)
{
  var entries = archive.Entries;
  foreach (var entry in entries)
  {
    var extractPath = Path.Combine(destinationDirectory, entry.FullName);
    entry.ExtractToFile(extractPath, true);
  }
}

Здесь внутри цикла файлы поочередно извлекаются из архива в директорию, расположенную по пути 'destinationDirectory'. Для каждого файла создаётся путь распаковки с помощью метода 'Path.Combine', после чего результат записывается в переменную 'extractPath'. Далее 'extractPath' используется в качестве аргумента метода 'entry.ExtractToFile', выполняющего разархивирование файла по заданному пути.

Предположим, что архив должен быть извлечён в директорию 'C:\ApplicationFiles\UserFiles'. Однако если свойство 'entry.FullName' вернёт строку вида '\..\config.ini', файл попадёт в корневой каталог приложения 'C:\ApplicationFiles'. В случае совпадения имени извлекаемого файла и, например, файла конфигурации приложения, будет выполнена перезапись последнего.

Обезопасить код в предыдущем примере можно, например, следующим образом:

public void ExtractArchive(ZipArchive archive, string destinationDirectory)
{
  var destinationDirectoryFullPath = Path.GetFullPath(destinationDirectory);
  foreach (var entry in archive.Entries)
  {
    var extractPath = Path.Combine(destinationDirectory, entry.FullName);
    var extractFullPath = Path.GetFullPath(extractPath);
    if (!extractFullPath.StartsWith(destinationDirectoryFullPath))
    {
      throw new IOException("Zip Slip vulnerability");
    }

    entry.ExtractToFile(extractFullPath);
  }
}

Здесь в переменную 'extractFullPath' записывается результат обработки пути 'extractPath' методом 'Path.GetFullPath'. В ходе этой операции путь, содержащий "dot-dot-slash" последовательности, будет заменен на аналогичный, не включающий их.

После этого с помощью метода 'extractFullPath.StartsWith' проверяется, не изменилась ли директория для распаковки файла в результате предыдущей операции. В случае если произошла подмена директории, выбрасывается исключение.

Данная диагностика классифицируется как: