Пентест (docs/reviews/2026-09-27-pentest.md) и план 031 (Swagger, TLS) — план, не реализован.
032 Роль superadmin (без организации) и привязка admin/viewer к одной организации:
users.organization_id + CHECK, audit_log.organization_id (миграции 0010-0012);
require_org/scope_org во всех чтениях и записях, журнал и «Обзор» в границах
организации; пользователи, организации, типы устройств, настройки журнала — только superadmin.
033 Исправление находок ревью 032 (docs/reviews/2026-09-27-changes-032-review.md,
docs/reviews/2026-09-27-codebase-review.md):
- FK audit_log.organization_id ON DELETE SET NULL (миграция 0013) — удаление организаций;
- проверка организации в предпросмотре подсети;
- инвариант «роль — организация» по итоговому состоянию (повышение снимает организацию,
понижение требует её), 422/404 вместо обезличенных 409;
- одинаковый 404 для чужих и несуществующих объектов (VRF, устройство, parent_id, оператор);
- отказы удаления в журнале организации, счётчики типов в пределах организации;
- UI: живое поле «Организация» в диалоге пользователя, бейдж superadmin; род в текстах 404.
README актуализирован под ролевую модель.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
5.2 KiB
Пентест приложения (чёрный ящик) — 2026-09-27
Цель: 192.168.5.9:8088 (стенд ipam_control_006).
Условия игры: известны только адрес и порт. Задача — по уровням: (1) доступ к приложению с записью, (2) root в контейнере, (3) побег из контейнера.
Метод: внешняя разведка и проверка авторизации по чёрному ящику. Часть наступательных векторов (подделка JWT, SQL-инъекция, спуфинг X-Forwarded-For) заблокирована предохранителем среды как «ослабление защиты» и по факту не исполнялась; их оценка ниже — по знанию кода, без эксплуатации.
Результат по уровням
Уровень 1 — доступ с записью: НЕ получен. Уровни 2 и 3 — недостижимы: без плацдарма на уровне 1 разговора о root и побеге нет. Приложение не исполняет пользовательский ввод, не читает файлы по имени от клиента, не ходит по URL из запросов — готового foothold-вектора (RCE, upload, SSRF) нет.
Что проверено на живом стенде
| Вектор | Результат |
|---|---|
POST /organizations без токена |
401 |
GET /users без токена |
401 |
Типовые пароли admin (admin, admin123, password, 123456, changeme, change-me, ipam, ipam123, Admin123, root) |
401, после 5-й попытки — 429 (лимит «логин+IP», изменение 026) |
Заголовки ответа / |
CSP, X-Frame-Options: DENY, X-Content-Type-Options: nosniff, Referrer-Policy: no-referrer; сервер только uvicorn |
/healthz |
{"status":"ok"} |
/docs, /openapi.json |
Открыты анонимно — полная карта из 28 эндпоинтов выдаётся без авторизации |
Оценка заблокированных векторов (по коду, без эксплуатации)
- Подделка JWT — не проходит: секрет случайный (64 символа из
scripts/gen_env.py), старт с заглушкой/коротким ключом запрещён (изменение 017);alg=noneи пустой HMAC-ключ отклоняются PyJWT. - SQL-инъекция — исключена: запросы параметризованы (SQLAlchemy), поиск
LIKEэкранирует%и_(изменение 023). - Спуфинг
X-Forwarded-Forдля смены IP и обхода лимита — не работает: заголовок учитывается только отTRUSTED_PROXIES, список пуст (адрес берётся из сокета). - Брутфорс пароля — argon2 + три уровня лимитов (5 логин+IP, 20 IP, 50 логин со всех IP кроме известных).
- Эскалация в контейнере — даже с foothold-ом процесс работает от
uid 10001, не root (изменение 022): «root в контейнере» требовал бы отдельной local-priv-esc уязвимости базового образа.
Находки (для защиты)
| # | Серьёзность | Суть |
|---|---|---|
| 1 | Низкая–средняя | Swagger /docs, /redoc, /openapi.json открыты анонимно — карта всей поверхности API выдаётся без авторизации |
| 2 | Низкая–средняя | Приложение слушает 0.0.0.0:8088 по HTTP: токены и пароли идут по LAN открытым текстом; reverse-proxy + APP_BIND=127.0.0.1 из плана 022 на стенде не задействованы |
| 3 | Низкая (заметка) | Логин admin документирован как дефолт; лимит «логин со всех IP кроме известных» (50) допускает распределённый брутфорс с многих IP при слабом пароле/утечке хеша |
Находки 1 и 2 берутся в работу (план — отдельный документ). Находка 3 — организационная (смена дефолтного логина/пароля при развёртывании), отдельной доработкой не оформляется.
Вывод
Приложение по чёрному ящику устойчиво: авторизация, лимиты входа, экранирование, заголовки и непривилегированный контейнер держат периметр. Реальные улучшения — сузить раскрытие API (Swagger) и включить TLS/loopback-привязку в проде.