Moodle 5.2.3 — высокий — удалённый — IDOR — core_grades_get_gradeitems раскрывает скрытые элементы оценок
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · moodle-grades-gradeitems
Moodle LMS 5.2.3 - Moodle
Класс: IDOR Доступ: Удалённый
core_grades_get_gradeitems — это ajax плюс официальный мобильный сервис, без ключа capabilities в services.php. validate_context — единственная преграда. Затем grade_item::fetch_all выгружает все элементы курса. array_filter отбрасывает GRADE_TYPE_NONE, элементы категорий и элемент курса. Скрытые в этот фильтр не входят. Соседний core_grades_get_grade_tree уже требует moodle/grade:viewall.
Записанный на курс студент отправляет POST {courseid} и получает имена скрытых элементов оценок, которые интерфейс журнала оценок студента всё ещё скрывает.
| ID | CVE пока нет |
| CWE | CWE-862 / CWE-200 |
| CVSS | Средний: 4.3 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N |
| Продукт | Moodle |
| Затронуто | 5.2.3 тег v5.2.3 (344232c15336c71b80f9aca8359ce0e0a9f3d116) |
| Аутентификация | записанный студент (moodle/grade:view; без viewall / viewhidden) |
| Лицензия | GNU Affero GPL v3.0 |
| Лаборатория | только 127.0.0.1 |
Роль: записанный на курс студент. Он отправляет POST в AJAX-сервис с {courseid}. Ответ содержит имена, ID и категории. В схеме ответа нет оценок. Это не RCE. Не LPE. Не запись оценок.
| Привилегия | Метод / точка сброса | Разведка / целостность / доступность | Доказано в лаборатории или предположено |
|---|---|---|---|
| Чтение имени, id и категории скрытого элемента оценок | POST /lib/ajax/service.php?sesskey= core_grades_get_gradeitems {courseid} | Разведка | Доказано в лаборатории. HTTP 200, имена включают MOODLE-GRADES-GRADEITEMS-WITNESS |
| Чтение имени, id и категории видимого элемента оценок | Тот же ответ | Разведка (предназначено для преподавателей) | Доказано в лаборатории. имена включают Visible Lab Assignment |
| Тот же каталог через официальный мобильный сервис | Тот же класс, services включает MOODLE_OFFICIAL_MOBILE_SERVICE | Разведка | Предположено из services.php. В лаборатории использовался AJAX. |
Перебор последовательных значений courseid для курсов, куда студент может войти | Тот же метод, угаданные id | Разведка | Предположено. В лаборатории использовался предустановленный id курса 2 |
| Просмотр скрытого элемента в интерфейсе журнала оценок студента | GET /grade/report/user/index.php?id= | н/д | Доказано в лаборатории закрыто. hidden-in-ui=False, visible-in-ui=True |
| Вызов без сессии | AJAX с фиктивным sesskey | н/д | Доказано в лаборатории закрыто. servicerequireslogin |
| Вызов от имени вошедшего пользователя, не записанного на курс | AJAX постороннего, тот же courseid | н/д | Доказано в лаборатории закрыто. requireloginerror |
| Чтение оценок других студентов или запись оценок | н/д | н/д | Закрыто. Ключи ответа — id, itemname, category |
| PHP RCE / OS LPE | н/д | н/д | Закрыто. Этот остаток — чтение каталога |
Преподаватель или менеджер, у которого уже есть moodle/grade:viewall, и так видит каталог. Гостям / неаутентифицированным вызывающим всё ещё нужен контекст курса.
Другие остатки того же пина: Blackboard img file read, enrol_database SQLi, grades feedback IDOR.
Я зафиксировал moodle/moodle v5.2.3 после MSA-26-0042/0043. Веб-сервисы оценок попали в это окно MSA. В get_gradeitems.php по-прежнему нет require_capability. Интерфейс студента уже скрывал элемент. AJAX-каталог — нет.
Уже зафиксированные ошибочные пути: трактовка неаутентифицированного AJAX 200 как утечки (тело — servicerequireslogin); называть это IDOR оценок из-за слова grade в имени метода (схема содержит только имена); ожидание, что get_grade_tree — тот же остаток (он уже требует viewall). Обратная оболочка. Театр.
Живой Moodle v5.2.3 на php:8.3-apache + MariaDB 11.4. Сид записывает labstudent, оставляет laboutsider вне курса и создаёт видимый ручной элемент плюс скрытый элемент, имя которого является свидетелем. run.sh копирует локальный пин или git clone --depth 1 --branch v5.2.3. Дерево Moodle не входит в этот пакет.
python3 moodle-grades-gradeitems-Abraxas-Labs.py
или
cd lab
./run.sh
Цель только http://127.0.0.1:19590. Compose-проект moodle-grades-gradeitems. Стек разбирается после запуска.
SUCCESS moodle-grades-gradeitems student-ajax=200 hidden-in-ajax=yes hidden-in-ui=no visible-in-ajax=yes visible-in-ui=yes outsider-error=yes unauth-error=yes MOODLE-GRADES-GRADEITEMS-WITNESS
После validate_context требовать ту же возможность, что и get_grade_tree: require_capability('moodle/grade:viewall', $context). Также отбрасывать скрытые элементы, если у вызывающего нет moodle/grade:viewhidden. Добавить случай Behat/PHPUnit: записанный студент, скрытый ручной элемент, core_grades_get_gradeitems должен опускать этот элемент (или 403). Интерфейс журнала оценок студента уже его скрывает.
get_gradeitems.phpget_grade_tree.phpservices.php (core_grades_get_gradeitems, без capabilities)GNU Affero GPL v3.0. См. LICENSE. Только лаборатория на loopback. Без гарантий.