├── cheatsheet.pdf ├── requirements.txt ├── crtsh_enum_psql.sh ├── Pipfile ├── crtsh_enum_web.py ├── README.md ├── virustotal_subdomain_enum.py ├── san_subdomain_enum.py ├── censys_subdomain_enum.py ├── crtsh_enum_psql.py ├── cloudflare_subdomain_enum.py └── Pipfile.lock /cheatsheet.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appsecco/the-art-of-subdomain-enumeration/HEAD/cheatsheet.pdf -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | requests==2.18.4 2 | asn1crypto==0.24.0 3 | cffi==1.11.2 4 | cryptography==2.1.4 5 | enum34==1.1.6 6 | idna==2.6 7 | ipaddress==1.0.19 8 | pycparser==2.18 9 | pyOpenSSL==17.5.0 10 | six==1.11.0 11 | censys==0.0.8 12 | psycopg2 13 | beautifulsoup4 14 | -------------------------------------------------------------------------------- /crtsh_enum_psql.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Script by Hanno Bock - https://github.com/hannob/tlshelpers/blob/master/getsubdomain 4 | 5 | query="SELECT ci.NAME_VALUE NAME_VALUE FROM certificate_identity ci WHERE ci.NAME_TYPE = 'dNSName' AND reverse(lower(ci.NAME_VALUE)) LIKE reverse(lower('%.$1'));" 6 | 7 | echo $query | \ 8 | psql -t -h crt.sh -p 5432 -U guest certwatch | \ 9 | sed -e 's:^ *::g' -e 's:^*\.::g' -e '/^$/d' | \ 10 | sort -u | sed -e 's:*.::g' 11 | -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | url = "https://pypi.org/simple" 3 | verify_ssl = true 4 | name = "pypi" 5 | 6 | [dev-packages] 7 | 8 | [packages] 9 | requests = "==2.18.4" 10 | "asn1crypto" = "==0.24.0" 11 | cffi = "==1.11.2" 12 | cryptography = "==2.1.4" 13 | "enum34" = "==1.1.6" 14 | idna = "==2.6" 15 | ipaddress = "==1.0.19" 16 | pycparser = "==2.18" 17 | six = "==1.11.0" 18 | censys = "==0.0.8" 19 | "psycopg2" = "==2.7.3.2" 20 | "beautifulsoup4" = "*" 21 | pyOpenSSL = "==17.5.0" 22 | asyncpg = "*" 23 | 24 | [requires] 25 | python_version = "2.7" 26 | -------------------------------------------------------------------------------- /crtsh_enum_web.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | import urllib.request 5 | import urllib.parse 6 | import re 7 | 8 | 9 | if len(sys.argv) == 1: 10 | print("Usage: " + sys.argv[0] + " [domain] ...") 11 | sys.exit(1) 12 | 13 | for i, arg in enumerate(sys.argv, 1): 14 | domains = set() 15 | with urllib.request.urlopen('https://crt.sh/?q=' + urllib.parse.quote('%.' + arg)) as f: 16 | code = f.read().decode('utf-8') 17 | for cert, domain in re.findall('(?:\s|\S)*?href="\?id=([0-9]+?)"(?:\s|\S)*?([*_a-zA-Z0-9.-]+?\.' + re.escape(arg) + ')(?:\s|\S)*?', code, re.IGNORECASE): 18 | domain = domain.split('@')[-1] 19 | if not domain in domains: 20 | domains.add(domain) 21 | print(domain) 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## The art of subdomain enumeration 2 | 3 | - This repository contains all the supplement material for the book "The art of subdomain enumeration" 4 | - The book is available here: https://appsecco.com/books/subdomain-enumeration/ 5 | 6 | 1. `censys_subdomain_enum.py` - Extract subdomains for a given domain using Censys.io API 7 | 2. `cheatsheet.pdf` - cheat sheet for the subdomain enumeration techniques 8 | 3. `cloudflare_subdomain_enum.py` - A script to do DNS enumeration using Cloudflare service 9 | 4. `crtsh_enum_psql.py` - Extract subdomains for a given domain using crt.sh postgres interface(Python) 10 | 5. `crtsh_enum_psql.sh` - Extract subdomains for a given domain using crt.sh postgres interface(shell script) 11 | 6. `crtsh_enum_web.py` - Extract subdomains for a given domain using crt.sh by scraping the web page(Python3) 12 | 7. `san_subdomain_enum.py` - Extract domains/subdomains listed in Subject Alternate Name(SAN) of SSL/TLS cert for a domain 13 | 8. `virustotal_subdomain_enum.py` - Extract subdomains for a given domain using VirusTotal API 14 | 15 | ### Feedback/Suggestions 16 | 17 | [@0xbharath](https://twitter.com/0xbharath) 18 | -------------------------------------------------------------------------------- /virustotal_subdomain_enum.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | 3 | 4 | __author__ = "Bharath" 5 | __version__ = "0.1.0" 6 | __description__ = "A script to extract sub-domains that virus total \ 7 | has found for a given domain name" 8 | import sys 9 | 10 | try: 11 | from requests import get, exceptions 12 | except ImportError: 13 | raise ImportError('requests library missing. pip install requests') 14 | sys.exit(1) 15 | 16 | def get_domain(): 17 | if len(sys.argv) <= 2: 18 | print("\n\033[33mUsage: python virustotal_enum.py \033[1;m\n") 19 | sys.exit(1) 20 | else: 21 | return sys.argv[1], int(sys.argv[2]) 22 | 23 | def check_virustotal(domain_name, limit): 24 | url = "https://www.virustotal.com/ui/domains/{0}/subdomains?limit={1}".format(domain_name, limit) 25 | print("URL being queried: {}".format(url)) 26 | try: 27 | req = get(url) 28 | except exceptions.RequestException as e: # This is the correct syntax 29 | print(e) 30 | sys.exit(1) 31 | response = get(url) 32 | return response.json() 33 | 34 | def print_results(search_results): 35 | for index, item in enumerate(search_results['data']): 36 | print(item['id']) 37 | 38 | if __name__ == '__main__': 39 | domain_name, limit = get_domain() 40 | if limit > 40: 41 | print("Limit cannot be over 40.") 42 | sys.exit(1) 43 | search_results = check_virustotal(domain_name, limit) 44 | print_results(search_results) 45 | -------------------------------------------------------------------------------- /san_subdomain_enum.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | 3 | 4 | __author__ = "Bharath" 5 | __version__ = "0.1.0" 6 | __description__ = "A script to extract sub-domains from Subject Alternate Name(SAN) in X.509 certs" 7 | 8 | import sys 9 | import re 10 | import ssl 11 | 12 | try: 13 | import OpenSSL as openssl 14 | except ImportError: 15 | raise ImportError('pyopenssl library missing. pip install pyopenssl') 16 | sys.exit(1) 17 | 18 | def get_domain_name(): 19 | if len(sys.argv) <= 1: 20 | print("\n\033[33mUsage: python san_enum.py \033[1;m\n") 21 | sys.exit(1) 22 | else: 23 | return sys.argv[1] 24 | 25 | def get_cert(domain_name): 26 | cert = ssl.get_server_certificate((domain_name, 443)) 27 | return cert 28 | 29 | def get_san(cert): 30 | x509 = openssl.crypto.load_certificate(openssl.crypto.FILETYPE_PEM, cert) 31 | domain_list = [] 32 | for i in range(0, x509.get_extension_count()): 33 | ext = x509.get_extension(i) 34 | if "subjectAltName" in str(ext.get_short_name()): 35 | content = ext.__str__() 36 | for d in content.split(","): 37 | domain_list.append(d.strip()[4:]) 38 | return domain_list 39 | 40 | def print_domains(domain_list): 41 | if len(domain_list) > 1: 42 | for domain in domain_list: 43 | print(domain) 44 | else: 45 | print("[!] No domains found using Subject Alternate Name(SAN)") 46 | 47 | if __name__ == '__main__': 48 | domain_name = get_domain_name() 49 | cert = get_cert(domain_name) 50 | domain_list = get_san(cert) 51 | print_domains(domain_list) 52 | -------------------------------------------------------------------------------- /censys_subdomain_enum.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # A script to extract domain names from related SSL/TLS certificates using Censys 4 | # You'll need Censys API ID and API Secret to be able to extract SSL/TLS certificates 5 | # Needs censys module to run. pip install censys. 6 | 7 | from __future__ import print_function 8 | 9 | import logging 10 | 11 | logging.basicConfig( 12 | level=logging.INFO, 13 | format="%(message)s" 14 | ) 15 | 16 | __author__ = "Bharath(github.com/0xbharath)" 17 | __version__ = "0.1" 18 | __purpose__ = "Extract subdomains for a domain from censys certificate dataset" 19 | 20 | CENSYS_API_ID = "" 21 | CENSYS_API_SECRET = "" 22 | 23 | import argparse 24 | import re 25 | import sys 26 | 27 | try: 28 | import censys.certificates 29 | import censys.ipv4 30 | except ImportError: 31 | logging.info("\033[1;31m[!] Failed to import censys module. Run 'pip install censys'\033[1;m") 32 | sys.exit() 33 | 34 | def get_certificates(): 35 | try: 36 | if not CENSYS_API_ID or not CENSYS_API_SECRET: 37 | logging.info("\033[1;31m[!] API KEY or Secret for Censys not provided.\033[1;m" \ 38 | "\nYou'll have to provide them in the script") 39 | sys.exit() 40 | logging.info("[+] Extracting certificates for {} using Censys".format(domain)) 41 | censys_certificates = censys.certificates.CensysCertificates(CENSYS_API_ID, CENSYS_API_SECRET) 42 | return censys_certificates 43 | except censys.base.CensysUnauthorizedException: 44 | logging.info('[!] Your Censys credentials look invalid.\n') 45 | exit(1) 46 | except censys.base.CensysRateLimitExceededException: 47 | logging.info('[!] Looks like you exceeded your Censys account limits rate. Exiting\n') 48 | exit(1) 49 | 50 | def get_subdomains(domain, certificates): 51 | logging.info("[+] Extracting sub-domains for {} from certificates".format(domain)) 52 | subdomains = [] 53 | certificate_query = 'parsed.names: {}'.format(domain) 54 | certificates_search_results = certificates.search(certificate_query, fields=['parsed.names']) 55 | for search_result in certificates_search_results: 56 | subdomains.extend(search_result['parsed.names']) 57 | return set(subdomains) 58 | 59 | def print_subdomains(subdomains, domain): 60 | unique_subdomains = [] 61 | if len(subdomains) is 0: 62 | logging.info('[!] Did not find any subdomains') 63 | return 64 | for subdomain in subdomains: 65 | if '*' not in subdomain and subdomain.endswith(domain): 66 | unique_subdomains.append(subdomain) 67 | logging.info("\033[1;32m[+] Total unique subdomains found: {}\033[1;m".format(len(unique_subdomains))) 68 | for subdomain in sorted(unique_subdomains): 69 | print(subdomain) 70 | 71 | def get_domain(): 72 | if len(sys.argv) < 2: 73 | print("\n[!] Usage: python subdomain_enum_censys.py \n") 74 | sys.exit() 75 | else: 76 | domain = sys.argv[1] 77 | return domain 78 | 79 | if __name__ == '__main__': 80 | domain = get_domain() 81 | certificates = get_certificates() 82 | subdomains = get_subdomains(domain, certificates) 83 | print_subdomains(subdomains, domain) 84 | -------------------------------------------------------------------------------- /crtsh_enum_psql.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | 3 | __author__ = 'Bharath' 4 | __version__ = "0.1.0" 5 | 6 | try: 7 | import psycopg2 8 | except ImportError: 9 | raise ImportError('\n\033[33mpsycopg2 library missing. pip install psycopg2\033[1;m\n') 10 | sys.exit(1) 11 | 12 | try: 13 | import click 14 | except ImportError: 15 | raise ImportError('\n\033[33mclick library missing. pip install click\033[1;m\n') 16 | sys.exit(1) 17 | import re 18 | import sys 19 | import json 20 | import logging 21 | from os.path import abspath 22 | 23 | logging.basicConfig( 24 | level=logging.INFO, 25 | format="%(message)s" 26 | ) 27 | 28 | DB_HOST = 'crt.sh' 29 | DB_NAME = 'certwatch' 30 | DB_USER = 'guest' 31 | DB_PASSWORD = '' 32 | 33 | def connect_to_db(domain_name): 34 | try: 35 | conn = psycopg2.connect("dbname={0} user={1} host={2}".format(DB_NAME, DB_USER, DB_HOST)) 36 | conn.autocommit = True 37 | cursor = conn.cursor() 38 | cursor.execute("SELECT ci.NAME_VALUE NAME_VALUE FROM certificate_identity ci WHERE ci.NAME_TYPE = 'dNSName' AND reverse(lower(ci.NAME_VALUE)) LIKE reverse(lower('%{}'));".format(domain_name)) 39 | except: 40 | logging.info("\n\033[1;31m[!] Unable to connect to the database\n\033[1;m") 41 | return cursor 42 | 43 | def get_unique_domains(cursor, domain_name): 44 | unique_domains = [] 45 | for result in cursor.fetchall(): 46 | matches=re.findall(r"\'(.+?)\'",str(result)) 47 | for subdomain in matches: 48 | if subdomain not in unique_domains: 49 | if ".{}".format(domain_name) in subdomain: 50 | unique_domains.append(subdomain) 51 | return unique_domains 52 | 53 | def do_dns_resolution(unique_domains): 54 | try: 55 | import dns.resolver 56 | except ImportError: 57 | raise ImportError('\n\033[33mdnspython library missing. pip install dnspython\033[1;m\n') 58 | sys.exit(1) 59 | dns_resolution_results = {} 60 | for domain in set(unique_domains): 61 | domain = domain.replace('*.','') 62 | dns_resolution_results[domain] = {} 63 | try: 64 | for qtype in ['A','CNAME']: 65 | dns_answer = dns.resolver.query(domain,qtype, raise_on_no_answer=False) 66 | if dns_answer.rrset is None: 67 | pass 68 | elif dns_answer.rdtype == 1: 69 | a_records = [str(i) for i in dns_answer.rrset] 70 | dns_resolution_results[domain]["A"] = a_records 71 | elif dns_answer.rdtype == 5: 72 | cname_records = [str(i) for i in dns_answer.rrset] 73 | dns_resolution_results[domain]["CNAME"] = cname_records 74 | else: 75 | dns_resolution_results[domain]["A"] = "bla" 76 | dns_resolution_results[domain]["CNAME"] = "bla bla" 77 | except dns.resolver.NXDOMAIN: 78 | dns_resolution_results[domain]["A"] = "No such domain" 79 | pass 80 | except dns.resolver.Timeout: 81 | dns_resolution_results[domain]["A"] = "Timed out while resolving" 82 | dns_resolution_results[domain]["CNAME"] = "Timed out error while resolving" 83 | pass 84 | except dns.exception.DNSException: 85 | dns_resolution_results[domain]["A"] = "Unknown error while resolving" 86 | dns_resolution_results[domain]["CNAME"] = "Unknown error while resolving" 87 | pass 88 | return dns_resolution_results 89 | 90 | def print_json_results(domain,dns_resolution_results): 91 | print(json.dumps(dns_resolution_results)) 92 | results_file = "{}_results.json".format(domain) 93 | with open(results_file, 'w+') as results_file: 94 | json.dump(dns_resolution_results, results_file, default=str) 95 | file_path = abspath(results_file.name) 96 | logging.info("\033[1;32m[+] Results written to JSON file : {}\033[1;m".format(file_path)) 97 | 98 | @click.command() 99 | @click.argument('domain') 100 | @click.option('--resolve/--no-resolve','-r', default=False, 101 | help='Enable/Disable DNS resolution') 102 | @click.option('--output','-o', default='json', 103 | help='Output in JSON format') 104 | def main(domain, resolve, output): 105 | domain_name = domain 106 | cursor = connect_to_db(domain_name) 107 | unique_domains = get_unique_domains(cursor, domain_name) 108 | if resolve == False: 109 | for domain in unique_domains: 110 | print(domain) 111 | sys.exit() 112 | else: 113 | dns_resolution_results = do_dns_resolution(unique_domains) 114 | print_json_results(domain,dns_resolution_results) 115 | 116 | if __name__ == '__main__': 117 | main() -------------------------------------------------------------------------------- /cloudflare_subdomain_enum.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # Created using Metafidv2 by Matthew Bryant (mandatory) 4 | # Unauthorized use is stricly prohibited, please contact mandatory@gmail.com with questions/comments. 5 | from __future__ import print_function 6 | import requests 7 | import getpass 8 | import json 9 | import time 10 | import csv 11 | import sys 12 | import os 13 | from bs4 import BeautifulSoup 14 | 15 | class cloudflare_enum: 16 | def __init__( self ): 17 | # Master list of headers to be used in each connection 18 | self.global_headers = { 19 | } 20 | self.verbose = True 21 | 22 | self.s = requests.Session() 23 | self.s.headers.update( self.global_headers ) 24 | self.atok = '' 25 | 26 | def log_in( self, username, password ): 27 | parse_dict = {} 28 | 29 | r = self.s.get('https://www.cloudflare.com/', ) 30 | 31 | new_headers = { 32 | 'Referer': 'https://www.cloudflare.com/', 33 | } 34 | self.s.headers.update( dict( new_headers.items() + self.global_headers.items() ) ) 35 | r = self.s.get('https://www.cloudflare.com/a/login', ) 36 | parse_dict[ 'security_token_0' ] = self.find_between_r( r.text, '"security_token":"', '"}};' ) # http://xkcd.com/292/ 37 | 38 | post_data = { 39 | 'email': username, 40 | 'password': password, 41 | 'security_token': parse_dict[ 'security_token_0' ], 42 | } 43 | new_headers = { 44 | 'Referer': 'https://www.cloudflare.com/a/login', 45 | 'Content-Type': 'application/x-www-form-urlencoded', 46 | } 47 | self.s.headers.update( dict( new_headers.items() + self.global_headers.items() ) ) 48 | r = self.s.post('https://www.cloudflare.com/a/login', data=post_data) 49 | self.atok = self.find_between_r( r.text, 'window.bootstrap = {"atok":"', '","locale":"' ) # http://xkcd.com/292/ 50 | 51 | def get_domain_dns( self, domain ): 52 | parse_dict = {} 53 | post_data = { 54 | "betas": [], 55 | "created_on": "2015-08-24T00:27:16.048Z", 56 | "development_mode": False, 57 | "jump_start": True, 58 | "meta": {}, 59 | "modified_on": 'null', 60 | "name": domain, 61 | "owner": {}, 62 | "paused": False, 63 | "status": "initializing", 64 | "type": "full" 65 | } 66 | 67 | new_headers = { 68 | 'Content-Type': 'application/json; charset=UTF-8', 69 | 'X-Requested-With': 'XMLHttpRequest', 70 | 'Referer': 'https://www.cloudflare.com/a/add-site', 71 | 'Pragma': 'no-cache', 72 | 'Cache-Control': 'no-cache', 73 | 'X-ATOK': self.atok, 74 | } 75 | self.s.headers.update( dict( new_headers.items() + self.global_headers.items() ) ) 76 | r = self.s.post('https://www.cloudflare.com/api/v4/zones', data=json.dumps( post_data )) 77 | data = json.loads( r.text ) 78 | success = data['success'] 79 | if not success: 80 | print( r.text ) 81 | return False 82 | 83 | request_id = data['result']['id'] 84 | time.sleep( 60 ) 85 | 86 | get_data = { 87 | 'per_page': '100', 88 | 'direction': 'asc', 89 | 'page': '1', 90 | 'order': 'type', 91 | } 92 | new_headers = { 93 | 'X-Requested-With': 'XMLHttpRequest', 94 | 'Referer': 'https://www.cloudflare.com/a/setup/' + domain + '/step/2', 95 | 'X-ATOK': self.atok, 96 | } 97 | self.s.headers.update( dict( new_headers.items() + self.global_headers.items() ) ) 98 | r = self.s.get('https://www.cloudflare.com/api/v4/zones/' + request_id + '/dns_records', params=get_data) 99 | return_data = json.loads( r.text ) 100 | 101 | new_headers = { 102 | 'X-Requested-With': 'XMLHttpRequest', 103 | 'Referer': 'https://www.cloudflare.com/a/setup/' + domain + '/step/2', 104 | 'X-ATOK': self.atok, 105 | } 106 | self.s.headers.update( dict( new_headers.items() + self.global_headers.items() ) ) 107 | r = self.s.delete('https://www.cloudflare.com/api/v4/zones/' + request_id, ) 108 | 109 | get_data = { 110 | 'status': 'initializing,pending', 111 | 'per_page': '50', 112 | 'page': '1', 113 | } 114 | new_headers = { 115 | 'X-Requested-With': 'XMLHttpRequest', 116 | 'Referer': 'https://www.cloudflare.com/a/add-site', 117 | 'X-ATOK': self.atok, 118 | } 119 | self.s.headers.update( dict( new_headers.items() + self.global_headers.items() ) ) 120 | r = self.s.get('https://www.cloudflare.com/api/v4/zones', params=get_data) 121 | 122 | return return_data['result'] 123 | 124 | def get_spreadsheet( self, domain ): 125 | dns_data = self.get_domain_dns( domain ) 126 | if dns_data: 127 | filename = domain.replace( ".", "_" ) + ".csv" 128 | 129 | with open( filename, 'wb' ) as csvfile: 130 | dns_writer = csv.writer(csvfile, delimiter=',', quotechar='|', quoting=csv.QUOTE_MINIMAL) 131 | dns_writer.writerow( [ "name", "type", "content" ] ) 132 | for record in dns_data: 133 | dns_writer.writerow( [ record["name"], record["type"], record["content"] ] ) 134 | 135 | self.statusmsg( "Spreadsheet created at " + os.getcwd() + "/" + filename ) 136 | 137 | def print_banner( self ): 138 | if self.verbose: 139 | print(""" 140 | 141 | `..--------..` 142 | .-:///::------::///:.` 143 | `-//:-.`````````````.-://:.` ` ` 144 | .://-.```````````````````.-://-` : `- . 145 | `-//:.........................-://. /. -: `:` `` 146 | `://--------:::://////:::--------://-::.::`:- .:. 147 | ``.---..` `///::::::///////////////////:::::::///::::::--:.`.-. 148 | .://::::///::///::///////////////////////////:::///:-----::--:-` ` 149 | `:/:-...--:://////////////////////////////////////////----------.--.` 150 | `:/:..-:://////////////////////////////////////////////-----------.```` 151 | .//-::////////////////////////////////////:::::////////-...--------...` 152 | -/////////////////////////////////////////////::::----:. `.-::::::-..`` 153 | ``.--:////////////////////////////////////////////////::-..```-///::::///:-` 154 | `.:///::::://////////////////////////////////////:::::::::::::::-----......-:/:. 155 | `-//:-----::::://///////////////////////////////:///////////////////:-::::---..-//:` 156 | `:/:---://+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//+++//::--//: 157 | `//:-/+oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo+++oooo+//://. 158 | :///ossssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssosssssso+//: 159 | `//+sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss+/- 160 | `//+ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo+++++/. 161 | `````````````````````````````````````````````````````````````````````````````````````` 162 | Cloudflare DNS Enumeration Tool v1.3 163 | Created by mandatory 164 | Modified by yamakira 165 | """ ) 166 | 167 | def pprint( self, input_dict ): 168 | print( json.dumps(input_dict, sort_keys=True, indent=4, separators=(',', ': ')) ) 169 | 170 | def statusmsg( self, msg ): 171 | if self.verbose: 172 | print( "[ STATUS ] " + msg ) 173 | 174 | def errormsg( self, msg ): 175 | if self.verbose: 176 | print( "[ ERROR ] " + msg ) 177 | 178 | def successmsg( self, msg ): 179 | if self.verbose: 180 | print( "[ SUCCESS ] " + msg ) 181 | 182 | def find_between_r( self, s, first, last ): 183 | try: 184 | start = s.rindex( first ) + len( first ) 185 | end = s.rindex( last, start ) 186 | return s[start:end] 187 | except ValueError: 188 | return "" 189 | 190 | def find_between( s, first, last ): 191 | try: 192 | start = s.index( first ) + len( first ) 193 | end = s.index( last, start ) 194 | return s[start:end] 195 | except ValueError: 196 | return "" 197 | 198 | def get_cookie_from_file( self, cookie_file ): 199 | return_dict = {} 200 | with open( cookie_file ) as tmp: 201 | data = tmp.readlines() 202 | tmp_data = [] 203 | for i, item in enumerate(data): 204 | if " " in data[i]: 205 | pew = data[i].split( " " ) 206 | return_dict[ pew[5] ] = pew[6] 207 | 208 | return return_dict 209 | 210 | def get_creds(self): 211 | username = sys.argv[1] 212 | password = getpass.getpass('Provide your cloudflare password:') 213 | return username,password 214 | 215 | if __name__ == "__main__": 216 | if len( sys.argv ) < 2: 217 | print( "Usage: " + sys.argv[0] + " username@email.com domain.com" ) 218 | else: 219 | cloud = cloudflare_enum() 220 | username,password = cloud.get_creds() 221 | cloud.print_banner() 222 | cloud.log_in(username,password) 223 | cloud.get_spreadsheet(sys.argv[2]) 224 | -------------------------------------------------------------------------------- /Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "d58bacf5d273f521c17ba6b4175a19951607bc33dfbf92fb4147d00c9235e306" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "2.7" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "asn1crypto": { 20 | "hashes": [ 21 | "sha256:2f1adbb7546ed199e3c90ef23ec95c5cf3585bac7d11fb7eb562a3fe89c64e87", 22 | "sha256:9d5c20441baf0cb60a4ac34cc447c6c189024b6b4c6cd7877034f4965c464e49" 23 | ], 24 | "index": "pypi", 25 | "version": "==0.24.0" 26 | }, 27 | "asyncpg": { 28 | "hashes": [ 29 | "sha256:03dea4fe865cd21b5e5b6b575c582d09463c00ea0b137b323ebcffc114e7fefb", 30 | "sha256:0b2efe8f3dce86d9c16aa6d7043e7496d99ee25e7390dacff660ed7b5e25060f", 31 | "sha256:10efb357cf879f0e7e3ea4ea852b0b52877f208d988aeb626296092d2601e3cd", 32 | "sha256:2aeb44894fc8ce747f324200fddb2eb16709f420c44d94b445f8889152a5ab96", 33 | "sha256:323b1db6bf6c99be6a16e371c5dcf1fd7b1f32f22719e6f6305610347f811423", 34 | "sha256:60a70530dda8cfd09edcea77ef328e37f1d189c00a48e22049f554ef58e5f06b", 35 | "sha256:69af70030faa8b6ce00e921d38e076f58dbba251314d61cc71e479f8cbaa30a3", 36 | "sha256:7adfabdd2683b4c7b7fe1e6fd46bd9873563c1ed41f12dd5f2f9b360af4c5ef4", 37 | "sha256:8b507afc0f5657a4ebbf5270d00d27513935aabd78f07628353b2a778ec4af61", 38 | "sha256:9b92d536cf5881b99aaa99ce7af4848a91a063127ef94044e4139fe530d88d8a", 39 | "sha256:a1522b0408195242068c5899d6ecb1efb818cee86dab514971463a67d395da06", 40 | "sha256:b24a7451ca40af9a809012074289dba8ef403816bc1d4221a5aef3091389a729", 41 | "sha256:b368229bf96f497a3369fb24ef6a32063b8ebd94e91a2781b6a49de6a08a3d77", 42 | "sha256:bb5dd96503dff7e3038655e0c8946db9a6fd6b8a7307096ca48ad165c9cb185b", 43 | "sha256:e9c5245837ce08f4cee2b01e639bed79abaebb0b39e4be573c1c7387ce2ff01f", 44 | "sha256:f003d4b2b887dd0661c94c80aeeca1410dc0aafa1e16652cde91e0b0c43b8808" 45 | ], 46 | "index": "pypi", 47 | "version": "==0.17.0" 48 | }, 49 | "beautifulsoup4": { 50 | "hashes": [ 51 | "sha256:194ec62a25438adcb3fdb06378b26559eda1ea8a747367d34c33cef9c7f48d57", 52 | "sha256:90f8e61121d6ae58362ce3bed8cd997efb00c914eae0ff3d363c32f9a9822d10", 53 | "sha256:f0abd31228055d698bb392a826528ea08ebb9959e6bea17c606fd9c9009db938" 54 | ], 55 | "index": "pypi", 56 | "version": "==4.6.3" 57 | }, 58 | "censys": { 59 | "hashes": [ 60 | "sha256:7e5f623fbdc2ce1dcf3ef531e63ba486f7e255f20c4d4006b4f70b6d59a78534" 61 | ], 62 | "index": "pypi", 63 | "version": "==0.0.8" 64 | }, 65 | "certifi": { 66 | "hashes": [ 67 | "sha256:376690d6f16d32f9d1fe8932551d80b23e9d393a8578c5633a2ed39a64861638", 68 | "sha256:456048c7e371c089d0a77a5212fb37a2c2dce1e24146e3b7e0261736aaeaa22a" 69 | ], 70 | "version": "==2018.8.24" 71 | }, 72 | "cffi": { 73 | "hashes": [ 74 | "sha256:03a9b9efc280dbe6be149a7fa689f59a822df009eee633fdaf55a6f38795861f", 75 | "sha256:062c66dabc3faf8e0db1ca09a6b8e308846e5d35f43bed1a68c492b0d96ac171", 76 | "sha256:09b7d195d163b515ef7c2b2e26a689c9816c83d5319cceac6c36ffdab97ab048", 77 | "sha256:11a8ba88ef6ae89110ef029dae7f1a293365e50bdd0c6ca973beed80cec95ae4", 78 | "sha256:1c103c0ee8235c47c4892288b2287014f33e7cb24b9d4a665be3aa744377dcb9", 79 | "sha256:248198cb714fe09f5c60b6acba3675d52199c6142641536796cdf89dd45e5590", 80 | "sha256:2c707e97ad7b0417713543be7cb87315c015bb5dd97903480168d60ebe3e313e", 81 | "sha256:3ac9be5763238da1d6fa467c43e3f86472626837a478588c94165df09e62e120", 82 | "sha256:401ba2f6c1f1672b6c38670e1c00fa5f84f841edd30c32742dab5c7151cd89bf", 83 | "sha256:4d9bf1b23896bcd4d042e823f50ad36fb6d8e1e645a3dfb2fe2f070851489b92", 84 | "sha256:5357b465e3d6b98972b7810f9969c913d365e75b09b7ba813f5f0577fe1ac9f4", 85 | "sha256:5f96c92d5f5713ccb71e76dfa14cf819c59ecb9778e94bcb541e13e6d96d1ce5", 86 | "sha256:61cf049b1c649d8eec360a1a1d09a61c37b9b2d542364506e8feb4afd232363d", 87 | "sha256:627298d788edcb317b6a01347428501e773f5e8f2988407231c07e50e3f6c1cf", 88 | "sha256:6d8c7e20eb90be9e1ccce8e8dd4ee5163b37289fc5708f9eeafc00adc07ba891", 89 | "sha256:75e1de9ba7c155d89bcf67d149b1c741df553c8158536e8d27e63167403159af", 90 | "sha256:89829f5cfbcb5ad568a3d61bd23a8e33ad69b488d8f6a385e0097a4c20742a9b", 91 | "sha256:8b3d6dc9981cedfb1ddcd4600ec0c7f5ac2c6ad2dc482011c7eecb4ae9c819e0", 92 | "sha256:943b94667749d1cfcd964e215a20b9c891deae913202ee8eacaf2b94164b155f", 93 | "sha256:974f69112721ba2e8a6acd0f6b68a5e11432710a3eca4e4e6f4d7aaf99214ed1", 94 | "sha256:a79b15b9bb4726672865cf5b0f63dee4835974a2b11b49652d70d49003f5d1f4", 95 | "sha256:ab87dd91c0c4073758d07334c1e5f712ce8fe48f007b86f8238773963ee700a6", 96 | "sha256:ba78da7c940b041cdbb5aaff5afe11e8a8f25fe19564c12eefea5c5bd86930ca", 97 | "sha256:bdd28cf8302eeca1b4c70ec727de384d4f6ea640b0e698934fd9b4c3bc88eeb1", 98 | "sha256:c962cb68987cbfb70b034f153bfa467c615c0b55305d39b3237c4bdbdbc8b0f4", 99 | "sha256:ce3da410ae2ab8709565cc3b18fbe9a0eb96ea7b2189416098c48d839ecced84", 100 | "sha256:d54a7c37f954fdbb971873c935a77ddc33690cec9b7ac254d9f948c43c32fa83", 101 | "sha256:d7461ef8671ae40f991384bbc4a6b1b79f4e7175d8052584be44041996f46517", 102 | "sha256:e72d8b5056f967ecb57e166537408bc913f2f97dc568027fb6342fcfa9f81d64", 103 | "sha256:e7f5ad6b12f21b77d3a37d5c67260e464f4e9068eb0c0622f61d0e30390b31b6", 104 | "sha256:f6799913eb510b682de971ddef062bbb4a200f190e55cae81c413bc1fd4733c1" 105 | ], 106 | "index": "pypi", 107 | "version": "==1.11.2" 108 | }, 109 | "chardet": { 110 | "hashes": [ 111 | "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", 112 | "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" 113 | ], 114 | "version": "==3.0.4" 115 | }, 116 | "cryptography": { 117 | "hashes": [ 118 | "sha256:0d39a93cf25edeae1f796bbc5960e587f34513a852564f6345ea4491a86c5997", 119 | "sha256:18d0b0fc21f39b35ea469a82584f55eeecec1f65a92d85af712c425bdef627b3", 120 | "sha256:27a208b9600166976182351174948e128818e7fc95cbdba18143f3106a211546", 121 | "sha256:28e4e9a97713aa47b5ef9c5003def2eb58aec89781ef3ef82b1c2916a8b0639b", 122 | "sha256:2cfcee8829c5dec55597826d52c26bc26e7ce39adb4771584459d0636b0b7108", 123 | "sha256:33b564196dcd563e309a0b07444e31611368afe3a3822160c046f5e4c3b5cdd7", 124 | "sha256:41f94194ae78f83fd94ca94fb8ad65f92210a76a2421169ffa5c33c3ec7605f4", 125 | "sha256:4f385ee7d39ee1ed74f1d6b1da03d0734ea82855a7b28a9e6e88c4091bc58664", 126 | "sha256:55555d784cfdf9033e81f044c0df04babed2aa141213765d960d233b0139e353", 127 | "sha256:69285f5615507b6625f89ea1048addd1d9218585fb886eb90bdebb1d2b2d26f5", 128 | "sha256:6cb1224da391fa90f1be524eafb375b62baf8d3df9690b32e8cc475ccfccee5e", 129 | "sha256:6fb22f63e17813f3d1d8e30dd1e249e2c34233ba1d3de977fd31cb5db764c7d0", 130 | "sha256:7a2409f1564c84bcf2563d379c9b6148c5bc6b0ae46e109f6a7b4bebadf551df", 131 | "sha256:8487524a1212223ca6dc7e2c8913024618f7ff29855c98869088e3818d5f6733", 132 | "sha256:9a2945efcff84830c8e237ab037d0269380d75d400a89cc9e5628e52647e21be", 133 | "sha256:9a47a80f65f4feaaf8415a40c339806c7d7d867152ddccc6ca87f707c8b7b565", 134 | "sha256:a3c180d12ffb1d8ee5b33a514a5bcb2a9cc06cc89aa74038015591170c82f55d", 135 | "sha256:a5f2c681fd040ed648513939a1dd2242af19bd5e9e79e53b6dcfa33bdae61217", 136 | "sha256:b984523d28737e373c7c35c8b6db6001537609d47534892de189bebebaa42a47", 137 | "sha256:d18df9cf3f3212df28d445ea82ce702c4d7a35817ef7a38ee38879ffa8f7e857", 138 | "sha256:e4d967371c5b6b2e67855066471d844c5d52d210c36c28d49a8507b96e2c5291", 139 | "sha256:ee245f185fae723133511e2450be08a66c2eebb53ad27c0c19b228029f4748a5", 140 | "sha256:fc2208d95d9ecc8032f5e38330d5ace2e3b0b998e42b08c30c35b2ab3a4a3bc8" 141 | ], 142 | "index": "pypi", 143 | "version": "==2.1.4" 144 | }, 145 | "enum34": { 146 | "hashes": [ 147 | "sha256:2d81cbbe0e73112bdfe6ef8576f2238f2ba27dd0d55752a776c41d38b7da2850", 148 | "sha256:644837f692e5f550741432dd3f223bbb9852018674981b1664e5dc339387588a", 149 | "sha256:6bd0f6ad48ec2aa117d3d141940d484deccda84d4fcd884f5c3d93c23ecd8c79", 150 | "sha256:8ad8c4783bf61ded74527bffb48ed9b54166685e4230386a9ed9b1279e2df5b1" 151 | ], 152 | "index": "pypi", 153 | "version": "==1.1.6" 154 | }, 155 | "idna": { 156 | "hashes": [ 157 | "sha256:2c6a5de3089009e3da7c5dde64a141dbc8551d5b7f6cf4ed7c2568d0cc520a8f", 158 | "sha256:8c7309c718f94b3a625cb648ace320157ad16ff131ae0af362c9f21b80ef6ec4" 159 | ], 160 | "index": "pypi", 161 | "version": "==2.6" 162 | }, 163 | "ipaddress": { 164 | "hashes": [ 165 | "sha256:200d8686011d470b5e4de207d803445deee427455cd0cb7c982b68cf82524f81" 166 | ], 167 | "index": "pypi", 168 | "version": "==1.0.19" 169 | }, 170 | "netaddr": { 171 | "hashes": [ 172 | "sha256:38aeec7cdd035081d3a4c306394b19d677623bf76fa0913f6695127c7753aefd", 173 | "sha256:56b3558bd71f3f6999e4c52e349f38660e54a7a8a9943335f73dfc96883e08ca" 174 | ], 175 | "version": "==0.7.19" 176 | }, 177 | "psycopg2": { 178 | "hashes": [ 179 | "sha256:009e0bc09a57dbef4b601cb8b46a2abad51f5274c8be4bba276ff2884cd4cc53", 180 | "sha256:0344b181e1aea37a58c218ccb0f0f771295de9aa25a625ed076e6996c6530f9e", 181 | "sha256:0cd4c848f0e9d805d531e44973c8f48962e20eb7fc0edac3db4f9dbf9ed5ab82", 182 | "sha256:1286dd16d0e46d59fa54582725986704a7a3f3d9aca6c5902a7eceb10c60cb7e", 183 | "sha256:1cf5d84290c771eeecb734abe2c6c3120e9837eb12f99474141a862b9061ac51", 184 | "sha256:207ba4f9125a0a4200691e82d5eee7ea1485708eabe99a07fc7f08696fae62f4", 185 | "sha256:25250867a4cd1510fb755ef9cb38da3065def999d8e92c44e49a39b9b76bc893", 186 | "sha256:2954557393cfc9a5c11a5199c7a78cd9c0c793a047552d27b1636da50d013916", 187 | "sha256:317612d5d0ca4a9f7e42afb2add69b10be360784d21ce4ecfbca19f1f5eadf43", 188 | "sha256:37f54452c7787dbdc0a634ca9773362b91709917f0b365ed14b831f03cbd34ba", 189 | "sha256:40fa5630cd7d237cd93c4d4b64b9e5ed9273d1cfce55241c7f9066f5db70629d", 190 | "sha256:57baf63aeb2965ca4b52613ce78e968b6d2bde700c97f6a7e8c6c236b51ab83e", 191 | "sha256:594aa9a095de16614f703d759e10c018bdffeafce2921b8e80a0e8a0ebbc12e5", 192 | "sha256:5c3213be557d0468f9df8fe2487eaf2990d9799202c5ff5cb8d394d09fad9b2a", 193 | "sha256:697ff63bc5451e0b0db48ad205151123d25683b3754198be7ab5fcb44334e519", 194 | "sha256:6c2f1a76a9ebd9ecf7825b9e20860139ca502c2bf1beabf6accf6c9e66a7e0c3", 195 | "sha256:7a75565181e75ba0b9fb174b58172bf6ea9b4331631cfe7bafff03f3641f5d73", 196 | "sha256:7a9c6c62e6e05df5406e9b5235c31c376a22620ef26715a663cee57083b3c2ea", 197 | "sha256:7c31dade89634807196a6b20ced831fbd5bec8a21c4e458ea950c9102c3aa96f", 198 | "sha256:82c40ea3ac1555e0462803380609fbe8b26f52620f3d4f8eb480cfd8ceed8a14", 199 | "sha256:8f5942a4daf1ffac42109dc4a72f786af4baa4fa702ede1d7c57b4b696c2e7d6", 200 | "sha256:92179bd68c2efe72924a99b6745a9172471931fc296f9bfdf9645b75eebd6344", 201 | "sha256:94e4128ba1ea56f02522fffac65520091a9de3f5c00da31539e085e13db4771b", 202 | "sha256:988d2ec7560d42ef0ac34b3b97aad14c4f068792f00e1524fa1d3749fe4e4b64", 203 | "sha256:9d6266348b15b4a48623bf4d3e50445d8e581da413644f365805b321703d0fac", 204 | "sha256:9d64fed2681552ed642e9c0cc831a9e95ab91de72b47d0cb68b5bf506ba88647", 205 | "sha256:b9358e203168fef7bfe9f430afaed3a2a624717a1d19c7afa7dfcbd76e3cd95c", 206 | "sha256:bf708455cd1e9fa96c05126e89a0c59b200d086c7df7bbafc7d9be769e4149a3", 207 | "sha256:d3ac07240e2304181ffdb13c099840b5eb555efc7be9344503c0c03aa681de79", 208 | "sha256:ddca39cc55877653b5fcf59976d073e3d58c7c406ef54ae8e61ddf8782867182", 209 | "sha256:fc993c9331d91766d54757bbc70231e29d5ceb2d1ac08b1570feaa0c38ab9582" 210 | ], 211 | "index": "pypi", 212 | "version": "==2.7.3.2" 213 | }, 214 | "pycparser": { 215 | "hashes": [ 216 | "sha256:99a8ca03e29851d96616ad0404b4aad7d9ee16f25c9f9708a11faf2810f7b226" 217 | ], 218 | "index": "pypi", 219 | "version": "==2.18" 220 | }, 221 | "pyopenssl": { 222 | "hashes": [ 223 | "sha256:07a2de1a54de07448732a81e38a55df7da109b2f47f599f8bb35b0cbec69d4bd", 224 | "sha256:2c10cfba46a52c0b0950118981d61e72c1e5b1aac451ca1bc77de1a679456773" 225 | ], 226 | "index": "pypi", 227 | "version": "==17.5.0" 228 | }, 229 | "requests": { 230 | "hashes": [ 231 | "sha256:6a1b267aa90cac58ac3a765d067950e7dbbf75b1da07e895d1f594193a40a38b", 232 | "sha256:9c443e7324ba5b85070c4a818ade28bfabedf16ea10206da1132edaa6dda237e" 233 | ], 234 | "index": "pypi", 235 | "version": "==2.18.4" 236 | }, 237 | "six": { 238 | "hashes": [ 239 | "sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9", 240 | "sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb" 241 | ], 242 | "index": "pypi", 243 | "version": "==1.11.0" 244 | }, 245 | "urllib3": { 246 | "hashes": [ 247 | "sha256:06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b", 248 | "sha256:cc44da8e1145637334317feebd728bd869a35285b93cbb4cca2577da7e62db4f" 249 | ], 250 | "version": "==1.22" 251 | } 252 | }, 253 | "develop": {} 254 | } 255 | --------------------------------------------------------------------------------