pf-badhost

Stop the evil doers in their tracks!

About

pf-badhost is a simple, easy to use badhost blocker that uses the power of the pf firewall to block many of the internet's biggest irritants. Annoyances such as ssh bruteforcers are largely eliminated. Shodan scans and bots looking for webservers to abuse are stopped dead in their tracks. When used to filter outbound traffic, pf-badhost blocks many seedy, spooky malware containing and/or compromised webhosts.

Filtering performance is exceptional, as the badhost list is stored in a pf table. To quote the OpenBSD FAQ page regarding tables: "the lookup time on a table holding 50,000 addresses is only slightly more than for one holding 50 addresses."

pf-badhost is simple and powerful. The blocklists are pulled from quality, trusted sources. The 'Firehol', 'Emerging Threats' and 'Binary Defense' block lists are used as they are popular, regularly updated lists of the internet's most egregious offenders. The pf-badhost.sh script can easily be expanded to use additional or alternate blocklists.

pf-badhost works best when used in conjunction with unbound-adblock for the ultimate badhost blocking.

How To

• Create a new user (we’ll call ours “_pfbadhost”)

 # adduser _pfbadhost 

• Download and put pf-badhost.sh into /usr/local/bin/

 
	# ftp https://www.geoghegan.ca/scripts/pf-badhost.sh
	# mv pf-badhost.sh /usr/local/bin/
	# chown root:bin /usr/local/bin/pf-badhost.sh
	

• Give user ‘_pfbadhost’ strict doas permission for the exact commands the script needs run as superuser:

	# vi /etc/doas.conf
	permit nopass _pfbadhost cmd cp args /tmp/pf-badhost.txt /etc/
        permit nopass _pfbadhost cmd pfctl args -t pfbadhost -T replace -f /etc/pf-badhost.txt
        
   


• Edit _pfbadhost crontab to run pf-badhost.sh every night at midnight

      # crontab -u _pfbadhost -e
      @midnight 		/bin/sh /usr/local/bin/pf-badhost.sh

	

• Add the following lines to your pf.conf :

      table <pfbadhost> persist file “/etc/pf-badhost.txt”
      block in quick on egress from <pfbadhost> to any
      block out quick on egress from any to <pfbadhost>
	
	
• login to user “_pfbadhost”

      # su _pfbadhost
	

• Run the pfbadhost.sh scripts to create the required files

      $ sh /usr/local/bin/pf-badhost.sh
	

• It should say about ~50,000 addresses were added to the <pfbadhost> table

• Now reload your pf rule set:

      # pfctl -f /etc/pf.conf
	

• For good measure, we'll run the pf-badhost.sh script once more

      $ sh /usr/local/bin/pf-badhost.sh
	


Yay! pf-badhost is now installed!

With the nightly cron job, the list will be be regularly updated with the latest known bad hosts.



Notes:

Note: If you are trying to run pf-badhost on a LAN or are using NAT, you will want to add a rule to your pf.conf appearing BEFORE the pf-badhost rules allowing traffic to and from your local subnet so that you can still access your gateway and any DNS servers.
Something like this should do:

 # vi /etc/pf.conf
	
	pass in quick on egress from 192.168.17.0/24
	pass out quick on egress from any to 192.168.17.0/24

   	table  persist file “/etc/pf-badhost.txt”
     	block in quick on egress from <pfbadhost> to any
     	block out quick on egress from any to <pfbadhost>
	


Conversely, adding a line to pf-badhost.sh that removes your subnet range from the <pfbadhost> table should also work. Just make sure you choose a subnet range / CIDR block that is actually in the list. 192.168.0.0/16, 172.16.0.0/12 and 10.0.0.0/8 are the most common home/office subnet ranges.

	# vi /etc/doas.conf
	permit nopass _pfbadhost cmd pfctl args -t pfbadhost -T delete 192.168.0.0/16

	# vi /usr/local/bin/pf-badhost.sh

	# Move banlist into /etc and reload the pf table

	mv /tmp/banlist/pf-badhost.txt /tmp/
	doas cp /tmp/pf-badhost.txt /etc/
	doas pfctl -t pfbadhost -T replace -f /etc/pf-badhost.txt
        doas pfctl -t pfbadhost -T delete 192.168.0.0/16 
	

In case you need to just copy and paste the code for some reason, here is the contents of pf-badhost.sh

# Copyright 2018 Jordan Geoghegan

# Permission to use, copy, modify, and/or distribute this software for any 
# purpose with or without fee is hereby granted, provided that the above 
# copyright notice and this permission notice appear in all copies.

# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 
# PERFORMANCE OF THIS SOFTWARE.


# Download some of the most popular IP Blocklists, you can add any lists here 
# you like as long as they have similar formatting to the other lists. 

# Make temp folder to hold all files

mkdir /tmp/pfbadhost

# Download popular IP blocklists and parse

cd /tmp/pfbadhost 
ftp https://www.binarydefense.com/banlist.txt
ftp https://rules.emergingthreats.net/blockrules/compromised-ips.txt
ftp https://rules.emergingthreats.net/fwrules/emerging-Block-IPs.txt
ftp https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_level3.netset
ftp https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_level2.netset
ftp https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_level1.netset
perl -lne 'print if ! /^\s*(#.*)?$/' *.txt *.netset | sort -uV > pf-badhost.txt

# Block Shodan

ftp https://isc.sans.edu/api/threatlist/shodan/shodan.txt 
egrep -o '([[:digit:]]{1,3}\.){3}[[:digit:]]{1,3}' shodan.txt >> pf-badhost.txt

# Move banlist into /etc and reload the pf table

mv /tmp/pfbadhost/pf-badhost.txt /tmp/
doas cp /tmp/pf-badhost.txt /etc/
doas pfctl -t pfbadhost -T replace -f /etc/pf-badhost.txt

# Clean up after ourselves

rm -r /tmp/pfbadhost
rm /tmp/pf-badhost.txt