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>