Proteggere il proprio sito da 9 Milioni di PPS. L' approccio scalabile

Nei giorni scorsi il sito web seflow.it è stato impattato da un attacco TCP da 9 Milioni di PPS. Si tratta del primo attacco con peak superiore ai 4 Milioni ricevuto dall’ implementazione del servizio WAF con mitigazione scalabile.

La protezione DDoS SeFlow si basa su 3 livelli, ognuno con uno scopo preciso al fine di mitigare completamente l’ attacco.

SeGuard

Fino a qualche giorno fa ogni cluster era in load balancing. Soluzione efficace, ma poco efficiente in ambiente condiviso perchè, durante un attacco tutte le risorse venivano messe in campo per la mitigazione. Il nuovo approccio è attivare le risorse on-demand così da lasciare risorse inutilizzate per attacchi contemporanei. Abbiamo inoltre aggiunto un nuovo sistema WAF, come ultimo livello con attivazione automatica in caso di attacco e varie possibilità di challenge (recaptcha v3, 5s), ma ne parleremo in altro articolo.

In pratica, come funziona il nuovo approccio?

Quando un attacco viene rilevato, il sistema attiva la prima sequenza di firewall/filtri/waf non impegnati da altri attacchi e inizia il lavoro di pulizia

 

Un sistema di load monitoring proprietario fa il controllo degli apparati. Se dovessimo rilevare un carico elevato, su un device della sequenza, il sistema attiva la seconda batteria e tramite BGP multipath bilanceremo il traffico:

Protezione DDoS Bilanciata

In questo modo l’ attacco si bilancerà riducendo il carico. L’ architettura ci permette di scalare facilmente aggiungendo nuovi cluster e la gestione e monitoring del carico saranno molto semplificate.

 

Ma come funziona in pratica?

Nei giorni scorsi abbiamo ricevuto un attacco da 9 Milioni PPS sul nostro sito web istituzionale. Quando l’attacco è stato identificato, il portale ha generato l’ anomalia:

 

Anomalia 1

 

Ed ha attivato la prima batteria di Filtri. Mentre i Firewall sono basati su architettura ASIC, i filtri Layer3-4 sono basati su architettura x86 e quindi soggetti a carico. Infatti visionando il carico nel filtro vediamo:

# velin
Monitoring ens2f0… (press CTRL-C to stop)

rx: 12.86 Gbit/s 9837056 p/s tx: 0 bit/s 0 p/s

# uptime
00:32:46 up 45 days, 15:05, 2 users, load average: 30.01, 33.02, 41.20

 

Il load è molto alto a causa degli IRQ che utilizzano completamente la CPU. Il nostro monitor, accorgendosi dell’ overload bilancia il traffico e, circa tre minuti dipo questa è la situazione:

 

Cluster 1:

# velin
Monitoring ens2f0… (press CTRL-C to stop)

rx: 4.86 Gbit/s 3837056 p/s tx: 0 bit/s 0 p/s^C

# uptime
00:35:46 up 45 days, 15:05, 2 users, load average: 4.01, 23.02, 38.20

Cluster2:

# velin
Monitoring enp5s0f1… (press CTRL-C to stop)

rx: 7.74 Gbit/s 6137056 p/s tx: 0 bit/s 0 p/s^C

# uptime
00:36:20 up 81 days, 22:40, 1 user, load average: 3.01, 3.02, 1.20

 

E in tutto questo il sito web?

Il sito web è sempre rimasto correttamente raggiungibile e il carico era molto basso. L’ attacco grazie all’ unione dei filtri layer 3/4 e waf ha mitigato l’ attacco. Il carico e gli accessi (a mezzanotte abbiamo pochissimi accessi) era di fatto nella norma:

# netstat -n
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 83.136.107.2:80 94.141.1.xxx:54064 SYN_RECV
tcp 0 0 83.136.107.230:22 89.7.187.xxx:21366 TIME_WAIT
tcp 0 384 83.136.107.2:22 94.198.96.xxx:59498 ESTABLISHED
tcp 0 0 83.136.107.2:22 212.64.8.xx:35998 ESTABLISHED
tcp 0 0 83.136.107.230:22 118.34.12.xx:40024 TIME_WAIT
tcp 0 0 83.136.107.2:22 104.154.239.xxx:59660 TIME_WAIT
tcp 0 0 127.0.0.1:80 127.0.0.1:40648 TIME_WAIT

# uptime
00:42:01 up 158 days, 13:01, 1 user, load average: 0.13, 0.21, 0.22

 

Alcune informazioni sul tipo di DDoS e come mitigarlo

Di seguti riporto un estratto del dump dell’ attacco

01:26:15.605635 IP (tos 0x48, ttl 105, id 12674, offset 0, flags [DF], proto TCP (6), length 52)
1.31.82.180.49403 > 158.58.172.130.80: Flags [.], cksum 0x2406 (correct), seq 0, ack 1, win 16616, options [nop,nop,TS val 125819436 ecr 3679778033], length 0
0x0000: 4548 0034 3182 4000 6906 416a 011f 52b4 EH.41.@.i.Aj..R.
0x0010: 9e3a ac82 c0fb 0050 0000 0000 0000 0001 .:…..P……..
0x0020: 8010 40e8 2406 0000 0101 080a 077f da2c ..@.$……….,
0x0030: db54 f4f1 .T..
01:26:15.605594 IP (tos 0x48, ttl 111, id 0, offset 0, flags [DF], proto TCP (6), length 40)
94.207.147.215.20213 > 158.58.172.130.80: Flags [.], cksum 0x1a09 (correct), seq 4128839183, ack 2492164174, win 32, length 0
0x0000: 4548 0028 0000 4000 6f06 ce24 5ecf 93d7 EH.(..@.o..$^…
0x0010: 9e3a ac82 4ef5 0050 f619 160f 948b 684e .:..N..P……hN
0x0020: 5010 0020 1a09 0000 0000 0000 0000 P………….
01:26:15.605620 IP (tos 0x48, ttl 97, id 25872, offset 0, flags [DF], proto TCP (6), length 52)
27.222.113.48.60419 > 158.58.172.130.80: Flags [.], cksum 0xffac (correct), seq 0, ack 1, win 254, options [nop,nop,TS val 125819436 ecr 3679778033], length 0
0x0000: 4548 0034 6510 4000 6106 dca0 1bde 7130 EH.4e.@.a…..q0
0x0010: 9e3a ac82 ec03 0050 0000 0000 0000 0001 .:…..P……..
0x0020: 8010 00fe ffac 0000 0101 080a 077f da2c ……………,
0x0030: db54 f4f1 .T..
01:26:15.605704 IP (tos 0x48, ttl 93, id 0, offset 0, flags [DF], proto TCP (6), length 40)
117.110.221.191.65013 > 158.58.172.130.80: Flags [.], cksum 0xdbb2 (correct), seq 2184053085, ack 1092711204, win 32, length 0
0x0000: 4548 0028 0000 4000 5d06 7f9d 756e ddbf EH.(..@.]…un..
0x0010: 9e3a ac82 fdf5 0050 822e 015d 4121 7324 .:…..P…]A!s$
0x0020: 5010 0020 dbb2 0000 0000 0000 0000 P………….
01:26:15.605644 IP (tos 0x48, ttl 120, id 0, offset 0, flags [DF], proto TCP (6), length 40)
78.118.18.144.55456 > 158.58.172.130.80: Flags [.], cksum 0x24ea (correct), seq 202813276, ack 176504863, win 32, length 0
0x0000: 4548 0028 0000 4000 7806 56c5 4e76 1290 EH.(..@.x.V.Nv..
0x0010: 9e3a ac82 d8a0 0050 0c16 af5c 0a85 401f .:…..P…\..@.
0x0020: 5010 0020 24ea 0000 0000 0000 0000 P…$………
01:26:15.605735 IP (tos 0x48, ttl 85, id 0, offset 0, flags [DF], proto TCP (6), length 40)
111.61.242.36.10100 > 158.58.172.130.80: Flags [.], cksum 0x174d (correct), seq 1801344566, ack 1150467677, win 32, length 0
0x0000: 4548 0028 0000 4000 5506 7969 6f3d f224 EH.(..@.U.yio=.$
0x0010: 9e3a ac82 2774 0050 6b5e 5636 4492 be5d .:..’t.Pk^V6D..]
0x0020: 5010 0020 174d 0000 0000 0000 0000 P….M……..
01:26:15.605783 IP (tos 0x48, ttl 71, id 0, offset 0, flags [DF], proto TCP (6), length 40)
88.187.40.232.12452 > 158.58.172.130.80: Flags [.], cksum 0x1bf9 (correct), seq 1793758754, ack 3827282234, win 32, length 0
0x0000: 4548 0028 0000 4000 4706 6728 58bb 28e8 EH.(..@.G.g(X.(.
0x0010: 9e3a ac82 30a4 0050 6aea 9622 e41f b13a .:..0..Pj..”…:
0x0020: 5010 0020 1bf9 0000 0000 0000 0000 P………….
01:26:15.605837 IP (tos 0x48, ttl 118, id 0, offset 0, flags [DF], proto TCP (6), length 40)
12.155.83.51.19003 > 158.58.172.130.80: Flags [.], cksum 0xe9c5 (correct), seq 2736319287, ack 90848542, win 32, length 0
0x0000: 4548 0028 0000 4000 7606 59fd 0c9b 5333 EH.(..@.v.Y…S3
0x0010: 9e3a ac82 4a3b 0050 a318 eb37 056a 3d1e .:..J;.P…7.j=.
0x0020: 5010 0020 e9c5 0000 0000 0000 0000 P………….
01:26:15.605786 IP (tos 0x48, ttl 114, id 0, offset 0, flags [DF], proto TCP (6), length 40)
49.120.62.11.50472 > 158.58.172.130.80: Flags [.], cksum 0x6256 (correct), seq 1673688667, ack 1451531523, win 32, length 0
0x0000: 4548 0028 0000 4000 7206 4e48 3178 3e0b EH.(..@.r.NH1x>.
0x0010: 9e3a ac82 c528 0050 63c2 765b 5684 9d03 .:…(.Pc.v[V…
0x0020: 5010 0020 6256 0000 0000 0000 0000 P…bV……..
01:26:15.605837 IP (tos 0x48, ttl 98, id 16238, offset 0, flags [DF], proto TCP (6), length 52)
23.25.58.199.42561 > 158.58.172.130.80: Flags [.], cksum 0x05bc (correct), seq 0, ack 1, win 256, options [nop,nop,TS val 125819450 ecr 4103231109], length 0
0x0000: 4548 0034 3f6e 4000 6206 3c71 1719 3ac7 EH.4?n@.b.<q..:.
0x0010: 9e3a ac82 a641 0050 0000 0000 0000 0001 .:…A.P……..
0x0020: 8010 0100 05bc 0000 0101 080a 077f da3a ……………:
0x0030: f492 5685 ..V.

Come possiamo vedere l’attacco era di tipo TCP, principalmente con pacchetti di lunghezza 40 e 52 e verso l’ ip 158.58.172.130 porta 80.

In questo caso i firewall statici non sono in grado di mitigare l’attacco e devono intervenire i filtri layer 3/4 e i parzialmente  waf. Quando un attacco viene rilevato facciamo sniffing dell’ attacco e iniettiamo delle regole automatizzate specifiche per il tipo di attacco. Queste regole sono replicabili su commodity hardware, certo dovrete lasciarle staticamente, ma fanno il loro dovere, quindi come mitigare?

Sfruttiamo IPtables, impostando regole ad hoc, in particolare SYNPROXY in grado, in questo caso di bloccare completamente l’ attacco. per prima cosa aprimamo il file /etc/sysctl.conf e inseriamo

net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.all.rp_filter = 1
net.ipv4.ip_nonlocal_bind = 1
net.netfilter.nf_conntrack_max = 10000000
net.netfilter.nf_conntrack_tcp_loose = 0
net.netfilter.nf_conntrack_tcp_timeout_established = 1800
net.netfilter.nf_conntrack_tcp_timeout_close = 10
net.netfilter.nf_conntrack_tcp_timeout_close_wait = 10
net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 20
net.netfilter.nf_conntrack_tcp_timeout_last_ack = 20
net.netfilter.nf_conntrack_tcp_timeout_syn_recv = 20
net.netfilter.nf_conntrack_tcp_timeout_syn_sent = 20
net.netfilter.nf_conntrack_tcp_timeout_time_wait = 10

Applichiamo i cambiamenti con

sysctl -p

A quel punto impostiamo delle regole iptables in grado di bloccare questo tipo di attacchi

iptables -t raw -A PREROUTING -i eth0 -p tcp -m tcp –dport 443 –tcp-flags FIN,SYN,RST,ACK SYN -j CT –notrackiptables -t raw -A PREROUTING -i eth0 -p tcp -m tcp –dport 80 –tcp-flags FIN,SYN,RST,ACK SYN -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 -i eth0 -p tcp -m tcp –dport 443 -m state –state INVALID,UNTRACKED -j SYNPROXY –sack-perm –timestamp –wscale 7 –mss 1460

iptables -A INPUT -m state –state INVALID -j DROP

Ricordiamoci infine di aumentare i conntrack hash size:

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

Per i più smanettoni, vi lascio alcune regole che il nostro software ha aggiunto per affinare la mitigazione
:

target prot opt source destination
DROP tcp — 0.0.0.0/0 0.0.0.0/0 tcp flags:0x3F/0x01
DROP tcp — 0.0.0.0/0 0.0.0.0/0 tcp flags:0x3F/0x29
DROP tcp — 0.0.0.0/0 0.0.0.0/0 tcp flags:0x06/0x06
DROP tcp — 0.0.0.0/0 0.0.0.0/0 tcp flags:0x03/0x03
DROP tcp — 0.0.0.0/0 0.0.0.0/0 tcp flags:0x3F/0x3F
DROP tcp — 0.0.0.0/0 0.0.0.0/0 tcp flags:0x3F/0x00
DROP all — 0.0.0.0/0 0.0.0.0/0 match-set seguard_blacklist src
DROP all — 255.255.255.255 0.0.0.0/0
DROP all — 239.255.255.0/24 0.0.0.0/0
DROP all — 0.0.0.0/8 0.0.0.0/0
DROP all — 240.0.0.0/5 0.0.0.0/0
DROP all — 224.0.0.0/4 0.0.0.0/0
DROP all — 127.0.0.0/8 0.0.0.0/0
DROP all — 192.168.0.0/16 0.0.0.0/0
DROP all — 172.16.0.0/12 0.0.0.0/0
DROP all — 10.0.0.0/8 0.0.0.0/0
DROP all — 0.0.0.0/0 0.0.0.0/0 -m geoip –source-country US
DROP all — 0.0.0.0/0 0.0.0.0/0 -m geoip –source-country CN
RETURN all — 0.0.0.0/0 0.0.0.0/0

Per poter impostare queste regole è necessario avere le xtable_addons abilitate, altrimenti rimuovete la parte geoip.