Open Source Threat Intelligence And Makeshift RPZ with Unbound

📆
🏷
, , , , ,

Update: Added some remarks about what DNS RPZ actually is, what my objective is and what the outcome will be.

A friend of mine and I tried to play w/ RPZ and knot yesterday and gravely failed. The fact that knot as well as RPZ had been new to us didn’t help. Discussing the failure later that night I remembered that I was already doing something similar at home for adblocking at the DNS level instead of every application on every client. In some way this is also DNS RPZ.

DNS RPZ is something that could be described as DNS firewalling and is described by wikipedia as follows:

Domain Name Service Response Policy Zones (DNS RPZ) is a method that allows a nameserver administrator to overlay custom information on top of the global DNS to provide alternate responses to queries. It is currently implemented in the ISC BIND nameserver (9.8 or later). Another generic name for the DNS RPZ functionality is “DNS firewall”.

My main objective is to block ad networks and malware sites (e.g. command and control) on the DNS level for all devices without them having to install adblockers or stuff. So if someone tries to access a blacklisted site, say domain.tld the client will get a NXDOMAIN as an answer instead of the real IP address. As I can’t keep up with the domains I also want to leverage some of the OSINT feeds available. Currently I have roughly 16k domains blacklisted.

So today I was incorporating some of my OSINT and PF work into my DNS setup at home. Just as a quick primer: I am using OpenBSD as the OS, unbound(8) as recursor and rcs(1) for local and simple version control. Nothing mentioned here is specific to OpenBSD besides the ftp(1) command that I use to fetch the feeds and the location of the files.

Setting up unbound

Setup is pretty simple, just add the following line to /var/unbound/etc/unbound.conf within the server: section of the file:

include: /var/unbound/zones/rpz

Then setup /var/unbound/zones/rpz w/ additional includes, e.g.

include: /var/unbound/zones/adblock.yoyo
include: /var/unbound/zones/adblock.local
include: /var/unbound/zones/ransomware.abuse.ch

where

  • adblock.local is my local, hand-crafted block list with AD networks that are missing in the yoyo list and which I find annoying enough to block them.
  • adblock.yoyo is a list provided by yoyo
  • ransomware.abuse.ch is being provided by abuse.ch and is more focused on the malicious part than yoyo.

Each of the files follows the specification as descibed in the unbound.conf(5) manual page. Basically I am using local-zones of type static, e.g.:

local-zone: "domain.tld" static

Constructing the zones

Currently I am not updating the above zones regularily but manually whenever I remember to do so but I don’t see why I shouldn’t setup a cronjob for doing so. But before that I’d like to move away from working as root while downloading and constructing the files. For now I can live with that, though. The script is as follows:

for _s in adblock.yoyo ransomware.abuse.ch; do
        echo "$_s"
        if [[ -e /var/unbound/zones/"${_s}" ]]; then
                co -l /var/unbound/zones/"${_s}"
        else
                touch /var/unbound/zones/"${_s}"
                ci -l -i -t- /var/unbound/zones/"${_s}"
        fi

        case "${_s}" in
                "adblock.yoyo")  ftp -V -o - 'https://pgl.yoyo.org/adservers/serverlist.php?hostformat=unbound&showintro=0&mimetype=plaintext' |\
                        sed -ne "/local-zone/s/redirect$/static/p" > /var/unbound/zones/"${_s}";;
                "ransomware.abuse.ch")  ftp -VMo- https://ransomwaretracker.abuse.ch/feeds/csv/ |\
                        awk -F, '/^#/{ next }; { if ( $4 ~ /[a-z]/ ) printf("local-zone: %s static\n",$4) }' > /var/unbound/zones/"${_s}";;
        esac

        rcsdiff -u /var/unbound/zones/"${_s}"
        ci -u -m'automatic update' /var/unbound/zones/"${_s}"
done
unbound-checkconf && unbound-control reload

Currently there are lots of sanity checks missing and I’ll let unbound weed out the duplicates. But this is not to be considered more than a POC.

CAVEAT

Obviously this is missing live updates and it doesn’t scale well. I’d love to have a feed that I can share / get e.g. by AXFR but on the otherside, this is maybe not as bad as a starting point as I first thought.

--EOF