June 12, 2024

Burp + Elastic = Куча логов(багов?)

Интро

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

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

Немного походив вокруг задачи я решил развернуть ELK для ее решения.

Но что же может дать использование ELK? Зачем оно надо?

Я заметил за собой, что часто пропускаю при анализе web-приложения такой параметр, как время ответа. И это ведет к тому, что потенциальные неочевидные уязвимые точки, например, содержащие SQLi, я могу просто не заметить. Используя ELK я могу на большом объеме посмотреть всю картину и найти аномалии по данному параметру.

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

 

Развертка ELK

Весь процесс сводится к копипасте официальной документации. Ниже продублированы основные файлы и конфигурации на случай, если дока переедет или изменится, так же сделан снапшот страницы через waybackmachine и файлов конфигурации .env и docker-compose.yml

Что потребуется?

Машинка с Docker и docker compose

Если у вас есть только машинка - не беда. Докер поставить - задача одной минуты.

Если нет машинки, то самое время найти такую. Себе под эксперементы я однажды взял Firebat MN56 и после небольшого тюнинга по ОЗУ и SSD, остаюсь полностью доволен по сей день.

Установка Docker (линки на оф.манулы)

Официальные манулы по установке Docker Desktop (GUI) :

Официальный манул на ubuntu (cli version) :

Настройка/запуск ELK

Развертывание в моем случае происходит на mini pc с Ubuntu 22.04 по инструкции multi-node cluster варианта.

Выберете для себя каталог размещения файлов .env и docker-compose.yml. В примере я использую /srv/elk/.

Создайте или сохраните файлы .env и docker-compose.yml.

Пример .env

# Password for the 'elastic' user (at least 6 characters)
ELASTIC_PASSWORD=changeme

# Password for the 'kibana_system' user (at least 6 characters)
KIBANA_PASSWORD=changeme

# Version of Elastic products
STACK_VERSION=8.14.0

# Set the cluster name
CLUSTER_NAME=docker-cluster

# Set to 'basic' or 'trial' to automatically start the 30-day trial
LICENSE=basic
#LICENSE=trial

# Port to expose Elasticsearch HTTP API to the host
ES_PORT=9200
#ES_PORT=127.0.0.1:9200

# Port to expose Kibana to the host
KIBANA_PORT=5601
#KIBANA_PORT=80

# Increase or decrease based on the available host memory (in bytes)
MEM_LIMIT=1073741824

# Project namespace (defaults to the current folder name if not set)
#COMPOSE_PROJECT_NAME=myproject

Файл docker-compose.yml

services:
  setup:
    image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION}
    volumes:
      - certs:/usr/share/elasticsearch/config/certs
    user: "0"
    command: >
      bash -c '
        if [ x${ELASTIC_PASSWORD} == x ]; then
          echo "Set the ELASTIC_PASSWORD environment variable in the .env file";
          exit 1;
        elif [ x${KIBANA_PASSWORD} == x ]; then
          echo "Set the KIBANA_PASSWORD environment variable in the .env file";
          exit 1;
        fi;
        if [ ! -f config/certs/ca.zip ]; then
          echo "Creating CA";
          bin/elasticsearch-certutil ca --silent --pem -out config/certs/ca.zip;
          unzip config/certs/ca.zip -d config/certs;
        fi;
        if [ ! -f config/certs/certs.zip ]; then
          echo "Creating certs";
          echo -ne \
          "instances:\n"\
          "  - name: es01\n"\
          "    dns:\n"\
          "      - es01\n"\
          "      - localhost\n"\
          "    ip:\n"\
          "      - 127.0.0.1\n"\
          "  - name: es02\n"\
          "    dns:\n"\
          "      - es02\n"\
          "      - localhost\n"\
          "    ip:\n"\
          "      - 127.0.0.1\n"\
          "  - name: es03\n"\
          "    dns:\n"\
          "      - es03\n"\
          "      - localhost\n"\
          "    ip:\n"\
          "      - 127.0.0.1\n"\
          > config/certs/instances.yml;
          bin/elasticsearch-certutil cert --silent --pem -out config/certs/certs.zip --in config/certs/instances.yml --ca-cert config/certs/ca/ca.crt --ca-key config/certs/ca/ca.key;
          unzip config/certs/certs.zip -d config/certs;
        fi;
        echo "Setting file permissions"
        chown -R root:root config/certs;
        find . -type d -exec chmod 750 \{\} \;;
        find . -type f -exec chmod 640 \{\} \;;
        echo "Waiting for Elasticsearch availability";
        until curl -s --cacert config/certs/ca/ca.crt https://es01:9200 | grep -q "missing authentication credentials"; do sleep 30; done;
        echo "Setting kibana_system password";
        until curl -s -X POST --cacert config/certs/ca/ca.crt -u "elastic:${ELASTIC_PASSWORD}" -H "Content-Type: application/json" https://es01:9200/_security/user/kibana_system/_password -d "{\"password\":\"${KIBANA_PASSWORD}\"}" | grep -q "^{}"; do sleep 10; done;
        echo "All done!";
      '
    healthcheck:
      test: ["CMD-SHELL", "[ -f config/certs/es01/es01.crt ]"]
      interval: 1s
      timeout: 5s
      retries: 120

  es01:
    depends_on:
      setup:
        condition: service_healthy
    image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION}
    volumes:
      - certs:/usr/share/elasticsearch/config/certs
      - esdata01:/usr/share/elasticsearch/data
    ports:
      - ${ES_PORT}:9200
    environment:
      - node.name=es01
      - cluster.name=${CLUSTER_NAME}
      - cluster.initial_master_nodes=es01,es02,es03
      - discovery.seed_hosts=es02,es03
      - ELASTIC_PASSWORD=${ELASTIC_PASSWORD}
      - bootstrap.memory_lock=true
      - xpack.security.enabled=true
      - xpack.security.http.ssl.enabled=true
      - xpack.security.http.ssl.key=certs/es01/es01.key
      - xpack.security.http.ssl.certificate=certs/es01/es01.crt
      - xpack.security.http.ssl.certificate_authorities=certs/ca/ca.crt
      - xpack.security.transport.ssl.enabled=true
      - xpack.security.transport.ssl.key=certs/es01/es01.key
      - xpack.security.transport.ssl.certificate=certs/es01/es01.crt
      - xpack.security.transport.ssl.certificate_authorities=certs/ca/ca.crt
      - xpack.security.transport.ssl.verification_mode=certificate
      - xpack.license.self_generated.type=${LICENSE}
    mem_limit: ${MEM_LIMIT}
    ulimits:
      memlock:
        soft: -1
        hard: -1
    healthcheck:
      test:
        [
          "CMD-SHELL",
          "curl -s --cacert config/certs/ca/ca.crt https://localhost:9200 | grep -q 'missing authentication credentials'",
        ]
      interval: 10s
      timeout: 10s
      retries: 120

  es02:
    depends_on:
      - es01
    image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION}
    volumes:
      - certs:/usr/share/elasticsearch/config/certs
      - esdata02:/usr/share/elasticsearch/data
    environment:
      - node.name=es02
      - cluster.name=${CLUSTER_NAME}
      - cluster.initial_master_nodes=es01,es02,es03
      - discovery.seed_hosts=es01,es03
      - bootstrap.memory_lock=true
      - xpack.security.enabled=true
      - xpack.security.http.ssl.enabled=true
      - xpack.security.http.ssl.key=certs/es02/es02.key
      - xpack.security.http.ssl.certificate=certs/es02/es02.crt
      - xpack.security.http.ssl.certificate_authorities=certs/ca/ca.crt
      - xpack.security.transport.ssl.enabled=true
      - xpack.security.transport.ssl.key=certs/es02/es02.key
      - xpack.security.transport.ssl.certificate=certs/es02/es02.crt
      - xpack.security.transport.ssl.certificate_authorities=certs/ca/ca.crt
      - xpack.security.transport.ssl.verification_mode=certificate
      - xpack.license.self_generated.type=${LICENSE}
    mem_limit: ${MEM_LIMIT}
    ulimits:
      memlock:
        soft: -1
        hard: -1
    healthcheck:
      test:
        [
          "CMD-SHELL",
          "curl -s --cacert config/certs/ca/ca.crt https://localhost:9200 | grep -q 'missing authentication credentials'",
        ]
      interval: 10s
      timeout: 10s
      retries: 120

  es03:
    depends_on:
      - es02
    image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION}
    volumes:
      - certs:/usr/share/elasticsearch/config/certs
      - esdata03:/usr/share/elasticsearch/data
    environment:
      - node.name=es03
      - cluster.name=${CLUSTER_NAME}
      - cluster.initial_master_nodes=es01,es02,es03
      - discovery.seed_hosts=es01,es02
      - bootstrap.memory_lock=true
      - xpack.security.enabled=true
      - xpack.security.http.ssl.enabled=true
      - xpack.security.http.ssl.key=certs/es03/es03.key
      - xpack.security.http.ssl.certificate=certs/es03/es03.crt
      - xpack.security.http.ssl.certificate_authorities=certs/ca/ca.crt
      - xpack.security.transport.ssl.enabled=true
      - xpack.security.transport.ssl.key=certs/es03/es03.key
      - xpack.security.transport.ssl.certificate=certs/es03/es03.crt
      - xpack.security.transport.ssl.certificate_authorities=certs/ca/ca.crt
      - xpack.security.transport.ssl.verification_mode=certificate
      - xpack.license.self_generated.type=${LICENSE}
    mem_limit: ${MEM_LIMIT}
    ulimits:
      memlock:
        soft: -1
        hard: -1
    healthcheck:
      test:
        [
          "CMD-SHELL",
          "curl -s --cacert config/certs/ca/ca.crt https://localhost:9200 | grep -q 'missing authentication credentials'",
        ]
      interval: 10s
      timeout: 10s
      retries: 120

  kibana:
    depends_on:
      es01:
        condition: service_healthy
      es02:
        condition: service_healthy
      es03:
        condition: service_healthy
    image: docker.elastic.co/kibana/kibana:${STACK_VERSION}
    volumes:
      - certs:/usr/share/kibana/config/certs
      - kibanadata:/usr/share/kibana/data
    ports:
      - ${KIBANA_PORT}:5601
    environment:
      - SERVERNAME=kibana
      - ELASTICSEARCH_HOSTS=https://es01:9200
      - ELASTICSEARCH_USERNAME=kibana_system
      - ELASTICSEARCH_PASSWORD=${KIBANA_PASSWORD}
      - ELASTICSEARCH_SSL_CERTIFICATEAUTHORITIES=config/certs/ca/ca.crt
    mem_limit: ${MEM_LIMIT}
    healthcheck:
      test:
        [
          "CMD-SHELL",
          "curl -s -I http://localhost:5601 | grep -q 'HTTP/1.1 302 Found'",
        ]
      interval: 10s
      timeout: 10s
      retries: 120

volumes:
  certs:
    driver: local
  esdata01:
    driver: local
  esdata02:
    driver: local
  esdata03:
    driver: local
  kibanadata:
    driver: local

Самые внимательные наверняка заметили, что в варианте описаном выше отсутствует строка version: "2.2". Это сделано специально, т.к. в последних версиях docker compose свойство version устарело и больше не используется.

Теперь для запуска остается выполнить команду

docker compose up -d

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

После запуска идем в kibana

http://ip_вашей_машины:5601/app/enterprise_search/content/search_indices

Вводим логин elastic и пароль из переменной ELASTIC_PASSWORD=

Тут нам необходимо создать индекс, который будет содержать в себе данные из burp

Настройка Burp

Плагины

Приступаем к самому интересному.

Как же заставить Burp отправлять логи в Elastic? Посмотрим, что предлагает BApp Store и не только:

  1. ElasticBurp
  2. Report To Elastic Search
  3. Logger++
  4. ElasticBurp-NG (отсутствует в BApp Store)

Я попробовал все варианты. Какими выводами я могу с вами поделиться:

ElasticBurp, ElasticBurp-NG (Next Generation!!!11) и Report To Elastic Search - это все разные стороны одной кучи 💩

Эти плагины считают, что соединение к elastic должно быть по http и без аутентификации.

Другое дело Logger++, но нужена версия с github от nccgroup, т.к. в BApp Store лежит древняя.

Итак, мы поставили плагин и уже хотим пойти в настройки. Но именно на данном этапе стоит сделать шаг в сторону.

Настройка сертификатов

В используемой конфигурации elastic'а, соединение возможно только через https. Поэтому для корректной работы необходимо добавить сертификат сервера в доверенные сертификаты той Java, которая используется Burp'ом.

Интернет полон следующим адресом хранилища сертификатов $JAVA_HOME/jre/lib/security/cacerts, однако это не применимо к Burp под MacOS тк там используется поставляемый, вместе с Burp'ом, Java bundle.

Как быть, если мы MacOS пользователи.

Для начала сохраним наш сертификат в домашний каталог пользователя на нашей MacOS

openssl x509 -in <(openssl s_client -connect адрес_вашего_сервера:9200 -prexit 2>/dev/null) -out ./elk.crt

Затем "пропатчим" хранилище сертификатов Java bundle

sudo keytool -importcert -file ~/elk.crt -alias example -keystore /Applications/Burp\ Suite\ Professional.app/Contents/Resources/jre.bundle/Contents/Home/lib/security/cacerts -storepass changeit

Теперь момент о котором легко забыть - мы добавили сертификат, в котором указан Common Name: es01. В таком случае при обращении по IP мы будем получать сообщение о несоответствии сертификата к хостнейму.

Для обхода этого необходимо добавить банальные записи в /etc/hosts

sudo vim /etc/hosts

192.168.100.27 es01 # тут нужно указать ваш адрес сервера

Настройка плагина

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

Не забудьте про кнопку Configure

Все. Теперь вы можете наслаждаться логами в Kibana http://es01:5601/app/discover#/ , смотреть, фильтровать и строить визуализации.