At IETF 72 in Dublin I gave a demonstration of DNS spoofing based on the attack on DNS described by Dan Kaminsky. I was able to successfully inject a fake DNS record in to the cache of a name server with a fixed port in a few seconds and sometimes in well under a second.

Bert Hubert published a description of the math behind this attack on namedroppers and I have been playing with the spoofer to see how close I can get the experiment and theory.

I ran my spoofer on a network consisting of three machines linked by a cheap gigabit switch. The attacker was on a Mac Pro, the target nameserver was on a Mac Book Pro and the authoritative server, that the attacker was pretending to be, was on a old FreeBSD box (100Mb). I used DUMMYNET to simulate a longer link to the authoritative server (delay = 30ms).

I ran the spoofer 1000 times and plotted a histogram of the frequency of success against time.

The pink bar shows the median of all the times recorded. If I recall my A level maths correctly, this should coincide with the 50% chance of success predicted by the math.

The math presented by Bert Hubert considers the expansion of the binomial

Ps = probability of success on a single attempt

Pf = probability of failure on a single attempt

( Ps + Pf )^n = 1

Expanding this and remembering that the sum of all the terms containing success = (1- the term for always failing) leads to the probability of combined success

Pcs(n) = 1 – (1 – Ps)^(n)

We know that n = T/W so we get

Pcs(t) = 1 – (1 – Ps)^(t/W)

Bert Hubert tells us that Ps = (D*R*W)/(N*P*I) where

I: Number distinct IDs available (maximum 65536)

P: Number of ports used (maximum around 64000 as ports under 1024

are not always available, but often 1)

N: Number of authoritative nameservers for a domain (averages

around 2.5)

R: Number of packets sent per second by the attacker

W: Window of opportunity, in seconds. Bounded by the response

time of the authoritative servers (often 0.1s)

D: Average number of identical outstanding queries of a resolver

(typically 1, see Section 5)

I used the following values

I=65535

R=36000 – From looking at the traffic I was sending

W=0.030 – From the settings I gave DUMMYNET

N=1.0 (I fixed this)

P=1 (I fixed this)

D=1

Plotting this on the same graph as the histogram gives:

The blue circles are the predicted probability of combined success (Their y axis runs from 0 to 1 and is not shown). As you can see the predicted 50% chance (black cross lines) occurs slightly before the median but it is fairly close.

In order to improve things I added an extra term to the equation to account for the time that the window is closed (This is due to the spoofer taking a bit of time to notice that it has been unsuccessful and to try again). So:

n = T/(W+Wc)

Ps = (D*R*W))/(N*P*I)

where Wc is measured to be about 0.003 seconds. The graph now looks like

That seems like good agreement to me. The median in this case is 1386ms.

BTW: The graphs were plotted using R. This is the code I used

#Plot a histogram of frequency of success against time
mydata <- read.table("/tmp/speed-test-30ms",header=TRUE)
#Plot both on a single graph
h <- hist(mydata$time,breaks=100,plot=FALSE)
plot(h,freq=FALSE, xlim=range(h$mids),ylim=range(h$density),
sub="Histogram showing time to success of real spoofer (pink line shows median)",
main="DNS Spoofer Performance",
ylab="Density", xlab="Time/ms")
abline(v=median(mydata$time),col=70)
#Plot Bert Hubert's math
D=1.0
R=36000.0
W=0.030
Wc=0.003
N=1.0
P=1
I=65535
Ps <- ((D*R*W)/(N*P*I))
Pcs <- function(t){1 - (1 - Ps)**((t/1000)/(W+Wc))}
par(new=TRUE)
nx <- sample(h$mids)
y=Pcs(nx)
#Scale plot to same as histogram
my=max(y)
ny=y*max(h$density)/my
plot(nx,ny, xlim=range(h$mids),ylim=range(h$density),col="blue", ann=FALSE)
#Calculate time for 0.5 chance
time5 = 1000*(W+Wc)*(log10(0.5)/log10(1 - Ps))
abline(v=time5)
abline(h=0.5*max(h$density)/my)