Документация по ОС FreeBSD Воскресенье, 05.05.2024, 21:57
Приветствую Вас Гость | RSS
Меню сайта

Категории каталога
Apache [58]
DNS [25]
FTP [27]
Mail [74]
Samba [24]
Squid [46]
SSH [23]
VPN [35]
РРР [20]
Net [173]

Главная » Статьи » Сеть » Mail

Попытка защитить свой почтовый сервер от DDoS атаки [2009]
Друг попросил о помощи, его почтовик подвергся ddos атаке. У меня были написаны скрипты, но у меня не настолько большая нагрузка, чтобы можно было их потестить по нормальному, да и времени тоже не было. Навеяло на их написание, точнее дописание обсуждение Защита exim от DDoS. А тут как раз и повод появился.

В моём случае почтовый сервер и почтовый релей - это два разных сервера, но, если это один и тот же сервер - то всё работает также прекрасно, что и было доказано.

Топология:
- пограничный маршрутизатор: FreeBSD 7.2/i386, Atom c 1 сетевой картой, зато с кучей vlan
- почтовик, он же и прокся, он же и MySQL сервер: FreeBSD 7.2/amd64, Core2Duo E8500, 8G Ram

Теперь по порядку:
8 - 10 тысяч одновременных конектов к exim, при условии, что в офисе работает 50 человек. Это уже слишком. Попахивает DDos'ом.
Ддосили smtp, imap не юзается, точнее юзается imaps, а его, почему-то, не ддосят.

Перед какими либо действиями обновляем порты, я это делаю с помощью cvsup.
[root@mx ]# cd /usr/ports/net/cvsup-without-gui
[root@mx ]# make install clean

оздаём к ниму конфиг-файл /usr/local/etc/cvsup/ports-sup
*default host=cvsup3.uk.freebsd.org
*default base=/var/db
*default prefix=/usr
*default release=cvs tag=.
*default delete use-rel-suffix
*default compress
ports-all

После чего командой
cvsup -g -L 2 /usr/local/etc/cvsup/ports-sup

обновляем порты.

Ставим Mysql:
[root@mx /usr/ports]# cd /usr/ports/databases/mysql51-server/
[root@mx ]# make install clean
[root@mx ]# echo 'mysql_enable="YES"' >> /etc/rc.conf

конфиге указывываем побольше количество коннектов, параметр max_connections=1000 в секции [mysqld]. В моём случае это было 10000. По умолчанию файл конфигурации my.cnf будет находится в каталоге с самой базой /var/db/mysql, но пока мы не инициализируем mysql, там ничего не будет. Это можно сделать несколькими способами, один из них, запустить mysql, он сам всё сделает, затем отредактировать конфигурационный файл и перезапустить mysql. Запуск осуществляется командой
[root@mx /var/db]# /usr/local/etc/rc.d/mysql-server start

олее детально установка MySQL описана в статье Установка MySQL Автор Lissyara.

Ставим exim:
[root@mx /var/db]# cd /usr/ports/mail/exim
[root@mx /usr/ports/mail/exim]# make install clean
[root@mx ]# echo 'exim_enable="YES"' >> /etc/rc.conf

а этом сайте приведено множество примеров конфигурирования exim под разные цели: exim & dovecot, exim + exchange автор Lissyara, мои конфиги базируются на этих статьях, поэтому повторяться не буду, напишу только свои дополнения:
В файле конфигурации /usr/local/etc/exim/configure, если ваш файл разбит на несколько файлов, то в соответвтвующих файлах, параметр
# Максимальное число одновременных подключений по
# SMTP. Рассчитывать надо исходя из нагрузки на сервер
smtp_accept_max = 50

еобходимо сделать побольше, иначе ваш exim буквально сразу захлебнётся. Перед begin acl создаём макрос:
MYSQL_IPFW = INSERT INTO `ipfw` \
(`ip`, `date`, `type`, `coun`,`email`) VALUES \
('$sender_host_address', now(), '$acl_m18', '1', '$sender_address')

Далее в разделе acl, создаём переменные:
 warn set acl_m18 = 0
warn set acl_m19 = 0

добавляем в секции проверок, в которых идут следующие  запреты:
 set acl_m18 = HELO1
set acl_m19 = ${lookup mysql{MYSQL_IPFW}}

В разделе на проверки на EHLO/HELO, для каждой проверки можно присваивать свои значения $acl_m18, HELO1,HELO2,HELO10, чтобы потом отслеживать , где попался
 set acl_m18 = DNSRBL
set acl_m19 = ${lookup mysql{MYSQL_IPFW}}

вносим, на проверке на RBL
 set acl_m18 = UnUser
set acl_m19 = ${lookup mysql{MYSQL_IPFW}}

вносим, за попытку отправить почту несуществующим пользователям.
Создаём таблицы в MySQL, у меня exim использует базу exim_db, если у вас другая, то необходимо исправить на свою:
-- Создаём таблицу для занесения статистики
CREATE TABLE ipfw(
ip CHAR (15) NOT NULL,
`date` CHAR (19) NOT NULL,
type CHAR (9) NOT NULL,
coun INT (8) NOT NULL,
email VARCHAR (64) DEFAULT NULL,
INDEX `date` USING BTREE (`date` (13)),
INDEX ip USING BTREE (ip),
INDEX type USING BTREE (type)
)
ENGINE = MYISAM
CHARACTER SET latin1
COLLATE latin1_swedish_ci;

-- Создаём таблицы для анализа и занесения результатов
CREATE TABLE ddos_analis(
ip CHAR (15),
type CHAR (9) DEFAULT NULL,
date_in CHAR (19) DEFAULT NULL,
date_last CHAR (19) DEFAULT NULL,
date_exp CHAR (19) DEFAULT NULL,
coun INT (8) UNSIGNED DEFAULT NULL,
PRIMARY KEY (ip),
UNIQUE INDEX ip_type USING BTREE (ip, type)
)
ENGINE = MEMORY
CHARACTER SET koi8r
COLLATE koi8r_general_ci;

CREATE TABLE ddos_exp(
ip CHAR (15) NOT NULL,
date_delete CHAR (19) DEFAULT NULL,
active CHAR (1) DEFAULT '0',
UNIQUE INDEX ip USING HASH (ip)
)
ENGINE = MEMORY
CHARACTER SET koi8r
COLLATE koi8r_general_ci;

Теперь создаём логику, которая и будет почти всё делать
CREATE
TRIGGER ddos_analis1
AFTER INSERT
ON ipfw
FOR EACH ROW
BEGIN
SET @coun = new.coun + 1;
SET @ip = new.ip;
SET @type = new.type;
-- Время первого заноса в таблицу
SET @date_in = new.`date`;
-- Время последнего заноса в таблицу
SET @date_last = new.`date`;
-- Интервал, за который идёт анализ
SET @date_exp = NOW() + INTERVAL 5 MINUTE;
-- Интервал, для чего-то создавался, мож быть где-то пригодиться
-- SET @date_delete = NOW() + INTERVAL 1 DAY;

-- Заносим данные в таблицу колектор и, в случаи нахождения ip,
-- обновляем и добавляем очки
INSERT
INTO exim_db.ddos_analis (ip, type, date_in, date_last, date_exp, coun)
VALUES (@ip, @type, @date_in, @date_last, @date_exp, 1)
ON DUPLICATE KEY
UPDATE
exim_db.ddos_analis.coun = exim_db.ddos_analis.coun + 1,
exim_db.ddos_analis.date_last = @date_last,
exim_db.ddos_analis.date_exp = @date_exp;

-- Заносим данные в таблицу, из которой информацию черпает фаервол
-- Данные заносятся из таблицы коллектора
-- coun >10 - это условие, при котором можно с уверенностью сказать,
-- что вас или спамят или ддосят, интервал анализа - @date_exp
-- date_exp + INTERVAL 10 MINUTE интервал,
-- сколько в фаерволе будет находится ip
INSERT IGNORE
INTO exim_db.ddos_exp (ip, date_delete)
SELECT
ip, date_exp + INTERVAL 10 MINUTE
FROM
exim_db.ddos_analis
WHERE
coun > 10;

-- Удаляем просроченные записи или записи из таблицы коллектора
-- по времени оканчания срока жизни @date_exp
DELETE
FROM
exim_db.ddos_analis
WHERE
LEFT(date_exp, 16) < NOW();

-- Удаляем из таблицы коллектора свои подсети
-- Надо будет переделать на свой whitelist, хранимый в мускуле
DELETE
FROM
exim_db.ddos_analis
WHERE
ip LIKE '10.4.%' OR ip LIKE '192.168.%';
END

В триггере присутствуют комментарии, поэтому писать не буду ничего

Создаём скрипт на маршрутизаторе add_ipfw.sh:
#!/bin/sh

/usr/local/bin/mysql --host=ip_you_mysql_server \
--password='xхх' --user=user_to_access_to_mysql_server exim_db --execute=' \

update exim_db.ddos_exp \
set active = 2 \
WHERE \
LEFT(date_delete, 16) < NOW() and active = 1; \

SELECT "ipfw table 125 add " asdf, ip FROM exim_db.ddos_exp \
WHERE \
active = 0; \

SELECT "ipfw table 125 delete " asdf, ip FROM exim_db.ddos_exp \
WHERE \
active = 2; \

UPDATE exim_db.ddos_exp \
SET active = 1 where active = 0; \

delete FROM exim_db.ddos_exp \
WHERE \
LEFT(date_delete, 16) < NOW() and active = 2;'| \
grep -v asdf>/tmp/exim_ipfw_add_table_blacklist.sh

. /tmp/exim_ipfw_add_table_blacklist.sh

rm /tmp/exim_ipfw_add_table_blacklist.sh

елаем скрипт выполнимым
[root@hqgw1 ]$ chmod +x add_ipfw.sh

омментарии: в таблице ddos_exp есть поле active, которое отвечает за состояние ip в фаерволе, может принимать 3 значения:
0 - ip ожидают вноса в таблицу фаервола
1 - данные внесены
2 - данные ожидают удаления из фаервола

У меня используется ipfw. В крон root добавляем
* * * * * /путь/к/вашему/скрипту/add_ipfw.sh

фаер добавляем:
#deny mail
${fwcmd} add 56 deny log ip from table\(125\) to any 25 via ${ifwan}


.
.
.
Следующей немаловажной защитой является защита от так называемых пустых коннекшинов, трафик как бы не идёт, но слот занят и потом отваливается с записью в логе
2009-09-07 15:12:42 [40591] SMTP connection from [91.78.180.232]:1666
I=[217.112.209.34]:25 lost
2009-09-07 15:12:42 [40591] no MAIL in SMTP connection from [91.78.180.232]:1666
I=[217.112.209.34]:25 D=4m38s

С помощью конфига Exim, я не нашел способа бороться, но у меня есть замечательный файл /var/log/all.log, в который пишется весь(почти) лог. Создаётся он так: в файле /etc/syslog.conf раскомментируется строка:
*.* /var/log/all.log

атем
touch /var/log/all.log
/etc/rc.d/syslogd restart

Этот файл у меня и так парсится на предмет перебора паролей на ftp, ssh. Так пусть и exim'у он тоже поможет.

Создаём таблицу для занесения статистики:
CREATE TABLE ddos_nomail(
`data` VARCHAR (255) DEFAULT NULL
)
ENGINE = MYISAM
CHARACTER SET koi8r
COLLATE koi8r_general_ci;

Создаём логику:
CREATE
TRIGGER trigger_nomail
AFTER INSERT
ON ddos_nomail
FOR EACH ROW
BEGIN

SET @ip = new.`data`;
SET @type = "noMAIL";
-- Время первого заноса в таблицу
SET @date_in = NOW();
-- Время последнего заноса в таблицу
SET @date_last = NOW();
-- Интервал, за который идёт анализ
SET @date_exp = NOW() + INTERVAL 5 MINUTE;
-- Интервал, для чего-то создавался, мож быть где-то пригодиться
-- SET @date_delete = NOW() + INTERVAL 1 DAY;

-- Заносим данные в таблицу коллектор и, в случае нахождения ip,
-- обновляем и добавляем очки
INSERT
INTO exim_db.ddos_analis (ip, type, date_in, date_last, date_exp, coun)
VALUES (SUBSTRING_INDEX(SUBSTRING_INDEX(@ip, "]:", 2), "[", -1),
@type, @date_in, @date_last, @date_exp, 1)
ON DUPLICATE KEY
UPDATE
exim_db.ddos_analis.coun = exim_db.ddos_analis.coun + 1,
exim_db.ddos_analis.date_last = @date_last,
exim_db.ddos_analis.date_exp = @date_exp;

-- Заносим данные в таблицу, из которой информацию черпает фаервол
-- Данные заносятся из таблицы коллектора
-- coun >10 - это условие, при котором можно с уверенностью сказать,
-- что вас или спамят или ддосят, интервал анализа - @date_exp
-- date_exp + INTERVAL 10 MINUTE интервал,
-- сколько в фаерволе будет находится ip
INSERT IGNORE
INTO exim_db.ddos_exp (ip, date_delete)
SELECT
ip, date_exp + INTERVAL 10 MINUTE
FROM
exim_db.ddos_analis
WHERE
coun > 10;

-- Удаляем просроченные записи или записи из таблици коллектора
-- по времени окончания срока жизни @date_exp
DELETE
FROM
exim_db.ddos_analis
WHERE
LEFT(date_exp, 16) < NOW();

-- Удаляем из таблицы коллектора свои подсети
-- Надо будет переделать на свой whitelist, хранимый в мускуле
DELETE
FROM
exim_db.ddos_analis
WHERE
ip LIKE '10.4.%' OR ip LIKE '192.168.%';

END

Создаём очередной скрипт all_log_pars.sh
#!/bin/sh
msql_e="/usr/local/bin/mysql --user=exim_ins --password=ххх \
--database=exim_db --host=12.12.12.12"
lf="/var/log/all.log"

cp ${lf} ${lf}.tmp
> ${lf}
cat ${lf}.tmp >> ${lf}.store

## Exim analis for no MAIL in SMTP connection

cat ${lf}.tmp|grep 'no MAIL in SMTP connection'| \
awk '{print "insert into exim_db.ddos_nomail value (\""$0"\");"}'#|${msql_e}
rm -f ${lf}.tmp

и делаем его исполнимым
chmod +x all_log_pars.sh

root cron добавляем его выполнение по расписанию.
* * * * * /путь/к/вашему/скрипту/all_log_pars.sh

анный метод анализа и защиты использует таблицы и скрипт из первой части статьи.

Следует обратить внимание, что у таблиц ddos_exp и ddos_analis тип MEMORY, нечего насиловать винт, для временных таблиц.



Источник: http://www.lissyara.su/?id=1980
Категория: Mail | Добавил: oleg (07.10.2009) | Автор: buryanov
Просмотров: 781 | Рейтинг: 0.0/0 |
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Форма входа

Beastie

Друзья сайта

Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0
links

Copyright MyCorp © 2024