FreeBSD firewall using PF

FreeBSD firewalls using PF (Tutorial)
By Click Death Squad (C.D.S.)
Revision 1.0

An intermediate level BSD firewall script provides the opportunity to host services on your home network connection, but also shield you from rampant attacks that occur on the Internet. Click Death Squad has a test computer that receives multiple brute force attempts each day, in addition to exploits for ftp services and http daemons. Consider normalizing your traffic and reducing the amount of garbage filling your log files. You do check your log files, right? When you are receiving hundreds of SSH brute force attempts every single day, you may want to re-evaluate your situation.

In this example, we used a FreeBSD 7 box, and all the commands issued are given in quotes, with the result of the commands being listed in grey. After each step, a screenshot is given so you may compare your output to what should be happening. Please note that not all the screenshots contain the exact same data which is given in the example, they are merely for reference purposes.

Tools you will need to accomplish this task:
  • A FreeBSD server that you have administrative rights to
  • Intermediate to advanced Linux/UNIX networking skills
  • A text editor (nano)
  • A cold beer

Step 1: Ensure your firewall script will start when the server boots.

The first step to setting up your firewall is to ensure that PF starts when your box boots up. Edit your rc.conf file to set this up.
"sudo nano /etc/rc.conf" ### edit the boot time configuration file.

pf_enable="YES" ### turn PF on when the computer boots.                         
pf_rules="/etc/pf.conf" ### define the rules for the firewall.
pf_flags="" ### additional flags (none).
pflog_enable="YES" ### turn on packet logging support.
pflog_logfile="/var/log/pflog" ### where to log data to, used with pflogd daemon.
pflog_flags="" ### additional flags (none).


Step 2: Edit the PF configuration file.
Now edit your PF config file and setup some rules that will protect your home network. Utilized in the provided example are various options that can be set to prevent your box from being passively OS fingerprinted, subject to DDoS attacks and spoofing. Here is a configuration that you may wish to use.

"sudo nano /etc/pf.conf" ### edit the PF configuration file.

######################################
# Click Death Squad's PF Ruleset         
# iztehsux@gmail.com            
# optimized for paranoia and freebsd
# revision 1.3                     
######################################

### macro name for external interface.
ext_if = "sis0"

### all incoming traffic on external interface is normalized and fragmented
### packets are reassembled.
scrub in on $ext_if all fragment reassemble

### set a default deny everything policy.
block all

### exercise antispoofing on the external interface, but add the local
### loopback interface as an exception, to prevent services utilizing the
### local loop from being blocked accidentally.
set skip on lo0
antispoof for $ext_if inet

### block anything coming from sources that we have no back routes for.
block in from no-route to any

### block packets that fail a reverse path check. we look up the routing
### table, check to make sure that the outbound is the same as the source
### it came in on. if not, it is probably source address spoofed.
block in from urpf-failed to any

### drop broadcast requests quietly.
block in quick on $ext_if from any to 255.255.255.255

### block packets claiming to come from reserved internal address blocks, as
### they are obviously forged and cannot be contacted from the outside world.
block in log quick on $ext_if from { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 255.255.255.255/32 } to any

### block probes that can possibly determine our operating system by disallowing
### certain combinations that are commonly used by nmap, queso and xprobe2, who
### are attempting to fingerprint the server.
### * F : FIN  - Finish; end of session
### * S : SYN  - Synchronize; indicates request to start session
### * R : RST  - Reset; drop a connection
### * P : PUSH - Push; packet is sent immediately
### * A : ACK  - Acknowledgement
### * U : URG  - Urgent
### * E : ECE  - Explicit Congestion Notification Echo
### * W : CWR  - Congestion Window Reduced
block in quick on $ext_if proto tcp flags FUP/WEUAPRSF
block in quick on $ext_if proto tcp flags WEUAPRSF/WEUAPRSF
block in quick on $ext_if proto tcp flags SRAFU/WEUAPRSF
block in quick on $ext_if proto tcp flags /WEUAPRSF
block in quick on $ext_if proto tcp flags SR/SR
block in quick on $ext_if proto tcp flags SF/SF

### keep state on any outbound tcp, udp or icmp traffic. modulate the isn of
### outgoing packets. (initial sequence number) broken operating systems
### sometimes don't randomize this number, making it guessable.
pass out on $ext_if proto { tcp, udp, icmp } from any to any modulate state

### normally, a client connects to the server and we handshake with them, then
### proceed to exchange data. by telling pf to handshake proxy between the client
### and our server, tcp syn flood attacts from ddos become uneffective because
### a spoofed client cannot complete a handshake.

### set a rule that allows inbound ssh traffic with synproxy handshaking.
pass in on $ext_if proto tcp from any to any port ssh flags S/SA synproxy state

### set a rule that allows inbound www traffic with synproxy handshaking.
pass in on $ext_if proto tcp from any to any port www flags S/SA synproxy state

### setup a table and ruleset that prevents excessive abuse by hosts
### that attempt to brute force the ssh daemon with repeated requests.
### any host that hammers more than 3 connections in 5 seconds gets
### all their packet states killed and dropped into a blackhole table.
table <ssh_abuse> persist
block in quick from <ssh_abuse>
pass in on $ext_if proto tcp to any port ssh flags S/SA keep state (max-src-conn 10, max-src-conn-rate 3/5, overload <ssh_abuse> flush)

Step 3: Start the PF service immediately to have the firewall take effect.
Once your rules have been saved and you have enabled PF to run at boot time, it might be advisable to start PF up with the ruleset you created right away. This isn't difficult to do, just utilize the rc.d script and fire it up. You will also want to enable the PF logging daemon as well.

"sudo /etc/rc.d/pf start" ### start PF.
"sudo /etc/rc.d/pflog start" ### start the PF logging daemon.

Step 4: Double check your rules and view the firewall stats.
PF is running, and your rules have been defined. It would be wise to use "pfctl" the control program, to manually reload your ruleset and check to verify that all the rules are being applied correctly. Use pfctl to reload the rules, and then check your current status.

"sudo pfctl -d; sudo pfctl -e -f /etc/pf.conf" ### tell pfctl to disable the firewall daemon, then re-enable it using your ruleset.
"sudo pfctl -s all" ### print all the current rules that are in effect.


The rules are in place, and your PF firewall should be actively tracking state connections and dealing with brute force attacks as needed. PF is a very powerful piece of software and offers limitless possibilities for configuring your network setup. For more information regarding PF, you should check out the FAQ on OpenBSD's website.. Happy safe server hosting to you, and remember to always check your logfiles.