Syn flood

Материал из poiuty wiki
Перейти к: навигация, поиск

Решили проверить защиту OVH от syn flood.
Первые 5~10 минут весь трафик попадает на сервер.
Далее включается VAC (защита OVH) и все благополучно фильтруется.
Проблема в том, что сервер может быть недоступен в первые минуты атаки.
syn_flood2.png

Проверим, выживет ли наш сервер если заблокировать все соединения.

iptables -N ALLOWED
iptables -A INPUT -j ALLOWED
iptables -A ALLOWED -s НАШ_IP -j ACCEPT
iptables -A INPUT -j DROP

Да, сервер выжил: коннект не пропал. Как вариант сделать white list. Но этот вариант не всегда подойдет.

Пытаемся переварить трафик

На сервере стоит сетевая карта.

# lspci |grep Ether
03:00.0 Ethernet controller: Intel Corporation I350 Gigabit Network Connection (rev 01)
03:00.1 Ethernet controller: Intel Corporation I350 Gigabit Network Connection (rev 01)

Редактируем /etc/sysctl.conf

# Disable ICMP
net.ipv4.icmp_echo_ignore_all = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1

# Disable source routing and redirects
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.accept_source_route = 0

# TCP SYN Flood Protection
net.ipv4.tcp_syncookies = 1
net.core.somaxconn = 1024
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_synack_retries = 3
net.ipv4.tcp_keepalive_time = 60
net.ipv4.tcp_keepalive_intvl = 10
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.tcp_fin_timeout = 15

# Increase conntrack
net.netfilter.nf_conntrack_max=524285

Увеличиваем размер хеша conntrack.

echo 131071 > /sys/module/nf_conntrack/parameters/hashsize

Собираем информацию

Начинаем атаковать сервер и первым делом ловим 500 пакетов через tcpdump

tcpdump -i eth0 port 80 -c 500 -w capture.cap

Смотрим через wireshark.
syn_flood.png

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

cat /proc/net/ip_conntrack > conntrack.log

Смотрим conntrack.log

tcp      6 58 SYN_RECV src=185.12.125.172 dst=178.33.27.176 sport=20370 dport=80 src=178.33.27.176 dst=185.12.125.172 sport=80 dport=20370 mark=0 use=2
tcp      6 53 SYN_RECV src=197.140.219.200 dst=178.33.27.176 sport=2152 dport=80 src=178.33.27.176 dst=197.140.219.200 sport=80 dport=2152 mark=0 use=2
tcp      6 52 SYN_RECV src=41.189.165.88 dst=178.33.27.176 sport=15219 dport=80 src=178.33.27.176 dst=41.189.165.88 sport=80 dport=15219 mark=0 use=2
tcp      6 52 SYN_RECV src=119.12.108.197 dst=178.33.27.176 sport=56382 dport=80 src=178.33.27.176 dst=119.12.108.197 sport=80 dport=56382 mark=0 use=2
tcp      6 51 SYN_RECV src=90.64.144.9 dst=178.33.27.176 sport=61016 dport=80 src=178.33.27.176 dst=90.64.144.9 sport=80 dport=61016 mark=0 use=2
tcp      6 49 SYN_RECV src=103.126.216.171 dst=178.33.27.176 sport=48407 dport=80 src=178.33.27.176 dst=103.126.216.171 sport=80 dport=48407 mark=0 use=2
...

Вытащим из файла только уникальные IP.

cat conntrack.log | awk '{print $5}' | sort | uniq > ips.log

Открываем ips.log и видим 220k ip адресов. Полный лог можно посмотреть здесь.

src=100.108.214.213
src=100.108.215.153
src=100.108.60.32
src=100.108.81.55
src=100.109.101.139
src=100.109.116.129
src=100.109.141.248
src=100.109.171.12
src=100.109.172.14
src=100.109.205.2
src=100.109.40.20
src=100.109.58.68
src=100.109.84.60
src=100.109.96.215
src=100.110.159.149
src=100.110.170.233
src=100.110.183.100
src=100.110.191.28
src=100.110.201.67
src=100.110.206.143
src=100.110.21.133
src=100.110.223.193
src=100.110.223.26
...

Скорее всего это ip spoofing. В этом случае бессмысленно блокировать эти ip.
В интернете по запросу "syn flood iptables" можно найти правила.

Число новых SYN пакетов - максимум 500 в секунду, при превышении порога в 1500 - новые пакеты блокируются.
Действительно снизит нагрузку. Но так же заблокируете новые соединения.

iptables -N syn_flood
iptables -A INPUT -p tcp --syn -j syn_flood
iptables -A syn_flood -m limit --limit 500/s --limit-burst 1500 -j RETURN
iptables -A syn_flood -j DROP

Тоже самое, только привязка к количеству SYN пакетов отправленных с одного IP.
Здесь DROP вообще не срабатывает. Так как нас атакуют 220K ненастоящих IP.

iptables -N syn_flood
iptables -A INPUT -p tcp --syn -j syn_flood
iptables -A syn_flood -p tcp --dport 80 --syn -m hashlimit --hashlimit 10/sec --hashlimit-burst 15 --hashlimit-mode srcip --hashlimit-name syn --hashlimit-htable-size 2097152 --hashlimit-htable-max 262144 -j RETURN
iptables -A syn_flood -p tcp --dport 80 --syn -j DROP

Тем временем таблица conntrack переполняется. Сервер становится недоступен.
syn_flood3.png

Пробуем SYNPROXY

На старых ядрах не работает. Появилось в ядре 3.12 и iptables 1.4.21
Обновляю debian c wheezy до jessie. И включаю synproxy.

iptables -t raw -I PREROUTING -i eth0 -p tcp -m tcp --syn --dport 80 -j CT --notrack
iptables -A INPUT -i eth0 -p tcp -m tcp --dport 80 -m state --state INVALID,UNTRACKED -j SYNPROXY --sack-perm --timestamp --wscale 7 --mss 1460
iptables -A INPUT -m state --state INVALID -j DROP

Увеличиваю лимиты sysctl

echo 1000000 > /sys/module/nf_conntrack/parameters/hashsize
/sbin/sysctl -w net/netfilter/nf_conntrack_max=2000000

Включаю более строгий conntrack. Это необходимо чтобы иметь INVALID статус для плохих ACK пакетов.

/sbin/sysctl -w net/netfilter/nf_conntrack_tcp_loose=0


Атакуем снова. Смотрим iptraf - около 100K пакетов.
syn_flood_iptraf.png

Смотрим правила iptables. В DROP попало всего 19M из 1657M.

# iptables -L -v -n
Chain INPUT (policy ACCEPT 12419 packets, 724K bytes)
 pkts bytes target     prot opt in     out     source               destination
  41M 1657M SYNPROXY   tcp  --  eth0   *       0.0.0.0/0            0.0.0.0/0            tcp dpt:80 state INVALID,UNTRACKED SYNPROXY sack-perm timestamp wscale 7 mss 1460
 460K   19M DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0            state INVALID


Пакеты из tcpdump.
syn_flood_tcpdump.png

Смотрим нагрузку в top.
syn_flood_top.png

В итоге выбило из ssh через 30-120 секунд с момента начала атаки.
Статистика в личном кабинете OVH.
syn_flood_ovh3.png

Hetzner Abuse

Интересный момент. Через некоторое время после атаки, приходит жалоба от Hetzner.

Dear Sir or Madam,
our monitoring system noticed a network scan (or network attack) from an IP adress under your responsibility.

В письме так же есть лог

##########################################################################
#              Portscan detected from host   178.33.27.176               #
##########################################################################

time                protocol src_ip src_port          dest_ip dest_port
---------------------------------------------------------------------------
Tue Jan 27 05:52:53 2015 TCP   178.33.27.176 22    =>  138.201.42.102 8563 
Tue Jan 27 05:51:28 2015 TCP   178.33.27.176 22    =>  138.201.19.175 32684
Tue Jan 27 05:52:13 2015 TCP   178.33.27.176 22    =>  138.201.106.94 9682 
Tue Jan 27 05:51:40 2015 TCP   178.33.27.176 22    =>     78.46.124.9 32675
Tue Jan 27 05:51:26 2015 TCP   178.33.27.176 22    =>  138.201.88.158 50941
Tue Jan 27 05:52:11 2015 TCP   178.33.27.176 22    => 136.243.194.150 55880
Tue Jan 27 05:53:00 2015 TCP   178.33.27.176 22    =>  136.243.217.11 42085
Tue Jan 27 05:52:41 2015 TCP   178.33.27.176 22    =>  138.201.194.88 2927 
Tue Jan 27 05:51:22 2015 TCP   178.33.27.176 22    =>  138.201.14.192 2746 
Tue Jan 27 05:51:19 2015 TCP   178.33.27.176 22    =>  88.198.146.124 59253
Tue Jan 27 05:51:49 2015 TCP   178.33.27.176 22    => 138.201.240.174 7290 
Tue Jan 27 05:51:39 2015 TCP   178.33.27.176 22    => 138.201.136.120 31760
Tue Jan 27 05:51:29 2015 TCP   178.33.27.176 22    =>    78.46.170.27 51842
Tue Jan 27 05:52:25 2015 TCP   178.33.27.176 22    => 138.201.182.118 15908
Tue Jan 27 05:53:02 2015 TCP   178.33.27.176 22    =>   138.201.14.87 10361
Tue Jan 27 05:51:32 2015 TCP   178.33.27.176 22    =>  213.133.126.54 59579
Tue Jan 27 05:52:24 2015 TCP   178.33.27.176 22    =>  138.201.227.70 27236
...

В итоге получается, что мы отвечаем на фейковые IP, а ответ приходит на реальные.

Другая атака

Еще одна тестовая атака. Статистика из личного кабинета OVH.
syn_flood5.png

syn_flood6.png

Продолжаем собирать информацию

Лучший способ бороться со spoof - выключить все состояния подключений (т.е. целиком выгрузить conntrack).

При спуфе ложится ядро а не приложение, ksoftirq начинает сжирать процессор для обработки пакетов.
Приходит тебе 100к пакетов в секунду, каждый с разного IP. Ядро на каждый пакет пытается установить состояние в conntrack`е.
И отправить им в ответ syn-ack, и если timeout установки соединения ~30s итого мы получаем в conntrack 100000*30=3000000(3млн), подвисших соединений.
Ведь еще надо искать по ним. При поступлении нового пакета он пробегает по всем 3млн записям и если не находит нужно добавить.
А ведь еще по таймауту нужно удалять, а еще нужно делать дефрагментацию памяти и тд.

Так же необходимо распределить прерывания равномерно между ядрами.

# cat /proc/interrupts
           CPU0       CPU1       CPU2       CPU3       CPU4       CPU5       CPU6       CPU7
  0:        166          0          0          0          0          0          0          0  IR-IO-APIC-edge      timer
  1:          2          0          0          0          0          0          0          0  IR-IO-APIC-edge      i8042
  3:          2          0          0          0          0          0          0          0  IR-IO-APIC-edge
  4:          2          0          0          0          0          0          0          0  IR-IO-APIC-edge
  8:          1          0          0          0          0          0          0          0  IR-IO-APIC-edge      rtc0
  9:          0          0          0          0          0          0          0          0  IR-IO-APIC-fasteoi   acpi
 10:          2          0          0          0          0          0          0          0  IR-IO-APIC-edge
 12:          4          0          0          0          0          0          0          0  IR-IO-APIC-edge      i8042
 16:         60          0          0          0          0          0          0          0  IR-IO-APIC-fasteoi   ehci_hcd:usb1
 23:         31          0          0          0          0          0          0          0  IR-IO-APIC-fasteoi   ehci_hcd:usb2
 48:          0          0          0          0          0          0          0          0  DMAR_MSI-edge      dmar0
 49:      11100          0          0          0          0          0          0          0  IR-HPET_MSI-edge      hpet2
 50:          0          0          0          0          0          0          0          0  IR-HPET_MSI-edge      hpet3
 51:          0          0          0          0          0          0          0          0  IR-HPET_MSI-edge      hpet4
 52:          0          0          0          0          0          0          0          0  IR-HPET_MSI-edge      hpet5
 53:          0          0          0          0          0          0          0          0  IR-HPET_MSI-edge      hpet6
 54:  835175678          0          0          0          0          0          0          0  IR-PCI-MSI-edge      ahci
 55:          1          0          0          0          0          0          0          0  IR-PCI-MSI-edge      isci-msix
 56:          0          0          0          0          0          0          0          0  IR-PCI-MSI-edge      isci-msix
 57:          2          0          0          0          0          0          0          0  IR-PCI-MSI-edge      eth0
 58: 1659069182          0          0          0          0          0          0          0  IR-PCI-MSI-edge      eth0-TxRx-0
 59: 1618684875          0          0          0          0          0          0          0  IR-PCI-MSI-edge      eth0-TxRx-1
 60: 1625056053          0          0          0          0          0          0          0  IR-PCI-MSI-edge      eth0-TxRx-2
 61: 1646178325          0          0          0          0          0          0          0  IR-PCI-MSI-edge      eth0-TxRx-3
 62: 1598331613          0          0          0          0          0          0          0  IR-PCI-MSI-edge      eth0-TxRx-4
 63: 3550848340          0          0          0          0          0          0          0  IR-PCI-MSI-edge      eth0-TxRx-5
 64: 1645219775          0          0          0          0          0          0          0  IR-PCI-MSI-edge      eth0-TxRx-6
 65: 1622696613          0          0          0          0          0          0          0  IR-PCI-MSI-edge      eth0-TxRx-7
NMI:      27157      33618      32201      30421      36752      25110      14191       9902   Non-maskable interrupts
LOC: 1826320366 3347873870 3884633685  170293731 3734129552 4064651217 2047688429 4196445074   Local timer interrupts
SPU:          0          0          0          0          0          0          0          0   Spurious interrupts
PMI:      27157      33618      32201      30421      36752      25110      14191       9902   Performance monitoring interrupts
IWI:         34         15          7         11         13         16         20         11   IRQ work interrupts
RES: 1171319009 2709680425 2670984534 2481664580 2845454774 1744630140  823270568  453042284   Rescheduling interrupts
CAL:  111848330   59288386   50621717   48685811   81293414   35073331   19902178   11481179   Function call interrupts
TLB:    1650682    1467088    1565947    1690281    1450397    2509157    3481884    4185470   TLB shootdowns
TRM:          0          0          0          0          0          0          0          0   Thermal event interrupts
THR:          0          0          0          0          0          0          0          0   Threshold APIC interrupts
MCE:          0          0          0          0          0          0          0          0   Machine check exceptions
MCP:      11101      11101      11101      11101      11101      11101      11101      11101   Machine check polls
ERR:          0
MIS:          0

Сделаем каждый eth0-TxRx-N на отдельный поток.

echo 1 > /proc/irq/58/smp_affinity
echo 2 > /proc/irq/59/smp_affinity
echo 4 > /proc/irq/60/smp_affinity
echo 8 > /proc/irq/61/smp_affinity
echo 10 > /proc/irq/62/smp_affinity
echo 20 > /proc/irq/63/smp_affinity
echo 40 > /proc/irq/64/smp_affinity
echo 80 > /proc/irq/65/smp_affinity

Проверим.

# cat /proc/interrupts
           CPU0       CPU1       CPU2       CPU3       CPU4       CPU5       CPU6       CPU7
  0:        166          0          0          0          0          0          0          0  IR-IO-APIC-edge      timer
  1:          2          0          0          0          0          0          0          0  IR-IO-APIC-edge      i8042
  3:          2          0          0          0          0          0          0          0  IR-IO-APIC-edge
  4:          2          0          0          0          0          0          0          0  IR-IO-APIC-edge
  8:          1          0          0          0          0          0          0          0  IR-IO-APIC-edge      rtc0
  9:          0          0          0          0          0          0          0          0  IR-IO-APIC-fasteoi   acpi
 10:          2          0          0          0          0          0          0          0  IR-IO-APIC-edge
 12:          4          0          0          0          0          0          0          0  IR-IO-APIC-edge      i8042
 16:         60          0          0          0          0          0          0          0  IR-IO-APIC-fasteoi   ehci_hcd:usb1
 23:         31          0          0          0          0          0          0          0  IR-IO-APIC-fasteoi   ehci_hcd:usb2
 48:          0          0          0          0          0          0          0          0  DMAR_MSI-edge      dmar0
 49:      11102          0          0          0          0          0          0          0  IR-HPET_MSI-edge      hpet2
 50:          0          0          0          0          0          0          0          0  IR-HPET_MSI-edge      hpet3
 51:          0          0          0          0          0          0          0          0  IR-HPET_MSI-edge      hpet4
 52:          0          0          0          0          0          0          0          0  IR-HPET_MSI-edge      hpet5
 53:          0          0          0          0          0          0          0          0  IR-HPET_MSI-edge      hpet6
 54:  835442315          0          0          0          0          0          0          0  IR-PCI-MSI-edge      ahci
 55:          1          0          0          0          0          0          0          0  IR-PCI-MSI-edge      isci-msix
 56:          0          0          0          0          0          0          0          0  IR-PCI-MSI-edge      isci-msix
 57:          2          0          0          0          0          0          0          0  IR-PCI-MSI-edge      eth0
 58: 1659197266          0          0          0          0          0          0          0  IR-PCI-MSI-edge      eth0-TxRx-0
 59: 1618843832      13311          0          0          0          0          0          0  IR-PCI-MSI-edge      eth0-TxRx-1
 60: 1625245532          0      14948          0          0          0          0          0  IR-PCI-MSI-edge      eth0-TxRx-2
 61: 1646336279          0          0      12965          0          0          0          0  IR-PCI-MSI-edge      eth0-TxRx-3
 62: 1598523635          0          0          0      15653          0          0          0  IR-PCI-MSI-edge      eth0-TxRx-4
 63: 3552197020          0          0          0          0     107780          0          0  IR-PCI-MSI-edge      eth0-TxRx-5
 64: 1645402956          0          0          0          0          0      14922          0  IR-PCI-MSI-edge      eth0-TxRx-6
 65: 1622840974          0          0          0          0          0          0      11415  IR-PCI-MSI-edge      eth0-TxRx-7
NMI:      27161      33622      32205      30425      36758      25113      14193       9904   Non-maskable interrupts
LOC: 1827198690 3348397814 3885251301  170977374 3734667517 4065294038 2048640792 4197675156   Local timer interrupts
SPU:          0          0          0          0          0          0          0          0   Spurious interrupts
PMI:      27161      33622      32205      30425      36758      25113      14193       9904   Performance monitoring interrupts
IWI:         34         15          7         11         13         16         20         11   IRQ work interrupts
RES: 1171508570 2710029537 2671316345 2481980870 2845833493 1744856666  823391001  453113259   Rescheduling interrupts
CAL:  111867073   59298510   50630566   48693663   81307032   35079203   19905815   11483436   Function call interrupts
TLB:    1650916    1467209    1566158    1690496    1450563    2509521    3482368    4186052   TLB shootdowns
TRM:          0          0          0          0          0          0          0          0   Thermal event interrupts
THR:          0          0          0          0          0          0          0          0   Threshold APIC interrupts
MCE:          0          0          0          0          0          0          0          0   Machine check exceptions
MCP:      11102      11102      11102      11102      11102      11102      11102      11102   Machine check polls
ERR:          0
MIS:          0

Блокируем трафик через iptables - используем таблицу raw (т.е. не доходя до conntrack)
Логика такая - делаем tcpdump, анализируем его. В данном случае мы получаем пакеты WIN=0, SEQ=0.
Их можно заблокировать следующим образом.

iptables -t raw -A PREROUTING -m u32 --u32 "6&0xFF=0x6 && 32&0xFFFF=0x0000 && 4&0x1FFF=0x0000" -j DROP

Заключительное тестирование

iptables справился.

# iptables -t raw -L -v -n
Chain PREROUTING (policy ACCEPT 11M packets, 1718M bytes)
 pkts bytes target     prot opt in     out     source               destination
1317K   53M DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0            u32 "0x6&0xff=0x6&&0x20&0xffff=0x0&&0x4&0x1fff=0x0"

Chain OUTPUT (policy ACCEPT 12M packets, 6646M bytes)
 pkts bytes target     prot opt in     out     source               destination

Снова ловим пакеты и как видно, больше не отвечаем на них.
syn_flood10.png

Ссылки по теме

Тема на ЛОРЕ
Защита Linux-сервера от SYN flood: основы и методы
Большие потоки трафика и управление прерываниями в Linux

Спасибо

kam и anonymous anon.png