
phpMyAdmin 5.2.3 — высокий — удалённый — SQLi — ImportLdi TERMINATED BY leftover
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · phpmyadmin-importldi
Класс: SQLi Доступ: Удалённый
phpMyAdmin 5.2.3 (RELEASE_5_2_3 / 962857e) - phpMyAdmin
ImportLdi.php собирает LOAD DATA с FIELDS/LINES TERMINATED BY из POST-параметров ldi_terminated и ldi_new_line. Эти две строки конкатенируются в SQL внутри одинарных кавычек. ldi_enclosed и ldi_escaped проходят через escapeString. phpMyAdmin устанавливает PMA_ENABLE_LDI на /import, поэтому MYSQLI_OPT_LOCAL_INFILE включён.
Аутентифицированный пользователь отправляет POST format=ldi с кавычкой в ldi_terminated. Сформированный LOAD DATA содержит сырой POST внутри TERMINATED BY. SQL-инъекция в пользовательское соединение, а не в control user.
| ID | CVE пока нет |
| Класс | SQLi |
| Доступ | Удалённый (аутентификация через cookie; импорт таблицы, формат ldi) |
| CWE | CWE-89 |
| CVSS | Средний: 6.5 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N |
| Продукт | phpMyAdmin |
| Затронуто | 5.2.3 тег RELEASE_5_2_3 (962857e4f63d42e38f11ff4d63f5e722018add76) |
| Аутентификация | аутентификация через cookie. Импорт таблицы, формат ldi |
| Лицензия | GNU Affero GPL v3.0 |
| Лаборатория | только 127.0.0.1 |
Аутентифицированный пользователь phpMyAdmin, имеющий доступ к импорту таблиц, может внедрить SQL в LOAD DATA ... TERMINATED BY в своём соединении с MySQL.
| Привилегия | Метод / точка внедрения | Разведка / целостность / доступность | Доказано в лаборатории или предположено |
|---|---|---|---|
Разрыв литерала FIELDS TERMINATED BY | POST index.php?route=/import format=ldi ldi_terminated с кавычкой | Целостность формируемого PMA запроса | Доказано в лаборатории. HTML SQL-бокс: TERMINATED BY '',PMA-IMPORTLDI-WITNESS' |
Сохранение ENCLOSED BY в исходном виде | Тот же POST, кавычка в ldi_enclosed | Отрицательный контроль | Доказано в лаборатории. ENCLOSED BY экранируется |
| Дополнительный SQL в пользовательском соединении (INTO OUTFILE / stacked, если разрешено) | Та же точка внедрения после закрытия строки | Целостность пользовательского соединения | Предположено. Лаборатория останавливается на сломанном разделителе. По умолчанию mysqli::query выполняет один запрос |
| Чтение/запись файлов на стороне MySQL | Тот же LOAD DATA, если у учётной записи есть FILE или LOCAL INFILE к веб-серверу | Целостность файлов, доступных mysqld | Предположено. Здесь не предоставлено. Не заявлено |
Закрыто в этой лаборатории: неаутентифицированный доступ, control user / pmadb, OS include LFI и чтение/запись через FILE. У аутентифицированного пользователя уже есть SQL-бокс; этот остаток — неэкранированный разделитель внутри запроса, который PMA формирует для него.
Тот же пин: WebAuthn CustomServer leftover.
Я зафиксировал phpMyAdmin RELEASE_5_2_3. Плагины импорта, которые вручную собирают LOAD DATA, — это аудит кавычек. Два из четырёх полей-разделителей экранировались. Два — нет:
$sql .= ' FIELDS TERMINATED BY \'' . $ldi_terminated . '\'';
...
$sql .= ' LINES TERMINATED BY \'' . $ldi_new_line . '\'';
ldi_enclosed / ldi_escaped вызывают $dbi->escapeString. Common.php устанавливает PMA_ENABLE_LDI на /import + format=ldi. Маршруты GET|POST /import и GET|POST /table/import.
Уже зафиксированные ошибочные пути: заявление об LFI без разрешения FILE; рассмотрение SQL-бокса как находки (остаток — это неэкранированный разделитель, который конкатенирует PMA); заявление о control user / pmadb; reverse shell. Театр.
python3 phpmyadmin-importldi-Abraxas-Labs.py
# or: cd lab && ./run.sh
Цель только http://127.0.0.1:19290. Образы phpmyadmin:5.2.3 и mysql:8.0. Compose-проект phpmyadmin-importldi. Стек удаляется после запуска.
Вход через cookie. POST /import с format=ldi и кавычкой в ldi_terminated. Сформированный LOAD DATA LOCAL INFILE ... INTO TABLE \ldi_target` FIELDS TERMINATED BY '',PMA-IMPORTLDI-WITNESS'. Та же кавычка в ldi_enclosedсохраняется как экранированныйENCLOSED BY. Исходный код на образе 5.2.3 всё ещё содержит '.$ldi_terminated.'и$dbi->escapeString($ldi_enclosed)`.
SUCCESS phpmyadmin-importldi pin=RELEASE_5_2_3 how=live TERMINATED-BY-raw ENCLOSED-escaped PMA-IMPORTLDI-WITNESS
escapeString для ldi_terminated и ldi_new_line, так же как для enclosed и escaped. Приведение к int для skip_queries.
962857e4f63d42e38f11ff4d63f5e722018add76)libraries/classes/Plugins/Import/ImportLdi.phpGNU Affero GPL v3.0. См. LICENSE. Только loopback-лаборатория. Без гарантий.