Небольшой пример из практики на тему того, как ломают web сервера на Linux. А то некоторые думают, что под линуксом вирусов нет, или что Linux настолько безопасен, что его даже защищать не надо. В общем, показательная история из жизни. Ничего особенного, просто пример, которых наверняка много у любого админа, который работает с разработчиками.
На углубленном курсе "Архитектура современных компьютерных сетей" вы с нуля научитесь работать с Wireshark и «под микроскопом» изучите работу сетевых протоколов. На протяжении курса надо будет выполнить более пятидесяти лабораторных работ в Wireshark.
Пересылает мне утром владелец учетной записи в Hetzner информацию о том, что пришло уведомление, что у нас на одном из серверов подозрительная активность и его вырубят, если мы ничего не сделаем. Это тестовый сервер разработчика. Иду по ssh на сервер и вижу.
Вижу явный вирус. Думаю, что майнер какой-нибудь (на виртуалке за 3 евро, хе-хе). Смотрю дерево процессов, чтобы понять, откуда ноги растут.
Все понятно. На сервере стоит Docker. В нем контейнер Postgres. Вирус сидит в контейнере. Иду смотреть, как запущен контейнер. Ничуть не удивлен тем, что он смотрит напрямую в инет.
Дальше решил проверить, с какими параметрами он запущен. Опять не удивляюсь.
В лучших традициях жанра, все запущено с дефолтной учеткой postgres/postgres. Фраза fixme игнорируется.
Решил на всякий случай проверить прод. Захожу, а там все то же самое, но вируса пока нет. Не стал разбираться, чтобы ненароком не словить бан от Hetzner. Первую виртуалку просто удалили. На второй сразу поменяли пароль.
Вот так легко и просто взламываются веб сервера под Linux. Ожидали чего-то большего? Не нужны никакие хакеры, суперсофт и скилл. Достаточно взять какой-то сканер и найти открытые в инет службы. Затем проверить дефолтные пароли к ним и наверняка что-то подойдет. Разработчиков с каждым годом все больше и больше, докер контейнеров тоже. Так что ломать сервера будет все проще и проще.
Тут, конечно, есть недоработка докера. Он зачем-то по дефолту мапит контейнеры к 0.0.0.0, а не к локалхосту. Понятно, что так проще разработчикам, но результат налицо. Разработчики чаще всего не парятся над этим и даже не обращают внимание. Я постоянно вижу на dev серверах контейнеры с backend, смотрящие напрямую в инет. Так что надо обязательно вручную заблокировать доступ к контейнерам Docker из интернета.
В данном случае, достаточно было заблокировать доступ к postgres с помощью iptables:
/sbin/iptables -I DOCKER-USER -i eth0 -p tcp --dport 5432 -j DROP
Расскажите, встречались с похожими, простыми и очевидными факапами?
Научиться настраивать MikroTik с нуля или систематизировать уже имеющиеся знания можно на углубленном онлайн-курcе по администрированию MikroTik. Автор курcа – сертифицированный тренер MikroTik Дмитрий Скоромнов. Более 40 лабораторных работ по которым дается обратная связь. В три раза больше информации, чем в MTCNA.
Давно читаю ваш сайт. Вот было бы очень интересно почитать в вашем изложении статью про разворачивание сайта на хостинге. От аренды машины до рабочего сайта. со всеми нюансами настройки фаервола и иже с ним.
В современном IT создавать такие материалы не имеет большого смысла. Трудозатрат надо очень много, а через пол года часть материала уже будет неактуальной. Всё это нужно регулярно обновлять и поддерживать, что занимает много времени и сил. В рамках обычного сайта это нереально создать. Многие продавцы курсов, которые на этом зарабатывают, не могут себе позволить держать актуальными свои материалы.
Мне тут помогли, спасибо.
Мне не понятно, почему перед запуском чего угодно, особенно с выходом на 0.0.0.0 нельзя сменить данные учётной записи на корректные, для балбесов же написали "фих ме"!! Как так-то?? Сейчас всем знакомым фанатам докера эту статью покажу!!! Оленизм какой-то!
А полика iptables по-умолчанию DROP для INPUT , FORWARD не спасает? Пусть слушает все интерфейсы, а попадут только если разрешить?
Если не ошибаюсь, docker сам управляет iptables. Я не помню, какие он правила делает по умолчанию, но взаимодействовать с iptables нужно по его правилам, если нужна нормальная работа.
» встречались с похожими, простыми и очевидными факапами?
О. Нынче заходишь иногда на сервер, пишешь ifconfig или iptables-save и глубоко вдыхая констатируешь docker.
Да уж, простой жизни теперь не стало. Я вообще толком так и не понял, как корректно работать с iptables и докером одновременно. Пока спасаюсь тем, что прячу продовые сервера на шлюзы с iptables, но не всегда это возможно. На хостах с докером приходится вручную колхозить скрипты, которые накидывают правила уже после ребута и старта докера.
-A DOCKER-USER -p tcp -m conntrack --ctorigdstport 80 --ctdir ORIGINAL -j RETURN
-A DOCKER-USER -p tcp -m conntrack --ctorigdstport 443 --ctdir ORIGINAL -j RETURN
-A DOCKER-USER -m state --state RELATED,ESTABLISHED -j RETURN
-A DOCKER-USER -m set --match-set whitelist src -j RETURN
-A DOCKER-USER -p tcp -m conntrack --ctdir ORIGINAL -j DROP
Вы можете защищать вашу сеть так как вы привыкли, и при этом запускать контейнеры не в изолированной сети а с использованием хостовой сети ( --net "host" )
Ну хорошо хоть не "мяукнули" прод какой-нибудь.
1. Я всегда думал что 0.0.0.0 в выводе netstat означает - слушать порт на всех интерфейсах сервера . Причем здесь "смотрит напрямую в инет" ?
2. По поводу - " зачем-то по дефолту мапит контейнеры к 0.0.0.0, а не к локалхосту". Ведь в приведенном compose файле явно написано 0.0.0.0:5432
И если "потребитель" Postgres на другой виртуалке или запущен в другом стеке compose, то как иначе ?
ну если дефолт пароль и юзера разрабам поменять религия не позволяет, то прописать правило в айпитейблах с разрешением подключаться только определенному айпи к тому порту что мешает?
Очевидно, всё та же религия. Пофигизм.
Орден святого Лентяиуса.
1. В данном случае виртуальная машина с внешним ip, так что слушая 0.0.0.0 приложение принимает запросы в том числе и из интернета.
2. Потому что в докере так принято по-умолчанию, вот все и оставляют, кто не придет этому значение. Тут все было запущено на одной виртуалке и на одном стеке.
да очень просто:
- network:
external: true
Ещё кстати помогает команда
lsof -p имя процесса
Показывает какие библиотеки, сокеты и логи использует процесс. Можно понять что конкретно делает вирус.
Извиняюсь, не имя а pid процесса
Яч то то не понял, он у вас висел на ipv6 исходя из netstat, вы используете ipv6?
Никто не использовал. Это по дефолту так. Виртуалка вообще не моя, я не следил за ней.
Ну тогда как на нее проникли, если там ipv6, а ее никто не использует
Те сервисы, что висят на ipv6, они же доступны и по ipv4. Такое отображение команды netstat.
Понятно, спасибо
эм, а создать свой network между бд и веб сервером???
Зачем? Есть же дефолтный docker-compose, запустил и поехали кодить :) За отдельный network между бд и веб сервером никто лишних денег разработчику не заплатит. И админа не наймет, чтобы он подсказал.
есть такое. Хотя пару строчек всего и проблема решена.
127.0.0.1 вместо нулей прокатило бы
угу или заменить дефолтные юзернейм и пассворд на свои :-)
вот тут как раз docker не виноват:
```Тут, конечно, есть недоработка докера. Он зачем-то по дефолту мапит контейнеры к 0.0.0.0, а не к локалхосту.```
как указано выше - нужно было писать 127.0.0.1 вместо нулей - как ему сказали мапить, так он и мапит, тут недоработка со стороны мейнтейнера
Тем не менее, если маппинг к адресу вообще не указать, он запустит контейнер на 0.0.0.0, а мне кажется, что по дефолту лучше было бы мапить к 127.0.0.1. Из-за этого и разработчики, видя дефолтное поведение 0.0.0.0, его же и указывают. Просто по факту чаще всего никто ничего не меняет и запускает контейнеры как есть, в дефолте и они слушают 0.0.0.0. Постоянно с этим сталкиваюсь.
То что по умолчанию на 0.0.0.0 мапит это нормальное поведение, так и должно быть. А вот то что конкретная система смотрит в мир голым задом - это не нормально, так нельзя делать, все должно стоять за отдельным файрволом.
Кому должно и где должно? Так можно сказать, что учетная запись admin без пароля это нормально, а то что сервис смотрит в интернет - нет. Я считаю, что было бы лучше мапить по дефолту к локалхосту. А если надо смотреть в мир, то отдельно это настраивается настройкой внешнего ip адреса.
А не задумывались что такой мапинг был по какой-то конкретной причине принят разработчикам, и никак иначе?
А то что если бы и сделали по умолчанию локалхост, то у разрабов было бы первым правилось менять его на 0.0.0.0 не задумываясь, поверьте, везде в интернете в "манах для чайников" было бы примером мапить на 0.0.0.0 и мало кто задумывался бы об этом.
Есть best practices. Не просто так же придумали что все к чему есть доступ с мира выносить в DMZ за файрвол.
Задумывался. Так проще разработчикам, которые не разбираются в работе сети. Есть системы, в которых подумали о базовой безопасности, а есть где нет. Например, mysql по умолчанию мапится на локалхост, а то ли монга, толи еластик в дефолте мапится на 0.0.0.0 с дефолтной учеткой. Поэтому в сети постоянно появляются новости о сливах этих баз, в то время как про mysql я вообще подобных новостей не слышал.
Не будут разработчики настраивать DMZ, если они не способны 0.0.0.0 поменять на 127.0.0.1 или что-то другое самостоятельно.