D2
Администратор
- Регистрация
- 19 Фев 2025
- Сообщения
- 4,380
- Реакции
- 0
Авторство: hackeryaroslav
Источник: xss.is
Время чтения: 6 минутОффтоп:
1.Читал форум несколько месяцев и заметил одно: очень мало свежих статей, которые люди выпускают по пентестингу, особенно для новичков. Поэтому сам себя решил попробовать. Давайте больше прогревать форум хорошими авторскими статьями! Весь мой график забит, но когда остается парочку лишних часов, я беру блокнот и накидываю план будущих статей. Поэтому, не ленитесь делиться своими знаниями. Теперь, давайте к делу).
2. Хотя для демонстрации используется Java, уязвимость актуальна для любых веб-приложений, где происходит формирование имен файлов из пользовательского ввода.

Имена файловых путей и навигация по каталогам
Файлы используются настолько часто, что часто им уделяется недостаточное внимание. Тем не менее, небрежное программирование может легко создать серьезные уязвимости. Современные файловые системы организованы в виде каталогов и, возможно, дополнительных подкаталогов, формируя иерархию, где каждый именованный компонент имеет уникальный путь.
Атака обхода каталога (или атака обхода пути) возникает, когда программа формирует путь с использованием входных данных, контролируемых злоумышленником, что может привести к доступу к неожиданному файлу. Ниже приведены примеры, иллюстрирующие, как это может происходить на практике.
Эти атаки аналогичны инъекционным атакам, поскольку злоумышленник вводит метасимволы, изменяющие значение пути таким образом, что он указывает на другие файлы, которые не предусматривались заранее. При создании путей для доступа к файлам необходимо предотвращать вредоносные манипуляции, чтобы злоумышленный код не мог изменить путь неожиданным образом.
Имена путей состоят из идентификаторов, объединенных символами-разделителями путей, чтобы указать компонент иерархической файловой структуры. В путях Unix используется косая черта ('/'), а в путях Windows - обратная косая черта ('\'). В данной статье мы будем использовать имена путей в стиле Unix, но те же принципы применимы к обеим операционным системам, хотя существуют и некоторые тонкие различия, выходящие за рамки данной статьи, но важные для программиста.
Абсолютные имена путей начинаются от корня файловой системы и в Unix начинаются с символа слэша ('/'), а в Windows либо с '\\', либо с именования диска по букве, например, 'C:\' Приведем некоторые примеры абсолютных путей для лучшего понимания различных возможных форм.
Синтаксис Unix | Синтаксис Windows |
---|---|
/primer | \\\primer |
/dir/file | \\\dir\file |
/Users/user123/dev/src/file.c | C:\Users\user123\dev\src\file.c |
В первом примере указывается файл primer в корневом каталоге. Во втором примере ссылается на файл file в каталоге dir корневого каталога. В третьем примере указывается файл file.c в каталоге src в каталоге dev в каталоге user123 в каталоге Users корневого каталога (диска C, для Windows).
Относительные имена путей относятся к текущему рабочему каталогу для контекста процесса, который устанавливается системным вызовом (или командой cd или chdir). Эти пути начинаются с имени каталога или файла, либо с одной точки или символа точки ('.'), который указывает текущий каталог в данной точке интерпретации пути.
Синтаксис Unix | Синтаксис Windows |
---|---|
file.c | file.c |
./test123.doc | .\test123.doc |
git/test.py | git\test.py |
В первом примере указывается файл file.c в текущем каталоге. Во втором примере указывается файл test123.doc в текущем каталоге (с использованием ведущей '.').В третьем примере указывается файл test.py в каталоге git в текущем каталоге.
Еще одной особенностью имен путей является использование двойной точки ('..'), которая указывает на родительский каталог текущего каталога, перемещаясь на один уровень вверх по иерархии файловой системы.
Синтаксис Unix | Синтаксис Windows |
---|---|
/usr/admin/../adminxss/git/xss.py | \\usr\admin\..\adminxss\git\xss.py |
../admin/./test.py | ..\admin\.\test.py |
Первый пример представляет собой абсолютный путь, который интерпретируется слева направо следующим образом: начинаем с корня файловой системы, содержащего каталог usr, затем каталог admin внутри него. Далее, ".." указывает назад к родительскому каталогу usr; оттуда к каталогу adminxss, внутри которого находится каталог git, и, наконец, находим файл xss.py.
Второй пример представляет относительный путь; двойная точка ("..") указывает на родительский каталог текущего каталога. Также упоминается каталог admin внутри текущего каталога (точка (".") ссылается на тот же каталог admin и может быть опущена), и, наконец, указывается файл test.py внутри текущего каталога.
Каноническое имя пути (да такое существует
Это описание имен путей предназначено для введения в основы и упрощено для объяснения возможных атак. Оно не претендует на полноту информации и зависит от конкретной операционной системы. Рекомендуется дополнительно изучить особенности платформы, на которой вы работаете, чтобы понять возможные дополнительные атаки.
Пути веб-адресов также подвергаются атакам обхода каталога, аналогично именам файловых путей, так как они используют тот же синтаксис "." и "..". Это особенно актуально, поскольку части URL-путей часто используются непосредственно как часть имен путей.
Атаки обхода каталога
При формировании программным обеспечением строк имен путей из входных данных злоумышленники могут внедрять различные специальные символы, такие как разделители путей и ссылки на родительские каталоги "..", что создает потенциальные уязвимости.
Давайте рассмотрим пример, где код был написан без учета безопасности. В данном случае веб-сервис принимает параметр "file", предполагая, что он соответствует имени файла, уже находящегося в каталоге /adminxssdircodetest123 сервера. Запрос к серверу приводит к удалению файла. Пользователи управляют файлами в данном каталоге, поэтому это, по мнению программиста, должно быть абсолютно безопасно.
Java: Скопировать в буфер обмена
Код:
String filename = request.getParameter("file");
String pathname = "/adminxssdircodetest123/" + filename;
File f = new File(pathname);
f.delete();
Однако, передав параметр файла URL: "../etc/passwd", вторая строка создает строку имени пути: "/adminxssdircodetest123/../etc/passwd". Поскольку /adminxssdircodetest123 находится в корне файловой системы, то эффективным именем пути становится /etc/passwd, что приводит к удалению всех паролей.
В следующем примере наш пугливый программист предпринимает попытку предотвратить атаку, добавив код:
Java: Скопировать в буфер обмена
Код:
String filename = request.getParameter("file");
String pathname = "/adminxssdircodetest123/" + filename;
pathname = pathname.replace("../", ""); // Удалить "../" для предотвращения обхода /adminxssdircodetest123
File f = new File(pathname);
f.delete();
Поймете в чем ошибка до того, как я объясню?
Все верно! передав параметр файла URL: "....//etc/passwd", вторая строка строит строку имени пути: "/adminxssdircodetest123/....//etc/passwd". Третья строка изменяет строку имени пути, но злоумышленник использует второй шанс, предоставляя параметр файла URL: "....//etc/passwd". Теперь третья строка приводит к строке имени пути: "/adminxssdircodetest123/.../etc/passwd", что снова приводит к удалению всех системных паролей.
Этот пример показывает, что блокировка подобных атак может быть рискованной, и даже продуманные защитные меры могут иметь уязвимости.
Безопасное преодоление атаки обхода каталога
Безопасный подход к предотвращению атак обхода каталога включает в себя работу с каноническими именами путей, предоставляя надежное решение, поскольку эти канонические имена не содержат ухищренных ссылок на родительские каталоги или несанкционированных ссылок. Рассмотрим следующий код, который эффективно предотвращает подобные атаки.
Java: Скопировать в буфер обмена
Код:
String filename = request.getParameter("file");
final String base = "/adminxssdircodetest123";
File prefix = new File(base);
File path = new File(prefix, filename);
// Проверка, что результирующий путь начинается с префикса базового пути
if (!path.getCanonicalPath().startsWith(base)) {
throw new PathTraversalException(filename + " is invalid");
}
// Проверка, что результирующий путь длиннее префикса базового пути более чем на 1 символ
if (!(path.getCanonicalPath().length() > prefix.getCanonicalPath().length() + 1)) {
throw new PathTraversalException(filename + " is invalid");
}
// Безопасное удаление файла
path.delete();
Код начинается с получения имени файла из пользовательского запроса в виде пути. Затем создается объект File для безопасного каталога /adminxssdircodetest123 с именем prefix, а также еще один объект File относительно безопасного каталога для удаляемого файла с именем path.
Перед выполнением действий две проверки гарантируют, что удаление происходит только в пределах безопасного каталога:
- Первая проверка (оператор if) убеждается, что безопасный каталог /adminxssdircodetest123 является префиксом канонического пути, гарантируя, что эффективная цель находится в этом каталоге или под ним в иерархии.
- Вторая проверка (оператор if) гарантирует, что канонический путь длиннее пути к безопасному каталогу /adminxssdircodetest123/, чтобы избежать удаления самого безопасного каталога.
Еще один тонкий вид атаки
Вот еще один реальный пример, который еще более наглядно демонстрирует риски, связанные с попыткой обработки пользовательского ввода, который используется для создания имен файлов. В данном случае программист решил отклонять пользовательский ввод, если строка содержала символ-разделитель пути к файлу, который в UNIX-системах (включая Linux) равен "/", а в системах Windows - "\". Для обеспечения переносимости кода он использовал встроенное определение java.io.File.separator. Это определение возвращает соответствующий символ разделителя пути для операционной системы, на которой запущена программа.
Java: Скопировать в буфер обмена
Код:
String path = request.getParameter("file");
String fullpath = "C:\\AdminXSSHowToBeInDARKBOYS666?\\🤘" + path;
// Проверка наличия разделителей dir для предотвращения выхода из safedir
if (path.contains(java.io.File.separator)) {
throw new PathTraversalException(path + " фиг тебе, а не etc/passwd!");
}
File f = new File(fullpath);
f.delete();
Однако в Java существует тонкое поведение, которое подрывает этот метод санитарной обработки ввода. При выполнении под Windows имя пути к файлу в Java может содержать как прямую, так и обратную косую черту в качестве разделителей, в то время как в системах Linux допустимы только прямые косые черты. В приведенном коде происходит несоответствие: в Windows java.io.File.separator - это "\", однако в именах файлов также может использоваться "/". Если злоумышленник предоставит строку "../Windows/System32/Boot/winload.exe", эффективный путь к удаляемому файлу будет "C:\Windows\System32\Boot\winload.exe".
Этот код также сталкивается с проблемой, когда имя файла состоит только из ".". Однако ранее представленное решение смягчения последствий решает эти проблемы. Вызов getCanonicalPath содержит только символ разделителя пути, соответствующий операционной системе, что делает неудачным сравнение между построенной строкой и канонической версией.
Средства защиты от обхода каталога
Атаки с обходом каталога могут быть предотвращены, если код строит имена путей на основе входных данных, с которыми пользователи не могут взаимодействовать напрямую. Если динамическое создание имен путей неизбежно, важно тщательно ограничивать входные данные только теми символами, которые безопасны для компонентов пути, и запрещать использование разделителей и символов с особым значением. Регулярные выражения, например ^[A-Za-z0-9]+$, могут использоваться для требования, чтобы входная строка состояла только из буквенно-цифровых символов, чтобы предотвратить обход каталога. Однако такой подход может оказаться ограниченным в случае использования Unicode или других сложных кодировок символов, поэтому лучше использовать стандартные средства, такие как объекты java.nio.file.Path, для построения путей. Преобразование относительных путей в абсолютные также облегчает их проверку на корректность.
Если это возможно, уменьшение привилегий процесса, обращающегося к файлам, снижает потенциальный ущерб в случае обхода. Злоумышленник чаще всего стремится выполнить атаку с обходом каталога с привилегиями администратора, чтобы получить доступ к системным файлам. Снижение привилегий усложняет эту задачу, так как доступ к файлам становится более ограниченным.
Попытка хитроумно обработать все возможные вредоносные входы рискованна, так как вы должны правильно предвидеть и блокировать каждую возможную атаку, что может быть сложной задачей.
Супер простые уязвимые коды к Path traversal attack на C#, PHP, Python
C#:
C#: Скопировать в буфер обмена
Код:
string fileName = Request.QueryString["file"];
string path = "/uploads/" + fileName;
File.Delete(path);
Глубже в уязвимость обхода каталога на шарпах
Давайте рассмотрим следующий код:
C#: Скопировать в буфер обмена
Код:
Response.Write("<strong>Абсолютный путь e:\\: </strong><br />");
string[] dirs = Directory.GetDirectories("e:\\");
foreach (string dir in dirs)
{
Response.Write(dir + "<br />");
}
Response.Write("<br /><strong>Чтение e:\\StorageHelper.cs по абсолютному пути: </strong><br />");
Response.Write(File.ReadAllText("e:\\StorageHelper.cs") + "<br />");
Response.Write("<br /><strong>Корневой путь C: полученный с помощью ./../../../: </strong><br />");
string[] dirs2 = Directory.GetDirectories("./../../../");
foreach (string dir in dirs2)
{
Response.Write(dir + "<br />");
}
Response.Write("<br/><strong>Чтение c:\\StorageHelper.cs с ./../../../: </strong><br />");
Response.Write(File.ReadAllText("./../../../StorageHelper.cs") + "<br />");
Response.Write("<br /><strong>Каталог приложения: полученный с помощью ServerMapPath(\"~/../..\"): </strong><br />");
string[] dirs3 = Directory.GetDirectories(Server.MapPath("~/../"));
foreach (string dir in dirs3)
{
Response.Write(dir + "<br />");
}
// Этот код вызывает исключение - но здесь низкий уровень безопасности
Response.Write("Каталог приложения: полученный с помощью /../: <br/>");
string[] dirs4 = Directory.GetDirectories(Server.MapPath("/../."));
foreach (string dir in dirs4)
{
Response.Write(dir + "<br />");
}
Response.Write("<br /><strong>Каталог приложения: полученный с помощью Server.MapPath(\"/\") + \"../\": </strong><br />");
string[] dirs5 = Directory.GetDirectories(Server.MapPath("/") + "../");
foreach (string dir in dirs5)
{
Response.Write(dir + "<br />");
}
Результат выполнения этого кода будет следующим:
Обход каталога
Абсолютный путь e::
e:$RECYCLE.BIN
e:\ASP.NET_TEMP
e:\AzureSLN
Чтение e:\StorageHelper.cs по абсолютному пути:
************ Некоторый код 2 ************
Корневой путь C: полученный с помощью ./../../../:
./../../../$Recycle.Bin./../../../Backup./../../../Boot
Чтение c:\StorageHelper.cs с ./../../../:
*************************** Некоторый код StorageHelper.cs ***************************
Каталог приложения: полученный с помощьюServerMapPath("~/../"):
C:\inetpub\wwwroot\3855_10914C:\inetpub\wwwroot\3889_32518C:\inetpub\wwwroot\3968_07397
Каталог приложения: полученный с помощью Server.MapPath("/")"../:
C:\inetpub\wwwroot../AdminScriptsC:\inetpub\wwwroot../custerrC:\inetpub\wwwroot../history
Это список с одного конкретного жесткого диска. Точные пути или списки не важны, главное - вы можете просто читать любой файл или перечислять любой каталог. И вы можете использовать как относительные, так и абсолютные пути. В данном случае это даже более серьезная уязвимость, называемая полным раскрытием пути. Эта ошибка позволяет злоумышленнику видеть полный путь в сообщении об ошибке. Злоумышленник узнает структуру вашего каталога и может эффективно использовать уязвимость обхода каталога.
PHP:
PHP: Скопировать в буфер обмена
Код:
$fileName = $_GET['file'];
$path = "/uploads/" . $fileName;
unlink($path);
Python:
Python: Скопировать в буфер обмена
Код:
filename = request.args.get('file')
path = f"/uploads/{filename}"
os.remove(path)
Как мы видим, даже если ни один из языков вам не знаком, мы понимаем, что приведенные фрагменты уязвимого кода имеют схожую структуру. Во всех случаях происходит получение входных данных от пользователя, конкатенация со строкой пути к файлу и затем - работа с этим файлом.
Несмотря на различия в синтаксисе языков программирования, логика уязвимости остается неизменной. Злоумышленник может манипулировать входными данными таким образом, что результирующий путь будет указывать на другой файл, с которым изначально не планировалось взаимодействовать. Так происходит обход файловой структуры и получение несанкционированного доступа.
Это еще раз подчеркивает мысль, что проблема носит логический характер и касается этапа проектирования приложения и архитектуры. Небезопасная работа с входными данными при построении пути к файлу может привести к подобной уязвимости на любом языке программирования.
Итоги
Итак, мы рассмотрели различные типы атак, связанных с обходом каталогов, на примере уязвимого кода в Java, Как видно, эта проблема актуальна для многих технологий и приложений. Были продемонстрированы примеры взломов сайтов через подобные уязвимости.