Friday, September 7, 2012

Fixing Metasploit's AXFR support

DNS zone transfers (AXFR requests) are a great source of information about a network, allowing an "interested party" access to all the records on a DNS server. Robin Wood has offered a great resource to the community in the form of zonetransfer.me, a domain that allows zone transfers for testing purposes. Here's what it looks like:

me@here:~$ dig +short zonetransfer.me NS
ns12.zoneedit.com.
ns16.zoneedit.com.
me@here:~$ dig @ns12.zoneedit.com. zonetransfer.me AXFR

; <<>> DiG 9.8.1-P1 <<>> @ns12.zoneedit.com. zonetransfer.me AXFR
; (1 server found)
;; global options: +cmd
zonetransfer.me. 7200 IN SOA ns16.zoneedit.com. soacontact.zoneedit.com. 2012272996 2400 360 1209600 300
zonetransfer.me. 7200 IN NS ns16.zoneedit.com.
zonetransfer.me. 7200 IN NS ns12.zoneedit.com.
zonetransfer.me. 7200 IN A 217.147.180.162
zonetransfer.me. 7200 IN MX 0 ASPMX.L.GOOGLE.COM.
zonetransfer.me. 7200 IN MX 10 ALT1.ASPMX.L.GOOGLE.COM.
zonetransfer.me. 7200 IN MX 10 ALT2.ASPMX.L.GOOGLE.COM.
zonetransfer.me. 7200 IN MX 20 ASPMX2.GOOGLEMAIL.COM.
zonetransfer.me. 7200 IN MX 20 ASPMX3.GOOGLEMAIL.COM.
zonetransfer.me. 7200 IN MX 20 ASPMX4.GOOGLEMAIL.COM.
zonetransfer.me. 7200 IN MX 20 ASPMX5.GOOGLEMAIL.COM.
zonetransfer.me. 301 IN TXT "Remember to call or email Pippa on +44 123 4567890 or pippa@zonetransfer.me when making DNS changes"
zonetransfer.me. 301 IN TXT "google-site-verification=tyP28J7JAUHA9fw2sHXMgcCC0I6XBmmoVi04VlMewxA"
testing.zonetransfer.me. 301 IN CNAME www.zonetransfer.me.
164.180.147.217.in-addr.arpa.zonetransfer.me. 7200 IN PTR www.zonetransfer.me.
ipv6actnow.org.zonetransfer.me. 7200 IN AAAA 2001:67c:2e8:11::c100:1332
asfdbauthdns.zonetransfer.me. 7900 IN AFSDB 1 asfdbbox.zonetransfer.me.
office.zonetransfer.me. 7200 IN A 4.23.39.254
owa.zonetransfer.me. 7200 IN A 207.46.197.32
info.zonetransfer.me. 7200 IN TXT "ZoneTransfer.me service provided by Robin Wood - robin@digininja.org. See www.digininja.org/projects/zonetransferme.php for more information."
asfdbbox.zonetransfer.me. 7200 IN A 127.0.0.1
canberra_office.zonetransfer.me. 7200 IN A 202.14.81.230
asfdbvolume.zonetransfer.me. 7800 IN AFSDB 1 asfdbbox.zonetransfer.me.
email.zonetransfer.me. 2222 IN NAPTR 1 1 "" "E2U+email" "" email.zoneedit.com.zonetransfer.me.
dzc.zonetransfer.me. 7200 IN TXT "AbCdEfG"
rp.zonetransfer.me. 321 IN RP robin.zonetransfer.me.zonetransfer.me. robinwood.zonetransfer.me.
dr.zonetransfer.me. 300 IN LOC 53 20 56.558 N 1 38 33.526 W 0.00m 1m 10000m 10m
sip.zonetransfer.me. 3333 IN NAPTR 2 3 "au" "E2U+sip" "!^.*$!sip:customer-service@zonetransfer.me!" .
alltcpportsopen.firewall.test.zonetransfer.me. 301 IN A 127.0.0.1
www.zonetransfer.me. 7200 IN A 217.147.180.162
staging.zonetransfer.me. 7200 IN CNAME www.sydneyoperahouse.com.
deadbeef.zonetransfer.me. 7201 IN AAAA dead:beaf::
robinwood.zonetransfer.me. 302 IN TXT "Robin Wood"
vpn.zonetransfer.me. 4000 IN A 174.36.59.154
_sip._tcp.zonetransfer.me. 14000 IN SRV 0 0 5060 www.zonetransfer.me.
dc_office.zonetransfer.me. 7200 IN A 143.228.181.132
zonetransfer.me. 7200 IN SOA ns16.zoneedit.com. soacontact.zoneedit.com. 2012272996 2400 360 1209600 300
;; Query time: 61 msec
;; SERVER: 209.62.64.46#53(209.62.64.46)
;; WHEN: Wed Sep  5 17:12:42 2012
;; XFR size: 37 records (messages 37, bytes 2673)

I had previously used this service to update Nmap's dns-zone-transfer NSE script, so I thought similar updates would be a simple place to start with Metasploit development. Unfortunately (or fortunately!) I ran into a road block: Zone transfers were broken in Metasploit!

The module in question was auxiliary/gather/enum_dns, which has lots of other good DNS enumeration functions besides AXFR. The underlying problem, though was a problem with the Net::DNS library that Metasploit uses. First, a little about how AXFR transactions work:

DNS usually works over UDP, fitting an entire response into a single packet. For zone transfers, though, responses can be much larger. Since zone transfers are used for synchronizing DNS servers, ensuring that no data is lost is critical. For this reason, AXFR transactions are conducted over TCP.

Most DNS transactions involve a single request with a Questions section being answered by a single response with an Answers section (among other sections). AXFR is different; since it has to transfer an entire zone, the server responds with a series of DNS responses, each of which contains some number of Answers. The responses begin with the Start Of Authority (SOA) record for the zone, and end with the same record.

Now we come to the broken part. Net::DNS (and Metasploit by extension) was smart enough to switch to TCP when an AXFR request was passed, but it only read the first response. Modifying the method to loop until 2 SOA messages had been seen was a fun exercise in Ruby that I may write about another time. In the meantime, you could check out the commit diff. Here's how it looks now:

msf > use auxiliary/gather/enum_dns
msf  auxiliary(enum_dns) > show options

Module options (auxiliary/gather/enum_dns):

   Name         Current Setting     Required  Description
   ----         ---------------     --------  -----------
   DOMAIN                           yes       The target domain name
   ENUM_AXFR    true                yes       Initiate a zone transfer against each NS record
   ENUM_BRT     false               yes       Brute force subdomains and hostnames via the supplied wordlist
   ENUM_IP6     false               yes       Brute force hosts with IPv6 AAAA records
   ENUM_RVL     false               yes       Reverse lookup a range of IP addresses
   ENUM_SRV     true                yes       Enumerate the most common SRV records
   ENUM_STD     true                yes       Enumerate standard record types (A,MX,NS,TXT and SOA)
   ENUM_TLD     false               yes       Perform a TLD expansion by replacing the TLD with the IANA TLD list
   IPRANGE                          no        The target address range or CIDR identifier
   NS                               no        Specify the nameserver to use for queries (default is system DNS)
   STOP_WLDCRD  false               yes       Stops bruteforce enumeration if wildcard resolution is detected
   WORDLIST     /redacted/file.txt  no        Wordlist for domain name bruteforcing

msf  auxiliary(enum_dns) > set ENUM_SRV false
ENUM_SRV => false
msf  auxiliary(enum_dns) > set ENUM_STD false
ENUM_STD => false
msf  auxiliary(enum_dns) > set DOMAIN zonetransfer.me
DOMAIN => zonetransfer.me  
msf  auxiliary(enum_dns) > run

[*] Setting DNS Server to zonetransfer.me NS: 69.64.68.41
[*] Performing zone transfer against all nameservers in zonetransfer.me
[*] Testing nameserver: ns16.zoneedit.com.
AXFR query, switching to TCP
Error parsing axfr response: uninitialized constant Net::DNS::RR::AFSDB
Error parsing axfr response: uninitialized constant Net::DNS::RR::AFSDB
Error parsing axfr response: uninitialized constant Net::DNS::RR::NAPTR
Error parsing axfr response: uninitialized constant Net::DNS::RR::RP
Error parsing axfr response: uninitialized constant Net::DNS::RR::LOC
Error parsing axfr response: uninitialized constant Net::DNS::RR::NAPTR
[*] Zone transfer successful
[*] Name: ns16.zoneedit.com. Record: SOA
[*] Name: ns16.zoneedit.com. Record: NS
[*] Name: ns12.zoneedit.com. Record: NS
[*] Name: zonetransfer.me. IP address: 217.147.180.162 Record: A
[*] Name: ASPMX.L.GOOGLE.COM. Preference: 0 Record: MX
[*] Name: ALT1.ASPMX.L.GOOGLE.COM. Preference: 10 Record: MX
[*] Name: ALT2.ASPMX.L.GOOGLE.COM. Preference: 10 Record: MX
[*] Name: ASPMX2.GOOGLEMAIL.COM. Preference: 20 Record: MX
[*] Name: ASPMX3.GOOGLEMAIL.COM. Preference: 20 Record: MX
[*] Name: ASPMX4.GOOGLEMAIL.COM. Preference: 20 Record: MX
[*] Name: ASPMX5.GOOGLEMAIL.COM. Preference: 20 Record: MX
[*] Text: zonetransfer.me.        301     IN      TXT
[*] Text: zonetransfer.me.        301     IN      TXT
[*] Name: www.zonetransfer.me. Record: CNAME
[*] IPv6 Address: 2001:67c:2e8:11::c100:1332 Record: AAAA
[*] Name: office.zonetransfer.me. IP address: 4.23.39.254 Record: A
[*] Name: owa.zonetransfer.me. IP address: 207.46.197.32 Record: A
[*] Text: info.zonetransfer.me.   7200    IN      TXT
[*] Name: asfdbbox.zonetransfer.me. IP address: 127.0.0.1 Record: A
[*] Name: canberra_office.zonetransfer.me. IP address: 202.14.81.230 Record: A
[*] Text: dzc.zonetransfer.me.    7200    IN      TXT
[*] Name: alltcpportsopen.firewall.test.zonetransfer.me. IP address: 127.0.0.1 Record: A
[*] Name: www.zonetransfer.me. IP address: 217.147.180.162 Record: A
[*] Name: www.sydneyoperahouse.com. Record: CNAME
[*] IPv6 Address: dead:beaf:: Record: AAAA
[*] Text: robinwood.zonetransfer.me.   302   IN   TXT
[*] Name: vpn.zonetransfer.me. IP address: 174.36.59.154 Record: A
[*] Host: www.zonetransfer.me. Port: 5060 Priority: 0 Record: SRV
[*] Name: dc_office.zonetransfer.me. IP address: 143.228.181.132 Record: A
[*] Testing nameserver: ns12.zoneedit.com.
AXFR query, switching to TCP
Error parsing axfr response: uninitialized constant Net::DNS::RR::AFSDB
Error parsing axfr response: uninitialized constant Net::DNS::RR::AFSDB
Error parsing axfr response: uninitialized constant Net::DNS::RR::NAPTR
Error parsing axfr response: uninitialized constant Net::DNS::RR::RP
Error parsing axfr response: uninitialized constant Net::DNS::RR::LOC
Error parsing axfr response: uninitialized constant Net::DNS::RR::NAPTR
[*] Zone transfer successful
[*] Name: ns16.zoneedit.com. Record: SOA
[*] Name: ns16.zoneedit.com. Record: NS
[*] Name: ns12.zoneedit.com. Record: NS
[*] Name: zonetransfer.me. IP address: 217.147.180.162 Record: A
[*] Name: ASPMX.L.GOOGLE.COM. Preference: 0 Record: MX
[*] Name: ALT1.ASPMX.L.GOOGLE.COM. Preference: 10 Record: MX
[*] Name: ALT2.ASPMX.L.GOOGLE.COM. Preference: 10 Record: MX
[*] Name: ASPMX2.GOOGLEMAIL.COM. Preference: 20 Record: MX
[*] Name: ASPMX3.GOOGLEMAIL.COM. Preference: 20 Record: MX
[*] Name: ASPMX4.GOOGLEMAIL.COM. Preference: 20 Record: MX
[*] Name: ASPMX5.GOOGLEMAIL.COM. Preference: 20 Record: MX
[*] Text: zonetransfer.me.        301     IN      TXT
[*] Text: zonetransfer.me.        301     IN      TXT
[*] Name: www.zonetransfer.me. Record: CNAME
[*] IPv6 Address: 2001:67c:2e8:11::c100:1332 Record: AAAA
[*] Name: office.zonetransfer.me. IP address: 4.23.39.254 Record: A
[*] Name: owa.zonetransfer.me. IP address: 207.46.197.32 Record: A
[*] Text: info.zonetransfer.me.   7200    IN      TXT
[*] Name: asfdbbox.zonetransfer.me. IP address: 127.0.0.1 Record: A
[*] Name: canberra_office.zonetransfer.me. IP address: 202.14.81.230 Record: A
[*] Text: dzc.zonetransfer.me.    7200    IN      TXT
[*] Name: alltcpportsopen.firewall.test.zonetransfer.me. IP address: 127.0.0.1 Record: A
[*] Name: www.zonetransfer.me. IP address: 217.147.180.162 Record: A
[*] Name: www.sydneyoperahouse.com. Record: CNAME
[*] IPv6 Address: dead:beaf:: Record: AAAA
[*] Text: robinwood.zonetransfer.me.   302   IN   TXT
[*] Name: vpn.zonetransfer.me. IP address: 174.36.59.154 Record: A
[*] Host: www.zonetransfer.me. Port: 5060 Priority: 0 Record: SRV
[*] Name: dc_office.zonetransfer.me. IP address: 143.228.181.132 Record: A
[*] Auxiliary module execution completed
msf  auxiliary(enum_dns) >

See all the parsing errors? That's what I intended to fix when I started. Well, no time like the present!