Nmap Development mailing list archives

Defeating a Nmap decoy scan using statistics


From: Brandon Enright <bmenrigh () ucsd edu>
Date: Mon, 14 Jul 2008 22:57:48 +0000

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Fellow developers and port scanning geeks,

I've been giving some thought to how to detect the real scanning host in
a sea of decoys.  Up until I think it has been generally accepted that
if the attacker does everything "right" there isn't a way to determine
the real attacker.

By right I mean that the scan doesn't leak any addition information
because it doesn't do DNS, service or OS fingerprinting, etc.

For example, this scan shouldn't leak information:

# nmap <victim> -sS -n -v -P0 -T5 -p <ports> -D fake1,fake2,ME,fake3...

Of course, this assumes that all the decoys actually reach the target.
This would not be the case with RPF (reverse-path-forwarding) or
quality egress filtering.

So lets break a simplified version of this where Nmap uses the same TTL
on all the IP packets it sends.  In this setup, Nmap scans <victim>
with itself and one <decoy> and all the IP packets start with a TTL of
10.  Nmap is 5 hops away from <victim> and <decoy> is some other number
of hops away from <victim>, say, 7.

Breaking this is somewhat trivial -- <victim> can look at the packets
from the real scanner and from <decoy> and see that they all arrive
with a TTL of 5.  Since <victim> has the source code to Nmap and knows
that all packets started with a TTL of 10, <victim> knows the real
attacker is 5 hops away.  <victim> can now probe each of the potential
attackers to determine which is 5 hops away (there are several ways to
do this and it can't be prevented in general).

An attackers sending decoys has no generic way to prevent such
information disclosure.  The attackers can't (in general) determine how
many hops the victim is away from the decoys and can't prevent the TTL
from decrementing uniformly for all the decoy probes.

The obvious approach to solving this problem is to randomize the
initial TTL so that the victim gets random TTLs.  Nmap does this but it
does it too uniformly and the simplified attack discussed above can be
extended to break how Nmap currently sends decoys.

The heart of the problem is with this code:

/* Time to live */
if (ttl == -1) {
  myttl = (get_random_uint() % 23) + 37;
} else {
  myttl = ttl;
}

Nmap chooses a random TTL for each probe uniformly in the range
[37, 59].  Instead of the victim receiving packets with the same TTL,
the packets have randomized TTLs.  Statistically though we know that
Nmap sent a TTL of 48 _on_average_.  All the victim has to do now is
compute the average TTL for incoming packets.  48 - <computed average>
is the distance the attacker is away from the victim.  With even just a
few dozen probes the average will fall very close to an integer offset
from 48.  Now that the victim knows the attacker's distance they can
probe hosts to determine which of the scanning machines has that
distance.

The reason this attack works is that the initial random TTL is chosen
uniformly across different decoy hosts.  If each decoy host had a
slightly different range of TTLs, it would not be possible to find the
"correct" average and the victim would not be able to determine how
many hops the real attacker is away.

So how do we "fix" this so that decoys don't leak information about the
attacker?  This is what I propose:

For each decoy, we generate a decoy-specific TTL offset.  We then
change the TTL generation code to look like this:

/* Time to live */
if (ttl == -1) {
  myttl = (get_random_uint() % 23) + 37 + decoy_offset;
} else {
  myttl = ttl;
}

At the very startup of Nmap, we generate a random decoy_offset for each
decoy host that persists for the remainder of the scan.  I propose a
random decoy offset range of [0,16) which should be good enough unless
you pick decoys that are more than 15 hops different to the victim --
something that is very unlikely on the current Internet.

Note that the above system can also be broken but it would require that
the attacker scanned the victim with the same set of decoys many times
until the victim could average the decoy_offset per host to be 7.5 --
no stealthy Nmap user would do this...

Comments welcome.

Brandon

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.9 (GNU/Linux)

iEYEARECAAYFAkh72fMACgkQqaGPzAsl94KfSgCfb7nFMYPv/sBymyZwAiDLcNrs
qkIAoK3WOpMVywjPMxEEuCyJEGqIUNoO
=PDcO
-----END PGP SIGNATURE-----

_______________________________________________
Sent through the nmap-dev mailing list
http://cgi.insecure.org/mailman/listinfo/nmap-dev
Archived at http://SecLists.Org


Current thread: