Blocking INVALID Packets using UFW

Hey everyone,

I’ve been busy this past week working on blocking INVALID packets using UFW, and I’d like to share the process with you to enhance the security of your servers.

The UFW firewall blocks packets considered INVALID by default and this could be verified by taking a look at the before.rules file:

...
# drop INVALID packets (logs these in loglevel medium and higher)
-A ufw-before-input -m conntrack --ctstate INVALID -j ufw-logging-deny
-A ufw-before-input -m conntrack --ctstate INVALID -j DROP
...

Before I continue, what specifically are INVALID packets?

You’re most likely familiar with the good old TCP three-way handshake:

  • You send a packet with only the SYN flag, indicating: “Hello web server, I would like to establish a connection with you!”
  • In response, the web server sends a packet with the SYN and ACK flags set, signaling: “Hey, I’m here and ready to establish a connection with you!”
  • Upon receiving the SYN-ACK packet, you send a packet with only the ACK flag, confirming to the server your readiness to establish the connection.
  • Once the web server receives your ACK flag, the connection is established.

This process occurs each time you visit a website and works similarly for any TCP connection, such as SSH.

Hackers use tools to create TCP packets with unusual, weird flag combinations, known as INVALID packets, capable of causing significant harm.

UFW blocks these INVALID packets by default, but there are still instances where UFW may overlook and fail to block.

Try running this command using the Nmap utility after enabling the UFW firewall and allowing SSH traffic:

nmap -sW <server_ip>

This performs a Window scan, which bombards the target server with ACK packets. The scan should show that port 22 is open, which means, UFW failed to block this scan.

To enable UFW to block this type of scan, we need to add another rule to the before.rules file, positioned below the default UFW rule for blocking INVALID packets:

-A ufw-before-input -p tcp -m tcp ! --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j ufw-logging-deny
-A ufw-before-input -p tcp -m tcp ! --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j DROP

This rule will block all NEW packets that are not SYN packets. Remember, a connection always starts with a SYN flag!

Don’t forget to add the same to the before6.rules file.

Now, reload UFW:

ufw reload

Try running the same scan again – it won’t work now because UFW is capable of blocking this scan:

...
All 1000 scanned ports on <server_ip> are filtered
...

As you can see, Nmap is unable to find any open ports, even though the SSH port is open.

As a performance bonus, we may opt to block INVALID packets before they travel the entire INPUT chain.

We could do that with a PREROUTING chain, but the filter table doesn’t have it. Therefore, we need to use the PREROUTING chain of the mangle table instead.

The PREROUTING chain takes effect in the routing process before packets reach the OUTPUT, FORWARD, or INPUT chains.

Add this to the end of the before.rules file, replacing the previously mentioned rule:

*mangle
:PREROUTING ACCEPT [0:0]
-A PREROUTING -m conntrack --ctstate INVALID -j DROP
-A PREROUTING -p tcp -m tcp ! --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j DROP
COMMIT

Don’t forget to add the same to the before6.rules file.

Now, reload UFW:

ufw reload

And that’s it!

1 Like