Однажды у меня появилась идея. Эта идея воплотилась в проекте PiAlert. Узнать о том, что это такое, вы можете из этого видео. Если рассказать о PiAlert в двух словах, то окажется, что это устройство, на котором, если происходят попытки вторжения на серверы, загораются разноцветные лампочки. Система подсчитывает общее количество таких событий. Я, в основном, наблюдал за попытками подключения к 22 (SSH) порту моих серверов. Обычно эти события являются результатом деятельности ботов. За сутки на одном из моих
А вот — несколько снимков.
Выключенное устройство, вид спереди
Выключенное устройство, вид сбоку
Должен сказать, что то, что у меня получилось, в лучшем случае можно назвать альфа-версией устройства. Код проекта и модель для 3D-печати корпуса я выложил в общий доступ в надежде на то, что если мой проект кого-то заинтересует, мне помогут его улучшить для всеобщего блага.
Обзор проекта
После недавнего происшествия с одним из моих серверов я понял, что мне очень нравится рыться в логах и разбираться в том, что произошло. Обычно я пользуюсь такими командами:
tail -n 80 -f /var/log/apache2/error.log
tail -n 80 -f /var/log/apache2/access.log
tail -n 80 -f /var/log/auth.log
Интересно наблюдать за тем, к каким страницам пытаются обратиться неизвестно откуда взявшиеся боты, или за тем, в какие учётные записи они пытаются войти через SSH. А ещё всё это напоминает хакерские фильмы. Тогда я подумал, что мог бы создать что-то, выглядящее гораздо привлекательнее окна терминала. В этот момент и родился проект, о котором я тут рассказываю.
Результаты наблюдения за попытками входа в систему в последнее время изменились. Случилось это после того, как я внедрил более строгую процедуру входа. А именно, количество попыток войти в систему сильно снизилось. Это стало очевидным после того, как созданная мной система наблюдения за серверами проработала 24 часа. Ниже я об этом расскажу.
Этот материал включает в себя три раздела. В первом речь идёт об аппаратном обеспечении, во втором — о настройке серверов, в третьем — о программах для Raspberry Pi.
Аппаратное обеспечение
Моё устройство собрано из следующих компонентов:
- Плата Raspberry Pi Zero W.
- Светодиодная панель Pimoroni Blinkt!.
- Дешёвый 7-сегментный дисплей на 4 цифры (белый) с AliExpress.
Вот схема подключения.
Схема подключения компонентов к плате
Для подключения к Raspberry Pi светодиодной панели Blinkt! были использованы соединительные провода DuPont. С одной стороны я их обрезал и припаял к соответствующим выводам 40-контактного GPIO-порта панели. Я не мог подключить его напрямую к плате, так как мне ещё нужно было подключить к ней дисплей.
Для того чтобы заставить панель работать мне понадобилось немало времени. Поначалу я думал, что мой экземпляр страдает от плохих соединений в коннекторе. И мне, чтобы с этим разобраться, пришлось, идя путём проб и ошибок, потратить гораздо больше времени, чем мне хотелось бы на это тратить. После того, как я обратился в Pimoroni через Twitter, оказалось, что ранние версии Blinkt! используют для 5V пин №2, а не №4, как показано на pinout.xyz. Я, правда, пока это не выяснил, в спешке заказал ещё одну светодиодную панель Blinkt!, на тот случай, если моя оказалась бы нерабочей. А теперь, после того, как удалось запустить первую, мне надо подумать над новым проектом, в котором можно было бы использовать вторую.
Все эти компоненты я разместил в корпусе, который я спроектировал в Tinkercad. Корпус был напечатан на моём 3D-принтере Ender 3 Pro. Корпус у меня получился, но я так и не смог додуматься до того, как сделать его части такими, чтобы они или плотно входили бы друг в друга, или крепились бы друг к другу защёлками. В итоге я сформировал на одной из частей корпуса пару столбиков, рассчитанных на винты M5, которые я использовал для сборки готового устройства. Эти столбики размещены по краям, так, чтобы в корпусе хватило бы места для Raspberry Pi.
Для печати корпуса я использовал PLA-пластик неизвестного производителя (температура печати — 217°C, величина заполнения — 10%). Я применял обычные настройки, которые подобрал после просмотра различных видео на YouTube.
Результаты нескольких попыток печати корпуса
Сборка корпуса
Создать прилично выглядящую переднюю панель корпуса мне удалось лишь с девятой попытки. Каждый раз, когда я её печатал, оказывалось, что что-то надо слегка переместить, или что где-то, пусть и немного, надо что-то подправить. Я пользовался Tinkercad лишь несколько раз, редактируя модель, и мне пришлось практически сначала начинать работу над ней. Я хотел закрепить светодиодную панель Blinkt! с использованием защёлок, но после нескольких неудачных попыток отказался от этой идеи и решил вопрос с помощью клеевого пистолета (люблю я эту штуку!). Им же я, в итоге, закрепил и дисплей, и саму плату Raspberry Pi. Завершая работу над корпусом, я решал вопрос, касающийся размещения в нём платы. Поначалу я никак плату в корпусе не закреплял, но из-за этого подключение к ней USB-кабеля превратилось в настоящее приключение. В итоговом варианте корпуса (если вообще можно говорить о том, что какой-то его вариант будет «итоговым») мне хотелось бы избавиться от винтов, от отверстий для них и от столбиков внутри корпуса, и найти способ соединения частей корпуса, например, с помощью защёлок. Если кто-то хочет поучаствовать в работе над корпусом и всё в нём поменять — милости прошу! А мне ещё хочется закрыть переднюю панель корпуса чем-то вроде полупрозрачного стекла или куска акрила. Это придало бы устройству законченный вид, скрыв слишком «технические» детали.
Плата Raspberry Pi, на которой основан этот проект, уже использовалась в другом проекте, в котором нужно было, чтобы 40-пиновый GPIO-порт был бы смонтирован с обратной стороны платы. Это, как оказалось, стало плюсом. Плата намертво закреплена в корпусе, в других проектах я её, вероятно, использовать уже не буду. Поэтому некоторые пины я согнул для того чтобы лучше всё разместить в корпусе.
Всё поместилось!
В конце у меня возникла ещё одна идея, которая заключается в том, что мне следует оснастить устройство хотя бы парой кнопок. Может, даже не выводить их наружу, а просто скрыть их где-то в корпусе. Одна нужна для переключения между разными типами зафиксированных атак и для вывода их количества. А вторая должна, коротким нажатием, выключать дисплей, а длинным — аккуратно завершать работу Raspberry Pi. Если нужно, к моему устройству всегда можно подключиться по SSH, а если мне очень понадобится, я могу создать URL-маршрут, вызывающий команду sudo halt
.
Настройка серверов
Я, когда после вышеупомянутого происшествия занимался усилением защиты серверов и наладкой мониторинга, проверил, чтобы на них была бы установлена программа fail2ban. Это — замечательный FOSS-проект. Fail2ban наблюдает за логами на сервере и записывает сведения о чём-то таком, что, в нормальных условиях, происходить не должно, вроде множественных неудачных попыток входа на сервер по SSH. Далее, программа банит IP-адрес, с которого исходят подозрительные запросы, делая это в том случае, если речь идёт о потенциально серьёзной проблеме, или если некие события повторяются в течение заранее заданного промежутка времени. По умолчанию fail2ban наблюдает за SSH-трафиком, но программу можно настроить и так, чтобы она присматривала и за чем-то другим, вроде количества ошибок 404 или числа неудачных попыток входа в панель администратора WordPress-проекта.
Fail2ban позволяет создавать собственные действия, вызываемые при возникновении различных событий. Оказалось, что это сложнее, чем нечто вроде простого выполнения curl-запроса, поэтому я, в итоге, обратился за помощью на GitHub. Мне, что бы я ни делал, не удавалось заставить систему работать так, как надо. Для того чтобы вам было легче решить похожую задачу, расскажу о том, как мне, в итоге, удалось всё настроить. А именно, речь идёт об использовании fail2ban на сервере, основанном на Debian.
Создадим файл jail.local
и добавим в него следующее:
[sshd]
enabled = true
port = ssh
banaction = pinotifyred[myhost="SCRIPTHOSTSERVER"]
Здесь SCRIPTHOSTSERVER
надо заменить на подходящий URL (например — на dev.testing:8080
). Обратите внимание на то, что в начале этого URL нет сведений о протоколе, в конце нет пути, адрес не должен завершаться косой чертой.
В результате окажется, что в нашем распоряжении останутся обычные действия, связанные с SSHD, программа продолжит банить подозрительные IP-адреса, но мы ещё и сможем создавать дополнительные действия. К сожалению, нельзя просто описать команду, которая будет здесь выполняться (в этом и заключалась моя проблема). Вместо этого нужно сообщить системе о том, какое именно действие требуется выполнить. Действие вызывается из файла, хранящегося в папке action.d
. Имена .conf-файлов в этой папке соответствуют именам действий (в нашем случае это pinotifyred.conf
). Вот как выглядят такие файлы:
[Definition]
# отправка get-запроса вроде "http://example.com/red"
actionban = curl --fail "http://<my-host>/red" >> /dev/null
[Init]
# это надо переписать в jail-файл в виде параметра действия:
my-host = SCRIPTHOSTSERVER
Тут, опять же, надо поменять SCRIPTHOSTSERVER
на подходящий URL (вроде dev.testing:8080
), придерживаясь тех же правил, о которых шла речь выше, в описании файла jail.local
.
Код вызывает действие и меняет переменную my-host
. Мне не удалось заставить всё это работать без такой переменной.
Этот код выполняет необходимую команду. В нём объявлены некоторые переменные, которые нужны для работы fail2ban. Кроме того, то, как это всё настраивается, означает, что у нас имеется возможность отправлять curl- или wget-запросы с разными параметрами. Среди этих параметров, например, могут быть сведения о том, какой именно IP был забанен, и о том, когда именно это произошло. Поэтому если вам хочется получать более подробные сведения об атаках, чем, как в моём случае, лишь данные об их количестве, вы можете этим воспользоваться. А именно, чтобы это сделать, вы можете разместить в папке action.d
файл примерно такого содержания:
[Definition]
#отправляет get-запрос вроде "http://example.com/ban.php?jail=sshd&ip=192.0.2.100":
actionban = curl -G --data-urlencode "jail=%(name)s" --data-urlencode "ip=" --fail "http://<my-host>/ban.php"
[Init]
# это надо переписать в jail-файл в виде параметра действия:
my-host = SCRIPTHOSTSERVER
Мне хотелось бы заметить, что тут, вероятно, имеется ошибка, так как действие вызывается дважды — когда IP-адрес блокируется и когда разблокируется. Я планирую заняться этим позже, возможно, это приводит к удвоению показателей о количестве атак.
Программы для Raspberry Pi
Буду честен: мой код — это полный бардак. Он написан на Python 3 человеком (мной), который не знает Python, но умеет искать ответы на вопросы в интернете. Это, дополненное общими знаниями в области программирования, позволило мне написать программу на Python.
Я не будут тут рассказывать о подготовке Raspberry Pi к работе по SSH, так как об этом уже много кто рассказывал. Код, о котором идёт речь, размещён на GitHub. Он представлен парой файлов. Первый файл — это pialert.py
, он запускается при загрузке системы. Второй файл, tm1637.py
, это библиотека, которую я взял из этого материала с сайта RaspberryTips.
Моя Python-программа работает как HTTP-сервер (знаю, она — не для продакшна, но, всё же, речь идёт о простом домашнем проекте), прослушивающий все запросы. Это — однопоточная программа, поэтому если запросов будет очень много, она, скорее всего, с ними не справится. Программа ожидает поступления URL, и если он в ней зарегистрирован, она выполняет действие. Действие — это включение светодиода на Blinkt!, выполняемое в стиле «Larson Scanner», и увеличение показателя счётчика. От URL зависит выбор цвета светодиодов.
Я использую 4 цвета:
- Синий — указывает на атаку, совершённую на мой WordPress-сайт.
- Красный — SSH-атака на сервер A.
- Фиолетовый — SSH-атака на сервер B.
- Зелёный — URL-атака на сервер C.
Возможно, я, со временем, расширю набор атак, регистрируемых устройством. Но даже то, что есть сейчас, позволяет быть в курсе событий, не подключаясь при этом к серверам.
В моём коде не обрабатываются ошибки, не контролируется возможное переполнение счётчика. Программа, кроме прочего, показывает мне, что даже моя домашняя сеть постоянно подвергается атакам в виде запросов по особым URL. Атакующие пытаются получить доступ к сети через любую обнаруженную ими уязвимость (из-за этого возникают исключения, но программу это не останавливает).
Одна из последних задач, которую мне нужно было решить в ходе работы над проектом, заключалась в настройке Raspberry Pi. А именно, мне было нужно, чтобы плата, сразу после загрузки, запускала бы скрипт, и чтобы потом всё просто работало. Решается эта задача путём редактирования файла /etc/rc.loca
l. Я, пользуясь редактором vi, добавил в файл команду, которая обычно используется для запуска программ:
python3 /home/pi/PiAlert/pialert.py &
После этого мне осталось решить лишь одну задачу. Она заключалась в том, чтобы обеспечить бесперебойный доступ моих
Итоги
Демонстрация работы устройства
PiAlert — это устройство, которое нельзя сравнивать с какой-нибудь крутейшей хакерской штукой из фильмов. Его цель — напоминать о том, что каждый день тысячи ботов пытаются получить доступ к чему-то такому, к чему у них доступа быть не должно. Созданное мной устройство просто переносит сведения о подобных попытках в реальный мир, напоминая нам о них. Оно, кроме того, получилось довольно симпатичным.
Что ещё хорошего я могу сказать о PiAlert? Устройство выглядит нейтрально и является весьма гибким. Если я решу, что оно, в его существующем виде, мне больше не нужно, я могу переписать код и превратить его в часы. Или могу сделать из него счётчик посещений страниц моего сайта. На самом деле — есть масса вариантов использования RGB-светодиодов и дисплея, способного выводить 4 цифры. Кроме того, устройство у меня получилось компактное. Оно стоит передо мной на столе когда я пишу код и напоминает мне о том, что в мире есть люди, которые занимаются нехорошими делами. PiAlert для работы нужно совсем немного энергии, поэтому устройство вполне может работать от батарей. Его можно разместить где угодно в доме, главное — чтобы оно могло бы подключиться к WiFi-сети. Там оно будет просто делать своё дело. А если мне понадобится другая сеть — достаточно будет подключиться к Raspberry Pi по SSH или создать новый файл wpa_supplicant.conf
в /boot
.
В итоге хочу отметить, что мой код, конечно, выглядит не очень. Его можно и нужно отрефакторить. Если я когда-нибудь подучу Python — я это тут же сделаю. Корпус тоже можно улучшить и я, опять же, если освою какую-нибудь программу для 3D-моделирования, поработаю над корпусом. Но, если не брать это в расчёт, могу сказать, что я счастлив тем, что у меня получилось.
Планируете ли вы сделать устройство, напоминающее PiAlert?
Автор: ru_vds