📝 Adequate

Реагування на інциденти безпеки

Систематичний процес — від виявлення інциденту до post-mortem та покращень. Написано під інфраструктуру UMTC (WireGuard-only доступ, Matrix для комунікації, Docker для сервісів).

💡 Золоте правило
**Не поспішай і не панікуй.** Поспішне рішення знищує докази. Перше що треба — ЗАФІКСУВАТИ стан системи. Відновлення — після збору доказів.

Класифікація інцидентів

Різні типи інцидентів — різні пріоритети реагування.

Тип Приклад Перший крок
Compromise Несанкціонований доступ, виконання команд зловмисником Ізоляція + forensics
Unauthorized access Спроби входу, перебір паролів, 0-day сканер Моніторинг + блок
DoS / DDoS Сервіс недоступний через flood трафік Rate limit + upstream filter
Data leak Витік ключів, паролів, логів у публіку Ротація секретів + аудит
Malware Майнер, ботнет, шкідливе ПО в контейнері Ізоляція + відновлення з clean backup
Insider threat Зловмисна дія від легітимного юзера Відкликання доступу + юридичний процес

Пріоритети (SLA реагування)

flowchart LR
    P1[P1: Critical<br/>Active compromise<br/>15 хв] --> Isolate
    P2[P2: High<br/>Потенційна компрометація<br/>1 год] --> Investigate
    P3[P3: Medium<br/>Підозріла активність<br/>4 год] --> Monitor
    P4[P4: Low<br/>False positive<br/>24 год] --> Document

    style P1 fill:#dc2626,color:#fff
    style P2 fill:#f59e0b,color:#000
    style P3 fill:#fbbf24,color:#000
    style P4 fill:#10b981,color:#fff

Фаза 1 — Виявлення та тріаж

Типові сигнали

  • Алерт від Prometheus/Grafana: аномальний CPU, мережа, кількість процесів
  • fail2ban нотифікація про бан
  • Увага користувача: "Matrix поводиться дивно", "не пускає в VPN"
  • Щоденний огляд логів journalctl --since yesterday | grep -iE 'fail|error|unauthorized'
  • Cron з rkhunter, chkrootkit, aide

Перевірка — це справді інцидент?

# Підозрілі процеси
ps auxf | less                          # дерево процесів
ps aux --sort=-%cpu | head -20          # top CPU
ps aux --sort=-%mem | head -20
lsof -nP -iTCP -sTCP:LISTEN             # хто слухає порти

# Невідомі автентифікації
last -20                                # останні логіни
lastb -20                               # невдалі спроби
w                                       # хто онлайн зараз

# Підозрілі з'єднання
ss -tuanp | grep ESTAB                  # всі встановлені з'єднання
ss -tuanp | awk '{print $5}' | sort -u  # унікальні remote endpoints

Якщо щось підозріле — переходимо в режим інциденту.


Фаза 2 — Ізоляція (НЕ перезавантажуй!)

🚨 НЕ перезавантажуй сервер
Reboot стирає: процеси в пам'яті, мережеві з'єднання, `/proc/*/exe` посилання на видалені бінарники, tmpfs зі шкідливим кодом. Це **основні докази**.

Якщо це VPS хаб

# 1. Заблокувати новий зовнішній трафік, але зберегти активні сесії admin
iptables -I INPUT 1 -i eth0 -m conntrack --ctstate NEW -j DROP
iptables -I INPUT 1 -i eth0 -m conntrack --ctstate ESTABLISHED,RELATED \
  -s <YOUR_ADMIN_IP> -j ACCEPT

# АБО: від'єднати від інтернету з console VPS-провайдера
# (shutdown мережі через network-manager — залишиться WireGuard тільки)

Якщо це сервіс у Docker

# Зупинити контейнер БЕЗ видалення (щоб volume та процеси залишились для аналізу)
docker stop <container>

# Заморозити процеси замість зупинки (PID, пам'ять залишаються)
docker pause <container>

# Зняти snapshot файлової системи контейнера для forensics
docker commit <container> forensic-snapshot-2026-04-23
docker save forensic-snapshot-2026-04-23 | gzip > /evidence/snapshot.tar.gz

Якщо це WireGuard peer

# Видалити скомпрометованого peer з хабу
wg set wg0 peer <COMPROMISED_PUBKEY> remove
wg-quick save wg0    # зафіксувати в конфіг

# Скомпрометований ключ у blacklist (не допустити повторний додавання)
echo "<COMPROMISED_PUBKEY>" >> /etc/wireguard/banned-peers.txt

Фаза 3 — Збір доказів

Що збирати

# Створити директорію для доказів (поза компрометованим хостом бажано!)
mkdir -p /evidence/$(hostname)-$(date +%Y%m%d-%H%M%S)
cd /evidence/*

# 1. Дамп системних логів (ДО будь-яких дій, що їх можуть перезаписати)
journalctl --since "7 days ago" > journalctl.log
cp -a /var/log/ ./var-log/
cp /var/log/wtmp /var/log/btmp ./

# 2. Стан системи
ps auxfww                > ps.txt
ss -tuanp                > ss.txt
netstat -an              > netstat.txt
lsof -nP                 > lsof.txt
iptables-save            > iptables.txt
nft list ruleset         > nft.txt
w; last -50              > sessions.txt

# 3. Файли з unexpected mtime (новіше за останній deploy)
find / -xdev -newer /var/log/dpkg.log -type f 2>/dev/null > recent-files.txt

# 4. SUID/SGID бінарі (можуть бути підкинуті)
find / -xdev \( -perm -4000 -o -perm -2000 \) -type f 2>/dev/null > suid.txt

# 5. Docker стан
docker ps -a            > docker-ps.txt
docker images           > docker-images.txt
docker network ls       > docker-net.txt
docker inspect <susp>   > docker-inspect.txt

# 6. Пам'ять (якщо є LiME або acquire tools)
# Потребує попередньо встановленого LiME
# insmod /opt/lime.ko "path=/evidence/memory.lime format=lime"

# 7. Хеші усього для integrity
find /evidence -type f -exec sha256sum {} \; > /evidence/hashes.txt

# 8. Копія на зовнішній носій — ОБОВ'ЯЗКОВО
rsync -a /evidence/ admin@forensic-vault:/incidents/

Ключові файли логів

Файл Що шукати
/var/log/auth.log (Ubuntu) SSH login, sudo, PAM
/var/log/syslog Системні події, kernel, firewall drops
/var/log/wtmp (last) Успішні логіни — коли, звідки
/var/log/btmp (lastb) Невдалі спроби — brute force
journalctl -u sshd Деталі SSH connection attempts
journalctl -u wg-quick@wg0 WireGuard handshakes
/var/log/caddy/access.log HTTP requests — хто звертався
docker logs <container> Логи скомпрометованого сервісу

Аналітичні запити

# Хто логінився за останні 24 години
last --since yesterday

# SSH невдалі спроби — топ-10 IP
grep "Failed password" /var/log/auth.log | \
  awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head

# Виконані sudo команди
grep "COMMAND=" /var/log/auth.log | tail -50

# Нові процеси, запущені як root за останні 6 годин (якщо auditd працює)
ausearch -ts today -ui 0 -m execve

# Відхилені WireGuard handshakes
journalctl -u wg-quick@wg0 --since "1 day ago" | grep -i "invalid\|fail"

Фаза 4 — Аналіз: хто, коли, що

Мета — зрозуміти timeline та scope.

Timeline reconstruction

# Об'єднати всі логи у timeline за ISO8601 timestamps
for f in auth.log syslog caddy.log; do
  awk -v file="$f" '{print $0" ["file"]"}' /var/log/$f
done | sort > /evidence/timeline.txt

# або журнал з машинно-читабельним timestamp
journalctl --since "48 hours ago" -o short-iso | less

Скоуп — що ще зачепило

  • Файли створені/модифіковані в період атаки: find / -newermt "2026-04-23 10:00" ! -newermt "2026-04-23 14:00"
  • SSH ключі додані: cat /root/.ssh/authorized_keys, cat /home/*/.ssh/authorized_keys
  • Cron-задачі модифіковані: ls -la /var/spool/cron/, ls -la /etc/cron.*/
  • Systemd unit-файли: find /etc/systemd/ -newer /var/log/dpkg.log
  • Docker контейнери з незнайомими образами: docker ps -a --format 'table {{.Names}}\t{{.Image}}\t{{.CreatedAt}}'

Індикатори компрометації (IoC)

  • Невідомі IP у authorized_keys (SSH), wg show (WireGuard)
  • Процеси з PID без запису в /proc/<PID>/exe (виконуваний файл видалено)
  • Мережеві з'єднання до C2 (dynamic DNS домени, Tor, tor-bridges)
  • Підвищене навантаження CPU від невідомих бінарників (крипто-майнер)
  • Нові SUID binaries, особливо у /tmp, /dev/shm, /var/tmp

Фаза 5 — Відновлення

⚠️ Не "почистити і забути"
Якщо зловмисник мав root — вся система недовірена. Не шукати "де саме він сидів і видалити". Відновлювати з clean state.

План відновлення

  1. Ротація всіх секретів — припустити що ВСЕ скомпрометовано:
    - wireguard ключі всіх peer-ів на ураженому хабі
    - SSH host keys (/etc/ssh/ssh_host_*) та authorized_keys
    - Паролі (MAS, Matrix, PostgreSQL, Redis, Grafana)
    - API токени, TLS приватні ключі (mtls, Caddy account key)
    - SIM карток (якщо LTE core скомпрометовано — K/OPc ключі)
  2. Переінсталяція — чисте встановлення ОС з ISO, не "clean up" поточної
  3. Відновлення сервісів з backup, старіших за дату компрометації
  4. Аудит конфігів перед запуском — backup міг містити зворотні двері
  5. Новий firewall ruleset — default deny, явний allowlist
  6. Моніторинг посилений на 7-14 днів — зловмисник може спробувати повторно

Перевірка before go-live

# Базовий baseline
rkhunter --check --skip-keypress
chkrootkit

# File integrity baseline (після чистої інсталяції!)
aide --init
mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db
# Далі щодня cron: aide --check

# Перевірка що nic не в promiscuous
ip link | grep PROMISC

Фаза 6 — Post-mortem

Документ для команди (не шукаємо винуватого, шукаємо причину).

Шаблон post-mortem

# Incident: <short title>
**Дата:** YYYY-MM-DD  **Тривалість:** X год Y хв  **Severity:** P1/P2/P3

## Timeline
- 10:15 — перший алерт X
- 10:23 — тріаж, підтверджено як інцидент
- 10:45 — ізоляція
- ...

## Impact
- Сервіси: які недоступні, скільки часу
- Дані: чи витекло, чи видозмінено
- Користувачі: скільки зачеплено

## Root cause
Що саме дозволило атаку (CVE, misconfig, weak password, etc.)

## What went well
- Що спрацювало — швидка ізоляція, робочий backup, тощо

## What went poorly
- Чого не вистачило — алерту не було, logging вимкнено, runbook застарілий

## Action items
- [ ] <конкретна дія> — <власник> — <термін>
- [ ] Патч CVE-2026-XXXX на всіх хостах — @admin — 2026-04-30
- [ ] Додати alert на >50 failed SSH/min — @monitoring — 2026-04-25

Особливості UMTC

WireGuard-only доступ — сильна й слабка сторона

ℹ️ WireGuard як attack surface reducer
У UMTC всі admin-сервіси (SSH, Grafana, Synapse admin, Open5GS WebUI) прив'язані до `wg0` інтерфейсу. Атакуючи з публічного інтернету — зловмисник бачить тільки порти 80/443 (Caddy) та 51820/udp (WG handshake). SSH-brute force технічно неможливий.
⚠️ Компрометація WG ключа = повний доступ
Якщо peer-ключ потрапив до атакуючого — він отримує мережевий доступ такий же як легітимний адміністратор: SSH порт відкритий, внутрішні сервіси видимі. Ключі peer-ів є **такими ж секретами як паролі root**, ставлення відповідне: зберігання в менеджері паролів/HSM, ротація при підозрі, окремі ключі для production vs staging vs польових вузлів.

Docker forensics специфіка

  • docker exec всередині контейнера — перегляд як root, але зміни в overlay FS шарі губляться при docker rm. Для збереження — docker commit перед видаленням.
  • Скомпрометований контейнер може escape через --privileged, mounted /var/run/docker.sock, capability SYS_ADMIN. Після escape — атакуючий root на host. Перевірка: docker inspect <container> | jq '.[] | .HostConfig.Privileged, .HostConfig.Binds'.

Matrix як канал повідомлень про інцидент

  • Окрема кімната #incidents:matrix.umtc.local (E2EE, обмежене членство)
  • Не використовувати сам Matrix як кризовий канал ЯКЩО Matrix-сервер постраждав. Fallback: signal/telephone, pre-agreed
  • Зберігати номери/альтернативні канали у роздрукованому runbook, не лише в Matrix

SIM картки та LTE core

Якщо скомпрометовано HSS (Open5GS subscriber DB), атакуючий має Ki/OPc всіх SIM. Наслідок: можна клонувати будь-який SIM і підключатись до мережі від імені легітимного абонента.

  • Ротація всіх Ki/OPc — перезаписати SIM через pySim/OYEITIMES
  • Нові IMSI (новий діапазон PLMN 255/33), старі "спалити" у blacklist
  • Перевірити що HSS база не містить IMSI, яких ми не створювали

Troubleshooting процесу IR

Не можу отримати докази — хост недоступний навіть через console
- Симптом: атакуючий змінив firewall/SSH так, що console-доступ не дає shell.
- Причина: rootkit замінив bash/login, або зламаний LUKS ключ.
- Рішення: rescue режим з ISO/Live CD провайдера. Змонтувати / як read-only: mount -o ro /dev/sda1 /mnt. Зробити dd-копію диска: dd if=/dev/sda of=/external/image.dd bs=4M status=progress — аналізувати offline. НЕ бутитись у скомпрометовану систему.

Логи виглядають підчищеними — lastlog порожній, auth.log обірваний
- Симптом: перед точкою інциденту логи просто "нуль рядків" або явні розриви.
- Причина: атакуючий має root, >/var/log/auth.log стерло файл.
- Рішення: перевірити journalctl --no-pager — він у binary форматі, важче підчистити. Налаштувати централізоване логування (rsyslog → окремий log host у WG мережі, куди атакуючий не зміг залізти). Для майбутніх інцидентів — chattr +a /var/log/* (append-only) ускладнює стирання, але не захищає від root.

Post-mortem перетворюється у пошук винного — команда закривається
- Симптом: на post-mortem зустрічі всі оправдовуються, action items розмиті.
- Причина: культура "хто винен" замість "blameless post-mortem".
- Рішення: явне правило "blameless" — на першому слайді. Фокус на: як система дозволила цю помилку (а не чому N зробив помилку). Питання "що могло спрацювати замість людини?" (автоматизація, моніторинг, руdnebook). Action items — ТЕХНІЧНІ та процесні, не "Петро буде уважніший".


Пов'язані статті

Шлях: security/incident-response.md

UMTC Wiki © 2026 | Ukrainian Military Tactical Communications