Archive for February, 2012

13
Feb
12

Mapping CDN Domains

Introduction

Feel free to read from the bottom up if your not bothered about my ramblings

There an IETF draft proposed Google, Verisign and Neustar, available here http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-00. The benefit of this draft is to allow CDN networks to direct users to the web server which offeres the best performance for the users IP network.

The problem the CDN networks are trying to resolve exists because of the way CDN networks currently engineer traffic. In current implementations the source IP address of the dns query is used to decide which A Record it will return to the user. Most users do not perform iterative queries, they simply ask there upstream DNS cache to perform the query. So when the CDN network provides an answer it is on the source IP address of the caching server and not the user IP address.

In most situations this is not a problem because the caching server and the user will most likely prefer the same webserver. This becomes a problem for users who use Anycast Public DNS services, e.g. OpenDNS or large ISPs. In these cases the server which is making the query could be far away from the user asking. this can result in a UK user being directed to a US web-server.

Client-subnet resolves this problem by letting a user set the client subnet option with the value the CDN server should use to make its decisions instead of the the source address of the query.

Here is a diagram, OK i forgot how much i hated doing diagrams. Ill try and do something on the whiteboard later and upload a photo.  i should probably also mention that my desktop publishing skills are pretty much lacking across the board.

How can we use this?

Well if we are “pen testing” a network we want to find as many targets as possible. With normal query we can only retrive the serveres that the CDN provider thinks is best for us [or your cache]. We could utilise the current behavior of CDN networks to enumerate more entries. Grap your list of open resolvers and see what records and gather all the different answers.

Seems a bit of a pain, you need to maintain your list of serveres, write a script to resolve everything; collate it etc. But with this new extension we can just send an arbitrary IP address and ask the resolver to give us information for that address. Note this is by design and not a flaw.

With this in mind i thought it would be great if we could have these features in nmap. point nmap at an authoritative NS server, give it a domain and have nmap query the name server from multiple geographical locations and scan each record it finds.

This has led me to create 2 new scripts for nmap.

  • dns-client-subnet.nse
  • dns-client-subnet-scan.nse

dns-client-subnet.nse

The first script is more a proof of concept it takes the following arguments

  • dns-client-subnet.domain The domain to lookup
  • dns-client-subnet.address the client address to use
  • dns-client-subnet.nameserver nameserver to use. (default = host.ip)

This allows us to perform one scan/query specifying our own client IP address to see if we get different results.

Here we specify a source of 1.0.0.0

 nmap -sU -p 53 --script dns-client-subnet --script-args dns-client-subnet.domain=www.google.com,dns-client-subnet.address=1.0.0.0,dns-client-subnet.nameserver=ns1.google.com ns1.google.com</p>
Starting Nmap 5.61TEST4 ( http://nmap.org ) at 2012-02-13 20:45 CET
Nmap scan report for ns1.google.com (216.239.32.10)
Host is up (0.014s latency).
PORT STATE SERVICE
53/udp open|filtered domain
| dns-client-subnet:
| A : 74.125.235.84,74.125.235.80,74.125.235.81,74.125.235.83,74.125.235.82
|_ details : 24/32/1.0.0

Here we specify a source of 2.0.0.0

nmap -sU -p 53 --script dns-client-subnet --script-args dns-client-subnet.domain=www.google.com,dns-client-subnet.address=2.0.0.0,dns-client-subnet.nameserver=ns1.google.com ns1.google.com</p>
Starting Nmap 5.61TEST4 ( http://nmap.org ) at 2012-02-13 20:45 CET
Nmap scan report for ns1.google.com (216.239.32.10)
Host is up (0.015s latency).
PORT STATE SERVICE
53/udp open|filtered domain
| dns-client-subnet:
| A : 209.85.147.104,209.85.147.103,209.85.147.147,209.85.147.105,209.85.147.106,209.85.147.99
|_ details : 24/20/2.0.0</p>
Nmap done: 1 IP address (1 host up) scanned in 0.35 seconds

Success you can clearly see that the results are completely different.

Details

While we are here ill explain the details section.

  • details : 24/20/2.0.0

the first parameter is the subnet mask we sent. We are basically saying this user is somewhere in the 1.0.0.0/24 subnet.

The second parameter explains what subnet this response is valid for.

  • The first response we see a value of 32. this means that the response is only valid for the ip address 1.0.0.0/32.
  • The second has 20 so you should get the same response if you query from ip address in the 2.0.0.0/20

The last parameter is just an echo of the address we sent. One bit is missing because we only sent a /24 so the last bit is not needed.

One thing to explore further is how we can use this information to walk the dns. i.e. if we get a response like the above 2.0.0/20, we know to set the next client-subnet to 2.0.16/20. Then adjust subnet mask and client-subnet of the next query, based on the response we get. I played with this a bit but i got a lot of /32 response which would make things take a while. Although this is something that is worth more research though.

dns-client-subnet-scan.nse

So As the above method worked but we cant use details to easily enumerate all entries. So i decided to use a database of IP addresses and cycle through them. For this i chose the maxmind database. All i need is an IP address for each location. To gather this information i ran the following bash one liners. after downloading and extracting the maxmind cvs files.

awk -F, '{print $2}' GeoLiteCity_20120207/GeoLiteCity-Location.csv | tr -d \" | sort | uniq &gt; cc.codes
for i in $(&lt; area.codes ) ;
 do grep -m 1 ${i} GeoLiteCity_20120207/GeoLiteCity-Location.csv ;
done | tr -d \" | awk -F, '{printf "%s %s:%s,%s\n",$1,$2,$3,$4}' | while read line ;
do id=${line%% *};
 description_and_country=${line##* };
 description=${description_and_country##*:};
 country=${description_and_country%%:*};
 if [ "${description}" != "," ];
 then code=${description%%,*};
 place=${description##*,} ;
 addr=$(grep -m 1 "\"${id}\"" GeoLiteCity_20120207/GeoLiteCity-Blocks.csv | \
 tr -d \" | awk -F, '{print $1}') ;
 echo -e "\t${country}.${code} = {ip=${addr}, desc=\"${country},${description}\"}," ;
 fi ;
done

I wont expand this one


awk -F, '{print $2}' GeoLiteCity_20120207/GeoLiteCity-Location.csv | tr -d \" | sort | uniq &gt; cc.codes
 for i in $(&lt; cc.codes ) ; do grep -m 1 ${i} GeoLiteCity_20120207/GeoLiteCity-Location.csv ; done | tr -d \" | awk -F, '{printf "%s %s\n",$1,$2}' | while read line ; do id=${line%% *}; country=${line##* }; addr=$(grep -m 1 "\"${id}\"" GeoLiteCity_20120207/GeoLiteCity-Blocks.csv | tr -d \" | awk -F, '{print $1}') ; echo -e "\t$country = {ip=${addr}, desc=\"${country}\"}," ; done

Now the above code is a very dirty hack and still required me to do some manual clean up. dont ask me to explain my logic, it was late and i just wanted results :). However with a bit of massaging the above managed to get me the structure you see at the top of the this script. This takes that structure, cycles through it, and performs a query for each address.

This script takes the following arguments

  • dns-client-subnet.domain The domain to lookup
  • dns-client-subnet.nameserver nameserver to use. (default = host.ip)

The results are instead of getting 6 ip addresses for http://www.google.com. We get lots

nmap -sU -p 53 --script dns-client-subnet-scan --script-args dns-client-subnet-scan.domain=www.google.com ns1.google.com
Starting Nmap 5.61TEST4 ( http://nmap.org ) at 2012-02-13 21:19 CET
Nmap scan report for ns1.google.com (216.239.32.10)
Host is up (0.013s latency).
PORT STATE SERVICE
53/udp open|filtered domain
| dns-client-subnet-scan:
| 173.194.33.16
| 173.194.33.17
| 173.194.33.18
| 173.194.33.19
| 173.194.33.20
| 173.194.33.48
| 173.194.33.49
| 173.194.33.50
| 173.194.33.51
| 173.194.33.52
| 173.194.34.112
| 173.194.34.113
| 173.194.34.114
| 173.194.34.115
| 173.194.34.116
| 173.194.34.144
| 173.194.34.145
| 173.194.34.146
| 173.194.34.147
| 173.194.34.148
| 173.194.34.16
| 173.194.34.17
| 173.194.34.176
| 173.194.34.177
| 173.194.34.178
| 173.194.34.179
| 173.194.34.18
| 173.194.34.180
| 173.194.34.19
| 173.194.34.20
| 173.194.34.48
| 173.194.34.49
| 173.194.34.50
| 173.194.34.51
| 173.194.34.52
| 173.194.34.80
| 173.194.34.81
| 173.194.34.82
| 173.194.34.83
| 173.194.34.84
| 173.194.41.112
| 173.194.41.113
| 173.194.41.114
| 173.194.41.115
| 173.194.41.116
| 173.194.41.144
| 173.194.41.145
| 173.194.41.146
| 173.194.41.147
| 173.194.41.148
| 173.194.41.80
| 173.194.41.81
| 173.194.41.82
| 173.194.41.83
| 173.194.41.84
| 173.194.65.103
| 173.194.65.104
| 173.194.65.105
| 173.194.65.106
| 173.194.65.147
| 173.194.65.99
| 173.194.66.103
| 173.194.66.104
| 173.194.66.105
| 173.194.66.106
| 173.194.66.147
| 173.194.66.99
| 173.194.67.103
| 173.194.67.104
| 173.194.67.105
| 173.194.67.106
| 173.194.67.147
| 173.194.67.99
| 173.194.69.103
| 173.194.69.104
| 173.194.69.105
| 173.194.69.106
| 173.194.69.147
| 173.194.69.99
| 209.85.137.103
| 209.85.137.104
| 209.85.137.105
| 209.85.137.147
| 209.85.137.99
| 209.85.143.104
| 209.85.143.99
| 209.85.147.103
| 209.85.147.104
| 209.85.147.105
| 209.85.147.106
| 209.85.147.147
| 209.85.147.99
| 209.85.173.103
| 209.85.173.104
| 209.85.173.105
| 209.85.173.147
| 209.85.173.99
| 209.85.229.103
| 209.85.229.104
| 209.85.229.105
| 209.85.229.147
| 209.85.229.99
| 72.14.204.103
| 72.14.204.104
| 72.14.204.105
| 72.14.204.147
| 72.14.204.99
| 74.125.113.103
| 74.125.113.104
| 74.125.113.105
| 74.125.113.106
| 74.125.113.147
| 74.125.113.99
| 74.125.115.103
| 74.125.115.104
| 74.125.115.105
| 74.125.115.106
| 74.125.115.147
| 74.125.115.99
| 74.125.127.103
| 74.125.127.104
| 74.125.127.105
| 74.125.127.106
| 74.125.127.147
| 74.125.127.99
| 74.125.157.104
| 74.125.157.147
| 74.125.157.99
| 74.125.159.103
| 74.125.159.104
| 74.125.159.105
| 74.125.159.106
| 74.125.159.147
| 74.125.159.99
| 74.125.224.240
| 74.125.224.241
| 74.125.224.242
| 74.125.224.243
| 74.125.224.244
| 74.125.224.80
| 74.125.224.81
| 74.125.224.82
| 74.125.224.83
| 74.125.224.84
| 74.125.225.80
| 74.125.225.81
| 74.125.225.82
| 74.125.225.83
| 74.125.225.84
| 74.125.226.144
| 74.125.226.145
| 74.125.226.146
| 74.125.226.147
| 74.125.226.148
| 74.125.227.112
| 74.125.227.113
| 74.125.227.114
| 74.125.227.115
| 74.125.227.116
| 74.125.227.48
| 74.125.227.49
| 74.125.227.50
| 74.125.227.51
| 74.125.227.52
| 74.125.229.208
| 74.125.229.209
| 74.125.229.210
| 74.125.229.211
| 74.125.229.212
| 74.125.230.208
| 74.125.230.209
| 74.125.230.210
| 74.125.230.211
| 74.125.230.212
| 74.125.230.240
| 74.125.230.241
| 74.125.230.242
| 74.125.230.243
| 74.125.230.244
| 74.125.230.80
| 74.125.230.81
| 74.125.230.82
| 74.125.230.83
| 74.125.230.84
| 74.125.239.16
| 74.125.239.17
| 74.125.239.18
| 74.125.239.19
| 74.125.239.20
| 74.125.31.103
| 74.125.31.104
| 74.125.31.105
| 74.125.31.106
| 74.125.31.147
| 74.125.31.99
| 74.125.53.103
| 74.125.53.104
| 74.125.53.105
| 74.125.53.106
| 74.125.53.147
| 74.125.53.99
| 74.125.71.103
| 74.125.71.104
| 74.125.71.105
| 74.125.71.106
| 74.125.71.147
| 74.125.71.99
| 74.125.79.103
| 74.125.79.104
| 74.125.79.105
| 74.125.79.106
| 74.125.79.147
|_ 74.125.79.99
Nmap done: 1 IP address (1 host up) scanned in 4.50 seconds

Conlusion

I think there is a lot more that could be explored here but i thought i would write up what i have done and see if anyone else is has any ideas

Installation

These scripts both rely on patches to the dns.lua library. I have checked in the full dns.lua library im using and other files to github, see below. copy dns.lua to your system nselib dir. on my system this is
/usr/local/share/nmap/nselib
However this will vary a lot depending on distribution. then copy the dns-client-subnet.nse and dns-client-subnet-scan.nse into ~/.nmap/scripts. Once you have done that you should be able to use the scripts as per the examples above

Files

https://github.com/b4ldr/nse-scripts/blob/master/dns-client-subnet-scan.nse
https://github.com/b4ldr/nse-scripts/blob/master/dns-client-subnet.nse
https://github.com/b4ldr/nselib/blob/master/dns.lua

Advertisements