Skip to content

Commit db75cd3

Browse files
committed
Fixes #5 - Check for fake/wildcard DNS records in checkresolvers
1 parent 60c2a65 commit db75cd3

File tree

1 file changed

+60
-13
lines changed

1 file changed

+60
-13
lines changed

dnsbrute/checkresolvers.py

+60-13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from __future__ import print_function
22
import sys
3+
import os
4+
import base64
35
import argparse
46
import logging
57
import random
@@ -9,7 +11,7 @@
911
import progressbar
1012
import gevent
1113
import gevent.pool
12-
from dns.resolver import Resolver, Answer
14+
from dns.resolver import Resolver, Answer, NXDOMAIN, NoNameservers
1315
from dns.exception import DNSException
1416

1517

@@ -46,6 +48,7 @@ def time_resolve(args, server, name, rectype, tries=3):
4648
resolver.lifetime = args.timeout
4749
resolver.nameservers = [server]
4850
results = []
51+
4952
while tries > 0:
5053
start = time.time()
5154
try:
@@ -62,28 +65,72 @@ def time_resolve(args, server, name, rectype, tries=3):
6265
return server, check_results(results), results
6366

6467

65-
def download_resolvers():
66-
LOG.info("Downloading nameservers from public-dns.info")
67-
resp = requests.get('http://public-dns.info/nameservers.txt')
68-
resp.raise_for_status()
69-
return map(str.strip, filter(None, str(resp.text).split("\n")))
70-
71-
72-
def load_resolvers(handle):
73-
return map(str.strip, filter(None, handle.read().split("\n")))
68+
def check_for_wildcards(args, server, name, rectype, tries=4):
69+
"""
70+
Verify that the DNS server doesn't return wildcard results for domains
71+
which don't exist, it should correctly return NXDOMAIN.
72+
"""
73+
resolver = Resolver()
74+
resolver.timeout = args.timeout
75+
resolver.lifetime = args.timeout
76+
resolver.nameservers = [server]
77+
nx_names = [base64.b32encode(
78+
os.urandom(
79+
random.randint(8, 10))
80+
).strip('=').lower() + name
81+
for _ in range(0, tries)]
82+
correct_result_count = 0
83+
for check_nx_name in nx_names:
84+
try:
85+
result = resolver.query(check_nx_name, rectype)
86+
return False # Any valid response = immediate fail!
87+
except (NXDOMAIN, NoNameservers):
88+
correct_result_count += 1
89+
except DNSException:
90+
continue
91+
return correct_result_count > (tries / 2.0)
7492

7593

7694
def check_resolver(args, resolver):
95+
"""
96+
Ensure that the resolver passes all integrity checks, and output to save
97+
list if it does. The checks are:
98+
99+
* Consistently and quickly resolves valid domains
100+
* Doesn't return results for invalid domains
101+
"""
102+
bad_reason = ""
77103
server, (avgtime, isgood), _ = time_resolve(args, resolver, "example.com", "A")
104+
if not isgood:
105+
bad_reason = "TIMEOUT"
106+
else:
107+
for rectype in ["A", "AAAA", "MX", "SOA"]:
108+
if not check_for_wildcards(args, resolver, "example.com", rectype):
109+
bad_reason = "WILDCARD-" + rectype
110+
isgood = False
111+
break
112+
78113
if args.output and isgood:
79114
args.output.write(server + "\n")
80115
args.output.flush()
116+
81117
if not args.quiet:
82118
color = bcolors.OKGREEN if isgood else bcolors.FAIL
83-
print("%s%s (%.2fs)%s" % (color, server, avgtime, bcolors.ENDC))
119+
print("%s%s (%.2fs) %s%s" % (color, server, avgtime, bad_reason, bcolors.ENDC))
84120
sys.stdout.flush()
85121

86122

123+
def download_resolvers():
124+
LOG.info("Downloading nameservers from public-dns.info")
125+
resp = requests.get('http://public-dns.info/nameservers.txt')
126+
resp.raise_for_status()
127+
return map(str.strip, filter(None, str(resp.text).split("\n")))
128+
129+
130+
def load_resolvers(handle):
131+
return map(str.strip, filter(None, handle.read().split("\n")))
132+
133+
87134
def run(args):
88135
if args.download:
89136
resolvers = download_resolvers()
@@ -112,8 +159,8 @@ def main():
112159
help='Download new list of resolvers from public-dns.info')
113160
parser.add_argument('-T', '--timeout', default=0.5, type=float, metavar='SECS',
114161
help="Timeout for DNS request in seconds, default: 0.5")
115-
parser.add_argument('-C', '--concurrency', default=20, type=int,
116-
help="Concurrent DNS requests, default: 20", metavar='N')
162+
parser.add_argument('-C', '--concurrency', default=10, type=int,
163+
help="Concurrent DNS requests, default: 10", metavar='N')
117164
parser.add_argument('-q', '--quiet', action='store_true',
118165
help="Don't print results to console")
119166
parser.add_argument('-v', '--verbose', action='store_const',

0 commit comments

Comments
 (0)