#!/usr/bin/env Python2.7 import sys import argparse import random import mechanize import dns.resolver from time import sleep from blessings import Terminal t = Terminal() # Input validation, usage if not len(sys.argv[1:]): print t.cyan(""" _ _ _ __ /_\ _ __ ___ _ __ | (_) _\_ __ _ _ //_\\\| '_ ` _ \| '_ \| | \ \ |'_ \| | | | / _ \ | | | | | |_) | | |\ \ |_) | |_| | \_/ \_/_| |_| |_| .__/|_|_\__/ .__/ \__, | |_| |_| |___/ Welcome to AmpliSpy The purpose of this program is to check a local or remote list of DNS servers for potential suitability with DNS Amplification attacks. The program comes with the option to provide your own custom DNS server list or to fetch one remotely from public-dns.info. Type -h or --help to display all options. Example: amplispy.py -h amplispy.py -l /tmp/dns_list.txt --url target.com """) sys.exit(0) # Handle command line arguments parser = argparse.ArgumentParser(description=" probe for DNS AMP suitable servers.\n") group = parser.add_mutually_exclusive_group() group.add_argument("-l", "--local", help=" select locally saved list of name servers\n") group.add_argument("-r", "--remote", action="store_true", help="fetch remote list of name servers from public-dns.info\n") parser.add_argument("-u", "--url", type=str, help=" provide the URL for a domain to test against\n") args = parser.parse_args() if not args.url: print "\n[" + t.red("!") + "]Critical, the '-u' option is mandatory.\n" sys.exit(1) # Random user-agent selector def select_UA(): UAs = ["'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'", "'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'", "'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'", "'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0'", "'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0'", "'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/602.3.12 (KHTML, like Gecko) Version/10.0.2 Safari/602.3.12'", "'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36'", "'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36'", "'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36'", "'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:50.0) Gecko/20100101 Firefox/50.0'" ] return random.choice(tuple(UAs)) # Fetch list def mech_ops(): br = mechanize.Browser() br.set_handle_robots(False) br.addheaders = [('user-agent', select_UA()), ('accept', 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8')] try: response = br.open("http://public-dns.info//nameservers.txt") except Exception as e: print "\n[" + t.red("!") + "]Critical, could not open public-dns.info" print "[" + t.green("+") + "]The following status code was recieved:" print "\n %s" % (e) sys.exit(1) result = response.read() proc = result.rstrip().split('\n') return proc # If args, read list, else fetch if args.local: RHOSTS = [] print "\n[" + t.green("+") + "]Reading in list from: " + args.local + "\n" try: with open(args.local, "r") as infile: text = infile.read() proc = text.rstrip().split('\n') for line in proc: RHOSTS.append(line) except IOError as e: print "\n[" + t.red("!") + "]Critical. Unable to read list" print "An IO Error was raised with the following error message: " print "\n %s" % (e) else: RHOSTS = mech_ops() known_pubs = {"8.8.8.8","8.8.4.4","209.244.0.3","209.244.0.4", "64.6.64.6","64.6.65.6","84.200.69.80","84.200.70.40","8.26.56.26", "8.20.247.20","208.67.222.222","208.67.220.220","156.154.70.1", "156.154.71.1","199.85.126.10","199.85.127.10","81.218.119.11", "209.88.198.133","195.46.39.39","195.46.39.40","50.116.23.211", "107.170.95.180","208.76.50.50","208.76.51.51", "216.146.35.35", "216.146.36.36","37.235.1.174","37.235.1.177","198.101.242.72", "23.253.163.53","77.88.8.8","77.88.8.1","91.239.100.100", "74.82.42.42","109.69.8.51"} R_checked = [] # Validate def query(address): dnsserver = address resolver = dns.resolver.Resolver() resolver.nameservers = [dnsserver] try: answer = resolver.query(args.url, "A") return True except dns.resolver.NoNameservers: return False except dns.resolver.NoAnswer: return False except dns.resolver.NXDOMAIN: return False except dns.exception.Timeout: return False # Sort def start(known_pubs): pub = "" delay = raw_input("[" + t.magenta("?") + "]Set delay? (default is 0): ") if delay == "" or delay == "0": delay = 0 else: delay = int(delay) print "\n[" + t.green("+") + "]Potentially suitable for DNS Amplification:\n" for address in RHOSTS: if address in known_pubs: pub = True else: pub = False if not pub: valid = query(address) if valid: print "[" + t.magenta("~") + "] %s " % address R_checked.append(address) else: continue elif pub: continue sleep(delay) start(known_pubs) with open("amplispy.log", "w") as outfile: for item in R_checked: outfile.write("%s\n" % item) print "\n[" + t.green("+") + "]Done. Results saved to %s in the current directory" % outfile