Lug@GT Setting up a Firewall Securely
Presented on Sept. 14 2005 by Matt Wood (matt /at woodzy /dot com)


Intro to some FW's

IpTablesPF
Nifty Features
  • Modules
  • Built-in Connection Tracking (FTP)
  • Rate Limiting
  • Per Rule Statistics
  • EXTENSIVE Logging Features
  • Scrub (Packet Normalization)
  • Queuing Built in
  • Anchors & Tables
  • Rule Shorthand (Antispoof)
Problems
  • AltQ
  • Syntax/Grammar
  • Dynamic Changes
  • Hacks to Save Rules
  • Requires 3rd Party app for connection tracking
  • Some syntax isn't too intuitive
All in all, if you can't tell, I'm kinda partial to PF...

Example Statistics Output IPTables

woodzy@va-www ~# iptables -vnL
Chain INPUT (policy DROP 41071 packets, 1811K bytes)
 pkts bytes target     prot opt in     out     source               destination
  20M 3029M ACCEPT     all  --  eth0   *       0.0.0.0/0            0.0.0.0/0           state RELATED,ESTABLISHED
8415K  563M ACCEPT     all  --  lo     *       0.0.0.0/0            0.0.0.0/0
    0     0 DROP       all  --  eth0   *       127.0.0.0/8          0.0.0.0/0
    0     0 DROP       all  --  eth0   *       192.168.0.0/24       0.0.0.0/0
    0     0 DROP       all  --  eth0   *       10.0.0.0/8           0.0.0.0/0
  15M  6661 DROP       tcp  --  *      *       67.162.151.217       0.0.0.0/0           tcp flags:0x16/0x02
 868K   45M ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp dpt:80 flags:0x16/0x02
  629 32444 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp dpt:443 flags:0x16/0x02
48524 2902K ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp dpt:22 flags:0x16/0x02
 7976  403K ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp dpt:25 flags:0x16/0x02
 1058 63460 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp dpt:993 flags:0x16/0x02
   24  1312 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp dpt:2401 flags:0x16/0x02
99881   20M DROP       udp  --  eth0   *       0.0.0.0/0            0.0.0.0/0
 7454  298K DROP       tcp  --  eth0   *       0.0.0.0/0            0.0.0.0/0           tcp flags:0x16/0x02

Chain FORWARD (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 9413K packets, 814M bytes)
 pkts bytes target     prot opt in     out     source               destination
  21M   22G ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp spt:80
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp spt:21
 792K  128M ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp spt:22
 132K   11M ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp spt:25

Example Statistics PF

root@ga /home/woodzy# pfctl -sinfo
Status: Enabled for 24 days 10:24:24          Debug: Urgent

Hostid: 0xabc896b8

Interface Stats for ne3               IPv4             IPv6
  Bytes In                     33188249329              128
  Bytes Out                    21768735045                0
  Packets In
    Passed                        54085054                0
    Blocked                        4839289                2
  Packets Out
    Passed                        54179338                0
    Blocked                             68                0

State Table                          Total             Rate
  current entries                     1196
  searches                       223346490          105.8/s
  inserts                          5782539            2.7/s
  removals                         5781343            2.7/s
Counters
  match                           10600030            5.0/s
  bad-offset                             0            0.0/s
  fragment                               0            0.0/s
  short                                 17            0.0/s
  normalize                             31            0.0/s
  memory                              3899            0.0/s

Basic Syntax of IPTables & PF

IPTables (A Servers Host Based Firewall)

#!/bin/bash
#Set Default
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

# Flush (-F) all specific rules
iptables -F INPUT
iptables -F FORWARD
iptables -F OUTPUT
iptables -F -t nat

# Permit packets in to firewall itself that are part of existing and related connections.
iptables -A INPUT -i eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT

# Allow all inputs to firewall from the internal network and local interfaces
iptables -A INPUT -i lo -s 0/0 -d 0/0 -j ACCEPT

# Deny any packet coming in on the public internet interface eth0
# which has a spoofed source address from our local networks:
iptables -A INPUT -i eth0 -s 127.0.0.0/8 -j DROP
iptables -A INPUT -i eth0 -s 192.168.0.0/24 -j DROP
iptables -A INPUT -i eth0 -s 10.0.0.0/8 -j DROP

#block bastard
iptables -A INPUT -p tcp -s 67.162.151.217/32 -d 0/0 --syn -j DROP

# Accept all tcp SYN packets on allowed ports
#Enable http
iptables -A INPUT -p tcp -s 0/0 -d 0/0 --destination-port 80 --syn -j ACCEPT
#Enable https
iptables -A INPUT -p tcp -s 0/0 -d 0/0 --destination-port 443 --syn -j ACCEPT
#Enable remote ssh
iptables -A INPUT -p tcp -s 0/0 -d 0/0 --destination-port 22 --syn -j ACCEPT
#Enable incoming SMTP
iptables -A INPUT -p tcp -s 0/0 -d 0/0 --destination-port 25 --syn -j ACCEPT
#Enable income FTP
#iptables -A INPUT -p tcp -s 0/0 -d 0/0 --destination-port 21 --syn -j ACCEPT
#Enable strange VNC port
#iptables -A INPUT -p tcp -s 0/0 -d 0/0 --destination-port 31333 --syn -j ACCEPT
#Enable remote pop3s
#iptables -A INPUT -p tcp -s 0/0 -d 0/0 --destination-port 995 --syn -j ACCEPT
#Enable remote imaps
iptables -A INPUT -p tcp -s 0/0 -d 0/0 --destination-port 993 --syn -j ACCEPT
#Enable remote cvs
iptables -A INPUT -p tcp -s 0/0 -d 0/0 --destination-port 2401 --syn -j ACCEPT

#Count some specific droppings
iptables -A INPUT -i eth0 -s 0/0 -d 0/0 -p udp -j DROP
iptables -A INPUT -i eth0 -s 0/0 -d 0/0 -p tcp --syn -j DROP

##Add this just to count our output to the world
iptables -A OUTPUT -p tcp -s 0/0 -d 0/0 --source-port 80 -j ACCEPT
iptables -A OUTPUT -p tcp -s 0/0 -d 0/0 --source-port 21 -j ACCEPT
iptables -A OUTPUT -p tcp -s 0/0 -d 0/0 --source-port 22 -j ACCEPT
iptables -A OUTPUT -p tcp -s 0/0 -d 0/0 --source-port 25 -j ACCEPT

PF (A Gateway Router/NAT Based Firewall)

root@ga /home/woodzy# cat /etc/pf.conf
# macros
int_if = "xl0"
ext_if = "ne3"

tcp_services = "{ 22,53,80 }"
udp_services = "{ 53 }"
intern_tcp_services = "{ 6880:6889, 2222 }"
intern_udp_services = "{ 6880:6889 }"
icmp_types = "echoreq"

priv_nets = "{ 127.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8 }"
#priv_nets="{127.0.0.0/8}"

# options
set block-policy drop
set loginterface $ext_if
set optimization normal

# scrub
scrub in all fragment reassemble
scrub out on $ext_if random-id

#queues
#altq on $ext_if priq bandwidth 100% queue { q_pri, q_bt, q_def }
#queue q_pri priority 7
#queue q_bt priority 2 priq
#queue q_def priority 5 priq(default)

# nat/rdr
nat on $ext_if from $int_if:network to any -> ($ext_if)

#BT stuff
rdr on $ext_if proto udp from any to $ext_if:0 port 6881:6889 -> 10.13.13.14 port 6881:6889
rdr on $ext_if proto tcp from any to $ext_if:0 port 6881:6889 -> 10.13.13.14 port 6881:6889
rdr on $ext_if proto tcp from any to $ext_if:0 port 2222 -> 10.13.13.14 port 2222

# filter rules
block log all

pass quick on lo0 all

#ssh blocks
block drop in quick log on $ext_if from <sshblocks> to any
#end ssh blocks


block drop in  quick log on $ext_if from $priv_nets to any
block drop out quick log on $ext_if from any to $priv_nets

pass in on $ext_if inet proto tcp from any to ($ext_if) \
   port $tcp_services flags S/SA
pass in on $ext_if inet proto udp from any to ($ext_if) \
   port $udp_services

#pass in rules for RDR
pass in on $ext_if proto tcp from any to any \
   port $intern_tcp_services keep state
pass in on $ext_if proto udp from any to any \
   port $intern_udp_services

pass in inet proto icmp all icmp-type $icmp_types keep state

pass in  on $int_if from $int_if:network to any keep state
pass out on $int_if from any to $int_if:network keep state

pass out on $ext_if proto tcp all modulate state #flags S/SA queue (q_def, q_pri)
pass out on $ext_if proto { udp, icmp } all keep state

SSH Blocks Table

root@ga /home/woodzy# pfctl -tsshblocks -Tshow
   24.137.111.42
   61.66.208.60
   61.66.208.117
   61.72.102.26
   61.74.67.139
   61.79.228.100
   61.82.137.141
   61.85.239.211
   61.129.49.27
   61.218.8.110
   61.220.244.252
   62.73.5.215
    .
    .
    .
   220.70.167.67
   220.95.231.111
   220.194.58.118
   221.113.36.252
   221.115.123.27
   221.166.169.102
   222.45.45.132
   222.88.82.76
   222.118.5.179
   222.122.13.23
   222.237.79.237
root@ga /home/woodzy# wc -l /etc/pf.ssh.blocks
     6347 /etc/pf.ssh.blocks
root@ga /home/woodzy# cat ~/scripts/ssh-failedlogin-blocker.pl
#!/usr/bin/perl
use File::Tail;
use warnings;

my $count = 0;
my @iplist =();
my @occurlist =();
my $line = "";
my $ip = 0;
my $i;
my $file = File::Tail->new(name=>"/var/log/authlog",maxinterval=>1,resetafter=>86400);


while(defined($line=$file->read))
{
  if ($line =~ m/Failed password for root from ([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})/)
  {
    insertIP($1);
  }
  elsif ($line =~ m/Illegal user [a-zA-Z0-9]+ from ([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})/)
  {
    insertIP($1);
  }

  if ($i > $#iplist)
  {
    #print "if, added, root, ". $ip ."\n";
    $iplist[$i] = $ip;
    $occurlist[$i] = 1;
  }
}

exit;

sub insertIP
{
   $ip = $_[0];
   for($i = 0; $i <= $#iplist; $i++)
   {
     if ($iplist[$i] eq $ip)
     {
       print "if, found, root ". $ip ."\n";
       $occurlist[$i]++;
       if ($occurlist[$i] > 5)
       {
         #print "already added...\n";
         $orange=`pfctl -t sshblocks -T replace -f /etc/pf.ssh.blocks`
       }
       elsif ($occurlist[$i] > 4)
       {
         open(SSH_BLOCK,">> /etc/pf.ssh.blocks") or die "crap file open failed $!";
         #print SSH_BLOCK "$ip\n";
         $orange=`pfctl -t sshblocks -T replace -f /etc/pf.ssh.blocks`;
         close(SSH_BLOCK);
       }
       last;
     }
   }
}

#vim expandtab:cin:sw=4

Network Design

Stolen from http://www.geocities.com/boothmonkey2000/variation1.gif
Stolen from http://www.geocities.com/boothmonkey2000/variation2.gif

What a firewall / packet filter should be

Why do network administrators want/need firewalls? Well I'm sure the target audience is pretty familiar with reasons why such a device proves necessary (Kernel Flaws, Unwanted Worms, (D)Dos, Spyware, Dr. Jekyl and Mr. Hyde problems). A firewall on a network is alot like a windshield on your car, you want to let through the information you want (the road, lines, other cars, protons) and at the same time keep the bugs and wind out of your eyes. But a firewall isn't perfect and should never be considered a protection against actual threats. Going with the windsheild analogy... a metal pipe or high intensity gamma rays aren't going to be stopped by a windshield at speed. Same goes for firewalls, a 0day for (insert daemon here... ie Apache) is gonna plow right through any standard firewall. A firewalls true purpose is not to protect from "evil people" like the commercial giants and media want you to think, but protect your computers from run of the mill miscreants and your own configuration/installation mistakes. Of course a "drop all" rule is effective in protecting you from the Internet very nicely.

Why a NAT is not a Firewall!

All these Cable/DSL NAT/Router/Crapwall/Broken POS things that are sold nowadays do some good, but do not do nearly as much as what the consumer thinks its actually doing. In some cases these little appliances will destroy your network through explosions and rabid penguins. But seriously stuff like: a maximum of 2k states in table, arp irritations, foolish web interface designs, backdoors, slow processor, HUGELY vulnerable to SynFlood Attacks, dhcp lease file corruption... they are just generally unstable. But this rant has nothing to do with actual Network Address Translation devices... we all know what these are right? Both IPTables and PF allow for some type of NAT to be integrated into the firewall, but by no means does the translation of addresses secure a host on a network. (wrt54g idefense stuff... if you dont have openwrt on them your screwed)

NAT'ing Security Risks and Advantages

Advantages Risks

QoS

This isn't too important for the standard user, but there are some optimizations that prove exceptionally useful (especially on campus network style setups). Connections such as BitTorrent readily fill your upload and download pipe with data,acks and leave little for for the syn's and synacks needed to setup standard connections. Such that if you happen to be downloading the DVD Screener for 40 Year Old Virgin while wanting to ssh and surf the net, you'll see a significant delay while opening new connections or starting to send packets (or a noticed delay in reception of packets) because your pipe is so full.

Explanation from "http://www.benzedrine.cx/ackpri.html"
Even when a TCP connection is used to send data only in one direction (like when downloading a file through ftp), TCP acknowledgements (ACKs) must be sent in the opposite direction, or the peer will assume that its packets got lost and retransmit them. To keep the peer sending data at the maximum rate, it's important to promptly send the ACKs back.

When the uplink is saturated by other connections (like a concurrent upload), all outgoing packets get delayed equally by default. Hence, a concurrent upload saturating the uplink causes the outgoing ACKs for the download to get delayed, which causes the drop in the download throughput.

The basic PF ruleset that accomplishes something similiar with BitTorrent queuing added this looks like the following...
ext_if="interfaceName"

altq on $ext_if priq bandwidth $BWUpload queue { std_que, bt_que, ack_out }
queue ack_out priority 7
queue bt_que priority 1
queue std_que priority 3 priq(default)

pass out on $ext_if proto tcp from $ext_if to any port 6881:6889 flags S/SA keep state queue (bt_que, ack_out)
pass out on $ext_if proto tcp from $ext_if to any flags S/SA keep state queue (std_que, ack_out)
pass in  on $ext_if proto tcp from any to $ext_if port 6881:6889 flags S/SA keep state queue (bt_que, ack_out)
pass in  on $ext_if proto tcp from any to $ext_if flags S/SA keep state queue (std_que, ack_out)

ICMP Traffic that needs to be slapped

Basic rule here is drop everything you don't specifically care about. The only type of ICMP message I allow through my firewalls is echoreq everything else is dropped before it crosses the FW. Some other types that I generally allow to reach the firewall itself are ICMP message types such as "host/port-unreachable." Alot of other types are generally do not need to really be worried about, and 5 of the 17 types are more useful for DoS attacks than helpful in indenfication of errors.

Source and Destination Filtering from the INTERNAL Devices

What that title means is you really want to have rules that specifically allow traffic EXITing and ENTERing... none of this ESTABLISHED/RELATED and allow all packets on the inside out. It does negate some of the usefulness of the firewall.

For Example...
iptables -P INPUT DROP
iptables -P OUTPUT DROP
iptables -A INPUT -p tcp -s 0/0 -d 0/0 --destination-port 80 --syn -j ACCEPT
iptables -A OUTPUT -p tcp -s 0/0 -d 0/0 --source-port 80 -j ACCEPT
block drop in all
block drop out all
pass in on $ext_if inet proto tcp from any to ($ext_if) \
   port $tcp_services
pass out on $ext_if proto tcp from any to any port $tcp_services modulate state
Of course this is an extreme example where you ONLY have a web server on port 80 running, but as you can see this would restrict unauthorized traffic from leaving the internal side of the network. This is more applicable to Host based firewalls than for router/gateways. This is also pretty tedious to setup and maintain and the calculated gain is questionable... because if an intruder were to compromise a service on your machine... the chances of compromising the firewall are rather high as well.

Cute Tricks

IPTables SSH Rate Limit

iptables -A INPUT -m hashlimit -m tcp -p tcp --dport 22 --hashlimit 1/min --hashlimit-mode srcip --hashlimit-name ssh \
   -m state --state NEW -j LOG --log-prefix SSHBRUTE

IPTables Forced Replies...

iptables -A LOGREJECT -j LOG --log-level warning --log-prefix 'WEBDROP ' --log-tcp-sequence --log-ip-options --log-tcp-options
iptables -A LOGREJECT -p tcp -j REJECT --reject-with tcp-reset
iptables -A LOGREJECT -j REJECT --reject-with icmp-port-unreachable

Stop NMAP OS Fingerprinting

set-block-policy return

block in log quick proto tcp flags FUP/WEUAPRSF
block in log quick proto tcp flags WEUAPRSF/WEUAPRSF
block in log quick proto tcp flags SRAFU/WEUAPRSF
block in log quick proto tcp flags /WEUAPRSF
block in log quick proto tcp flags SR/SR
block in log quick proto tcp flags SF/SF
(S)YN: synchronize sequence numbers.
(A)CK: acknowledge.
(R)ST: reset.
(F)IN: Finish.
(P)USH: push.
(U)RG: urgent pointer.
(E)CE: (ECN-Echo) explicit congestion notification echo.
C(W)R: congestion window reduced.

More NMAP Spoilers

This messes up the Stealth FIN/Xmas Tree and Null scan modes... it doesn't totally screw it up, but reduces the accuracy of identifying filtered ports versus open/closed invisible ports.
block in log quick on $Ext inet proto tcp from any to any flags FUP/FUP
block in log quick on $Ext inet proto tcp from any to any flags SF/SFRA
block in log quick on $Ext inet proto tcp from any to any flags /SFRA
block in log quick on $Ext proto tcp from any to any flags SAFRPU
block in log quick on $Ext proto tcp from any to any flags SAFRU/SAFRU

PFTop

pfTop: Up State 1-22/402, View: default, Order: none
PR   DIR SRC                  DEST                 STATE   AGE   EXP  PKTS BYTES
tcp  Out 10.13.13.14:48954    205.188.8.8:5190      4:4  2644m 17995 58683 6745K
tcp  Out 10.13.13.14:59986    130.207.107.12:993    4:4  2633m 17968 23489 1878K
tcp  In  10.13.13.14:41810    10.13.13.1:22         4:4    235 18000   806  180K
tcp  In  10.13.13.14:48954    205.188.8.8:5190      4:4  2644m 17995 58683 6745K
tcp  In  10.13.13.14:59986    130.207.107.12:993    4:4  2633m 17968 23489 1878K
tcp  In  10.13.13.14:58124    130.207.165.106:993   4:4  26010 17788   461 41381
tcp  In  10.13.13.14:58423    130.207.244.116:119   4:4    919 17084    22  2727
tcp  In  10.13.13.14:58424    130.207.244.116:119   4:4    918 17083    16  1334
tcp  In  10.13.13.14:39423    64.12.160.141:5190    4:4  2644m 17832  1074 43890
tcp  In  10.13.13.14:52852    205.188.9.168:5190    4:4  2644m 17972  5702  287K
tcp  In  10.13.13.14:43451    216.155.193.174:5050  4:4  2143m 17948  4355  266K
tcp  In  10.13.13.14:33034    12.168.116.239:993    4:4  2643m 17789 15329 7166K
tcp  In  10.13.13.14:33035    12.168.116.239:993    4:4  2643m 17789 11691 2368K
tcp  In  10.13.13.14:33036    12.168.116.239:993    4:4  2643m 17789  8984 1322K
tcp  In  10.13.13.14:33037    12.168.116.239:993    4:4  2643m 17789  7238  744K
tcp  In  10.13.13.14:33038    12.168.116.239:993    4:4  2643m 17789  6981  691K
tcp  In  10.13.13.14:34200    12.168.116.239:22     4:4    213 17936  1059  151K
tcp  Out 10.13.13.14:58124    130.207.165.106:993   4:4  26010 17788   461 41381
tcp  Out 10.13.13.14:58424    130.207.244.116:119   4:4    918 17083    16  1334
tcp  Out 10.13.13.14:58423    130.207.244.116:119   4:4    919 17084    22  2727
tcp  Out 10.13.13.14:39423    64.12.160.141:5190    4:4  2644m 17832  1074 43890
tcp  Out 10.13.13.14:52852    205.188.9.168:5190    4:4  2644m 17972  5702  287K


Pedantic Security Stuff

ChiliSpot http://www.chillispot.org/
AuthPf http://www.openbsd.org/faq/pf/authpf.html

Yep... thats it...