Fast Flux
and DNS Cache Poisoning Detection 0.2
On the suggestion of Andre
Ludwig, I ported the crusty old DNS preprocessor code to a newer
version (2.8.3.beta), and am releasing it for general use. In it's
current form I just made a few modifications for data structure changes
and attached it to the excellent existing dynamic DNS
preprocessor. This set of code should detect two general
types of interesting events:
- Classic DNS Cache poisoning where a large number of false
responses are made to a record lookup within a (given) time window.
- DNS Fast Flux detection for A record lookup responses. This
is based on work by Holz et al - see below for details.
If there is interest for this software, I would be happy to create more
documentation than just this page. Until that point in time this
set of notes will have to do.
Details
DNS Cache Poisoning
Several excellent descriptions of this phenomena exist already so I
will not go cut and paste them into here. There are several
different tests that are done here. They are as follows:
Multiple responses to a query where the
DNS server IP and query name match, but the transaction ID
varies. This alert looks like:
[**]
[131:4:1] (spp_dns_session) NOID
host.example.com [**]
[Priority: 3]
07/23-10:36:16.300546
10.10.10.10:53 -> 192.168.1.127:53
UDP TTL:255 TOS:0x0 ID:5312
IpLen:20 DgmLen:187
Len: 159
Multiple responses to a query where the
DNS server IP, query name and transaction ID match. This is
similar to the attack above, except that there is a transaction ID
match. The alert text looks like:
[**]
[131:5:1] (spp_dns_session) ID
host.example.com [**]
[Priority: 3]
07/23-10:36:16.941173
10.20.20.20:53 -> 192.168.1.127:53
UDP TTL:52 TOS:0x0 ID:51123
IpLen:20 DgmLen:126
Len: 98
Unexpected responses where there is no
observed question. This is somewhat noisy, but is added to
provide a site the ability to monitor this quantity over time.
The alert text looks like:
[**]
[131:6:1] (spp_dns_session) DNS
Response without question for x.example.com [**]
[Priority: 3]
07/23-10:36:15.839465
10.30.30.30:53 -> 192.168.1.127:53
UDP TTL:255 TOS:0x0 ID:39003
IpLen:20 DgmLen:187
Len: 159
Fast Flux Detection
Like the cache poisoning, there are many interesting and informative
sites which describe DNS fast flux. One of my favorites is the
Honey Net site's "Know
Your Enemy: Fast Flux Service Networks" . The main algorithm
used in this detector is based in part on a paper presented at NDSS
'08 by Holz, Gorecki, Freiling and Rieck. Their contribution
to network based fast flux detection can not be emphasized enough!!
What we look for is an unusually large number of ASN records associated
with a given A records lookup taken over a time window. The
running weight for a particular A record is not just a simple W = A*i +
B*n (with A and B being constants, i being the number of unique IP
addresses and n being the number of unique ASN's), but also
incorporates the notion that fast flux networks will be spread out more
evenly across address space than 'normal' content distribution
networks. With this in mind, the running weight looks more like:
W = ( n / i )( A * i + B * n ). This does a slightly better
job in detection.
Note that this will absolutely flag an number of records which by
design act exactly like hostile fast flux domains. Examples are
pool.ntp.org, chat.freenode.net, ocsp.verisign.net and several
more. We expect to publish a new algorithm soon which will
address a number of these problems.
Output from this preprocessor looks like:
[**]
[131:7:1] FLUX mailers.gfi.com
IP: 6 ASN: 6 WEIGHT: 119.160000[**]
[Priority: 3]
08/21-12:12:54.187414
216.218.202.31:53 -> 128.55.6.66:51407
UDP TTL:118 TOS:0x0 ID:51700
IpLen:20 DgmLen:488
Len: 460
Configuration
There are a number of additional configuration options available to the
dns preprocessor. They are as follows:
Option
|
Notes
|
| dns_session |
Activates cache poisoning
detection. Not required for flux detection.
|
| dns_state_window <time in
sec> |
Time window that state
information is maintained before being flushed. Default = 10
seconds.
|
| max_noid_threshold <n> |
Number of DNS responses which
match client IP and query name, but which disagree on session ID.
Default = 50.
|
| max_id_threshold <n> |
Same as above except that
session id matches as well. Default = 50.
|
| multiple_response <n> |
Look for multiple DNS responses
where session id matches. Associated with max_id_threshold.
Default = 1: set to 0 to turn off.
|
| multiple_response_timeout
<time in sec> |
Defines window for
max_id_threshold test.
|
| rogue_response |
Report DNS responses which do
not have an associated request. Rather noisy. Default = off.
|
| dns_flux |
Activate fast flux detector.
|
| dns_flux_runtime_dump |
Dump running debug
information. Output looks something like:
pool.ntp.org IP: 1 ASN: 1
WEIGHT: 19.860000 IP: 69.36.240.252 ASN: AS8121
pool.ntp.org IP: 2
ASN: 2 WEIGHT: 39.720000 IP: 216.184.20.83 ASN: AS10381
pool.ntp.org IP: 3
ASN: 3 WEIGHT: 59.580000 IP: 216.75.55.11 ASN: AS10439
pool.ntp.org IP: 4
ASN: 4 WEIGHT: 79.440000 IP: 74.53.198.146 ASN: AS21844
|
| flux_logfile < absolute file path > |
Optional logfile to dump detailed log information to.
|
Sample Usage:
preprocessor dns: \
ports { 53 } \
enable_rdata_overflow \
enable_experimental_types \
dns_session \
multiple_response \
dns_flux \
dns_flux_runtime_dump \
flux_logfile /tmp/logf
Install
For now the install is a little free and loose. For fast flux
detection to work, you will have to have the MaxMind GeoIP libraries
installed as well as the GeoLite ASN database. The general GeoIP
can be found here, while
the GeoLite ASN is here.
Make sure that the install went correctly before proceeding.
The source tarball contains the following files:
src/dynamic-preprocessors/dns/spp_dns.c
: man preprocessor source
src/dynamic-preprocessors/dns/spp_dns.h : main preprocessor header
src/dynamic-preprocessors/dns/Makefile.in : makefile prototype for new
libs
src/dynamic-preprocessors/libs/dnslib.c : library functions for the new
code
src/dynamic-preprocessors/libs/dnslib.h : library functions for the new
code
you should just be able to untar the code in the main source
root. This was built against snort-2.8.3.beta, but this part of
the source tree has been dormant as of late so the changes should work
for most versions.
The 'configure' environment will have to be modified slightly to take
into consideration GeoIP by modifying environmental variables.
For example:
export LDFLAGS -L/usr/local/lib
export LIBS -lGeoIP
export CPPFLAGS -I/usr/local/include
then configure and make as usual with whatever changes are normal to
your system.