Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 19 Jun 1999 18:29:55 -0700 (PDT)
From:      Richard Steenbergen <humble@quadrunner.com>
To:        freebsd-security@freebsd.org
Subject:   SYN Floods, some food for thought
Message-ID:  <Pine.LNX.4.10.9906191654220.23102-100000@puffer.quadrunner.com>

next in thread | raw e-mail | index | archive | help
As much as I would like to work out tested and well reasoned arguements,
develop patches, and save the world, I do not have time. So, in the
interest of perhaps getting some widely distributed protection, or at
least provoke some ideas and discussion (after reviewing some of the
fbsd-security archives I realized a lot of the thinking was way off), I
present the following.

Syn floods. We all know what they are, but in many ways we don't
understand how they kill. The first thing that pops into mind is Panix,
and low bandwidth syn floods that filled queues and prevented new
connections. However, if you've ever tried doing something stupid like run
an EFNet IRC Server, the first thing that pops into mind is BladeX (and
the like, script kiddies playing with toys they barely understand because
it gives them wood to take down people who understand things even less),
and SYN floods that disable machines and networks for hours on end. The
old classic technique of filling queues has long since been fixed, but syn
floods in sufficient quantity remain a killer. Why?

First, some analysis from my own experience. One day I got sick and tired
of hearing about systems going down and of course under freebsd rebooting
when under syn flood, so I whipped out two machines and decided to do some
tests. The first machine was a Cyrix 133 P166+, the second was a Pentium
II 450 (yes a little uneven, but all I had available at the time), both
running FreeBSD 3.2-STABLE with identical Netgear 310TX PNIC-based 100Mbit
PCI ethernet cards, crossover'd and running in full duplex. Bandwidth and
packets per second (pps) analysis done with "netstat -n 1" on both ends.
First I found some packet kiddie programs, synk4, slice, and the like
(some truely bad code in all of it, all derived from the original synk.c
flooders, but a starting point). I then sat down and wrote the best
possible syn flooder I could write. From my P166, I was able to generate
around 3kpps (3,000 packets per second) with the synk-based programs,
using my flooder and the most optimal techniques I could come up with
(including asm checksum :P) I was about to generate approx 15kpps (a 4.6x
improvement). The pII 450 was able to do ~ 150kpps.

/* The stuff that I'm going to gloss over here for public security
interests, if you're interested and can prove that you're not a packet
kiddie, you can contact me privately for details */
The limitation in a synflood is calls to sendto(), significant overhead
exists for copying the packet to kernelland every time, doing all the
checks (routing etc etc), building the ethernet frame, and actually
shipping it out to the NIC queue. I'm certain the more observant will
realize the simple solution to improving syn floods dramatically, but I'm
not going to go into detail.
/* Ok done with all that nastiness */


Some interesting things to note. Firstly, when attacking the P166, I was
able to hit it so hard the cursor stopped blinking (hardware interrupts
getting 150kpps from the nic?). When attacking the 450:
 - Hitting closed ports which generated RSTs used approx 25% cpu, all
   interrupt, as reported by top.
 - Hitting open ports generated a hell of a lot of SYN|ACKs, which
   normally (in an internet situation) would go outward unto the net
   towards all those little random hosts (more on this later), but because
   of the simulation they were going back to the attacking machine (the
   P166) and beating the ever loving crap out of it (the same as a syn
   flood would :P)
 - ipfw'ing syns inbound cuts cpu to approx 20%
 - ipfw'ing syn|ack's and rst's outbound allowed the test machine to
   generate a full 15kpps, and completely blew the 450 away, 100%
   interrupt cpu usage.
 - I was able to make memory usage in the Wired state rise to almost 64MB
   with those unanswered SYN|ACKs being held in state, and of course
   retransmitted on a regular basis.

Some thoughts... CPU load caused by having to run through that huge queue
and retransmit syn|acks? Possible solutions, stop retransmitting so often
and discard from the queue quicker when under attack (if thats the source
of the cpu load)? SYN Cookies would be a quick way to get rid of that
problem (with a better hash algorithm and some more thought given to
design, like not picking common MSS numbers out of your ass? :P MD5 on
very syn and every ack is wasteful in the extreme, and considering they
only use the first 32 bits of the 128 bit result and throw away the
rest... hello, anyone home? :P). However, we know that the linux syn flood
defense is not effective, so I would really like to take a look and see
where it fails.

Some practical defense... Firstly, filter reserved ip blocks to cut the
dammage caused by random source attacks. And I'm not talking RFC1918 here,
I'm talking 64.0.0.0/2 and 224.0.0.0/3, etc (those two alone cut 35% of
the ip space). Those are certainly good filters to apply on your network
borders (for the acl challanged thats 64.0.0.0 192.0.0.0 and 224.0.0.0
224.0.0.0), but remember that 64.0.0.0/2 covers the 127/8 reserved for
loopback, so if you filter by that on your system make sure you include a
recv interface param or you'll hose your loopback :P. If your ethernet can
take it (100Mbit, 10 is not terribly hard to fill and turn the syn flood
into a bandwidth attack, also remember that these 40 byte packets will be
padded to 64 byte frames, so the bandwidth attack is 1.6x more effective
then it would seem by looking at iphdr/tcphdr), it may be a better
solution for you to let the syns hit the actual target machine, and
discard them there (assuming a decent-sized cpu too), for the following
reason. If you can't find distinguishing characteristics to filter the
fake syns by, any rate limiting you do will also do a pretty effective job
of preventing new connections. Look around, you'll find LOTS of
distinguishing characteristics that allow you to pick off the packet
kiddie syns with a 2 line kernel modification. Now down to the actual rate
limiting that prevents you from keeling over completely. If you have Cisco
Express Forwarding (only for the highend 7000+ series on 11.3 IOS,
available for 2600+ in 12.0 IOS), you have Committed Access Rates. If you
just want to rate-limit at the machine, the simplest way is to use
dummynet (man dummynet, options DUMMYNET, yada yada), and:
ipfw pipe 1 config bw 256Kbit/s queue 100Packets
ipfw add pipe 1 tcp from any to <yourip> in recv <yournetworkinterface>.

Solaris is particularly easy to toast with a syn flood. Perhaps someone
would like to hack in some rate limiting to IP Filter?

Oh, and as for that annoying little kernel panic issue. Some thoughts.
When you're flooded with all those random source packets, and actually
reply with rst or syn|ack or whatever, you're going to be hitting a lot of
dud ips and getting a lot of ICMP Redirects from some dumb networks out
there. FreeBSD will happily add temporary routing table entries for them
(do we really want this behavior? I can certainly think of ways that being
able to create arbitrary routing table entries on the unfiltered with some
spoofed redirects could be a "bad thing" *hint*. OpenBSD has 
net.inet.icmp.rediraccept :P). 

Enough of my rambling for one day. Thoughts, ideas, flames?

-- 
Richard Steenbergen <humble@lightning.net> humble@EFNet PGP ID: 0x741D0374
PGP Key Fingerprint: C6EF EFA0 83B2 071F 1AB6  B879 1F70 4303 741D 0374
http://users.quadrunner.com/humble



To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-security" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.LNX.4.10.9906191654220.23102-100000>