Inspired by Jordan Geoghegan’s article about pf-badhost I wanted to create my own list based on the “attack attempts” I get on my personal servers.

I just put toghether a small shell script that parses the httpd(8) logs and creates 2 files. One to load into a PF table and another one with entries I’m not sure about and had to be checked manually (either to add them to the patterns to search for or to discard them as legit).

It’s all really simple. The script is this one:


        #!/bin/sh
        
        FILE=$1
        BLOCK=$2
        BAD=""
        UNKNOWN=""
        
        patterns="login.cgi
        admin
        php
        webdav
        iframe"
        
        [ -z "$FILE" ] && echo "Need a log file" && exit 1
        
        while IFS= read -r line
        do
            # ignore first line (rotation)
            echo "$line" | grep -q newsyslog && continue
        
            #gather some info
            IP=$(echo "$line" | awk '{print $2}')
            REQ=$(echo "$line" | awk -F'"' '{print $2}' | awk '{print $2}')
        
            # if you're behind a NAT and want to remove your network segment ...
            # is not really needed if you just filter on egress, but still.
            # echo "$IP" | grep -q "^10\\.42" && continue
        
            # sort things into unknown and bad folks
            if echo "$REQ" | grep -q -e "$patterns" ; then
                BAD="${BAD}${IP}
        "
            else
                UNKNOWN="${UNKNOWN}${IP} ($REQ)
        "
            fi
        done < "$FILE"
        
        echo "$BAD" | sort -uV > /tmp/bad_folks.txt
        echo "$UNKNOWN" | sort -uV >> /tmp/to_check.txt
        
        # and now we clean for duplicates and stuff ...
        cat /etc/pf_tables/bad_folks.txt >> /tmp/bad_folks.txt
        sort -uV /tmp/bad_folks.txt > /etc/pf_tables/bad_folks.txt
        
        # and clean
        rm /tmp/bad_folks.txt
        
        if [ "$BLOCK" = "block" ]; then
            doas pfctl -t bad_folks -T replace -f /etc/pf_tables/bad_folks.txt
        fi

Just fill the patterns variable with one grep pattern per line.

Of course you’ll have to add some rules to pf.conf:


        table <bad_folks> persist file "/etc/pf_tables/bad_folks.txt"
        block in quick on egress from <bad_folks> to any

Remember to add the necessary permissions on doas.conf to the user that runs the script.