├── requirements.txt ├── README.md ├── setup.sh ├── LICENSE └── FindFrontableDomains.py /requirements.txt: -------------------------------------------------------------------------------- 1 | argparse 2 | dnspython 3 | requests 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FindFrontableDomains 2 | Search for potential frontable domains 3 | 4 | Based on information found here: https://www.bamsoftware.com/papers/fronting/ 5 | 6 | Getting Started: 7 | 8 | Run setup.sh 9 | 10 | Example Command: ./FindFrontableDomains.py --alexa 10000 --threads 20 11 | 12 | Example Command: ./FindFrontableDomains.py --domain example.com --threads 20 13 | -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [[ $EUID -ne 0 ]]; then 4 | echo "This script must be run as root" 1>&2 5 | exit 1 6 | fi 7 | pip install -r requirements.txt 8 | pip install -e git://github.com/davedash/Alexa-Top-Sites.git#egg=alexa-top-sites 9 | git clone https://github.com/rvrsh3ll/Sublist3r.git 10 | touch Sublist3r/__init__.py 11 | git clone https://github.com/rthalley/dnspython 12 | cd dnspython/ 13 | python setup.py install 14 | exit 1 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2017, Steve Borosh 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /FindFrontableDomains.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # Run setup.sh first! 3 | 4 | import alexa 5 | import dns.resolver 6 | from dns.resolver import Resolver 7 | import threading 8 | import Queue 9 | import argparse 10 | import sys 11 | from Sublist3r import sublist3r 12 | 13 | class ThreadLookup(threading.Thread): 14 | def __init__(self, queue): 15 | threading.Thread.__init__(self) 16 | self.queue = queue 17 | def run(self): 18 | 19 | while True: 20 | if self.queue.empty(): 21 | break 22 | #grabs host from queue 23 | hostname = self.queue.get() 24 | try: 25 | 26 | dns.resolver.default_resolver = dns.resolver.Resolver(configure=False) 27 | dns.resolver.default_resolver.nameservers = ['209.244.0.3', '209.244.0.4','64.6.64.6','64.6.65.6', '8.8.8.8', '8.8.4.4','84.200.69.80', '84.200.70.40', '8.26.56.26', '8.20.247.20', '208.67.222.222', '208.67.220.220','199.85.126.10', '199.85.127.10', '81.218.119.11', '209.88.198.133', '195.46.39.39', '195.46.39.40', '96.90.175.167', '193.183.98.154','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', '89.233.43.71', '74.82.42.42', '109.69.8.51'] 28 | query = dns.resolver.query(hostname, 'a') 29 | # Iterate through response and check for potential CNAMES 30 | for i in query.response.answer: 31 | for j in i.items: 32 | target = j.to_text() 33 | if 'cloudfront' in target: 34 | print 'CloundFront Frontable domain found: ' + str(hostname) + " " + str(target) 35 | elif 'appspot.com' in target: 36 | print 'Google Frontable domain found: ' + str(hostname) + " " + str(target) 37 | elif 'msecnd.net' in target: 38 | print 'Azure Frontable domain found: ' + str(hostname) + " " + str(target) 39 | elif 'aspnetcdn.com' in target: 40 | print 'Azure Frontable domain found: ' + str(hostname) + " " + str(target) 41 | elif 'azureedge.net' in target: 42 | print 'Azure Frontable domain found: ' + str(hostname) + " " + str(target) 43 | elif 'a248.e.akamai.net' in target: 44 | print 'Akamai frontable domain found: ' + str(hostname) + " " + str(target) 45 | elif 'secure.footprint.net' in target: 46 | print 'Level 3 URL frontable domain found: ' + str(hostname) + " " + str(target) 47 | elif 'cloudflare' in target: 48 | print 'Cloudflare frontable domain found: ' + str(hostname) + " " + str(target) 49 | elif 'unbouncepages.com' in target: 50 | print 'Unbounce frontable domain found: ' + str(hostname) + " " + str(target) 51 | except Exception as e: 52 | pass 53 | self.queue.task_done() 54 | 55 | def main(): 56 | parser = argparse.ArgumentParser() 57 | parser.add_argument('-f', '--file', type=str, required=False) 58 | parser.add_argument('-t', '--threads', type=int, required=False, default=10) 59 | parser.add_argument('-a', '--alexa', type=int, required=False) 60 | parser.add_argument('-d', '--domain', type=str, required=False) 61 | args = parser.parse_args() 62 | threads = args.threads 63 | top = args.alexa 64 | file = args.file 65 | domain = args.domain 66 | queue = Queue.Queue() 67 | if file: 68 | with open(file, 'r') as f: 69 | for d in f: 70 | d = d.rstrip() 71 | if d: 72 | queue.put(d) 73 | elif domain: 74 | subdomains = [] 75 | subdomains = sublist3r.main(domain, threads, savefile=None, ports=None, silent=False, verbose=False, enable_bruteforce=False, engines=None) 76 | for i in subdomains: 77 | print i 78 | queue.put(i) 79 | elif alexa: 80 | results = alexa.top_list(top) 81 | for i in results: 82 | for r in i: 83 | r = str(r) 84 | if not r.isdigit(): 85 | queue.put(r) 86 | else: 87 | print "No Input Detected!" 88 | sys.exit() 89 | print "---------------------------------------------------------" 90 | print "Starting search for frontable domains..." 91 | # spawn a pool of threads and pass them queue instance 92 | for i in range(threads): 93 | t = ThreadLookup(queue) 94 | t.setDaemon(True) 95 | t.start() 96 | 97 | queue.join() 98 | print "" 99 | print "Search complete!" 100 | 101 | if __name__ == "__main__": 102 | main() 103 | --------------------------------------------------------------------------------