Возможность перезаписи файлов в приватной директории приложения при работе с zip-архивами
Критичность: ВЫСОКИЙ | |
Описание
Выявленная уязвимость относится к конкретному сценарию, при котором возможно перезаписать приватные файлы приложения, эксплуатируя сочетание zip-архива и уязвимости обхода пути (Path Traversal). Уязвимость обхода пути (Path Traversal) — это тип уязвимости, при котором злоумышленник может манипулировать путем к файлу с целью получить доступ к файлам или каталогам за пределами предполагаемой директории. Проще говоря, это означает, что злоумышленник может «пройти» по файловой системе выше и получить доступ к файлам, к которым он не должен иметь доступ, к примеру через указание пути ../../../
.
Примерный сценарий атаки:
-
Злоумышленник создает специально подготовленный zip-архив, содержащий файл с путем, включающим последовательность обхода пути. Например, файл внутри zip-архива может иметь путь
../../data/private_file.txt
. -
Злоумышленник убеждает целевого пользователя загрузить и извлечь вредоносный zip-архив на своем устройстве Android. Это может быть достигнуто средствами социальной инженерии, например, через вредоносный веб-сайт, электронное письмо с вредоносным вложением или другими способами. Либо атака может быть направлена на обход локальных проверок, например, если аутентификация по pin-коду осуществлена локально, возможно перезаписать файл, содержащий значение кода, на свой и войти в приложение.
-
При извлечении zip-архива, если не выполняется должная проверка путей файлов внутри архива, злоумышленник может перезаписать приватные файлы.
В зависимости от файла, на который направлена атака, это может потенциально привести к несанкционированному раскрытию конфиденциальной информации или изменению важных данных.
Пример уязвимого кода.
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class ZipExtractor {
public static void extractZip(String zipFilePath, String destinationPath) {
try {
File destDir = new File(destinationPath);
byte[] buffer = new byte[1024];
ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(zipFilePath));
ZipEntry zipEntry = zipInputStream.getNextEntry();
while (zipEntry != null) {
String entryName = zipEntry.getName();
String entryPath = destinationPath + File.separator + entryName;
File outputFile = new File(entryPath);
outputFile.getParentFile().mkdirs();
FileOutputStream fos = new FileOutputStream(outputFile);
int length;
while ((length = zipInputStream.read(buffer)) > 0) {
fos.write(buffer, 0, length);
}
fos.close();
zipEntry = zipInputStream.getNextEntry();
}
zipInputStream.closeEntry();
zipInputStream.close();
System.out.println("Zip extraction complete.");
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
String zipFilePath = "/path/to/malicious.zip"; // Path to the malicious zip-archive
String destinationPath = "/data/private/"; // Destination directory for extracting files
extractZip(zipFilePath, destinationPath);
}
}
В этом коде метод extractZip()
отвечает за извлечение файлов из zip-архива. Однако он некорректно фильтрует пути к файлам, что делает его уязвимым для атак Path Traversal. Например, если destinationPath
установлен на /data/private/
, злоумышленник может создать файл с путем ../../data/private_file.txt
внутри zip-архива. Когда уязвимый код извлекает архив, он добавляет путь к файлу к destinationPath
, что в итоге даст путь к /data/private/../../data/private_file.txt
. В результате злоумышленник получает доступ к private_file.txt и сможет перезаписать его.
Чтобы устранить эту уязвимость, необходимо проводить правильную валидацию и санитизацию входных данных, связанных с путями к файлам. Этого можно достичь сравнением путей к файлам с ожидаемой структурой каталогов с целью убедиться, что извлеченные файлы находятся в предназначенном каталоге.
Рекомендации
Чтобы устранить уязвимость и предотвратить атаки с Path Traversal, необходимо реализовать проверку ввода и санитизировать пути к файлам. Например, в представленном выше коде это можно исправить следующим образом.
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class ZipExtractor {
public static void extractZip(String zipFilePath, String destinationPath) {
try {
File destDir = new File(destinationPath);
byte[] buffer = new byte[1024];
ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(zipFilePath));
ZipEntry zipEntry = zipInputStream.getNextEntry();
while (zipEntry != null) {
String entryName = zipEntry.getName();
String entryPath = sanitizeFilePath(destinationPath, entryName);
if (entryPath != null) {
File outputFile = new File(entryPath);
outputFile.getParentFile().mkdirs();
FileOutputStream fos = new FileOutputStream(outputFile);
int length;
while ((length = zipInputStream.read(buffer)) > 0) {
fos.write(buffer, 0, length);
}
fos.close();
}
zipEntry = zipInputStream.getNextEntry();
}
zipInputStream.closeEntry();
zipInputStream.close();
System.out.println("Zip extraction complete.");
} catch (IOException e) {
e.printStackTrace();
}
}
private static String sanitizeFilePath(String destinationPath, String entryName) {
// Ensure that the entry name does not contain any path traversal sequences
String sanitizedEntryName = entryName.replace("..", "").replace("/", "").replace("\\", "");
// Check if the resulting path is within the intended destination directory
String entryPath = destinationPath + File.separator + sanitizedEntryName;
File destinationDir = new File(destinationPath);
if (!destinationDir.toPath().normalize().equals(new File(entryPath).toPath().normalize())) {
// Abort extraction if the entry path is outside the intended directory
System.err.println("Invalid file path: " + entryPath);
return null;
}
return entryPath;
}
public static void main(String[] args) {
String zipFilePath = "/path/to/malicious.zip"; // Path to the malicious zip-archive
String destinationPath = "/data/private/"; // Destination directory for extracting files
extractZip(zipFilePath, destinationPath);
}
}
В обновленном коде введен метод sanitizeFilePath()
, который выполняет валидацию и санитизацию путей к извлеченным файлам. Вот как это работает:
-
Метод принимает
destinationPath
(предполагаемый каталог для извлечения файлов) иentryName
(имя файла внутри zip-архива) в качестве входных данных. -
Метод очищает
entryName
путем удаления любых последовательностей обхода пути, таких как..
, прямых (/
) и обратных (\
) слэшей. -
Затем он добавляет очищенный
entryName
кdestinationPath
для получения полного путиentryPath
. -
Метод сравнивает нормализованную версию
entryPath
с нормализованной версиейdestinationPath
, чтобы убедиться, что извлеченный файл будет находиться в предполагаемом каталоге. Несовпадение путей указывает на то, что путь к файлу пытается выйти за пределы предполагаемой структуры каталогов и процесс извлечения прерывается.
В результате этих модификаций код выполняет валидацию входных данных и предотвращает атаки прохода по пути, убеждаясь, что извлеченные файлы остаются в предполагаемом каталоге назначения.
Чтобы предотвратить подобные уязвимости, необходимо придерживаться основных принципов:
-
Валидация и санитизация ввода. Необходимо реализовать надежные механизмы валидации входных данных, особенно имен и путей файлов, контролируемых пользователем. Входные данные необходимо проверять на соответствие белому списку разрешенных символов.
-
Использование абсолютных путей к файлам. При доступе к файлам вместо относительных путей используйте абсолютные. Это гарантирует, что операции с файлами будут явно ограничены определенными каталогами и предотвращает непреднамеренный обход пути.
-
Избегайте путей, контролируемых пользователем. Минимизируйте использование входных данных, контролируемых пользователем, особенно для функциональности, связанной с файлами. Если необходимо использовать пользовательский ввод, тщательно валидируйте его перед использованием.
-
Используйте белый список разрешенных имен и путей файлов. Создайте белый список разрешенных имен/путей файлов и валидируйте ввод на соответствие этому списку. Запрещайте или очищайте любой ввод, который не соответствует заранее определенной структуре или шаблонам.
-
Используйте безопасные API и библиотеки для работы с файлами. Используйте безопасные файловые API и библиотеки, которые обеспечивают встроенную защиту от атак Path Traversal. Во многих библиотеках защита от данной уязвимости уже реализована.
-
Регулярно обновляйте зависимости. Следите за актуальностью всех зависимостей, включая фреймворки и библиотеки, с помощью последних патчей безопасности. Уязвимости в коде сторонних разработчиков могут внести риск прохода по пути в ваше приложение. Будьте в курсе информации о безопасности и своевременно обновляйте зависимости.