pfSense Plus MIM API toolkit b4acd7ca — High — Удалённо — Остаточные привилегии — example-add-devices.py JSON в SSH
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · pfsense-api-enroll-json-ssh
Класс: Оставшиеся привилегии Достижимость: Удалённая
Набор инструментов pfSense Plus MIM API (b4acd7ca) - Netgate
example-add-devices.py — это документированный способ регистрации контроллера Nexus на каждом устройстве pfSense Plus по SSH. Он выполняет json.dumps для GET /mim/controller/identity, заменяет только ", затем дважды применяет .format к этому блобу, вставляя его в POSIX-скрипт с curl -d в двойных кавычках. Paramiko exec_command запускает скрипт от имени SSHUSER (в примере по умолчанию admin) на каждом адресе из pfsense_addresses.
json.dumps вместе с replace('"', '\\"') сохраняет кавычки закрытыми. $(), обратные кавычки и ${...} не являются метасимволами JSON. Они остаются активными внутри всё ещё открытой строки -d в двойных кавычках. OpenSSH exec — это оболочка. Вот в чём суть оставшейся уязвимости.
Это не сторонний REST-пакет CE. Это официальный клиент OpenAPI и примеры для контроллера pfSense Plus Nexus Multi-instance Management. Я не создавал Plus. Лаборатория — это зафиксированная интерполяция плюс макет /var/run/pfnet-controller.sock.
| ID | пока нет CVE |
| Класс | Оставшиеся привилегии (JSON контроллера в SSH-регистрацию) |
| Достижимость | Удалённая (на пути к CONTROLLER_URL, пока пример устанавливает verify_ssl=False, или записывающий в строковые поля ControllerSummary) |
| CWE | CWE-78 |
| CVSS | Высокий: 8.1 CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H |
| Продукт | Netgate/pfsense-api (набор инструментов Plus MIM) |
| Затронуто | публичная ветка main b4acd7ca21dbca739a530403a1f62a7440f7726f example-add-devices.py |
| Аутентификация | оператор запускает документированный пример. Атакующий находится на пути или может записывать строки summary. Вход в контроллер всё равно происходит первым. |
| Лицензия | GNU Affero GPL v3.0 |
| Лаборатория | только 127.0.0.1:19101. Без образа Plus. |
Часть 1 из серии об оставшихся уязвимостях Nexus MIM. Смежные материалы: enroll-autoadd, unix-sock-noauth, example-ssl-verify (G9 — это то, как узел на пути формирует этот JSON), fleet-jwt, export-key-get.
Оставшаяся уязвимость — это подстановка команд внутри всё ещё открытой строки -d в двойных кавычках. json.dumps вместе с проходом по кавычкам сохраняют строку закрытой. $(), обратные кавычки и ${...} выживают и выполняются от имени SSHUSER, когда OpenSSH выполняет exec для скрипта.
| Метод | Sink | Привилегия | Доказано в лаборатории или выведено |
|---|---|---|---|
Поместить $() (или обратные кавычки / ${...}) в строковое поле ControllerSummary, затем дать оператору запустить example-add-devices.py | controller_info.replace('"', '\\"') затем device_script.format(...) затем sshclient.exec_command(device_script) (example-add-devices.py ~104-161) | Shell от имени SSHUSER (в примере по умолчанию admin; SSH-доступ администратора pfSense обычно эквивалентен root) на каждом адресе в pfsense_addresses | Доказано в лаборатории на интерполяции: INJECT vpn_listenaddr=$(printf %s PFSENSE-API-ENROLL-JSON-SSH-WITNESS >/oracle/witness) пережил экранирование только кавычек (dollar-paren-survived=yes) и записал свидетельство (inject-oracle=yes). Сам Paramiko/SSH в этот compose не входит. |
TLS MITM для GET /api/mim/controller/identity, пока пример использует verify_ssl=False | Тот же разбор ControllerSummary, затем тот же скрипт | Тот же shell. Все поля ControllerSummary имеют тип str или Unset, поэтому достаточно MITM JSON-тела, которое проходит разбор типов. | Выведено из примера (example-add-devices.py login Client и AuthenticatedClient оба устанавливают verify_ssl=False). Лаборатория отправляет объект summary напрямую. Родственный: example-ssl-verify. |
Записать символы подстановки в name или vpn_listenaddr на контроллере, дождаться следующей регистрации | Тот же sink | Тот же shell, когда оператор в следующий раз запустит пример | Выведено. Требуется предварительная запись этих полей (уже controller-admin, или родственный unix-sock-noauth). |
Тот же shell, дополнительные ключи через ControllerSummary.additional_properties | Тот же дамп включает дополнительные MITM-ключи (to_dict копирует остатки после from_dict) | Дополнительные поля попадают в -d и в shell | Выведено из to_dict. Лаборатория внедряет только через vpn_listenaddr. |
| Метод | Sink | Привилегия | Доказано в лаборатории или выведено |
|---|---|---|---|
| Прочитать stdout рабочей станции регистрации | print("CONTROLLER_SUMMARY:", controller_info) | Идентичность контроллера key, Netgard vpn_pubkey / vpn_netkey / адреса прослушивания | Выведено из print в примере. Лаборатория не печатает blob живого контроллера. |
| Перехватить или MITM SSH exec-канал | Полезная нагрузка exec_command(device_script) — это curl -d JSON | Та же идентичность контроллера в трафике к каждому устройству | Выведено. AutoAddPolicy на этом канале — родственный отчёт. |
| Случай CONTROL на гаджете | POST /case name=control | Честный vpn_listenaddr доходит до unix-сокета без изменений | Доказано в лаборатории. 192.0.2.10:51820 отправлен как есть, без oracle (control-clean=yes). |
| Метод | Sink | Привилегия | Доказано в лаборатории или выведено |
|---|---|---|---|
Внедрённая команда от имени SSHUSER | Тот же exec_command | Остановить pfnet-controller, стереть регистрацию, перезагрузить или иным образом вывести устройство из MIM | Выведено как побочный эффект shell. Лаборатория только записывает файл-свидетельство. |
Требуется: официальный путь примера (регистрация оператором). UI:N для on-path пира, как только этот пример запущен. Вход в контроллер всё равно происходит первым.