Authenticated as: Anonymous (Change Credentials / Create Account)

Strykar

By Strykar

Posted: 08:58:00 2008-04-01

Modified: 06:27:24 2008-04-10 by Strykar

Port knocking with OpenBSD using a shell script in RAMfs.

The other day, I needed to setup port-knocking while running some tests, and wrote a small script to grep OpenBSD's pf log and dynamically change firewall rules. Since I didn't wanna run the disk on the archaic machine I was trying it via ADSL to the ground, I used a RAM based filesystem ramfs to prevent the frequent read/write operations the few lines in the script may have caused.

It's a dirty hack, and could be *vastly* improved upon, but it was enough for a day's worth of testing and took 5 minutes to set up. It uses a second pflog interface to keep my regular logs clean. Getting pf's second log interface up is as easy as: ifconfig pflog2 up

Setup rules and tables in pf.conf:

In the snippet below, we've created a table called knockers and we block UDP packets to port 65535 and log them to pflog2. Now we allow incoming TCP connections to port 22 for IP addresses in this table as listed in /tmp/ramfs/knockers. You can get pretty creative with what you want pf or a script running system commands to do.

# cat /etc/pf.conf|grep knock table <knockers> persist file "/tmp/ramfs/knockers" block in log (to pflog2) on $ext_if proto udp from any to ($ext_if) port 65535 #knocker pass in on $ext_if inet proto tcp from <knockers> to ($ext_if) port 22 flags S/SA keep state

Create a 160kb filesystem in RAM

mkdir /tmp/ramfs & mount_mfs -s 614 -i 512 swap /tmp/ramfs

Consult the mount_mfs manpage for details. We're basically defining size in blocks. The chosen size of 160kb is arbitrary, use sensible values as you need.

The portknocker listener script:

This basically checks if the actual script, called knocker.sh is running, and if not, to restart it.

# cat /tmp/ramfs/knockd.sh #!/bin/ksh SCRIPT=knocker.sh SCRIPTID="pgrep -f /tmp/ramfs/knocker.sh" if [ $? -ne 1 ]; then sleep 20 pkill -9 -f $SCRIPT /tmp/ramfs/knocker.sh exit 0 fi

The knocker script:

Now, we simply use netcat (nc) to craft a UDP packet with a source port of 65535 and send it to our machine we're running knockd.sh on. Think creatively here, I didn't need this as a permanent solution. You can go Jason Bourne here and have encrypted payloads instead of a simple UDP packet, the list goes on.

The following example basically greps the pflog2 interface for the IP our particular "packet" is coming in from. It then opens port 22 for 30 seconds, which is your window for login. It allows your IP only, which is the one you sent it the 'packet' from; 30 seconds later, it blocks it again. The SSH session you login during this window is unaffected.

# cat /tmp/ramfs/knocker.sh #!/bin/ksh IP=`/usr/sbin/tcpdump -c 1 -n -e -ttt -i pflog2|/usr/bin/awk '{print$10}'|/usr/bin/sed -e 's/......$//g'` SCRIPT1=/tmp/ramfs/knockd.sh /sbin/pfctl -t knockers -T add $IP sleep 30 /sbin/pfctl -t knockers -T delete $IP pkill $SCRIPT1 $SCRIPT1 exit 0

Start knockd.sh and it will kick up knocker.sh now allowing you to open port 22 remotely for just your IP via the specially crafted packets using nc.