AppSecFest — это ежегодное событие, где вы можете познакомиться с миром кибербезопасности и узнать больше о событиях и решениях используемых многими компаниями уже сейчас.

На данном мероприятии наша команда mimicats выступала в роли организаторов и мы решили разбавить выступления спикеров и презентации решений более практическими и интересными заданиями.

Нами было сделано Play Zone, где участвуя в интерактивных играх и квизах связанных с кибербезопасностью вы могли заработать коины для покупки эксклюзивного мерча.
А также мы решили простроить целую инфраструктуру для данного мероприятия и проведения локального соревнования, где приняли участие как и уже бывалые ИБ-шники, так и совсем зеленные новички.

Дальше уже пойдет больше про то, что было сделано, а также вектор в котором мы двигались при построении данной инфраструктуры.

План статьи:

1) Архитектура проекта и немного воды
2) Настройка OpenVPN
3) Телеграм ботыы
4) CTFd
5) Wazuh
6) Zabbix

Архитектура проекта:

Основной идеей у нас было создать безопасную систему, в который участники могли бы комфортно решать задания и мы видели если бы они совали носы куда не стоит)

И стоит заметить, что тут скорее не про то как НУЖНО делать, а про то как видели и хотели сделать мы.

OpenVPN 

Важная часть инфры, так как нам надо было ограничить доступ к нашим заданиям как можно сильнее и контролировать как можно больше.

Было поднято 2 Openvpn

1) Для обычных юзеров без авторизации  - доступ к веб таскам и CTFd 

2) Для админов с авторизацей - доступ к SIEM(Wazuh), Zabbix, веб таскам и CTFd по ssh 

sudo apt update sudo apt install openvpn easy-rsa make-cadir ~/openvpn-ca cd ~/openvpn-ca ./easyrsa init-pki ./easyrsa build-ca # задайте имя и пароль CA ./easyrsa gen-req server_non_auth nopass ./easyrsa sign-req server server_non_auth ./easyrsa gen-req server_auth nopass ./easyrsa sign-req server server_auth ./easyrsa gen-dh openvpn --genkey secret ta.key

Затем настройка конфигов

  1. для юзеров:

nano /etc/openvpn/server/server_non_auth.conf port 1194 proto udp dev tun topology subnet ; Пути к сертификатам и ключам ca /etc/openvpn/ca.crt cert /etc/openvpn/server_non_auth.crt key /etc/openvpn/server_non_auth.key dh /etc/openvpn/dh.pem ; tls-auth /etc/openvpn/ta.key 0 # Разрешаем запуск скриптов script-security 3 # Подключаем скрипт, который будет вызываться при каждом входящем подключении client-connect /etc/openvpn/scripts/client-connect.sh ; Задаём основной пул IP (например, 10.10.10.0/24) server 10.10.10.0 255.255.255.0 ifconfig-pool-persist /etc/openvpn/ipp_non_auth.txt ; Раздача маршрута для доступа к сети 192.168.52.0/24 push "route 192.168.52.0 255.255.255.0" keepalive 10 120 cipher AES-256-CBC persist-key persist-tun status /var/log/openvpn_non_auth_status.log verb 3

client-connect /etc/openvpn/scripts/client-connect.sh - данная часть кода нужна для того чтобы выполнялся скрипт client-connect.sh при каждом подключении клиента #!/bin/bash # /etc/openvpn/scripts/client-connect.sh LOGFILE="/var/log/openvpn-client-connect.json" # Получаем метку времени timestamp=$(date '+%Y-%m-%dT%H:%M:%S%z') # Формируем JSON-строку json="{\"timestamp\":\"${timestamp}\",\ \"event\":\"client-connect\",\ \"common_name\":\"${common_name}\",\ \"untrusted_ip\":\"${untrusted_ip}\",\ \"untrusted_port\":\"${untrusted_port}\",\ \"vpn_ip\":\"${ifconfig_pool_remote_ip}\"}" echo "${json}" >> "${LOGFILE}" exit 0

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

В итоге получаем логи в формате json для удобной передачи в Wazuh

[root@vpn-rocky openvpn]# cat /var/log/openvpn-client-connect.json 

{"timestamp":"2025-04-22T19:21:21+0000","event":"client-connect","common_name":"client1","untrusted_ip":"176.64.21.98","untrusted_port":"27086","vpn_ip":"10.10.10.4"}

{"timestamp":"2025-04-23T00:25:10+0500","event":"client-connect","common_name":"client1","untrusted_ip":"176.64.21.98","untrusted_port":"29515","vpn_ip":"10.10.10.4"}

  1. для админов

Такая же конфигурации но только выдача админам IP из подсети 10.69.69.0/24  для доступа к админской подсети 192.168.69.0/24

Также добавили авторизацию. Авторизация происходить через проверку логина/пароля через PAM.

Далее идет настройка сети для того чтобы юзеры могли получить доступ к внутренней сети с помощью ВПН.

Телеграм боты

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

Автоматизировать мы решили следующие процессы:

1. Выдача доступов.
2. Поддержка
3. Озвучка First Blood'ов

  1. Бот для раздачи данных, кредов и openvpn файлов для доступа к CTFd и таскам

Сделать так чтобы одной командой участник мог получить все доступы, было легко.
Однако, надо было сделать так, чтобы этот же пользователь не мог получить доступы для еще одной учетки, для этого мы решили чтобы бот собирал user_id и приписывал их для каждой пары логин, пароль+vpn конфиг.

По итогу простенький бот, но который сильно помог нам с выдачей доступов, ведь поток людей был на протяжении всего соревнования.

Пример работы:


2. Support bot

Обработка запросов участников это одна из неотъемлемых частей любой СТФки, поэтому тут я решил просто облегчить работу админам, человек создавал запросы через телеграм:

А мы обрабатывали их в отдельном мессенджере:

3. First Blood

Вот тут было сложно придумать как реализовать автоматическую озвучку всех First Blood-ов
Так как у нас был отдельный VPN, я решил со своего ноута подключить SSH тунель до сервера с CTFd.
Таким образом, чтобы при обращении на сервере CTFd на localhost:6000 этот запрос обращался на localhost:5000 моего ноута.

Команда для подключения(с моего ноута):
ssh -4 -N -o ServerAliveInterval=30 -o ServerAliveCountMax=3 -R 127.0.0.1:6000:127.0.0.1:5000 user@{ctfd_ip}

Как происходит озвучка First Blood:

https://drive.google.com/drive/folders/1qaVZQR3AvCD5d4CztWlri06cCkHjBixr?usp=sharing


CTFd

Разворачивание CTFd было стандартное с контейнера, но решили сделать свой дизайн под эту сореву.


SIEM Wazuh: Логирование, трафик и безопасность

В дополнение к всей системе мы приняли решение развернуть SIEM-решение для централизованного сбора логов, анализа сетевого трафика и контроля VPN-соединений. В качестве основы был выбран open-source стек Wazuh, обладающий широкими возможностями по корреляции событий и интеграции с Elastic Stack.

Компоненты и архитектура

  • Wazuh agent — установлен на всех целевых серверах для сбора системных логов и событий безопасности.

  • Packetbeat — отвечает за сбор сетевого трафика, включая протоколы уровня приложений.

  • Filebeat — используется для отправки нестандартных и кастомных логов, в основном с VPN-сервера.

  • Logstash — принимает, обрабатывает и передаёт данные в OpenSearch (или Elasticsearch).

? Мониторинг VPN-трафика через Packetbeat

На хосте с VPN-сервером был установлен Packetbeat. Конфигурация направлена на отслеживание ключевых протоколов (HTTP, TLS, DNS, PostgreSQL, MongoDB и др.) и фильтрацию по внутренним IP-диапазонам.

Фрагмент packetbeat.yml:

packetbeat.interfaces.device: any packetbeat.interfaces.poll_default_route: 1m packetbeat.interfaces.internal_networks:

- private

packetbeat.flows:

timeout: 30s

period: 10s

packetbeat.protocols:

- type: icmp

enabled: true

- type: http

include_body_for: ["application/json", "text/html", "application/xml"]

ports: [80, 8080, 8000, 5000, 8002,8088]

send_headers: true

send_all_headers: true

send_request: true

send_response: true

- type: tls

ports:

- 443

- 993

- 995

- 5223

- 8443

- 8883

- 9243

- type: dns

ports: [53]

- type: mysql

ports: [3306, 3307]

- type: pgsql

ports: [5432]

- type: redis

ports: [6379]

- type: mongodb

ports: [27017]

- type: memcache

ports: [11211]

- type: thrift

ports: [9090]

- type: nfs

ports: [2049]

- type: cassandra

ports: [9042]

- type: amqp

ports: [5672]

- type: dhcpv4

ports: [67, 68]

- type: sip

ports: [5060]

setup.template.settings:

index.number_of_shards: 1

processors:

- drop_event.when.not.or:

- network.source.ip: "10.69.69.0/24"

- network.source.ip: "10.10.10.0/24"

- drop_fields:

fields:

- host.hostname

- host.name - host.architecture - host.os.* - host.containerized - cloud - ecs - agent - docker - container - related - tags - input - service - event.dataset - event.kind - user_agent.device - url.query - status - status_phrase - http.request.headers - http.response.headers output.logstash: hosts: ["192.168.69.140:5000"]

? Сбор логов OpenVPN через Filebeat

Для мониторинга активности OpenVPN были настроены отдельные inputs в filebeat.yml, включая статус-подключения, аутентификацию и клиентские события.

Пример конфигурации:

[rockylinux@vpn-rocky filebeat]$ sudo cat filebeat.yml filebeat.inputs: - type: log enabled: true paths: - /var/log/openvpn.log fields: category: openvpn log_type: main - type: log enabled: true paths: - /var/log/openvpn_auth_status.log fields: category: openvpn log_type: auth - type: log enabled: true paths: - /var/log/openvpn_non_auth.log fields: category: openvpn log_type: non_auth - type: log enabled: true paths: - /var/log/openvpn-client-connect.log fields: category: openvpn log_type: connect - type: log enabled: true paths: - /var/log/openvpn_non_auth_status.log fields: category: openvpn log_type: non_auth_status - type: log enabled: true paths: - /var/log/openvpn-client-connect.json json.keys_under_root: true json.add_error_key: true fields: category: openvpn log_type: client_connect output.logstash: hosts: ["192.168.69.140:5000"]

? Обработка и маршрутизация логов в Logstash

Logstash принимает данные от Beat-агентов, фильтрует их, парсит JSON (если требуется) и перенаправляет в нужные индексы OpenSearch.

Основные моменты:

  • Разделение логов по категориям (openvpn, packetbeat и пр.).

  • Создание индексов по шаблону: openvpn-auth-2025.05.13, packetbeat-logs-2025.05.13 и т.п.

  • Частичная очистка полей (mutate/remove_field) для упрощения структуры документа.

Фрагмент output-конфига:

root@wazuh-zabbix:/etc/logstash/conf.d# cat wazuh-opensearch.conf input { beats { port => 5000 ssl => false } } filter { if [fields][log_type] == "json_connect" { json { source => "message" skip_on_invalid_json => true } date { match => ["timestamp", "ISO8601"] target => "@timestamp" timezone => "UTC" } } if [@metadata][beat] == "filebeat" { mutate { remove_field => [ "@version", "[agent]", "ecs.version", "[host][name]", "[input][type]", "[log]", "tags" ] } } } output { if [@metadata][beat] == "filebeat" and [fields][category] == "openvpn" { opensearch { hosts => ["https://localhost:9200"] index => "openvpn-%{[fields][log_type]}-%{+YYYY.MM.dd}" user => "admin" password => "wazuhpassword" ssl => true ssl_certificate_verification => false } } else if [@metadata][beat] == "filebeat" { opensearch { hosts => ["https://localhost:9200"] index => "submissions" user => "admin" password => "wazuhpassword" ssl => true ssl_certificate_verification => false } } else if [@metadata][beat] == "packetbeat" { opensearch { hosts => ["https://localhost:9200"] index => "packetbeat-logs-%{+YYYY.MM.dd}" user => "admin" password => "R.z9oDh6j9paU5UYlYtH*MKQ+IoUMUWR" ssl => true ssl_certificate_verification => false } } }


Создание кастомных правил и декодеров в Wazuh для анализа специфических форматов логов (в т.ч. OpenVPN).

Создание кастомных индексов в OpenSearch для изоляции логов по источнику и типу события.

Разработка простых дашбордов в Wazuh Dashboards для визуального анализа активности.

Активность VPN: белые IP-адреса, количество подключений, геолокация.
Активность VPN: белые IP-адреса, количество подключений, геолокация.
Сетевые соединения клиентов: анализ обращений к CTF-серверам по портам и протоколам
Сетевые соединения клиентов: анализ обращений к CTF-серверам по портам и протоколам
Активность пользователей по времени
Активность пользователей по времени



Zabbix + Grafana: Контроль нагрузки на сеть и серверы

Последним этапом нашей работы стал контроль за нагрузкой на сеть и серверы. Для сбора метрик использовалась система мониторинга Zabbix, а визуализация данных осуществлялась с помощью Grafana.

Особое внимание было уделено параметрам сетевого трафика. Для предотвращения перегрузки сети мы ограничили скорость каждого клиента. Это позволило избежать узких мест и обеспечить стабильную работу всей системы при высоких нагрузках.

Мониторинг загрузки процессора позволил своевременно выявлять потенциальные точки перегрева и перераспределять ресурсы между сервисами, поддерживая оптимальный уровень производительности(к счастью сервера были обеспеченны ресурсами).

По итогу хотелось бы еще раз подчеркнуть, что это всё это наш опыт в построении и администрировании инфраструктуры.

Мы надеемся, что наш подход и решения окажутся полезными для тех, кто также работает над созданием устойчивой и прозрачной системы мониторинга.

Комментарии (1)


  1. YX1978
    14.05.2025 06:09

    Вот это совпадение, случаянно наткнулся) Классная статья, интересно кто же из команды её написал? Жаль не удалось поучавствовать в этот раз)