Advanced Netfilter

...or, “A bunch of iptables stuff off the top of my head that you may not have known about”.

CALUG

Marc Curry

11/9/2005

Subtopics

Custom chains

Stateful packet inspection

Match specifiers

Port knocking

Basics

iptables -t table -A chain match_criteria -j target

Table	Default Policy

Rule(s)	Match Specs

Target

Tables & their Chains

Specified with “-t” option

filter (default)

INPUT, FORWARD, OUTPUT

nat

OUTPUT, PREROUTING, POSTROUTING

mangle

All of the above....

Filter Checkpoints

PREROUTING

INPUT

FORWARD

OUTPUT

POSTROUTING

Local Processes

In

Out

?

Routing

Decision

Basic Targets

ACCEPT

Allow the packet

DROP

Literally -- send no message back to the sender

LOG [--log-{level,prefix}]

Log packet info to syslogd

REJECT

Send back an error-packet in response

--reject-with type

Default type: icmp-port-unreachable

Others:	icmp-{net,host,proto}-unreachable

icmp-{net,host,admin}-prohibited

Simple Chain Example

iptables -P INPUT DROP

iptables -A INPUT -p tcp -i eth0 –dport 22 -s 192.168.0.0/24 -j ACCEPT

Custom Chains

Think if them as a “subroutine call” for your chain rules

Delete a custom chain (-X chain)

Create a new custom chain (-N chain)

Example 1: Counter

iptables -N count_bin

iptables -A count_bin -j RETURN

iptables -A INPUT -i eth0 -p tcp -m tcp --dport 2000:3000 -j count_bin

Zero out count with “iptables -Z count_bin”

Inspect byte/packet count with “iptables -v -L”

Example 2: Log-then-drop

iptables -N logdrop

iptables -A logdrop -j LOG --log-prefix "Netbios: "

iptables -A logdrop -j DROP

iptables -A INPUT -p tcp -i eth0 --dport 139 -j logdrop

Nov 9 16:58:30 server1 kernel: Netbios: IN=eth0 OUT= MAC=00:0d:56:80:82:24:00:0d:60:5f:33:20:08:00 SRC=192.168.0.14 DST=192.168.0.254 LEN=60 TOS=0x10 PREC=0x00 TTL=64 ID=41366 DF PROTO=TCP SPT=50054 DPT=139 WINDOW=5840 RES=0x00 SYN URGP=0

Stateful Packets

-m state –state STATE1[,...]

modprobe ip_conntrack

modprobe ip_conntrack_ftp

Uses more memory

Stateful Inspection

ESTABLISHED

associated with a connection which has seen packets in both directions

RELATED

starting a new connection, but is associated with an existing connection

INVALID

associated with no known connection

NEW

started a new connection, or otherwise associated with a connection which has not seen packets in both directions

Example 1: One-way ssh

iptables -A INPUT -i eth0 -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT

iptables -A OUTPUT -o eth0 -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT

Example 2: One-way ftp

iptables -A INPUT -i eth0 -p tcp --sport 21 -m state --state ESTABLISHED -j ACCEPT

iptables -A OUTPUT -o eth0 -p tcp --dport 21 -m state --state NEW,ESTABLISHED -j ACCEPT

iptables -A INPUT -i eth0 -p tcp --sport 20 -m state --state ESTABLISHED,RELATED -j ACCEPT

iptables -A OUTPUT -o eth0 -p tcp --dport 20 -m state --state ESTABLISHED -j ACCEPT

Example 3: One-way, period.

iptables -P INPUT DROP

iptables -I INPUT -i ! lo -m state –state ESTABLISHED,RELATED -j ACCEPT

Match specifiers

limit

recent

owner

random

match

limit Mechanism

Imagine a bucket of tokens. Every packet requires a token to pass.

--limit-burst

The max # of tokens the bucket will hold

--limit

The rate at which the bucket is refilled w/ tokens

limit Example

iptables -A logdrop -m limit --limit 2/minute --limit-burst 1 -j LOG --log-prefix "SSH Brute Force: "

Problem: cuts off the service, even for the “good guys”.

Solution: “recent” match specifier.

recent Match Specifier

-m recent

--rcheck (check)

--name (..this list)

--hitcount N (...to see if >N hits are in there)

--seconds M (...within the past M seconds)

--set (Add this event to the list)

recent Example 1

Input packets are checked against the SSH recent list, if >3packets /20s, then logdrop.

iptables -A INPUT -m recent --name SSH --rcheck --hitcount 3 --seconds 20 -j logdrop

If this is a new ssh packet, add it to SSH list.

iptables -A INPUT -p tcp -i eth0 -m state --state NEW --dport 22 -m recent --name SSH --set -j ACCEPT

recent Example 2

If someone knocks on my port 139, drop ALL of their traffic for 20 seconds.

iptables -A INPUT -m recent --name portscan --rcheck --seconds 20 -j DROP

iptables -A INPUT -p tcp -i eth0 --dport 139 -m recent --name portscan --set -j REJECT

owner Match Specifier

Matches if packet was created by...

-m owner

--uid-owner userid

--gid-owner groupid

--pid-owner processid

--sid-owner sessionid

--cmd-owner name

random Match Specifier

Randomly matches a certain percentage of all packets (50% default)

-m random

--average percent

--tcp-flags

Block commonly used port scans

--tcp-flags inspect_flag[,...] set_flag

$IPTABLES -t mangle -A PREROUTING -p tcp --tcp-flags ALL FIN,URG,PSH -j LOG --log-prefix "NMAP-XMAS SCAN:" --log-tcp-options --log-ip-options

$IPTABLES -t mangle -A PREROUTING -p tcp --tcp-flags ALL NONE -j LOG --log-prefix "NMAP-NULL SCAN:" --log-tcp-options --log-ip-options

$IPTABLES -t mangle -A PREROUTING -p tcp --tcp-flags SYN,RST SYN,RST -j LOG --log-prefix "SYN/RST SCAN:" --log-tcp-options --log-ip-options

$IPTABLES -t mangle -A PREROUTING -p tcp --tcp-flags SYN,FIN SYN,FIN -j LOG --log-prefix "SYN/FIN SCAN:" --log-tcp-options --log-ip-options

$IPTABLES -t mangle -A PREROUTING -p tcp --tcp-flags ALL FIN,URG,PSH -j DROP

$IPTABLES -t mangle -A PREROUTING -p tcp --tcp-flags ALL NONE -j DROP

$IPTABLES -t mangle -A PREROUTING -p tcp --tcp-flags SYN,RST SYN,RST -j DROP

$IPTABLES -t mangle -A PREROUTING -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP

Port and IP address Ranges

IP Range

iptables -A FORWARD -m iprange --src-range 192.168.1.5-192.168.1.10 -j ACCEPT

iptables -A FORWARD -m iprange --dst-range 10.0.0.0-10.255.255.255 -j ACCEPT

Port Range & Muliport

iptables -A INPUT -p tcp --dport 1:1024 -j ACCEPT

iptables -A INPUT -p tcp -m tcp -m multiport --source-ports 25,110,143 -j ACCEPT

NETMAP Target

Provides a target for the nat table

Creates a static 1:1 mapping of the network address, while keeping host addresses intact.

iptables -t nat -A PREROUTING -d 1.2.3.0/24 -j NETMAP --to 5.6.7.0/24

iptables -t nat -A POSTROUTING -s 5.6.7.0/24 -j NETMAP --to 1.2.3.0/24

REDIRECT Target

iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 81

Port Knocking

Only allow ssh connections after a connection attempt is made to port 2200, followed by an ICMP echo request

Only one recent list can be used at a time, so we need to use MARK to pass hosts between lists, doing all recent list modification in the mangle table

Can't use –remove and –seconds, so have to do that part in 2 steps

Port Knocking, Phase 1

Allow things with mark set to 50

iptables -A INPUT -p tcp --dport 22 -m mark --mark 50 -j ACCEPT

Block everything else to port 22

iptables -A INPUT -p tcp --dport 22 -j DROP

Add the port 2200 knock to PHASE1 recent list

iptables -t mangle -A INPUT -p tcp --dport 2200 -m recent --name PHASE1 --set -j ACCEPT

Port Knocking, Phase 2

Check for subsequent knock in form of ping & add to PHASE2

iptables -t mangle -A INPUT -p icmp --icmp-type echo-request -m recent --name PHASE1 --seconds 60 --rcheck -j MARK --set-mark 51

iptables -t mangle -A INPUT -m mark --mark 51 -m recent --name PHASE1 --remove -j MARK --set-mark 51

iptables -t mangle -A INPUT -m mark --mark 51 -m recent --name PHASE2 --set -j ACCEPT

Port Knocking, Final Phase

Finally, for anything that made it to PHASE2, set the mark to 50

iptables -t mangle -A INPUT -m recent --name PHASE2 --seconds 60 --update -j MARK --set-mark 50

Homework Challenge Problems

Kernel recompile

Kernel netfilter modules:

/lib/modules/<kernelver>/kernel/net/ipv4/netfilter/*.ko

/lib/iptables, /lib64/iptables

libipt_name.so used for match specifiers

Uppercase=targets, Lowercase=match spec

Restrict Parallel Connections

Allow 2 telnet connections per client host.

iptables -p tcp --syn --dport 23 -m connlimit --connlimit-above 2 -j REJECT

Limit the number of parallel http requests to 16 per class C sized network (24 bit netmask)

iptables -p tcp --syn --dport 80 -m connlimit --connlimit-above 16 --connlimit-mask 24 -j REJECT

TARPIT Target

Instead of dropping those SSH attacks, send them to a tarpit!

Tarpit ignores attempts to close the connection & accepts no data from the remote end, but asks the remote to re-send packets.

Few local resources are used, but the remote system has to wait up to 25 minutes to time out the connection so it can attack someone else.

Load Balancing with nth

iptables -t nat -A PREROUTING -p tcp –dport 80 -m state --state NEW -m nth --counter 0 --every 2 --packet 0 -j DNAT –to-dest 192.168.0.1

iptables -t nat -A PREROUTING -p tcp –dport 80 -m state --state NEW -m nth --counter 0 --every 2 --packet 1 -j DNAT –to-dest 192.168.0.2

Closing Tips

Drop ALL, then allow specific traffic

Use a script:

Maintain with CVS/Subversion

Easier to make changes

Variables

Ensure /proc/sys tunable parameters are set

Ensure proper kernel modules are loaded

Comments

Easy to rebuild on upgrade/data loss

Monitor those Logs!

2005-11-08T20:54:51