This post appeared originally in our sysadvent series and has been moved here following the discontinuation of the sysadvent microsite

In a recent sysadvent article I described how to configure BIND with a Response Policy Zone. Using an RPZ can efficiently thwart outbound network traffic based on one’s own preferences, and it can be extended to import and/or subscribe to externally provided DNS zones.

Configuring BIND

My local BIND server has been configured with two RPZs. One is maintained manually, mostly for reaching internal resources behind a NAT firewall by their official DNS names. The other one is a dedicated malware RPZ, automatically updated once a day from the freely available files provided by the Malware Domain Blocklist (note their terms of use). When downloaded, the list of domains associated with malicious activity is converted to an RPZ compatible zone file. The resulting file is saved as /etc/bind/db.malware. Below are the first few lines of this file after conversion.

$TTL 60
@               IN      SOA     primary-dns.example.com. root.example.com.  (
                        2015120911      ; serial
                        3H              ; refresh
                        1H              ; retry
                        1W              ; expiry
                        1H)             ; minimum
                IN      NS      primary-dns.example.com.
                IN      NS      secondary-dns.example.com.

jnvzpp.sellclassics.com IN      A       127.0.0.1
                        IN      AAAA    ::1
iebar.t2t2.com          IN      A       127.0.0.1
                        IN      AAAA    ::1
27simn888.com           IN      A       127.0.0.1
                        IN      AAAA    ::1
74203s040.edusite.ru    IN      A       127.0.0.1
                        IN      AAAA    ::1
adfrut.cl               IN      A       127.0.0.1
                        IN      AAAA    ::1
byxlujke.ru             IN      A       127.0.0.1
                        IN      AAAA    ::1
; [...]

The malware zone

BIND allows up to 32 different Response Policy Zone files, so I’ve separated the two, naming the manual zone “rpz” and the malware domains zone “malware”. Configuring them is done in named.conf or a supporting file (for instance /etc/named.conf.local if you’re on a Debian based platform).

zone "rpz" {
  ; manually maintained zone
  type master;
  file "/etc/bind/db.rpz";
};
zone "malware" {
  ; automatically updated zone
  type master;
  file "/etc/bind/db.malwaredomains";
};

Both zones are added to the response-policy {} clause. Add this inside the options {} section in named.conf (or /etc/bind/named.conf.options on Debian and derivatives).

options {
  response-policy {
    zone "rpz";
    zone "malware";
  };
};

Log configuration

The zones defined in the above response-policy {} setting will automatically log to the rpz category. In Debian, logging is configured in /etc/bind/named.conf.local.

logging {
  ; Define a logging target (channel)
  channel named-rpz {
    file "/var/log/bind/rpz.log" versions 3 size 250k;
    severity info;
  };

  ; Direct every rpz event to the defined channel
  category rpz {
    named-rpz;
  };
};

Paydirt!

When properly configured, requests for domains in the malware zone are logged in the RPZ log file, suffixed with the zone reference, namely malware. The following extract shows successful logging of a request for a domain listed in the malware zone.

client 127.0.0.1#53547 (byxlujke.ru): rpz QNAME Local-Data rewrite
byxlujke.ru via byxlujke.ru.malware

Requests picked up by the other RPZ file, simply named “rpz”, will have a .rpz suffix.

Adding OSSEC to the mix

After testing that attempts to reach malware sites are indeed logged by the DNS server, I set up OSSEC to tail BIND’s malware query log. For this I had to write a decoder and define logging rules in OSSEC, shown below. Both of these could probably be drastically improved by someone more fluent in OSSEC. That said, I haven’t seen a single false positive - yet…

OSSEC master

The log parsing takes place on the OSSEC master. There are two files to modify, and one to add.

Add the following content to /var/ossec/etc/local_decoder.xml:

<decoder name="malware-dns">
    <prematch>^client </prematch>
</decoder>

<decoder name="malware-dns-lookup">
    <parent>malware-dns</parent>
    <regex offset="after_parent">^(\.+)#\d+ \((\.+)\): \.+.malware$</regex>
    <order>srcip, extra_data</order>
</decoder>

Add a new file /var/ossec/rules/malware_dns_rules.xml with the following content:

<group name="syslog,bind">
  <!-- Malware DNS Log Types -->
  <!-- level=0 for not generating alerts by default -->
  <rule id="110201" level="0">
    <decoded_as>malware-dns</decoded_as>
    <description>Malware DNS group</description>
  </rule>

  <!-- Malware DNS Event Chains -->
  <!-- Fire an alert (level=8) if the log line ends with "malware" -->
  <rule id="110202" level="8">
    <if_sid>110201</if_sid>
    <match>malware$</match>
    <description>Malware DNS lookup</description>
  </rule>
</group>

Last step on the OSSEC master is to include the above rules file. Add an <include> line in /var/ossec/etc/ossec.conf:

<ossec_config>
  [...]
  <rules>
    [...]
    <include>malware_dns_rules.xml</include>
  </rules>
  [...]
</ossec_config>

OSSEC agent

The name of the file to tail needs to be defined on every OSSEC agent. The configuration file for this is /var/ossec/etc/ossec.conf.

<ossec_config>
  [...]
  <localfile>
    <log_format>syslog</log_format>
    <location>/var/log/bind/rpz.log</location>
  </localfile>
</ossec_config>

Testing the parser

If everything has been set up correctly, OSSEC parsing should work as expected. To be on the safe side, test the parser with OSSEC’s ossec-logtest.

root@server:~# /var/ossec/bin/ossec-logtest
2015/12/09 08:49:48 ossec-testrule: INFO: Reading local decoder file.
2015/12/09 08:49:48 ossec-testrule: INFO: Started (pid: 2772).
ossec-testrule: Type one log per line.

client 127.0.0.1#3558 (byxlujke.ru): rpz QNAME Local-Data rewrite
byxlujke.ru via byxlujke.ru.malware


**Phase 1: Completed pre-decoding.
       full event: 'client 127.0.0.1#3558 (byxlujke.ru): rpz QNAME
       Local-Data rewrite byxlujke.ru via byxlujke.ru.malware'
       hostname: 'server'
       program_name: '(null)'
       log: 'client 127.0.0.1#3558
       (byxlujke.ru): rpz QNAME Local-Data rewrite byxlujke.ru via
       byxlujke.ru.malware'

**Phase 2: Completed decoding.
       decoder: 'malware-dns'
       srcip: '127.0.0.1'
       extra_data: 'byxlujke.ru'

**Phase 3: Completed filtering (rules).
       Rule id: '110202'
       Level: '8'
       Description: 'Malware DNS lookup'
       **Alert to be generated.

The result

Now, if someone (or something) on my network is trying to reach a resource on a domain registered as affiliated with malware, OSSEC will react and alert by email, raise an alarm in your SIEM, or whatever else you want OSSEC to do.

Below is a sample email alert from OSSEC, when attempting to browse a malware domain from a client.

OSSEC HIDS Notification.
2015 Dec 09 15:07:06

Received From: server->/var/log/bind/rpz.log
Rule: 110202 fired (level 8) -> "Malware DNS lookup"
Portion of the log(s):

client 192.168.42.42#52162 (byxlujke.ru):
rpz QNAME Local-Data rewrite byxlujke.ru via byxlujke.ru.malware

And an extract from OSSEC’s alert log:

** Alert 1449670026.3728841: mail  - syslog,bind
2015 Dec 09 15:07:06 server->/var/log/bind/rpz.log
Rule: 110202 (level 8) -> 'Malware DNS lookup'
Src IP: 192.168.42.42
client 192.168.42.42#52162 (byxlujke.ru): rpz QNAME Local-Data rewrite byxlujke.ru via byxlujke.ru.malware

Bjørn Ruberg

Senior Systems Consultant at Redpill Linpro

With long experience as both a network security consultant and system administrator, Bjørn is one of those guys we go to when we need forensics to be done on a potentially compromised system. He's also good at dealing with tailored DDoS-attacks on our customers, and always has a trick up his sleeve.

Containerized Development Environment

Do you spend days or weeks setting up your development environment just the way you like it when you get a new computer? Is your home directory a mess of dotfiles and metadata that you’re reluctant to clean up just in case they do something useful? Do you avoid trying new versions of software because of the effort to roll back software and settings if the new version doesn’t work?

Take control over your local development environment with containerization and Dev-Env-as-Code!

... [continue reading]

Ansible-runner

Published on February 27, 2024

Portable Java shell scripts with Java 21

Published on February 21, 2024