LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Security (https://www.linuxquestions.org/questions/linux-security-4/)
-   -   iptables good packet chain (instead of bad packet chain) (https://www.linuxquestions.org/questions/linux-security-4/iptables-good-packet-chain-instead-of-bad-packet-chain-680794/)

win32sux 11-03-2008 06:28 AM

iptables good packet chain (instead of bad packet chain)
 
Almost anyone who's used Netfilter/iptables for packet-filtering is familiar with "bad packet chains". They are user-built chains with rules that match packets with characteristics you consider to be "bad", mainly unusual TCP flag combinations. Essentially, a bad packet chain is a packet blacklist (default allow).

I've often wondered if anyone has ever taken the opposite approach. That is, use a whitelist (default deny) to create a "good packet chain" instead. Default deny has shown to be a much more solid approach than default allow when it comes to information security in general, and I would like to know if it is feasible to use it in this particular context.

Some specific questions I have might be: Would it be asking for trouble? Would it take too much work to build this kind of chain? Is it worth the effort? Your opinions on these and any other relevant questions would be greatly appreciated.

estabroo 11-03-2008 07:47 AM

Its definitely worth the effort. It is more secure especially if you default deny on all 3 main chains (input, forward, output). When you are first setting it up make sure you do it on a local machine that you have console access because more than likely you'll lock yourself out network wise at least once. Usually people only need a few "good" rules, though output can be messy which leads most people to just doing the deny on input and forward (which is still a good idea).

win32sux 11-03-2008 08:30 AM

Quote:

Originally Posted by estabroo (Post 3330021)
Its definitely worth the effort. It is more secure especially if you default deny on all 3 main chains (input, forward, output). When you are first setting it up make sure you do it on a local machine that you have console access because more than likely you'll lock yourself out network wise at least once. Usually people only need a few "good" rules, though output can be messy which leads most people to just doing the deny on input and forward (which is still a good idea).

It seems you've misunderstood my question. I'm not referring to default policies for the built-in chains. I'm referring specifically to user-built chains designed to filter packets with bad TCP flag combinations. These chains are AFAICT always designed using a default allow approach (not a policy, as user-built chains don't have policies). My question is about changing from a "match all packets with weird TCP flag combinations" approach to a "match all packets with proper TCP flag combinations" one. Whatever you've got set as a default policy for your built-in chains is irrelevant in this case. Thanks for your reply, though, as it allows me to clarify my question - something I was expecting I would need to do.

estabroo 11-03-2008 09:08 AM

hehe, glad I could be of some service at least, sorry it wasn't to answer the question :)

win32sux 11-04-2008 07:13 AM

You can see an example of a typical bad packet chain here:
Code:

# Our "hey, them's some bad tcp flags!" chain.
$IPT -N badflags
$IPT -A badflags -m limit --limit 15/minute -j LOG --log-prefix Badflags:
$IPT -A badflags -j DROP

# Drop those nasty packets! These are all TCP flag
# combinations that should never, ever occur in the
# wild. All of these are illegal combinations that
# are used to attack a box in various ways, so we
# just drop them and log them here.
$IPT -A INPUT -p tcp --tcp-flags ALL FIN,URG,PSH -j badflags
$IPT -A INPUT -p tcp --tcp-flags ALL ALL -j badflags
$IPT -A INPUT -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j badflags
$IPT -A INPUT -p tcp --tcp-flags ALL NONE -j badflags
$IPT -A INPUT -p tcp --tcp-flags SYN,RST SYN,RST -j badflags
$IPT -A INPUT -p tcp --tcp-flags SYN,FIN SYN,FIN -j badflags

As you can see, the chain sends to LOG and then to DROP any packets which are determined to have a weird combination of TCP flags. There are, of course, much more lengthy bad packet chains out there - this is just an example.

The idea I've been kicking around is to do the inverse, kinda like this:
Code:

$IPT -N GOOD_FLAGS
$IPT -A GOOD_FLAGS -p TCP --tcp-flags SYN,RST,ACK,FIN SYN -j ACCEPT
# The list of ACCEPT rules continues here.
$IPT -A GOOD_FLAGS -j LOG --log-prefix "BAD FLAGS: "
$IPT -A GOOD_FLAGS -j DROP

As you can see, this would send to ACCEPT any packet with a valid TCP flag combination, and those which don't have one will get sent to LOG and then to DROP. I've only used one possible ACCEPT rule to illustrate, the idea is of course to have enough rules to cover all proper TCP flag combinations (instead of trying to cover as many bad ones as possible).

win32sux 11-04-2008 11:05 AM

Okay, I decided to go for it and get started with a proof-of-concept. I've made a CHECK_FLAGS chain with matches for the TCP flag combinations which AFAIK I need for the handshake, data transfer, and termination phases. Here's the rules I'm using to test right now, with INPUT policy set to DROP and OUTPUT policy set to ACCEPT. This is on my laptop, which does run one service (BitTorrent), so the TCP flags I'm checking include both client and server angles.
Code:

$IPT -N CHECK_FLAGS
$IPT -A CHECK_FLAGS -p TCP --tcp-flags SYN,ACK,FIN,RST ACK -j ACCEPT
$IPT -A CHECK_FLAGS -p TCP --tcp-flags SYN,ACK,FIN,RST SYN,ACK -j ACCEPT
$IPT -A CHECK_FLAGS -p TCP --tcp-flags SYN,ACK,FIN,RST RST -j ACCEPT
$IPT -A CHECK_FLAGS -p TCP --tcp-flags SYN,ACK,FIN,RST RST,ACK -j ACCEPT
$IPT -A CHECK_FLAGS -p TCP --tcp-flags SYN,ACK,FIN,RST FIN -j ACCEPT
$IPT -A CHECK_FLAGS -p TCP --tcp-flags SYN,ACK,FIN,RST FIN,ACK -j ACCEPT
$IPT -A CHECK_FLAGS -j LOG --log-prefix "BAD TCP FLAGS: "
$IPT -A CHECK_FLAGS -j DROP


$IPT -A INPUT -i lo -j ACCEPT
$IPT -A INPUT -p TCP -m state --state ESTABLISHED -j CHECK_FLAGS
$IPT -A INPUT -p UDP -m state --state ESTABLISHED -j ACCEPT

$IPT -A INPUT -p TCP ! --syn -m state --state NEW -j LOG --log-prefix "NEW NOT SYN: "
$IPT -A INPUT -p TCP ! --syn -m state --state NEW -j DROP

$IPT -A INPUT -p ICMP -m state --state RELATED -j ACCEPT

$IPT -A INPUT -p TCP --dport 6881 -m state --state NEW -j ACCEPT

$IPT -A INPUT -j LOG --log-prefix "INPUT DROP: "

A few things to note: I'm only checking packets in the ESTABLISHED state, as the check for packets in state NEW is a one-liner (they need to have the SYN bit set and the RST, ACK, and FIN bits unset, which is what the --syn match does). Since I know that for my laptop all incoming packets in state RELATED should be ICMP, I'm just sending to DROP any which aren't. Of course, every packet sent to DROP is sent to LOG first so that I may spot problems. So far the CHECK_FLAGS chain seems to be working just fine, but I'm expecting that I'll need to make changes after I've tested it more thoroughly.

win32sux 11-06-2008 06:02 AM

Okay, after a couple days worth of testing, I've concluded that the whitelist approach is feasible. I can also say somewhat less conclusively (I still need to do more testing) that it works well. That said, I haven't really finished the chain yet, as I haven't been able to decide on how to deal with bad PSH and URG flags yet (I could easily do some blacklisting, but the whole point of my endeavor is to do whitelisting only).

Here's what I've got so far:
Code:

$IPT -N CHECK_TCP_FLAGS
$IPT -A CHECK_TCP_FLAGS -p TCP --tcp-flags SYN,ACK,FIN,RST ACK -j ACCEPT
$IPT -A CHECK_TCP_FLAGS -p TCP --tcp-flags SYN,ACK,FIN,RST SYN -j ACCEPT
$IPT -A CHECK_TCP_FLAGS -p TCP --tcp-flags SYN,ACK,FIN,RST SYN,ACK -j ACCEPT
$IPT -A CHECK_TCP_FLAGS -p TCP --tcp-flags SYN,ACK,FIN,RST RST -j ACCEPT
$IPT -A CHECK_TCP_FLAGS -p TCP --tcp-flags SYN,ACK,FIN,RST RST,ACK -j ACCEPT
$IPT -A CHECK_TCP_FLAGS -p TCP --tcp-flags SYN,ACK,FIN,RST FIN -j ACCEPT
$IPT -A CHECK_TCP_FLAGS -p TCP --tcp-flags SYN,ACK,FIN,RST FIN,ACK -j ACCEPT
$IPT -A CHECK_TCP_FLAGS -j LOG --log-prefix "BAD TCP FLAGS: "
$IPT -A CHECK_TCP_FLAGS -j DROP

$IPT -A INPUT -i lo -j ACCEPT
$IPT -A INPUT -p TCP -m state --state ESTABLISHED -j CHECK_TCP_FLAGS
$IPT -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
$IPT -A INPUT -p TCP --dport 6881 --syn -m state --state NEW -j ACCEPT
$IPT -A INPUT -j LOG --log-prefix "INPUT DROP: "

As you can see, pretty much the only thing that's changed since my last post is the addition of a match in the CHECK_TCP_FLAGS chain for packets with the SYN bit set (I've put the rule in bold). With that rule commented, I get several SYN packets being sent to DROP. This is interesting, as these are packets which the kernel sees as being in the ESTABLISHED state (otherwise they wouldn't be traversing that chain). Here's a sample from my log file to show you what I mean:
Quote:

Nov 6 05:22:56 candystore kernel: [ 7109.994754] BAD TCP FLAGS: IN=wlan0 OUT= MAC=01:18:de:b4:b8:c0:00:13:cf:1d:12:3c:08:00 SRC=80.173.8.58 DST=192.168.1.100 LEN=64 TOS=0x00 PREC=0x00 TTL=52 ID=5636 DF PROTO=TCP SPT=53143 DPT=6881 WINDOW=65535 RES=0x00 SYN URGP=0
Nov 6 05:22:59 candystore kernel: [ 7110.558050] BAD TCP FLAGS: IN=wlan0 OUT= MAC=01:18:de:b4:b8:c0:00:13:cf:1d:12:3c:08:00 SRC=80.173.8.58 DST=192.168.1.100 LEN=64 TOS=0x00 PREC=0x00 TTL=52 ID=5898 DF PROTO=TCP SPT=53143 DPT=6881 WINDOW=65535 RES=0x00 SYN URGP=0
Nov 6 05:23:04 candystore kernel: [ 7111.642276] BAD TCP FLAGS: IN=wlan0 OUT= MAC=01:18:de:b4:b8:c0:00:13:cf:1d:12:3c:08:00 SRC=80.173.8.58 DST=192.168.1.100 LEN=64 TOS=0x00 PREC=0x00 TTL=52 ID=6410 DF PROTO=TCP SPT=53164 DPT=6881 WINDOW=65535 RES=0x00 SYN URGP=0
Nov 6 05:23:07 candystore kernel: [ 7112.320472] BAD TCP FLAGS: IN=wlan0 OUT= MAC=01:18:de:b4:b8:c0:00:13:cf:1d:12:3c:08:00 SRC=80.173.8.58 DST=192.168.1.100 LEN=64 TOS=0x00 PREC=0x00 TTL=52 ID=6667 DF PROTO=TCP SPT=53164 DPT=6881 WINDOW=65535 RES=0x00 SYN URGP=0
Nov 6 05:23:11 candystore kernel: [ 7113.216864] BAD TCP FLAGS: IN=wlan0 OUT= MAC=01:18:de:b4:b8:c0:00:13:cf:1d:12:3c:08:00 SRC=80.173.8.58 DST=192.168.1.100 LEN=48 TOS=0x00 PREC=0x00 TTL=52 ID=6993 DF PROTO=TCP SPT=53164 DPT=6881 WINDOW=65535 RES=0x00 SYN URGP=0
Nov 6 05:23:27 candystore kernel: [ 7116.773364] BAD TCP FLAGS: IN=wlan0 OUT= MAC=01:18:de:b4:b8:c0:00:13:cf:1d:12:3c:08:00 SRC=75.34.32.251 DST=192.168.1.100 LEN=48 TOS=0x00 PREC=0x00 TTL=118 ID=49628 DF PROTO=TCP SPT=3151 DPT=6881 WINDOW=64240 RES=0x00 SYN URGP=0
Nov 6 05:24:09 candystore kernel: [ 7125.650846] BAD TCP FLAGS: IN=wlan0 OUT= MAC=01:18:de:b4:b8:c0:00:13:cf:1d:12:3c:08:00 SRC=79.220.62.58 DST=192.168.1.100 LEN=64 TOS=0x00 PREC=0x00 TTL=54 ID=48585 DF PROTO=TCP SPT=43137 DPT=6881 WINDOW=65535 RES=0x00 SYN URGP=0
Nov 6 05:24:32 candystore kernel: [ 7130.554235] BAD TCP FLAGS: IN=wlan0 OUT= MAC=01:18:de:b4:b8:c0:00:13:cf:1d:12:3c:08:00 SRC=218.242.68.109 DST=192.168.1.100 LEN=52 TOS=0x00 PREC=0x00 TTL=52 ID=51218 DF PROTO=TCP SPT=15772 DPT=6881 WINDOW=65535 RES=0x00 SYN URGP=0
Nov 6 05:25:20 candystore kernel: [ 7140.799262] BAD TCP FLAGS: IN=wlan0 OUT= MAC=01:18:de:b4:b8:c0:00:13:cf:1d:12:3c:08:00 SRC=203.176.178.23 DST=192.168.1.100 LEN=64 TOS=0x00 PREC=0x00 TTL=53 ID=52041 DF PROTO=TCP SPT=50996 DPT=6881 WINDOW=65535 RES=0x00 SYN URGP=0
Nov 6 05:25:25 candystore kernel: [ 7141.944061] BAD TCP FLAGS: IN=wlan0 OUT= MAC=01:18:de:b4:b8:c0:00:13:cf:1d:12:3c:08:00 SRC=203.176.178.23 DST=192.168.1.100 LEN=64 TOS=0x00 PREC=0x00 TTL=53 ID=57190 DF PROTO=TCP SPT=50996 DPT=6881 WINDOW=65535 RES=0x00 SYN URGP=0
Nov 6 05:26:32 candystore kernel: [ 7156.678510] BAD TCP FLAGS: IN=wlan0 OUT= MAC=01:18:de:b4:b8:c0:00:13:cf:1d:12:3c:08:00 SRC=82.11.32.84 DST=192.168.1.100 LEN=64 TOS=0x00 PREC=0x00 TTL=53 ID=40447 DF PROTO=TCP SPT=62799 DPT=6881 WINDOW=65535 RES=0x00 SYN URGP=0
Nov 6 05:29:28 candystore kernel: [ 7195.533458] BAD TCP FLAGS: IN=wlan0 OUT= MAC=01:18:de:b4:b8:c0:00:13:cf:1d:12:3c:08:00 SRC=80.179.37.252 DST=192.168.1.100 LEN=60 TOS=0x00 PREC=0x00 TTL=54 ID=41365 DF PROTO=TCP SPT=53183 DPT=6881 WINDOW=5840 RES=0x00 SYN URGP=0
Nov 6 05:29:34 candystore kernel: [ 7197.818324] BAD TCP FLAGS: IN=wlan0 OUT= MAC=01:18:de:b4:b8:c0:00:13:cf:1d:12:3c:08:00 SRC=90.25.251.215 DST=192.168.1.100 LEN=64 TOS=0x00 PREC=0x00 TTL=52 ID=37093 DF PROTO=TCP SPT=58356 DPT=6881 WINDOW=65535 RES=0x00 SYN URGP=0
Nov 6 05:29:50 candystore kernel: [ 7204.241106] BAD TCP FLAGS: IN=wlan0 OUT= MAC=01:18:de:b4:b8:c0:00:13:cf:1d:12:3c:08:00 SRC=79.220.62.58 DST=192.168.1.100 LEN=64 TOS=0x00 PREC=0x00 TTL=54 ID=52674 DF PROTO=TCP SPT=33283 DPT=6881 WINDOW=65535 RES=0x00 SYN URGP=0
Nov 6 05:30:17 candystore kernel: [ 7215.477959] BAD TCP FLAGS: IN=wlan0 OUT= MAC=01:18:de:b4:b8:c0:00:13:cf:1d:12:3c:08:00 SRC=72.201.198.107 DST=192.168.1.100 LEN=60 TOS=0x00 PREC=0x00 TTL=56 ID=2813 DF PROTO=TCP SPT=55044 DPT=6881 WINDOW=5840 RES=0x00 SYN URGP=0
I used QUOTE tags instead of CODE tags for that as otherwise the page rendering gets all weird and stuff, sorry. Can anyone shed some light as to what conditions would make Linux/Netfilter treat certain SYN packets as being in the ESTABLISHED state?


All times are GMT -5. The time now is 06:28 PM.