mrash / fwknop

Single Packet Authorization > Port Knocking
http://www.cipherdyne.org/fwknop/
GNU General Public License v2.0
1.12k stars 232 forks source link

linux: firewall incorrectly detected because it is currently not supported #266

Open fabianfrz opened 6 years ago

fabianfrz commented 6 years ago

the used tool: /usr/bin/nft - firewall: nftables

configure output (partial)

checking for pcap_open_live in -lpcap... yes
checking for firewall-cmd... no
checking for firewalld... no
checking for iptables... /usr/bin/iptables
checking for ipfw... no
checking for pfctl... no
checking for ipf... no
checking that generated files are newer than configure... done
configure: creating ./config.status

    fwknop-2.6.9 configuration.
    ==========================================================
        Client build:               yes
        Server build:               yes
        GPG encryption support:     yes
                  Gpgme engine:     /usr/bin/gpg

        Installation prefix:        /usr/local

    Server support:
        firewall type:              iptables
        firewall program path:      /usr/bin/iptables

 /bin/sh ./config.status
config.status: creating Makefile
config.status: creating lib/Makefile
config.status: creating client/Makefile
config.status: creating server/Makefile
config.status: creating common/Makefile
config.status: creating doc/Makefile
mrash commented 6 years ago

Hi - fwknop just looks for the existence of the iptables binary, and assumes this is the firewall to use if it's there. To get things working with nftables, just ignore the default 'iptables' detection, and do something very similar to these instructions for using 'ipset' instead of 'iptables'. nftables can be supported in a similar fashion: http://www.cipherdyne.org/fwknop/docs/fwknop-tutorial.html#spa-with-ipset

There is also a blog post about this here: http://cipherdyne.org/blog/2015/12/single-packet-authorization-and-third-party-devices.html

thomasrebele commented 5 years ago

Debian also switched to netfilter, so I looked for a workaround. I added those two lines to /etc/fwknop/access.conf:

CMD_CYCLE_OPEN /etc/fwknop/nft.sh OPEN $IP $PORT
CMD_CYCLE_CLOSE /etc/fwknop/nft.sh CLOSE $IP $PORT

CMD_CYCLE_TIMER 30;

Here the content of the script /etc/fwknop/nft.sh

#!/bin/bash

LOG_FILE="/var/log/fwknop-nft.log"

ACTION="$1"
IP="$2"
PORT="$3"

if [ "$ACTION" == "OPEN" ]; then
    nft add rule inet filter FWKNOP_INPUT ip saddr $IP tcp dport $PORT accept
fi

if [ "$ACTION" == "CLOSE" ]; then
    nft -nn list ruleset -a >> $LOG_FILE 2>&1

    _RULES() {
        nft -nn list ruleset -a | grep " $IP " | grep " dport $PORT "
    }

    echo "removing access for $IP port $PORT: found $(_RULES | wc -l) rules" >> $LOG_FILE
    _RULES | while read -r RULE; do
        HANDLE=$(echo "$RULE" | sed 's/.*handle //')
        echo "dropping rule $RULE using handle $HANDLE" >> $LOG_FILE
        nft delete rule inet filter FWKNOP_INPUT handle $HANDLE  >> $LOG_FILE 2>&1
    done
fi

You also need to set the executable bit chmod u+x /etc/fwknop/nft.sh

redongh commented 4 years ago

@thomasrebele trying to follow your suggestion I got permission-errors like fwknopd[12345]: run_extcmd(): execvpe() failed: Permission denied upon the execution of nft.sh (of course this has perm 0700 and is owned by root) so I wonder which owner/perms you have set?

oddly, even specifying CMD_CYCLE_OPEN /usr/bin/touch /tmp/touchtest yields this error which makes me wonder even more what the limiting permission might be.

looking around other configurable options I came across CMD_EXEC_USER which according to the comment doesn't really apply here but should use root per default as i didn't specify anything specific here.

oh, and it seems that it is also necessary to define CMD_CYCLE_TIMER besides configuring CMD_CYCLE_OPEN / CMD_CYCLE_CLOSE as you mentioned above.

one last thing: what default-drop firewall (netfilter!) policy did you use?

thomasrebele commented 4 years ago

I've set the permissions to 0544/-r-xr--r--. Owner and group is root. Is /etc/fwknop mounted with the noexec option? Does it work when you run the script from the shell?

Thanks for pointing out that CMD_CYCLE_TIMER is required. I've updated my previous comment.

I'm using these rules: https://gist.github.com/thomasrebele/c3dcdbb7ea275ac30147bafec81804d3 Any ideas how to improve them are welcome!

redongh commented 4 years ago

@thomasrebele poking around further helped me to determine that the permission-errors were likely related to an incomplete uninstall of the fwknop-apparmor-package and are now gone (after reinstalling and modifying it to allow reading nft.sh), so this issue seems solved.

the ruleset also helped me to better understand how everything works together, thanks for providing the gist-link! evaluating these rules i found that the specified port appears as filtered (as they are DROPped) outside the enabled cycle while all unhandled ports appear as closed (REJECT) when scanning with nmap so i guess i'll check how to further align the behaviour. oh, and as i browsed the originating ruleset i also found that the author recently provided a simplyfied nft-ruleset of his original iptables-ruleset: https://github.com/alpinelinux/aports/blob/5fb99cfa8dd7081477426ed885b2e385c0278fce/main/nftables/nftables.nft

EDIT: initially, filtering the ssh-port did not appear to work properly as nmap reported it as being open in my case but after disabling the service sshguard which was also installed and active on my system, bevahiour changed as described.

thomasrebele commented 4 years ago

thanks for the link! I have not much experience in configuring firewalls. I might align my configuration with the link you provided.

Raybuntu commented 4 years ago

@thomasrebele I like your script. Actually I was about to code something in python since there is python3-nftables and it's simple to get the "handle". Now I was reading the nftables docs and this should work too (untested yet): nft add set ip filter fwknop-input "{ type ipv4_addr . inet_service; flags timeout; size 65536; }" nft add rule ip filter INPUT ip saddr . tcp dport @fwknop-input accept

1st command creates a SET fwknop-input and use concatenations to store both ip4_addr and dport. 2nd command checks (in the INPUT chain of table filter) saddr and tcp dport from the elements in fwknop-input SET. Example to add an IP/Port combo:

nft add element filter fwknop-input "{ 10.2.3.4 . 22 timeout 60s }" I could not find a way to set the protocol. So it would be best to make a small bash script to check $PROTO and have 2 SETS in the filter table. We should also be able to pass $CLIENT_TIMEOUT.

In the script for tcp: nft add element filter fwknop-tcp-input "{ $SRC . $PORT timeout $CLIENT_TIMEOUT }" or for udp: nft add element filter fwknop-udp-input "{ $SRC . $PORT timeout $CLIENT_TIMEOUT }" CMD_CYCLE_CLOSE can be None because the kernel will handle the timeout. Same could be extended to ipv6 too but I have no idea if fwknop even supports ipv6.

Ray

UPDATE This is the script I'm using with the solution above:

#!/bin/bash

IP="$1"
PROTO="$2"
PORT="$3"
CLIENT_TIMEOUT="$4"

if [[ "$PORT" -gt 65535 ]];then 
    echo "illegal port number"
    exit 1
fi

if [[ "$PROTO" -eq 6 ]];then 
    NFTSET="fwknop-input-tcp"
elif [[ "$PROTO" -eq 17 ]];then 
    NFTSET="fwknop-input-udp"
else
    echo "unsupported proto: $PROTO"
    exit 1
fi

echo nft add element filter "$NFTSET" "{ $IP . $PORT timeout ${CLIENT_TIMEOUT}s }"
nft add element filter "$NFTSET" "{ $IP . $PORT timeout ${CLIENT_TIMEOUT}s }"
CMD_CYCLE_OPEN /usr/local/bin/nft-fwknop $SRC $PROTO $PORT $CLIENT_TIMEOUT
CMD_CYCLE_CLOSE NONE
CMD_CYCLE_TIMER 30;
NicholasFahey commented 4 years ago

How should I be configuring fwknop if my system's only firewall binary is nft? I'm using CMD_CYCLE_OPEN and CMD_CYCLE_CLOSE with nft, so seems like I shouldn't have to specify a firewall binary but configure fails with

checking for firewall-cmd... no
checking for firewalld... no
checking for iptables... no
checking for ipfw... no
checking for pfctl... no
checking for ipf... no
configure: error: No firewall program was found or specified.

Doesn't seem like there's a way to tell configure I am using custom commands and to not check for a firewall binary. Seems like an oversight. I can work around it with something like --with-firewall-cmd=/usr/bin/nft as a configure option but seems a bit misleading.

hmh commented 1 year ago

My issue with this kind of compatibility layer is that the fwknopd events are not capable of handling multiple entries, so if you just open one port, they work. If you need it to open a list of protocol/port, it only calls the event with the first one in the list.

Yeah, you can work around it if you don't care about what is inside the packet (which is a sound way of doing things!), but really, usability is rather bad.