Перейти к содержанию

Path/directory traversal

Описание

Уязвимость Path Traversal возникает, когда злоумышленник контролирует часть пути, которая затем передается API-интерфейсам файловой системы без проверки. Это может привести к несанкционированным операциям с файловой системой. Например, злоумышленник может использовать специальные символы, такие как ../, чтобы выйти за пределы целевого каталога.

Реализации openFile(...) и openAssetFile(...) в экспортированных ContentProviders могут быть уязвимы, если они должным образом не проверяют входящие параметры uri. Вредоносное приложение может предоставить созданный uri (например, тот, который содержит /../), чтобы заставить ваше приложение вернуть ParcelFileDescriptor для файла за пределами предполагаемого каталога, тем самым позволяя вредоносному приложению получить доступ к любому файлу.

Примеры «небезопасных» (отсутствие проверок uri) реализаций методов openFile(...) и openAssetFile(...).

public ParcelFileDescriptor openFile(Uri uri, String mode) throws RemoteException, FileNotFoundException {
    return provider.openFile(uri, mode);
}
public @Nullable AssetFileDescriptor openAssetFile(@NonNull Uri uri, @NonNull String mode)
        throws FileNotFoundException {
    ParcelFileDescriptor fd = openFile(uri, mode);
    return fd != null ? new AssetFileDescriptor(fd, 0, -1) : null;
}

Также в Android-экосистеме можно встретиться с уязвимостью Zip Path Traversal, также известной как ZipSlip, которая связана с обработкой сжатых архивов. Чуть ниже будет продемонстрирована данная уязвимость на примере формата ZIP, но аналогичные проблемы могут возникнуть и в библиотеках, обрабатывающих другие форматы, такие как TAR, RAR или 7z.

Проблема в том, что внутри ZIP-архивов каждый упакованный файл хранится с полным именем, которое допускает использование специальных символов, таких как косая черта и точки. Библиотека по умолчанию из пакета java.util.zip не проверяет имена записей архива на наличие символов обхода каталога (../), поэтому необходимо соблюдать особую осторожность при объединении имени, извлеченного из архива, с целевым путем к каталогу.

Очень важно проверять любые фрагменты кода и библиотеки из внешних источников, связанные с работой с ZIP-архивами — многие из них уязвимы для Zip Path Traversals.

Влияние

Результат атаки зависит от операции и содержимого файла, но обычно приводит к перезаписи файла (при записи файлов), утечке данных (при чтении файлов) или изменению прав доступа (при изменении разрешений файла/каталога).

Уязвимость Zip Path Traversal может использоваться для произвольной перезаписи файла. В зависимости от условий последствия могут различаться, но во многих случаях эта уязвимость может привести к серьезным проблемам с безопасностью, например к выполнению кода.

Рекомендации

  1. Получите канонический путь с помощью File.getCanonicalPath() и сравните префикс с ожидаемым каталогом. Один файл, существующий в системе, может иметь много разных путей к нему, но только один канонический путь. Канонический путь — это уникальный абсолютный путь для данного файла.

    public File saferOpenFile(String path, String expectedDir) throws IllegalArgumentException {
        File f = new File(path);
        String canonicalPath = f.getCanonicalPath();
        if (!canonicalPath.startsWith(expectedDir)) {
            throw new IllegalArgumentException();
        }
        return f;
    }
    

    Дополнительные проверки:

    • Проверьте, существует ли уже файл, чтобы предотвратить случайную перезапись.
    • Проверьте, является ли целевой файл ожидаемой целью, чтобы предотвратить утечку данных или неправильное изменение разрешений.
    • Проверьте, является ли текущий каталог операции точно таким, как ожидается в возвращаемом значении из канонического пути.
    • Обеспечьте, чтобы система разрешений была явно привязана к операции (например, проверка того, что она не запускает службы от имени пользователя root) и разрешения каталога были ограничены указанной службой или командой.
  2. Сделайте ваш ContentProvider android:exported = false, если это возможно.

  3. Установите в ContentProvider атрибут android:permission как разрешение с android:protectionLevel="signature", чтобы запретить приложениям, написанным другими разработчиками, отправлять намерения ContentProvider.

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

    public static File newFile(File targetPath, ZipEntry zipEntry) throws IOException {
        String name = zipEntry.getName();
        File f = new File(targetPath, name);
        String canonicalPath = f.getCanonicalPath();
        if (!canonicalPath.startsWith(targetPath.getCanonicalPath() + File.separator)) {
            throw new ZipException("Illegal name: " + name);
        }
        return f;
    }
    
  5. Перед началом процесса извлечения данных из архива убедитесь, что каталог назначения пуст. Чтобы избежать случайной перезаписи существующих файлов, необходимо перед началом извлечения убедиться, что каталог назначения пуст, в противном случае вы рискуете потенциальными сбоями или в крайних случаях компрометацией приложения.

    void unzip(final InputStream inputStream, File destinationDir)
            throws IOException {
        if(!destinationDir.isDirectory()) {
            throw IOException("Destination is not a directory.");
        }
    
        String[] files = destinationDir.list();
        if(files != null && files.length != 0) {
            throw IOException("Destination directory is not empty.");
        }
    
        try (ZipInputStream zipInputStream = new ZipInputStream(inputStream)) {
            ZipEntry zipEntry;
            while ((zipEntry = zipInputStream.getNextEntry()) != null) {
                final File targetFile = new File(destinationDir, zipEntry);
            
            }
        }
    }
    

Ссылки

  1. Path traversal
  2. Zip Slip Vulnerability
  3. Zip Path Traversal
  4. Дополнительная информация о Path traversal
К началу