PFlogging 2.0

It’s no secret that I’m a big fan of computer systems that are running a Unix-like or Unix-derived operating system. There are quite a few around me right now, running FreeBSD, Linux-Mint and Mac OS X Lion. I have a couple more that I keep around in Virtualbox, but don’t use that often. What I really like about Unix , second to its excellent and massive documentation, is its logfiles. Nearly everything you can think of is – or can be – logged into a simple human readable textfile. One of the first things you’d learn using Unix is that syslog will handle logfiles for most of the entire system.“Most? Not all?” Yes, that’s true. Not everything is handled by syslog. A noticeable exception on BSD systems is the PF logging daemon. From the manual-page:

pflogd is a background daemon which reads packets
logged by pf(4) to a pflog(4) interface, normally pflog0,
and writes the packets to a logfile (normally /var/log/pflog)
in tcpdump(1) binary format.

Although tcpdump’s binary format (pcap!) is truly magnificent, as you can feed it to wireshark and replay recorded sessions and stuff like that, it was for me the start of a small shell scripting exercise to get it back to text and syslog so I can read it without too much fancy tooling. Here’s the result:

#!/bin/sh

# -- Globals

export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin

SCRIPT="`basename $0 | sed 's/\..*//'`"
LOCKFILE="/var/run/$SCRIPT"

# -- Functions

warn() {
    echo "$@" >&2
    return 0
}

die() {
    warn "$@. Aborted"
    exit 1
}

clear_lock() {
    rm -f "$LOCKFILE" >/dev/null 2>&1
    return 0
}

clean_exit() {
    clear_lock
    exit 0
}

bailout() {
    clear_lock
    die "Something went wrong. Removed lock ${LOCKFILE}. Please fix"
}

# -- Sanity checking

if [ -f "$LOCKFILE" ]; then
    die "Lockfile $LOCKFILE exists. Another instance active?"
fi

touch "$LOCKFILE" || die "Failed to create lockfile $LOCKFILE"

# -- Main

trap bailout 2 3 6 15

/usr/sbin/tcpdump -l -n -v -s 0 -i pflog0 action block | /usr/bin/logger -p security.info -t "PFLOG-FIREWALL-BLOCKED"

This script will run from root’s crontab and log blocked packets in the security-log. No more, no less. It really is that simple.

### WARNING! THE FOLLOWING COMMANDS REQUIRE ROOT PRIVILEGES AND MAY DAMAGE YOUR COMPUTER SYSTEM AND EVERYTHING ON IT ### USE AT OWN RISC OR DO NOT PROCEED ###

Installing it is quite simple:

  1. Become root on your BSD-box (su -), then
  2. use cron (crontab -e) to run this script every 5 minutes or so.

The script will terminate if a previous placed lockfile is present, it is safe to do something like:

*/5    *    *    *    *    /root/bin/log-blocked.sh >/dev/null 2>&1

…In which /root/bin/log-blocked.sh is the script. Make sure that it is executable (chmod 755 /root/bin/log-blocked.sh).

If you’ve left /etc/syslog.conf as it was installed with the operating system, your security-logfile will be in /var/log/security, on FreeBSD. You can watch the logfile grow using the tail (-f) command on that file and watch for blocked packets. Please note that you will only see blocked traffic if you’ve configured PF to do so (it’s in /etc/pf.conf), and pflogd is running (check /etc/rc.conf). I’d highly recommend using a “block log all” as a default PF policy. This will ensure traffic being dropped that you did not specifically allow in the first place.

…But if you’ve done all that, you will – eventually – see quite some bizar internet traffic, such as:

Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED: 21:10:21.170001 IP (tos 0x0, ttl 49, id 0, offset 0, flags [DF], proto UDP (17), length 998)
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     212.175.16.5.5060 > 83.163.213.6.5060: SIP, length: 970
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     INVITE sip:67209983373663@83.163.213.6 SIP/2.0
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     Via: SIP/2.0/UDP 212.175.16.5;branch=z9hG4bKjgJbEocO3Fv4;rport
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     From: "unknown" <sip:unknown@212.175.16.5>;tag=WRLzuKbXWq
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     To: <sip:67209983373663@83.163.213.6>
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     Contact: <sip:unknown@212.175.16.5>
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     Call-ID: aJf94c9870e0RoUjIPFedqaUFV2bywf1@212.175.16.5
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     CSeq: 101 INVITE
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     User-Agent: CALXNP9NDmrYroPbmPFQ
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     Max-Forwards: 70
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     Allow: INVITE, ACK, CANCEL, BYE
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     Content-Type: application/sdp
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     Content-Length: 510
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     v=0
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     o=unknown 12493 12493 IN IP4 2.3.4.5
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     s=unknown
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     c=IN IP4 2.3.4.5
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     t=0 0
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     m=audio 10318 RTP/AVP 10 4 3 0 8 112 5 7 18 111 101
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     a=rtpmap:10 L16/8000
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     a=rtpmap:4 G723/8000
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     a=fmtp:4 annexa=no
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     a=rtpmap:3 GSM/8000
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     a=rtpmap:0 PCMU/8000
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     a=rtpmap:8 PCMA/8000
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     a=rtpmap:112 AAL2-G726-32/8000
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     a=rtpmap:5 DVI4/8000
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     a=rtpmap:7 LPC/8000
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     a=rtpmap:18 G729/8000
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     a=fmtp:18 annexb=no
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     a=rtpmap:111 G726-32/8000
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     a=rtpmap:101 telephone-event/8000
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     a=fmtp:101 0-16
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     a=silenceSupp:off - - - -
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     a=ptime:20
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:     a=sendrecv
Nov 13 21:10:22 gromit PFLOG-FIREWALL-BLOCKED:

Epilogue

When I first wrote this script I tried to make it a Unix daemon (Unix slang for “service”), with a nice rc-script. As it turned out: Unix shell script works perfectly, but isn’t really suited for more serious programming tasks as that script soon became hideously complex and had numerous bugs. The “solution” presented in this article isn’t perfect either as logging when scheduled from cron allows time-gaps in the logfile. Fixing these blind-spots can not be solved easily without modifying pflogd itself. If you think you can, then please share your thoughts!

 

 

 

This entry was posted in FreeBSD, IT Security and tagged , , , , , . Bookmark the permalink.