FlawOpen

flawopen.com/Обход пути/Zip Slip

Что такое уязвимость Zip Slip?

Reference page
ELI5

В ZIP-архиве может быть имя ../../outside.txt. Если распаковщик ему доверяет, файл запишется за пределами целевого каталога — в пределах прав процесса.

Почему это легко пропустить

Распаковка кажется обычной операцией, но создатель недоверенного ZIP- или TAR-архива задаёт имена его записей. Соединение outputDir + entry.name без проверки пути позволяет выйти из каталога через содержимое архива.

VULNERABLE (conceptual)
for entry in zip_file:
    dest = os.path.join(output_dir, entry.name)
    write_file(dest, entry.read())
# entry.name может быть "../../outside.txt"
ЛЕКСИЧЕСКАЯ ПРОВЕРКА ГРАНИЦ — не защищает от гонок сама по себе
root = os.path.realpath(output_dir)
os.makedirs(root, exist_ok=True)
for entry in zip_file:
    dest = os.path.realpath(
      os.path.join(root, entry.name)
    )
    try:
        inside_root = os.path.commonpath([root, dest]) == root
    except ValueError:
        inside_root = False
    if not inside_root:
        raise ValueError("Unsafe entry path")
    write_file(dest, entry.read())

Эта проверка блокирует выходы за каталог, в том числе соседние пути с одинаковым текстовым префиксом. Распаковывайте в новую закрытую директорию, отклоняйте записи-symlink и учитывайте существующие symlink и параллельные изменения файловой системы — для этого нужны API, устойчивые к гонкам, или поддерживаемая библиотека распаковки.

Частые вопросы

В Python API архивов по-разному защищают пути

Показанная выше пара кода — концептуальный пример собственного цикла распаковки, а не встроенный метод Python ZipFile.extractall(). В документации Python сказано, что ZipFile.extract() и extractall() пытаются предотвращать выход за каталог через абсолютные пути и .., но также рекомендуется проверять недоверенные архивы. zipfile.Path не очищает имена элементов, поэтому вызывающий код должен проверять их сам. Фильтры извлечения TAR появились в Python 3.12; в Python 3.14 значением по умолчанию стал filter="data". В поддерживаемых версиях задавайте этот фильтр явно, если значение по умолчанию может быть менее строгим. Даже фильтр data не блокирует все небезопасные действия и риски исчерпания ресурсов. Распаковывайте архив в новый закрытый временный каталог и ограничивайте размер архива, число элементов, общий объём распакованных данных и время обработки.

Защищают ли современные архивные библиотеки автоматически?

В некоторых версиях после широкой огласки этого шаблона в 2018 году появилась защита; другие не проверяют пути по умолчанию. Проверьте документацию своей версии и явно валидируйте каждую запись.

Источники

См. также Обход каталогов (CWE-22): как это работает и как предотвратить на любом языке — flawopen.com Node.js path.join() не защищает от Path Traversal PHP include() и пути, заданные пользователем Защита от Path Traversal в Python os.path.join()