
Signal-Server v20261007.0.0 - Высокий - Удалённый - Остаточные привилегии - unauth Dropwizard admin :8081
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · signal-server-dropwizard-admin
Класс: Оставшиеся привилегии Доступ: Удалённый
Signal-Server v20261007.0.0 (a15d5cd) — Signal Messenger, LLC
Dropwizard 5.0.2 DefaultServerFactory поставляет HTTP-коннектор администратора на порту 8081 с неустановленным bindHost (все интерфейсы) и без аутентификации администратора. Signal-Server это никогда не переопределяет. В service/config/sample.yml нет блока server:. YAML, в котором перечислены только TLS applicationConnectors, всё равно наследует открытый 8081 на 0.0.0.0. server вместе с тремя воркерами ServerCommand запускает его. ExternalRequestFilter находится только в контексте приложения.
Неаутентифицированный HTTP на :8081 — это операционная плоскость администратора. Не RCE. Не захват аккаунта. Не чтение запечатанных сообщений.
| ID | CVE пока нет |
| Класс | Оставшиеся привилегии (неаутентифицированный Dropwizard admin) |
| Доступ | Удалённый (все интерфейсы :8081, без аутентификации) |
| CWE | CWE-306, CWE-1188 |
| CVSS | High: 7.3 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L |
| Продукт | Signal-Server |
| Затронуто | v20261007.0.0 (a15d5cd) Dropwizard 5.0.2. Встроенный sample / отсутствующий adminConnectors. |
| Аутентификация | отсутствует на коннекторе администратора |
| Лицензия | GNU Affero GPL v3.0 |
| Лаборатория | только 127.0.0.1 |
Любой, кто может открыть TCP-соединение с портом администратора (по умолчанию 0.0.0.0:8081, без дополнительной конфигурации, без заголовка Authorization), получает все стандартные сервлеты администратора Dropwizard 5 плюс дополнительную задачу Signal. Это полный набор привилегий. Ничто в этом списке не является RCE, ATO или чтением тел запечатанных сообщений.
| Метод | Путь | Привилегия |
|---|---|---|
| GET | /ping | Подтвердить, что слушатель администратора работает. Тело — pong. |
| GET | /metrics | Прочитать полный реестр Codahale в формате JSON: heap и non-heap JVM, счётчики GC, количество потоков, метрики коннектора Jetty, датчики 4xx/5xx, таймеры. Используйте это для фингерпринтинга процесса, оценки нагрузки и наблюдения за эффектом последующих задач. |
| GET | /threads | Полный дамп потоков JVM: имя каждого потока, id, состояние и кадры стека. В лаборатории это показало dw-admin-* плюс кадры nio из java.base. На живом узле Signal тот же дамп может содержать имена классов, имена логгеров и любую строку, которая случайно оказалась в стеке (пути к файлам, имена хостов, toString аргументов в полёте). Это не дамп heap и не дамп очереди сообщений. |
| GET | /healthcheck | Запустить зарегистрированные проверки здоровья. Это дерево никогда не регистрирует дополнительные проверки, поэтому тело — это проверка взаимоблокировок по умолчанию (deadlocks.healthy). 200 против 500 говорит о том, считает ли JVM, что она во взаимоблокировке. |
| GET | /tasks | Список задач администратора. На этой версии: gc, log-level, set-request-logging-enabled. |
| Метод | Путь | Привилегия |
|---|---|---|
| POST | /tasks/log-level?logger=<name>&level=<LEVEL> | Установить любой логгер Logback в TRACE, DEBUG, INFO, WARN, ERROR или OFF. TRACE может заставить логгеры приложения выводить больше (включая значения, которые залогировал разработчик). OFF на логгере безопасности или доступа отключает его. Атакующий не получает поток логов по этому HTTP. Он меняет то, что процесс записывает на диск или в stdout. Оракул лаборатории: имя логгера SIGNAL-SERVER-DROPWIZARD-ADMIN-WITNESS в TRACE. |
| POST | /tasks/gc | Вызвать System.gc(). Ответ — Running GC... / Done!. Это stop-the-world толчок, а не смерть процесса. |
| POST | /tasks/set-request-logging-enabled?enabled=true | Задача только Signal, зарегистрированная в WhisperServerService.run. Включает фильтр журнала доступа к запросам (RequestLogManager). После этого HTTP на прикладной коннектор может записывать метод, URI и заголовки (включая Authorization Basic) в журнал доступа на диске. Клиент администратора не получает эти строки обратно. На воркерах message-persister-service / APN / idle-job у прикладного порта нет ресурсов Signal Jersey, поэтому эта задача важна на server. enabled=false снова отключает её. |
ProcessBuilder, ни Runtime.exec.GET /heapdump — 404.sample.yml или адресов привязки.Соседний контейнер в той же сети Docker достиг http://vuln:8081/ping (200 pong) и не смог достичь http://patched:8081/ping, когда bindHost был 127.0.0.1. Это и есть удалённая половина.
Я зафиксировал signalapp/Signal-Server v20261007.0.0. Восемнадцать поисков по исходникам. Чат, ключи, сообщения, резервные копии, пожертвования, звонки, MFA, gRPC-омнибус и исходящий HTTP вернулись пустыми на уровне Critical/High. Поиск по воркерам/администратору — нет. Dropwizard 5.0.2 HttpConnectorFactory.admin() по-прежнему использует порт 8081 и null bind host. Signal никогда не устанавливает adminConnectors. Администратор Caddy по умолчанию — localhost. Этот — нет.
Неверный поворот: попытка загрузить полный Signal-Server. sample.yml проходит check и всё равно требует FoundationDB, Dynamo, Redis и набор секретов для run. Оставшиеся привилегии — это коннектор фреймворка, который ServerCommand запускает до всего этого. Лаборатория — Dropwizard 5.0.2 с тем же пустым YAML server: и именем дополнительной задачи Signal.
cd lab
./run.sh
Loopback 127.0.0.1:19010. Проект Compose signal-server-dropwizard-admin. Свидетель SIGNAL-SERVER-DROPWIZARD-ADMIN-WITNESS. Gadget YAML не имеет блока server:. Негативный YAML устанавливает bindHost: 127.0.0.1. Последняя строка:
SUCCESS signal-server-dropwizard-admin how=unauth-admin-8081 ping=200 metrics=200 threads=200 healthcheck=200 tasks=200 log-level=TRACE gc=200 set-log=enabled bind=* remote-vuln=200 remote-patched=fail SIGNAL-SERVER-DROPWIZARD-ADMIN-WITNESS
Привяжите администратора к 127.0.0.1, установите adminConnectors: [] или добавьте аутентификацию / mTLS в контекст администратора. Не поставляйте YAML, в котором перечислены только прикладные коннекторы, и не предполагайте, что 8081 остался отключённым.