IPtables magic, or… Blocking Aggressive Outbound Traffic with IPtables

Blocking Aggressive Outbound Traffic with IPtables.

For starters, I’ve tested this on a test system that started out with NO iptables rules, and then moved on to an IPCop install (the vmware download from vmwarez.com…)

I’ve detailed previously one dilemma that I had with regard to my own cable connection which made me question how one could SAFELY host a wireless access point (in the clear) for guest web browsing, without allowing a wireless user to port scan the outside world/aggressively spread viruses/etc. Traditional firewall setups are typically oriented towards protecting the internal network. This post is an attempt to give an explanation of how to implement the idea put forth in this post.

IPtables is essentially the Linux Kernel’s firewall and has been extended with many interesting functionalities.

At this point I think I have a reasonable solution that would make it safer. Safety is relative though and realistically there are PLENTY of options for bypassing these restrictions, but more on the flaws at the end of this.

Most of this was done by using the “recent” extension for iptables and was inspired by rules to blunt bruteforce ssh attacks. However, most firewall rules are oriented to block outside traffic from coming in, this approach is concerned about inside traffic from less trusted sources, getting out. (Although my test implementation ignored the source of the traffic (inside or outside) which COULD be useful.) Ultimately, the best application for your situation MAY differ greatly, but hopefully this will pose as an example of how something like this can be done, then it can be refined for a specific goal. (For me, it’s as much a reminder of what I’ve set up as anything else.)

Truth be told iptables rules are something I’ve tried to avoid delving too deeply into. Up until now, I’ve stuck to gui/web based tools that pretty much give you simple rule configuration. We’re definitely heading into advanced linux firewall rules territory, so… you’ve been warned. I suggest testing any self designed rules out on a test system (or systems) first to make sure things are well thought out. (And be cautious of changing firewall rules remotely or you could easily lock yourself out.)

OK, first…. iptables has three default Chains… INPUT, OUTPUT and FORWARD. INPUT are the incoming connections, OUTPUT are outgoing connections and FORWARD is for those things that the machine actually forwards to another machine. So, the first test I did was with a machine on a network, NOT acting as a router to another network. For that reason, I tested the first rules with the INPUT chain. Here’s what I added…. (In all cases, the LONG dash is really a double -, the shorter dashes are a single – Please consult your iptables setup and documentation for supported extensions and current switches.)

iptables -I INPUT 1 -m state —state NEW -m recent —set —name PERSISTENT

iptables -I INPUT 2 -m state —state NEW -m recent —update —seconds 60 —hitcount 10 —name PERSISTENT -j LOG

iptables -I INPUT 3 -m state —state NEW -m recent —update —seconds 60 —hitcount 10 —name PERSISTENT -j DROP

So, what does all of this do…. Let me start with the first one…. It inserts the rule in the INPUT chain in the 1st position…. it matches ALL packets with state “NEW” and set’s them as a “recent” visitor and tags it with the name “PERSISTENT” (The choice of name is entirely arbitrary and the decision to match ALL “NEW” packets as opposed to TCP “NEW” packets is something you might consider.)

The second rule is inserted in 2nd place in the INPUT chain…. we’re still looking at NEW packets and we call the recent module to UPDATE an IP that’s already in the PERSISTENT list… further if we’ve had 10 matches or hits of this rule in 60 seconds we’ll LOG the activity…

Finally, we put this rule in 3rd place, the very same as above, except if we’ve got 10 hits in 60 seconds now we DROP the packet. The effect of this is that a ping from machine b will send 10 packets and then further pings will be dropped UNTIL there have been fewer than 10 received in 60 seconds. As the rule is set, the same would be true of ssh connections, a port scan, etc…. with a portscan you get interesting results, some ports will give a true open/closed status and then as the rule is triggered everything else shows up as filtered. Now, realistically you could set the hitcount lower or higher depending on your situation, but… rather than playing with those settings I moved on to the REAL goal, setting this up in a firewall/router environment.

I fired up an IPCOP firewall vmware image and a kubuntu 6.06 cd vmware environment that was in the same virtual network, so the kubuntu image treated the ipcop firewall as it’s ONLY route to the outside world. First, I started out with a default environment for both to make sure things worked, I was able to do dns lookups, browse the internet and portscan the LAN that hosts the virtual environments (which the IPCOP firewall considers to be part of the internet or outside world.)

OK…. time to put these rules into place, but since we’re dealing with ROUTED packets and want to block scanning the OUTSIDE WORLD, they’ll go in the FORWARD chain…

iptables -I FORWARD 1 -m state —state NEW -m recent —set —name PERSISTENT

iptables -I FORWARD 2 -m state —state NEW -m recent —update —seconds 60 —hitcount 8 —name PERSISTENT -j LOG

iptables -I FORWARD 3 -m state —state NEW -m recent —update —seconds 60 —hitcount 8 —name PERSISTENT -j DROP

To make testing a bit simpler I dropped the hitcount to 8.

It should be noted that I’m inserting (-I) these rules into the first slots of the chain because IPCOP has a complex rulestructure and it seemed simplest to do our aggressive activity check first, thus any non-aggressive activity is processed in order the way it normally would be.

OK – I did a test scan of the LAN from the Kubuntu cd image (had to apt-get install nmap) I got a peculiar, but mostly expected response, nmap traffic did not reveal much other than port 80 open on the LAN machines. I tried ssh’ing to a LAN machine, I was now locked out (for 60 seconds at least.) So, I tried a web page…. it came up??? has the ban timed out already, tried ping to a LAN machine, no answer…. hm…. Ah – I realized quickly that the web proxy is on the firewall and for that reason web traffic isn’t affected by our rule. (Nice really, because my main concern was coming up with a good reasonable rate of traffic without crimping legitimate connections.)

So, what this means, with these rules in FORWARD, AND web proxying enabled, you could pull up 20 pages a minute and never trigger this rule, UNLESS they were https (which is not proxied…). It should be noted that in this case DNS lookups are going to the firewall machine and those do not get the FORWARD chain treatment either, so even though you might lock out someones ability to portscan the outside world they can still get DNS resolution.

Now, this setup listed above affects ALL FORWARD chain traffic, which means inside going out, outside coming in, BLUE (wireless) network going out, GREEN (LAN) going out, etc. etc. ANY traffic that is truly “FORWARD”‘ed and not Proxied through the machine works on the filter. You MIGHT refine this setup by matching the incoming ethernet interface (-i eth0) for instance, or even the outgoing interface (-o eth0). You could also affect only tcp packets -p tcp OR only a specific service. (-p tcp –dport 22)

One of the nice things about using the state NEW match is that existing connections through the firewall are not connected. After the ban timed out, I established a ssh connection to a machine outside the LAN on the internet…. then I proceeded to do another portscan of the LAN and got NEW outbound connections banned again, but I checked my ssh connection which was still active and usable.

OK, so now we’ve prevented someone causing problems on the outside network, but the firewall itself is still vulnerable to our “somewhat untrusted” network. OK, let’s take another look at the input chain. We still want to allow web proxy traffic and DNS lookups, so we might do this….

iptables -I INPUT 1 -p tcp —dport ! 800 -m recent —name LOCALRECENT —set -m state —state NEW

iptables -I INPUT 2 -p udp —dport ! 53 -m recent —name LOCALRECENT —set -m state —state NEW

iptables -I INPUT 3 -p tcp —dport ! 800 -m state —state NEW -m recent —name LOCALRECENT —update —seconds 60 –hitcount 4 -j LOG

iptables -I INPUT 4 -p tcp —dport ! 800 -m state —state NEW -m recent —name LOCALRECENT —update —seconds 60 —hitcount 4 -j DROP

iptables -I INPUT 5 -p udp —dport ! 53 -m state —state NEW -m recent —name LOCALRECENT —update —seconds 60 —hitcount 4 -j

iptables -I INPUT 6 -p udp —dport ! 53 -m state —state NEW -m recent —name LOCALRECENT —update —seconds 60 —hitcount 4 -j DROP

The above are a bit more restrictive…. First we tag all tcp packets except those to port 800 *(our proxy), then all udp packets except those to port 53 *(dns)… next for each of those we LOG and then DROP when we get more than 4 in 60 seconds. So, port scans or bruteforce ssh attacks would clamp down after 4 tries in 60 seconds and any legitimate proxy/dns traffic would pass, but this lowers the limit. Notice the above does not affect ICMP pings and would seem to tighten the restrictions we set in FORWARD (at least the way their currently defined.) In order to keep our network – > firewall settings tighter than our network -> outside world, we might add -d IPADDRESS_OF_FIREWALL to the above rules. (Although in the test I did, I didn’t see a tighter restriction on LAN->outside world traffic…. (I may need to revisit this section to think through WHY that is.) MAYBE the answer is this…. traffic that is to be routed to another network doesn’t enter the INPUT chain, only the FORWARD chain? I should also note that IF we trip the INPUT chain rules by scanning the router to the outside world, it DOESN’T clamp down on outside world access (unless we use the same –name for both recent lists?) It may be that we WANT activity in one chain (INPUT) to work towards the quota on the other (FORWARD) chain.

So, where else could we go with this train of thought? Well, I found something interesting in looking at the iptables defences against brutessh attacks and one idea was to setup several limits or threshholds for the aggressive activity. This page has a good approach to this with regards to ssh blocking…. 3 attempts in 20 seconds, 15 in 200 seconds (a bit over 3 minutes), 80 in 2000 seconds (a bit over 33 minutes) and 400 in 20000 seconds (a bit over 5 and 1/2 hours). This approach might be more effective at blocking out the MOST aggressive of scanning attempts. They essentially use 4 lists of “recent” users for counting up the different limits.

There are weaknesses to the approach described above. One of those with the existing setup is that a patient attacker could do a slow port scan of the outside world. If they were targetting a single port (443 maybe) they could get 8 hosts a minute or 480 in an hour. The timing adjustments above could help mitigate that because 400+ hosts would get a user banned for 5+ hours.

That’s not the only weakness to this approach though. What if an attacker realizes what’s going on and decides to make OTHER users lives miserable by spoofing addresses. They could certainly disrupt all non-proxied traffic. (non-web-based mail/https services and ftp for instance.) If they spoofed external DNS IP’s I don’t see how they could significantly disrupt DNS lookups (those would be initiated from the firewall itself and NOT in the FORWARD chain (but in the OUTPUT chain ?) Further the LAN is using the firewall for DNS lookups, and THAT connectivity is allowed anyway.

Another problem I see is this, there is no “evil bit” in the tcp protocol that a malicious user can politely set to let others know of their malicious intentions, so you could still have abuse of the connection, it might be limited to using the wireless connection for a single connection to ANOTHER machine that a port scan can be initiated from. Also, with patient, slow, persistent testing of what’s exposed to this “somewhat untrusted” network, they might find weaknesses to exploit allowing access to machines that have greater outside world access. For instance, I had setup LAN DNS names in the IPCOP install, on doing a network scan of the entire LAN subnet, the firewall clamped down traffic as it should, however, since DNS was still a sanctioned service (on the firewall and not subject to our rules), then… I still got reverse dns lookups for some of the LAN machines, so a clever attacker might be able to use that information to hone in on a specific “up” machine and then carefully, slowly probe for vulnerable services.

In other words this should not be the ONLY firewall approach to protecting your LAN from a wireless network, you still ought to pay attention to hardening those services in the LAN.

One problem I see with the longer timeout rules listed above is what if client-A … “joe cracker” comes along and get’s a wireless address and attempts a massive portscan – 500 hosts full port lists and get’s banned for 5+ hours. Then client-B “cindy wireless user” comes along 2 hours after “joe cracker” has left, the connection has timed out and so, she get’s a new dhcp lease on the old IP that “joe cracker” had…. and suffers the continuing ban, so the timing of dhcp lease timeouts might also be considered in weighing the application of these rules.

All in all, this seems to be a fairly decent application of stateful firewall rules in ipchains to control abusive use of an open wireless connection. Any comments or suggestions on this idea and improvements are welcome. (Yes comments are moderated)


One thing I neglected to mention that I probably should. (Just in case) If you’re doing the above with iptables, you need to include the above scripts in your firewall startup script, or you’ll loose the chains on reboot. I thought that would be fairly obvious, but just thought clarity might save someone some frustration. (/etc/rc.d/firewall would be a good first place to look.)

   Send article as PDF   

Similar Posts