Перейти к содержанию

Что такое Umbryx

Note

Umbryx разрабатывается с использованием AI-инструментов. Каждый релиз проходит автоматизированный тестовый прогон и проверку безопасности.

Не приложение для заметок. Платформа, где разведка, операции, доказательства и отчётность живут в одном пространстве — и питают друг друга.


Какую проблему решает

Типичный engagement размазан по дюжине инструментов и трём открытым терминалам. Результаты сканов живут в текстовых файлах. Креды — в таблице. Сетевая диаграмма — в отдельной вкладке draw.io. Findings — в Word-документе, который обновляется в конце.

Umbryx собирает всё состояние engagement в одном месте:

  • Операции выполняются из платформы, а не просто логируются в неё
  • Результаты обновляют состояние — скан создаёт хосты, валидация учётных данных отмечает рёбра доступа, найденные хэши попадают в loot
  • Граф отражает то, что вы знаете прямо сейчас, а не статичную диаграмму, нарисованную один раз
  • Отчётность собирается из реальных данных, а не из памяти

Текущее состояние

Активно развивается — см. Планируемые функции. Недавний фокус:

  • Пул workstation (EE) — подготовка атакующих машин заранее через провайдеров Platform Ops (Hetzner, Proxmox, Docker, Kubernetes, чистый SSH), привязка их к пользователям через профильные SSH-ключи с полным журналом grant/revoke
  • Platform Ops (EE) — infrastructure-as-catalog: стеки C2+redirector, фишинг-киты и pivot-цепочки развёртываются с автоматическим конвейером после развёртывания (файрвол, discovery, DNS, учётные данные, VPN)
  • Постоянная работа по усилению безопасности: контроль ROE/scope, тайминги аутентификации и границы админской авторизации

Основные возможности

Оркестрация

Запускайте инструменты через платформу. Каждая операция — Job со статусом, выводом и структурированным результатом, который возвращается в состояние проекта.

Сканы nmap, nuclei, httpx, ffuf — через атакующий SSH или глобальный connector
Массовые операции Исполнение на динамических коллекциях хостов: все Windows, все с валидным SMB-учётной записью, все в подсети
Валидация учётных данных SMB, WinRM, SSH, LDAP, MSSQL, RDP — результаты создают рёбра доступа и кандидатов в findings
Рабочие процессы AD SPN enum, ASREP, delegation, ADCS, BloodHound collect, domain enum
C2-интеграции Adaptix, Mythic, Sliver — получение сессий/колбэков и учётных данных, исполнение команд из панели действий над хостом или как шаг плейбука
Плейбуки Упорядоченные последовательности операций с live-поллингом шагов и выделенным шагом c2:exec
Отмена Запущенные задания можно убить — останавливается subprocess, а не только запись в БД

Отслеживание состояния

Операции меняют проект. Автоматически.

  • nmap-скан → хосты создаются/обновляются с портами и ОС
  • Валидация учётных данных → рёбра доступа в графе, статус хоста обновляется
  • Вывод задания → NTLM-хэши, Kerberos-тикеты, секреты авто-извлекаются в Loot
  • Структурированные результаты заданий → кандидаты в findings, передаваемые аналитику на ревью

Аналитика

Всё, что команде нужно знать об engagement, в одном месте.

  • Hosts — инвентарь со статусом (up / access / pwned), ролями, портами, сервисами, тегами, связанными учётными данными; панель деталей со вкладками (Details · Activity · Creds · Path)
  • Credentials — plaintext, NTLM, Kerberos-тикеты; доменные/локальные; состояние крэка; привязка к хостам
  • Findings — критичность, CVE/CVSS, proof, рекомендации, MITRE ID, статус рабочего процесса
  • Notes — Markdown с вложениями, фазами, тегами, живой коллаборацией
  • Knowledge Base — Markdown-статьи (глобальные или проектные) с полнотекстовым поиском
  • Attack Path — упорядоченные шаги эскалации с полями MITRE-техник; привязка шагов к реальным хостам
  • Scope — записи CIDR/домен/hostname с шлюзом, флагом entry-point и pivot-хостом «reachable via»

Визуализация

Два графа, показывающих разные ракурсы одного и того же состояния engagement.

Network Map — топологический канвас с VLAN-регионами, режимами оверлеев (Threats · Sessions · Access · Roles · Pivots), drag-and-drop-раскладкой, инспектором хостов с таймлайном активности. Рёбра entry uplink показываются оранжевым. Подсети, доступные только через pivot-хост, показывают ⇄ via [host] на регионе.

Attack Graph — интерактивный канвас, где хосты соединены путями по учётным данным, рёбрами доступа, pivot-маршрутами и цепочками повышения привилегий. Бейджи узлов для статуса DA/DC и дистанции достижимости. Боковая панель показывает путь привилегий и pivot-маршруты выбранного хоста.

C2-фреймворки

Umbryx интегрируется с тремя операторскими C2-фреймворками. Все три предоставляют одинаковый набор возможностей (синхронизация ✓ живые агенты ✓ исполнение ✓ история задач ✓), поэтому панель действий над хостом и шаг плейбука c2:exec работают одинаково независимо от того, в каком фреймворке живёт сессия.

Фреймворк Транспорт Аутентификация Примечания
Adaptix REST поверх HTTPS username + password (или токен) Тянет хосты, агентов, учётные данные и каталог BOF; поддерживает исполнение сырой командной строки
Mythic GraphQL (Hasura) заголовок apitoken или username/password → JWT Тянет колбэки + учётные данные; мутация createTask для исполнения с опциональным префиксом !command args для указания команды Mythic, отличной от стандартной
Sliver Нативный gRPC через sliver-py operator config JSON (вставьте файл, созданный sliver-server operator --save) Сессии + биконы; интерактивный interact_session.execute для сессий, асинхронные задачи биконов для биконов

Сессии появляются в панели действий над хостами, чей IP совпадает с RemoteAddress агента; оттуда оператор может либо выполнить разовую команду, либо поставить в очередь многошаговый плейбук против агента.

Пивоты

  • Ручное создание пивотов из тулбара Network Map (инструмент, тип, route CIDR, статус)
  • Автосбор из chisel / ligolo / Adaptix через SSH-коллектор
  • Рёбра pivot-маршрутов: все хосты в route CIDR связываются с pivot-узлом на Attack Graph
  • via_host_id в scope: пометьте подсеть как доступную только через конкретную машину — Smart Build добавит рёбра маршрутов, а регион покажет pivot-аннотацию

Platform Ops (инфраструктура)

Проектируйте, разворачивайте и управляйте атакующей инфраструктурой из каталога вместо ручного сочинения docker-compose-файлов на каждый engagement.

  • Templates — предсобранные стеки (C2 + Redirector, C2 + Redirector + DNS, C2 Cluster, Phishing Kit, Pivot Chain) и конструктор с чистого канваса
  • Stacks — развёрнутый шаблон становится InfraStack: сервисы создаются средствами provisioning, затем запускается конвейер автоинтеграции — правила файрвола, discovery сервисов, сшивка nginx/Cloudflare-линков, генерация учётных данных, WireGuard VPN и DNS-записи — каждый шаг отслеживается per-service со статусом
  • Nodes / Providers — регистрация вычислительных ресурсов, на которые разворачивается стек (Hetzner, Proxmox, Docker-хосты, Kubernetes, чистый SSH)
  • DevOps-лог — централизованный, фильтруемый журнал каждой инфраструктурной операции, независимый от отдельного стека

Workstation

Атакующие десктопы как управляемый ресурс вместо общего jump-хоста.

  • Workstation на проект — поднимите контейнер Kali/Parrot/BlackArch/Ubuntu (или облачную VM), скоупированный на один engagement, из шаблона или кастомного образа
  • Пул workstation — подготовьте общий пул машин заранее через тех же инфраструктурных провайдеров, храните SSH public key пользователей в их профиле и выдавайте/отзывайте доступ per-user (добавляет/удаляет помеченную строку в authorized_keys по SSH) — каждый grant, revoke и шаг provisioning зеркалируется в таймлайн проекта и журнал аудита
  • Поддержка hetzner, proxmox, Docker, Kubernetes и зарегистрированных вручную SSH-хостов как нижележащего субстрата

Конвейер доказательств

  • Loot: файлы, хэши, секреты, конфиги — загрузка/скачивание с авторизацией, привязка к хосту + заданию + учётной записи
  • Автоизвлечение из вывода заданий: NTLM-хэши, Kerberos-тикеты, секреты, ссылки на файлы
  • sha256 на каждую загрузку; классификация типа артефакта

Отчётность

Executive summary собирается из реальных данных проекта: скомпрометированные хосты, крэкнутые учётные данные, критичные findings, таймлайн активности операторов, нарратив пути атаки.


Скриншоты

Network Map — топологический канвас с VLAN-регионами и режимами оверлеев

Network Map

Attack Graph — пути привилегий, pivot-маршруты, бейджи узлов DA/DC

Attack Graph

Hosts — панель со вкладками: Details · Activity · Creds · Path

Hosts

Credentials

Credentials

Findings

Findings

Notes (Markdown)

Notes

Loot

Loot

Knowledge Base

Knowledge Base

Scope — с полями gateway, entry-point и pivot-хоста

Scope

Attack Path

Attack Path

Jobs

Jobs

Report

Report

Timeline

Timeline

Scans

Scans

Playbooks

Playbooks

Automations

Automations

Commands (шпаргалка)

Commands

Platform Ops — каталог инфраструктуры и стеки

Platform Ops

Workstations

Workstations

ROE (Rules of Engagement)

ROE

Checklist

Checklist

Objectives

Objectives


Операционный цикл

Reconnaissance  →  Collections  →  Operations  →  Results
     ↑                                               ↓
  Report    ←    Intelligence   ←   Graph State  ←──┘

Каждый слой питает следующий. Данные не вводятся дважды.


Развёртывание

Important

Umbryx спроектирован для внутренних доверенных сетей — VPN, air-gapped-лаборатория, jump host. Здесь нет харденинга под публичный интернет (вход ограничен по IP — 5 попыток в минуту, — но WAF и капчи нет). Не выставляйте его напрямую в интернет. Если нужен удалённый доступ — поставьте за VPN или reverse proxy с mTLS.

Быстрая установка (TUI)

./install.sh

Интерактивный мастер с text-UI (whiptail, с запасным текстовым режимом, если недоступен) генерирует секреты, пишет .env/.env.ha и поднимает стек за вас — без ручного редактирования. Покрывает оба режима развёртывания:

  • All-in-one — один хост, всё в одном docker compose up.
  • Multi-node HA — проводит через точную последовательность из HA-развёртывания (монитор pg_auto_failover, создание ролей БД, HAProxy/keepalived VIP, Redis Sentinel) на seed-узле: подключение второго узла и направление слоя приложения на кластерный VIP. Регистрация pg_auto_failover — одноразовое рукопожатие — читайте подтверждения перед продолжением на живом кластере.

Запустите сначала ./install.sh --dry-run, чтобы увидеть точно, что он сделает, ничего не меняя. Ручные шаги ниже по-прежнему здесь — для тех, кто хочет понять или кастомизировать действия инсталлятора.

Предварительные требования

  • Docker ≥ 24.0 с плагином compose (docker compose version должен работать)
  • Linux-хост с минимум 2 GB RAM и 5 GB свободного диска под базу данных + loot-артефакты
  • OpenSSL для генерации секретов (openssl version)
  • Опционально: отдельная атакующая машина, доступная по SSH, если вы хотите запускать сканы (nmap, nuclei, netexec, donpapi) — платформа не поставляет эти инструменты сама

1. Получите проект

Репозиторий Community Edition (Core) публично доступен на GitHub:

git clone https://github.com/Umbryx-Project/umbryx-core.git
cd umbryx-core

Образы Enterprise Edition распространяются отдельно по лицензии — см. установку EE.

2. Сгенерируйте секреты

Два значения должны быть заданы перед любым не-одноразовым развёртыванием:

# JWT signing key — sessions are issued and verified with this
openssl rand -hex 32

# Encryption key — Fernet key used to encrypt credentials, sensitive notes, loot text
python3 -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"

Сохраните оба — вы вставите их в .env на следующем шаге. Потеря ENCRYPTION_KEY после первого старта делает существующие зашифрованные данные навсегда нечитаемыми. Создайте резервную копию до перехода в промышленную эксплуатацию.

3. Настройте .env

cp .env.example .env

Откройте .env в редакторе и заполните все значения с change_me:

# Database
DB_USER=umbryx
DB_PASSWORD=<a-strong-password>
DB_NAME=umbryx

# Secrets — paste the generated values from step 2
JWT_SECRET=<openssl rand -hex 32 #1>
ENCRYPTION_KEY=<python3 Fernet.generate_key() #2>

# Initial admin account — auto-created on first start if no users exist
ADMIN_USERNAME=admin
ADMIN_PASSWORD=<a-strong-password>

# Host port — change if 3000 conflicts with something else
PORT=3000

# Cookie security — set true ONLY when serving over HTTPS
COOKIE_SECURE=false

Файл .env подхватывается docker compose автоматически. Никогда не коммитьте его — .gitignore уже исключает его.

4. (Опционально) Настройте пул воркеров

Задания из очереди (nmap, nuclei, donpapi) привязаны к SSH — большую часть времени они ждут сетевой I/O, а не CPU. Значения по умолчанию консервативны:

WORKER_POOL_MAX_WORKERS=8        # total parallel jobs across all projects
WORKER_POOL_MAX_PER_PROJECT=3    # max concurrent jobs for one project

Поднимите значения, если ваша атакующая машина выдержит больше параллельных сканов, не упираясь в рейт-лимиты целей.

5. Сборка и запуск

docker compose up -d --build

Первая загрузка занимает 1–3 минуты (инициализация Postgres, сборка фронта, alembic-миграции). Последующие рестарты — секунды.

6. Проверка

# Core services should be Up; db/redis/backend/frontend should report healthy
docker compose ps

# Published health probe through nginx (should return 200)
curl -i http://localhost:${PORT:-3000}/health

# Tail logs in case something failed
docker compose logs backend --tail=30
docker compose logs frontend --tail=10

Откройте http://localhost:${PORT} и войдите с админскими учётными данными из .env.

7. Первичная настройка внутри приложения

  1. Создайте проект — левый сайдбар → New project
  2. Настройте атакующую цель (Infra → Connections) — вставьте SSH-хост, порт и учётные данные, которые платформа будет использовать для запуска сканов. Это единственный способ, которым сканы реально выполняются.
  3. Пригласите членов команды (Admin → Users) — создайте обычные аккаунты user, затем добавьте их в проекты с проектными ролями — 11 ролей от owner до auditor
  4. Опционально: добавьте C2-интеграции (Admin → Modules) — Adaptix, Mythic, Sliver

Обновление

git pull
docker compose up -d --build

Alembic-миграции запускаются автоматически при старте бэкенда. Всегда создавайте резервную копию тома с данными PostgreSQL и data/uploads/ перед обновлением через мажорную версию.

# Quick backup
tar -czf umbryx-backup-$(date +%Y%m%d).tar.gz data/ .env

Important

При пересборке образа автосгенерированный JWT-секрет сохраняется: он записывается в /data/.jwt_secret (см. Security overview). Регенерируется он, только если каталог данных потерян или был недоступен для записи — это завершает сеансы всех пользователей и ломает API-токены. Задавайте JWT_SECRET явно в .env, чтобы сеансы не зависели от каталога данных.


Заметки по обновлению

Политика версионирования

Umbryx использует версионирование по мотивам semver (MAJOR.MINOR.PATCH) с одним явным послаблением: patch-релизы могут включать Alembic-миграции, если те являются аддитивными (новые колонки, новые индексы, новые таблицы). Это соответствует реальному ритму внутреннего red-team-инструмента, где добавление колонок сопровождает патчи возможностей.

Исключение, которое нужно проговорить: любая миграция, которая удаляет строки, дропает колонки или необратимо трансформирует данные, считается data-breaking-патчем. Такие релизы помечаются ⚠ DATA. Создавайте резервную копию перед обновлением до релиза с меткой ⚠ DATA.

Что означает каждая метка

Метка Тип миграции Можно пропустить резервное копирование?
(нет) Только аддитивное (новые колонки/индексы, значения по умолчанию) Рискованно, но обычно восстановимо
⚠ DATA Удаляет или трансформирует существующие строки Нет — сначала резервная копия

Data-breaking-релизы на текущий момент

Версия Что меняется Миграция
v0.4.8 ⚠ DATA Авто-дедупликация строк creds с идентичными (pid, username, domain, host) — дубликаты удаляются навсегда 006_data_stability_unique

Откат

Автоматического отката нет. Если миграция упала или дала неожиданные результаты, восстановитесь из резервной копии:

# Stop everything
docker compose down

# Restore DB and uploads from backup
tar -xzf umbryx-backup-YYYYMMDD.tar.gz

# Restart (runs migrations from current state)
docker compose up -d --build

Откат отдельных миграций (продвинутое):

# Identify the target revision
docker compose exec backend alembic history

# Downgrade one step
docker compose exec backend alembic downgrade -1

Примечание: downgrade() в каждой миграции восстанавливает схему (дропает добавленные колонки), но не восстанавливает удалённые строки. Для релизов ⚠ DATA даунгрейд требует восстановления из резервной копии БД.


Устранение неполадок

Симптом Причина Решение
502 Bad Gateway от nginx после пересборки бэкенда nginx закэшировал старый IP контейнера бэкенда docker compose restart nginx
auth: 401 на каждый запрос JWT_SECRET изменился между рестартами Задайте JWT_SECRET явно в .env, разверните заново
Ошибки Cannot read encrypted value ENCRYPTION_KEY изменился после записи данных Восстановитесь из резервной копии; зашифрованные колонки не восстановить без оригинального ключа
Фронт грузится, но данных нет WebSocket блокируется промежуточным прокси Добавьте proxy_http_version 1.1 + заголовки Upgrade/Connection на вашем reverse proxy
Сканы в очереди навсегда Не настроена цель attacker_ssh Infra → Connections → добавить SSH executor-цель
Ошибка alembic-миграции при старте Схема БД новее кода (даунгрейд) Восстановите резервную копию БД или выполните alembic stamp <revision> вручную
Бэкенд падает с Permission denied при записи в /data Автофикс владельца из entrypoint не поможет, если режим ./data (не только владелец) блокирует запись — например, он на noexec/read-only-маунте или был создан chmod 000 Проверьте сам хостовый маунт: stat ./data; это должна быть обычная записываемая директория. Несовпадение владельца обрабатывается автоматически — это проблема уровня маунта, а не UID

Переменные окружения

Полный справочник. У всех разумные значения по умолчанию; только секреты и пароль админа обязаны быть заданы до промышленной эксплуатации.

Переменная По умолчанию Обязательна? Описание
JWT_SECRET auto-generated Да для промышленной эксплуатации Ключ подписи JWT. Генерируйте через openssl rand -hex 32. Если не задан, бэкенд авто-генерирует и персистит в /data/.jwt_secret — ок для локальной разработки, не для промышленной эксплуатации.
ENCRYPTION_KEY генерируется в /data/secret.key, если не задан в dev Да для промышленной эксплуатации Fernet-ключ для шифрования учётных данных, чувствительных заметок, значений loot и шифрованных loot-файлов. Генерируйте через python3 -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())". Храните резервную копию — потеря делает зашифрованные данные навсегда нечитаемыми.
DB_USER umbryx Нет Пользователь PostgreSQL
DB_PASSWORD change_me_strong_password Да Пароль PostgreSQL — смените перед любой не-одноразовой установкой
DB_NAME umbryx Нет Имя базы PostgreSQL
ADMIN_USERNAME admin Нет Имя изначального админа (используется только при первой загрузке, когда пользователей нет)
ADMIN_PASSWORD auto-generated Да для промышленной эксплуатации Пароль изначального админа. Если не задан, бэкенд печатает сгенерированный в свой лог при первой загрузке.
PORT 3000 Нет Хостовый порт, публикуемый nginx
COOKIE_SECURE false Нет Задайте true при работе по HTTPS, чтобы сессионные куки получали флаг Secure
CORS_ORIGINS (пусто) Нет Разрешённые origins через запятую. Пусто = только same-origin
WEBHOOK_HMAC_SECRET (пусто) Нет Если задан, каждый webhook-запрос обязан включать X-Hub-Signature-256: sha256=<hmac>
WORKER_POOL_MAX_WORKERS 8 Нет Общее число параллельных слотов заданий по всем проектам
WORKER_POOL_MAX_PER_PROJECT 3 Нет Максимум одновременных заданий для одного проекта (не даёт одному проекту морить остальных голодом)
PUBLIC_BASE_URL выводится из запроса Рекомендуется для промышленной эксплуатации Используется для построения OIDC/SSO redirect_uri на стороне сервера (например, https://umbryx.example.com) — см. ACCESS_CONTROL.md. Запасной вариант — host самого входящего запроса, что нормально за хорошо настроенным reverse proxy, но не должно оставаться на спуфяемом заголовке Host при промышленной эксплуатации.
DB_HOST / DB_PORT / DB_SSLMODE db / 5432 / prefer Нет Направьте приложение на внешний Postgres вместо встроенного сервиса db — например, VIP кластера multi-node HA. См. «Multi-node HA» ниже.
REDIS_SENTINEL_HOSTS / REDIS_SENTINEL_MASTER / REDIS_SENTINEL_PASSWORD (пусто) Нет Направьте Redis-доступ на кворум Sentinel вместо одиночного экземпляра Redis, заданного REDIS_URL — приоритетнее REDIS_URL, когда задано.

Multi-node HA

Этот docker-compose.yml — одноузловой: одна db, один redis, и хватит. Для автоматического failover на 2+ хостах (Postgres через pg_auto_failover, Redis через Sentinel, плавающий VIP, без ручного вмешательства при потере узла) см. docker-compose.ha.yml и HA-развёртывание — отдельный compose-файл для инфраструктурного слоя, запускаемый рядом с этим. Проверено вживую: убили первичный Postgres-узел под реальным трафиком — ноль зависших запросов, ~41 с до полного автоматического восстановления, все данные (включая зашифрованные секреты учётных данных) целы на любом из узлов после этого.


Архитектура

nginx ──► frontend   (React + Vite, static build)
     ──► backend    (FastAPI + SQLAlchemy + asyncio worker pool)
                └──► PostgreSQL 16
  • Аутентификация: JWT bearer-токены плюс проектный RBAC (11 проектных ролей от owner до auditor) и глобальные админ-контролы
  • Realtime: WebSocket на проект — presence и live-синхронизация сущностей
  • Воркеры: по умолчанию ограниченный внутренний async-пул воркеров, опционально Redis/arq-бэкенд для исполнения через очередь, настоящая отмена через cancellation token + kill subprocess
  • Хранилище: загруженные файлы в data/uploads/, данные PostgreSQL в Docker-волюме pgdata. Контейнер бэкенда стартует под root, чинит владельца /data (и, в продовом compose-файле, его отдельные волюмы uploads/plugins) под app-пользователя, затем дропает привилегии через setpriv перед запуском приложения — см. backend/scripts/docker-entrypoint.sh. Это выполняется на каждом старте, но реально chown делает только при неверном владельце, так что волюм с корректным владельцем обходится одним вызовом stat, а не обходом содержимого. Ни ручного docker exec ... chown на первом старте, ни после рестарта не требуется.
  • Исполнение: атакующий SSH-connector или глобальная цель; SSH-команды запускаются через Popen с потоком-наблюдателем отмены

Безопасность

  • Смените JWT_SECRET и DB_PASSWORD перед любым не-локальным развёртыванием
  • Спроектировано для внутренних доверенных сетей — публичный интернет не предполагается
  • Все скачивания файлов требуют валидный auth-токен (?token= или заголовок Authorization)
  • Креды шифруются at rest
  • Конфиденциальное содержимое заметок шифруется at rest, когда заметка несёт теги вроде confidential, secret, sensitive, opsec или restricted
  • Чувствительные текстовые значения loot шифруются at rest для не-файловых артефактов
  • События read-аудита записываются, когда пользователи просматривают секреты учётных данных, конфиденциальные заметки, чувствительный loot или скачивают защищённые файлы