errorCodex - Computer Questions & Solutions Forum


  errorCodex - Computer Questions & Solutions Forum » Blue Screen » Basic How-tos

Basic How-tos Help Us Noobs by Sharing Your Wisdom

Reply
 
Thread Tools
  #1  
Old 25 May 2010, 20:07
Miraenda's Avatar
Miraenda Miraenda is offline
Mime Stalker
 
Join Date: Nov 2009
Location: Coralville Iowa
Age: 37
Posts: 75
Miraenda has disabled reputation
Default Building a pf Configuration on FreeBSD

From the prior guide at this location, we are first going to review a few points.

pf Basic Commands Review

Configuration file location:
Code:
/etc/pf.conf
Syntax check and reload on configuration file:
Code:
pfctl -vnf /etc/pf.conf
Flush firewall and reload the rules:
Code:
pfctl -F all -f /etc/pf.conf
View currently running rules since last restart:
Code:
pfctl -s all
Building Our Own Firewall Configuration

Good Comments

To ensure our firewall policy is easily understood, we are going to use comments for all entries in the /etc/pf.conf file. Comments start with # such as the following:
Code:
### This is a comment.
We will use three of the comment sign (###) to designate such comments so they stand out.

Frontend Interface

Last time, we discussed setting the interface macro for the frontend IP, so our firewall will start with this interface as the first setting:

Code:
### fxp0 is our frontend IP interface based on ifconfig -a
ext_if = "fxp0"
Default Block All Policy

Since pf will traverse the ruleset until it reaches the last rule, then handle any filtering based on the last (not the first) rule unless quick is added to the rule, the default rules usually start with a block policy:
Code:
### block all incoming and outgoing packets from all source
### addresses and all source ports to all destination addresses
### and destination ports
block all
When in or out isn’t mentioned in a rule, both in and out are being defined. This means the above is the same as the following two rules:
Code:
block in all
block out all
Skipping Localhost

In order to ensure we do not block packets on local addresses within the network, we want to skip localhost:
Code:
### skip localhost to prevent it from being blocked
set skip on lo0
If you aren’t sure the localhost interface name, you can always run the following to see the one noted as loopback:
Code:
server# ifconfig -a | grep -i loopback
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> metric 0 mtu 16384
Antispoof

Antispoof prevents incoming packets from pretending to be stemming from the network itself, so we will add the following rule next:
Code:
### antispoof drop packets using the source IP or pretending
### to stem from the network for the frontend IP
antispoof for $ext_if inet
Of note, if we wanted to do the same for IPv6 packets, we would use inet6 for the address family name:
Code:
antispoof for $ext_if inet6
My system isn't using IPv6, so I am not adding this into my firewall (as I have no routing for inet6 on the system).

Block Reserved Internal IPs

Now, let’s block those reserved IP addresses we mentioned in the last guide, but we will define a macro at the top of the file after the $ext_if defined one:
Code:
### define a list of reserved IPs that shouldn't be used for
### incoming packets
reserved = "{ 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 255.255.255.255/32 }"
Now, we can use the following after our antispoof rule:
Code:
### Block any incoming packets with logging and force this rule
### on the frontend IP from the reserved IP blocks to any
### destination address or any destination port
block in log quick on $ext_if from $reserved to any
Allow Outgoing Connections

Last guide, we defined this macro:
Code:
### define a list of common protocols
mainproto = "{ tcp, udp, icmp }"
Ensure to put that at the top of the configuration file after the reserved marco. At this point, to allow all outgoing connections on the network, we will set the following rule now after the reserved IP block rule:
Code:
### Allow outgoing packets and force the ruleset on the frontend
### IP for tcp, udp and icmp traffic from any source address or
### source port to any destination address or destination port
pass out quick on $ext_if proto $mainproto from any to any
Force Synproxy Handshake

We want to allow in packets that can handshake with our machine and cut down on denial of service attempts. This will be handled with the next two rules:
Code:
### Allow incoming packets on the frontend IP via tcp from any
### source address or source port to any destination address
### on the destination port SSH with flag on SYN and using SYN
### with ACK only if the packets can return a synproxy handshake
pass in on $ext_if proto tcp from any to any port ssh flags S/SA synproxy state

### allow incoming packets on the frontend IP via tcp from any
### source address or source port to any destination address
### on the destination port www with flag on SYN and using SYN
### with ACK only if the packets can return a synproxy handshake
pass in on $ext_if proto tcp from any to any port www flags S/SA synproxy state
Since spoofed clients cannot complete a handshake, this should drastically cut down on any such attacks.

Stop SSH and IMAP Brute Force Attempts

The next rule is even more complex, but important to define as it will be the basis you can use for other brute force attempt rules:
Code:
### Set up a rule table called <ssh_abuse> for connections
### that try to brute force the SSH service with repeated
### requests. Block incoming packets in that table and force
### the ruleset. Pass in on the frontend IP for tcp to any
### destination address on port SSH using SYN on flag with
### SYN and ACK in keep state where the max source connections
### are 10 OR the max source connection rate is 3 attempts in
### 5 seconds, putting those packets into the ssh_abuse 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)
If you wanted to add the same rule for imap brute force attempts, you could do something like the following:
Code:
table <imap_abuse> persist
block in quick from <imap_abuse>
pass in on $ext_if proto tcp to any port imap flags S/SA keep state (max-src-conn 10, max-src-conn-rate 3/5, overload <imap_abuse> flush)
Since we've brought up state in this rule (keep state) and the prior rule (synproxy state), we are going to mention state further as it wasn't covered in the prior guide. As a reprise, here is the syntax for block and pass rule actions:

action (in | out) [log] [quick] on interface [af] [proto protocol] [src_addr | dst_addr] [src_port | dst_port] [tcp_flags] [state]

[ ] around an option means it is optional

We covered all of the prior options in the last guide besides state. For state, the delimiters are the following:

no state - works with TCP, UDP, and ICMP. PF will not track this connection statefully. For TCP connections, flags any is usually also required
keep state works with TCP, UDP, and ICMP. This option is the default for all filter rules
modulate state works only with TCP. PF will generate strong Initial Sequence Numbers (ISNs) for packets matching this rule
synproxy state - proxies incoming TCP connections to help protect servers from spoofed TCP SYN floods. This option includes the functionality of keep state and modulate state

When state is mentioned in a rule, then additional options for connections can then be added in ( ) after the state such as what we just listed above:
Code:
keep state (max-src-conn 10, max-src-conn-rate 3/5, overload <ssh_abuse> flush)
max-src-conn # - limits the maximum number of simultaneous TCP connections that have completed the three way handshake that a single source packet IP host can make
max-src-conn-rate # / interval - limits the rate of new connections to a certain amount per time second interval
overload <table_name> - puts an offending source host IP address into the table <table_name>
flush [global] - kills any other states that match this rule and that were created by the source host IP. If global is added after flush, then all states are killed that match this source host IP no matter which rule created the state

For the full SSH rule again:
Code:
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)
Reading it in reverse, allow incoming packets on the frontend IP via TCP to any destination address via SSH with SYN on and SYN and ACK in keep state where that source host IP has 10 simultaneous connections OR the source host IP connects 3 times in 5 seconds. Put the offending source host IP into a table called <ssh_abuse> and kill any other packet states that match this same rule from that source host IP.

After an IP hits that table, future connections from that IP are checked in the persistent table <ssh_abuse> and blocked for incoming connections, forcing that ruleset.

Block Set IPs

Please note that if you want to block a series of IPs on the machine, you could do the following:
Code:
### Load the table <blockedips> from the file
### /etc/pf.blockedips.conf. Block incoming packets, log,
### forcing the ruleset, on the frontend IP for IPs in the
### <blockedips> table to any destination address or
### destination port.
table <blockedips> persist file "/etc/pf.blockedips.conf"
block in log quick on $ext_if from <blockedips> to any
Please note that you would not want to block IPs one at a time in /etc/pf.conf file since that is the main configuration file, which should be limited in rules for clarity. It is more coherent to create a file of blocked IPs, then load the table of those blocked IP. Think of this as similar to APF and CSF for their deny_hosts.rules and csf.deny files, respectively. You are basically building your own firewall with pf not simply creating a series of low-end rules like in iptables on Linux.

You will now need to create the file:
Code:
touch /etc/pf.blockedips.conf
To add an IP to the file:
Code:
echo 74.74.74.74 >> /etc/pf.blockedips.conf
Or, simply edit the file directly.

To dynamically add an IP as blocked (temporary add won't stick on server reboot or firewall reload):
Code:
pfctl -t blockedips -T add 74.74.74.74
To dynamically remove an IP as blocked (temporary remove won't stick on server reboot or firewall reload):
Code:
pfctl -t blockedips -T delete 74.74.74.74
To view IP addresses listed in tables:
Code:
pfctl -t blockedips -T show
To see statistics for each IP:
Code:
pfctl -t blockedips -T show -v
Allow Set IPs

Finally, we might want to create a similar table of allowed IPs to prevent our IPs from being blocked:
Code:
### Load the table <allowed> from the file
### /etc/pf.allowedips.conf. Allow incoming packets, log,
### forcing the ruleset, on the frontend IP for IPs in the
### <allowedips> table to any destination address or
### destination port.
table <allowedips> persist file "/etc/pf.allowedips.conf"
pass in log quick on $ext_if from <allowedips> to any
Again, you will need to create the file:
Code:
touch /etc/pf.allowedips.conf
To dynamically add an IP as allowed (temporary add won't stick on server reboot or firewall reload):
Code:
pfctl -t allowedips -T add 75.75.75.75
To dynamically remove an IP as allowed (temporary remove won't stick on server reboot or firewall reload):
Code:
pfctl -t allowedips -T delete 75.75.75.75
Of note, we will place this rule above the blockedips one in order to ensure that our allowed IPs aren't ever accidentally blocked on the machine. If we had the allowedips ruleset after blockedips, then if an IP were added into both tables, the block in log quick portion of the blockedips rule would cause the IP to be blocked before reaching this allowedips pass in log quick rule.

Pass in All Other Packets

Since you need to allow any other traffic that hasn't been blocked already using quick as otherwise you might be blocking services you need to have open, you need to end the configuration on the machine with the following:
Code:
### allow all incoming packets from all source addresses and
### all source ports to all destinations addresses and
### destination ports
pass in all
You don't need to do this for outgoing traffic as we already handled that earlier with the following:
Code:
### allow outgoing packets and force the ruleset on the frontend
### IP for tcp, udp and icmp traffice from any source address or
### source port to any destination address or detination port
pass out quick on $ext_if proto $mainproto from any to any
Final Firewall Configuration

You can view the final firewall configuration at this location.

Viewing Logs

If you’ve set pf to log in /etc/rc.conf with this option:
Code:
pflog_enable="YES"
Then started the logging with this command:
Code:
/etc/rc.d/pflog start
The logs can be viewed using tcpdump at that point:
Code:
tcpdump -n -e -ttt -r /var/log/pflog
tcpdump -n -e -ttt -r /var/log/pflog port 80
tcpdump -n -e -ttt -r /var/log/pflog host 74.74.74.74
To see the log in real time:
Code:
tcpdump -n -e -ttt -i pflog0
tcpdump -n -e -ttt -i pflog0 port 80
tcpdump -n -e -ttt -i pflog0 host 74.74.74.74
__________________
Miraenda
~ Ex uno disce omnes ~
Reply With Quote
Reply

Bookmarks

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -6. The time now is 15:11.


A vBSkinworks Design
Powered by vBulletin® Version 3.8.1
Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.