Moodle 5.2.3 — высокий — удалённый — IDOR — core_grades_get_gradeitems раскрывает скрытые элементы оценок
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · moodle-grades-gradeitems
Разбор: https://abraxaslabs.tech/research/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. Без гарантий.