Cowrie honeypot: установка, настройка, использование

 Публичный пост для комнаты «Селфхостинг»
28 марта 2025  297

Введение

Привет! Расскажу про Cowrie SSH Honeypot, как его настроить и для чего применить в Homelab.

Статья рассчитана на тех, кто уже более-менее уверенно чувствует себя в селфхарме селфхосте, не уходит в панику при виде куска compose.yml. Используемые технологии: docker compose, grafana, victorialogs, promtail, crowdsec. Если все слова знакомые, читать будет очень просто. Как говорят в кровавом ентерпрайзе, if you have questions – please let me know.

Honeypot – это сервис - ловушка, который висит на определенном порту, и ждет, пока в него войдут. Есть ханипоты для разных сервисов: будь то SSH, Telnet, RDP…  Его суть в том, чтобы в эту ловушку попали - у себя мы это логируем, строим красивые дашборды и отправляем нарушителя спокойствия в бан. Бан есть просто локальный, но можно и отправлять в сторонний сервис (у меня это Crowdsec). Ну и для дашбордиков красивых, конечно!

красивый дашбордик
красивый дашбордик

Примеры ханипотов:

  • pisshoff: SSH Honeypot. A very simple SSH server using thrussh that exposes mocked versions of a bash shell, some commands and SSH subsystems to act as a honeypot for would-be crackers.
  • endlessh: SSH tarpit that slowly sends an endless banner
  • tpotce: 🍯 T-Pot - The All In One Multi Honeypot Platform 🐝
  • cowrie: Cowrie SSH/Telnet Honeypot
  • beelzebub: A secure low code honeypot framework, leveraging AI for System Virtualization.

Хоть они и разные ( например, просто слушать порт на микротике и банить при попытке зайти на порт - Youtube:Настройка Honeypot в Mikrotik), с разными требованиями (tpotce очень крутая, но хочет очень много ресурсов)...

… для себя я выбрал именно cowrie, так как хочу сделать красивые графики на дашборде с картой, обработку логов, беспалевный ханипот… а еще – это просто первое, что я нашел

Подробнее про Cowrie

аватарка проекта
аватарка проекта

Cowrie - это проект на python, который имитирует настоящий сервер, на который зашли по SSH/telnet. Он умеет прикольные фишки:

  • Разные варианты аутентификации (опа, быстрая проверка - или “авторизации”?)
  • Имитация ввода команд и их вывода
  • Фейковая файловая система
  • Сохранять загруженные файлы (но это я пока не юзаю)
  • 2 режима окружения - в питоне, или же в настоящем qemu (тоже пока не юзаю, звучит страшновато)
  • Сохранять историю ввода команд, с возможностью экспорта на asciinema
  • Логирование в JSON и запуск в Docker

Может, умеет еще что-то, что я мог забыть. Но мне этого было достаточно, чтобы остановить серфинг по мировой веб паутине в поисках ханипота.

Установка и настройка

Сначала просто его поднимем с простыми настройками, после этого покажу, как его [cowrie] кастомизировать.

Вот так можно запустить на коленке этот контейнер cowrie/cowrie с докерхаба:

docker run -it --rm -p 2222:2222 cowrie/cowrie

И вот так потестить с того же компа (опции SSH отключают запоминание и проверку ключа сервера):

ssh -o "UserKnownHostsFile=/dev/null" -o "StrictHostKeyChecking no" -p 2222 root@127.0.0.1

Тут же можем осмотреться. В качестве пароля я вбил “123”

/Users/ColCh/Workspace/cowrie-setup  took 2s88ms
 11:40:31 ✖  ssh -o "UserKnownHostsFile=/dev/null" -o "StrictHostKeyChecking no" -p 2222 root@127.0.0.1
root@127.0.0.1's password:
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
root@svr04:~# ls -lah
drwx------ 1 root root 4.0K 2013-04-05 12:25 .
drwxr-xr-x 1 root root 4.0K 2013-04-05 12:03 ..
drwx------ 1 root root 4.0K 2013-04-05 11:58 .aptitude
-rw-r--r-- 1 root root  570 2013-04-05 11:52 .bashrc
-rw-r--r-- 1 root root  140 2013-04-05 11:52 .profile
drwx------ 1 root root 4.0K 2013-04-05 12:05 .ssh
root@svr04:~# cat .bashrc
root@svr04:~# cat .profile
root@svr04:~# ls .ssh
known_hosts
root@svr04:~# cat .ssh/known_hosts
root@svr04:~# cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
lp:x:7:7:lp:/var/spool/lpd:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh
proxy:x:13:13:proxy:/bin:/bin/sh
www-data:x:33:33:www-data:/var/www:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh
list:x:38:38:Mailing List Manager:/var/list:/bin/sh
irc:x:39:39:ircd:/var/run/ircd:/bin/sh
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh
nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
libuuid:x:100:101::/var/lib/libuuid:/bin/sh
sshd:x:101:65534::/var/run/sshd:/usr/sbin/nologin
phil:x:1000:1000:Phil California,,,:/home/phil:/bin/bash
root@svr04:~# uname -a
Linux svr04 3.2.0-4-amd64 #1 SMP Debian 3.2.68-1+deb7u1 x86_64 GNU/Linux
root@svr04:~#

Как видим, файлы в домашней директории пустые. Также в юзерах записан какой-то Phil.

Как по мне, довольно палевно. Если бы я был Нео внутри матрицы - я бы давно согнул эту ложку.

Давайте настроим этот ханипот.

Кастомизация

Начнем с конфига. Хоть и в документации сказано, что можно использовать env переменные, у меня не получилось. Он просто игнорировал мои env переменные (хотя, судя по коду, должно работать). Но сейчас проверил - и заработало…магия.

Вот так можно запустить с конфигом (пока без compose, на коленке):

docker run -it --rm -p 2222:2222 \
   -e=COWRIE_HONEYPOT_HOSTNAME="droplet" \
   -e=COWRIE_HONEYPOT_TIMEZONE="Europe/Moscow" \
   -e=COWRIE_HONEYPOT_FAKEADDR="192.168.1.26" \
   -e=COWRIE_HONEYPOT_AUTH_CLASS="AuthRandom" \
   -e=COWRIE_HONEYPOT_AUTH_CLASS_PARAMETERS="1,2,10" \
   -e=COWRIE_SHELL_KERNEL_VERSION="6.8.1-4-amd64" \
   -e=COWRIE_SHELL_KERNEL_BUILD_STRING="#1 SMP Debian 6.8.11-1+deb12u1" \
   -e=COWRIE_SSH_SFTP_ENABLED="false" \
   -e=COWRIE_SSH_FORWARDING="false" \
   -e=COWRIE_SSH_FORWARD_REDIRECT="false" \
   cowrie/cowrie

Дефолтный конфиг тут, на GH. Чтобы написать его как env: берем секцию, имя опции, добавляем спереди cowrie, и оформляем это как constant case

Проверим:

/Users/ColCh/Workspace/cowrie-setup  took 2m59s170ms
 11:57:15 ➜  ssh -o "UserKnownHostsFile=/dev/null" -o "StrictHostKeyChecking no" -p 2222 root@127.0.0.1
root@127.0.0.1
root@127.0.0.1's password:
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
root@droplet:~# uname -a
Linux droplet 6.8.1-4-amd64 #1 SMP Debian 6.8.11-1+deb12u1 x86_64 GNU/Linux
root@droplet:~#

Выглядит рабочим. Авторизация в примере выбрана как AuthRandom, что позволяет войти с любым паролем на рандомной попытке между 1 и 2. Связка login/pass кешируется на 10 входов.

Я бы хотел сделать так, чтобы человек бот входил по уже заранее заготовленным логинам и паролям. Для этого нужно сделать userdb.

Давайте сделаем. Заодно уже покажу compose.yml с секцией configs

services:
 cowrie:
   image: cowrie/cowrie
   container_name: cowrie
   ports:
     - "2222:2222"
   environment:
     - COWRIE_HONEYPOT_HOSTNAME=droplet
     - COWRIE_HONEYPOT_TIMEZONE=Europe/Moscow
     - COWRIE_HONEYPOT_FAKEADDR=192.168.1.26
     - COWRIE_SHELL_KERNEL_VERSION=6.8.1-4-amd64
     - COWRIE_SHELL_KERNEL_BUILD_STRING="#1 SMP Debian 6.8.11-1+deb12u1"
     - COWRIE_SSH_SFTP_ENABLED=false
     - COWRIE_SSH_FORWARDING=false
     - COWRIE_SSH_FORWARD_REDIRECT=false
   configs:
     - source: cowrie_userdb
       target: /cowrie/cowrie-git/etc/userdb.txt

configs:
 cowrie_userdb:
   content: |
     root:x:foobar

Пробуем. Теперь проходит только пароль foobar.

NOTE: просто так пользователя написать не получится, его надо добавить в /etc/passwd

Сейчас это сделаем вместе с кастомной файловой системой.

Предлагаю стыбзить из alpine. Мой пользователь будет называться myuser:

docker run --rm -it -v $(realpath .)/fake_fs:/mnt alpine
/ # adduser myuser
/ # su myuser
/ $ cd
~ $ echo 'https://bit.ly/4kW5tWu' > passwords.txt
~ $ exit
/ # apk add rsync
/ # rsync -aAXv --exclude='/mnt/' --exclude='/proc' --exclude='/sys' --exclude='/dev' / /mnt/
/ # exit

Теперь в папке fake_fs есть настоящая файловая система из alpine. Сгенерим для нее pickle, как того хочет cowrie. Для этого придется установить проект. Предлагаю сделать это в докере:

docker run --rm -it -v $(realpath .)/fake_fs:/mnt debian:12
root@28e2b4e21a38:/# apt update
root@28e2b4e21a38:/# apt install -y git python3-venv libssl-dev libffi-dev build-essential libpython3-dev python3-minimal authbind
root@28e2b4e21a38:/# git clone [http://github.com/cowrie/cowrie](http://github.com/cowrie/cowrie)
root@28e2b4e21a38:/# cd cowrie/
root@d839f6e7c392:/cowrie# python3 -m venv cowrie-env
root@d839f6e7c392:/cowrie# source cowrie-env/bin/activate
(cowrie-env) root@d839f6e7c392:/cowrie# python -m pip install --upgrade pip
(cowrie-env) root@d839f6e7c392:/cowrie# python -m pip install --upgrade -r requirements.txt

Теперь генерим picke (это пока в том же контейнере):

(cowrie-env) root@d839f6e7c392:/cowrie# ls /mnt/
bin  etc  home lib  media  opt  root  run  sbin  srv  tmp  usr  var
(cowrie-env) root@d839f6e7c392:/cowrie# bin/createfs -l /mnt/ -d 9 -o /mnt/custom.pickle

Пока все рядом, можем запустить редактор виртуальной файловой системы. Удалю оттуда маковский мусор из “/”

(cowrie-env) root@d839f6e7c392:/cowrie# bin/fsctl /mnt/custom.pickle
/mnt/custom.pickle
Kippo/Cowrie file system interactive editor
Donovan Hubbard, Douglas Hubbard, March 2013
Type 'help' for help
custom.pickle:/$ ls
.DS_Store
.dockerenv
bin/
etc/
home/
lib/
media/
opt/
root/
run/
sbin/
srv/
tmp/
usr/
var/
custom.pickle:/$ rm .dockerenv
Deleted /.dockerenv
custom.pickle:/$ rm .DS_Store
Deleted /.DS_Store
custom.pickle:/$ cd /home/myuser
custom.pickle:/home/myuser$ ls
.ash_history
passwords.txt
custom.pickle:/home/myuser$

Когда закончили - выходим (CTRL+D или команда “exit”).  Из контейнера тоже.

После этого перемещаем пикливанную (кто-то есть из Волгограда?) файловую систему поближе к докеру. Папку с файлами для генерации удалять нельзя, так как она будет использоваться для содержимого файлов. Pickle содержит только метаданные.

/Users/ColCh/Workspace/cowrie-setup
 13:16:44 ➜  mv fake_fs/custom.pickle ./

Теперь осталось добавить этот файл в контейнер cowrie (и папку с файловой системой). Заодно поставим пароль для пользователя myuser:

services:
 cowrie:
   image: cowrie/cowrie
   container_name: cowrie
   ports:
     - "2222:2222"
   volumes:
     - ./custom.pickle:/custom.pickle:ro
     - ./fake_fs:/fake_fs:ro
   environment:
     - COWRIE_HONEYPOT_HOSTNAME=droplet
     - COWRIE_HONEYPOT_TIMEZONE=Europe/Moscow
     - COWRIE_HONEYPOT_FAKEADDR=192.168.1.26
     - COWRIE_SHELL_KERNEL_VERSION=6.8.1-4-amd64
     - COWRIE_SHELL_KERNEL_BUILD_STRING="#1 SMP Debian 6.8.11-1+deb12u1"
     - COWRIE_SSH_SFTP_ENABLED=false
     - COWRIE_SSH_FORWARDING=false
     - COWRIE_SSH_FORWARD_REDIRECT=false
     - COWRIE_HONEYPOT_CONTENTS_PATH=/fake_fs
     - COWRIE_SHELL_FILESYSTEM=/custom.pickle
   configs:
     - source: cowrie_userdb
       target: /cowrie/cowrie-git/etc/userdb.txt

configs:
 cowrie_userdb:
   content: |
     myuser:x:secret

Пробуем:

~/Workspace/cowrie-setup  took 1s18ms
 14:12:45 ➜  ssh -o "UserKnownHostsFile=/dev/null" -o "StrictHostKeyChecking no" -p 2222 myuser@127.0.0.1
myuser@127.0.0.1's password:
Welcome to Alpine!
The Alpine Wiki contains a large amount of how-to guides and general
information about administrating Alpine systems.
See <https://wiki.alpinelinux.org/>.
You can setup the system with the command: setup-alpine
You may change this message by editing /etc/motd.
myuser@droplet:~$
passwords.txt .ash_history
myuser@droplet:~$ cat passwords.txt
https://bit.ly/4kW5tWu
myuser@droplet:~$

Работает!

Дома я пока ограничился только файловой системой. Еще cowrie умеет выводить prompt в shell, делать моковые команды, сохранять то, что передали по scp для анализа), использовать настоящую виртуалку в qemu, прокси… но мне пока хватит.

Теперь приступим к дашборду. Но перед этим хотел бы еще одну штуку рассказать, интересную, как по мне.

asciinema

Asciinema это сервис, куда можно выгрузить “запись” терминала. Это будто бы снимали экран, но на самом деле это записанная последовательность действий внутри терминала и вывод команд. Чтобы туда эту запись загрузить, надо ее сначала правильно записать.

Cowrie умеет это делать. В логах будет встречаться вот такое:

{"eventid":"cowrie.log.closed","ttylog":"var/lib/cowrie/tty/c8081c94dbbbf06e9e1e28867806864acdeb0447f133c8437cf9a74f8eef3e6d","size":381,"shasum":"c8081c94dbbbf06e9e1e28867806864acdeb0447f133c8437cf9a74f8eef3e6d","duplicate":false,"duration":"5.9","message":"Closing TTY Log: var/lib/cowrie/tty/c8081c94dbbbf06e9e1e28867806864acdeb0447f133c8437cf9a74f8eef3e6d after 5.9 seconds","sensor":"ca404c2fe14b","timestamp":"2025-03-23T14:16:11.319573+0000","src_ip":"172.21.0.1","session":"bfdabc03ec02"}

Если этот файлик скачать к себе на комп, его можно локально проиграть. Чтобы не качать проект cowrie локально, я буду использовать docker, где войду в контейнер cowrie и вызову команду. Cowrie не имеет shell, поэтому буду использовать debian.

Из лога выше файл лежит в var/lib/cowrie/tty/c8081c94dbbbf06e9e1e28867806864acdeb0447f133c8437cf9a74f8eef3e6d

Абсолютный путь будет: /cowrie/cowrie-git/var/lib/cowrie/tty/c8081c94dbbbf06e9e1e28867806864acdeb0447f133c8437cf9a74f8eef3e6d

Ну и проиграть прямо в текущем терминале можно так:

docker compose exec -it cowrie /cowrie/cowrie-env/bin/python3 /cowrie/cowrie-git/bin/playlog -c -b -m 1.0 /cowrie/cowrie-git/var/lib/cowrie/tty/c8081c94dbbbf06e9e1e28867806864acdeb0447f133c8437cf9a74f8eef3e6d

А закинуть на asciinema вот так (ток надо сначала установить):

asciinema upload <( docker compose exec -it cowrie /cowrie/cowrie-env/bin/python3 /cowrie/cowrie-git/bin/asciinema /cowrie/cowrie-git/var/lib/cowrie/tty/3985077e433ea3cbc0fbe4f0ba8bd6d608b6f28fdae3ba7ad1e815cc75af997b )

https://asciinema.org/a/TbAtG45c4VoV4lfG8RJlYFQ3y

Здорово. Теперь к дашборду.

Дашборд на логах

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

Пример логов, которые cowrie пишет в терминал:

cowrie  | 2025-03-23T13:31:35+0000 [HoneyPotSSHTransport,0,172.21.0.1] Initialized emulated server as architecture: linux-x64-lsb
cowrie  | 2025-03-23T13:31:35+0000 [cowrie.ssh.userauth.HoneyPotSSHUserAuthServer#debug] b'myuser' authenticated with b'password'
cowrie  | 2025-03-23T13:31:35+0000 [cowrie.ssh.transport.HoneyPotSSHTransport#debug] starting service b'ssh-connection'
cowrie  | 2025-03-23T13:31:35+0000 [cowrie.ssh.connection.CowrieSSHConnection#debug] got channel b'session' request
cowrie  | 2025-03-23T13:31:35+0000 [cowrie.ssh.session.HoneyPotSSHSession#info] channel open
cowrie  | 2025-03-23T13:31:43+0000 [HoneyPotSSHTransport,0,172.21.0.1] CMD: cat passwords.txt
cowrie  | 2025-03-23T13:31:43+0000 [HoneyPotSSHTransport,0,172.21.0.1] Command found: cat passwords.txt

Здорово, но не очень читабельно для компьютера. Cowrie умеет писать логи в формате JSON, они лежат по определенному пути. Вытащить их можно так (compose.yml):

services:
 cowrie:
   …
   volumes:
     - ./logs/:/cowrie/cowrie-git/var/log/cowrie

Сам он файл не сможет создать, поэтому надо помочь:

mkdir logs
touch logs/cowrie.json

Если тестируете на MacOS, скорее всего, не будет хватать прав из-за UID/GID. Можно временно закостылить так:

chmod 666 logs/cowrie.json

На хомлабе права у директории вот такие:

chmod -R 0764 logs
chown -R 999:999 logs

Примеры логов (вот тут документация по логам):

{"eventid":"cowrie.session.connect","src_ip":"172.21.0.1","src_port":41966,"dst_ip":"172.21.0.2","dst_port":2222,"session":"bfdabc03ec02","protocol":"ssh","message":"New connection: 172.21.0.1:41966 (172.21.0.2:2222) [session: bfdabc03ec02]","sensor":"ca404c2fe14b","timestamp":"2025-03-23T14:16:03.314456+0000"}
{"eventid":"cowrie.login.failed","username":"myuser","fingerprint":"8c:42:29:26:4b:cc:ab:76:f1:0f:d0:94:ce:7d:db:c1","key":"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICFpiZP85S4X5kIAsIW0WPOoeqBCUA9CdPnVbmfkUQMt","type":"ssh-ed25519","message":"public key login attempt for [myuser] failed","sensor":"ca404c2fe14b","timestamp":"2025-03-23T14:16:03.347539+0000","src_ip":"172.21.0.1","session":"bfdabc03ec02"}
{"eventid":"cowrie.login.success","username":"myuser","password":"secret","message":"login attempt [myuser/secret] succeeded","sensor":"ca404c2fe14b","timestamp":"2025-03-23T14:16:05.328592+0000","src_ip":"172.21.0.1","session":"bfdabc03ec02"}
{"eventid":"cowrie.command.input","input":"echo 'hello world'","message":"CMD: echo 'hello world'","sensor":"ca404c2fe14b","timestamp":"2025-03-23T14:16:10.590840+0000","src_ip":"172.21.0.1","session":"bfdabc03ec02"}
{"eventid":"cowrie.session.closed","duration":"8.0","message":"Connection lost after 8.0 seconds","sensor":"ca404c2fe14b","timestamp":"2025-03-23T14:16:11.341929+0000","src_ip":"172.21.0.1","session":"bfdabc03ec02"}

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

Сделать это можно двумя шагами (есть и другие варианты, я бы с удовольствием перестал юзать promtail, но не сегодня):

Сначала качаем базку с айпишниками ака GeoIP, я использую maxmind/geoipupdate (бесплатное):

   geoipupdate:
       container_name: geoipupdate
       image: ghcr.io/maxmind/geoipupdate
       restart: always
       env_file: [.env]
       environment:
           # GEOIPUPDATE_ACCOUNT_ID=SEE_ENV
           # GEOIPUPDATE_LICENSE_KEY=SEE_ENV
           - 'GEOIPUPDATE_EDITION_IDS=GeoLite2-ASN GeoLite2-City GeoLite2-Country'
           - GEOIPUPDATE_FREQUENCY=72
       volumes:
           - ./data:/usr/share/GeoIP

Account ID и License Key можно взять у них после регистрации

скриншот аккаунта maxmind
скриншот аккаунта maxmind

Супер! Теперь добавим геодату к айпишникам. Для этого я использую promtail

Контейнер:

promtail:
   image: grafana/promtail
   restart: always
   expose:
       - 9080
   healthcheck:
       test: ["CMD-SHELL", "grep -q 'promtail' /proc/*/cmdline"]
   volumes:
       - ./logs/:/var/log/cowrie:ro
       - ./promtail.yml:/etc/promtail/promtail.yml:ro
       - ./promtail-data:/var/promtail
       - ../geoip/data/:/usr/share/GeoIP:ro
   command:
       - "--config.file=/etc/promtail/promtail.yaml"
       - "--config.expand-env=true"
   configs:
       - source: promtail-config
       target: /etc/promtail/promtail.yaml

configs:
 promtail-config:
   file: ./promtail.yml

Его конфижик, promtail.yml (NOTE: victorialogs:9428 - это я использую для логов):

server:
 http_listen_address: 0.0.0.0
 http_listen_port: 9080
 log_level: warn

positions:
 filename: "/var/promtail/positions.yaml"

clients:
 - url: http://victorialogs:9428/insert/loki/api/v1/push?_msg_field=message&_stream_fields=instance,job

scrape_configs:
 - job_name: cowrie
   static_configs:
     - targets:
         - localhost
       labels:
         job: cowrie
         __path__: /var/log/cowrie/cowrie.json
         instance: cowrie-promtail
   pipeline_stages:
     - json:
         expressions:
           timestamp: timestamp
           src_ip: src_ip
     - timestamp:
         source: timestamp
         format: 2025-02-25T12:57:07.457597+0100
     - geoip:
         db: /usr/share/GeoIP/GeoLite2-City.mmdb
         source: src_ip
         db_type: "city"
         output:
           geoip_country: country.iso_code
           geoip_city: city.names.en
           geoip_latitude: location.latitude
           geoip_longitude: location.longitude
     - labels:
         src_ip:
         geoip_country:
         geoip_city:
         geoip_latitude:
         geoip_longitude:

После этого данные можно увидеть в VictoriaLogs (это уже реальный лог из хомлабы):

{
   "_time": "2025-03-22T00:00:06.054139657Z",
   "_stream_id": "000000000000000068c424eea7c92cf2604a6c7c64ce0180",
   "_stream": "{instance=\"cowrie-promtail\",job=\"cowrie\"}",
   "_msg": "New connection: 182.92.68.168:41692 (172.31.3.130:2222) [session: 4de4bf864d44]",
   "filename": "/var/log/cowrie/cowrie.json",
   "instance": "cowrie-promtail",
   "job": "cowrie",
   "sensor": "cowrie",
   "dst_ip": "172.31.3.130",
   "dst_port": "2222",
   "eventid": "cowrie.session.connect",
   "geoip_city_name": "Beijing",
   "geoip_continent_code": "AS",
   "geoip_continent_name": "Asia",
   "geoip_country_name": "China",
   "geoip_location_latitude": "39.911",
   "geoip_location_longitude": "116.395",
   "geoip_subdivision_code": "BJ",
   "geoip_subdivision_name": "Beijing",
   "geoip_timezone": "Asia/Shanghai",
   "protocol": "ssh",
   "session": "4de4bf864d44",
   "src_ip": "182.92.68.168",
   "src_port": "41692",
   "timestamp": "2025-03-22T01:00:06.016764+0100"
 },

По вот этим geoip_* в Grafana можно построить вот такую карту

geomap в графане
geomap в графане

Как?

Я не буду расписывать прям весь дашборд (его я просто скину), расскажу только про карту.

Сначала надо выгрепать логи:

{instance="cowrie-promtail"} "New connection"

Вот так вот:

grafana table view
grafana table view

Далее делаем некоторую магию в Transformations, чтоб fields стали labels. И убираем всякие поля, оставляем только широту и долготу, указываем имена полей с координатами, как сказано в документации Grafana

grafana transformations
grafana transformations

Указываю на имена полей с широтой и долготой

geomap settings
geomap settings

et voila теперь в таблице получится что-то такое (ну и если переключить Table View, то заработает карта с heatmap)

result table view
result table view

Сам дашборд можно скачать тут готовый: https://grafana.com/grafana/dashboards/23141

Вообще можно было на этом остановиться, но для полного набора не хватает баньки… от слова BAN.

И тут на сцену выходит Crowdsec

Crowdsec

Что это такое? https://www.crowdsec.net

Если своими словами, то:

  • С одной стороны – это антифрод на основе логов (блочим плохих юзеров.
  • С другой – это распределенный fail2ban (один “микросервис” вычитывает логи, другой банит, третий закрывает доступ до траффика забаненым айпишникам), с возможностью шарить блок листы*

* - как другим пользователями, так и компании, конечно же.

Вот такая схемка у них в доке есть:

crowdsec overview
crowdsec overview

Есть вот такие компоненты – в скобочках термины из Crowdsec:

  • Агенты (agents) ака машины (machines) - анализируют логи, выполняют решение (Decisions) при каких-либо сценариях (Crenarios) (напр. Кто-то пытался авторизоваться 10 раз за 1 минуту - баним на час), шлет алерты в LAPI
  • LAPI (Local API) - координатор, хранилище конфигурации, блоклистов. Связывается с CAPI (Central API) - серверами CrowdSec (напр. чтоб скачать блок листы)
  • Bouncer - по конфигурации из LAPI, выполняет действие над нарушителем - например, может через cloudflare показать капчу, или (если это на фаерволле) - забанить входящий траффик от нарушителя

Статья не об crowdsec, но если хочется узнать поподробнее, прошу написать в комментах :) Предположим, что у вас уже он настроен, и Вы бы хотели интегрировать туда cowrie.

Итак, давайте сделаем так, чтобы при соединении по SSH в ханипот - IP адрес банило на какое-то время.

У crowdsec уже есть готовая коллекция, но она использует формат логов у cowrie НЕ-JSON (еще есть невлитый PR), поэтому тут будет 2 стула: либо мы парсим logfmt логи через VictoriaLogs, либо мы пишем свой парсер логов для crowdsec. Я выбрал второе. Если интересуют детали того, что за опции в yml (и как это протестить), прошу в доку crowdsec.

Сам парсер лежит по пути: /crowdsec/parsers/cowrie.yaml

# yaml-language-server: $schema=https://raw.githubusercontent.com/crowdsecurity/crowdsec-yaml-schemas/refs/heads/main/parser_schema.yaml
---
# Custom parser for Cowrie JSON logs
onsuccess: next_stage
name: cowrie-json-log
description: "Parse Cowrie honeypot JSON logs and extract connection details"
filter: "evt.Parsed.program == 'cowrie-json-log'"
# filter: 1 == 1
# debug: true
nodes:
 - grok:
     pattern: 'New connection: %{IPV4:src_ip}:[0-9]+ \(%{IPV4:dst_ip}:%{INT:dst_port}\) \[session: %{DATA:session}\]'
     expression: JsonExtract(evt.Parsed.message, "message")
statics:
 - meta: service
   expression: "evt.Parsed.protocol"
 - meta: log_type
   value: "cowrie.session.connect"
 - meta: source_ip
   expression: "evt.Parsed.src_ip"
 - meta: dest_ip
   expression: "evt.Parsed.dst_ip"
 - meta: dest_port
   expression: "evt.Parsed.dst_port"
 - parsed: session_id
   expression: "evt.Parsed.session"

Далее сценарий. Лежит по пути: scenarios/cowrie-ssh-ban.yaml

# https://docs.crowdsec.net/docs/scenarios/format/
---
type: trigger
name: "cowrie/ssh-ban"
description: "Ban any IP that makes a connection to the SSH honeypot (Cowrie)."
filter: "evt.Meta.log_type == 'cowrie.session.connect'"
groupby: evt.Meta.source_ip
blackhole: 744h # 31 days
labels:
 service: ssh
 confidence: 3
 spoofable: 0
 classification:
   - attack.T1110
 label: "SSH Bruteforce"
 behavior: "ssh:bruteforce"
 remediation: true

Дальше можем это добро запустить вот так (считаю, что crowdsec уже используется в хомлабе и LAPI уже есть и настроено):

 crowdsec:
   image: crowdsecurity/crowdsec
   restart: always
   healthcheck:
     test: ["CMD", "cscli", "lapi", "status"]
   environment:
     PARSERS: "crowdsecurity/cowrie-logs"
     LEVEL_INFO: "true"
     # LEVEL_DEBUG: 'true' # Force DEBUG level for the container log
     # LEVEL_TRACE: 'true' # Force TRACE level (VERY verbose) for the container log
     DISABLE_LOCAL_API: "true"
     LOCAL_API_URL: "http://crowdsec-lapi:8080/"
     CUSTOM_HOSTNAME: "cowrie-crowdsec"
     # ТУТ ВАШЕ
     # AGENT_USERNAME
     # AGENT_PASSWORD"
   volumes:
     - /etc/localtime:/etc/localtime:ro
     - ./crowdsec/acquis.yaml:/etc/crowdsec/acquis.yaml:ro
     - ./cowrie-var/log/cowrie:/var/log/cowrie/:ro
     - ./crowdsec/db:/var/lib/crowdsec/data/
     - ./crowdsec/config:/etc/crowdsec/
     - ./crowdsec/parsers/cowrie.yaml:/etc/crowdsec/parsers/s01-parse/cowrie-logs-json.yaml:ro
     - ./crowdsec/scenarios/cowrie-ssh-ban.yaml:/etc/crowdsec/scenarios/cowrie-ssh-ban.yaml:ro

Заключение

That’s all folks!

Живу с ханипотом примерно месяц и вот, что бы я порекомендовал:

Ограничить доступы у контейнера и его ресурсы:

   cpu_count: 1
   mem_limit: 512m
   cap_drop:
     - ALL
   security_opt:
     - no-new-privileges:true
   tmpfs:
     - /tmp/cowrie:uid=999,gid=999
     - /tmp/cowrie/data:uid=999,gid=999

Еще было бы круто ему поставить “read_only: true”, но тут у меня закончилось желание и время.

Также на этом порту микротик троттлит трафик:

mikrotik throttle
mikrotik throttle

Но я бы не сказал, что это прям нужно:

mikrotik stats
mikrotik stats

Crowsec довольно часто кого-то банит, вот его же дашборд:

crowdsec own dashboard
crowdsec own dashboard

И его еще один дашборд из админ панельки

crowdsec hub dashboards
crowdsec hub dashboards

Что еще можно почитать про настройку cowrie: https://cryptax.medium.com/customizing-your-cowrie-honeypot-8542c888ca49

Надеюсь, это кому-то пригодится. Удачи в настройке приманки в вашей домашней лаборатории!

Аватар Максим Сысоев
Максим Сысоев @ColCh
Senior Software Eng ManagerMicrosoft, ex-Yandex
📍Белград, Сербия

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

линкедин (только рабочее) https://www.linkedin.com/in/colch/

моя телега (только личное) https://t.me/colch

инстаграмм дать не могу, он только для родственников :)

4 комментария 👇

как искусство это весело, но я не готов столько ресурсов виртуалки отдавать под это дело

ставлю себе всегда endlessh (у тебя как раз он упомянут), и раз в пару месяцев смотрю логи для внутреннего удовлетворения

  Развернуть 1 комментарий

@TiraelSedai, она вроде не так много жрет, если пользоваться только ей

stats для cowrie:

CPU %                0.00%
MEM USAGE / LIMIT    49MiB / 256MiB
NET I/O              68.8MB / 63.4MB
BLOCK I/O            56.2MB / 180MB

много всякого вокруг неё - логи, дашборд, баны... это всё опционально :)

  Развернуть 1 комментарий

@ColCh, ну учитывая что на многих виртуалках 500 или 1000 рам, а endlessh жрёт 4 мб, то разница существенная как есть. ну а если не ставить дашборды то зачем это всё?

  Развернуть 1 комментарий

@TiraelSedai, да, fair point. если задача - просто пассивно отвлекать сканеры и не тратить ресурсы - endlessh идеально для этого подходит

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

с дашбордами, бэками и логами - получается целый маленький проект. не каждому нужно

  Развернуть 1 комментарий

😎

Автор поста открыл его для большого интернета, но комментирование и движухи доступны только участникам Клуба

Что вообще здесь происходит?


Войти  или  Вступить в Клуб