├── 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 |
--------------------------------------------------------------------------------