I have tried to enhance my FreeBSD desktop's security with some tweaks without knowing what they do ....Any other useful tweaks ?

When I look at how the rules of PF are created, they neither mention IPV4 nor IPV6. So doesn't that mean when you are creating a block rule both IPV4 & IPV6 are getting blocked & similarly when there is a pass/allow rule it applies to to both IPV4 & IPV6 ?
If there's nothing specific to either IPv4 or IPv6 (like e.g. a concrete address) in the rule, then yes, the rule applies to both protocols.
 
That's just awesome ! Success ! Thanks a lot for that.
This is my PF conf.
Code:
block all
pass out proto { tcp udp } to port { 53 80 443 995 }
pass out inet proto icmp icmp-type { echoreq }
Looks like you didn't read far enough. You don't even have set skip on lo0. That'll end in tears sooner or later.
 
Looks like you didn't read far enough. You don't even have set skip on lo0. That'll end in tears sooner or later.
No, I didn't miss that. While I was experimenting I noticed that everything is working without that rule so I thought lets just avoid it. If that can cause any issues in the future I will add it right now & reload PF.
 
OK. For anyone else reading this thread, blocking traffic on the loopback interface is a profoundly stupid thing to do. It adds absolutely no security, and is likely to cause problems.
 
"The Book Of PF" by Peter N.M. Hansteen is like a Michael W Lucas book: easy to understand, good examples. Yes a little bit dated by now, but it covers the basics very well and in the past, the rules worked in FreeBSD.
 
I tried searching for the specific post in that thread where you have shown how to block incoming and outgoing traffic on TCP and UDP port 0 but I can't find it.
Here is the ruleset on this desktop:

/etc/pf.conf
Code:
### Macro name for external interface
ext_if = "em0"
netbios_tcp = "{ 22, 23, 25, 80, 110, 111, 123, 512, 513, 514, 515, 6000, 6010 }"
netbios_udp = "{ 123, 512, 513, 514, 515, 5353, 6000, 6010 }"

### Reassemble fragmented packets
scrub in on $ext_if all fragment reassemble

### Default deny everything
block log all

### Pass loopback
set skip on lo0

### Block spooks
antispoof for lo0
antispoof for $ext_if inet
block in from no-route to any
block in from urpf-failed to any
block in quick on $ext_if from any to 255.255.255.255
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 all IPv6
block in quick inet6 all
block out quick inet6 all

### Block to and from port 0
block quick proto { tcp, udp } from any port = 0 to any
block quick proto { tcp, udp } from any to any port = 0

### Block specific ports
block in quick log on $ext_if proto tcp from any to any port $netbios_tcp
block in quick log on $ext_if proto udp from any to any port $netbios_udp

### Keep and modulate state of outbound tcp, udp and icmp traffic
pass out on $ext_if proto { tcp, udp, icmp } from any to any modulate state

This is it at work right now:

Code:
root@obake:/ # pfctl -s all
FILTER RULES:
scrub in on em0 all fragment reassemble
block drop log all
block drop in on ! lo0 inet6 from ::1 to any
block drop in on ! lo0 inet from 127.0.0.0/8 to any
block drop in from no-route to any
block drop in from urpf-failed to any
block drop in quick on em0 inet from any to 255.255.255.255
block drop in log quick on em0 inet from 10.0.0.0/8 to any
block drop in log quick on em0 inet from 172.16.0.0/12 to any
block drop in log quick on em0 inet from 192.168.0.0/16 to any
block drop in log quick on em0 inet from 255.255.255.255 to any
block drop in quick inet6 all
block drop out quick inet6 all
block drop quick proto tcp from any port = 0 to any
block drop quick proto tcp from any to any port = 0
block drop quick proto udp from any port = 0 to any
block drop quick proto udp from any to any port = 0
block drop in log quick on em0 proto tcp from any to any port = ssh
block drop in log quick on em0 proto tcp from any to any port = telnet
block drop in log quick on em0 proto tcp from any to any port = smtp
block drop in log quick on em0 proto tcp from any to any port = http
block drop in log quick on em0 proto tcp from any to any port = pop3
block drop in log quick on em0 proto tcp from any to any port = sunrpc
block drop in log quick on em0 proto tcp from any to any port = ntp
block drop in log quick on em0 proto tcp from any to any port = exec
block drop in log quick on em0 proto tcp from any to any port = login
block drop in log quick on em0 proto tcp from any to any port = shell
block drop in log quick on em0 proto tcp from any to any port = printer
block drop in log quick on em0 proto tcp from any to any port = x11
block drop in log quick on em0 proto tcp from any to any port = x11-ssh
block drop in log quick on em0 proto udp from any to any port = ntp
block drop in log quick on em0 proto udp from any to any port = biff
block drop in log quick on em0 proto udp from any to any port = who
block drop in log quick on em0 proto udp from any to any port = syslog
block drop in log quick on em0 proto udp from any to any port = printer
block drop in log quick on em0 proto udp from any to any port = mdns
block drop in log quick on em0 proto udp from any to any port = x11
block drop in log quick on em0 proto udp from any to any port = x11-ssh
pass out on em0 proto tcp all flags S/SA modulate state
pass out on em0 proto udp all keep state
pass out on em0 proto icmp all keep state

INFO:
Status: Enabled for 18 days 22:01:55          Debug: Urgent

State Table                          Total             Rate
  current entries                        0               
  searches                         4469011            2.7/s
  inserts                            42894            0.0/s
  removals                           42894            0.0/s
Counters
  match                              98854            0.1/s
  bad-offset                             0            0.0/s
  fragment                               0            0.0/s
  short                                  0            0.0/s
  normalize                              0            0.0/s
  memory                                 0            0.0/s
  bad-timestamp                          0            0.0/s
  congestion                             0            0.0/s
  ip-option                              0            0.0/s
  proto-cksum                            0            0.0/s
  state-mismatch                         0            0.0/s
  state-insert                           0            0.0/s
  state-limit                            0            0.0/s
  src-limit                              0            0.0/s
  synproxy                               0            0.0/s
  map-failed                             0            0.0/s

TIMEOUTS:
tcp.first                   120s
tcp.opening                  30s
tcp.established           86400s
tcp.closing                 900s
tcp.finwait                  45s
tcp.closed                   90s
tcp.tsdiff                   30s
udp.first                    60s
udp.single                   30s
udp.multiple                 60s
icmp.first                   20s
icmp.error                   10s
other.first                  60s
other.single                 30s
other.multiple               60s
frag                         30s
interval                     10s
adaptive.start            60000 states
adaptive.end             120000 states
src.track                     0s

LIMITS:
states        hard limit   100000
src-nodes     hard limit    10000
frags         hard limit     5000
table-entries hard limit   200000

OS FINGERPRINTS:
762 fingerprints loaded
root@obake:/ #
 
I tried searching for the specific post in that thread where you have shown how to block incoming and outgoing traffic on TCP and UDP port 0 but I can't find it.
Makes me wonder what in the world is Trihexagonal doing with port 0... 🤪 A quick Google search on "tcp port 0" turned up a pretty nice explanation about why port 0 even exists, and why it should not be used in network configs.

Edit: After actually reading the config - his rules are trying to block any connections from port 0, be it outside or inside. The link I provided actually explains that port 0 sometimes works like a wildcard in network scanners.

😩 Security is a neverending rabbit hole. Yeah, it's important to do some basic lockdown, and not leave yourself exposed. But generally, even "consumer plastic" routers offer some level of protection. Mine has DD-WRT flashed on it. It's a Linux distro, but offers the kind of config flexibility that just doesn't come with the default firmwares of consumer plastic.
 
  • Like
Reactions: mer
Makes me wonder what in the world is [FONT=monospace]Trihexagonal[/FONT] doing with port 0... 🤪
None are so blind as those who cannot search to see - Yo Momma ☯️

 
None are so blind as those who cannot search to see - Yo Momma ☯️

Yeah, this would be good for OP to see, too, IMHO. But I wonder - are we dumping too much info on OP? After all, while UNIX is not a religion, it does have the philosophy of keeping the implementations clean and simple.
 
Well I've stuck to one thread and tried to reference what has already been posted. I thought I had my port 0 rule listed in the tutorial but had left that out. For simplicity. So I porvided my ruleset.

If john_rambo follows the outline of programs installed, like for updating the CPU firmware, limits himself to editing the Security and System files I have provided examples of and uses my pf ruleset he will be using the same system hardening settings I use on all my laptops.

Except for the browser extensions and everyone has their own preferences in that area.

If that's not good enough for him, it is for me, and how I've been doing it a long time now.
Clean and simply as possible.
 
Trihexagonal
I have combined my existing rules with your rules. This is how it looks now

Code:
### Macro name for external interface
ext_if = "wlan0"
netbios_tcp = "{ 22, 23, 25, 80, 110, 111, 123, 512, 513, 514, 515, 6000, 6010 }"
netbios_udp = "{ 123, 512, 513, 514, 515, 5353, 6000, 6010 }"


set skip on lo0
block all
pass out proto { tcp udp } to port { 53 80 443 995 6697 }
pass out inet proto icmp icmp-type { echoreq }
antispoof quick for wlan0
icmp_types = "{ unreach }"

### Block all IPv6
block in quick inet6 all
block out quick inet6 all

### Block to and from port 0
block quick proto { tcp, udp } from any port = 0 to any
block quick proto { tcp, udp } from any to any port = 0

### Block specific ports
block in quick log on $ext_if proto tcp from any to any port $netbios_tcp
block in quick log on $ext_if proto udp from any to any port $netbios_udp

### Keep and modulate state of outbound tcp, udp and icmp traffic
pass out on $ext_if proto { tcp, udp, icmp } from any to any modulate state

I had to change this >> ext_if = "wlan0" otherwise it refuses to work.
You have rules which specifically blocks IPV6 both in and out. What's the reason ? My rules blocks all incoming both IPV4 & IPV6. I guess yours does the same. What's the risk in allowing IPV6 ?
 
A firewall config really isn't for copy&paste. Now you have three unused (and therefore unnecessary) variables: netbios_tcp, netbios_udp and icmp_types. edit: did you update your post? Now I see these netbios ports are used, for rules that are functionally redundant, but add logging for these specific ports. (why?) The icmp_types variable is still unused…

Really, you must understand what the rules are doing and you must decide what you actually want…

I only use packet filtering on my actual firewall box, not on the machines "behind" it (again, I think this would only make sense for mobile devices that could be used in untrusted networks as well). I won't show my ruleset: I's useless for anyone else anyways (every network is different), but would unnecessarily expose information about the inner structure of my network.

You have rules which specifically blocks IPV6 both in and out. What's the reason ? My rules blocks all incoming both IPV4 & IPV6. I guess yours does the same. What's the risk in allowing IPV6 ?
I'd have an answer to that. You typically only allow what you want to use. If you're sure you don't want to use IPv6, there's nothing wrong with just blocking it.

Without any IPv4- or IPv6-specific rules, this is kind of redundant as the other rules apply to both protocols. But it might help to avoid errors. If you e.g. add a "block" rule that has an IPv4 address, it will only match for IPv4.
 
A firewall config really isn't for copy&paste. Now you have three unused (and therefore unnecessary) variables: netbios_tcp, netbios_udp and icmp_types.

Really, you must understand what the rules are doing and you must decide what you actually want…

I only used packet filtering on my actual firewall box, not on the machines "behind" it (again, I think this would only make sense for mobile devices that could be used in untrusted networks as well). I won't show my ruleset: I's useless for anyone else anyways (every network is different), but would unnecessarily expose information about the inner structure of my network.
I will tell what I understand what my own config is doing

Code:
set skip on lo0
block all
pass out proto { tcp udp } to port { 53 80 443 995 6697 }
pass out inet proto icmp icmp-type { echoreq }
antispoof quick for wlan0
(1) It blocks all incoming traffic.
(2) It blocks all outgoing traffic excepting ports 53, 80, 443, 995 & 6697
(3) I have read what antispoof does so no point in discussing it here.

Now what's new to me when I see Trihexagonal 's rules are (1) specific rules for blocking traffic to port 0, (2) specifically blocking IPV6 & (3) Rules for keeping modulate state of outbound tcp, udp and icmp traffic

I am not sure if I need to add this or since I am using "deny all in & deny out with only specific out ports allowed".
 
What's also new is a rule about blocking some specific (netbios-related?) ports and logging that. Do you really want to specifically log attempts to connect to these ports? If not, don't just copy this stuff.

About rules for port 0: port 0 is invalid, if machines do something with it when it actually hits the wire, that's broken behavior. I'd recommend a scrub rule instead which is documented to check for many invalid things and drop these packets, port 0 should be included.

About IPv6: see above. Redundant, might help to avoid errors once you add rules specific to e.g. some IPv4-address (and might forget the IPv6 equivalent)

No idea about that state stuff, for me, connection state was working just fine so far.

Finally: I'd still suggest to allow ICMP unreach, even if PF gets ist correct. The manual at least isn't fully specific here. I don't see any reason to block it, what should be the risk (question to everyone)? But that isn't done by just declaring an unused variable icmp_types.
 
The modulate state option works just like keep state, except that it only applies to TCP packets. With modulate state, the initial sequence number (ISN) of outgoing connections is randomized. This is useful for protecting connections initiated by certain operating systems that do a poor job of choosing ISNs.


At least some of the "certain operating systems" were old versions of Windows that used an ancient BSD TCP/IP stack. Dunno how applicable it is nowadays. I think ISNs were also used for OS fingerprinting, but I can't find a reference for that now.
 
[FONT=monospace]Trihexagonal[/FONT]
I have combined my existing rules with your rules. This is how it looks now
And you did it wrong.

You have your additions to my ruleset in the wrong place and it is all messed up now.

Remove these lines from where they are in your example:

Code:
pass out proto { tcp udp } to port { 53 80 443 995 6697 }
pass out inet proto icmp icmp-type
{ echoreq }icmp_types = "{ unreach }"
wlan0 is your wi-fi internet interface.

The ruleset is fine the way it is.
If you add to it without knowing what you're doing you're going to break things.

If it's not broke don't fix it.
 
Trihexagonal
I want to ask a question. I read many articles about network security. Almost all of them suggests that closing all incoming ports is enough to protect a home network. Blocking outgoing ports doesn't really make any sense in a home environment. If you see my rules, I mean the rules that I had set myself.

Code:
# sudo cat /etc/pf.conf
set skip on lo0
block all
pass out proto { tcp udp } to port { 53 80 443 995 6697 }
pass out inet proto icmp icmp-type { echoreq }
antispoof quick for wlan0

Not only it blocks all incoming ports I have blocked outgoing ports too leaving the ones which are necessary for daily activities like web browsing, using an email client, IRC chat client, etc.

So my question is can a home desktop be made more secure than this ?
 
I won't show my ruleset: I's useless for anyone else anyways (every network is different), but would unnecessarily expose information about the inner structure of my network.
Doesn't that apply to people who deliberately open incoming port(s) so that they can host some kind of a server. I mean suppose a hacker knows that I am using FreeBSD with PF & all my incoming ports are blocked & he also gets to know exactly which outgoing ports I have allowed. So what can hacker possible do ?

Is it possible to hack a FreeBSD box which is using PF with all incoming ports blocked ?
 
Doesn't that apply to people who deliberately open incoming port(s) so that they can host some kind of a server.
It applies to me, not so much because there are services offered (everyone can scan that from the outside anyways), but because this is a real firewall between multiple network zones, and a published ruleset would reveal their structure, making it easier for an attacker to know what to try next if they somehow managed to get into some machine in the DMZ.
Is it possible to hack a FreeBSD box which is using PF with all incoming ports blocked ?
Wrong question. There's no "absolute" security. Even packet filtering code could have bugs itself. That's why a real firewall box (where this code doesn't run on a machine it should protect) is preferable.
 
Wrong question. There's no "absolute" security. Even packet filtering code could have bugs itself. That's why a real firewall box (where this code doesn't run on a machine it should protect) is preferable.
Can you elaborate a bit ? I mean suppose I assemble a new machine & install pfSense or OPNsense. How are these firewall OSs made ? OPNsense used to use the HardenedBSD as their base which they no longer do I have no idea why they took this decision & pfSense uses FreeBSD as their base & uses PF. So my question is how is a pfSense box different than my desktop which is also running FreeBSD and PF ? I mean if my FreeBSD install can have bugs can't a pfSense or an OPNsense box also have bugs ?
 
If there's a remote-exploitable bug in packet filtering code, with a dedicated firewall, an attacker would compromise that machine, not the one to protect. Add some extra hardening on that special-purpose machine (e.g. no shell or a very limited one, no runtime rule changes allowed, etc), this gives a much better chance the attack will be unsuccessful in the end.
 
If there's a remote-exploitable bug in packet filtering code, with a dedicated firewall, an attacker would compromise that machine, not the one to protect. Add some extra hardening on that special-purpose machine (e.g. no shell or a very limited one, no runtime rule changes allowed, etc), this gives a much better chance the attack will be unsuccessful in the end.
Got it. I was reading about pfSense Vs OPNsense & one of the points that article mentions which is one the reasons why pfSense was forked & OPNsense was created is this

Security issues related to the web UI being run as root

This is the article >>> https://teklager.se/en/pfsense-vs-opnsense/

What's your opinion about this if you are a pfSense user or have pfSense in the past ?
 
Well, I don't use it and I don't have any opinion about it. For a professional installation, you'd typically buy some ready-to-use appliance anyways (and make sure the vendor gives some warranties). For me at home, I just use FreeBSD with PF in a virtual machine, that "owns" the NICs on PCI level (not perfect, but hey, it's a private installation, you don't want to operate more than 1 machine 24/7).

In a nutshell:
  • There's nothing wrong with packet filtering on your own host, and it makes sense if you also operate it in untrusted networks. It just can't give the same level of defense as a dedicated firewall.
  • In any case, packet filtering rules MUST be understood and tailored to YOUR needs and (risk) decisions. NO copy&paste.
  • Never ever think "you can't be hacked". That's always wrong unless you "pull the plug". The goal is to make it as unlikely as possible while keeping functionality you need and with effort in relation to your usecase.
 
Back
Top