---
title: DT,LFI,RFI
---
<div class="header__logo" >Вот они слева-направо: Directory Traversal, LFI и RFI!
</div>
<p>
</p>
<style>
.header__logo {
font-size: 30px;
font-weight: 700;
color: #270469;
text-align: center;
}
</style>
<style>
.secret{
display: flex;
margin-left: auto;
margin-right: auto;
width: 50%;
}
</style>
<style>
.secret__block{
background-color: #fff;
display: block;
max-width: 100%;
height: auto;
transition: opacity .8s linear;
color: black;
text-transform: uppercase;
font-weight: 700;
text-align: center;
}
</style>
<style>
.secret__block img{
opacity: 5;
}
</style>
<style>
.secret__block:hover {
opacity: 2 ;
}
</style>
<style>
.secret__img {
opacity: ;
transition: transform 1.8s linear;
}
</style>
<style>
.secret__img img{
opacity: 0 ;
transition: transform 1.8s linear;
}
</style>
<style>
.secret__img img: hover{
opacity: 5 ;
transition: transform 1.8s linear;
}
</style>
<style>
.secret__img img {
display: block;
max-width: 100%;
height: auto;
transition: opacity 1.8s linear;
}
</style>
<style>
.secret__img:hover {
opacity: 5 ;
}
</style>
<style>
.secret__inner {
position: relative;
background-color: #fff;
}
</style>
<style>
.secret__inner:hover .secret__img {
transform: translate3d(-10px, -10px, 0);
}
</style>
<style>
.secret__inner img:hover {
opacity: 0;
transition: opacity 2s linear;
}
</style>
<style>
.secret__inner img {
transition: opacity 2s linear;
}
</style>
<style>
.secret__inner:hover .secret__img img {
opacity: 1;
}
</style>

<div class="TOC" >
Содержание:
<p>
</p>
</div>
<style>
.TOC {
font-size: 26px;
font-weight: 550;
color: #270469;
text-align: left;
</style>
> [TOC]
---
# Вводная часть
Приветствую вас, сегодня мы будем проходить 3 очень похожие баги, а именно:
1) Directory Traversal (порой её также называют Path Traversal).
2) Local File inclusion (LFI).
3) Remote File inclusion (RFI).
Посмотрим, что они из себя представляют, чтобы вы прибавили 100 очков к интеллекту и не путали эти баги:)
В качестве лаб я буду юзать [PortSwigger для Directory Traversal](https://portswigger.net/web-security/file-path-traversal), и таски ([1](https://gitlab.com/mctf/training-02.2023/-/tree/main/WEB/CTF-WIKI) и [2](https://gitlab.com/mctf/training-02.2023/-/tree/main/WEB/CTF-WIKIv2)) [@i_013K](https://t.me/i_013k), которые были на тренировке в конце февраля.
---
# Из чего обычно состоит веб-приложение
Как мы знаем, веб-сайты состоят в наше время из большого количества компонентов: сам HTML-документ с вёрсткой, css-файлы для задания различных стилей, возможно js-файлы, благодаря которым сайт может делать запросы и взаимодействовать с пользователям(например выводя подсказки а как правильно вводить данные в поле email), возможно элементы php(чтобы делать сайт динамичнее, взаимодействовать с БД, совершать загрузки файлов). Помимо этого есть и другие компоненты: картинки, видео и др.

Большинство этих компонентов обрабатывается сервером и потом отправляется браузеру. И тут важный момент: все эти элементы потом включаются в HTML-документ различными способами. То есть, нам не нужно отдельно читать текст в HTML, а потом получать нужную полученную картинку, чтобы увидеть, а про что говорилось в том абзаце. Нет, мы просто получаем все файлы и видим/взаимодействуем с ними через HTML'ку. Давайте разберём а как обычно всё это добро "вкладывается" в HTML-документ
---
# Как обычно включают файлы в HTML-документ
## Статичное
**В качестве примера возьмём картинки.**
Предположим, что некий разработчик решил сделать главную страницу своего сайта примерно такого вида:

Как мы видим, на ней есть изображения и какая-то вёрстка. Он, соответственно, сделал HTML-документ, в котором расположил все элементы как надо, сделал css-файл, с помощью которого "придал красок" сайту, и откуда-то добыл нужные изображения для сайта и положил их в директорию `/var/www/images/`. Как вы понимаете, различные картинки/файлы не находятся изначально в HTML-коде, а они загружаются извне, та же папка images. И чтобы показать HTML'ке, что потом после рендеринга должна быть картинка, или что нужно также использовать js/css из других файлов, нужно использовать теги. Например, тег img встраивает изображение в документ:
```<img width="100%" height="300" src="/home/arroiz/images/someImage.png" />```
И вот, разработчик внедрил в HTML-документ всё, что нужно, настроил сервер, поднял его, и сайт начал функционировать. Через время появился человек, который сделал HTTP-запрос на сервер с целью получить главную страницу. Сервер запрос получает и перенаправляет запрос на дальнейшую обработку к программе-обработчику — например, PHP, фреймворку Flask, Ruby или ASP.NET. Программа внимательно изучает содержимое запроса — например, понимает, в каком формате нужно отправить ответ и какие именно файлы нужны(то есть, надо вернуть html, но html в свою очередь должен содержать и картинки, так что помимо неё нужно ещё отправить определённые картинки из `/var/www/images/`). Программа собирает всё, что нужно, передаёт результат серверу, а сервер передаёт результат уже браузеру пользователя. Браузер распаковывает полученный ответ и постепенно начинает отображать полученный контент на экране пользователя.
У вас может возникнуть вопрос: а зачем всё это было рассказано?
Ну, в моём ответе есть 2 пункта:
1) Вы повторили основы, а это всегда полезно:)
2) Вы теперь имеете представление о том, как на сервере происходит процесс отбора нужных файлов, которые нужно отправить в ответе пользователю. Мы рассмотрели по сути как статично задать то, какие файлики нужно отправить, а что если выборка файлов будет происходить динамично?
## Динамичное
Рассмотрим приложение для покупок, которое отображает изображения товаров для продажи. Изображения загружаются через HTML-тег, как показано ниже:
`<img src="/loadImage?filename=218.png">`
В качестве источника изображения у нас указан маршрут `/loadImage` с параметром filename. Он принимает и возвращает содержимое указанного файла. Сами файлы изображений хранятся на диске в папке `/var/www/images/`. Чтобы вернуть изображение, приложение добавляет запрошенное имя файла к этому базовому каталогу и использует API файловой системы для чтения содержимого файла. В приведенном выше случае приложение читает из следующего пути к файлу:
`/var/www/images/218.png`
И в этом не было ничего такого, ну обратывает приложенька пользовательский ввод(значение параметра filename, которое мы можем контролировать) и пусть обрабатывает. Однако, давайте вспомним вот такую интересную штучку:
Как мы помним, чтобы вернуться в родительскую директорию в терминале(linux, windows, mac os) мы можем использовать `../`. Так вот, такой приём также можно спокойно использовать не только в терминале, но и в той же HTML'ке или в HTTP-запросе, вместо того же 218.png можно указать `../../../../../../../../../etc/passwd` и получить не картинку, а информацию об существующих пользователях на сервере, где приложенька работает.
:::info
**Справочка**
Используя `../../../../../../../../../` в примере выше я как бы вышел из папки images, потом из www, потом из var, а потом ещё несколько "подъёмов" вверх, чтобы точно попасть в корневую папку. После я перешёл в директорию etc и попросил мне выдать файлик passwd.

:::
Теперь, после того как вы ознакомились с базой и поняли, что из себя представляет Directory Traversal, предлагаю наконец к ней перейти!
---
# Directory Traversal
:::warning
**Обход каталога** — это уязвимость, которая позволяет злоумышленнику читать произвольные файлы на сервере, на котором запущено приложение. Это может включать код приложения и данные, учетные данные для серверных систем и конфиденциальные файлы операционной системы.
Обычно здесь задействована комбинация из `../`, чтобы выйти из начальной папки и попасть в ту директорию, которая содержит "интересные" для нас файлы.
:::
Причём, чтобы переходить на один уровень вверх в Windows можно использовать и `../` и `..\`, это следует запомнить!
```https://insecure-website.com/loadImage?filename=..\..\..\windows\win.ini```
## Как обойти различные защиты, мешающие исполнить Directory Traversal?
Естественно, в реальной жизни не всё так просто, и разработчики могут попытаться защитить своё приложение от данной уязвимости, используя различные методы, которые можно обойти, давайте ознакомимся с ними!
### Использование абсолютного пути
:::info
**Лабораторная**:
https://portswigger.net/web-security/file-path-traversal/lab-absolute-path-bypass
:::
Если приложение удаляет или блокирует последовательности обхода каталога из имени файла, предоставленного пользователем, то можно обойти защиту, используя абсолютный путь от корня файловой системы, например `filename=/etc/passwd`, для прямой ссылки на файл без использования каких-либо последовательностей обхода.
**ПРИМЕР**
Не катит, так как есть проверка на последовательность обхода:

Использования абсолютного пути без обходов:

### Использование вложенных последовательностей обхода каталогов
:::info
**Лабораторная**:
https://portswigger.net/web-security/file-path-traversal/lab-sequences-stripped-non-recursively
:::
Если приложение удаляет или блокирует последовательности обхода каталога из имени файла, предоставленного пользователем, и при этом нельзя использовать абсолютный путь, то можно обойти защиту, используя вложенные последовательности обхода, такие как `....//` или `....\/`, которые вернутся к простым последовательностям обхода при удалении внутренней последовательности, проще говоря, это альтернатива для `../`
**ПРИМЕР**
Не катит, так как есть проверка на последовательность обхода:

Не катит, так как есть проверка на абсолютный путь:

Использование вложенных последовательностей обхода:

### URL-кодировка
:::info
**Лабораторная**:
https://portswigger.net/web-security/file-path-traversal/lab-superfluous-url-decode
:::
В некоторых контекстах, таких как URL-адрес или параметр filename запроса multipart/form-data, веб-серверы могут удалять любые последовательности обхода каталога перед передачей нашего ввода в приложение(то есть ни одно из перечисленных ранее методов не работает). Иногда можно обойти этот вид очистки с помощью кодирования URL-адресов или даже двойного кодирования URL-адресов, например, символов ../, что приводит к %2e%2e%2f или %252e%252e%252f соответственно.

Можно также использовать различные нестандартные кодировки, такие как ..%c0%af или ..%ef%bc%8f.
**ПРИМЕР**
Вот картинки, благодаря которым можно понять, что ни один из перечисленных ранее методов больше не работает:



А вот что будет, если мы закодируем в URL нашу полезную нагрузку(2 раза закодируем):

### Обход проверки начала пути
:::info
**Лабораторная**:
https://portswigger.net/web-security/file-path-traversal/lab-validate-start-of-path
:::
Если приложение требует, чтобы имя файла, заданное пользователем, начиналось с ожидаемой базовой папки, например /var/www/images, то можно включить требуемую базовую папку, за которой следуют подходящие последовательности обхода.
Например:
`filename=/var/www/images/../../../etc/passwd`
Тут думаю вы сами сможете решить эту лабу, она простая!
### Обход проверки расширения файла
:::info
**Лабораторная**:
https://portswigger.net/web-security/file-path-traversal/lab-validate-file-extension-null-byte-bypass
:::
Если приложение требует, чтобы введенное пользователем имя файла заканчивалось ожидаемым расширением файла, например .png, то можно использовать нулевой байт для того, чтобы опустить всё, что идёт дальше вместе с `.`(.png, .jpg ...).
Например:
`filename=../../../etc/passwd%00.png`
:::warning
Тут %00 - это и есть нулевой байт, закодированный в URL. Его можно сравнить со знаком комментария в ЯП или в SQL-запросах, то есть, всё, что идёт после него - не учитывается. Таким образом, в запросе в конце есть нужное расширение, но когда дело дойдёт до того, чтобы получить файл, исходное `filename=../../../etc/passwd%00.png` преобразуется в `filename=../../../etc/passwd`.
:::
## Как исправить данную уязвимость?
Самый эффективный способ предотвратить уязвимости, связанные с обходом пути к файлу, — полностью отказаться от передачи пользовательского ввода в API файловой системы. Многие прикладные функции, которые делают это, можно переписать, чтобы обеспечить то же самое поведение более безопасным способом. То есть, мы не должны пользовательский ввод "вкладывать" в путь к файлу, чтобы не было такого:
1) Приложение получает пользовательский ввод, например ../../../../../../etc/passwd
2) Приложение получает путь к папке с картинками - /var/www/images
3) Приложение соединяет путь к папке с пользовательским вводом - /var/www/images/../../../../../../etc/passwd
4) В итоге в HTML выходит что-то типа такого:
`<img src="/var/www/images/../../../../../../etc/passwd"/>`.
Если же передача пользовательского ввода в API файловой системы считается неизбежной, то для предотвращения атак следует использовать вместе два уровня защиты:
1) Приложение должно проверять ввод пользователя перед его обработкой. В идеале проверка должна сравниваться с белым списком разрешенных значений. Если это невозможно для требуемой функциональности, то при проверке следует убедиться, что входные данные содержат только разрешенный контент, например чисто буквенно-цифровые символы. То есть, можно использовать различные проверки в коде, например, на наличие ../
2) После проверки предоставленных входных данных приложение должно добавить входные данные в базовый каталог и использовать API файловой системы платформы для канонизации пути. Он должен убедиться, что канонизированный путь начинается с ожидаемого базового каталога.
Ниже приведен пример простого кода Java для проверки канонического пути к файлу на основе пользовательского ввода:
```
File file = new File(BASE_DIRECTORY, userInput);
if (file.getCanonicalPath().startsWith(BASE_DIRECTORY)) {
// process file
}
```
## Всё?
И тут можно было бы поставить жирную точку и закончить этот топик, но..
Есть один такой момент=)
Directory Traversal это лишь подмножество другой баги, и эта бага уже называется совсем по-другому и умеет она не только читать файлы!
---
# Что такое LFI и RFI, и почему они так похожи на Directory Traversal

На схеме выше вы можете увидеть, что Directory Traversal - это лишь часть уязвимости Local File Inclusion, а она в свою очередь принадлежит уязвимости File inclusion. Давайте разберёмся, что такое File Inclusion и на что он делится!
:::warning
**Для начала давайте резберёмся с Directory Traversal:**
Уязвимость Path Traversal позволяет злоумышленнику получить доступ к файлу, обычно используя механизм «чтения», реализованный в целевом приложении.
*С помощью этой уязвимости мы можем читать файлы!*
**А теперь, что такое File Inclusion:**
Уязвимость File Inclusion(включение файла) позволяет злоумышленнику "включить" файл в ответ, обычно используя механизмы «динамического включения файлов», реализованные в целевом приложении.
*Если файл, который мы включаем в ответ, нельзя исполнить(так как его расширение веб-сервер не исполняет), то по сути мы просто получим его содержимое как в Directory Traversal, а вот если сервер настроен на исполнение файлов с таким расширением, то мы можем этот файл запустить, таким образом заставив, например, сервер исполнять зловредные скрипты!*
:::
А теперь давайте по порядку!
---
# Как использовать LFI
Давайте в качестве примера возьмём таск Саши (@i_013K) с тренировки, которая была в феврале и просто запустим его, после чего зайдём на сайтик.
Зайдя на страницу мы видим шапку, в которой есть разделы сайта, кликая на каждый раздел у нас меняется только основная часть сайта, а всё остальное остаётся таким же:



Также стоит обратить внимание, что при смене каждого раздела меняется и URL сайта:


А что это за файлы такие, которые изменяются?
Давайте глянем в код:

1) В папке с основными файлами у нас есть 5 мини HTML-файлов и один главный php-файл, который потом будет преобразован(после выполнения всего php-кода) в HTML на сервере и отдан именно HTML'кой клиенту.
2) Те самые ссылки в шапке, которые перекидывают то на ?file=1,2,3... Но это до сих пор не отвечает на вопрос, как изменяется контент сам, так как php страница тут одна, а отдельные мини html-файлы не годны для отдельного использования, так как они из себя представляют что-то такое:

3) Раз мини HTML-файлы не могут быть использованы отдельно, но мы их видим на сайте, значит они куда-то ВКЛЮЧАЮТСЯ, и вот тут как раз вступает в игру мини php-код почти в самом низу:
```
<?php if(isset($_GET['file'])) {
include($_GET['file']);}?>
```
:::info
**Функция Include в PHP:**
На самом деле любой разрабатываемый ресурс не может поместится на одной странице, так как современный сайт состоит из десятков страниц, связанных между собой. Все файлы проекта можно сравнить с вагонами поезда. При необходимости можно убрать лишний, а при нехватке – удлинить «программный» состав еще на один. Для «сцепки» файлов используется функция **include** в PHP. Именно благодаря этой функции мы включаем контент мини HTML-файлов в наш php-файл!
То есть, мы можем создать 1 шаблон, и в него внедрять другие части, как это и сделано в таске. Шапка и прочее те же, а вот основной контент меняется в зависимости от страницы.
:::
:::warning
**Перед тем как продолжить я хочу разъяснить вот какой момент, он связан опять с базой по вебу, но его стоит упомянуть, так как дальше он сыграет важную роль:**
Как мы видим, в таске есть **1** php-файл, и сколько-то там HTML-файлов. И тут у многих может встать вопрос:
- А как так получилось, что тут основная страница в php, в которую внедряются html-ки, а по факту нам приходит один единый **HTML** файл?
Смотрите, я это упоминал раньше здесь "Сервер запрос получает и перенаправляет запрос на дальнейшую обработку к программе-обработчику — например, PHP, фреймворку Flask, Ruby или ASP.NET". И сейчас мы раскроем это предложение. Обычно сервер может как просто вернуть клиенту какой-то статичный файл(допустим просто обычную HTML'ку, картинку и тд), а может получить запрос на такой файл, который надо сначала **ОБРАБОТАТЬ**, и вот файл с расширением .php - один из таких файлов. Например, в таске у нас есть php-файл, который запрашивает пользователь, точнее он запрашивает не его, а главную страницу, но по факту это одно и тоже. Сервер, который настроен на исполнение .php файлов, дальше выясняет, что пользователь запросил как раз-таки этот файлик и видит, что этот файлик, грубо говоря, сырой, так как надо сначала выполнить весь php-код в нём. Для этого он передаёт данный php-файл с параметрами запроса программе-обработчику, в нашем случае это PHP. Дальше этот php, получив всё это, подставляем, если надо, что-то в этот файлик, а потом преобразует его в **HTML** и передаёт уже именно **его** веб-серверу. А веб-сервер передаёт уже готовый HTML пользователю.
Что сейчас произошло, если кратко:
Сервер настроен на то, чтобы **исполнять** php-файлы, и чтобы их исполнять он передаёт всё, что нужно для этого PHP'шке. После чего он результат исполнения возвращает пользователю.
:::
Так, вернёмся к коду:
```
<?php if(isset($_GET['file'])) {
include($_GET['file']);}?>
```
Если разорбрать, что делает тут php-код, то получится следующее:
1) Если есть в запросе параметр file с каким-то значением, то выполняется следующий пункт, в противном случае этот php-код как бы исчезает, файл конвертируется в HTML и отдаётся пользователю.
2) Если всё же есть параметр file, то нужно вернуть такой файлик, который указан в значении параметра, т.е. если значение это 2, то нужно вернуть вернуть файл с именем 2(это как раз мини html'ka, хотя по факту это что угодно может быть, оно всё равно встроится в HTML и теги внутри просто будут как теги для HTML). А под словом вернуть имеется в виду, что в **это** конкретное место в коде "внедриться" этот мини html-файл. А потом этот php-файл конвертнётся в HTML(и весь php-код из него исчезнет) и этот HTML'ка вернётся пользователю.

И в чём тут уязвимость, и зачем мы всё это разбирали?
Да всё просто, тут есть LFI, и она тут есть, так как веб-приложение включает файл без правильной очистки ввода, что позволяет злоумышленнику манипулировать вводом и вводить символы обхода пути, а также включать другие файлы с того же веб-сервера.
И по сути мы можем тут провернуть тот же Directory Traversal!

Но так как тут именно LFI, мы можем не только читать файлы, но и исполнять команды, так как напоминаю о том, что было выше, веб-сервер может и порой должен исполнять некоторые файлы, и в данном случае тут исполняется php-код, а это значит мы можем сделать вредоноснгую нагрузку, связанную с php, чтобы например просмотреть путь до дериктории, в которой мы находимся:

И в результате нам "включится" в HTML файл вывод команды pwd!
Давайте ознакомимся со всеми возможностями LFI, чтобы у вас сложилось полное представление по ней:
## Чтение исполняемых файлов
Если есть LFI, то можно спокойно читать те файлы, которые не исполняемые, так как при попытке прочитать исполняемые файлы веб-сервер просто исполнит файл и вернёт результат, таким образом вы например не увидите секретные креды в php-файле. Однако это ограничение можно обойти с помощью встроенного php-фильтра.
```
php://filter
```
Можно прочитать содержимое исполняемого файла закодиров его в base64, используя следующую полезную нагрузку:
```
vuln.php?page=php://filter/convert.base64-encode/resource=/etc/passwd
```


А можно и без кодирования в base64:
`?page=php://filter/resource=/etc/passwd`
Картинок тут не будет, так как таск слегка ломается, но иногда вообщем и так можно:)
Поэтому многое зависит от конфигурации!!!
## Выполнение команд ОС
С помощью LFI, как я показывал ранее, можно выполнять команды в ОС.
Для этого есть 2 полезные нагрузки:
```
php?page=expect://ls (модуль PHP expect не включен по умолчанию)
```
Если URL-адрес включает =on в конфигурацию php.ini, мы можем легко выполнять команды ОС и получать обратную оболочку по data://text/plain,
```
data://text/plain,<?php%20system($_GET[%27cmd%27])%20?>&cmd=whoami
```

## Обратная оболочка от LFI
Вообще, такое не приветствуется на стф:)
Но пару вещей скажу. Вообще есть 2 способа сделать обратную оболочку:
1) С помощью data://. Вы используете `data://text/plain, + php-код для обратного ревёрса` и netcat, чтобы включить порты для прослушивания `nc -lvp 1234`. Сначала второе делаете, а потом первое, и вот вы получили обратную оболочку!
2) Отравление логов. Тут советую ознакомиться с [ЭТИМ](https://effortlesssecurity.in/2021/08/01/lfi-rfi-from-basic-to-advance/) сайтом, тут всё подробно расписано!
---
# Как использовать RFI
:::warning
Используя **LFI**, злоумышленник может **получить** файлы с локального сервера, а также **выполнить** файлы локального сервера.
Используя **RFI**, злоумышленник может **запускать** файлы с удаленного сервера.
:::
Помимо того, что исполнять файлы можно локально, это также можно сделать и удалённо. Т.е. мы можем сделать зловредный скриптик где-нибудь на гитхабе и заставить сервер его исполнить!
## Чтение файлов и команды ОС
1) Создать txt или php файл со следующим содержимым: `<?php system($_GET['cmd']) ?>`
2) Загрузить этот файл с вашего источника, исполняя команды ОС через параметр cmd:




## Reverse shell из-под RFI
Опять-таки не буду вам тут показывать эти гадости, но быстро пройдусь по пунктам:
1) создать файл с расширением txt или php с reverse shell'ом в гит тот же
2) подтянуть этот файл как в примере выше
3) получить оболочку и огрести люлей
---
# Домашка(по желанию)
Ну чтож, вот топик и подошёл к концу, предлагаю вам выполнить следующую домашку, чтобы закрепить материал:
1) Прорешать [раздел Directory Traversal](https://portswigger.net/web-security/file-path-traversal) в PortSwigger'e, он там простой!
2) Сказать, что ещё можно сделать с LFI/RFI.
3) Как исправить LFI/RFI.
4) Какие есть ограничения и моменты, которые следует помнить?
И на этом всё, спасибо вам, что дочитали данный топик, надеюсь вам было интересно и понятно!
Если есть вопросы - пишите в тг @ArroizX
